1
0
Fork 0
mirror of https://gitnet.fr/deblan/side_menu.git synced 2025-12-18 05:10:50 +01:00

add mount of menu

fix store usage

add page loader
This commit is contained in:
Simon Vieille 2025-04-06 14:09:06 +02:00
parent d8a622ce0f
commit b287b671be
No known key found for this signature in database
GPG key ID: 579388D585F70417
15 changed files with 175 additions and 81 deletions

View file

@ -28,7 +28,7 @@
"@nextcloud/browserslist-config": "^3.0.1",
"@nextcloud/event-bus": "^3.3.1",
"@nextcloud/initial-state": "^2.2.0",
"@nextcloud/l10n": "^3.1.0",
"@nextcloud/l10n": "^3.2.0",
"babel-loader": "^9.1.3",
"css-loader": "^7.1.2",
"eslint": "^9.19.0",

View file

@ -1,20 +0,0 @@
const createElement = require('./lib/createElement')
const PageLoader = () => {
const pageLoader = createElement('div', { id: 'side-menu-loader' })
const pageLoaderBar = createElement('div', { id: 'side-menu-loader-bar' })
pageLoader.appendChild(pageLoaderBar)
document.querySelector('body').appendChild(pageLoader)
let pageLoaderValue = 0
window.addEventListener('beforeunload', () => {
setInterval(() => {
pageLoaderBar.style.width = pageLoaderValue.toString() + '%'
pageLoaderValue = Math.min(pageLoaderValue + 0.2, 100)
}, 25)
})
}
module.exports = PageLoader

View file

@ -42,7 +42,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@close="hideAddForm"
>
<div class="modal__content">
<div v-for="(lang, key) in langs" :key="key">
<div
v-for="(lang, key) in langs"
:key="key"
>
<span class="lang">{{ lang }}</span>
<input
v-model="newValue[lang]"
@ -66,7 +69,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@close="hideEditForm"
>
<div class="modal__content">
<div v-for="(lang, key) in langs" :key="key">
<div
v-for="(lang, key) in langs"
:key="key"
>
<span class="lang">{{ lang }}</span>
<input
v-model="editValue[lang]"

View file

