add mount of menu
fix store usage add page loader
This commit is contained in:
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
"@nextcloud/browserslist-config": "^3.0.1",
|
"@nextcloud/browserslist-config": "^3.0.1",
|
||||||
"@nextcloud/event-bus": "^3.3.1",
|
"@nextcloud/event-bus": "^3.3.1",
|
||||||
"@nextcloud/initial-state": "^2.2.0",
|
"@nextcloud/initial-state": "^2.2.0",
|
||||||
"@nextcloud/l10n": "^3.1.0",
|
"@nextcloud/l10n": "^3.2.0",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"eslint": "^9.19.0",
|
"eslint": "^9.19.0",
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -42,7 +42,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
@close="hideAddForm"
|
@close="hideAddForm"
|
||||||
>
|
>
|
||||||
<div class="modal__content">
|
<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>
|
<span class="lang">{{ lang }}</span>
|
||||||
<input
|
<input
|
||||||
v-model="newValue[lang]"
|
v-model="newValue[lang]"
|
||||||
@@ -66,7 +69,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
@close="hideEditForm"
|
@close="hideEditForm"
|
||||||
>
|
>
|
||||||
<div class="modal__content">
|
<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>
|
<span class="lang">{{ lang }}</span>
|
||||||
<input
|
<input
|
||||||
v-model="editValue[lang]"
|
v-model="editValue[lang]"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const emit = defineEmit('input')
|
const emit = defineEmits('input')
|
||||||
const { value } = defineProps({
|
const { value } = defineProps({
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -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>
|
||||||
+8
-6
@@ -1,11 +1,13 @@
|
|||||||
const waitContainer = async (selector) => {
|
const waitContainer = async (selector) => {
|
||||||
new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
const container = document.querySelector(selector)
|
||||||
const container = document.querySelector(selector)
|
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
resolve(selector, container)
|
return resolve(selector, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
waitContainer(selector)
|
||||||
}, 50)
|
}, 50)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-6
@@ -13,14 +13,11 @@ const containsAppsMatchingSearch = (values, search) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isAppMatchingSearch = (item, search) => {
|
const isAppMatchingSearch = (item, search) => {
|
||||||
if (search.value.trim() === '') {
|
if (search.trim() === '') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.name.toLowerCase().includes(search.value.trim().toLowerCase())
|
return item.name.toLowerCase().includes(search.trim().toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { containsAppsMatchingSearch, isAppMatchingSearch }
|
||||||
containsAppsMatchingSearch,
|
|
||||||
isAppMatchingSearch,
|
|
||||||
}
|
|
||||||
|
|||||||
+17
-27
@@ -19,39 +19,29 @@ import './scss/menu.scss'
|
|||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import { waitContainer } from './lib/dom.js'
|
import { createElement } from './lib/dom.js'
|
||||||
|
|
||||||
// import AppMenu from './menus/AppMenu.vue'
|
import MenuContainer from './menus/MenuContainer.vue'
|
||||||
import SideMenu from './menus/SideMenu.vue'
|
|
||||||
import SideMenuBig from './menus/SideMenuBig.vue'
|
|
||||||
import SideMenuWithCategories from './menus/SideMenuWithCategories.vue'
|
|
||||||
|
|
||||||
// import PageLoader from './components/PageLoader.vue'
|
// import PageLoader from './components/PageLoader.vue'
|
||||||
|
|
||||||
// window.PageLoader = PageLoader
|
// window.PageLoader = PageLoader
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
|
const body = document.querySelector('body')
|
||||||
waitContainer('#side-menu').then((selector, container) => {
|
const container = createElement('div', {
|
||||||
const component = (() => {
|
id: 'side-menu-container',
|
||||||
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)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
waitContainer('#header .app-menu').then((selector) => {
|
body.appendChild(container)
|
||||||
const app = createApp(AppMenu)
|
|
||||||
|
|
||||||
app.use(pinia)
|
const app = createApp(MenuContainer)
|
||||||
app.mount(selector)
|
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)
|
||||||
|
// })
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -17,8 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
<template>
|
<template>
|
||||||
<div id="side-menu">
|
<div id="side-menu">
|
||||||
<div
|
<div
|
||||||
class="side-menu-header"
|
|
||||||
v-if="settings || !openerHover || (!avatar && !alwaysDisplayed && logo) || avatar"
|
v-if="settings || !openerHover || (!avatar && !alwaysDisplayed && logo) || avatar"
|
||||||
|
class="side-menu-header"
|
||||||
>
|
>
|
||||||
<SettingsButton
|
<SettingsButton
|
||||||
v-if="settings"
|
v-if="settings"
|
||||||
@@ -75,6 +75,8 @@ import SideMenuApp from '../components/SideMenuApp'
|
|||||||
import AppSearch from '../components/AppSearch'
|
import AppSearch from '../components/AppSearch'
|
||||||
import Logo from '../components/Logo'
|
import Logo from '../components/Logo'
|
||||||
|
|
||||||
|
const navStore = useNavStore()
|
||||||
|
const configStore = useConfigStore()
|
||||||
const targetBlankApps = ref(null)
|
const targetBlankApps = ref(null)
|
||||||
const forceLightIcon = ref(null)
|
const forceLightIcon = ref(null)
|
||||||
const avatar = ref(null)
|
const avatar = ref(null)
|
||||||
@@ -86,12 +88,7 @@ const alwaysDisplayed = ref(null)
|
|||||||
const search = ref('')
|
const search = ref('')
|
||||||
const apps = ref([])
|
const apps = ref([])
|
||||||
|
|
||||||
function getFiltredAndSortedApps(
|
function getFiltredAndSortedApps(items, order, topMenuApps, topSideMenuApps) {
|
||||||
items,
|
|
||||||
order,
|
|
||||||
topMenuApps,
|
|
||||||
topSideMenuApps
|
|
||||||
) {
|
|
||||||
const data = []
|
const data = []
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
@@ -115,8 +112,8 @@ function getFiltredAndSortedApps(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
const config = useConfigStore.getConfig()
|
const config = await configStore.getConfig()
|
||||||
|
|
||||||
targetBlankApps.value = config['target-blank-apps']
|
targetBlankApps.value = config['target-blank-apps']
|
||||||
forceLightIcon.value = config['force-light-icon']
|
forceLightIcon.value = config['force-light-icon']
|
||||||
@@ -128,10 +125,10 @@ onMounted(() => {
|
|||||||
alwaysDisplayed.value = config['always-displayed']
|
alwaysDisplayed.value = config['always-displayed']
|
||||||
|
|
||||||
apps.value = getFiltredAndSortedApps(
|
apps.value = getFiltredAndSortedApps(
|
||||||
useNavStore.getApps(),
|
await navStore.getApps(),
|
||||||
config['apps-order'],
|
config['apps-order'],
|
||||||
config['top-menu-apps'],
|
config['top-menu-apps'],
|
||||||
config['top-side-menu-apps'],
|
config['top-side-menu-apps']
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
+6
-2
@@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { axios } from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
export const useConfigStore = defineStore('config', () => {
|
export const useConfigStore = defineStore('config', () => {
|
||||||
@@ -11,8 +11,12 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
return config.value
|
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 config.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getConfig,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+10
-4
@@ -1,20 +1,21 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { axios } from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
export const useNavStore = defineStore('nav', () => {
|
export const useNavStore = defineStore('nav', () => {
|
||||||
const categories = ref(null)
|
const categories = ref(null)
|
||||||
const apps = ref(null)
|
const apps = ref(null)
|
||||||
|
|
||||||
function getApps() {
|
async function getApps() {
|
||||||
if (apps.value !== null) {
|
if (apps.value !== null) {
|
||||||
return apps.value
|
return apps.value
|
||||||
}
|
}
|
||||||
|
|
||||||
apps.value = []
|
apps.value = []
|
||||||
|
const cats = await getCategories()
|
||||||
|
|
||||||
getCategories().forEach((category) => {
|
cats.forEach((category) => {
|
||||||
Object.values(category.apps).forEach((app) => {
|
Object.values(category.apps).forEach((app) => {
|
||||||
apps.value.push(app)
|
apps.value.push(app)
|
||||||
})
|
})
|
||||||
@@ -28,8 +29,13 @@ export const useNavStore = defineStore('nav', () => {
|
|||||||
return categories.value
|
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 categories.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getApps,
|
||||||
|
getCategories,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ const SMcreateElement = (tagName, attributes) => {
|
|||||||
sideMenuContainer.appendChild(sideMenu)
|
sideMenuContainer.appendChild(sideMenu)
|
||||||
|
|
||||||
<?php if ($_['loader-enabled'] === true): ?>
|
<?php if ($_['loader-enabled'] === true): ?>
|
||||||
PageLoader()
|
// PageLoader()
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
if (nextcloud) {
|
if (nextcloud) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const isDev = buildMode === 'development'
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
target: 'web',
|
target: 'web',
|
||||||
mode: buildMode,
|
mode: buildMode,
|
||||||
|
devtool: "inline-source-map",
|
||||||
entry: {
|
entry: {
|
||||||
menu: path.resolve(path.join('src', 'menu.js')),
|
menu: path.resolve(path.join('src', 'menu.js')),
|
||||||
// admin: path.resolve(path.join('src', 'admin.js')),
|
// admin: path.resolve(path.join('src', 'admin.js')),
|
||||||
|
|||||||
Reference in New Issue
Block a user