diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 42afdfc..0b9fd24 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -123,14 +123,14 @@ class Application extends App implements IBootstrap
//Util::addStyle(self::APP_ID, 'sideMenu');
$assets = [
- // 'stylesheet' => [
- // 'route' => 'side_menu.Css.stylesheet',
- // 'type' => 'link',
- // 'route_attr' => 'href',
- // 'attr' => [
- // 'rel' => 'stylesheet',
- // ],
- // ],
+ 'stylesheet' => [
+ 'route' => 'side_menu.Css.stylesheet',
+ 'type' => 'link',
+ 'route_attr' => 'href',
+ 'attr' => [
+ 'rel' => 'stylesheet',
+ ],
+ ],
// 'script' => [
// 'route' => 'side_menu.Js.script',
// 'type' => 'script',
diff --git a/lib/Controller/JsController.php b/lib/Controller/JsController.php
index 8f06345..68cf330 100644
--- a/lib/Controller/JsController.php
+++ b/lib/Controller/JsController.php
@@ -145,6 +145,8 @@ class JsController extends Controller
'opener-hover' => $this->config->getAppValueBool('opener-hover', '0'),
'external-sites-in-top-menu' => $this->config->getAppValueBool('external-sites-in-top-menu', '0'),
'force-light-icon' => $this->config->getAppValueBool('force-light-icon', '0'),
+ 'display-logo' => $this->config->getAppValueBool('display-logo', '1'),
+ 'use-avatar' => $this->config->getAppValueBool('use-avatar', '0'),
'hide-when-no-apps' => $this->config->getAppValueBool('hide-when-no-apps', '0'),
'loader-enabled' => $this->config->getAppValueBool('loader-enabled', '1'),
'always-displayed' => $this->config->getAppValueBool('always-displayed', '0'),
diff --git a/lib/Controller/NavController.php b/lib/Controller/NavController.php
index 1d90849..e2bdef4 100644
--- a/lib/Controller/NavController.php
+++ b/lib/Controller/NavController.php
@@ -115,6 +115,7 @@ class NavController extends Controller
$appsCategories[$app['id']][] = $category;
$items[$category]['apps'][$app['id']] = [
+ 'id' => $app['id'],
'name' => $app['name'],
'href' => $app['href'],
'icon' => $app['icon'],
diff --git a/package.json b/package.json
index fb48ac4..c34ca5e 100644
--- a/package.json
+++ b/package.json
@@ -10,10 +10,12 @@
"format": "./node_modules/.bin/prettier src --write"
},
"dependencies": {
+ "@babel/core": ">=7.12.0 <8.0.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/vue": "^9.0.0-alpha.8",
"node-polyfill-webpack-plugin": "^4.1.0",
"pinia": "^3.0.1",
+ "postcss": "^7.0.0 || ^8.0.1",
"vue": "^3.5.13"
},
"browserslist": [
diff --git a/src/admin.js b/src/admin.js
index d79ea98..cf5e607 100644
--- a/src/admin.js
+++ b/src/admin.js
@@ -8,268 +8,25 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*/
+import './scss/admin.scss'
+
import { createApp } from 'vue'
-import AdminCategoriesCustom from './components/AdminCategoriesCustom.vue'
+import { createPinia } from 'pinia'
+import { waitContainer } from './lib/dom.js'
-let elements = []
+import AdminSettings from './pages/AdminSettings.vue'
-const selector = '#side-menu-message'
-
-const userConfig = (name, value, callbacks) => {
- const url = OC.generateUrl('/apps/side_menu/personalSetting/valueSet')
- const formData = []
-
- formData.push('name=' + encodeURIComponent(name))
- formData.push('value=' + encodeURIComponent(value))
-
- fetch(url, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- body: formData.join('&'),
- })
- .then(callbacks.success)
- .catch(callbacks.error)
-}
-
-const appConfig = (name, value, callbacks) => {
- OCP.AppConfig.setValue('side_menu', name, value, callbacks)
-}
-
-const saveSettings = (key) => {
- const element = elements[key]
-
- if (!element) {
- return
- }
-
- let value
- let name
-
- if (element.hasAttribute('data-checkbox')) {
- name = element.getAttribute('data-name')
- value = []
-
- const inputs = document.querySelectorAll('input[name="' + name + '[]"]:checked')
-
- for (let input of inputs) {
- value.push(input.value)
- }
-
- value = JSON.stringify(value)
- } else {
- name = element.getAttribute('name')
- value = element.value
- }
-
- const size = elements.length
-
- if (name === 'cache') {
- ++value
- }
-
- const progress = document.querySelector('#side-menu-save-progress')
-
- progress.style.width = '40px'
- progress.style.marginLeft = '5px'
-
- const callbacks = {
- success: () => {
- const percent = parseInt(((key + 1) * 100) / size)
-
- progress.setAttribute('value', percent)
-
- if (key < size - 1) {
- saveSettings(key + 1)
- } else {
- location.reload()
- }
- },
- error: () => {
- OC.msg.finishedError(selector, t('side_menu', 'Error while saving "' + element + '"'))
- },
- }
-
- if (element.hasAttribute('data-personal')) {
- userConfig(name, value, callbacks)
- } else {
- appConfig(name, value, callbacks)
- }
-}
-
-const elementToggler = (element) => {
- let display = 'none'
-
- if (window.getComputedStyle(element).display === 'none') {
- display = 'block'
- }
-
- element.style.display = display
-}
-
-const updateAppsCategoriesCustom = () => {
- let values = {}
-
- for (let item of document.querySelectorAll('.apps-categories-custom')) {
- let app = item.getAttribute('data-app')
- let value = item.value
-
- if (value) {
- values[app] = value
- }
- }
-
- document.querySelector('#apps-categories-custom').value = JSON.stringify(values)
-}
-
-document.addEventListener('DOMContentLoaded', () => {
- $('*[data-toggle="tooltip"]').tooltip()
-
- if (document.querySelector('#side-menu-categories-custom')) {
- const app = createApp(AdminCategoriesCustom)
- app.mount('#side-menu-categories-custom')
- }
-
- elements = document.querySelectorAll('.side-menu-setting')
-
- document.querySelector('#side-menu-save').addEventListener('click', (event) => {
- event.preventDefault()
- OC.msg.startSaving(selector)
-
- saveSettings(0)
- })
-
- const resets = document.querySelectorAll('.btn-reset')
-
- for (let btn of resets) {
- btn.addEventListener('click', (event) => {
- const target = event.target
- const values = JSON.parse(target.getAttribute('data-reset'))
-
- target.classList.toggle('btn-reset--progress', true)
-
- for (let i in values) {
- document.querySelector(`#${i}`).value = values[i]
- }
-
- window.setTimeout(() => {
- target.classList.toggle('btn-reset--progress', false)
- }, 800)
- })
- }
-
- const displays = document.querySelectorAll('.side-menu-display')
-
- for (let display of displays) {
- display.addEventListener('click', (event) => {
- const target = event.target
-
- for (let d of displays) {
- d.classList.toggle('is-active', d === display)
- }
-
- document.querySelector('#side-menu-always-displayed').value = target.getAttribute('data-alwaysdiplayed')
- document.querySelector('#side-menu-big-menu').value = target.getAttribute('data-bigmenu')
- document.querySelector('#side-menu-side-with-categories').value = target.getAttribute('data-sidewithcategories')
- })
- }
-
- for (let item of document.querySelectorAll('.apps-categories-custom')) {
- item.addEventListener('change', (event) => {
- updateAppsCategoriesCustom()
- })
- }
-
- for (let item of document.querySelectorAll('.side-menu-setting-live')) {
- item.addEventListener('change', (event) => {
- const target = event.target
- const name = target.getAttribute('name')
-
- let value = target.value
- let id = null
-
- if (name === 'background-color-opacity') {
- id = '#side-menu-background-color, #side-menu-background-color-to'
- } else if (name === 'dark-mode-background-color-opacity') {
- id = '#side-menu-dark-mode-background-color, #side-menu-dark-mode-background-color-to'
- }
-
- if (id) {
- document.querySelector(id).dispatchEvent(new CustomEvent('change'))
-
- return
- }
-
- if (name === 'opener') {
- const url = OC.generateUrl(`/apps/side_menu/img/${value}.svg`).replace('/index.php', '')
-
- value = `url(${url})`
- }
-
- if (name === 'icon-invert-filter' || name === 'icon-opacity') {
- value /= 100
- }
-
- if (['dark-mode-background-color', 'dark-mode-background-color-to'].indexOf(name) > -1) {
- const opacity = parseInt((document.querySelector('#side-menu-dark-mode-background-color-opacity').value * 255) / 100)
-
- value = [value, opacity.toString(16)].join('')
- } else if (['background-color', 'background-color-to'].indexOf(name) > -1) {
- const opacity = parseInt((document.querySelector('#side-menu-background-color-opacity').value * 255) / 100)
-
- value = [value, opacity.toString(16)].join('')
- }
-
- document.documentElement.style.setProperty('--side-menu-' + name, value)
- })
- }
-
- for (let toggler of document.querySelectorAll('.side-menu-toggler')) {
- toggler.addEventListener('click', (event) => {
- const target = event.target
- const element = document.querySelector(target.getAttribute('data-target'))
-
- elementToggler(element)
- })
- }
-
- sortable('#categories-list .side-menu-setting-list', {
- placeholderClass: 'side-menu-setting-list-drop',
- })
-
- try {
- sortable('#categories-list .side-menu-setting-list')[0].addEventListener('sortstop', (e) => {
- let value = []
-
- for (let item of document.querySelectorAll('#categories-list .side-menu-setting-list-item')) {
- value.push(item.getAttribute('data-id'))
- }
-
- document.querySelector('input[name="categories-order"]').value = JSON.stringify(value)
- })
- } catch (e) {}
-
- sortable('#apps-order-list .side-menu-setting-list', {
- placeholderClass: 'side-menu-setting-list-drop',
- })
-
- try {
- sortable('#apps-order-list .side-menu-setting-list')[0].addEventListener('sortstop', (e) => {
- let value = []
-
- for (let item of document.querySelectorAll('#apps-order-list .side-menu-setting-list-item')) {
- value.push(item.getAttribute('data-id'))
- }
-
- document.querySelector('input[name="apps-order"]').value = JSON.stringify(value)
- })
- } catch (e) {}
+waitContainer('#side-menu-admin-settings').then((selector) => {
+ const pinia = createPinia()
+ const app = createApp(AdminSettings)
+ app.use(pinia)
+ app.mixin({ methods: { t, n }})
+ app.mount(selector)
})
diff --git a/src/components/AdminCategoriesCustom.vue b/src/components/AdminCategoriesCustom.vue
index 407ae06..c9259ff 100644
--- a/src/components/AdminCategoriesCustom.vue
+++ b/src/components/AdminCategoriesCustom.vue
@@ -102,101 +102,92 @@ along with this program. If not, see .
-
+
+
diff --git a/src/scss/admin.scss b/src/scss/admin.scss
index 911b939..fafdd14 100644
--- a/src/scss/admin.scss
+++ b/src/scss/admin.scss
@@ -114,6 +114,7 @@
.side-menu-setting-table {
display: table;
width: 100%;
+ padding: 10px;
}
.side-menu-setting-row {
@@ -141,6 +142,10 @@
vertical-align: top;
}
+.side-menu-setting-label--middle {
+ vertical-align: middle;
+}
+
.side-menu-setting-form {
display: table-cell;
min-width: 300px;
@@ -218,3 +223,23 @@
border-color: #c681d4;
color: #fff;
}
+
+.side-menu-setting {
+ padding: 10px;
+ display: flex;
+ gap: 12px;
+}
+
+.side-menu-setting-color-picker {
+ display: inline-block;
+ margin-right: 12px;
+ width: 60px;
+ height: 30px;
+
+ &-value {
+ cursor: pointer;
+ width: 60px;
+ height: 30px;
+ border-radius: 6px;
+ }
+}
diff --git a/src/scss/menu.scss b/src/scss/menu.scss
index 9e8c749..c1dd6cf 100644
--- a/src/scss/menu.scss
+++ b/src/scss/menu.scss
@@ -41,12 +41,40 @@
display: block;
}
}
+
+ .side-menu-opener {
+ margin-top: 1px !important;
+ }
+
+ &.side-menu-big {
+ max-width: 100%;
+ height: auto;
+ }
+
+ &.side-menu-with-categories {
+ max-width: 290px;
+ height: 100vh;
+
+ .side-menu-categories {
+ display: block;
+ padding: 0;
+ width: 100%;
+ }
+
+ .side-menu-category {
+ padding: 10px 0;
+ }
+ }
+
+ &.side-menu-big, &.side-menu-with-categories {
+ height: auto;
+ }
}
#header {
.side-menu-opener {
margin-left: 0px;
- margin-top: -1px;
+ margin-top: 0px;
}
}
@@ -111,20 +139,19 @@
display: none;
}
-#side-menu.hide-opener .side-menu-opener,
-.side-menu-opener.hide,
-#side-menu.hide {
- display: none !important;
-}
-
.side-menu-apps-list {
- height: calc(100vh - 150px);
+ height: calc(100vh - 49px);
+ top: 49px;
z-index: 2200;
position: fixed;
- top: 150px;
width: 100%;
max-width: 290px;
overflow: auto;
+
+ &.side-menu-apps-list--with-logo {
+ height: calc(100vh - 160px);
+ top: 160px;
+ }
}
.side-menu-app-icon {
@@ -149,7 +176,8 @@
a:hover,
a:focus,
- &:active {
+ &:active,
+ &.active {
background: var(--side-menu-current-app-background-color, #444);
}
}
@@ -165,7 +193,6 @@
}
.side-menu-header {
- height: 150px;
width: 100%;
z-index: 2300;
max-width: 290px;
@@ -183,10 +210,6 @@
max-width: 295px;
}
-#side-menu.hide-opener .side-menu-logo {
- margin-top: 10px;
-}
-
#side-menu-loader {
position: fixed;
top: 0;
@@ -202,28 +225,24 @@
}
}
-#side-menu.side-menu-big,
-#side-menu.side-menu-with-categories {
- max-width: 100%;
- height: auto;
-}
+.side-menu-big, .side-menu-with-categories {
+ .side-menu-apps-list {
+ height: auto;
+ position: static;
+ max-width: 100vw;
+ overflow: auto;
+ }
-.side-menu-big .side-menu-header,
-.side-menu-with-categories .side-menu-header {
- height: auto;
-}
+ .side-menu-app {
+ a {
+ padding: 7px 0 7px 7px;
+ }
+ }
-.side-menu-big .side-menu-apps-list,
-.side-menu-with-categories .side-menu-apps-list {
- 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;
+ .side-menu-app-icon {
+ vertical-align: middle;
+ margin-top: -2px;
+ }
}
.side-menu-categories-wrapper {
@@ -265,11 +284,6 @@
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;
-}
.side-menu-always-displayed {
body {
@@ -287,12 +301,6 @@
}
.side-menu-apps-list {
- height: 100vh;
- top: 0;
- overflow: hidden;
- }
-
- .side-menu-apps-list--with-settings {
height: calc(100vh - 49px);
top: 49px;
}
@@ -331,32 +339,6 @@
right: 0 !important;
margin-left: 0 !important;
}
-
- .side-menu-search {
- display: none;
- }
-
- #body-settings,
- #body-settings.body-settings-side-menu {
- overflow-x: visible;
- }
-}
-
-#side-menu.side-menu-with-categories {
- max-width: 290px;
- height: 100vh;
-}
-
-.side-menu-with-categories {
- .side-menu-categories {
- display: block;
- padding: 0;
- width: 100%;
- }
-
- .side-menu-category {
- padding: 10px 0;
- }
}
.app-menu {
@@ -390,10 +372,6 @@
height: 100vh;
}
- #side-menu.hide-opener.side-menu-big .side-menu-search {
- float: none;
- }
-
.side-menu-categories {
display: block;
padding: 0;
diff --git a/templates/css/stylesheet.php b/templates/css/stylesheet.php
index 5638629..0909b77 100644
--- a/templates/css/stylesheet.php
+++ b/templates/css/stylesheet.php
@@ -8,65 +8,28 @@
}
-
- #appmenu {
- display: none;
- }
-
- #appmenu + nav {
- display: none;
- }
-
- .app-hidden {
- opacity: 0;
- }
-
-
#nextcloud {
display: none;
}
-
- .side-menu-logo {
- display: none;
+
+ #side-menu, .side-menu-apps-list {
+
+ width: 55px;
+
+ width: 52px;
+
}
- .side-menu-header {
- height: 50px;
+ #side-menu .side-menu-opener {
+
+ margin-left: 1px;
+
+ margin-left: 0px;
+
}
-
- .side-menu-apps-list {
- height: calc(100vh - 49px);
- top: 49px;
- }
-
- #side-menu.hide-opener .side-menu-header .side-menu-opener.side-menu-closer {
- visibility: hidden;
- }
-
- #side-menu.hide-opener.side-menu-with-categories .side-menu-search {
- float: none;
- }
-
-
- #side-menu, .side-menu-apps-list {
-
- width: 55px;
-
- width: 52px;
-
- }
-
- #side-menu .side-menu-opener {
-
- margin-left: 1px;
-
- margin-left: 0px;
-
- }
-
diff --git a/templates/js/script.php b/templates/js/script.php
deleted file mode 100644
index 6550507..0000000
--- a/templates/js/script.php
+++ /dev/null
@@ -1,42 +0,0 @@
- {
- let a = document.querySelector('#side-menu .side-menu-app.active a')
- || document.querySelector('#side-menu .side-menu-app a')
-
- if (a) {
- a.focus()
- }
- }
-
- document.querySelector('body').addEventListener('side-menu.apps', (e) => {
- const apps = e.detail.apps;
- })
-
- body.addEventListener('side-menu.ready', () => {
- const sideMenu = document.querySelector('#side-menu')
-
-
- const sideMenuObserver = new MutationObserver((e) => {
- if (body.getAttribute('id') !== 'body-settings') {
- return
- }
-
- body.classList.toggle('body-settings-side-menu', sideMenu.classList.contains('open'))
- })
-
- sideMenuObserver.observe(sideMenu, {
- attributes: true,
- attributeFilter: ['class'],
- childList: false,
- characterData: false
- })
- })
-})();
diff --git a/templates/settings/admin-form.php b/templates/settings/admin-form.php
index 1053b04..9666f08 100644
--- a/templates/settings/admin-form.php
+++ b/templates/settings/admin-form.php
@@ -20,1130 +20,7 @@ use OCP\IURLGenerator;
use OCP\IConfig;
use OCA\SideMenu\AppInfo\Application;
-vendor_script('side_menu', 'html5sortable.min');
-script('side_menu', 'admin');
-style('side_menu', 'admin');
-
-$urlGenerator = \OC::$server[IURLGenerator::class];
-$cacheSize = floor(mb_strlen(\OC::$server[IConfig::class]->getAppValue(Application::APP_ID, 'cache-categories', ''), '8bit') / 1024);
-
-$choicesYesNo = [
- 'No' => '0',
- 'Yes' => '1',
-];
-
-$choicesSizes = [
- 'Hidden' => 'hidden',
- 'Small' => 'small',
- 'Normal' => 'normal',
- 'Big' => 'big',
-];
-
-$labelShowHideApps = 'Show and hide the list of applications';
-$labelReset = 'Reset to default';
-$labelDefault = 'Default';
-$labelWithCategories = 'With categories';
-$labelBigMenu = 'Big menu';
-$labelAlwaysDisplayed = 'Always displayed';
-
+script('side_menu', 'side_menu-admin');
?>
-
+
diff --git a/templates/settings/admin-form.php.bk b/templates/settings/admin-form.php.bk
new file mode 100644
index 0000000..492b8df
--- /dev/null
+++ b/templates/settings/admin-form.php.bk
@@ -0,0 +1,1148 @@
+.
+ */
+
+use OCP\IURLGenerator;
+use OCP\IConfig;
+use OCA\SideMenu\AppInfo\Application;
+
+vendor_script('side_menu', 'html5sortable.min');
+script('side_menu', 'side_menu-admin');
+
+$urlGenerator = \OC::$server[IURLGenerator::class];
+$cacheSize = floor(mb_strlen(\OC::$server[IConfig::class]->getAppValue(Application::APP_ID, 'cache-categories', ''), '8bit') / 1024);
+
+$choicesYesNo = [
+ 'No' => '0',
+ 'Yes' => '1',
+];
+
+$choicesSizes = [
+ 'Hidden' => 'hidden',
+ 'Small' => 'small',
+ 'Normal' => 'normal',
+ 'Big' => 'big',
+];
+
+$labelShowHideApps = 'Show and hide the list of applications';
+$labelReset = 'Reset to default';
+$labelDefault = 'Default';
+$labelWithCategories = 'With categories';
+$labelBigMenu = 'Big menu';
+$labelAlwaysDisplayed = 'Always displayed';
+
+?>
+
diff --git a/webpack.config.js b/webpack.config.js
index c9ca6de..e971ab1 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -16,7 +16,7 @@ module.exports = {
devtool: "inline-source-map",
entry: {
menu: path.resolve(path.join('src', 'menu.js')),
- // admin: path.resolve(path.join('src', 'admin.js')),
+ admin: path.resolve(path.join('src', 'admin.js')),
},
output: {
path: path.resolve('./js'),
diff --git a/webpack.rules.js b/webpack.rules.js
index 101f29b..4314a8f 100644
--- a/webpack.rules.js
+++ b/webpack.rules.js
@@ -3,6 +3,10 @@ module.exports = {
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
+ css: {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader'],
+ },
vue: {
test: /\.vue$/,
loader: 'vue-loader',