Compare commits

...

115 Commits

Author SHA1 Message Date
Simon Vieille 2fc9a4effe update translations 2020-08-29 14:46:04 +02:00
Simon Vieille 6a5ecfa115 add translations: de 2020-08-29 14:30:46 +02:00
Simon Vieille aab26bad32 add documentation 2020-08-29 14:04:52 +02:00
Simon Vieille f3e657dcdb add gitignore 2020-08-29 14:04:45 +02:00
Simon Vieille e1ca610256 update release task 2020-08-28 20:17:58 +02:00
Simon Vieille acf2022938 update release task 2020-08-28 20:13:10 +02:00
Simon Vieille 707dbf6810 indentation 2020-08-28 17:30:08 +02:00
Simon Vieille f8dd123851 indentation 2020-08-28 17:29:03 +02:00
Simon Vieille 518f4bb70c update documentation 2020-08-28 17:28:12 +02:00
Simon Vieille c8b3258819 update update 2020-08-28 17:28:03 +02:00
Simon Vieille 186ee4d344 add Makefile 2020-08-28 17:11:12 +02:00
Simon Vieille 64ee6fb223 add gitignore 2020-08-28 17:09:24 +02:00
Simon Vieille c2662cdaae Merge branch 'feature/translations' into develop 2020-08-28 16:46:45 +02:00
Simon Vieille d3ee4120c9 add gitignore 2020-08-28 16:46:38 +02:00
Simon Vieille 4fd11f2deb add l10n generators and fr translations 2020-08-28 16:45:19 +02:00
Simon Vieille 72dc0c7d01 update forms to handle translations 2020-08-28 16:45:02 +02:00
Simon Vieille 8c38382eae remove l10n files 2020-08-28 16:44:36 +02:00
Simon Vieille 1567a8e82f fix #28: menu items invisible after 1.8.4 2020-08-25 19:06:01 +02:00
Simon Vieille e1ae5d21e2 add compatibility with NC 20 2020-08-25 13:33:02 +02:00
Simon Vieille 4370738625 fix #27: disable side menu on public pages - broken in 1.8.3 2020-08-25 12:18:39 +02:00
Simon Vieille acdd299573 release v1.8.3 2020-08-20 16:29:41 +02:00
Simon Vieille fae21390dd fix #26: alphabetic order of apps 2020-08-20 16:27:35 +02:00
Simon Vieille 4f0fdd91f9 release v1.8.2 2020-08-19 11:44:05 +02:00
Simon Vieille d084cfed86 fix #25: Icon x for closing the big menu 2020-08-19 11:41:10 +02:00
Simon Vieille 3db0c1ccd2 fix #23: hidden icons in the top menu 2020-08-19 11:29:21 +02:00
Simon Vieille e4f9765247 fix #24: missing apps 2020-08-19 09:18:29 +02:00
Simon Vieille e7d319bbf7 fix 't.apps is not iterable' 2020-08-18 14:39:45 +02:00
Simon Vieille cf0f459aeb release v1.8.1 2020-08-14 13:31:13 +02:00
Simon Vieille b5ce8b92e1 fix issue with links 2020-08-14 13:30:48 +02:00
Simon Vieille 39aede4a73 release v1.8.0 2020-08-13 23:15:03 +02:00
Simon Vieille d9ea37ba62 fix cache and config key 2020-08-13 23:02:28 +02:00
Simon Vieille aad3038003 admin ui, remove debugging code 2020-08-13 22:24:41 +02:00
Simon Vieille 011d24d3bd add icon opacity 2020-08-13 22:07:09 +02:00
Simon Vieille 9eec0ce3ef add icon color filter range 2020-08-13 21:22:10 +02:00
Simon Vieille 831d2d81fc add documentation 2020-08-13 16:51:41 +02:00
Simon Vieille c6a43f755d fix issue with empty cat 2020-08-13 16:33:05 +02:00
Simon Vieille d30603c7d1 update the big-menu size when screen < 1024px 2020-08-13 16:13:31 +02:00
Simon Vieille aa9ba60680 fix issue with the classic display 2020-08-13 13:05:38 +02:00
Simon Vieille d3b7b99aae Merge branch 'feature/issue22-favorite-apps' into develop 2020-08-13 11:34:43 +02:00
Simon Vieille 3a431f16e7 release v1.8.0-rc1 2020-08-13 11:34:40 +02:00
Simon Vieille e4abc5b43f add PSR 2 compliance 2020-08-13 11:21:59 +02:00
Simon Vieille ef72c00fbb fix translations 2020-08-13 11:21:06 +02:00
Simon Vieille e1c6784d41 update visible apps order 2020-08-12 16:32:26 +02:00
Simon Vieille 3f2a307226 refactoring 2020-08-12 16:27:43 +02:00
Simon Vieille deca4b2cba fix issue with 'top-menu-apps' 2020-08-12 16:16:50 +02:00
Simon Vieille a1b1396b63 add add top-menu-apps option in the personal settings 2020-08-12 15:59:51 +02:00
Simon Vieille 9d9afff08d fix compatibility with the option 'hide-when-no-apps' 2020-08-12 14:06:52 +02:00
Simon Vieille ffab77aff2 add options to select apps that must be displayed in the top menu (replace exteral sites option) 2020-08-12 10:51:49 +02:00
Simon Vieille caa9c092ef add external links 2020-08-11 15:52:15 +02:00
Simon Vieille 8aa08dbc6b add compatibility with basic side menu options 2020-08-11 15:26:40 +02:00
Simon Vieille 460dac5faf update admin and personal pages 2020-08-11 15:26:17 +02:00
Simon Vieille ce5c806524 update ui of the big menu, add 'files' app 2020-08-11 13:34:36 +02:00
Simon Vieille 307f69906b add links 2020-08-11 10:40:31 +02:00
Simon Vieille 5a86e16861 update ui of the big menu 2020-08-11 10:34:06 +02:00
Simon Vieille 8c3dd2a4f6 remove personal setting for the big menu 2020-08-11 10:33:48 +02:00
Simon Vieille 8e0be738a6 add base of the big menu 2020-08-06 15:00:59 +02:00
Simon Vieille ddb7cc40ce refactor appinfo 2020-08-06 15:00:24 +02:00
Simon Vieille cdcc4ddd51 refactor js 2020-08-04 09:15:16 +02:00
Simon Vieille e1d450218c release v1.7.0 2020-05-19 15:23:25 +02:00
Simon Vieille 93c8ade21a release v1.6.4 2020-05-19 15:21:44 +02:00
Simon Vieille dcc19f5b23 add loader 2020-05-19 15:17:54 +02:00
Simon Vieille 6418e79d49 compatibility with nextcloud 19 2020-05-15 16:59:52 +02:00
Simon Vieille 9b4aecaf41 add documentation 2020-05-14 17:03:09 +02:00
Simon Vieille 46148167e9 add documentation 2020-05-14 17:02:23 +02:00
Simon Vieille a0f4eddab0 release v1.6.3 2020-05-14 15:31:20 +02:00
Simon Vieille 24bf8496f3 fix issue #20: add shortcut to open and to hide the menu 2020-05-14 15:30:34 +02:00
Simon Vieille 8368562ed0 release v1.6.2 2020-05-14 13:28:39 +02:00
Simon Vieille 9a8f5517b6 add a cache for the top menu update (#19) 2020-05-13 12:25:11 +02:00
Simon Vieille bddd8e9c0c release v1.6.1 2020-05-12 19:48:44 +02:00
Simon Vieille 03dbe8eeed fix issue #19: add a hack to show external sites in the top menu with navigation 2020-05-12 19:45:46 +02:00
Simon Vieille 321e5b1178 add title on links 2020-05-12 09:25:43 +02:00
Simon Vieille 594b818515 release v1.6.0 2020-05-11 22:57:55 +02:00
Simon Vieille 7ac19c7bec add personal settings page to enabled (or not) the side menu 2020-05-11 22:51:27 +02:00
Simon Vieille 375ed7d2f1 indentation 2020-05-09 16:37:17 +02:00
Simon Vieille bbd4403c3e release v1.5.0 2020-05-09 16:05:17 +02:00
Simon Vieille c52079e882 fix #19: add option to keep external sites in the top menu 2020-05-09 15:53:25 +02:00
Simon Vieille 7864e16ef3 add option to force light icons 2020-05-09 14:30:24 +02:00
Simon Vieille 4b06b633b8 fix #16: add dark icons 2020-05-09 14:00:24 +02:00
Simon Vieille 12abd19936 fix #16: add dark icons and handle main menu svg filters 2020-05-09 14:00:11 +02:00
Simon Vieille 281e7e8de1 release v1.4.1 2020-05-05 18:53:04 +02:00
Simon Vieille d325d583d4 fix issue #15 and harmonization render with chrome browsers 2020-05-05 18:52:04 +02:00
Simon Vieille 63b03ae11e release v1.4.0 2020-04-29 09:07:07 +02:00
Simon Vieille ec50328f78 Merge branch 'feature/issue-12' into develop 2020-04-29 09:03:11 +02:00
Simon Vieille 4146e9c2a1 fix #12: add an option to hide the opener and the panel when there is no application 2020-04-29 09:03:03 +02:00
Simon Vieille 76ecd6aeaa Merge branch 'develop' into feature/issue-12 2020-04-29 08:44:10 +02:00
Simon Vieille ef22990f4b release v1.3.4 2020-04-27 08:48:48 +02:00
Simon Vieille c84ce6a615 release v1.4.0 2020-04-26 23:46:38 +02:00
Simon Vieille 9b060d1a4b fix #13: add option to show only the opener 2020-04-26 23:45:33 +02:00
Simon Vieille 26e737e2d7 fix #13: add alternate hamburger icon 2020-04-26 23:32:30 +02:00
Simon Vieille 67f27e0ef4 fix #13: add alternate hamburger icon 2020-04-26 23:30:43 +02:00
Simon Vieille a392bb07c0 first tests to solve issue #12 2020-04-26 21:36:54 +02:00
Simon Vieille 58661508d4 indentation 2020-04-25 16:29:52 +02:00
Simon Vieille 5509b69908 fix #11 2020-04-25 16:04:54 +02:00
Simon Vieille 51eccde659 add gitignore 2020-04-25 16:03:51 +02:00
Simon Vieille d0c072bee5 release v1.3.3 2020-04-25 14:30:02 +02:00
Simon Vieille 95f7eb5980 add options to select the size of icons and texts or hide them 2020-04-25 14:25:51 +02:00
Simon Vieille 18314b260f add 2nd background color 2020-04-25 13:25:41 +02:00
Simon Vieille e3c159b4d6 add 2nd background color 2020-04-25 13:05:01 +02:00
Simon Vieille a48611edf4 indentation 2020-04-22 19:35:56 +02:00
Simon Vieille 5dde7ca850 add padding on icons 2020-04-22 19:30:04 +02:00
Simon Vieille db2f7becae add documentation 2020-04-22 00:42:47 +02:00
Simon Vieille 1715ae5d52 release v1.3.2 2020-04-20 19:52:02 +02:00
Simon Vieille 847fa23345 add support message 2020-04-20 19:51:54 +02:00
Simon Vieille 0495046d02 fix #9: apply a patch to correctly generate an image path 2020-04-20 19:24:37 +02:00
Simon Vieille 0474ef55e8 release v1.3.1 2020-04-20 14:07:59 +02:00
Simon Vieille 7c9653943a remove extension from routes (css, js) 2020-04-20 14:05:08 +02:00
Simon Vieille 457bfc282b add opener-position option (issue #3) 2020-04-20 14:04:06 +02:00
Simon Vieille 84c78538f0 fix typo 2020-04-17 14:16:15 +02:00
Simon Vieille f0d17a61bd release v1.3.0 2020-04-17 13:59:42 +02:00
Simon Vieille fdbeaf6677 Merge branch 'feature/menu-position' into develop 2020-04-17 13:58:55 +02:00
Simon Vieille 9d18b33715 add styles 2020-04-17 13:58:45 +02:00
Simon Vieille bfb2b5d819 remove main.js from webpack and add styles 2020-04-17 13:58:34 +02:00
Simon Vieille a6e789c859 add option: enabled hover on opener 2020-04-17 13:58:01 +02:00
Simon Vieille 0cceb03213 add js script using a controller 2020-04-17 13:57:23 +02:00
Simon Vieille 91db830ea7 update screenshot 2020-04-17 13:56:37 +02:00
43 changed files with 3046 additions and 299 deletions
+6
View File
@@ -0,0 +1,6 @@
/js
/node_modules
/l10n/*
/releases
/package-lock.json
!/l10n/.gitkeep
+33
View File
@@ -0,0 +1,33 @@
## Feature
### Description
...
### Benefits
...
---
## Issue
### Environment
* Side menu version: ...
* PHP version: ...
* Web server (Nginx, Apache2): ...
### Steps to reproduce
* ...
* ...
* ...
### Observed Results
...
### Expected Results
...
+24
View File
@@ -0,0 +1,24 @@
npm-build:
npm run build
npm-watch:
npm run watch
.ONESHELL:
release: npm-build translations
if [ -z "$$VERSION" ]; then
echo "VERSION required"
exit 1
fi
test -d releases/$$VERSION && rm -fr releases/$$VERSION
mkdir -p releases/$$VERSION/side_menu
cp -r README.md appinfo css lib img l10n js src templates releases/$$VERSION/side_menu
cd releases/$$VERSION
zip -r side_menu_v$$VERSION.zip side_menu
tar cvzf side_menu_v$$VERSION.tar.gz side_menu
rm -fr side_menu
openssl dgst -sha512 -sign $$HOME/.nextcloud/certificates/side_menu.key side_menu_v$$VERSION.tar.gz | openssl base64 > side_menu_v$$VERSION.sig
translations:
php bin/generate_l10n.php
+37 -29
View File
@@ -1,52 +1,60 @@
🤙 Nextcloud app / Side menu 🎨 🤙 Nextcloud app / Side menu 🎨
=============================== ===============================
Side menu allows you to modify the position of the main menu by creating a panel on the left of the interface or with a big menu on the top.
You can also define apps that must be displayed in the top menu. Fully customisable.
This application moves the top menu of Nextcloud to the left side. This application is rather suitable for instances that activate a lot of applications.
Comptatible with AppOrder. Comptatible with AppOrder.
Installation * [Installation and upgrade](#installation-and-upgrade)
------------ * [How to contribute?](#how-to-contribute)
* [Preview](#preview)
Side menu is availabe from the app store. Installation and upgrade
------------------------
If you want to install it from source: go to https://gitnet.fr/deblan/side_menu/releases and download the last release (side_menu_vX.Y.Z.zip). Side menu is availabe from the app store. If you want to install it from source: go to https://gitnet.fr/deblan/side_menu/releases and download the last release (side_menu_vX.Y.Z.zip). Copy the content into `apps`.
Copy the archive to your Nextcloud server.
``` ```
$ cd /path/to/nextcloud/apps $ cd /path/to/nextcloud/apps
$ unzip -d side_menu /path/to/side_menu_vX.Y.Z.zip $ unzip /path/to/side_menu_vX.Y.Z.zip # tar xvf /path/to/side_menu_vX.Y.Z.tar.gz
``` ```
Upgrade Administrators can edit many settings using the administration page.
-------
Side menu can be upgraded from the app store. Users can disable the menu using the page of personal settings.
If you want to install it from source: go to https://gitnet.fr/deblan/side_menu/releases and download the last release (side_menu_vX.Y.Z.zip).
Copy the archive to your Nextcloud server.
```
$ cd /path/to/nextcloud/apps
$ rm -frv side_menu
$ unzip -d side_menu /path/to/side_menu_vX.Y.Z.zip
```
![](https://upload.deblan.org/u/2020-03/5e7fab2b.jpg)
![](https://upload.deblan.org/u/2020-03/5e81b219.jpg)
![](https://upload.deblan.org/u/2020-04/5e8ee1f7.jpg)
Use the shortcut `Ctrl`+`o` to open and to hide the side menu. Use `tab` to navigate.
How to contribute? How to contribute?
------------------ ------------------
Fork the repository, go to `apps/`, clone your repository and run `npm install` inside. You can report a bug or request a feature by opening an issue: https://gitnet.fr/deblan/side_menu/issues
Build javascripts using `webpack --config ./webpack.js` (add `-w` to build them in real time). If you are a developer:
* fork the repository
* install an instance of Nextcloud
* go to `apps/` and clone your repository
* go to `apps/side_menu` and run `npm install`
Build javascripts using `make npm-build` (or `make npm-watch` to build them in real time).
Then commit and create a pull request. Then commit and create a pull request.
Previews
--------
![](https://upload.deblan.org/u/2020-03/5e81b219.jpg)
![](https://upload.deblan.org/u/2020-03/5e7fab2b.jpg)
![](https://upload.deblan.org/u/2020-08/5f3551d1.png)
![](https://upload.deblan.org/u/2020-08/5f3551f0.png)
![](https://upload.deblan.org/u/2020-08/5f35aae1.png)
![](https://upload.deblan.org/u/2020-08/5f35ab0f.png)
+6 -48
View File
@@ -1,52 +1,10 @@
<?php <?php
/** use OCA\SideMenu\AppInfo\Application;
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Appinfo; $app = new Application();
use OC\Security\CSP\ContentSecurityPolicy; if ($app->isEnabled()) {
use OCP\Util; $app->registerAssets();
$app->registerServices();
$config = \OC::$server->getConfig(); }
$cspnm = \OC::$server->getContentSecurityPolicyNonceManager();
$stylesheet = \OC::$server->getURLGenerator()->linkToRoute(
'side_menu.Css.stylesheet',
[
'v' => $config->getAppValue('side_menu', 'cache', '0'),
]
);
Util::addHeader(
'link',
[
'href' => $stylesheet,
'rel' => 'stylesheet'
],
''
);
Util::addScript('side_menu', 'main');
Util::addScript('side_menu', 'sideMenu');
Util::addStyle('side_menu', 'sideMenu');
// whitelist the URL to allow loading JS from this external domain
// $CSPManager = \OC::$server->getContentSecurityPolicyManager();
// $policy = new ContentSecurityPolicy();
// $policy->addAllowedScriptDomain($url);
// $policy->addAllowedImageDomain($url);
// $policy->addAllowedConnectDomain($url);
// $CSPManager->addDefaultPolicy($policy);
+23 -7
View File
@@ -3,23 +3,39 @@
<id>side_menu</id> <id>side_menu</id>
<name>Side menu</name> <name>Side menu</name>
<summary>Move the top menu to the left side.</summary> <summary>Move the top menu to the left side.</summary>
<description>Move the top menu to the left side.</description> <description><![CDATA[Side menu allows you to modify the position of the main menu by creating a panel on the left of the interface or with a big menu on the top.
You can also define apps that must be displayed in the top menu. Fully customisable.
This application is rather suitable for instances that activate a lot of applications.
Use the shortcut `Ctrl`+`o` to open and to hide the side menu. Use `tab` to navigate.
Comptatible with AppOrder.
You can report a bug or request a feature by opening an issue.
]]></description>
<licence>agpl</licence> <licence>agpl</licence>
<author mail="dev+sidemenu@deblan.fr" homepage="https://www.deblan.io/">Simon Vieille</author> <author mail="contact@deblan.fr" homepage="https://www.deblan.io/">Simon Vieille</author>
<version>1.2.4</version> <version>1.8.6</version>
<namespace>SideMenu</namespace> <namespace>SideMenu</namespace>
<category>customization</category> <category>customization</category>
<website>https://gitnet.fr/deblan/side_menu</website> <website>https://gitnet.fr/deblan/side_menu</website>
<bugs>https://gitnet.fr/deblan/side_menu/issues</bugs> <bugs>https://gitnet.fr/deblan/side_menu/issues</bugs>
<repository type="git">https://gitnet.fr/deblan/side_menu</repository> <repository type="git">https://gitnet.fr/deblan/side_menu</repository>
<screenshot>https://upload.deblan.org/u/2020-03/5e7fab2b.jpg</screenshot>
<screenshot>https://upload.deblan.org/u/2020-03/5e81b219.jpg</screenshot> <screenshot>https://upload.deblan.org/u/2020-03/5e81b219.jpg</screenshot>
<screenshot>https://upload.deblan.org/u/2020-04/5e8ee1f7.jpg</screenshot> <screenshot>https://upload.deblan.org/u/2020-03/5e7fab2b.jpg</screenshot>
<screenshot>https://upload.deblan.org/u/2020-08/5f3551d1.png</screenshot>
<screenshot>https://upload.deblan.org/u/2020-08/5f3551f0.png</screenshot>
<screenshot>https://upload.deblan.org/u/2020-08/5f35aae1.png</screenshot>
<screenshot>https://upload.deblan.org/u/2020-08/5f35ab0f.png</screenshot>
<dependencies> <dependencies>
<nextcloud min-version="18" max-version="18"/> <nextcloud min-version="18" max-version="20"/>
</dependencies> </dependencies>
<settings> <settings>
<admin>OCA\SideMenu\Settings\Admin</admin> <admin>OCA\SideMenu\Settings\Admin</admin>
<admin-section>OCA\SideMenu\Settings\Section</admin-section> <admin-section>OCA\SideMenu\Settings\AdminSection</admin-section>
<personal>OCA\SideMenu\Settings\Personal</personal>
<personal-section>OCA\SideMenu\Settings\PersonalSection</personal-section>
</settings> </settings>
</info> </info>
+4 -1
View File
@@ -19,6 +19,9 @@
return [ return [
'routes' => [ 'routes' => [
['name' => 'Css#stylesheet', 'url' => '/css/stylesheet.css', 'verb' => 'GET'], ['name' => 'Css#stylesheet', 'url' => '/css/stylesheet', 'verb' => 'GET'],
['name' => 'Js#script', 'url' => '/js/script', 'verb' => 'GET'],
['name' => 'Nav#items', 'url' => '/nav/items', 'verb' => 'GET'],
['name' => 'PersonalSetting#valueSet', 'url' => '/personalSetting/valueSet', 'verb' => 'POST'],
], ],
]; ];
+33
View File
@@ -0,0 +1,33 @@
<?php
function generateJsContent($translations)
{
$json = json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
return <<< EOF
OC.L10N.register("side_menu", {$json}, "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
EOF;
}
function generateJsonContent($translations)
{
$datas = [
'translations' => $translations,
'pluralForm' => 'nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;',
];
return json_encode(
$datas,
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
);
}
chdir(__DIR__.'/../');
foreach (glob('src/l10n/fixtures/*.yaml') as $file) {
$lang = str_replace('.yaml', '', basename($file));
$translations = yaml_parse(file_get_contents($file));
file_put_contents('l10n/'.$lang.'.js', generateJsContent($translations));
file_put_contents('l10n/'.$lang.'.json', generateJsonContent($translations));
}
+19
View File
@@ -20,6 +20,25 @@
margin: 10px 0 10px 0; margin: 10px 0 10px 0;
} }
#side-menu-section input[type="checkbox"] {
vertical-align: middle;
}
#side-menu-section input[type="range"] {
vertical-align: middle;
}
#side-menu-section select { #side-menu-section select {
margin: 10px 0 10px 0; margin: 10px 0 10px 0;
} }
.keyboard-key {
padding: 1px 9px;
margin: 0 2px;
background: #eee;
border: 1px solid #aaa;
color: #555;
border-radius: 3px;
}
+125 -9
View File
@@ -15,10 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#appmenu, #appmenu + nav {
display: none;
}
#side-menu { #side-menu {
position: fixed; position: fixed;
top: 0; top: 0;
@@ -26,7 +22,7 @@
height: 100vh; height: 100vh;
width: 100%; width: 100%;
max-width: 250px; max-width: 250px;
background: var(--side-menu-background-color, #333); background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
z-index: 3000; z-index: 3000;
color: var(--side-menu-text-color, #fff); 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; 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;
@@ -37,6 +33,10 @@
display: block; display: block;
} }
#header .side-menu-opener {
margin-left: 5px;
}
.side-menu-opener { .side-menu-opener {
background: var(--side-menu-opener, url('../img/side-menu-opener.svg')); background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
height: 40px; height: 40px;
@@ -45,6 +45,15 @@
border: 0; border: 0;
} }
.side-menu-closer {
background: url('../img/side-menu-opener-closer.svg');
display: none;
}
#side-menu.hide-opener .side-menu-opener, .side-menu-opener.hide {
display: none;
}
.side-menu-apps-list { .side-menu-apps-list {
height: calc(100vh - 150px); height: calc(100vh - 150px);
z-index: 2200; z-index: 2200;
@@ -57,21 +66,28 @@
.side-menu-app-icon { .side-menu-app-icon {
width: 20px; width: 20px;
vertical-align: middle; vertical-align: top;
margin-right: 10px; 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;
} }
.side-menu-app a { .side-menu-app a {
line-height: 30px; line-height: 30px;
color: var(--side-menu-text-color, #fff); color: var(--side-menu-text-color, #fff);
display: block; display: block;
padding: 7px 0 7px 15px; padding: 7px 0 5px 15px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.side-menu-app a:hover, .side-menu-app.active a { .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);
} }
@@ -89,8 +105,108 @@
width: 100%; width: 100%;
z-index: 2300; z-index: 2300;
max-width: 250px; max-width: 250px;
background: var(--side-menu-background-color, #333);
position: fixed; position: fixed;
padding-top: 2px; padding-top: 2px;
padding-left: 5px;
top: 0; top: 0;
} }
#side-menu.hide-opener .side-menu-logo {
margin-top: 20px;
}
#side-menu-loader {
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;
}
#side-menu.side-menu-big {
max-width: 100%;
height: auto;
}
.side-menu-big .side-menu-header {
height: auto;
}
.side-menu-big .side-menu-apps-list {
height: auto;
position: static;
max-width: 100vw;
overflow: auto;
}
.side-menu-big .side-menu-app a {
padding: 7px 0 7px 7px;
}
.side-menu-categories-wrapper {
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%;
}
.side-menu-category {
padding: 10px 20px;
flex: 1 1 auto;
}
.side-menu-category-title {
padding-left: 10px;
color: var(--side-menu-text-color, #fff);
}
.side-menu-big .side-menu-app-icon {
vertical-align: middle;
margin-top: -2px;
}
@media screen and (max-width: 1024px) {
#side-menu.side-menu-big {
max-width: 290px;
}
.side-menu-categories {
display: block;
padding: 0;
}
.side-menu-category {
padding: 10px 0;
}
#side-menu.side-menu-big {
height: 100vh;
}
}
@media screen and (min-width: 1024px) {
.side-menu-closer {
display: block;
float: right;
margin-right: 9px;
}
.side-menu-big .side-menu-header {
max-width: 100%;
}
}
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583">
<g color="#000" fill="#fff">
<rect transform="rotate(135)" ry=".545" rx=".545" y="-8.209" x="-3.608" height="1.451" width="7.216" style="marker:none" overflow="visible" paint-order="stroke markers fill"/>
<rect transform="rotate(-135)" ry=".545" rx=".545" y="-.726" x="-11.091" height="1.451" width="7.216" style="marker:none" overflow="visible" paint-order="stroke markers fill"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 498 B

+173
View File
@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg935"
sodipodi:docname="side-menu-opener-dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata941">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs939" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview937"
showgrid="false"
inkscape:zoom="8.34386"
inkscape:cx="83.025045"
inkscape:cy="14.304895"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg935" />
<g
transform="translate(.3 -286.074)"
fill="#fff"
color="#000"
fill-opacity=".855"
id="g933"
style="fill:#000000;fill-opacity:0.89855075">
<rect
ry="0"
rx="0"
y="288.474"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#000000;fill-opacity:0.89855075"
overflow="visible"
paint-order="stroke markers fill"
id="rect909" />
<g
transform="translate(-.13)"
id="g915"
style="fill:#000000;fill-opacity:0.89855075">
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect911" />
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect913" />
</g>
<rect
ry="0"
rx="0"
y="290.631"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#000000;fill-opacity:0.89855075"
overflow="visible"
paint-order="stroke markers fill"
id="rect917" />
<g
transform="translate(-.13 2.157)"
id="g923"
style="fill:#000000;fill-opacity:0.89855075">
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect919" />
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect921" />
</g>
<rect
ry="0"
rx="0"
y="292.808"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#000000;fill-opacity:0.89855075"
overflow="visible"
paint-order="stroke markers fill"
id="rect925" />
<g
transform="translate(-.13 4.334)"
id="g931"
style="fill:#000000;fill-opacity:0.89855075">
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect927" />
<rect
style="marker:none;fill:#000000;fill-opacity:0.89855075"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect929" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

+102
View File
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg1090"
sodipodi:docname="side-menu-opener-hamburger-2-dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata1096">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1094" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview1092"
showgrid="false"
inkscape:zoom="8.34386"
inkscape:cx="84.523455"
inkscape:cy="12.270318"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg1090" />
<rect
overflow="visible"
style="marker:none;fill:#000000;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="2.787"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1082" />
<rect
overflow="visible"
style="marker:none;fill:#000000;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="4.655"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1084" />
<rect
overflow="visible"
style="marker:none;fill:#000000;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="6.54"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1086" />
<path
style="marker:none;fill:#000000;fill-opacity:1"
d="M1.243.71A.469.469 0 0 0 .881.88a.469.469 0 0 0-.171.362V9.34c0 .146.067.275.171.362a.469.469 0 0 0 .362.171H9.34a.469.469 0 0 0 .362-.171.469.469 0 0 0 .171-.362V1.243a.469.469 0 0 0-.171-.362A.469.469 0 0 0 9.34.71zm.723 1.256h6.65v6.65h-6.65z"
color="#000"
overflow="visible"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="path1088" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+101
View File
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg1443"
sodipodi:docname="side-menu-opener-hamburger-2.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata1449">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1447" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview1445"
showgrid="false"
inkscape:zoom="5.9"
inkscape:cx="90.508475"
inkscape:cy="4.5762712"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg1443" />
<rect
overflow="visible"
style="marker:none;fill:#ffffff;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="2.787"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1435" />
<rect
overflow="visible"
style="marker:none;fill:#ffffff;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="4.655"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1437" />
<rect
overflow="visible"
style="marker:none;fill:#ffffff;fill-opacity:1"
width="4.806"
height="1.256"
x="2.888"
y="6.54"
rx="0"
ry=".472"
color="#000"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="rect1439" />
<path
style="marker:none;fill:#ffffff;fill-opacity:1"
d="M1.243.71A.469.469 0 0 0 .881.88a.469.469 0 0 0-.171.362V9.34c0 .146.067.275.171.362a.469.469 0 0 0 .362.171H9.34a.469.469 0 0 0 .362-.171.469.469 0 0 0 .171-.362V1.243a.469.469 0 0 0-.171-.362A.469.469 0 0 0 9.34.71zm.723 1.256h6.65v6.65h-6.65z"
color="#000"
overflow="visible"
fill="#fff"
fill-opacity=".855"
paint-order="stroke markers fill"
id="path1441" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+92
View File
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg1168"
sodipodi:docname="side-menu-opener-hamburger-dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata1174">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1172" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview1170"
showgrid="false"
inkscape:zoom="5.9"
inkscape:cx="112.71186"
inkscape:cy="0.16949153"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg1168" />
<g
color="#000"
fill="#fff"
fill-opacity=".855"
transform="translate(0 -286.417)"
id="g1166"
style="fill:#000000;fill-opacity:0.99637681">
<rect
ry=".545"
rx="0"
y="288.816"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#000000;fill-opacity:0.99637681"
overflow="visible"
paint-order="stroke markers fill"
id="rect1160" />
<rect
ry=".545"
rx="0"
y="290.973"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#000000;fill-opacity:0.99637681"
overflow="visible"
paint-order="stroke markers fill"
id="rect1162" />
<rect
ry=".545"
rx="0"
y="293.15"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#000000;fill-opacity:0.99637681"
overflow="visible"
paint-order="stroke markers fill"
id="rect1164" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+89 -5
View File
@@ -1,7 +1,91 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<g color="#000" fill="#fff" fill-opacity=".855" transform="translate(0 -286.417)"> <svg
<rect ry=".545" rx="0" y="288.816" x="2.516" height="1.451" width="5.551" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> xmlns:dc="http://purl.org/dc/elements/1.1/"
<rect ry=".545" rx="0" y="290.973" x="2.516" height="1.451" width="5.551" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> xmlns:cc="http://creativecommons.org/ns#"
<rect ry=".545" rx="0" y="293.15" x="2.516" height="1.451" width="5.551" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg1382"
sodipodi:docname="side-menu-opener-hamburger.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata1388">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1386" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview1384"
showgrid="false"
inkscape:zoom="5.9"
inkscape:cx="108.13559"
inkscape:cy="3.8983051"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg1382" />
<g
color="#000"
fill="#fff"
fill-opacity=".855"
transform="translate(0 -286.417)"
id="g1380"
style="fill:#ffffff;fill-opacity:1">
<rect
ry=".545"
rx="0"
y="288.816"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#ffffff;fill-opacity:1"
overflow="visible"
paint-order="stroke markers fill"
id="rect1374" />
<rect
ry=".545"
rx="0"
y="290.973"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#ffffff;fill-opacity:1"
overflow="visible"
paint-order="stroke markers fill"
id="rect1376" />
<rect
ry=".545"
rx="0"
y="293.15"
x="2.516"
height="1.451"
width="5.551"
style="marker:none;fill:#ffffff;fill-opacity:1"
overflow="visible"
paint-order="stroke markers fill"
id="rect1378" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 2.4 KiB

+167 -14
View File
@@ -1,19 +1,172 @@
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<g transform="translate(.3 -286.074)" fill="#fff" color="#000" fill-opacity=".855"> <svg
<rect ry="0" rx="0" y="288.474" x="4.266" height="1.451" width="1.451" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> xmlns:dc="http://purl.org/dc/elements/1.1/"
<g transform="translate(-.13)"> xmlns:cc="http://creativecommons.org/ns#"
<rect style="marker:none" width="1.451" height="1.451" x="6.445" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
<rect style="marker:none" width="1.451" height="1.451" x="2.345" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="40"
height="40"
viewBox="0 0 10.583 10.583"
version="1.1"
id="svg1321"
sodipodi:docname="side-menu-opener.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata1327">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1325" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1918"
inkscape:window-height="1008"
id="namedview1323"
showgrid="false"
inkscape:zoom="5.9"
inkscape:cx="78.983051"
inkscape:cy="5.5932203"
inkscape:window-x="0"
inkscape:window-y="41"
inkscape:window-maximized="0"
inkscape:current-layer="svg1321" />
<g
transform="translate(.3 -286.074)"
fill="#fff"
color="#000"
fill-opacity=".855"
id="g1319"
style="fill:#ffffff;fill-opacity:0.94565219">
<rect
ry="0"
rx="0"
y="288.474"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
overflow="visible"
paint-order="stroke markers fill"
id="rect1295" />
<g
transform="translate(-.13)"
id="g1301"
style="fill:#ffffff;fill-opacity:0.94565219">
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1297" />
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1299" />
</g> </g>
<rect ry="0" rx="0" y="290.631" x="4.266" height="1.451" width="1.451" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> <rect
<g transform="translate(-.13 2.157)"> ry="0"
<rect style="marker:none" width="1.451" height="1.451" x="6.445" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> rx="0"
<rect style="marker:none" width="1.451" height="1.451" x="2.345" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> y="290.631"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
overflow="visible"
paint-order="stroke markers fill"
id="rect1303" />
<g
transform="translate(-.13 2.157)"
id="g1309"
style="fill:#ffffff;fill-opacity:0.94565219">
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1305" />
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1307" />
</g> </g>
<rect ry="0" rx="0" y="292.808" x="4.266" height="1.451" width="1.451" style="marker:none" overflow="visible" paint-order="stroke markers fill"/> <rect
<g transform="translate(-.13 4.334)"> ry="0"
<rect style="marker:none" width="1.451" height="1.451" x="6.445" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> rx="0"
<rect style="marker:none" width="1.451" height="1.451" x="2.345" y="288.474" rx="0" ry="0" overflow="visible" paint-order="stroke markers fill"/> y="292.808"
x="4.266"
height="1.451"
width="1.451"
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
overflow="visible"
paint-order="stroke markers fill"
id="rect1311" />
<g
transform="translate(-.13 4.334)"
id="g1317"
style="fill:#ffffff;fill-opacity:0.94565219">
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="6.445"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1313" />
<rect
style="marker:none;fill:#ffffff;fill-opacity:0.94565219"
width="1.451"
height="1.451"
x="2.345"
y="288.474"
rx="0"
ry="0"
overflow="visible"
paint-order="stroke markers fill"
id="rect1315" />
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File
+114
View File
@@ -0,0 +1,114 @@
<?php
namespace OCA\SideMenu\AppInfo;
use OC;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
use OC\User\User;
use OCA\SideMenu\Service\AppRepository;
use OCP\AppFramework\App;
use OCP\IUserSession;
use OCP\Util;
use Psr\Container\ContainerInterface;
/**
* class Application.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class Application extends App
{
/**
* @var OC\AllConfig
*/
protected $config;
/**
* @var ContentSecurityPolicyNonceManager
*/
protected $cspnm;
/**
* @var User
*/
protected $user;
/**
* {@inheritdoc}
*/
public function __construct(array $urlParams = [])
{
parent::__construct('side_menu', $urlParams);
$this->config = OC::$server->getConfig();
$this->cspnm = OC::$server->getContentSecurityPolicyNonceManager();
$this->user = OC::$server[IUserSession::class]->getUser();
}
/**
* Checks if this app is enabled.
*/
public function isEnabled(): bool
{
$enabled = true;
if (null !== $this->user) {
$enabled = (bool) $this->config->getUserValue($this->user->getUid(), 'side_menu', 'enabled', '1');
}
return $enabled;
}
/**
* Registes services.
*/
public function registerServices()
{
$container = $this->getContainer();
$container->registerService('AppRepository', function (ContainerInterface $c) {
return new AppRepository(new OC_App());
});
}
/**
* Registers assets.
*/
public function registerAssets()
{
Util::addScript('side_menu', 'sideMenu');
Util::addStyle('side_menu', 'sideMenu');
$stylesheet = OC::$server->getURLGenerator()->linkToRoute(
'side_menu.Css.stylesheet',
[
'v' => $this->config->getAppValue('side_menu', 'cache', '0'),
]
);
$script = OC::$server->getURLGenerator()->linkToRoute(
'side_menu.Js.script',
[
'v' => $this->config->getAppValue('side_menu', 'cache', '0'),
]
);
Util::addHeader(
'link',
[
'href' => $stylesheet,
'rel' => 'stylesheet',
],
''
);
Util::addHeader(
'script',
[
'src' => $script,
'nonce' => $this->cspnm->getNonce(),
],
''
);
}
}
+30 -10
View File
@@ -18,22 +18,23 @@
namespace OCA\SideMenu\Controller; namespace OCA\SideMenu\Controller;
use OC;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig; use OCP\IConfig;
use OCP\IRequest; use OCP\IRequest;
use OCP\IUserSession;
class CssController extends Controller class CssController extends Controller
{ {
/**
/** @var \OCP\IConfig */ * @var \OCP\IConfig
*/
protected $config; protected $config;
/** /**
* @param string $appName * @param string $appName
* @param IRequest $request
* @param IConfig $config
*/ */
public function __construct($appName, IRequest $request, IConfig $config) public function __construct($appName, IRequest $request, IConfig $config)
{ {
@@ -51,19 +52,38 @@ class CssController extends Controller
*/ */
public function stylesheet() public function stylesheet()
{ {
$requestUri = $this->request->server['REQUEST_URI']; $backgroundColor = $this->config->getAppValue('side_menu', 'background-color', '#333333');
$assetsRoot = str_replace('/index.php', '', $requestUri); $backgroundColorTo = $this->config->getAppValue('side_menu', 'background-color-to', $backgroundColor);
$assetsRoot = preg_replace('#apps/side_menu/.*#s', 'apps/side_menu', $assetsRoot);
$user = OC::$server[IUserSession::class]->getUser();
$topMenuApps = (array) json_decode($this->config->getAppValue('side_menu', 'top-menu-apps', '[]'), true);
if ($user) {
$userTopMenuApps = (array) json_decode($this->config->getUserValue($user->getUid(), 'side_menu', 'top-menu-apps', '[]'), true);
if (!empty($userTopMenuApps)) {
$topMenuApps = $userTopMenuApps;
}
}
$parameters = [ $parameters = [
'vars' => [ 'vars' => [
'background-color' => $this->config->getAppValue('side_menu', 'background-color', '#333333'), 'background-color' => $backgroundColor,
'background-color-to' => $backgroundColorTo,
'current-app-background-color' => $this->config->getAppValue('side_menu', 'current-app-background-color', '#444444'), 'current-app-background-color' => $this->config->getAppValue('side_menu', 'current-app-background-color', '#444444'),
'loader-color' => $this->config->getAppValue('side_menu', 'loader-color', '#0e75ac'),
'text-color' => $this->config->getAppValue('side_menu', 'text-color', '#FFFFFF'), 'text-color' => $this->config->getAppValue('side_menu', 'text-color', '#FFFFFF'),
'opener' => $this->config->getAppValue('side_menu', 'opener', 'side-menu-opener'), 'opener' => $this->config->getAppValue('side_menu', 'opener', 'side-menu-opener'),
'icon-invert-filter' => abs((int) $this->config->getAppValue('side_menu', 'icon-invert-filter', '0')).'%',
'icon-opacity' => abs((int) $this->config->getAppValue('side_menu', 'icon-opacity', '100') / 100),
], ],
'display-logo' => (bool) $this->config->getAppValue('side_menu', 'display-logo', 1), 'display-logo' => (bool) $this->config->getAppValue('side_menu', 'display-logo', 1),
'assetsRoot' => $assetsRoot, 'opener-only' => (bool) $this->config->getAppValue('side_menu', 'opener-only', 0),
'external-sites-in-top-menu' => (bool) $this->config->getAppValue('side_menu', 'external-sites-in-top-menu', 0),
'size-icon' => $this->config->getAppValue('side_menu', 'size-icon', 'normal'),
'size-text' => $this->config->getAppValue('side_menu', 'size-text', 'normal'),
'big-menu' => (bool) $this->config->getAppValue('side_menu', 'big-menu', '0'),
'top-menu-apps' => $topMenuApps,
]; ];
$response = new TemplateResponse('side_menu', 'css/stylesheet', $parameters, 'blank'); $response = new TemplateResponse('side_menu', 'css/stylesheet', $parameters, 'blank');
+82
View File
@@ -0,0 +1,82 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Controller;
use OC;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserSession;
class JsController extends Controller
{
/**
* @var \OCP\IConfig
*/
protected $config;
/**
* @param string $appName
*/
public function __construct($appName, IRequest $request, IConfig $config)
{
parent::__construct($appName, $request);
$this->config = $config;
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
*
* @return Response
*/
public function script()
{
$user = OC::$server[IUserSession::class]->getUser();
$topMenuApps = (array) json_decode($this->config->getAppValue('side_menu', 'top-menu-apps', '[]'), true);
if ($user) {
$userTopMenuApps = (array) json_decode($this->config->getUserValue($user->getUid(), 'side_menu', 'top-menu-apps', '[]'), true);
if (!empty($userTopMenuApps)) {
$topMenuApps = $userTopMenuApps;
}
}
$parameters = [
'opener-position' => $this->config->getAppValue('side_menu', 'opener-position', 'before'),
'opener-hover' => (bool) $this->config->getAppValue('side_menu', 'opener-hover', '0'),
'external-sites-in-top-menu' => (bool) $this->config->getAppValue('side_menu', 'external-sites-in-top-menu', 0),
'force-light-icon' => (bool) $this->config->getAppValue('side_menu', 'force-light-icon', '0'),
'hide-when-no-apps' => (bool) $this->config->getAppValue('side_menu', 'hide-when-no-apps', '0'),
'loader-enabled' => (bool) $this->config->getAppValue('side_menu', 'loader-enabled', '1'),
'big-menu' => (bool) $this->config->getAppValue('side_menu', 'big-menu', '0'),
'top-menu-apps' => $topMenuApps,
];
$response = new TemplateResponse('side_menu', 'js/script', $parameters, 'blank');
$response->addHeader('Content-Type', 'text/javascript');
return $response;
}
}
+208
View File
@@ -0,0 +1,208 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Controller;
use OC;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\URLGenerator;
use OCA\SideMenu\Service\AppRepository;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\L10N\IFactory;
class NavController extends Controller
{
/**
* @var IConfig
*/
protected $config;
/**
* @var AppRepository
*/
protected $appRepository;
/**
* @var IFactory
*/
protected $l10nFactory;
/**
* @var CategoryFetcher
*/
protected $categoryFetcher;
/**
* @var URLGenerator
*/
protected $router;
/**
* @param string $appName
*/
public function __construct(
$appName,
IRequest $request,
IConfig $config,
AppRepository $appRepository,
CategoryFetcher $categoryFetcher,
URLGenerator $router,
IL10N $trans,
IFactory $l10nFactory)
{
parent::__construct($appName, $request);
$this->config = $config;
$this->appRepository = $appRepository;
$this->categoryFetcher = $categoryFetcher;
$this->l10nFactory = $l10nFactory;
$this->router = $router;
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
*
* @return JSONResponse
*/
public function items()
{
$apps = $this->appRepository->getVisibleApps();
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$categoriesLabels = $this->categoryFetcher->get();
$externalSitesInTopMenu = (bool) $this->config->getAppValue('side_menu', 'external-sites-in-top-menu', 0);
$user = OC::$server[IUserSession::class]->getUser();
$appsCategories = [];
$categoriesAppsCount = [];
$items = [];
if (!$user) {
return new JSONResponse([
'items' => $items,
]);
}
$topMenuApps = (array) json_decode($this->config->getAppValue('side_menu', 'top-menu-apps', '[]'), true);
$userTopMenuApps = (array) json_decode($this->config->getUserValue($user->getUid(), 'side_menu', 'top-menu-apps', '[]'), true);
if (!empty($userTopMenuApps)) {
$topMenuApps = $userTopMenuApps;
}
foreach ($categoriesLabels as $k => $category) {
$categoriesLabels[$category['id']] = $category['translations'][$currentLanguage]['name'] ?? $category['translations']['en']['name'];
unset($categoriesLabels[$k]);
}
$categoriesLabels['external_links'] = $this->l10nFactory->get('external')->t('External sites');
$items['other'] = [
'name' => '',
'apps' => [],
];
foreach ($apps as $app) {
if (in_array($app['id'], $topMenuApps)) {
continue;
}
$categories = (array) $app['category'];
$appsCategories[$app['id']] = [];
if (empty($categories)) {
$categories = ['other'];
}
foreach ($categories as $category) {
if (!isset($items[$category])) {
$items[$category] = [
'name' => $categoriesLabels[$category],
'apps' => [],
];
}
if (!isset($categoriesAppsCount[$category])) {
$categoriesAppsCount[$category] = 0;
}
++$categoriesAppsCount[$category];
$appsCategories[$app['id']][] = $category;
$items[$category]['apps'][$app['id']] = [
'name' => $app['name'],
'href' => $app['href'],
'icon' => $app['icon'],
];
}
}
arsort($categoriesAppsCount);
$keys = array_keys($categoriesAppsCount);
foreach ($appsCategories as $app => $appCategories) {
$smallerIndex = count($categoriesAppsCount) - 1;
foreach ($appCategories as $appCategory) {
$appKey = array_keys($keys, $appCategory)[0];
if ($appKey < $smallerIndex) {
$smallerIndex = $appKey;
}
}
$category = $keys[$smallerIndex];
foreach ($items as $itemCategory => $value) {
if ($itemCategory !== $category && isset($value['apps'][$app])) {
unset($items[$itemCategory]['apps'][$app]);
if (empty($items[$itemCategory]['apps'])) {
unset($items[$itemCategory]);
}
}
}
}
foreach ($items as $category => $value) {
if (empty($items[$category]['apps'])) {
unset($items[$category]);
} else {
uasort($items[$category]['apps'], function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
}
}
usort($items, function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
return new JSONResponse([
'items' => $items,
]);
}
}
@@ -0,0 +1,94 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserSession;
class PersonalSettingController extends Controller
{
/**
* @var \OCP\IConfig
*/
protected $config;
/**
* @var IUserSession
*/
private $userSession;
public function __construct($appName, IRequest $request, IConfig $config, IUserSession $userSession)
{
parent::__construct($appName, $request);
$this->config = $config;
$this->userSession = $userSession;
}
/**
* @NoAdminRequired
*
* @param mixed $name
* @param mixed $value
*
* @return Response
*/
public function valueSet($name, $value)
{
$doSave = false;
$user = $this->userSession->getUser();
if ('enabled' === $name) {
$doSave = true;
if (!in_array($value, ['0', '1'])) {
$value = '1';
}
}
if ('top-menu-apps' === $name) {
$doSave = true;
$data = json_decode($value, true);
if (!is_array($data)) {
$doSave = false;
} else {
foreach ($data as $v) {
if (!is_string($v)) {
$doSave = false;
}
}
}
}
if ($doSave) {
$this->config->setUserValue($user->getUid(), 'side_menu', $name, $value);
return [
'name' => $name,
'value' => $value,
];
}
return [];
}
}
+84
View File
@@ -0,0 +1,84 @@
<?php
namespace OCA\SideMenu\Service;
use OC_App;
use OCP\L10N\IFactory;
/**
* class AppRepository.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class AppRepository
{
/**
* @var OC_App
*/
protected $ocApp;
/**
* @var IFactory
*/
protected $l10nFactory;
public function __construct(OC_App $ocApp, IFactory $l10nFactory)
{
$this->ocApp = $ocApp;
$this->l10nFactory = $l10nFactory;
}
/**
* Retrieves visibles apps.
*
* @return array
*/
public function getVisibleApps()
{
$navigation = $this->ocApp->getNavigation();
$apps = $this->ocApp->listAllApps();
$visibleApps = [];
foreach ($apps as $app) {
$id = $app['id'];
foreach ([$app['id'], $app['id'].'_index'] as $id) {
if (isset($navigation[$id])) {
$app['name'] = $this->l10nFactory->get($id)->t($app['name']);
$app['href'] = $navigation[$id]['href'];
$app['icon'] = $navigation[$id]['icon'];
$visibleApps[$id] = $app;
}
}
}
foreach ($navigation as $app) {
if ('external_index' === substr($app['id'], 0, 14)) {
$visibleApps[$app['id']] = [
'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']),
'href' => $app['href'],
'icon' => $app['icon'],
'category' => [
'external_links',
],
];
} elseif ('files' === $app['id']) {
$visibleApps[$app['id']] = [
'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']),
'href' => $app['href'],
'icon' => $app['icon'],
'category' => [],
];
}
}
usort($visibleApps, function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
return $visibleApps;
}
}
+38 -8
View File
@@ -18,28 +18,41 @@
namespace OCA\SideMenu\Settings; namespace OCA\SideMenu\Settings;
use OCA\SideMenu\Service\AppRepository;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IL10N; use OCP\IL10N;
use OCP\ILogger; use OCP\ILogger;
use OCP\Settings\ISettings; use OCP\Settings\ISettings;
use OCP\IConfig;
class Admin implements ISettings class Admin implements ISettings
{ {
/** @var IL10N */ /**
* @var IL10N
*/
private $l; private $l;
/** @var ILogger */ /**
* @var ILogger
*/
private $logger; private $logger;
/** @var IConfig */ /**
* @var IConfig
*/
private $config; private $config;
public function __construct(IL10N $l, ILogger $logger, IConfig $config) /**
* @var AppRepository
*/
private $appRepository;
public function __construct(IL10N $l, ILogger $logger, IConfig $config, AppRepository $appRepository)
{ {
$this->l = $l; $this->l = $l;
$this->logger = $logger; $this->logger = $logger;
$this->config = $config; $this->config = $config;
$this->appRepository = $appRepository;
} }
/** /**
@@ -47,13 +60,30 @@ class Admin implements ISettings
*/ */
public function getForm() public function getForm()
{ {
$backgroundColor = $this->config->getAppValue('side_menu', 'background-color', '#333333');
$backgroundColorTo = $this->config->getAppValue('side_menu', 'background-color-to', $backgroundColor);
$parameters = [ $parameters = [
'background-color' => $this->config->getAppValue('side_menu', 'background-color', '#333333'), 'background-color' => $backgroundColor,
'background-color-to' => $backgroundColorTo,
'current-app-background-color' => $this->config->getAppValue('side_menu', 'current-app-background-color', '#444444'), 'current-app-background-color' => $this->config->getAppValue('side_menu', 'current-app-background-color', '#444444'),
'loader-color' => $this->config->getAppValue('side_menu', 'loader-color', '#0e75ac'),
'icon-invert-filter' => (int) $this->config->getAppValue('side_menu', 'icon-invert-filter', '0'),
'icon-opacity' => (int) $this->config->getAppValue('side_menu', 'icon-opacity', '100'),
'loader-enabled' => $this->config->getAppValue('side_menu', 'loader-enabled', '1'),
'text-color' => $this->config->getAppValue('side_menu', 'text-color', '#FFFFFF'), 'text-color' => $this->config->getAppValue('side_menu', 'text-color', '#FFFFFF'),
'cache' => $this->config->getAppValue('side_menu', 'cache', '0'), 'cache' => $this->config->getAppValue('side_menu', 'cache', '0'),
'opener' => $this->config->getAppValue('side_menu', 'opener', 'side-menu-opener'), 'opener' => $this->config->getAppValue('side_menu', 'opener', 'side-menu-opener'),
'big-menu' => $this->config->getAppValue('side_menu', 'big-menu', '0'),
'display-logo' => $this->config->getAppValue('side_menu', 'display-logo', '1'), 'display-logo' => $this->config->getAppValue('side_menu', 'display-logo', '1'),
'opener-position' => $this->config->getAppValue('side_menu', 'opener-position', 'before'),
'opener-hover' => $this->config->getAppValue('side_menu', 'opener-hover', '0'),
'opener-only' => $this->config->getAppValue('side_menu', 'opener-only', '0'),
'hide-when-no-apps' => $this->config->getAppValue('side_menu', 'hide-when-no-apps', '0'),
'size-icon' => $this->config->getAppValue('side_menu', 'size-icon', 'normal'),
'size-text' => $this->config->getAppValue('side_menu', 'size-text', 'normal'),
'top-menu-apps' => (array) json_decode($this->config->getAppValue('side_menu', 'top-menu-apps', '[]'), true),
'apps' => $this->appRepository->getVisibleApps(),
]; ];
return new TemplateResponse('side_menu', 'settings/admin-form', $parameters, ''); return new TemplateResponse('side_menu', 'settings/admin-form', $parameters, '');
@@ -69,8 +99,8 @@ class Admin implements ISettings
/** /**
* @return int whether the form should be rather on the top or bottom of * @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the * the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100. * priority values. It is required to return a value between 0 and 100.
* *
* E.g.: 70 * E.g.: 70
*/ */
@@ -22,12 +22,16 @@ use OCP\IL10N;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\Settings\IIconSection; use OCP\Settings\IIconSection;
class Section implements IIconSection class AdminSection implements IIconSection
{ {
/** @var IL10N */ /**
* @var IL10N
*/
private $l; private $l;
/** @var IURLGenerator */ /**
* @var IURLGenerator
*/
private $url; private $url;
/** /**
+100
View File
@@ -0,0 +1,100 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Settings;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IL10N;
use OCP\ILogger;
use OCP\Settings\ISettings;
use OCP\IConfig;
use OCP\IUserSession;
use OCA\SideMenu\Service\AppRepository;
class Personal implements ISettings
{
/**
* @var IL10N
*/
private $l;
/**
* @var ILogger
*/
private $logger;
/**
* @var IConfig
*/
private $config;
/**
* @var IUserSession
*/
private $userSession;
/**
* @var AppRepository
*/
private $appRepository;
public function __construct(IL10N $l, ILogger $logger, IConfig $config, IUserSession $userSession, AppRepository $appRepository)
{
$this->l = $l;
$this->logger = $logger;
$this->config = $config;
$this->userSession = $userSession;
$this->appRepository = $appRepository;
}
/**
* @return TemplateResponse
*/
public function getForm()
{
$user = $this->userSession->getUser();
$parameters = [
'enabled' => $this->config->getUserValue($user->getUid(), 'side_menu', 'enabled', '1'),
'top-menu-apps' => (array) json_decode($this->config->getUserValue($user->getUid(), 'side_menu', 'top-menu-apps', '[]'), true),
'apps' => $this->appRepository->getVisibleApps(),
];
return new TemplateResponse('side_menu', 'settings/personal-form', $parameters, '');
}
/**
* @return string the section ID, e.g. 'sharing'
*/
public function getSection()
{
return 'side_menu';
}
/**
* @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
*
* E.g.: 70
*/
public function getPriority()
{
return 70;
}
}
+88
View File
@@ -0,0 +1,88 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
namespace OCA\SideMenu\Settings;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
class PersonalSection implements IIconSection
{
/**
* @var IL10N
*/
private $l;
/**
* @var IURLGenerator
*/
private $url;
/**
* @param IURLGenerator $url
* @param IL10N $l
*/
public function __construct(IURLGenerator $url, IL10N $l)
{
$this->url = $url;
$this->l = $l;
}
/**
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
*
* @returns string
*/
public function getID()
{
return 'side_menu';
}
/**
* returns the translated name as it should be displayed, e.g. 'LDAP / AD
* integration'. Use the L10N service to translate it.
*
* @return string
*/
public function getName()
{
return $this->l->t('Side menu');
}
/**
* @return int whether the form should be rather on the top or bottom of
* the settings navigation. The sections are arranged in ascending order of
* the priority values. It is required to return a value between 0 and 99.
*
* E.g.: 70
*/
public function getPriority()
{
return 70;
}
/**
* {@inheritdoc}
*/
public function getIcon()
{
return $this->url->imagePath('theming', 'app-dark.svg');
}
}
+2
View File
@@ -13,6 +13,8 @@
"dependencies": { "dependencies": {
"@nextcloud/axios": "^1.3.2", "@nextcloud/axios": "^1.3.2",
"@nextcloud/vue": "^1.4.0", "@nextcloud/vue": "^1.4.0",
"axios": "^0.19.2",
"trim": "0.0.1",
"vue": "^2.6.11" "vue": "^2.6.11"
}, },
"browserslist": [ "browserslist": [
+15 -3
View File
@@ -17,19 +17,31 @@
import Vue from 'vue' import Vue from 'vue'
import SideMenu from './SideMenu.vue' import SideMenu from './SideMenu.vue'
import SideMenuBig from './SideMenuBig.vue'
// Vue.prototype.t = t // Vue.prototype.t = t
// Vue.prototype.OC = OC Vue.prototype.OC = OC
// Vue.prototype.OC = OCP // Vue.prototype.OC = OCP
const View = Vue.extend(SideMenu)
const sideMenu = new View({})
const mountSideMenuComponent = () => { const mountSideMenuComponent = () => {
const sideMenuContainer = document.querySelector('#side-menu') const sideMenuContainer = document.querySelector('#side-menu')
if (sideMenuContainer) { if (sideMenuContainer) {
let component
if (sideMenuContainer.getAttribute('data-bigmenu')) {
component = SideMenuBig
} else {
component = SideMenu
}
const View = Vue.extend(component)
const sideMenu = new View({})
sideMenu.$mount('#side-menu') sideMenu.$mount('#side-menu')
$('body').trigger('side-menu.ready')
} else { } else {
window.setTimeout(mountSideMenuComponent, 50) window.setTimeout(mountSideMenuComponent, 50)
} }
+65 -24
View File
@@ -26,10 +26,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<ul class="side-menu-apps-list"> <ul class="side-menu-apps-list">
<li v-for="app in apps" v-bind:class="{'side-menu-app': true, 'active': app.active}"> <li v-for="app in apps" v-bind:class="{'side-menu-app': true, 'active': app.active}">
<a v-bind:href="app.href"> <a v-bind:href="app.href" v-bind:title="app.name">
<span class="side-menu-app-icon" v-html="app.icon"></span> <span class="side-menu-app-icon" v-html="app.icon"></span>
<span class="side-menu-app-text" v-html="app.name"></span>
{{ app.name }}
</a> </a>
</li> </li>
</ul> </ul>
@@ -37,55 +36,97 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</template> </template>
<script> <script>
import trim from 'trim'
export default { export default {
name: 'SideMenu', name: 'SideMenu',
data() { data() {
return { return {
apps: [], apps: [],
logo: null logo: null,
forceLightIcon: false,
} }
}, },
methods: { methods: {
retrieveApps() { retrieveApps() {
this.apps = []; this.apps = []
const links = document.querySelectorAll('#appmenu a'); const links = document.querySelectorAll('#appmenu a')
const menu = document.querySelector('#appmenu')
let menuIsHidden = true
if (menu) {
menuIsHidden = window.getComputedStyle(menu, null).getPropertyValue('display') === 'none'
}
for (let element of links) { for (let element of links) {
let href = element.getAttribute('href') let href = element.getAttribute('href')
var parent = element.parentNode
if (!parent) {
continue
}
var dataId = parent.getAttribute('data-id')
dataId = dataId !== null ? dataId : ''
if (!parent.classList.contains('app-hidden') && !menuIsHidden) {
continue
}
if (href !== '#') { if (href !== '#') {
let svg = element.querySelector('svg').outerHTML
svg = svg
.replace(/(height|width)="20"/, '')
.replace('id="invertMenuMain', 'id="invertSideMenu')
.replace('url(#invertMenuMain', 'url(#invertSideMenu')
if (this.forceLightIcon) {
svg = svg.replace(/filter="url[^"]+"/, '')
}
this.apps.push({ this.apps.push({
href: href, href: href,
name: element.querySelector('span').innerHTML, name: trim(element.querySelector('span').innerHTML),
icon: element.querySelector('svg').outerHTML, icon: svg,
active: element.classList.contains('active') active: element.classList.contains('active')
}); });
} }
} }
(function(apps) {
window.setTimeout(function() {
jQuery('body').trigger('side-menu.apps', [apps])
}, 1000)
})(this.apps)
}, },
retrieveLogo() { retrieveLogo() {
const ncLogo = document.querySelector('#nextcloud .logo') const ncLogo = document.querySelector('#nextcloud .logo')
if (ncLogo) { if (ncLogo) {
const url = window.getComputedStyle(ncLogo, null) const url = window.getComputedStyle(ncLogo, null)
.getPropertyValue('background-image') .getPropertyValue('background-image')
.replace('url("', '') .replace('url("', '')
.replace('")', '') .replace('")', '')
if (url && url !== 'none') { if (url && url !== 'none') {
this.logo = url this.logo = url
} }
} }
}, },
}, },
created() { mounted() {
this.retrieveApps(); this.retrieveApps()
this.retrieveLogo(); this.retrieveLogo()
this.forceLightIcon = document.querySelector('#side-menu-container').getAttribute('data-forcelighticon') == 1;
const menu = document.querySelector('#appmenu') const menu = document.querySelector('#appmenu')
const config = {attributes: true, childList: true, subtree: true};
const observer = new MutationObserver(this.retrieveApps); if (menu) {
observer.observe(menu, config); const config = {attributes: true, childList: true, subtree: true}
const observer = new MutationObserver(this.retrieveApps)
observer.observe(menu, config)
}
} }
} }
</script> </script>
+86
View File
@@ -0,0 +1,86 @@
<!--
@license GNU AGPL version 3 or any later version
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
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
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 <http://www.gnu.org/licenses/>.
-->
<template>
<div id="side-menu" class="side-menu-big">
<div class="side-menu-header">
<button class="side-menu-opener side-menu-closer"></button>
<button class="side-menu-opener"></button>
</div>
<div class="side-menu-categories-wrapper">
<div class="side-menu-categories">
<div class="side-menu-category" v-for="category in items">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-html="category.name"></h2>
<ul class="side-menu-apps-list">
<li v-bind:class="{'side-menu-app': true, 'active': activeApp === appId}" v-for="(app, appId) in category.apps">
<a v-bind:href="app.href" v-bind:title="app.name">
<img class="side-menu-app-icon" v-bind:src="app.icon"></span>
<span class="side-menu-app-text" v-html="app.name"></span>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import trim from 'trim'
import axios from 'axios'
export default {
name: 'SideMenuBig',
data() {
return {
items: [],
activeApp: null,
}
},
methods: {
retrieveApps() {
this.apps = []
let that = this
axios
.get(OC.generateUrl('/apps/side_menu/nav/items'))
.then(function(response) {
that.items = response.data.items
let apps = []
for (let category of that.items) {
for (let a in category.apps) {
apps.push(category.apps[a])
}
}
jQuery('body').trigger('side-menu.apps', [apps])
});
},
retrieveActiveApp() {
let activeAppLink = document.querySelector('#appmenu a.active')
this.activeApp = activeAppLink ? activeAppLink.parentNode.getAttribute('data-id') : null
},
},
mounted() {
this.retrieveApps()
this.retrieveActiveApp()
}
}
</script>
+45 -17
View File
@@ -15,28 +15,48 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
const elements = [ let elements = []
'side-menu-background-color',
'side-menu-current-app-background-color',
'side-menu-text-color',
'side-menu-opener',
'side-menu-display-logo',
'side-menu-cache',
];
const selector = '#side-menu-message'; const selector = '#side-menu-message';
const saveSettings = (key) => { const userConfig = (name, value, callbacks) => {
const element = elements[key] const url = OC.generateUrl('/apps/side_menu/personalSetting/valueSet')
const name = $('#' + element).attr('name')
let value = $('#' + element).val()
const size = elements.length
if (element === 'side-menu-cache') { $.post(url, {name: name, value: value}, callbacks.success)
value++ .fail(callbacks.error)
}
const appConfig = (name, value, callbacks) => {
OCP.AppConfig.setValue('side_menu', name, value, callbacks)
}
const saveSettings = (key) => {
const element = elements.get(key)
let value
let name
if ($(element).is('[data-checkbox]')) {
name = $(element).attr('data-name')
const inputs = $('input[name="' + name + '[]"]:checked')
value = []
inputs.each((i, v) => {
value.push(v.value)
})
value = JSON.stringify(value)
} else {
name = $(element).attr('name')
value = $(element).val()
} }
OCP.AppConfig.setValue('side_menu', name, value, { const size = elements.length
if (name === 'cache') {
++value
}
const callbacks = {
success: () => { success: () => {
OC.msg.finishedSuccess( OC.msg.finishedSuccess(
selector, selector,
@@ -52,10 +72,18 @@ const saveSettings = (key) => {
error: () => { error: () => {
OC.msg.finishedError(selector, t('side_menu', 'Error while saving "' + element + '"')) OC.msg.finishedError(selector, t('side_menu', 'Error while saving "' + element + '"'))
} }
}); }
if ($(element).is('[data-personal]')) {
userConfig(name, value, callbacks)
} else {
appConfig(name, value, callbacks)
}
} }
$(document).ready(() => { $(document).ready(() => {
elements = $('.side-menu-setting')
$('#side-menu-save').on('click', (event) => { $('#side-menu-save').on('click', (event) => {
event.preventDefault() event.preventDefault()
OC.msg.startSaving(selector) OC.msg.startSaving(selector)
+48
View File
@@ -0,0 +1,48 @@
"Side menu": "Seitenmenü"
"Enable the side menu": "Aktivieren Sie das Seitenmenü"
"No": "Nein"
"Yes": "Ja"
"Menu": "Speisekarte"
'Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to navigate.': 'Verwenden Sie die Tastenkombination <span class="keyboard-key">Strg</span>+<span class="keyboard-key">o</span>, um das Seitenmenü zu öffnen und auszublenden. Verwenden Sie zum Navigieren die Registerkarte <span class="keyboard-key">tab</span>.'
"Top menu": "Hauptmenü"
"Apps that not must be moved in the side menu": "Apps, die nicht im Seitenmenü verschoben werden müssen"
"If there is no selection then the global configuration is applied.": "Wenn keine Auswahl vorhanden ist, wird die globale Konfiguration angewendet."
"Experimental": "Experimental"
"Save": "Sparen"
"You like this app and you want to support me?": "Du magst diese App und möchtest mich unterstützen?"
"Buy me a coffe ☕": "Gib mir einen Kaffee ☕"
"Hidden": "Versteckt"
"Small": "Klein"
"Normal": "Normal"
"Big": "Groß"
"Colors": "Farben"
"Background color": "Hintergrundfarbe"
"Background color of current app": "Hintergrundfarbe der aktuellen App"
"Text color": "Textfarbe"
"Loader": "Ladestandanzeige"
"Icon": "Symbol"
"Same color": "Selbe Farbe"
"Opposite color": "Gegenfarbe"
"Transparent": "Transparent"
"Opaque": "Undurchsichtig"
"Opener": "Öffner"
"Default": "Standard"
"Default (dark)": "Standard (dunkel)"
"Hamburger": "Hamburger"
"Hamburger (dark)": "Hamburger (dunkel)"
"Hamburger 2": "Hamburger 2"
"Hamburger 2 (dark)": "Hamburger 2 (dunkel)"
"Before the logo": "Vor dem Logo"
"After the logo": "Nach dem Logo"
"Position": "Position"
"Show only the opener (hidden logo)": "Nur den Öffner anzeigen (verstecktes Logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Zeigen Sie das Seitenmenü und den Öffner nicht an, wenn keine Anwendung vorhanden ist (z. B. öffentliche Seiten)."
"Panel": "Panel"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Öffnen Sie das Menü, wenn Sie die Maus über den Öffner bewegen (auf Touchscreens automatisch deaktiviert)."
"Display the big menu": "Großes Menü anzeigen"
"The big menu is not compatible with AppOrder.": "Le menu large n'est pas compatible avec l'application AppOrder"
"Display the logo": "Logo anzeigen"
"This feature is not compatible with the <code>big menu</code> display.": "Diese Funktion ist nicht mit der großen Menüanzeige kompatibel."
"Icons and texts": "Symbole und Texte"
"Loader enabled": "Loader aktiviert"
"Tips": "Tipps"
+48
View File
@@ -0,0 +1,48 @@
"Side menu": "Menu latéral"
"Enable the side menu": "Activer le menu latéral"
"No": "Non"
"Yes": "Oui"
"Menu": "Menu"
'Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to navigate.': 'Utiliser le raccourcis clavier <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> pour ouvrir et fermer le menu latéral. Utiliser <span class="keyboard-key">tab</span> pour naviguer.'
"Top menu": "Menu supérieur"
"Apps that not must be moved in the side menu": "Les applications qui ne doivent pas être affichées dans le menu latéral"
"If there is no selection then the global configuration is applied.": "Si il n'y a aucune sélection alors la configuration globale sera appliquée"
"Experimental": "Expérimental"
"Save": "Sauvegarder"
"You like this app and you want to support me?": "Vous aimer cette application et vous souhaitez m'aider ?"
"Buy me a coffe ☕": "Offrez moi un café ☕"
"Hidden": "Caché"
"Small": "Petit"
"Normal": "Normal"
"Big": "Gros"
"Colors": "Couleurs"
"Background color": "Couleur de fond"
"Background color of current app": "Couleur de fond de l'application en cours"
"Text color": "Couleur du texte"
"Loader": "Indicateur de chargement"
"Icon": "Icône"
"Same color": "Même couleur"
"Opposite color": "Couleur opposée"
"Transparent": "Transparent"
"Opaque": "Opaque"
"Opener": "Bouton d'ouverture"
"Default": "Par défaut"
"Default (dark)": "Par défaut (sombre)"
"Hamburger": "Hamburger"
"Hamburger (dark)": "Hamburger (sombre)"
"Hamburger 2": "Hamburger 2"
"Hamburger 2 (dark)": "Hamburger 2 (sombre)"
"Before the logo": "Avant le logo"
"After the logo": "Après le logo"
"Position": "Position"
"Show only the opener (hidden logo)": "Afficher uniquement le bouton d'ouverture (masquer le logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Ne pas afficher le menu latéral et le bouton d'ouverture s'il n'y a aucune application (exemple : page publiques)."
"Panel": "Panneau"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Ouvrir le menu au passage de la souris (automatiquement désactivé sur les écrans tactiles)"
"Display the big menu": "Afficher le menu large"
"The big menu is not compatible with AppOrder.": "Le menu large n'est pas compatible avec l'application AppOrder"
"Display the logo": "Afficher le logo"
"This feature is not compatible with the <code>big menu</code> display.": "Cette fonctionnalité n'est pas compatible avec l'affichage du menu large."
"Icons and texts": "Icônes et textes"
"Loader enabled": "Activation de l'indicateur de chargement"
"Tips": "Astuces"
-30
View File
@@ -1,30 +0,0 @@
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
const sideMenuContainer = $('<div id="side-menu-container">')
const sideMenuOpener = $('<button class="side-menu-opener"></button>')
const sideMenu = $('<div id="side-menu">')
sideMenuContainer.append(sideMenu);
$('body').append(sideMenuContainer);
sideMenuOpener.insertBefore('#nextcloud');
$('body').on('click', '.side-menu-opener', () => {
$('#side-menu').toggleClass('open');
})
+105 -13
View File
@@ -1,24 +1,116 @@
:root { :root {
<?php foreach ($_['vars'] as $key => $value): ?> <?php foreach ($_['vars'] as $key => $value): ?>
<?php if ($key === 'opener'): ?> <?php if ($key === 'opener'): ?>
--side-menu-<?php echo $key ?>: url('<?php echo $_['assetsRoot'] ?>/img/<?php echo $value ?>.svg'); --side-menu-<?php echo $key ?>: url('<?php print_unescaped(image_path('side_menu', $value.'.svg')); ?>');
<?php else: ?> <?php else: ?>
--side-menu-<?php echo $key ?>: <?php echo $value ?>; --side-menu-<?php echo $key ?>: <?php echo $value ?>;
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
} }
<?php if ($_['display-logo'] === false): ?> <?php if (empty($_['top-menu-apps'])): ?>
.side-menu-logo { #appmenu {
display: none; display: none;
} }
.side-menu-header { #appmenu + nav {
height: 50px; display: none;
} }
<?php else: ?>
.side-menu-apps-list { .app-hidden {
height: calc(100vh - 60px); opacity: 0;
top: 60px; }
} <?php endif; ?>
<?php if ($_['opener-only'] === true): ?>
#nextcloud {
display: none;
}
<?php endif; ?>
<?php if ($_['display-logo'] === false): ?>
.side-menu-logo {
display: none;
}
.side-menu-header {
height: 50px;
}
.side-menu-apps-list {
height: calc(100vh - 49px);
top: 49px;
}
#side-menu.hide-opener .side-menu-header {
visibility: hidden;
}
<?php if ($_['size-text'] === 'hidden'): ?>
#side-menu, .side-menu-apps-list {
<?php if ($_['size-icon'] === 'big'): ?>
width: 55px;
<?php else: ?>
width: 52px;
<?php endif; ?>
}
#side-menu .side-menu-opener {
<?php if ($_['size-icon'] === 'big'): ?>
margin-left: 1px;
<?php else: ?>
margin-left: 0px;
<?php endif; ?>
}
<?php endif; ?>
<?php endif; ?>
<?php if ($_['size-icon'] === 'hidden'): ?>
.side-menu-app-icon {
display: none;
}
<?php elseif ($_['size-icon'] === 'small'): ?>
.side-menu-app-icon svg {
width: 15px;
height: 15px;
}
img.side-menu-app-icon {
width: 15px;
height: 15px;
}
<?php elseif ($_['size-icon'] === 'normal'): ?>
.side-menu-app-icon svg {
width: 20px;
height: 20px;
}
img.side-menu-app-icon {
width: 20px;
height: 20px;
}
<?php elseif ($_['size-icon'] === 'big'): ?>
.side-menu-app-icon svg {
width: 23px;
height: 23px;
}
img.side-menu-app-icon {
width: 23px;
height: 23px;
}
<?php endif; ?>
<?php if ($_['size-text'] === 'hidden'): ?>
.side-menu-app-text {
display: none;
}
<?php elseif ($_['size-text'] === 'small'): ?>
.side-menu-app-text {
font-size: 12px;
}
<?php elseif ($_['size-text'] === 'big'): ?>
.side-menu-app-text {
font-size: 16px;
}
<?php endif; ?> <?php endif; ?>
+15
View File
@@ -0,0 +1,15 @@
var pageLoader = $('<div id="side-menu-loader">')
var pageLoaderBar = $('<div id="side-menu-loader-bar">')
body.append(pageLoader)
pageLoader.append(pageLoaderBar)
var pageLoaderValue = 0
$(window).on('beforeunload', function() {
setInterval(function() {
pageLoaderBar.width(pageLoaderValue.toString() + '%')
pageLoaderValue = Math.min(pageLoaderValue + .2, 100)
}, 25)
})
+146
View File
@@ -0,0 +1,146 @@
var menuCache = null
var updateTopMenu = function() {
var breakpointMobileWidth = 1024
var menu = $('#appmenu')
var apps = menu.find('li')
var minAppsDesktop = 8
var usePercentualAppMenuLimit = 0.8
var isMobile = $(window).width() < breakpointMobileWidth
var lastShownApp = null
var appShown = []
var moreApps = $('#more-apps')
var navigation = $('#navigation')
var navigationApps = $('#apps ul')
var appCount = null
var currentMenuCache = menu.html() + menu.next().html()
if (currentMenuCache === menuCache) {
return
}
navigationApps.html('')
apps.each(function(i, app) {
var dataId = app.getAttribute('data-id')
if (dataId === null) {
return
}
if (topMenuApps.indexOf(dataId) === -1) {
app.classList.add('hidden')
app.classList.add('app-hidden')
} else {
app.classList.remove('hidden')
app.classList.add('app-external-site')
appShown.push(app)
navigationApps.append(app.outerHTML)
}
})
var rightHeaderWidth = $('.header-right').outerWidth()
var headerWidth = $('header').outerWidth()
var availableWidth = headerWidth - $('#nextcloud').outerWidth()
- $('#header .side-menu-opener').outerWidth()
- (rightHeaderWidth > 230 ? rightHeaderWidth : 230)
if (!isMobile) {
availableWidth = availableWidth * usePercentualAppMenuLimit
}
appCount = Math.floor(availableWidth / $('#appmenu li').width())
if (isMobile && appCount > minAppsDesktop) {
appCount = minAppsDesktop
} else if (!isMobile && appCount < minAppsDesktop) {
appCount = minAppsDesktop
}
if (appCount === 0) {
menu.addClass('hidden')
}
menu.removeClass('hidden')
menu.css('opacity', 1)
if (appShown.length - 1 - appCount >= 1) {
appCount--
}
moreApps.find('a').removeClass('active')
var k = 0
var notInHeader = 0
var name
$(appShown).each(function(i, app) {
app = $(app)
name = app.data('id')
if (k < appCount && appCount > 0) {
app.removeClass('hidden')
lastShownApp = app
$('#apps li[data-id=' + name + '].app-external-site').addClass('in-header')
} else {
app.addClass('hidden')
notInHeader++
$('#apps li[data-id=' + name + '].app-external-site').removeClass('in-header')
if (appCount > 0 && app.children('a').hasClass('active')) {
lastShownApp.addClass('hidden')
app.removeClass('hidden')
notInHeader++
$('#apps li[data-id=' + name + '].app-external-site')
.removeClass('in-header')
.addClass('in-header')
}
}
k++
})
$('#apps li.app-external-site').each(function(i, app) {
app = $(app)
var appId = app.attr('data-id')
if (app.hasClass('in-header')) {
app.find('svg').find('defs').remove()
} else {
var svg = app.find('svg');
if (svg.find('defs').length > 0) {
return;
}
var defs = `
<defs>
<filter id="invertMenuMore-${appId}">
<feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix>
</filter>
</defs>`
svg.prepend(defs)
svg.find('image').attr('filter', `url(#invertMenuMore-${appId})`)
var html = svg.get(0).innerHTML.replace(/fecolormatrix/g, 'feColorMatrix');
svg.html(html)
}
})
if (notInHeader === 0) {
moreApps.hide()
navigation.hide()
} else {
moreApps.show()
}
menuCache = menu.html() + menu.next().html()
}
setInterval(updateTopMenu, 50)
+112
View File
@@ -0,0 +1,112 @@
(function() {
var sideMenuContainer = $('<div id="side-menu-container">')
var sideMenuOpener = $('<button class="side-menu-opener"></button>')
var sideMenu = $('<div id="side-menu">')
var body = $('body')
var isTouchDevice = window.matchMedia("(pointer: coarse)").matches
<?php if ($_['big-menu']): ?>
sideMenu.attr('data-bigmenu', '1')
<?php endif; ?>
<?php if ($_['force-light-icon']): ?>
sideMenuContainer.attr('data-forcelighticon', '1')
<?php endif; ?>
body.on('side-menu.apps', function(e, apps) {
<?php if ($_['hide-when-no-apps']): ?>
sideMenu = $('#side-menu')
if (apps.length === 0) {
sideMenu.removeClass('open')
sideMenuOpener.addClass('hide')
} else {
sideMenuOpener.removeClass('hide')
}
<?php endif; ?>
})
body.on('side-menu.ready', function() {
sideMenu = $('#side-menu')
var headerMenuOpener = $('#header .side-menu-opener')
var sideMenuOpener = $('#side-menu .side-menu-opener')
sideMenuFocus = function() {
var a = sideMenu.find('.side-menu-app.active a')
if (a.length === 0) {
a = sideMenu.find('.side-menu-app:first-child a')
}
if (a.length > 0) {
a.focus()
}
}
<?php if ($_['opener-hover']): ?>
var sideMenuMouseLeave = function() {
sideMenu
.removeClass('open')
.off('mouseleave', sideMenuMouseLeave)
}
var sideMenuMouseEnter = function() {
sideMenu.on('mouseleave', sideMenuMouseLeave)
}
var sideMenuOpenerMouseEnter = function() {
sideMenu
.addClass('open')
.on('mouseenter', sideMenuMouseEnter)
sideMenuFocus()
}
if (!isTouchDevice) {
headerMenuOpener.on('mouseenter', sideMenuOpenerMouseEnter)
sideMenu.addClass('hide-opener')
}
<?php endif; ?>
headerMenuOpener.on('click', function() {
sideMenu.addClass('open')
sideMenu.find('.side-menu-app.active a').focus()
})
sideMenuOpener.on('click', function() {
sideMenu.removeClass('open')
})
$(document).keydown(function(e) {
var key = e.key || e.keyCode
if ((key === 'o' || key === 79) && e.ctrlKey === true) {
e.preventDefault()
sideMenu.toggleClass('open')
sideMenuFocus()
}
})
})
body.append(sideMenuContainer)
sideMenuContainer.append(sideMenu)
<?php if ($_['loader-enabled'] === true): ?>
<?php require_once __DIR__.'/_loaderEnabled.js'; ?>
<?php endif; ?>
<?php if ($_['opener-position'] === 'before'): ?>
sideMenuOpener.insertBefore('#nextcloud')
<?php else: ?>
sideMenuOpener.insertAfter('#nextcloud')
<?php endif; ?>
<?php if (!empty($_['top-menu-apps'])): ?>
var topMenuApps = <?php echo json_encode($_['top-menu-apps']); ?>;
<?php require_once __DIR__.'/_topMenuApps.js'; ?>
<?php endif; ?>
})();
+362 -77
View File
@@ -18,100 +18,385 @@
script('side_menu', 'admin'); script('side_menu', 'admin');
style('side_menu', 'admin'); style('side_menu', 'admin');
style('side_menu', 'support');
$choicesYesNo = [
'No' => '0',
'Yes' => '1',
];
$choicesSizes = [
'Hidden' => 'hidden',
'Small' => 'small',
'Normal' => 'normal',
'Big' => 'big',
];
?> ?>
<div id="side-menu-section" class="section"> <div id="side-menu-section">
<h2 class="inlineblock"><?php p($l->t('Side menu settings')); ?></h2> <div class="section">
<h2>
<?php p($l->t('Colors')); ?>
</h2>
<div> <div>
<label for="side-menu-background-color" class="settings-hint"> <label for="side-menu-background-color">
<?php p($l->t('Background color')); ?> <?php p($l->t('Background color')); ?>
</label> </label>
</div> </div>
<div> <div>
<input <input
id="side-menu-background-color" id="side-menu-background-color"
name="background-color" name="background-color"
type="color" type="color"
value="<?php print_unescaped($_['background-color']); ?>"> class="side-menu-setting"
value="<?php print_unescaped($_['background-color']); ?>">
<input
id="side-menu-background-color-to"
name="background-color-to"
type="color"
class="side-menu-setting"
value="<?php print_unescaped($_['background-color-to']); ?>">
</div>
<div>
<label for="side-menu-current-app-background-color">
<?php p($l->t('Background color of current app')); ?>
</label>
</div>
<div>
<input
id="side-menu-current-app-background-color"
name="current-app-background-color"
type="color"
class="side-menu-setting"
value="<?php print_unescaped($_['current-app-background-color']); ?>">
</div>
<div>
<label for="side-menu-text-color">
<?php p($l->t('Text color')); ?>
</label>
</div>
<div>
<input
id="side-menu-text-color"
name="text-color"
type="color"
class="side-menu-setting"
value="<?php print_unescaped($_['text-color']); ?>">
</div>
<div>
<label for="side-menu-text-color">
<?php p($l->t('Loader')); ?>
</label>
</div>
<div>
<input
id="side-menu-loader-color"
name="loader-color"
type="color"
class="side-menu-setting"
value="<?php print_unescaped($_['loader-color']); ?>">
</div>
<div>
<label for="side-menu-icon-invert-filter">
<?php p($l->t('Icon')); ?>
</label>
</div>
<div>
<em>
<?php p($l->t('Same color')); ?>
</em>
<input
type="range"
min="0" max="100"
id="side-menu-icon-invert-filter"
name="icon-invert-filter"
class="side-menu-setting"
value="<?php echo $_['icon-invert-filter'] ?>"
>
<em>
<?php p($l->t('Opposite color')); ?>
</em>
</div>
<div>
<em>
<?php p($l->t('Transparent')); ?>
</em>
<input
type="range"
min="0" max="100"
id="side-menu-icon-opacity"
name="icon-opacity"
class="side-menu-setting"
value="<?php echo $_['icon-opacity'] ?>"
>
<em>
<?php p($l->t('Opaque')); ?>
</em>
</div>
</div> </div>
<div> <div class="section">
<label for="side-menu-current-app-background-color" class="settings-hint"> <h2>
<?php p($l->t('Background color of current app')); ?> <?php p($l->t('Opener')); ?>
</label> </h2>
</div>
<div> <?php
<input $choices = [
id="side-menu-current-app-background-color" 'Default' => 'side-menu-opener',
name="current-app-background-color" 'Default (dark)' => 'side-menu-opener-dark',
type="color" 'Hamburger' => 'side-menu-opener-hamburger',
value="<?php print_unescaped($_['current-app-background-color']); ?>"> 'Hamburger (dark)' => 'side-menu-opener-hamburger-dark',
'Hamburger 2' => 'side-menu-opener-hamburger-2',
'Hamburger 2 (dark)' => 'side-menu-opener-hamburger-2-dark',
];
?>
<div>
<label for="side-menu-opener">
<?php p($l->t('Icon')); ?>
</label>
</div>
<div>
<select id="side-menu-opener" name="opener" class="side-menu-setting">
<?php foreach ($choices as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['opener']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php
$choices = [
'Before the logo' => 'before',
'After the logo' => 'after',
];
?>
<div>
<label for="side-menu-opener-position">
<?php p($l->t('Position')); ?>
</label>
</div>
<div>
<select id="side-menu-opener-position" name="opener-position" class="side-menu-setting">
<?php foreach ($choices as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['opener-position']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="side-menu-opener-only">
<?php p($l->t('Show only the opener (hidden logo)')); ?>
</label>
</div>
<div>
<select id="side-menu-opener-only" name="opener-only" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['opener-only']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="side-menu-hide-when-no-apps">
<?php p($l->t('Do not display the side menu and the opener if there is no application (eg: public pages).')); ?>
</label>
</div>
<div>
<select id="side-menu-hide-when-no-apps" name="hide-when-no-apps" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['hide-when-no-apps']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div> </div>
<div> <div class="section">
<label for="side-menu-text-color" class="settings-hint"> <h2>
<?php p($l->t('Text color')); ?> <?php p($l->t('Panel')); ?>
</label> </h2>
</div>
<div> <div>
<input <label for="side-menu-opener">
id="side-menu-text-color" <?php p($l->t('Open the menu when the mouse is hover the opener (automatically disabled on touch screens)')); ?>
name="text-color" </label>
type="color" </div>
value="<?php print_unescaped($_['text-color']); ?>">
<p>
<em><?php echo $l->t('Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to navigate.'); ?></em>
</p>
<div>
<select id="side-menu-opener-hover" name="opener-hover" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['opener-hover']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="side-menu-big-menu">
<?php p($l->t('Display the big menu')); ?>
<small><span class="warning"><?php p($l->t('Experimental')); ?></span></small>
</label>
</div>
<p><em><?php p($l->t('The big menu is not compatible with AppOrder.')); ?></em></p>
<div>
<select id="side-menu-big-menu" name="big-menu" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['big-menu']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="side-menu-opener">
<?php p($l->t('Display the logo')); ?>
</label>
</div>
<p><em><?php p($l->t('This feature is not compatible with the <code>big menu</code> display.')); ?></em></p>
<div>
<select id="side-menu-display-logo" name="display-logo" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['display-logo']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label>
<?php p($l->t('Icons and texts')); ?>
</label>
</div>
<div>
<select id="side-menu-size-icon" name="size-icon" class="side-menu-setting">
<?php foreach ($choicesSizes as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['size-icon']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?> icon
</option>
<?php endforeach; ?>
</select>
<select id="side-menu-size-text" name="size-text" class="side-menu-setting">
<?php foreach ($choicesSizes as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['size-text']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?> text
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="side-menu-loader-enabled">
<?php p($l->t('Loader enabled')); ?>
</label>
</div>
<div>
<select id="side-menu-loader-enabled" name="loader-enabled" class="side-menu-setting">
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['loader-enabled']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div> </div>
<div> <div class="section">
<label for="side-menu-opener" class="settings-hint"> <h2>
<?php p($l->t('Opener icon')); ?> <?php p($l->t('Top menu')); ?>
</label> </h2>
</div> <div>
<label for="side-menu-top-menu-apps">
<?php p($l->t('Apps that not must be moved in the side menu')); ?>
<small><span class="warning">Experimental</span></small>
</label>
</div>
<?php <div class="side-menu-setting" data-name="top-menu-apps" data-checkbox>
$choices = [ <?php foreach ($_['apps'] as $app): ?>
'Default' => 'side-menu-opener', <div>
'Hamburger' => 'side-menu-opener-hamburger', <input
]; type="checkbox"
?> name="top-menu-apps[]"
value="<?php echo $app['id'] ?>"
id="top-menu-app-<?php echo $app['id'] ?>"
<?php if (in_array($app['id'], $_['top-menu-apps'])): ?>checked<?php endif; ?>
/>
<div> <label for="top-menu-app-<?php echo $app['id'] ?>">
<select id="side-menu-opener" name="opener"> <?php echo p($l->t($app['name'])); ?>
<?php foreach ($choices as $label => $value): ?> </label>
<option value="<?php echo $value ?>" <?php if ($value === $_['opener']): ?>selected<?php endif; ?>> </div>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </div>
</div> </div>
<div> <div class="section">
<label for="side-menu-opener" class="settings-hint"> <h2>
<?php p($l->t('Display the logo')); ?> <?php p($l->t('Tips')); ?>
</label> </h2>
<p>
<em><?php echo $l->t('Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to navigate.'); ?></em>
</p>
</div> </div>
<?php <div class="section">
$choices = [ <input type="hidden" id="side-menu-cache" name="cache" value="<?php print_unescaped($_['cache']); ?>" class="side-menu-setting">
'Yes' => '1',
'No' => '0',
];
?>
<div> <button id="side-menu-save" class="btn btn-primary"><?php p($l->t('Save')); ?></button>
<select id="side-menu-display-logo" name="display-logo">
<?php foreach ($choices as $label => $value): ?> <span id="side-menu-message" class="msg"></span>
<option value="<?php echo $value ?>" <?php if ($value === $_['display-logo']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?> <div style="height: 30px"></div>
</option>
<?php endforeach; ?> <div>
</select> <span for="side-menu-opener">
<?php p($l->t('You like this app and you want to support me?')); ?>
<a style="margin-left: 10px" target="_blank" href="https://www.buymeacoffee.com/deblan">
<button>
<?php p($l->t('Buy me a coffe ☕')); ?>
</button>
</a>
</span>
</div>
</div> </div>
<input type="hidden" id="side-menu-cache" name="cache" value="<?php print_unescaped($_['cache']); ?>">
<button id="side-menu-save" class="btn btn-primary"><?php p($l->t('Save')); ?></button>
<span id="side-menu-message" class="msg"></span>
</div> </div>
+112
View File
@@ -0,0 +1,112 @@
<?php
/**
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
script('side_menu', 'admin');
style('side_menu', 'admin');
style('side_menu', 'support');
$choicesYesNo = [
'No' => '0',
'Yes' => '1',
];
?>
<div id="side-menu-section">
<div class="section">
<h2>
<?php p($l->t('Menu')); ?>
</h2>
<div>
<label for="side-menu-enabled">
<?php p($l->t('Enable the side menu')); ?>
</label>
</div>
<p>
<em><?php echo $l->t('Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to navigate.'); ?></em>
</p>
<div>
<select id="side-menu-enabled" name="enabled" class="side-menu-setting" data-personal>
<?php foreach ($choicesYesNo as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['enabled']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="section">
<h2>
<?php p($l->t('Top menu')); ?>
</h2>
<div>
<label for="side-menu-top-menu-apps">
<?php p($l->t('Apps that not must be moved in the side menu')); ?>
<small><span class="warning"><?php p($l->t('Experimental')); ?></span></small>
</label>
</div>
<p>
<em>
<?php p($l->t('If there is no selection then the global configuration is applied.')); ?>
</em>
</p>
<div class="side-menu-setting" data-name="top-menu-apps" data-checkbox data-personal>
<?php foreach ($_['apps'] as $app): ?>
<div>
<input
type="checkbox"
name="top-menu-apps[]"
value="<?php echo $app['id'] ?>"
id="top-menu-app-<?php echo $app['id'] ?>"
<?php if (in_array($app['id'], $_['top-menu-apps'])): ?>checked<?php endif; ?>
/>
<label for="top-menu-app-<?php echo $app['id'] ?>">
<?php echo $app['name'] ?>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="section">
<button id="side-menu-save" class="btn btn-primary"><?php p($l->t('Save')); ?></button>
<span id="side-menu-message" class="msg"></span>
<div style="height: 30px"></div>
<div>
<span for="side-menu-opener">
<?php p($l->t('You like this app and you want to support me?')); ?>
<a style="margin-left: 10px" target="_blank" href="https://www.buymeacoffee.com/deblan">
<button>
<?php p($l->t('Buy me a coffe ☕')); ?>
</button>
</a>
</span>
</div>
</div>
</div>
-1
View File
@@ -4,7 +4,6 @@ const StyleLintPlugin = require('stylelint-webpack-plugin')
module.exports = { module.exports = {
entry: { entry: {
'main': path.join(__dirname, 'src', 'main.js'),
'admin': path.join(__dirname, 'src', 'admin.js'), 'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'), 'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),
}, },