diff --git a/css/sideMenu.css b/css/sideMenu.css
index 80ed6b7..930a82e 100644
--- a/css/sideMenu.css
+++ b/css/sideMenu.css
@@ -16,326 +16,334 @@
*/
#side-menu {
- position: fixed;
- top: 0;
- left: 0;
- height: 100vh;
- width: 100%;
- max-width: 250px;
- background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
- z-index: 3000;
- color: var(--side-menu-text-color, #fff);
- box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px;
- display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100vh;
+ width: 100%;
+ max-width: 250px;
+ background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
+ z-index: 3000;
+ color: var(--side-menu-text-color, #fff);
+ box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px;
+ display: none;
}
#side-menu a {
- transition: 0.2s;
+ transition: 0.2s;
}
#side-menu.open {
- display: block;
+ display: block;
}
#header .side-menu-opener {
- margin-left: 0px;
+ margin-left: 0px;
}
.side-menu-settings {
- margin-right: 9px;
- margin-top: 2px;
- float: right;
- line-height: 34px;
- height: 28px;
- display: none;
+ margin-right: 9px;
+ margin-top: 2px;
+ float: right;
+ line-height: 34px;
+ height: 28px;
+ display: none;
}
.side-menu-settings a {
- color: var(--side-menu-text-color, #fff);
- display: block;
- padding: 4px 7px;
+ color: var(--side-menu-text-color, #fff);
+ display: block;
+ padding: 4px 7px;
}
.side-menu-settings:hover a, .side-menu-settings a:active, .side-menu-settings a:focus {
- background: var(--side-menu-current-app-background-color, #444);
+ background: var(--side-menu-current-app-background-color, #444);
}
.side-menu-settings img {
- vertical-align: bottom;
- margin-left: 3px;
- width: 32px;
- height: 32px;
+ vertical-align: bottom;
+ margin-left: 3px;
+ width: 32px;
+ height: 32px;
}
#side-menu.open .side-menu-settings {
- display: block;
+ display: block;
}
.side-menu-opener {
- background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
- background-color: transparent !important;
- height: 40px !important;
- width: 40px !important;
- border-radius: 0 !important;
- border: 0 !important;
- padding-right: 12px !important;
- padding-left: 12px !important;
- margin-left: 5px !important;
- margin-left: 3px !important;
+ background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
+ background-color: transparent !important;
+ height: 40px !important;
+ width: 40px !important;
+ border-radius: 0 !important;
+ border: 0 !important;
+ padding-right: 12px !important;
+ padding-left: 12px !important;
+ margin-left: 5px !important;
+ margin-left: 3px !important;
}
.side-menu-opener:active, .side-menu-opener:focus {
- background-color: var(--side-menu-current-app-background-color, #444) !important;
+ background-color: var(--side-menu-current-app-background-color, #444) !important;
}
.side-menu-closer {
- background: url('../img/side-menu-opener-closer.svg');
- display: none;
+ background: url('../img/side-menu-opener-closer.svg');
+ display: none;
}
#side-menu.hide-opener .side-menu-opener, .side-menu-opener.hide, #side-menu.hide {
- display: none !important;
+ display: none !important;
}
.side-menu-apps-list {
- height: calc(100vh - 150px);
- z-index: 2200;
- position: fixed;
- top: 150px;
- width: 100%;
- max-width: 250px;
- overflow: auto;
+ height: calc(100vh - 150px);
+ z-index: 2200;
+ position: fixed;
+ top: 150px;
+ width: 100%;
+ max-width: 250px;
+ overflow: auto;
}
.side-menu-app-icon {
- width: 20px;
- vertical-align: top;
- margin-right: 10px;
- filter: invert(var(--side-menu-icon-invert-filter, 0%));
- opacity: var(--side-menu-icon-opacity, 1);
+ width: 20px;
+ vertical-align: top;
+ margin-right: 10px;
+ filter: invert(var(--side-menu-icon-invert-filter, 0%));
+ opacity: var(--side-menu-icon-opacity, 1);
}
.side-menu-app-icon svg {
- vertical-align: middle;
- margin-top: -3px;
+ vertical-align: middle;
+ margin-top: -3px;
}
.side-menu-app-icon .app-icon-notification {
- display: none;
+ display: none;
}
.side-menu-app a {
- line-height: 30px;
- color: var(--side-menu-text-color, #fff);
- display: block;
- padding: 7px 0 5px 15px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+ line-height: 30px;
+ color: var(--side-menu-text-color, #fff);
+ display: block;
+ padding: 7px 0 5px 15px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
.side-menu-app a:hover, .side-menu-app.active, .side-menu-app a:focus {
- background: var(--side-menu-current-app-background-color, #444);
+ background: var(--side-menu-current-app-background-color, #444);
}
.side-menu-logo {
- text-align: center;
+ text-align: center;
}
.side-menu-logo img {
- max-width: 60%;
- max-height: 100px;
+ max-width: 60%;
+ max-height: 100px;
}
.side-menu-header {
- height: 150px;
- width: 100%;
- z-index: 2300;
- max-width: 250px;
- position: fixed;
- padding-top: 2px;
- top: 0;
+ height: 150px;
+ width: 100%;
+ z-index: 2300;
+ max-width: 250px;
+ position: fixed;
+ padding-top: 2px;
+ top: 0;
}
#side-menu.side-menu-with-categories .side-menu-header {
- max-width: 295px;
+ max-width: 295px;
}
#side-menu.hide-opener .side-menu-logo {
- margin-top: 20px;
+ margin-top: 20px;
}
#side-menu-loader {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- z-index: 3001;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 3001;
}
#side-menu-loader-bar {
- height: 4px;
- background: var(--side-menu-loader-color, #0e75ac);
- width: 0;
- transition-property: width;
+ height: 4px;
+ background: var(--side-menu-loader-color, #0e75ac);
+ width: 0;
+ transition-property: width;
}
#side-menu.side-menu-big, #side-menu.side-menu-with-categories {
- max-width: 100%;
- height: auto;
+ max-width: 100%;
+ height: auto;
}
.side-menu-big .side-menu-header, .side-menu-with-categories .side-menu-header {
- height: auto;
+ height: auto;
}
.side-menu-big .side-menu-apps-list, .side-menu-with-categories .side-menu-apps-list {
- height: auto;
- position: static;
- max-width: 100vw;
- overflow: auto;
+ height: auto;
+ position: static;
+ max-width: 100vw;
+ overflow: auto;
}
.side-menu-big .side-menu-app a, .side-menu-with-categories .side-menu-app a {
- padding: 7px 0 7px 7px;
+ padding: 7px 0 7px 7px;
}
.side-menu-categories-wrapper {
- padding-bottom: 70px;
+ padding-bottom: 70px;
}
.side-menu-categories {
- max-height: calc(100vh - 50px);
- overflow: auto;
- position: relative;
- top: 50px;
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- padding: 0 10% 0 10%;
+ max-height: calc(100vh - 50px);
+ overflow: auto;
+ position: relative;
+ top: 50px;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ padding: 0 10% 0 10%;
}
.side-menu-category {
- padding: 10px 20px;
- flex: 1 1 auto;
+ padding: 10px 20px;
+ flex: 1 1 auto;
}
.side-menu-category-title {
- padding-left: 10px;
- color: var(--side-menu-text-color, #fff);
+ padding-left: 10px;
+ color: var(--side-menu-text-color, #fff);
}
.side-menu-loader {
- text-align: center;
+ text-align: center;
}
.side-menu-loader svg {
- width: 38px;
- margin: auto;
- stroke: var(--side-menu-text-color, #fff);
+ width: 38px;
+ margin: auto;
+ stroke: var(--side-menu-text-color, #fff);
}
.side-menu-with-categories .side-menu-app-icon, .side-menu-big .side-menu-app-icon {
- vertical-align: middle;
- margin-top: -2px;
+ vertical-align: middle;
+ margin-top: -2px;
}
.side-menu-always-displayed #header,
.side-menu-always-displayed body {
- width: calc(100% - 50px) !important;
+ width: calc(100% - 50px) !important;
}
.side-menu-always-displayed body {
- position: absolute;
- left: 50px;
+ position: absolute;
+ left: 50px;
}
.side-menu-always-displayed #side-menu {
- display: block;
+ display: block;
}
.side-menu-always-displayed .side-menu-apps-list {
- height: calc(100vh - 49px);
- top: 49px;
- overflow: hidden;
+ height: calc(100vh - 49px);
+ top: 49px;
+ overflow: hidden;
}
.side-menu-always-displayed .side-menu-apps-list:hover {
- overflow: auto;
+ overflow: auto;
}
.side-menu-always-displayed #side-menu,
.side-menu-always-displayed .side-menu-header,
.side-menu-always-displayed .side-menu-apps-list {
- width: 50px;
+ width: 50px;
}
.side-menu-always-displayed #side-menu .side-menu-app-text,
.side-menu-always-displayed #header .side-menu-opener,
.side-menu-always-displayed .side-menu-logo {
- display: none;
+ display: none;
}
.side-menu-always-displayed #side-menu .side-menu-header {
- height: 49px;
+ height: 49px;
}
.side-menu-always-displayed #side-menu.open,
.side-menu-always-displayed #side-menu.open .side-menu-apps-list,
.side-menu-always-displayed #side-menu.open .side-menu-header {
- width: 100%;
+ width: 100%;
}
.side-menu-always-displayed #side-menu.open .side-menu-app-text {
- display: inline;
+ display: inline;
}
.side-menu-always-displayed .app-navigation--close {
- transform: translateX(calc(-100% + 50px)) !important;
+ transform: translateX(calc(-100% + 50px)) !important;
}
#side-menu.side-menu-with-categories {
- max-width: 290px;
- height: 100vh;
+ max-width: 290px;
+ height: 100vh;
}
.side-menu-with-categories .side-menu-categories {
- display: block;
- padding: 0;
+ display: block;
+ padding: 0;
}
.side-menu-with-categories .side-menu-category {
- padding: 10px 0;
+ padding: 10px 0;
}
.side-menu-always-displayed #body-settings, #body-settings.body-settings-side-menu {
- overflow-x: visible;
+ overflow-x: visible;
+}
+
+.app-menu {
+ visibility: hidden;
+}
+
+.app-menu.show {
+ visibility: visible;
}
@media screen and (max-width: 1024px) {
- #side-menu.side-menu-big {
- max-width: 290px;
- height: 100vh;
- }
+ #side-menu.side-menu-big {
+ max-width: 290px;
+ height: 100vh;
+ }
- .side-menu-categories {
- display: block;
- padding: 0;
- }
+ .side-menu-categories {
+ display: block;
+ padding: 0;
+ }
- .side-menu-category {
- padding: 10px 0;
- }
+ .side-menu-category {
+ padding: 10px 0;
+ }
}
@media screen and (min-width: 1024px) {
- .side-menu-closer {
- display: block;
- float: right;
- margin-right: 9px;
- }
+ .side-menu-closer {
+ display: block;
+ float: right;
+ margin-right: 9px;
+ }
- .side-menu-big .side-menu-header {
- max-width: 100%;
- }
+ .side-menu-big .side-menu-header {
+ max-width: 100%;
+ }
}
diff --git a/package.json b/package.json
index fb7e755..c71a094 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,6 @@
"stylelint:fix": "stylelint src --fix"
},
"dependencies": {
- "@nextcloud/axios": "^1.8.0",
- "@nextcloud/vue": "^1.5.0",
"axios": "^0.24.0",
"trim": "^1.0.1",
"vue": "^2.6.11"
@@ -24,6 +22,10 @@
"node": ">=16.0.0"
},
"devDependencies": {
+ "@nextcloud/axios": "^1.8.0",
+ "@nextcloud/initial-state": "^2.0.0",
+ "@nextcloud/l10n": "^1.6.0",
+ "@nextcloud/vue": "^1.5.0",
"@babel/core": "^7.9.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.0",
diff --git a/src/AppMenu.vue b/src/AppMenu.vue
new file mode 100644
index 0000000..c63a3bf
--- /dev/null
+++ b/src/AppMenu.vue
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SideMenu.js b/src/SideMenu.js
index a9848c4..244a6cf 100644
--- a/src/SideMenu.js
+++ b/src/SideMenu.js
@@ -16,35 +16,51 @@
*/
import Vue from 'vue'
+import AppMenu from './AppMenu.vue'
import SideMenu from './SideMenu.vue'
import SideMenuBig from './SideMenuBig.vue'
import SideMenuWithCategories from './SideMenuWithCategories.vue'
Vue.prototype.OC = OC
+Vue.prototype.t = OC.L10N.translate
const mountSideMenuComponent = () => {
- const sideMenuContainer = document.querySelector('#side-menu')
+ const container = document.querySelector('#side-menu')
- if (sideMenuContainer) {
- let component
+ if (!container) {
+ return window.setTimeout(mountSideMenuComponent, 50)
+ }
- if (sideMenuContainer.getAttribute('data-bigmenu')) {
- component = SideMenuBig
- } else if(sideMenuContainer.getAttribute('data-sidewithcategories')) {
- component = SideMenuWithCategories
- } else {
- component = SideMenu
- }
-
- const View = Vue.extend(component)
- const sideMenu = new View({})
-
- sideMenu.$mount('#side-menu')
-
- document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.ready'))
+ const component = (() => {
+ if (container.getAttribute('data-bigmenu')) {
+ return SideMenuBig
+ } else if(container.getAttribute('data-sidewithcategories')) {
+ return SideMenuWithCategories
} else {
- window.setTimeout(mountSideMenuComponent, 50)
+ return SideMenu
}
+ })()
+
+ const View = Vue.extend(component)
+ const App = new View({})
+
+ App.$mount('#side-menu')
+
+ document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.ready'))
+}
+
+const mountAppMenu = () => {
+ const container = document.querySelector('#header .app-menu')
+
+ if (!container) {
+ return window.setTimeout(mountAppMenu, 50)
+ }
+
+ const View = Vue.extend(AppMenu)
+ const App = new View({})
+
+ App.$mount('#header .app-menu')
}
mountSideMenuComponent()
+mountAppMenu()
diff --git a/templates/js/_topMenuApps.js b/templates/js/_topMenuApps.js
deleted file mode 100644
index 455b09a..0000000
--- a/templates/js/_topMenuApps.js
+++ /dev/null
@@ -1,216 +0,0 @@
-let menuCache = null
-
-const breakpointMobileWidth = 1024
-const usePercentualAppMenuLimit = 0.8
-const minAppsDesktop = 8
-
-const handleMenuClick = (e, icon) => {
- let element = e.target
-
- while (element.tagName !== 'LI') {
- element = element.parentNode
- }
-
- const a = querySelector('a', element)
-
- if (a.getAttribute('target') !== '_blank' && e.which === 1 && !e.ctrlKey && !e.metaKey) {
- for (let tag of ['svg', 'div']) {
- let el = querySelector(tag, element)
-
- if (el) {
- el.remove()
- }
- }
-
- const loader = createElement('div', {'class': icon})
-
- a.insertBefore(loader, querySelector('span', a))
- }
-}
-
-const updateTopMenu = function() {
- const isMobile = window.innerWidth < breakpointMobileWidth
- const menu = querySelector('#appmenu')
- const moreApps = querySelector('#more-apps')
- const navigation = querySelector('#navigation')
- const navigationApps = querySelector('#apps ul')
-
- let apps = querySelectorAll('li', menu)
- let lastShownApp = null
- let appShown = []
-
- if ((menu.innerHTML + menu.nextSibling.innerHTML) === menuCache) {
- return
- }
-
- let navigationAppsHtml = ''
-
- for (let app of apps) {
- const dataId = app.getAttribute('data-id')
-
- if (dataId === null) {
- continue
- }
-
- if (topMenuApps.indexOf(dataId) === -1 && topSideMenuApps.indexOf(dataId) === -1) {
- app.classList.add('hidden')
- app.classList.add('app-hidden')
- } else {
- app.classList.remove('hidden')
- app.classList.add('app-external-site')
-
- if (topSideMenuApps.indexOf(dataId) !== -1) {
- app.classList.add('app-top-side-menu')
- }
-
- appShown.push(app)
-
- navigationAppsHtml = navigationAppsHtml + app.outerHTML
- }
-
- if (targetBlankApps.indexOf(dataId) !== -1) {
- querySelector('a', app).setAttribute('target', '_blank')
- }
- }
-
- navigationApps.innerHTML = navigationAppsHtml
-
- const rightHeaderWidth = querySelector('.header-right').offsetWidth
- const headerWidth = querySelector('header').offsetWidth
-
- let availableWidth = headerWidth
-
- availableWidth -= nextcloud.offsetWidth
- availableWidth -= querySelector('#header .side-menu-opener').offsetWidth
- availableWidth -= rightHeaderWidth > 230 ? rightHeaderWidth : 230
- availableWidth *= isMobile ? usePercentualAppMenuLimit : 1
-
- let appCount = Math.floor(availableWidth / querySelector('#appmenu li:not(.hidden)').offsetWidth)
-
- if (isMobile && appCount > minAppsDesktop) {
- appCount = minAppsDesktop
- } else if (!isMobile && appCount < minAppsDesktop) {
- appCount = minAppsDesktop
- }
-
- menu.style.opacity = 1
-
- if (appShown.length - 1 - appCount >= 1) {
- appCount--
- }
-
- for (let item of querySelectorAll('a', moreApps)) {
- item.classList.remove('active')
- }
-
- let k = 0
- let notInHeader = 0
-
- for (let app of appShown) {
- const name = app.getAttribute('data-id')
- const li = querySelector('#apps li[data-id=' + name + '].app-external-site')
-
- if (k < appCount && appCount > 0) {
- app.classList.remove('hidden')
- li.classList.add('in-header')
-
- lastShownApp = app
- } else {
- app.classList.add('hidden')
- li.classList.remove('in-header')
-
- notInHeader++
-
- const a = querySelector('a', app)
-
- if (appCount > 0 && a.classList.contains('active')) {
- lastShownApp.classList.add('hidden')
- app.classList.remove('hidden')
- notInHeader++
-
- li.classList.add('in-header')
- }
- }
-
- k++
- }
-
- // Hack for:
- // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119
- // - https://github.com/nextcloud/server/blob/master/core/src/components/MainMenu.js#L97-L119
- jQuery(menu).undelegate('li:not(#more-apps) > a', 'click')
- jQuery(navigation).undelegate('a', 'click')
-
- const confs = [
- {
- items: querySelectorAll('#navigation li'),
- icon: 'icon-loading-small'
- },
- {
- items: querySelectorAll('li:not(#more-apps)', menu),
- icon: OCA.Theming && OCA.Theming.inverted ? 'icon-loading-small' : 'icon-loading-small-dark'
- },
- ]
-
- for (let conf of confs) {
- for (let item of conf.items) {
- item.addEventListener('click', (e) => {
- handleMenuClick(e, conf.icon)
- })
- }
- }
-
- for (let app of querySelectorAll('#apps li.app-external-site')) {
- const appId = app.getAttribute('data-id')
-
- if (app.classList.contains('in-header')) {
- for (let defs of querySelectorAll('svg defs', app)) {
- defs.remove()
- }
- } else {
- const svg = querySelector('svg', app)
-
- if (querySelectorAll('svg defs', app).length > 0) {
- continue
- }
-
- const defs = `
-
-
- `
-
- svg.innerHTML = defs + svg.innerHTML
-
- for (let image of querySelectorAll('image', svg)) {
- image.setAttribute('filter', `url(#invertMenuMore-${appId})`)
- }
-
- svg.innerHTML = svg.innerHTML.replace(/fecolormatrix/g, 'feColorMatrix')
- }
- }
-
- if (notInHeader === 0) {
- moreApps.style.display = 'none'
- navigation.style.display = 'none'
- } else {
- moreApps.style.display = 'flex'
- }
-
- menuCache = menu.innerHTML + menu.nextSibling.innerHTML
-}
-
-for (let i = 0; i < 4000; i+= 100) {
- setTimeout(updateTopMenu, i)
-}
-
-let resizeTimeout = null;
-
-window.addEventListener('resize', () => {
- if (resizeTimeout !== null) {
- clearTimeout(resizeTimeout)
- }
-
- resizeTimeout = setTimeout(updateTopMenu, 100)
-})
diff --git a/templates/js/script.php b/templates/js/script.php
index f62b7da..1c04466 100644
--- a/templates/js/script.php
+++ b/templates/js/script.php
@@ -203,12 +203,8 @@ if ($_['always-displayed']) {
nextcloud.parentNode.insertBefore(sideMenuOpener, nextcloud.nextSibling)
-
- const topMenuApps =
- const topSideMenuApps =
-
-
-
+ window.topMenuApps =
+ window.topSideMenuApps =