@ -26,7 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</template>
<script setup>
const emit = defineEmit('input')
const emit = defineEmits('input')
const { value } = defineProps({
value: {
type: String,

View file

@ -0,0 +1,24 @@
<template>
<div id="side-menu-loader">
<div id="side-menu-loader-bar" :style="createStyle(width)"></div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
const width = ref(0)
const createStyle = (size) => {
return {
width: `${size}%`,
}
}
onMounted(() => {
window.addEventListener('beforeunload', () => {
setInterval(() => {
width.value = Math.min(width.value + 0.2, 100)
}, 25)
})
})
</script>

View file

@ -1,11 +1,13 @@
const waitContainer = async (selector) => {
new Promise((resolve) => {
setTimeout(() => {
const container = document.querySelector(selector)
return new Promise((resolve) => {
const container = document.querySelector(selector)
if (container) {
resolve(selector, container)
}
if (container) {
return resolve(selector, container)
}
setTimeout(() => {
waitContainer(selector)
}, 50)
})
}

View file

@ -13,14 +13,11 @@ const containsAppsMatchingSearch = (values, search) => {
}
const isAppMatchingSearch = (item, search) => {
if (search.value.trim() === '') {
if (search.trim() === '') {
return true
}
return item.name.toLowerCase().includes(search.value.trim().toLowerCase())
return item.name.toLowerCase().includes(search.trim().toLowerCase())
}
export {
containsAppsMatchingSearch,
isAppMatchingSearch,
}
export { containsAppsMatchingSearch, isAppMatchingSearch }

View file

@ -19,39 +19,29 @@ import './scss/menu.scss'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { waitContainer } from './lib/dom.js'
import { createElement } from './lib/dom.js'
// import AppMenu from './menus/AppMenu.vue'
import SideMenu from './menus/SideMenu.vue'
import SideMenuBig from './menus/SideMenuBig.vue'
import SideMenuWithCategories from './menus/SideMenuWithCategories.vue'
import MenuContainer from './menus/MenuContainer.vue'
// import PageLoader from './components/PageLoader.vue'
// window.PageLoader = PageLoader
const pinia = createPinia()
waitContainer('#side-menu').then((selector, container) => {
const component = (() => {
if (container.getAttribute('data-bigmenu')) {
return SideMenuBig
} else if (container.getAttribute('data-sidewithcategories')) {
return SideMenuWithCategories
} else {
return SideMenu
}
})()
const app = createApp(component)
app.use(pinia)
app.mount(selector)
const body = document.querySelector('body')
const container = createElement('div', {
id: 'side-menu-container',
})
waitContainer('#header .app-menu').then((selector) => {
const app = createApp(AppMenu)
body.appendChild(container)
app.use(pinia)
app.mount(selector)
})
const app = createApp(MenuContainer)
app.use(pinia)
app.mixin({ methods: { t, n }})
app.mount(container)
// waitContainer('#header .app-menu').then((selector) => {
// const app = createApp(AppMenu)
// app.use(pinia)
// app.mixin({ methods: { t, n }})
// app.mount(selector)
// })

View file

@ -0,0 +1,87 @@
<template>
<template v-if="display">
<PageLoader v-if="hasPageLoader" />
<TopWideMenu v-if="display === 'big-menu'" />
<SideMenuWithCategories v-else-if="display === 'side-with-categories'" />
<SimpleSideMenu
v-else-if="display === 'simple-side-menu'"
:alawayDisplayed="display === 'always-displayed'"
/>
</template>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useConfigStore } from '../store/config.js'
import { createElement } from '../lib/dom.js'
import { translate as t } from '@nextcloud/l10n'
import SimpleSideMenu from './SimpleSideMenu'
import TopWideMenu from './TopWideMenu'
import SideMenuWithCategories from './SideMenuWithCategories'
import PageLoader from '../components/PageLoader'
const config = ref(null)
const configStore = useConfigStore()
const display = ref(null)
const alawayDisplayed = ref(false)
const hasPageLoader = ref(false)
const createOpener = () => {
const nextcloud = document.querySelector('#nextcloud')
const logo = document.querySelector('.header-left .logo, .header-start .logo')
if (!nextcloud || !logo) {
return
}
if (logo.parentNode !== nextcloud) {
nextcloud.appendChild(logo)
}
const opener = createElement('button', {
'class': 'side-menu-opener',
'arial-label': t('side_menu', 'Toggle the menu'),
'html': `<span>${t('side_menu', 'Toggle the menu')}</span>`
})
if (config.value['opener-position'] === 'before') {
nextcloud.parentNode.insertBefore(opener, nextcloud)
} else {
nextcloud.parentNode.insertBefore(opener, nextcloud.nextSibling)
}
}
const createLoader = () => {
const loader = createElement('div', { id: 'side-menu-loader' })
const bar = createElement('div', { id: 'side-menu-loader-bar' })
loader.appendChild(bar)
document.querySelector('body').appendChild(loader)
let pageLoaderValue = 0
window.addEventListener('beforeunload', () => {
setInterval(() => {
pageLoaderBar.style.width = pageLoaderValue.toString() + '%'
pageLoaderValue = Math.min(pageLoaderValue + 0.2, 100)
}, 25)
})
}
onMounted(async () => {
config.value = await configStore.getConfig()
if (config.value['big-menu']) {
display.value = 'big-menu'
} else if (config.value['side-with-categories']) {
display.value = 'side-with-categories'
} else {
display.value = 'simple-side-menu'
alawayDisplayed.value = config.value['always-displayed']
}
hasPageLoader.value = config.value['loader-enabled']
createOpener()
})
</script>

View file

@ -17,8 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<template>
<div id="side-menu">
<div
class="side-menu-header"
v-if="settings || !openerHover || (!avatar && !alwaysDisplayed && logo) || avatar"
class="side-menu-header"
>
<SettingsButton
v-if="settings"
@ -75,6 +75,8 @@ import SideMenuApp from '../components/SideMenuApp'
import AppSearch from '../components/AppSearch'
import Logo from '../components/Logo'
const navStore = useNavStore()
const configStore = useConfigStore()
const targetBlankApps = ref(null)
const forceLightIcon = ref(null)
const avatar = ref(null)
@ -86,12 +88,7 @@ const alwaysDisplayed = ref(null)
const search = ref('')
const apps = ref([])
function getFiltredAndSortedApps(
items,
order,
topMenuApps,
topSideMenuApps
) {
function getFiltredAndSortedApps(items, order, topMenuApps, topSideMenuApps) {
const data = []
items.forEach((item) => {
@ -115,8 +112,8 @@ function getFiltredAndSortedApps(
})
}
onMounted(() => {
const config = useConfigStore.getConfig()
onMounted(async () => {
const config = await configStore.getConfig()
targetBlankApps.value = config['target-blank-apps']
forceLightIcon.value = config['force-light-icon']
@ -128,10 +125,10 @@ onMounted(() => {
alwaysDisplayed.value = config['always-displayed']
apps.value = getFiltredAndSortedApps(
useNavStore.getApps(),
await navStore.getApps(),
config['apps-order'],
config['top-menu-apps'],
config['top-side-menu-apps'],
config['top-side-menu-apps']
)
})
</script>

View file

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { axios } from '@nextcloud/axios'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
export const useConfigStore = defineStore('config', () => {
@ -11,8 +11,12 @@ export const useConfigStore = defineStore('config', () => {
return config.value
}
config.value = await fetch(generateUrl('/apps/side_menu/js/config')).then((response) => response.data)
config.value = await axios.get(generateUrl('/apps/side_menu/js/config')).then((response) => response.data)
return config.value
}
return {
getConfig,
}
})

View file

@ -1,20 +1,21 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { axios } from '@nextcloud/axios'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
export const useNavStore = defineStore('nav', () => {
const categories = ref(null)
const apps = ref(null)
function getApps() {
async function getApps() {
if (apps.value !== null) {
return apps.value
}
apps.value = []
const cats = await getCategories()
getCategories().forEach((category) => {
cats.forEach((category) => {
Object.values(category.apps).forEach((app) => {
apps.value.push(app)
})
@ -28,8 +29,13 @@ export const useNavStore = defineStore('nav', () => {
return categories.value
}
categories.value = await fetch(generateUrl('/apps/side_menu/nav/items')).then((response) => response.data.items)
categories.value = await axios.get(generateUrl('/apps/side_menu/nav/items')).then((response) => response.data.items)
return categories.value
}
return {
getApps,
getCategories,
}
})

View file

@ -187,7 +187,7 @@ const SMcreateElement = (tagName, attributes) => {
sideMenuContainer.appendChild(sideMenu)
<?php if ($_['loader-enabled'] === true): ?>
PageLoader()
// PageLoader()
<?php endif; ?>
if (nextcloud) {

View file

@ -13,6 +13,7 @@ const isDev = buildMode === 'development'
module.exports = {
target: 'web',
mode: buildMode,
devtool: "inline-source-map",
entry: {
menu: path.resolve(path.join('src', 'menu.js')),
// admin: path.resolve(path.join('src', 'admin.js')),