Compare commits

..

415 Commits

Author SHA1 Message Date
Simon Vieille 9c3d9ccbc4 Merge pull request 'release v3.4.1' (#184) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/184
2022-12-02 12:33:30 +01:00
Simon Vieille 45a68cbfc8 release v3.4.1 2022-12-02 12:25:31 +01:00
Simon Vieille f42cb368db Merge pull request 'hide custom categories list when empty' (#183) from feature/issue182 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/183
2022-12-02 12:23:18 +01:00
Simon Vieille 6d940cc7c4 Merge pull request 'translations' (#181) from translations into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/181
2022-12-02 12:19:04 +01:00
Simon Vieille 2d30a1f1ea hide custom categories list when empty 2022-12-02 12:16:49 +01:00
Simon Vieille 599e70bf8a Merge branch 'develop' into translations 2022-11-21 08:43:19 +01:00
Simon Vieille d012e464a1 add translations 2022-11-21 08:43:08 +01:00
Codeberg Translate ae2b52cb36 Merge branch 'origin/translations' into Weblate. 2022-11-20 22:26:39 +00:00
zonorti 5444bbf987 Translated using Weblate (Russian)
Currently translated at 67.0% (61 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/ru/
2022-11-20 22:26:38 +00:00
jorisvandijk ed7d4f4750 Translated using Weblate (Dutch)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/nl/
2022-11-20 22:26:38 +00:00
Simon Vieille fe5ffcb6bf Merge pull request 'release v3.4.0' (#179) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/179
2022-11-20 15:17:23 +01:00
Simon Vieille f61f05c1c9 release v3.4.0 2022-11-20 15:10:50 +01:00
Simon Vieille c63ac1556e update ci 2022-11-20 15:04:54 +01:00
Simon Vieille c3cd78971b update changelog 2022-11-20 14:47:09 +01:00
Simon Vieille 0f24133b99 fix merge 2022-11-20 14:43:44 +01:00
deblan 887aa7f7f5 Added translation using Weblate (Dutch) 2022-11-20 14:41:02 +01:00
Codeberg Translate ac30ac25e9 Merge branch 'origin/develop' into Weblate. 2022-11-20 13:33:32 +00:00
Codeberg Translate 445b9d6986 Merge branch 'origin/develop' into Weblate. 2022-11-20 13:33:31 +00:00
nier 98d72a1e95 Translated using Weblate (Russian)
Currently translated at 64.8% (59 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/ru/
2022-11-20 13:25:04 +00:00
deblan 5ad6af0b0d Translated using Weblate (Russian)
Currently translated at 64.8% (59 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/ru/
2022-11-20 13:25:04 +00:00
deblan 0f93fbe7ea Translated using Weblate (Dutch)
Currently translated at 0.0% (0 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/nl/
2022-11-20 13:25:04 +00:00
Timur 8db686b3a2 Translated using Weblate (Russian)
Currently translated at 60.4% (55 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/ru/
2022-11-20 13:25:04 +00:00
deblan e208e19b1c Added translation using Weblate (Russian) 2022-11-20 13:25:04 +00:00
Simon Vieille d78bb6d93b update changelog 2022-11-20 14:13:54 +01:00
Simon Vieille 229d25cb44 Merge pull request 'feature/issue177' (#178) from feature/issue177 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/178
2022-11-20 14:12:11 +01:00
Simon Vieille 3ccf754e0d add possibility to define side_menu as default app and redirect to the first top menu app (#177) 2022-11-20 14:00:33 +01:00
Simon Vieille a4060c8db7 add possibility to define side_menu as default app and redirect to the first top menu app (#177) 2022-11-20 14:00:26 +01:00
Simon Vieille b474eeb29a update changelog 2022-11-11 21:20:20 +01:00
Simon Vieille e640343df9 Merge pull request 'translations' (#176) from translations into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/176
2022-11-11 19:41:16 +01:00
p-bo 84d1dff0ff Translated using Weblate (Czech)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/cs/
2022-11-10 21:05:00 +00:00
deblan 13b19c407a Added translation using Weblate (Dutch) 2022-11-10 21:05:00 +00:00
Simon Vieille fa15824dad Merge pull request 'release v3.3.2' (#175) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/175
2022-11-10 13:08:27 +01:00
Simon Vieille 474387ff43 release v3.3.2 2022-11-10 13:07:35 +01:00
Simon Vieille 45ae1b3579 Merge pull request 'reduce the height of categories list (fix #173)' (#174) from feature/issue173 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/174
2022-11-09 13:04:12 +01:00
Simon Vieille c10d0e8442 reduce the height of categories list (fix #173) 2022-11-09 12:51:56 +01:00
Simon Vieille f5cabe9708 Merge pull request 'release v3.3.1' (#171) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/171
2022-11-06 17:01:43 +01:00
Simon Vieille 00e8a56e15 release v3.3.1 2022-11-06 16:55:23 +01:00
Simon Vieille 0ea7fe04bf Merge branch 'feature/issue162' into develop 2022-11-06 16:54:25 +01:00
Simon Vieille 0ac55b7ba4 fix #162: top and side app is broken 2022-11-05 15:40:52 +01:00
Simon Vieille 1794997ca0 Merge pull request 'Translated using Weblate (French)' (#169) from translations into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/169
2022-11-05 12:25:05 +01:00
deblan 3c7cd2812f Translated using Weblate (French)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/fr/
2022-11-05 11:04:27 +00:00
Simon Vieille 2c75ebb3f7 Merge pull request 'translations' (#168) from translations into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/168
2022-11-05 12:02:29 +01:00
Anonymous 8bf7c7a8ce Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/zh_Hans/
2022-11-05 10:49:52 +00:00
Anonymous 5ed9e1e449 Translated using Weblate (French)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/fr/
2022-11-05 10:49:52 +00:00
Anonymous 2b4feb908e Translated using Weblate (German)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/de/
2022-11-05 10:49:51 +00:00
Anonymous 572f05ed52 Translated using Weblate (Czech)
Currently translated at 100.0% (91 of 91 strings)

Translation: Custom menu/Application
Translate-URL: https://translate.codeberg.org/projects/custom-menu/application/cs/
2022-11-05 10:49:51 +00:00
Simon Vieille dbf1c4316a Merge pull request 'release v3.3.0' (#167) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/167
2022-11-04 22:43:18 +01:00
Simon Vieille e9fb46b7b7 release v3.3.0 2022-11-04 22:36:54 +01:00
Simon Vieille 1357571104 update screenshots 2022-11-04 22:26:20 +01:00
Simon Vieille 0cec77154a Merge pull request 'fix #164: open apps in new tab does not work' (#166) from feature/issue164 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/166
2022-11-04 22:17:48 +01:00
Simon Vieille 6d7543f381 fix #164: open apps in new tab does not work 2022-11-04 22:14:28 +01:00
Simon Vieille 1d06c1b212 fix issue with top and side apps (#162 #159) 2022-11-04 21:43:18 +01:00
Simon Vieille 712777470c Merge pull request 'Sort menu on user level' (#165) from feature/issue160 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/165
2022-11-04 21:12:16 +01:00
Simon Vieille 52d88771d9 add apps sorter is user side (fix #160) 2022-11-04 21:07:44 +01:00
Simon Vieille c8ac0b5922 Merge pull request 'feature/doc' (#163) from feature/doc into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/163
2022-11-04 19:32:40 +01:00
Simon Vieille 78162f9a1e add translations 2022-11-04 18:53:47 +01:00
Simon Vieille 81f5dfcf2d add compatibility badges for each options 2022-11-04 18:50:45 +01:00
Simon Vieille 7f6f606d75 fix changelog 2022-10-29 11:41:48 +02:00
Simon Vieille 39fd049642 Merge pull request 'release v3.2.1' (#157) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/157
2022-10-29 10:43:56 +02:00
Simon Vieille 227f26679a release v3.2.1 2022-10-29 10:43:08 +02:00
Simon Vieille 6198a2abc2 Merge pull request 'develop' (#156) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/156
2022-10-28 22:44:23 +02:00
Simon Vieille 6e8d3ce245 Merge pull request 'fix #151: opener position' (#155) from feature/issue151 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/155
2022-10-28 22:35:11 +02:00
Simon Vieille c83dfef021 Merge pull request 'fix #150: Active app is not visible has active in menu (except in default menu).' (#153) from feature/issue150 into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/153
2022-10-28 22:35:04 +02:00
Simon Vieille 8b7163b3d5 fix #151: opener position 2022-10-28 22:23:17 +02:00
Simon Vieille bec53f0486 fix #150: Active app is not visible has active in menu (except in default menu). 2022-10-28 22:16:49 +02:00
Simon Vieille 0acb576995 Merge pull request 'release v3.2.0' (#149) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/149
2022-10-27 22:07:47 +02:00
Simon Vieille 131c4b643a release v3.2.0 2022-10-27 22:01:35 +02:00
Simon Vieille c0b187e55e update SideMenu with apps order and changelog 2022-10-27 21:58:21 +02:00
Simon Vieille f09eda85a6 Merge branch 'feature/issue147' into develop 2022-10-27 21:52:34 +02:00
Simon Vieille 1971c6f500 add ordered apps for all displays (#147) 2022-10-27 21:52:29 +02:00
Simon Vieille 07c7221ca2 rename 'top-menu-apps-order' with 'apps-order' 2022-10-27 21:51:58 +02:00
Simon Vieille d42593d203 removed unused translations 2022-10-27 21:50:13 +02:00
Simon Vieille 90fb46fb0e add effect of reset button 2022-10-27 21:49:55 +02:00
Simon Vieille 4b3bb0c5d8 update changelog 2022-10-27 20:32:13 +02:00
Simon Vieille 6533acdd60 use custom app names using 'app.navigation.name' (fix #148) 2022-10-27 20:30:14 +02:00
Simon Vieille 2cdb5d93a2 Merge pull request 'develop' (#146) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/146
2022-10-22 17:22:13 +02:00
Simon Vieille f20dc7282e add selfhosted notice 2022-10-21 23:59:27 +02:00
Simon Vieille 4dc07ed8fc add selfhosted notice 2022-10-21 23:58:36 +02:00
Simon Vieille e48d8d1114 Merge pull request 'update readme' (#145) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/145
2022-10-21 21:29:25 +02:00
Simon Vieille 36c8cb59bb update readme 2022-10-21 21:29:10 +02:00
Simon Vieille bc6ac9c7d3 Merge pull request 'develop' (#144) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/144
2022-10-21 21:27:27 +02:00
Simon Vieille fbe1b4f0bc update readme 2022-10-21 21:17:02 +02:00
Simon Vieille 8d9b12683a add translation badge 2022-10-21 21:16:24 +02:00
Simon Vieille c7bcc4a844 Merge pull request 'add template for translations' (#143) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/143
2022-10-21 20:25:49 +02:00
Simon Vieille 07ad842911 add template for translations 2022-10-21 20:25:35 +02:00
Simon Vieille 874332abf1 Merge pull request 'develop' (#142) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/142
2022-10-21 20:24:04 +02:00
Simon Vieille 5208b5d574 add template for translations 2022-10-21 20:20:23 +02:00
Simon Vieille fcd082cc0a update translations using translate.codeberg.org 2022-10-21 20:12:04 +02:00
Simon Vieille 7472e4050a Merge pull request 'release v3.1.0' (#141) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/141
2022-10-21 19:43:38 +02:00
Simon Vieille be0731f2d5 release v3.1.0 2022-10-21 19:36:55 +02:00
Simon Vieille 6a6792401e add base for translations 2022-10-21 19:34:48 +02:00
Simon Vieille a0c0cc0aa5 add custom apps sorting (fix SideMenu and admin ui) 2022-10-21 19:33:43 +02:00
Simon Vieille 1eb5e18d5c update changelog 2022-10-21 18:01:49 +02:00
Simon Vieille 84c620637e add custom apps sorting 2022-10-21 17:59:41 +02:00
Simon Vieille 7d82c78581 Merge branch 'feature/ui' into develop 2022-10-21 17:08:02 +02:00
Simon Vieille 83c2ccb5b4 update changelog 2022-10-21 17:08:00 +02:00
Simon Vieille 62e4a7df5b fix admin modale 2022-10-21 17:07:43 +02:00
Simon Vieille 16b8326fae update changelog 2022-10-21 16:50:39 +02:00
Simon Vieille 57f3a0d252 Merge branch 'feature/ui' into develop 2022-10-21 16:49:02 +02:00
Simon Vieille 5fac655856 remove unused translation keys 2022-10-21 16:48:59 +02:00
Simon Vieille 8a92b2d803 fix admin list 2022-10-21 16:48:36 +02:00
Simon Vieille 1ec9a3f2ff Merge pull request 'release v3.0.1' (#139) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/139
2022-10-18 22:33:36 +02:00
Simon Vieille 345f165aef release v3.0.1 2022-10-18 22:28:28 +02:00
Simon Vieille f6d9a9f71c refactoring of SideMenuWithCategories.vue 2022-10-18 22:27:50 +02:00
Simon Vieille 2a67038ff4 refactoring of SideMenuBig.vue 2022-10-18 22:22:26 +02:00
Simon Vieille a5ca86f573 add screenshots 2022-10-18 22:07:55 +02:00
Simon Vieille 501a1b23e1 update changelog 2022-10-18 22:07:46 +02:00
Simon Vieille c01db7c9e1 remove the gap between the window's top and menu categories (large menu) 2022-10-18 19:35:35 +02:00
Simon Vieille c0e24e39b6 Merge pull request 'release v3.0.0' (#138) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/138
2022-10-17 18:28:25 +02:00
Simon Vieille e31da3af6f release v3.0.0 2022-10-17 18:27:46 +02:00
Simon Vieille 8e5193417d Merge pull request 'comptability with nc25' (#137) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/137
2022-10-17 18:11:24 +02:00
Simon Vieille 2189d5c2c8 release v3.0.0 2022-10-17 18:06:18 +02:00
Simon Vieille 1adbfb33c9 fix CI 2022-10-17 17:55:50 +02:00
Simon Vieille 842776c2fd [ci] debug 2022-10-16 23:13:52 +02:00
Simon Vieille 719075db6c [ci] debug 2022-10-16 23:11:41 +02:00
Simon Vieille af95ab6265 [ci] debug 2022-10-16 23:09:29 +02:00
Simon Vieille 78e71dce97 update makefile 2022-10-16 23:00:26 +02:00
Simon Vieille d177bdbaeb update makefile 2022-10-16 22:54:28 +02:00
Simon Vieille f67a489130 update js conf 2022-10-16 22:18:56 +02:00
Simon Vieille 23fc3b9e5b update js conf 2022-10-16 22:14:10 +02:00
Simon Vieille e889d1e3d8 update js conf 2022-10-16 22:09:14 +02:00
Simon Vieille 39faeb70dc update js conf 2022-10-16 22:04:51 +02:00
Simon Vieille 433c480637 fix js dependecies 2022-10-16 20:10:55 +02:00
Simon Vieille 0321f6e7f4 update ci config 2022-10-16 20:04:11 +02:00
Simon Vieille ec8cf06082 update gitignore and add yarn lock file 2022-10-16 20:00:06 +02:00
Simon Vieille f30142abe6 update indentation 2022-10-16 19:59:18 +02:00
Simon Vieille 7c86d53da7 fix issue with loader and refactoring 2022-10-16 19:57:32 +02:00
Simon Vieille f0988b93bd fix fixed menu view 2022-10-16 19:19:03 +02:00
Simon Vieille a647f05fa4 update indentation 2022-10-16 19:01:46 +02:00
Simon Vieille 8aa07efaf9 update default view 2022-10-16 19:00:16 +02:00
Simon Vieille 9cdb008a72 update indentation (4 spaces -> 2 spaces) 2022-10-16 18:33:50 +02:00
Simon Vieille 585aec5ee2 update indentation (4 spaces -> 2 spaces) 2022-10-16 18:33:06 +02:00
Simon Vieille 1c1fe946cf update rules of makefile, webpack, stylelintrc 2022-10-16 18:23:20 +02:00
Simon Vieille 1a550f066f replace the top menu component with a custom one 2022-10-16 18:21:23 +02:00
Simon Vieille 01de6d998f lint admin.css 2022-10-14 19:35:49 +02:00
Simon Vieille cf87747924 fix position of reset buttons 2022-10-14 19:35:01 +02:00
Simon Vieille e5b3499077 add vuejs key on loops and apply a lint 2022-10-11 22:24:59 +02:00
Simon Vieille b6a529d65e Merge pull request 'fix #133' (#134) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/134
2022-09-01 17:00:32 +02:00
Simon Vieille b30e822bde update changelog 2022-09-01 16:59:46 +02:00
Simon Vieille 13688cd3d3 fix icon render 2022-09-01 16:59:04 +02:00
Simon Vieille 22fd48cf8d Merge pull request 'release v2.5.0' (#132) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/132
2022-09-01 10:50:17 +02:00
Simon Vieille f9c41e9407 Merge branch 'master' into develop 2022-09-01 10:49:37 +02:00
Simon Vieille 1da1cff551 release v2.5.0 2022-09-01 10:44:13 +02:00
Simon Vieille 1c2c413eef update changelog 2022-08-21 18:02:28 +02:00
Simon Vieille 36388bd472 add code quality makefile action 2022-08-21 18:02:28 +02:00
Simon Vieille 0c304b06a0 (cq) add missing let 2022-08-21 18:02:28 +02:00
Simon Vieille 538467dc99 (cq) replace v-html with v-text to prevent xss 2022-08-21 18:02:28 +02:00
Simon Vieille eba06e8ef8 (cq) replace var with let 2022-08-21 18:02:28 +02:00
Simon Vieille 3cf8b685ba (cq) replace var with let 2022-08-21 18:02:28 +02:00
Simon Vieille ed8f0e0959 (cq) remove unused package* 2022-08-21 18:02:28 +02:00
Simon Vieille ba7f0673b4 (cq) add alt attribute on app icon 2022-08-21 18:02:28 +02:00
Simon Vieille d2b589a644 (cq) add rel noopener attribute 2022-08-21 18:02:28 +02:00
Simon Vieille ca08a26e1b (cq) add alt attribute on logo 2022-08-21 18:02:28 +02:00
Simon Vieille 6347403ed7 (cq) remove unsed variable 2022-08-21 18:02:28 +02:00
Simon Vieille 80532ead63 (cq) rename variable 2022-08-21 18:02:28 +02:00
Simon Vieille 7b8d8800fc (cq) replace repeated strings with variables 2022-08-21 18:02:28 +02:00
Simon Vieille a20b0d4709 (cq) remove unsed variables 2022-08-21 18:02:28 +02:00
Simon Vieille 47c2beae4a (cq) remove duplicated code 2022-08-21 18:02:28 +02:00
Simon Vieille 49f45534de update changelog 2022-08-21 18:02:28 +02:00
Simon Vieille fd99827390 update changelog 2022-08-21 16:20:42 +02:00
Simon Vieille e802e05888 add code quality makefile action 2022-08-21 16:20:05 +02:00
Simon Vieille 13f535250a (cq) add missing let 2022-08-21 16:13:39 +02:00
Simon Vieille d837f1acf5 (cq) replace v-html with v-text to prevent xss 2022-08-21 16:12:52 +02:00
Simon Vieille f058ec10d3 (cq) replace var with let 2022-08-21 15:58:12 +02:00
Simon Vieille d3b3989e02 (cq) replace var with let 2022-08-21 15:55:59 +02:00
Simon Vieille 984bfcdc05 (cq) remove unused package* 2022-08-21 15:54:02 +02:00
Simon Vieille 983fabd460 (cq) add alt attribute on app icon 2022-08-21 15:53:26 +02:00
Simon Vieille ca7e8674e4 (cq) add rel noopener attribute 2022-08-21 15:46:33 +02:00
Simon Vieille 69e2c0670a (cq) add alt attribute on logo 2022-08-21 13:55:29 +02:00
Simon Vieille 4676243b2e (cq) remove unsed variable 2022-08-21 13:53:40 +02:00
Simon Vieille 84b50710a6 (cq) rename variable 2022-08-21 13:52:08 +02:00
Simon Vieille 059002ef1c (cq) replace repeated strings with variables 2022-08-21 13:49:20 +02:00
Simon Vieille fa9d5abf62 (cq) remove unsed variables 2022-08-21 13:48:42 +02:00
Simon Vieille 280c1d72ae (cq) remove duplicated code 2022-08-21 13:48:16 +02:00
Simon Vieille 373b8393bf update changelog 2022-08-15 15:03:46 +02:00
Simon Vieille 6205c9a6b6 Merge pull request 'upgrade dependencies' (#116) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/116
2022-08-15 14:26:44 +02:00
Simon Vieille d381d479da upgrade dependences 2022-08-15 14:17:36 +02:00
Simon Vieille ce9d6b93b1 upgrade dependences 2022-08-15 14:17:21 +02:00
Simon Vieille dc49747115 Merge pull request 'v2.4.3' (#115) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/115
2022-08-13 17:30:51 +02:00
Simon Vieille 1ce3f06b46 release v2.4.3 2022-08-13 17:26:35 +02:00
Simon Vieille 5fe272405e Merge pull request 'Tweaks to Czech localization' (#114) from Pavelb/side_menu:develop into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/114
2022-08-13 17:23:19 +02:00
Pavelb f2a09bc170 Updated Czech localization
Removed duplicated source string, minor tweaks to wording.
2022-08-13 14:50:46 +02:00
Pavelb a2ab8fa907 Merge pull request 'develop' (#1) from deblan/side_menu:develop into develop
Reviewed-on: https://gitnet.fr/Pavelb/side_menu/pulls/1
2022-08-13 14:38:27 +02:00
Simon Vieille 638ba27564 remove drone ci conf and update woodpecker ci conf 2022-07-28 10:14:37 +02:00
Simon Vieille 013d5b99f1 Merge pull request 'update ci' (#113) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/113
2022-07-26 15:29:33 +02:00
Simon Vieille 291eaa4f83 update ci 2022-07-26 15:27:56 +02:00
Simon Vieille 5bd88a32d9 Merge branch 'develop' 2022-07-26 15:08:39 +02:00
Simon Vieille 794d86f69e update ci 2022-07-26 15:05:44 +02:00
Simon Vieille e61e6880a2 update ci 2022-07-26 15:04:48 +02:00
Simon Vieille 4b81fa715c update ci 2022-07-26 15:04:22 +02:00
Simon Vieille 330ee2a43e update ci 2022-07-26 15:03:53 +02:00
Simon Vieille 3cf1b358b3 Merge pull request 'update ci' (#110) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/110
2022-07-26 14:57:46 +02:00
Simon Vieille ff1ebb4a50 update ci 2022-07-26 14:57:46 +02:00
Simon Vieille b246fa0281 update ci 2022-07-26 14:57:19 +02:00
Simon Vieille e6176d3e01 Merge pull request 'update ci' (#109) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/109
2022-07-26 14:55:43 +02:00
Simon Vieille 06b10568e7 update ci 2022-07-26 14:55:43 +02:00
Simon Vieille 3bc214b72e update ci 2022-07-26 14:55:25 +02:00
Simon Vieille a6df8db96b Merge pull request 'update ci' (#108) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/108
2022-07-26 14:50:14 +02:00
Simon Vieille 64f77b102d update ci 2022-07-26 14:49:29 +02:00
Simon Vieille ef604ee612 fix merge 2022-07-26 14:44:43 +02:00
Simon Vieille eafc020210 merge develop 2022-07-26 14:43:25 +02:00
Simon Vieille 2dac9ce0f4 Merge branch 'develop' 2022-07-26 14:41:52 +02:00
Simon Vieille 9f5143cc25 update changelog 2022-07-26 14:33:45 +02:00
Simon Vieille 48737c5300 update ci 2022-07-26 14:31:01 +02:00
Simon Vieille 293e4bf62b fix woodpecker pipeline 2022-07-25 11:06:27 +02:00
Simon Vieille 4c74b620b1 Merge pull request 'add new ci and fix minur bugs' (#107) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/107
2022-07-25 11:04:22 +02:00
Simon Vieille b83d9f8d76 add woodpacker ci 2022-07-25 11:04:22 +02:00
Simon Vieille 5835f1ae92 add woodpacker ci 2022-07-25 11:04:22 +02:00
Simon Vieille f6c40d9391 fix typo 2022-07-25 11:04:22 +02:00
Simon Vieille 049e601f62 add woodpacker ci 2022-07-25 10:38:59 +02:00
Simon Vieille 16ab6bfece add woodpacker ci 2022-07-25 10:34:24 +02:00
Simon Vieille 325b618434 Merge branch 'master' of gitnet.fr:deblan/side_menu 2022-07-05 16:52:13 +02:00
Simon Vieille 7892ce98d2 fix typo 2022-07-05 16:52:03 +02:00
Simon Vieille 4ea6c5b191 Merge pull request 'develop' (#106) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/106
2022-07-05 14:51:05 +02:00
Simon Vieille 87090b90c2 Merge branch 'develop' 2022-07-05 14:49:13 +02:00
Simon Vieille 2a1e9f5010 release v2.4.1 2022-07-05 14:49:06 +02:00
Simon Vieille 05b1b16cb1 fix user setting save 2022-07-05 14:49:00 +02:00
Simon Vieille 0176ef22d4 update readme 2022-05-31 21:39:55 +02:00
Simon Vieille 1d914458d0 Merge pull request 'release v2.4.0' (#104) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/104
2022-05-31 21:28:36 +02:00
Simon Vieille a8ecf3ea46 release v2.4.0 2022-05-31 21:24:08 +02:00
Simon Vieille 8d1842f622 update changelog 2022-05-31 21:23:53 +02:00
Simon Vieille a0be3757e9 update screenshots 2022-05-31 21:21:30 +02:00
Simon Vieille 7b2f64c5cd add translations 2022-05-31 21:11:11 +02:00
Simon Vieille 6b1a995d5d add tooltips 2022-05-31 16:43:49 +02:00
Simon Vieille 814567635d update changelog 2022-05-31 16:29:29 +02:00
Simon Vieille 32322a0ab2 add button to set default colors 2022-05-31 16:28:43 +02:00
Simon Vieille 95230e9e4a add menu hover effect 2022-05-31 15:48:17 +02:00
Simon Vieille e2430866e5 add button to set default colors 2022-05-31 15:48:02 +02:00
Simon Vieille 9f9f8f90c8 remove focus on opener after click 2022-05-30 19:49:59 +02:00
Simon Vieille 28fc33ee79 change saving progression 2022-05-30 19:49:36 +02:00
Simon Vieille f116b8463a fix menu with categories header 2022-05-30 13:22:03 +02:00
Simon Vieille d8edbae848 fix minor issues 2022-05-30 12:58:49 +02:00
Simon Vieille 4e0c7be2c6 remove deprecated app.php file 2022-05-30 12:04:15 +02:00
Simon Vieille 3fc141bee1 Merge branch 'develop' 2022-05-04 21:05:43 +02:00
Simon Vieille 2cb8c22be0 fix avatar size (nextcloud 24) 2022-05-04 21:05:38 +02:00
Simon Vieille 3e3e6ae943 Merge pull request 'release v2.3.5' (#100) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/100
2022-04-11 19:15:24 +02:00
Simon Vieille d759ccbdcc Merge branch 'develop' 2022-04-11 19:11:51 +02:00
Simon Vieille 389da47cab release v2.3.5 2022-04-11 19:11:41 +02:00
Simon Vieille 457c1ff53e Merge branch 'develop' 2022-04-10 18:56:58 +02:00
Simon Vieille a6a84ee784 update opener active style (fix #99) 2022-04-10 18:56:50 +02:00
Simon Vieille 52bbd49d9a update readme 2022-03-15 11:44:11 +01:00
Simon Vieille 92e1857ae8 Merge pull request 'fix issue #96' (#97) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/97
2022-03-15 11:14:40 +01:00
Simon Vieille c0b1701744 release v2.3.4 2022-03-15 10:56:05 +01:00
Simon Vieille ee98a49366 fix blank line when settings are open 2022-03-15 10:51:40 +01:00
Simon Vieille b4951b6cf1 Merge pull request 'develop' (#94) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/94
2022-02-07 14:35:05 +01:00
Simon Vieille a67688e779 release v2.3.3 2022-02-07 14:30:08 +01:00
Simon Vieille 9afde0dc9d update changelog 2022-02-07 14:29:51 +01:00
Simon Vieille 0f73ad42c4 fix SQL Exception InvalidFieldNameException (#93) 2022-02-07 14:28:34 +01:00
Simon Vieille 007ac2bb8e hide the scrollbar when mouse is out (menu always displayed) 2022-02-07 14:21:29 +01:00
Simon Vieille 4e21020600 Merge pull request 'develop' (#92) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/92
2022-01-14 17:03:28 +01:00
Simon Vieille 8c5b0e9834 update ci/cd conf 2022-01-14 16:52:36 +01:00
Simon Vieille 59e3b6b85e update ci/cd conf 2022-01-14 16:50:15 +01:00
Simon Vieille a913bd5ba2 update ci/cd conf 2022-01-14 16:49:14 +01:00
Simon Vieille 2d32e542cb update ci/cd conf 2022-01-14 16:46:47 +01:00
Simon Vieille 5d03fbaa49 update ci/cd conf 2022-01-14 16:44:54 +01:00
Simon Vieille 22011cb681 Merge pull request 'update the ci/cd config and screenshots' (#91) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/91
2022-01-13 00:47:43 +01:00
Simon Vieille 17a8137b4e Merge branch 'master' of gitnet.fr:deblan/side_menu 2022-01-13 00:20:11 +01:00
Simon Vieille 015493fc08 update ci/cd conf 2022-01-13 00:16:56 +01:00
Simon Vieille 992e54ac30 update ci/cd conf 2022-01-13 00:15:20 +01:00
Simon Vieille 67dfb7e833 update screenshots 2022-01-12 14:54:41 +01:00
Simon Vieille 1e68d6877d Merge pull request 'Quick fix' (#90) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/90
2022-01-12 14:13:08 +01:00
Simon Vieille 2ae08f7b77 release v2.3.2 2022-01-12 14:12:17 +01:00
Simon Vieille 489321081a fix hidden menu 2022-01-12 14:11:38 +01:00
Simon Vieille 68123ed45c Merge pull request 'Quick fix (#88)' (#89) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/89
2022-01-12 13:32:29 +01:00
Simon Vieille 66a1528341 release v2.3.1 2022-01-12 13:30:43 +01:00
Simon Vieille 64b7f3f534 fix #88 2022-01-12 13:29:44 +01:00
Simon Vieille fef936bef0 Merge pull request 'Issues #82 #83' (#87) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/87
2022-01-12 12:53:54 +01:00
Simon Vieille 715dae6ab4 release v2.3.0 2022-01-12 12:51:29 +01:00
Simon Vieille e2a9fecac9 fix typo 2022-01-12 12:48:50 +01:00
Simon Vieille e2d17022f9 fix incorrect html label 2022-01-12 12:46:41 +01:00
Simon Vieille 29d79ad589 update changelog 2022-01-12 12:43:11 +01:00
Simon Vieille 5a4294fad4 Merge branch 'feature/issue82' into develop 2022-01-12 12:41:29 +01:00
Simon Vieille d34b41ba94 add option to keep an app in the top and side menu 2022-01-12 12:40:17 +01:00
Simon Vieille a6016552c9 update changelog and readme 2022-01-12 11:44:45 +01:00
Simon Vieille 50c65811a6 add auto-reload when settings are saved 2022-01-11 22:23:13 +01:00
Simon Vieille f64436f0a3 Merge branch 'feature/issue83' into develop 2022-01-11 20:20:51 +01:00
Simon Vieille 34b1c2809b fix issue with custom categories and add experimental notice 2022-01-11 20:20:44 +01:00
Simon Vieille 5d9dc804f8 add bigger select 2022-01-11 20:02:02 +01:00
Simon Vieille 30072500bc add a way to create custom categories and manage application categories 2022-01-11 19:59:51 +01:00
Simon Vieille 9871cb93d8 Merge pull request 'develop' (#86) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/86
2022-01-10 15:07:07 +01:00
Simon Vieille a9ca55390d release v2.2.0 2022-01-10 15:02:05 +01:00
Simon Vieille 7230863d0a update icons (#84) 2022-01-10 14:59:17 +01:00
Simon Vieille d9046a205f update dependencies 2022-01-09 22:26:46 +01:00
Simon Vieille 0923a9107c fix categories order 2022-01-09 22:17:01 +01:00
Simon Vieille 1cbdca87df generate default colors using theming colors 2022-01-09 16:43:12 +01:00
Simon Vieille 2e8bed4531 Merge pull request 'update changelog' (#81) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/81
2021-12-03 14:15:36 +01:00
Simon Vieille 506fa22f4b update changelog 2021-12-03 14:14:03 +01:00
Simon Vieille 134148c6b2 Merge pull request 'release v2.1.0 (NC23 is compatible)' (#80) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/80
2021-12-03 14:03:10 +01:00
Simon Vieille a97e94e2e5 release v2.1.0 (NC23 is compatible) 2021-12-03 13:47:52 +01:00
Simon Vieille 8d287672e9 Merge branch 'master' of gitnet.fr:deblan/side_menu 2021-11-14 20:07:49 +01:00
Simon Vieille 7f33f7523f Merge pull request 'Release 2.0.1' (#79) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/79
2021-11-14 20:07:41 +01:00
Simon Vieille 0ecc706bad Merge branch 'develop' 2021-11-14 20:05:33 +01:00
Simon Vieille b6fb1783ba release v2.0.1 2021-11-14 20:05:22 +01:00
Simon Vieille 1b0418a466 fix js error on the personal settings page (undefined sortable) 2021-11-14 20:04:58 +01:00
Simon Vieille d37773cf5f fix js error on the personal settings page (undefined sortable) 2021-11-14 20:04:36 +01:00
Simon Vieille 1aea6ee4f4 fix #78: top menu is broken - invisible apps are shown 2021-11-14 20:01:43 +01:00
Simon Vieille a6dd6854e4 fix issue #77 2021-11-14 19:37:14 +01:00
Simon Vieille 70caa80af6 Merge pull request 'update makefile for assets build' (#75) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/75
2021-11-14 17:33:55 +01:00
Simon Vieille 48f403882a update makefile for assets build 2021-11-14 17:32:54 +01:00
Simon Vieille 6296c1c807 Merge pull request 'Release v2.0.0' (#74) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/74
2021-11-14 17:22:49 +01:00
Simon Vieille 71b9bc4766 release v2.0.0 2021-11-14 17:17:46 +01:00
Simon Vieille 228f07ea25 Merge branch 'feature/removing-jquery' into develop 2021-11-14 17:03:04 +01:00
Simon Vieille fd2ae59d16 remove background and border from opener (#73) 2021-11-14 16:44:52 +01:00
Simon Vieille 9124de3c81 fix the code of conduct 2021-11-06 20:11:53 +01:00
Simon Vieille 5e308b610d update the build task to include vendor/ 2021-11-05 20:20:42 +01:00
Simon Vieille db2220e745 replace the sortable jquery plugin with html5sortable 2021-11-05 20:19:08 +01:00
Simon Vieille 1143843a5b fix ci/cd conf 2021-11-03 23:02:57 +01:00
Simon Vieille 74d26106dc Merge pull request 'add ci/cd conf' (#72) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/72
2021-11-03 20:04:03 +01:00
Simon Vieille 539a81c07e add ci/cd conf 2021-11-03 20:01:54 +01:00
Simon Vieille d978da2c72 Merge branch 'develop' into feature/removing-jquery 2021-11-03 19:52:55 +01:00
Simon Vieille 544ed1a1fa add ci/cd conf (drone) 2021-11-03 19:52:24 +01:00
Simon Vieille ff5ba04217 Merge pull request 'add ci/cd conf (drone)' (#71) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/71
2021-11-03 19:20:36 +01:00
Simon Vieille 56e87d470d add ci/cd conf (drone) 2021-11-03 19:17:29 +01:00
Simon Vieille 9173ca37c7 add ci/cd conf (drone) 2021-11-02 20:48:54 +01:00
Simon Vieille 240b564e22 Merge pull request 'update documentation' (#70) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/70
2021-10-31 19:44:17 +01:00
Simon Vieille 11ccdceb98 update documentation 2021-10-31 19:43:25 +01:00
Simon Vieille 0608011d80 Merge pull request 'update metroline conf file' (#69) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/69
2021-10-31 18:45:36 +01:00
Simon Vieille 3d3da18322 update metroline conf file 2021-10-31 18:44:30 +01:00
Simon Vieille 3a999b22b0 Merge branch 'develop' into feature/removing-jquery 2021-10-31 17:48:06 +01:00
Simon Vieille 1544b28b57 Merge pull request 'add ci configuration' (#68) from develop into master
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/68
2021-10-31 17:47:47 +01:00
Simon Vieille e72d0555db update metroline conf file 2021-10-31 17:44:21 +01:00
Simon Vieille 7866089532 add metroline conf file 2021-10-31 17:42:22 +01:00
Simon Vieille ed2531db55 add fetch to make request 2021-10-31 17:27:08 +01:00
Simon Vieille c53221d112 fix indentation 2021-10-31 17:02:09 +01:00
Simon Vieille 9a95151156 remove console log 2021-10-31 16:56:52 +01:00
Simon Vieille 80369a39e1 remove jquery excepted for sorting categories 2021-10-31 16:55:43 +01:00
Simon Vieille 7471e93847 fix null setting update 2021-10-31 16:55:04 +01:00
Simon Vieille d1faf881da add timeout 2021-10-31 16:54:16 +01:00
Simon Vieille 96ffdf93ea remove useless vars 2021-10-29 15:30:22 +02:00
Simon Vieille 6f0c4e98e0 fix top menu generation; fix issue #66 by removing usage of setInterval 2021-10-29 13:56:48 +02:00
Simon Vieille c2e6d24b95 remove ';' on endline 2021-10-29 11:27:45 +02:00
Simon Vieille 5d93d02960 refactoring of alwaysDisplayed function 2021-10-29 11:24:01 +02:00
Simon Vieille a074d747c1 remove most of jquery from top menu 2021-10-29 11:14:27 +02:00
Simon Vieille cc7c9f6ed5 remove most of jquery 2021-10-28 15:47:03 +02:00
Simon Vieille f26adb6ac1 remove jquery from components 2021-10-28 13:50:16 +02:00
Simon Vieille 1e64b34cff Merge branch 'develop' 2021-10-28 13:17:04 +02:00
Simon Vieille 3b6b8ad54a add missing svg 2021-10-28 13:16:55 +02:00
Simon Vieille cc71fda3b0 Merge branch 'develop' 2021-10-21 21:43:51 +02:00
Simon Vieille 64c4d7a1e1 release v1.28.0 2021-10-21 21:43:30 +02:00
Simon Vieille fd367fe2d4 Merge branch 'develop' 2021-10-21 21:37:40 +02:00
Simon Vieille 3975f3be28 fix #63: add a new side menu with categories 2021-10-21 21:37:32 +02:00
Simon Vieille 3f590a97bc Merge branch 'develop' 2021-10-21 20:06:41 +02:00
Simon Vieille 1896bb399d fix #62: hide app notification icon 2021-10-21 20:06:17 +02:00
Simon Vieille d77c2ef9ae release v1.27.1 2021-08-11 14:43:52 +02:00
Simon Vieille db0fa60ce8 fix German translation render 2021-08-11 14:43:04 +02:00
Simon Vieille aac9f2cb16 Merge branch 'develop' 2021-08-11 11:58:25 +02:00
Simon Vieille 33d7c6a7f0 release v1.27.0 2021-08-11 11:58:15 +02:00
Simon Vieille a72bb87aa2 hide personal settings access when settings are forced by the administrator 2021-08-11 11:57:43 +02:00
Simon Vieille 5e4a7bcae4 improved German translations 2021-08-11 11:57:01 +02:00
Simon Vieille f7d4a8284b Merge branch 'develop' 2021-08-02 21:49:02 +02:00
Simon Vieille b900ed7a4d release v1.26.0 2021-08-02 21:48:58 +02:00
Simon Vieille 4a10338588 Merge pull request 'Add Czech localization' (#61) from Pavelb/side_menu:develop into develop
Reviewed-on: https://gitnet.fr/deblan/side_menu/pulls/61
2021-08-02 21:35:34 +02:00
Pavelb 88ecd2ceaf Add Czech localization 2021-07-23 14:45:45 +02:00
Simon Vieille 04d161ad9b Merge branch 'develop' 2021-07-09 12:55:07 +02:00
Simon Vieille 1dcf1b7938 update changelog 2021-07-09 12:55:05 +02:00
Simon Vieille dab5566be4 Merge branch 'develop' 2021-07-09 12:54:32 +02:00
Simon Vieille 143ece3be8 update changelog 2021-07-09 12:54:28 +02:00
Simon Vieille d735e1cfa6 Merge branch 'develop' 2021-07-09 12:43:01 +02:00
Simon Vieille f86ec1de52 update changelog 2021-07-09 12:42:51 +02:00
Simon Vieille b780f53e0b add PHP version as dependency 2021-07-09 12:42:43 +02:00
Simon Vieille 96a4235a10 Merge branch 'develop' 2021-07-09 11:52:28 +02:00
Simon Vieille 86be38af6c add translations: zh_CN 2021-07-09 11:52:05 +02:00
Simon Vieille 4413623618 merge develop 2021-07-07 21:36:02 +02:00
Simon Vieille 7887a441b3 add compatibility with Nextcloud 22, add CHANGELOG.md, update app icon 2021-07-07 21:35:25 +02:00
Simon Vieille 44478af3a2 release v1.24.0 2021-07-03 20:33:42 +02:00
Simon Vieille 7306a31a7d release v1.24.0 2021-07-03 20:32:39 +02:00
Simon Vieille d2a8b05772 add background opacity (fix #58) 2021-07-03 20:23:39 +02:00
Simon Vieille fba980416d fix translations 2021-03-02 19:16:53 +01:00
Simon Vieille 95c840ae83 release v1.23.1 2021-03-02 19:16:44 +01:00
Simon Vieille f021c9f0cd fix issue with opener selector 2021-03-02 19:16:37 +01:00
Simon Vieille 58e03e903c release v1.23.0 2021-02-27 14:28:02 +01:00
Simon Vieille 9747820cb8 add dark mode colors 2021-02-27 14:21:55 +01:00
Simon Vieille d8d6aededa add compatibility with nextcloud 21 2021-02-24 15:16:29 +01:00
Simon Vieille a27e723657 Merge branch 'feature/issue55' into develop 2021-02-09 16:51:29 +01:00
Simon Vieille c7db75cea3 release v1.22.2 2021-02-09 16:51:27 +01:00
Simon Vieille 4cd5421e53 fix regression: apps does not open in the tab 2021-02-09 16:50:16 +01:00
Simon Vieille f2d1de1cbe release v1.22.1 2021-02-05 17:57:46 +01:00
Simon Vieille 6be679c569 fix regression: apps does not open in the tab 2021-02-05 17:54:50 +01:00
Simon Vieille 0893ddd5fe release v1.22.0 2021-02-03 15:23:07 +01:00
Simon Vieille c893391065 update ui of admin and fix #53 2021-02-03 15:21:08 +01:00
Simon Vieille b06df8ad9f update ui of admin lists 2021-02-03 10:27:08 +01:00
Simon Vieille 13f7e63514 PSR 2 compliance 2021-02-03 10:15:59 +01:00
Simon Vieille 64da45e676 add feature: order categories 2021-02-03 10:14:03 +01:00
Simon Vieille 77e27bcc1a add code of conduct and update chat room link 2020-12-23 13:39:43 +01:00
Simon Vieille 99858d86c1 release v1.21.0 2020-12-03 13:34:57 +01:00
Simon Vieille 6984efdafd fix issue #51: add link on the logo 2020-12-03 13:33:28 +01:00
Simon Vieille 48d80edb0a update issue template 2020-11-08 12:32:19 +01:00
Simon Vieille b57743c61a add donation link 2020-11-06 18:17:17 +01:00
Simon Vieille a58ca57e46 release v1.20.1 2020-11-03 13:00:26 +01:00
Simon Vieille dc6ec4eb89 fix typo and translations 2020-11-03 13:00:09 +01:00
Simon Vieille 8588f1510f release v1.20.0 2020-11-03 12:20:01 +01:00
Simon Vieille 02825cee67 add option to hide apps (big menu display) 2020-11-03 12:16:36 +01:00
Simon Vieille 10e90df4b8 update issue templates 2020-11-01 14:13:54 +01:00
Simon Vieille 99590447e5 update issue templates 2020-11-01 13:53:19 +01:00
Simon Vieille b5e41ff96e update issue templates 2020-11-01 13:49:04 +01:00
Simon Vieille 680587e75c add documentation (related to #48) 2020-10-24 14:29:32 +02:00
Simon Vieille 9f7d6c931e add a script to import config 2020-10-23 18:25:08 +02:00
Simon Vieille 205a72f74d add documentation 2020-10-23 18:24:48 +02:00
Simon Vieille ef00aae51f update issue template 2020-10-23 11:51:28 +02:00
Simon Vieille b208c8cb19 release v1.19.1 2020-10-21 18:06:00 +02:00
Simon Vieille 0e5cd135b4 fix issue #47 2020-10-21 18:05:36 +02:00
Simon Vieille 854beb8078 release v1.19.0 2020-10-19 18:26:17 +02:00
Simon Vieille 709f938f48 update screenshots 2020-10-19 18:24:08 +02:00
Simon Vieille 80700cac32 add option: the menu is enabled by default for users 2020-10-19 13:44:07 +02:00
Simon Vieille a71a8c7208 add documentation 2020-10-16 13:42:23 +02:00
Simon Vieille cf80c3512c add licence 2020-10-16 11:46:25 +02:00
Simon Vieille a5d88317e6 update screenshots 2020-10-16 11:18:48 +02:00
Simon Vieille b2103a012c release v1.18.0 2020-10-16 11:17:44 +02:00
Simon Vieille 847b3696cb Merge branch 'feature/ref' into develop 2020-10-16 11:08:37 +02:00
Simon Vieille c67bfa0ce4 indentation 2020-10-16 11:07:45 +02:00
Simon Vieille 7edd6d6d84 refactor menus with separated components 2020-10-16 11:04:03 +02:00
Simon Vieille ae148aba02 Merge branch 'feature/issue44' into develop 2020-10-15 16:44:57 +02:00
Simon Vieille 575f963902 indentation 2020-10-15 15:47:28 +02:00
Simon Vieille ae74e745db add menu element: link to settings 2020-10-15 15:46:59 +02:00
Simon Vieille b749a9be2e add option: show link to settings 2020-10-15 15:46:43 +02:00
80 changed files with 5760 additions and 2607 deletions
+16
View File
@@ -0,0 +1,16 @@
---
name: "New feature"
about: "Use this template if you want to request a feature"
title: "[FEATURE] "
labels:
- enhancement
---
## Feature
### Description
...
### Benefits
...
+32
View File
@@ -0,0 +1,32 @@
---
name: "New issue"
about: "Use this template if you have a bug"
title: "[BUG] "
labels:
- bug
---
## Issue
### Environment
* Custom menu version:
* Nextcloud version:
* PHP version:
* Web server (Nginx, Apache2):
* Web browser and version (Firefox 80, Google Chrome 74, etc):
```
Insert your configuration here. You can export the configuration using the admin page.
```
### Steps to reproduce
...
### Observed Results
...
### Expected Results
...
+1
View File
@@ -4,3 +4,4 @@
/releases
/package-lock.json
!/l10n/.gitkeep
/yarn*.log
+5
View File
@@ -0,0 +1,5 @@
{
"rules": {
"indentation": 2
}
}
+43
View File
@@ -0,0 +1,43 @@
pipeline:
dependencies:
image: gitnet.fr/deblan/devenv
commands:
- make dep
when:
event: [tag, push, pull_request]
branch: [master, develop, feature/*]
build:
image: gitnet.fr/deblan/devenv
commands:
- make build
when:
branch: [master, develop, feature/*]
event: [push, pull_request]
package:
image: gitnet.fr/deblan/devenv
volumes:
- /var/www/html/artifacts:/var/www/html/artifacts
secrets: [app_certificate]
commands:
- mkdir -p "$HOME/.nextcloud/certificates"
- echo "$APP_CERTIFICATE" > "$HOME/.nextcloud/certificates/side_menu.key"
- export VERSION=$(grep "<version>" appinfo/info.xml | grep -o "[0-9]*\.[0-9]*\.[0-9]*" --color=never)
- export RELEASE_DIRECTORY="/var/www/html/artifacts/deblan/side_menu"
- make release
when:
event: [tag]
release:
image: plugins/gitea-release
volumes:
- /var/www/html/artifacts:/var/www/html/artifacts
settings:
api_key:
from_secret: gitnet_api_key
base_url: https://gitnet.fr
note: ${CI_COMMIT_MESSAGE}
files: /var/www/html/artifacts/deblan/side_menu/${CI_COMMIT_TAG/v//}/*
when:
event: [tag]
+437
View File
@@ -0,0 +1,437 @@
## [Unreleased]
## 3.4.1
## Added
* add translations (thanks to zonorti, jorisvandijk, jak2k)
## Fixed
* fix #183: hide custom categories list when empty (admin page)
## 3.4.0
### Added
* add translations (thanks to Pavelb, nier, Timur, p-bo)
* add possibility to define Custom Menu as default app and redirect to the first top menu app (#177)
## 3.3.2
### Fixed
* fix #173: reduce the height of categories list
## 3.3.1
### Fixed
* fix #162: top and side apps does work correctly
## 3.3.0
### Added
* add documentation in admin page
* add app sorter in user config side (#160)
### Fixed
* fix #164: open apps in new tab does not work
* fix #162 #159: top and side apps does work correctly
## 3.2.1
### Fixed
* fix #150: active app is not visible has active in menu (except in default menu)
* fix #151: opener position
## 3.2.0
### Added
* use custom app names using 'app.navigation.name' (#148)
* app sorting with all displays (#147)
## 3.1.0
### Added
* add global custom app sorting for the top menu
### Fixed
* fix admin list/modal look
## 3.0.1
### Fixed
* Remove the gap between the window's top and menu categories (large menu)
## 3.0.0
### Added
* Add compatibility with NC25 (#136/#135)
### Removed
* Nextcloud 20-24 are not supported anymore
* AppOrder is not supported anymore
## 2.5.1
### Fixed
* fix icon render (#133)
## 2.5.0
### Changed
* upgrade dependencies
### Fixed
* remove duplicated code
* remove unused variables and packages
* replace repeated strings with variables
* add html attributes
* replace var with let
* replace v-html with v-text to prevent xss
## 2.4.3
### Fixed
* fix translations
## 2.4.2
### Fixed
* fix typo
### Changed
* change ci/cd
## 2.4.1
### Fixed
* fix user setting save
## 2.4.0
### Added
* remove focus on opener after click
* add button to set default colors
* add menu hover effect
* add translations
### Fixed
* fix deprecated app.php file
* fix menu with categories header
* fix minor issues
### Changed
* change saving progression
### Removed
* Nextcloud 19 is not supported anymore
* PHP 7.3 is not supported anymore
## 2.3.5
### Fixed
* fix white square (#99)
## 2.3.4
### Fixed
* fix blank line when settings are open (#96)
## 2.3.3
### Added
* hide the scrollbar when mouse is out (menu always displayed)
### Fixed
* fix SQL Exception InvalidFieldNameException (#93)
## 2.3.2
### Fixed
- fix hidden menu
## 2.3.1
### Fixed
- fix #88: does not work with default menu
## 2.3.0
### Added
- fix #82: add an option to keep visible an app in both menus
- fix #83: add custom categories
- add auto-reload when settings are saved
## 2.2.0
### Added
- fix #84: update icons
- fix #85: use Nextcloud colors by default
### Fixed
- fix categories order in large menu
## 2.1.0
### Added
- add compatibility with Nextcloud 23
## 2.0.1
### Fixed
- fix #78: Top menu is broken - invisible apps are shown
- fix #77: Update personal settings - HTTP error 412 (Precondition Failed)
- fix js error on the personal settings page (undefined sortable)
## 2.0.0
### Fixed
- fix #66: removing usage of setInterval
- fix #73: icon background
### Changed
- fix #67: replace jQuery with Vanilla JS
### Removed
- Nextcloud 18 is not supported anymore
## 1.28.0
### Added
- fix #63: add a new side menu with categories
## 1.27.2
### Fixed
- fix #62: hide app notification icon
## 1.27.1
### Fixed
- fix German translation render
## 1.27.0
### Added
- hide personal settings access when settings are forced by the administrator
### Fixed
- improve German translations
## 1.26.0
### Added
- add Czech translation
## 1.25.2
### Fixed
- fix CHANGELOG
## 1.25.1
### Added
- add PHP version as dependency
- add chinese translation
### Fixed
- fix CHANGELOG
## 1.25.0
### Added
- add compatibility with Nextcloud 22
- add CHANGELOG.md (fix #59)
- update app icon
## 1.24.0
### Added
- add option to define the background opacity (fix #53)
- add missing translations
## 1.23.1
### Fixed
- fix but wih dark mode opener option
## 1.23.0
### Added
- add support of dark Theme and Breeze Dark
- add support of Nextcloud 21
## 1.22.2
### Fixed
- fix regression: apps does not open in new tab (fix #55)
## 1.22.1
### Fixed
- fix regression: apps does not open in new tab
## 1.22.0
### Added
- Add option to sort categories (fix #53)
- Update admin UI
## 1.21.0
### Added
- [FEATURE] Logo in the menu links to main page of installation (#51)
## 1.20.1
### Fixed
- Fix translations
## 1.20.0
### Added
- [FEATURE] Ability to remove apps from the Big Menu (#49)
## 1.19.1
### Fixed
- fix #47: setting for list/grid view in files app flashes and dissapears
## 1.19.0
### Added
- add option: the menu is enabled by default for users (fix #46)
## 1.18.0
### Added
- add option to show link to settings (fix #44)
- refactor menus using several components
## 1.17.0
### Added
- compliance with the app checker
- add an action to export the configuration
- add an action to purge the cache
## 1.16.3
### Fixed
- fix links that must be opened in new window (https://help.nextcloud.com/t/external-petit-probleme-concernant-lapplication-external-sites-ou-sites-externes/94884/11)
## 1.16.2
### Fixed
- fix issue with personal settings when global settings are forced
## 1.16.1
### Fixed
- fix #42: add cache to manage failures to access apps.nextcloud.com
- fix #41: side menu was hover apps list
## 1.16.0
### Added
- add an option to force settings to users (fix #38)
## 1.15.0
### Changed
- New name
### Fixed
- Fix #36: always displayed is not expanding
## 1.14.0
### Added
- add an api accessed by components
- add a config proxy in controllers
### Fixed
- fix translations
## 1.13.0
### Added
- add an option to display the avatar instead of the logo (fix #34)
## 1.12.3
### Added
- add a delay before moving elements (fix #33)
## 1.12.2
### Fixed
- fix #30: `Always displayed` menu can not be close using touchscreens
## 1.12.1
### Fixed
- fix typo
- fix translations
## 1.12.0
### Fixed
- fix #30: administrators and users can select what apps must be opened in new tab
- fix typo
## 1.11.0
### Added
- add the option for opening apps in new tab (fix #29)
### Fixed
- fix issue with the header of the always displayed menu
## 1.10.0
### Added
- add images to select the display of the menu
- add live preview
- update translations
- update app info
## 1.9.3
### Fixed
- fix regression with logo display
## 1.9.2
### Added
- add the option “always displayed” which fixes the position of the menu to the left and always displays the application icons (fix #21, fix #2)
## 1.8.6
### Added
- add translations: `fr` and `de`
- improve and publish the `Makefile`
- update documentation
## 1.8.5
### Fixed
- fix #28: menu items invisible after 1.8.4
## 1.8.4
### Fixed
- fix #27: disable side menu on public pages - broken in 1.8.3
## 1.8.3
### Fixed
- fix alphabetic order of apps (#26)
## 1.8.2
### Added
- add icon for closing the big menu (fix #25)
### Fixed
- fix hidden icons in the top menu (fix #23)
- fix missing apps (fix #24)
## 1.8.1
### Fixed
- fix issue with links
- fix missing l10n files
## 1.8.0
### Added
- add a `big menu` display (fix #22)
- add the possibility to choose what apps are displayed in the top menu (fix #22)
- add icon color filter
- add icon opacity filter
## 1.8.0-rc2
## 1.7.0
### Added
- add a loader when the page is unloading
- add compatibility with Nextcloud 19
## 1.6.3
### Fixed
- fix #20: add a shortcut to open and to hide the menu
## 1.6.2
### Fixed
- fix #19: add a cache to limit flashes
## 1.6.1
### Fixed
- fix #19: add a hack to show external sites in the top menu with navigation
## 1.6.0
### Added
- Add a page of personal settings
- Add an option to disable the side menu as user
- Refactoring of javascripts
## 1.5.0
### Added
- add option to force light icons instead of dark icons
### Fixed
- fix #19: add option to keep external sites in the top menu
- fix #16 #17: add dark icons and handle the svg filters
## 1.4.1
### Added
- Rendering harmonization with browsers
### Fixed
- FIX #15: make menu start after icon
## 1.4.0
### Fixed
- Fix #12: add an option to hide the opener and the panel when there is no application
## 1.3.4
### Fixed
- FIX #14: add option to show only the opener
- FIX #13: add alternate hamburger icon
- FIX #11: remove error in the console
## 1.3.3
### Added
- Add a second background color to create a background gradiant
- Update documentation
### Fixed
- FIX #10: add options to select the size of the icons and the text, or hide them
## 1.3.2
### Fixed
- FIX #9: opener icon not visible with multiple apps_paths
## 1.3.1
### Fixed
- FIX #3: Add an opition the choose the position of the opener (after or before the logo)
- FIX #8: Remove extension of dynamic asset's routes (js, css)
## 1.3.0
### Added
- `main.js` is replaced by a controller and a template
### Fixed
- FIX #2: add option to open the menu by hovering over opener
## 1.2.4
### Fixed
- FIX #7: Opener icon not visible in Safari
+5
View File
@@ -0,0 +1,5 @@
# Contributor Code of Conduct
This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage.
-35
View File
@@ -1,35 +0,0 @@
## Feature
### Description
...
### Benefits
...
---
## Issue
### Environment
* Side menu version: ...
* Nextcloud version: ...
* PHP version: ...
* Web server (Nginx, Apache2): ...
* Web browser and version (Firefox 80, Google Chrome 74, etc): ...
### Steps to reproduce
* ...
* ...
* ...
### Observed Results
...
### Expected Results
...
+20 -7
View File
@@ -1,20 +1,28 @@
npm-build:
build: dep
npm run build
npm-watch:
watch: dep
npm run watch
dep:
npm i
npm link @nextcloud/vue || sudo npm link @nextcloud/vue
.ONESHELL:
release: npm-build translations
release: 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 screenshots releases/$$VERSION/side_menu
cd releases/$$VERSION
if [ -z "$$RELEASE_DIRECTORY" ]; then
RELEASE_DIRECTORY=releases
fi
test -d $$RELEASE_DIRECTORY/$$VERSION && rm -fr $$RELEASE_DIRECTORY/$$VERSION
mkdir -p $$RELEASE_DIRECTORY/$$VERSION/side_menu
cp -r README.md CHANGELOG.md appinfo css lib img l10n js src templates screenshots vendor $$RELEASE_DIRECTORY/$$VERSION/side_menu
cd $$RELEASE_DIRECTORY/$$VERSION
zip -r side_menu_v$$VERSION.zip side_menu
tar cvzf side_menu_v$$VERSION.tar.gz side_menu
rm -fr side_menu
@@ -22,3 +30,8 @@ release: npm-build translations
translations:
php bin/generate_l10n.php
.ONESHELL:
run-code-quality-analysis:
export SONAR_TOKEN="$$SONAR_TOKEN_DEBLAN_SIDE_MENU"
sonar-scanner -Dsonar.projectKey=deblan-side_menu -Dsonar.sources=. -Dsonar.host.url=https://cq.gitnet.fr
+51 -8
View File
@@ -1,27 +1,44 @@
🤙 Nextcloud app / Custom menu 🎨
===============================
[![Build Status](https://ci.gitnet.fr/api/badges/deblan/side_menu/status.svg)](https://ci.gitnet.fr/deblan/side_menu)
[![Translations](https://translate.codeberg.org/widgets/custom-menu/-/application/svg-badge.svg)](https://translate.codeberg.org/engage/custom-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.
You can also add and sort custom categories, define apps that must be displayed in the top menu, etc. Fully customisable.
This application is rather suitable for instances that activate a lot of applications.
Comptatible with AppOrder.
You can customize colors depending of the theme (Dark theme and Breeze Dark).
* [Installation and upgrade](#installation-and-upgrade)
* [How to contribute?](#how-to-contribute)
* [Support](#support)
* [Screenshots](https://gitnet.fr/deblan/side_menu/src/branch/master/screenshots/)
You like this app and you want to support me? [Buy me a coffee](https://www.buymeacoffee.com/deblan) ☕
You like this app and you want to support me? ☕ [Buy me a coffee](https://www.buymeacoffee.com/deblan) or [Donate with liberapay](https://liberapay.com/deblan)
Requirements
------------
* PHP >= 8.0
* App `theming` enabled
Installation and upgrade
------------------------
Custom menu is available 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`.
Custom menu is available from the app store.
```
$ cd /path/to/nextcloud
$ php occ app:install side_menu
```
If you want to install it from source, go to https://gitnet.fr/deblan/side_menu/releases and copy the link to the last release (side_menu_vX.Y.Z.tar.gz). Then:
```
$ cd /path/to/nextcloud/apps
$ unzip /path/to/side_menu_vX.Y.Z.zip # tar xvf /path/to/side_menu_vX.Y.Z.tar.gz
$ curl -sS https://gitnet.fr/attachments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | tar xvfz -
```
Administrators can edit many settings using the administration page.
@@ -30,18 +47,44 @@ Users can disable the menu using the page of personal settings.
Use the shortcut `Ctrl`+`o` to open and to hide the side menu. Use `tab` to navigate.
### Use first top menu app as default app
You can easily let Custom Menu redirect to the first app in the top menu by changing the following parameter in your `config/config.php`:
```
'defaultapp' => 'side_menu',
```
If the top menu is empty then it redirects to files.
How to contribute?
------------------
You can report a bug or request a feature by opening an issue: https://gitnet.fr/deblan/side_menu/issues
If you are a developer:
### You are a translator
Translations are managed from [translate.codeberg.org](https://translate.codeberg.org/projects/custom-menu/application/).
### 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`
* go to `apps/side_menu` and run `make dep`
Build javascripts using `make npm-build` (or `make npm-watch` to build them in real time).
Build javascripts using `make build` (or `make watch` to build them in real time).
Then commit and create a pull request.
Support
-------
You can join the official room on Matrix: [#custommenu:neutralnetwork.org](https://matrix.to/#/#custommenu:neutralnetwork.org).
Notice
------
Because I believe in a free and decentralized Internet, [Gitnet](https://gitnet.fr) is **self-hosted at home**.
In case of downtime, you can download **Custom Menu** from [here](https://kim.deblan.fr/~side_menu/).
-10
View File
@@ -1,10 +0,0 @@
<?php
use OCA\SideMenu\AppInfo\Application;
$app = new Application();
if ($app->isEnabled()) {
$app->registerAssets();
$app->registerServices();
}
+22 -7
View File
@@ -11,16 +11,28 @@ This application is rather suitable for instances that activate a lot of applica
Use the shortcut `Ctrl`+`o` to open and to hide the side menu. Use `tab` to navigate.
Comptatible with AppOrder.
You can customize colors depending of the theme (Dark theme and Breeze Dark).
You can report a bug or request a feature by opening an issue.
If you like this application and want to support the development:
Requirements:
* ☕ [Buy me a coffee](https://www.buymeacoffee.com/deblan)
* 😃 [Leave a comment](https://apps.nextcloud.com/apps/side_menu#comments)
* PHP >= 8.0
* App `theming` enabled
If you like this application and if you want to support the development:
* [Buy me a coffee](https://www.buymeacoffee.com/deblan)
* [Donate with liberapay](https://liberapay.com/deblan)
* [Leave a comment](https://apps.nextcloud.com/apps/side_menu#comments)
Notice
------
Because I believe in a free and decentralized Internet, [Gitnet](https://gitnet.fr) is **self-hosted at home**.
In case of downtime, you can download **Custom Menu** from [here](https://kim.deblan.fr/~side_menu/).
]]></description>
<version>1.17.0</version>
<version>3.4.1</version>
<licence>agpl</licence>
<author mail="contact@deblan.fr" homepage="https://www.deblan.io/">Simon Vieille</author>
<namespace>SideMenu</namespace>
@@ -30,7 +42,7 @@ If you like this application and want to support the development:
</documentation>
<category>customization</category>
<website>https://gitnet.fr/deblan/side_menu</website>
<discussion>https://matrix.to/#/!GhfQePnOSPYpYEunWM:neutralnetwork.org</discussion>
<discussion>https://matrix.to/#/!TFPucDATKODpHNVAtu:neutralnetwork.org?via=neutralnetwork.org</discussion>
<bugs>https://gitnet.fr/deblan/side_menu/issues</bugs>
<repository type="git">https://gitnet.fr/deblan/side_menu</repository>
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/nc19_default_menu.png</screenshot>
@@ -39,8 +51,11 @@ If you like this application and want to support the development:
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/nc18_menu_always_displayed.png</screenshot>
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/nc20_big_menu_responsive.png</screenshot>
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/personal_settings.png</screenshot>
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/nc25_big_menu.png</screenshot>
<screenshot>https://gitnet.fr/deblan/side_menu/raw/branch/master/screenshots/nc25_default_menu.png</screenshot>
<dependencies>
<nextcloud min-version="18" max-version="20"/>
<nextcloud min-version="25" max-version="25"/>
<php min-version="7.4"/>
</dependencies>
<settings>
<admin>OCA\SideMenu\Settings\Admin</admin>
+1
View File
@@ -19,6 +19,7 @@
return [
'routes' => [
['name' => 'App#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'Css#stylesheet', 'url' => '/css/stylesheet', 'verb' => 'GET'],
['name' => 'Js#script', 'url' => '/js/script', 'verb' => 'GET'],
['name' => 'Js#config', 'url' => '/js/config', 'verb' => 'GET'],
+6
View File
@@ -1,4 +1,10 @@
<?php
/**
* Generates l10n files using Yaml.
*
* Usage:
* php bin/generate_l10n.php
*/
function generateJsContent($translations)
{
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* Imports a json configuration into a sqlite database.
*
* Usage:
* php bin/import_config.php /path/to/config.json /path/to/owncloud.db
*/
$configFile = $argv[1];
$databaseFile = $argv[2];
$content = file_get_contents($configFile);
$config = json_decode($content, true);
$pdo = new \Pdo(sprintf('sqlite:%s', $databaseFile));
$stmt = $pdo->prepare('UPDATE oc_appconfig SET configvalue=:value WHERE configkey=:key and appid=:appId');
foreach ($config as $key => $value) {
$stmt->execute([
'appId' => 'side_menu',
'key' => $key,
'value' => $value,
]);
}
+175 -25
View File
@@ -16,55 +16,205 @@
*/
#side-menu-section input[type="color"] {
width: 100px;
margin: 10px 0 10px 0;
width: 100px;
margin: 10px 0 10px 0;
padding: 0;
border-radius: 0;
}
#side-menu-section input[type="checkbox"] {
vertical-align: middle;
#-dropside-menu-section input[type="checkbox"] {
vertical-align: middle;
}
#side-menu-section input[type="range"] {
vertical-align: middle;
vertical-align: middle;
}
#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;
padding: 1px 9px;
margin: 0 2px;
background: #eee;
border: 1px solid #aaa;
color: #555;
border-radius: 3px;
}
.side-menu-display {
padding: 10px;
border: 2px solid transparent;
max-width: 100%;
cursor: pointer;
padding: 10px;
border: 2px solid transparent;
max-width: 100%;
cursor: pointer;
}
.side-menu-display.is-active {
border: 2px solid #91cb7f;
border: 2px solid #91cb7f;
}
.info {
margin-top: 8px;
padding: 5px;
background: #91cb7f;
color: #fff;
border-radius: var(--border-radius);
margin-top: 8px;
padding: 5px;
background: #91cb7f;
color: #fff;
border-radius: var(--border-radius);
}
#side-menu-section h2 small {
font-size: 11px;
font-weight: normal;
font-size: 11px;
font-weight: normal;
}
.side-menu-toggler {
cursor: pointer;
cursor: pointer;
}
.side-menu-setting-list {
margin: 10px 4px 4px 0px;
border: 2px solid var(--color-border-dark);
border-radius: 15px;
}
.side-menu-setting-list-item {
padding: 5px 10px;
border-bottom: 1px solid var(--color-border-dark);
max-width: 300px;
margin: -1px 0 0 0;
cursor: pointer;
line-height: 32px;
}
.side-menu-setting-list-item:last-child {
border-bottom: 0;
}
.side-menu-setting-list-drop {
background: yellow;
border-color: yellow;
height: 34px;
}
.side-menu-setting.arrow {
color: #ccc;
padding-right: 5px;
}
.side-menu-setting-list-item input {
margin-top: 0;
height: 21px !important;
min-height: auto !important;
}
#apps-categories-custom-list select {
width: 100%;
}
.side-menu-setting-table {
display: table;
width: 100%;
}
.side-menu-setting-row {
display: table;
margin-bottom: 10px;
}
.side-menu-setting-row code {
margin-left: 2px;
margin-bottom: 1px;
padding: 3px 10px;
border-radius: 5px;
display: inline-block;
right: 2px;
border: 1px solid var(--color-border-dark);
}
.side-menu-setting-label {
display: table-cell;
width: 430px;
padding-right: 20px;
}
.side-menu-setting-label--top {
vertical-align: top;
}
.side-menu-setting-form {
display: table-cell;
min-width: 300px;
}
.side-menu-setting-label-short {
width: 300px;
}
.side-menu-setting-form-long {
width: 400px;
}
#side-menu-save-progress {
display: inline-block;
width: 0;
height: 15px;
background: #fff;
}
.btn-reset {
display: inline-block;
cursor: pointer;
position: relative;
top: -8px;
left: 5px;
transition-duration: 0.8s;
transition-property: transform;
transform: rotate(360deg);
}
.btn-reset--down {
top: 2px;
}
.btn-reset--progress {
transform: rotate(-359deg);
}
.badges {
margin-bottom: 14px;
margin-top: 4px;
}
.badge {
border-size: 1px;
padding: 2px 8px;
margin-right: 2px;
margin-bottom: 5px;
display: inline-block;
border-radius: 4px;
font-size: 13px;
}
.badge-1 {
background: #d4ce14;
border-color: #cad413;
color: #373a05;
}
.badge-2 {
background: #96d47f;
border-color: #7ed49b;
color: #333;
}
.badge-3 {
background: #d4540a;
border-color: #d4700c;
color: #fff;
}
.badge-4 {
background: #9d81d4;
border-color: #c681d4;
color: #fff;
}
+208 -138
View File
@@ -16,256 +16,326 @@
*/
#side-menu {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
max-width: 250px;
background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
z-index: 3000;
color: var(--side-menu-text-color, #fff);
box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px;
display: none;
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100%;
max-width: 290px;
background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
z-index: 3000;
color: var(--side-menu-text-color, #fff);
box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px;
display: none;
}
#side-menu a {
transition: 0.2s;
}
#side-menu.open {
display: block;
display: block;
}
#header .side-menu-opener {
margin-left: 5px;
margin-left: 0px;
margin-top: -1px;
}
.side-menu-settings {
margin-right: 9px;
margin-top: 2px;
float: right;
line-height: 34px;
height: 28px;
display: none;
}
.side-menu-settings a {
color: var(--side-menu-text-color, #fff);
display: block;
padding: 4px 7px;
}
.side-menu-settings:hover a, .side-menu-settings a:active, .side-menu-settings a:focus {
background: var(--side-menu-current-app-background-color, #444);
}
.side-menu-settings img {
vertical-align: bottom;
margin-left: 3px;
width: 32px;
height: 32px;
}
#side-menu.open .side-menu-settings {
display: block;
}
.side-menu-opener {
background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
height: 40px;
width: 40px;
border-radius: 0;
border: 0;
background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
background-color: transparent !important;
height: 40px !important;
width: 40px !important;
border-radius: 0 !important;
border: 0 !important;
padding-right: 12px !important;
padding-left: 12px !important;
margin-left: 5px !important;
margin-left: 3px !important;
}
.side-menu-opener:active, .side-menu-opener:focus {
background-color: var(--side-menu-current-app-background-color, #444) !important;
}
.side-menu-closer {
background: url('../img/side-menu-opener-closer.svg');
display: none;
background: url('../img/side-menu-opener-closer.svg');
display: none;
}
#side-menu.hide-opener .side-menu-opener, .side-menu-opener.hide, #side-menu.hide {
display: none !important;
display: none !important;
}
.side-menu-apps-list {
height: calc(100vh - 150px);
z-index: 2200;
position: fixed;
top: 150px;
width: 100%;
max-width: 250px;
overflow: auto;
height: calc(100vh - 150px);
z-index: 2200;
position: fixed;
top: 150px;
width: 100%;
max-width: 290px;
overflow: auto;
}
.side-menu-app-icon {
width: 20px;
vertical-align: top;
margin-right: 10px;
filter: invert(var(--side-menu-icon-invert-filter, 0%));
opacity: var(--side-menu-icon-opacity, 1);
}
.side-menu-app-icon svg {
vertical-align: middle;
margin-top: -3px;
width: 20px;
vertical-align: middle;
margin-top: -4px;
margin-right: 10px;
filter: invert(var(--side-menu-icon-invert-filter, 0%));
opacity: var(--side-menu-icon-opacity, 1);
}
.side-menu-app a {
line-height: 30px;
color: var(--side-menu-text-color, #fff);
display: block;
padding: 7px 0 5px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 30px;
color: var(--side-menu-text-color, #fff);
display: block;
padding: 7px 0 5px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.side-menu-app a:hover, .side-menu-app.active, .side-menu-app a:focus {
background: var(--side-menu-current-app-background-color, #444);
background: var(--side-menu-current-app-background-color, #444);
}
.side-menu-logo {
text-align: center;
text-align: center;
}
.side-menu-logo img {
max-width: 60%;
max-height: 100px;
max-width: 60%;
max-height: 100px;
}
.side-menu-header {
height: 150px;
width: 100%;
z-index: 2300;
max-width: 250px;
position: fixed;
padding-top: 2px;
padding-left: 5px;
top: 0;
.enu-header {
height: 150px;
width: 100%;
z-index: 2300;
max-width: 290px;
position: fixed;
padding-top: 2px;
top: 0;
}
#side-menu.side-menu-with-categories .side-menu-header {
max-width: 295px;
}
#side-menu.hide-opener .side-menu-logo {
margin-top: 20px;
margin-top: 20px;
}
#side-menu-loader {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 3001;
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 3001;
}
#side-menu-loader-bar {
height: 4px;
background: var(--side-menu-loader-color, #0e75ac);
width: 0;
transition-property: width;
height: 4px;
background: var(--side-menu-loader-color, #0e75ac);
width: 0;
transition-property: width;
}
#side-menu.side-menu-big {
max-width: 100%;
height: auto;
#side-menu.side-menu-big, #side-menu.side-menu-with-categories {
max-width: 100%;
height: auto;
}
.side-menu-big .side-menu-header {
height: auto;
.side-menu-big .side-menu-header, .side-menu-with-categories .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-apps-list, .side-menu-with-categories .side-menu-apps-list {
height: auto;
position: static;
max-width: 100vw;
overflow: auto;
}
.side-menu-big .side-menu-app a {
padding: 7px 0 7px 7px;
.side-menu-big .side-menu-app a, .side-menu-with-categories .side-menu-app a {
padding: 7px 0 7px 7px;
}
.side-menu-categories-wrapper {
padding-bottom: 70px;
padding-bottom: 70px;
}
.side-menu-categories {
max-height: calc(100vh - 50px);
overflow: auto;
position: relative;
top: 50px;
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 0 10% 0 10%;
max-height: calc(100vh - 55px);
overflow: auto;
position: relative;
top: 5px;
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 0 10% 0 10%;
}
.side-menu-category {
padding: 10px 20px;
flex: 1 1 auto;
padding: 10px 20px;
flex: 1 1 auto;
}
.side-menu-category-title {
padding-left: 10px;
color: var(--side-menu-text-color, #fff);
padding-left: 10px;
color: var(--side-menu-text-color, #fff);
}
.side-menu-loader {
text-align: center;
text-align: center;
}
.side-menu-loader svg {
width: 38px;
margin: auto;
stroke: var(--side-menu-text-color, #fff);
width: 38px;
margin: auto;
stroke: var(--side-menu-text-color, #fff);
}
.side-menu-big .side-menu-app-icon {
vertical-align: middle;
margin-top: -2px;
}
.side-menu-always-displayed #header,
.side-menu-always-displayed body {
width: calc(100% - 50px) !important;
.side-menu-with-categories .side-menu-app-icon, .side-menu-big .side-menu-app-icon {
vertical-align: middle;
margin-top: -2px;
}
.side-menu-always-displayed body {
position: absolute;
left: 50px;
width: calc(100% - 50px) !important;
}
.side-menu-always-displayed body {
position: absolute;
left: 50px;
}
.side-menu-always-displayed #side-menu {
display: block;
display: block;
}
.side-menu-always-displayed .side-menu-apps-list {
height: calc(100vh - 49px);
top: 49px;
height: calc(100vh - 49px);
top: 49px;
overflow: hidden;
}
.side-menu-always-displayed .side-menu-apps-list:hover {
overflow: auto;
}
.side-menu-always-displayed #side-menu,
.side-menu-always-displayed .side-menu-header,
.side-menu-always-displayed .side-menu-apps-list {
width: 50px;
width: 50px;
}
.side-menu-always-displayed #side-menu .side-menu-app-text,
.side-menu-always-displayed #header .side-menu-opener,
.side-menu-always-displayed .side-menu-logo {
display: none;
display: none;
}
.side-menu-always-displayed #side-menu .side-menu-header {
height: 49px;
height: 49px;
}
.side-menu-always-displayed #side-menu.open,
.side-menu-always-displayed #side-menu.open .side-menu-apps-list,
.side-menu-always-displayed #side-menu.open .side-menu-header {
width: 100%;
width: 100%;
}
.side-menu-always-displayed #side-menu.open .side-menu-app-text {
display: inline;
display: inline;
}
.side-menu-always-displayed .app-navigation--close {
transform: translateX(calc(-100% + 50px)) !important;
transform: translateX(calc(-100% + 50px)) !important;
}
#side-menu.side-menu-with-categories {
max-width: 290px;
height: 100vh;
}
.side-menu-with-categories .side-menu-categories {
display: block;
padding: 0;
}
.side-menu-with-categories .side-menu-category {
padding: 10px 0;
}
.side-menu-always-displayed #body-settings, #body-settings.body-settings-side-menu {
overflow-x: visible;
}
.app-menu {
visibility: hidden;
}
.app-menu.show {
visibility: visible;
}
@media screen and (max-width: 1024px) {
#side-menu.side-menu-big {
max-width: 290px;
}
#side-menu.side-menu-big {
max-width: 290px;
height: 100vh;
}
.side-menu-categories {
display: block;
padding: 0;
}
.side-menu-categories {
display: block;
padding: 0;
}
.side-menu-category {
padding: 10px 0;
}
#side-menu.side-menu-big {
height: 100vh;
}
.side-menu-category {
padding: 10px 0;
}
}
@media screen and (min-width: 1024px) {
.side-menu-closer {
display: block;
float: right;
margin-right: 9px;
}
.side-menu-closer {
display: block;
float: right;
margin-right: 9px;
}
.side-menu-big .side-menu-header {
max-width: 100%;
}
.side-menu-big .side-menu-header {
max-width: 100%;
}
}
@@ -0,0 +1,224 @@
<?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="571.907"
height="156.921"
viewBox="0 0 151.317 41.519"
version="1.1"
id="svg901"
sodipodi:docname="layout-side-menu-with-categories.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata907">
<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="defs905" />
<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="1036"
id="namedview903"
showgrid="false"
inkscape:zoom="1.6086532"
inkscape:cx="455.61054"
inkscape:cy="16.694081"
inkscape:window-x="0"
inkscape:window-y="21"
inkscape:window-maximized="0"
inkscape:current-layer="svg901"
showguides="false" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#fff"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v41.16H.18zM62.735.18h58.532v41.16H62.735z"
id="path853" />
<g
fill="#b3b3b3"
stroke="#ccc"
fill-rule="evenodd"
stroke-width="1.465"
stroke-linecap="round"
id="g857">
<path
d="M84.066 21.35l5.055-5.056M82.925 29.835l18.152-18.151M95.893 25.225l3.585-3.586"
id="path855" />
</g>
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M62.735.18h58.532v41.16H62.735z"
id="path861" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#f9f9f9"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v5.063H.18z"
id="path877" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v41.16H.18z"
id="path879" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#666"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M1.357 1.034h3.496V4.39H1.357z"
id="path881" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#e6e6e6"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M6.068 1.034h6.102V4.39H6.068z"
id="path883" />
<g
fill="#b3b3b3"
stroke="#ccc"
fill-rule="evenodd"
stroke-width="1.465"
stroke-linecap="round"
id="g887">
<path
d="M21.51 21.35l5.056-5.056M20.37 29.835L38.52 11.684M33.337 25.225l3.586-3.586"
id="path885" />
</g>
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#fff"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.28v41.16h-25.28z"
id="path889" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#f9f9f9"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.257v5.063h-25.257z"
id="path891" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.257v41.16h-25.257z"
id="path893" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#4d4d4d"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h20.829v41.16h-20.83z"
id="path895" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#666"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M127.034 1.034h3.496V4.39h-3.496z"
id="path897" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#e6e6e6"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M127.569 10.155h1.893v1.81h-1.893zM130.498 10.486h12.463v1.148h-12.463zM127.569 13.696h1.893v1.81h-1.893zM130.498 14.027h10.592v1.148h-10.592zM127.569 17.104h1.893v1.81h-1.893zM130.498 17.435h12.997v1.148h-12.997zM127.569 24.708h1.893v1.81h-1.893zM130.498 25.04h7.585v1.147h-7.585zM127.569 28.116h1.893v1.81h-1.893zM130.498 28.447h11.46v1.148h-11.46zM127.569 31.657h1.893v1.81h-1.893zM130.498 31.988h9.322v1.148h-9.322zM127.569 35.065h1.893v1.81h-1.893zM130.498 35.396h11.126v1.148h-11.126zM127.616 6.848h11.518v1.148h-11.518zM127.569 21.311h9.344v1.148h-9.344z"
id="path899" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#4d4d4d;stroke:#b3b3b3;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 62.728587,0.17999881 h 20.829 V 41.34 h -20.83 z"
id="path895-5" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#666666;stroke:#cccccc;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 63.905587,1.0339988 h 3.496 V 4.389999 h -3.496 z"
id="path897-3" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#e6e6e6;stroke:#cccccc;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 64.440587,10.154999 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 12.463 v 1.148 h -12.463 z m -2.929,3.21 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 10.592 v 1.148 h -10.592 z m -2.929,3.077 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 12.997 v 1.148 h -12.997 z m -2.929,7.273 h 1.893 V 26.518 h -1.893 z m 2.929,0.332 h 7.585 v 1.147 h -7.585 z m -2.929,3.076001 h 1.893 v 1.81 h -1.893 z m 2.929,0.330999 h 11.46 v 1.147999 h -11.46 z m -2.929,3.21 h 1.893 v 1.809999 h -1.893 z m 2.929,0.330999 h 9.322 v 1.148001 h -9.322 z m -2.929,3.077001 h 1.893 v 1.809999 h -1.893 z m 2.929,0.331001 h 11.126 v 1.147999 h -11.126 z m -2.882,-28.5480012 h 11.518 v 1.1480001 h -11.518 z m -0.047,14.4630002 h 9.344 v 1.148 h -9.344 z"
id="path899-5" />
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

+223
View File
@@ -0,0 +1,223 @@
<?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="571.907"
height="156.921"
viewBox="0 0 151.317 41.519"
version="1.1"
id="svg901"
sodipodi:docname="layout-side-menu-with-categories.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata907">
<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="defs905" />
<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="1036"
id="namedview903"
showgrid="false"
inkscape:zoom="1.6086532"
inkscape:cx="455.61054"
inkscape:cy="16.694081"
inkscape:window-x="0"
inkscape:window-y="21"
inkscape:window-maximized="0"
inkscape:current-layer="svg901" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#fff"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v41.16H.18zM62.735.18h58.532v41.16H62.735z"
id="path853" />
<g
fill="#b3b3b3"
stroke="#ccc"
fill-rule="evenodd"
stroke-width="1.465"
stroke-linecap="round"
id="g857">
<path
d="M84.066 21.35l5.055-5.056M82.925 29.835l18.152-18.151M95.893 25.225l3.585-3.586"
id="path855" />
</g>
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M62.735.18h58.532v41.16H62.735z"
id="path861" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#f9f9f9"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v5.063H.18z"
id="path877" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M.18.18h58.532v41.16H.18z"
id="path879" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#666"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M1.357 1.034h3.496V4.39H1.357z"
id="path881" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#e6e6e6"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M6.068 1.034h6.102V4.39H6.068z"
id="path883" />
<g
fill="#b3b3b3"
stroke="#ccc"
fill-rule="evenodd"
stroke-width="1.465"
stroke-linecap="round"
id="g887">
<path
d="M21.51 21.35l5.056-5.056M20.37 29.835L38.52 11.684M33.337 25.225l3.586-3.586"
id="path885" />
</g>
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#fff"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.28v41.16h-25.28z"
id="path889" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#f9f9f9"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.257v5.063h-25.257z"
id="path891" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="none"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h25.257v41.16h-25.257z"
id="path893" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#4d4d4d"
stroke="#b3b3b3"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M125.857.18h20.829v41.16h-20.83z"
id="path895" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#666"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M127.034 1.034h3.496V4.39h-3.496z"
id="path897" />
<path
style="marker:none"
color="#000"
overflow="visible"
fill="#e6e6e6"
stroke="#ccc"
stroke-width=".359"
stroke-linecap="square"
paint-order="fill markers stroke"
d="M127.569 10.155h1.893v1.81h-1.893zM130.498 10.486h12.463v1.148h-12.463zM127.569 13.696h1.893v1.81h-1.893zM130.498 14.027h10.592v1.148h-10.592zM127.569 17.104h1.893v1.81h-1.893zM130.498 17.435h12.997v1.148h-12.997zM127.569 24.708h1.893v1.81h-1.893zM130.498 25.04h7.585v1.147h-7.585zM127.569 28.116h1.893v1.81h-1.893zM130.498 28.447h11.46v1.148h-11.46zM127.569 31.657h1.893v1.81h-1.893zM130.498 31.988h9.322v1.148h-9.322zM127.569 35.065h1.893v1.81h-1.893zM130.498 35.396h11.126v1.148h-11.126zM127.616 6.848h11.518v1.148h-11.518zM127.569 21.311h9.344v1.148h-9.344z"
id="path899" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#4d4d4d;stroke:#b3b3b3;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 62.728587,0.17999881 h 20.829 V 41.34 h -20.83 z"
id="path895-5" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#666666;stroke:#cccccc;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 63.905587,1.0339988 h 3.496 V 4.389999 h -3.496 z"
id="path897-3" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;fill:#e6e6e6;stroke:#cccccc;stroke-width:0.359;stroke-linecap:square;marker:none;paint-order:fill markers stroke"
overflow="visible"
d="m 64.440587,10.154999 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 12.463 v 1.148 h -12.463 z m -2.929,3.21 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 10.592 v 1.148 h -10.592 z m -2.929,3.077 h 1.893 v 1.81 h -1.893 z m 2.929,0.331 h 12.997 v 1.148 h -12.997 z m -2.929,7.273 h 1.893 V 26.518 h -1.893 z m 2.929,0.332 h 7.585 v 1.147 h -7.585 z m -2.929,3.076001 h 1.893 v 1.81 h -1.893 z m 2.929,0.330999 h 11.46 v 1.147999 h -11.46 z m -2.929,3.21 h 1.893 v 1.809999 h -1.893 z m 2.929,0.330999 h 9.322 v 1.148001 h -9.322 z m -2.929,3.077001 h 1.893 v 1.809999 h -1.893 z m 2.929,0.331001 h 11.126 v 1.147999 h -11.126 z m -2.882,-28.5480012 h 11.518 v 1.1480001 h -11.518 z m -0.047,14.4630002 h 9.344 v 1.148 h -9.344 z"
id="path899-5" />
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

+1 -113
View File
@@ -1,113 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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="37.099998mm"
height="37.099998mm"
viewBox="0 0 37.099998 37.099998"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="242.1839"
inkscape:cy="32.026866"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1918"
inkscape:window-height="1027"
inkscape:window-x="1920"
inkscape:window-y="21"
inkscape:window-maximized="0"
inkscape:snap-nodes="false" />
<metadata
id="metadata5">
<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>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-59.922223,-92.669069)">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.46500015;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:accumulate"
id="rect815-6-2-7"
width="34.535"
height="34.535"
x="61.204723"
y="93.951569"
rx="5.4806547"
ry="5.4806547" />
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;vector-effect:none;fill:#ececec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.46500015;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:accumulate"
id="rect815-6-7"
width="20.357224"
height="33.40107"
x="61.677193"
y="94.518532"
rx="0"
ry="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#333333;stroke-width:3.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 66.59458,111.16177 h 9.997359"
id="path873-5"
inkscape:connector-curvature="0" />
<g
id="g1018"
transform="translate(2.6458333)"
style="stroke:#333333;stroke-opacity:1">
<g
id="g1013"
style="stroke:#333333;stroke-opacity:1">
<path
style="fill:none;fill-rule:evenodd;stroke:#333333;stroke-width:3.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 63.948747,103.80467 H 75.349244"
id="path873"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#333333;stroke-width:3.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 63.948747,118.51887 H 75.349244"
id="path873-5-3"
inkscape:connector-curvature="0" />
</g>
</g>
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#333333;stroke-width:2.56500006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:accumulate"
id="rect815-6-2"
width="34.535"
height="34.535"
x="61.204723"
y="93.951569"
rx="5.4806547"
ry="5.4806547" />
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="145.889" height="145.889" viewBox="0 0 38.6 38.6"><g transform="translate(-59.172 -91.92)" stroke="#000" fill="none"><path d="M66.595 111.162h9.997M66.595 103.805h11.4m-11.4 14.714h11.4" stroke-width="3.165"/><rect width="34.535" height="34.535" x="61.205" y="93.952" overflow="visible" rx="5.481" ry="5.481" style="marker:none" color="#000" stroke-width="4.065" stroke-linecap="round" paint-order="fill markers stroke"/></g></svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 478 B

+1 -6
View File
@@ -1,6 +1 @@
<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>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><g fill="#fff" color="#000" transform="translate(-.067 .224)"><rect width="5.027" height=".777" x="-2.307" y="6.984" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none" transform="rotate(-45)"/><rect width="5.027" height=".777" x="4.859" y="-.595" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none" transform="rotate(45)"/></g></svg>

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 495 B

+1 -173
View File
@@ -1,173 +1 @@
<?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>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><g fill-opacity=".898" color="#000" transform="matrix(.90559 0 0 .86896 .772 -247.893)"><rect width="1.451" height="1.451" x="4.266" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="1.451" height="1.451" x="4.266" y="290.631" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13 2.157)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="1.451" height="1.451" x="4.266" y="292.808" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13 4.334)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+1 -102
View File
@@ -1,102 +1 @@
<?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>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><rect width="7.62" height="7.62" x="1.482" y="1.482" fill="none" stroke="#000" stroke-linecap="square" stroke-width=".777" color="#000" overflow="visible" paint-order="markers fill stroke" rx="0" ry="0" style="marker:none"/><rect width="5.027" height=".777" x="2.778" y="3.148" color="#000" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.027" height=".777" x="2.778" y="6.658" color="#000" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.027" height=".777" x="2.778" y="4.936" color="#000" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 786 B

+1 -101
View File
@@ -1,101 +1 @@
<?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>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><rect width="7.62" height="7.62" x="1.482" y="1.482" fill="none" stroke="#fff" stroke-linecap="square" stroke-width=".777" color="#000" overflow="visible" paint-order="markers fill stroke" rx="0" ry="0" style="marker:none"/><g fill="#fff" color="#000" transform="translate(0 .034)"><rect width="5.027" height=".777" x="2.778" y="3.114" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.027" height=".777" x="2.778" y="6.624" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.027" height=".777" x="2.778" y="4.903" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 809 B

+1 -92
View File
@@ -1,92 +1 @@
<?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>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><g color="#000" transform="matrix(.85624 0 0 .9944 .747 .03)"><g transform="matrix(1.0055 0 0 1 -.013 0)"><rect width="5.839" height=".782" x="2.372" y="2.764" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.839" height=".782" x="2.372" y="7.037" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="5.871" height=".782" x="2.372" y="4.901" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 637 B

+1 -91
View File
@@ -1,91 +1 @@
<?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="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>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><g fill="#fff" color="#000" transform="matrix(.85624 0 0 .9944 .747 .03)"><g transform="matrix(1.0055 0 0 1 -.013 0)"><rect width="5.839" height=".782" x="2.372" y="2.764" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="5.839" height=".782" x="2.372" y="7.037" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="5.871" height=".782" x="2.372" y="4.901" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 649 B

+1 -172
View File
@@ -1,172 +1 @@
<?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="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>
<rect
ry="0"
rx="0"
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>
<rect
ry="0"
rx="0"
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>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 10.583 10.583"><g fill="#fff" fill-opacity=".946" color="#000" transform="matrix(.90559 0 0 .86896 .772 -247.893)"><rect width="1.451" height="1.451" x="4.266" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="1.451" height="1.451" x="4.266" y="290.631" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13 2.157)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g><rect width="1.451" height="1.451" x="4.266" y="292.808" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><g transform="translate(-.13 4.334)"><rect width="1.451" height="1.451" x="6.445" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/><rect width="1.451" height="1.451" x="2.345" y="288.474" overflow="visible" paint-order="stroke markers fill" rx="0" ry="0" style="marker:none"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+70 -59
View File
@@ -6,8 +6,12 @@ use OC;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
use OC\User\User;
use OCA\SideMenu\Service\AppRepository;
use OCA\SideMenu\Service\CategoryRepository;
use OCA\SideMenu\Service\ConfigProxy;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\IUserSession;
use OCP\Util;
use Psr\Container\ContainerInterface;
@@ -17,7 +21,7 @@ use Psr\Container\ContainerInterface;
*
* @author Simon Vieille <simon@deblan.fr>
*/
class Application extends App
class Application extends App implements IBootstrap
{
public const APP_ID = 'side_menu';
@@ -43,81 +47,88 @@ class Application extends App
public function __construct(array $urlParams = [])
{
parent::__construct(self::APP_ID, $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
protected function isEnabled(): bool
{
$enabled = true;
$isForced = (bool) $this->config->getAppValue(self::APP_ID, 'force', '0');
if (null !== $this->user && !$isForced) {
$enabled = (bool) $this->config->getUserValue($this->user->getUid(), self::APP_ID, 'enabled', '1');
$enabled = (bool) $this->config->getUserValue(
$this->user->getUid(),
self::APP_ID,
'enabled',
$this->config->getAppValue(
self::APP_ID,
'default-enabled',
'1'
)
);
}
return $enabled;
}
/**
* Registes services.
*/
public function registerServices()
{
$container = $this->getContainer();
$container->registerService('AppRepository', function (ContainerInterface $c) {
return new AppRepository();
});
$container->registerService('ConfigProxy', function (ContainerInterface $c) {
return new ConfigProxy($this->config);
});
}
/**
* Registers assets.
*/
public function registerAssets()
protected function addAssets()
{
Util::addScript(self::APP_ID, 'sideMenu');
Util::addStyle(self::APP_ID, 'sideMenu');
$stylesheet = OC::$server->getURLGenerator()->linkToRoute(
'side_menu.Css.stylesheet',
[
'v' => $this->config->getAppValue(self::APP_ID, 'cache', '0'),
]
);
$script = OC::$server->getURLGenerator()->linkToRoute(
'side_menu.Js.script',
[
'v' => $this->config->getAppValue(self::APP_ID, 'cache', '0'),
]
);
Util::addHeader(
'link',
[
'href' => $stylesheet,
'rel' => 'stylesheet',
$assets = [
'stylesheet' => [
'route' => 'side_menu.Css.stylesheet',
'type' => 'link',
'route_attr' => 'href',
'attr' => [
'rel' => 'stylesheet',
],
],
''
);
Util::addHeader(
'script',
[
'src' => $script,
'nonce' => $this->cspnm->getNonce(),
'script' => [
'route' => 'side_menu.Js.script',
'type' => 'script',
'route_attr' => 'src',
'attr' => [
'nonce' => $this->cspnm->getNonce(),
],
],
''
);
];
$cache = $this->config->getAppValue(self::APP_ID, 'cache', '0');
foreach ($assets as $value) {
$route = OC::$server->getURLGenerator()->linkToRoute($value['route'], ['v' => $cache]);
$value['attr'][$value['route_attr']] = $route;
Util::addHeader($value['type'], $value['attr'], '');
}
}
public function register(IRegistrationContext $context): void
{
$context->registerService('AppRepository', function () {
return new AppRepository();
});
$context->registerService('CategoryRepository', function () {
return new CategoryRepository();
});
$context->registerService('ConfigProxy', function () {
return new ConfigProxy();
});
}
public function boot(IBootContext $context): void
{
$this->config = OC::$server->getConfig();
$this->cspnm = OC::$server->getContentSecurityPolicyNonceManager();
$this->user = OC::$server[IUserSession::class]->getUser();
if (!$this->isEnabled()) {
return;
}
$this->addAssets();
}
}
+3 -3
View File
@@ -69,7 +69,7 @@ class AdminSettingController extends Controller
public function exportConfiguration()
{
$keys = $this->config->getAppKeys(Application::APP_ID);
$config = [];
$appConfig = [];
$excludedKeys = [
'cache',
'cache-categories',
@@ -80,11 +80,11 @@ class AdminSettingController extends Controller
continue;
}
$config[$key] = $this->config->getAppValue(Application::APP_ID, $key);
$appConfig[$key] = $this->config->getAppValue(Application::APP_ID, $key);
}
return new DataDownloadResponse(
json_encode($config, JSON_PRETTY_PRINT),
json_encode($appConfig, JSON_PRETTY_PRINT),
'config.json',
'text/json'
);
+102
View File
@@ -0,0 +1,102 @@
<?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 OCA\SideMenu\Service\AppRepository;
use OCA\SideMenu\Service\ConfigProxy;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
class AppController extends Controller
{
/**
* @var ConfigProxy
*/
protected $config;
/**
* @var AppRepository
*/
protected $appRepository;
public function __construct(
string $appName,
IRequest $request,
AppRepository $appRepository,
IURLGenerator $urlGenerator,
ConfigProxy $config
) {
parent::__construct($appName, $request);
$this->appRepository = $appRepository;
$this->urlGenerator = $urlGenerator;
$this->config = $config;
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function index(): RedirectResponse
{
$user = OC::$server[IUserSession::class]->getUser();
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
$hiddenApps = $this->config->getAppValueArray('big-menu-hidden-apps', '[]');
$isForced = $this->config->getAppValueBool('force', '0');
$userTopMenuApps = $this->config->getUserValueArray($user, 'top-menu-apps', '[]');
$apps = $this->appRepository->getOrderedApps($user);
if (!$isForced && !empty($userTopMenuApps)) {
$topMenuApps = $userTopMenuApps;
}
foreach ($apps as $app) {
$inTopMenuApps = in_array($app['id'], $topMenuApps);
$inHiddenApps = in_array($app['id'], $hiddenApps);
if (!$inTopMenuApps || $inHiddenApps) {
continue;
}
return $this->redirectToApp($app['id']);
}
return $this->redirectToApp('files');
}
protected function redirectToApp($appId): RedirectResponse
{
$isIgnoreFrontController = true === OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false);
$isFrontControllerActive = 'true' === getenv('front_controller_active');
if ($isIgnoreFrontController || $isFrontControllerActive) {
$path = '/apps/%s/';
} else {
$path = '/index.php/apps/%s/';
}
$url = $this->urlGenerator->getAbsoluteURL(sprintf($path, $appId));
return new RedirectResponse($url);
}
}
+81 -9
View File
@@ -27,6 +27,8 @@ use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
use OCP\IUserSession;
use OCA\Theming\ThemingDefaults;
use OCA\SideMenu\Service\Color;
class CssController extends Controller
{
@@ -40,12 +42,30 @@ class CssController extends Controller
*/
protected $user;
public function __construct(string $appName, IRequest $request, ConfigProxy $config)
/**
* @var ThemingDefaults
*/
protected $theming;
/**
* @var Color
*/
protected $color;
public function __construct(
string $appName,
IRequest $request,
ConfigProxy $config,
ThemingDefaults $theming,
Color $color
)
{
parent::__construct($appName, $request);
$this->user = OC::$server[IUserSession::class]->getUser();
$this->config = $config;
$this->theming = $theming;
$this->color = $color;
}
/**
@@ -65,29 +85,80 @@ class CssController extends Controller
protected function getConfig(): array
{
$backgroundColor = $this->config->getAppValue('background-color', '#333333');
$backgroundColorTo = $this->config->getAppValue('background-color-to', $backgroundColor);
$isForced = $this->config->getAppValueBool('force', '0');
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
$topSideMenuApps = $this->config->getAppValueArray('top-side-menu-apps', '[]');
$isAccessibilityAppEnabled = $this->config->getAppValueBool('enabled', '0', 'accessibility');
$isBreezeDarkAppEnabled = $this->config->getAppValueBool('enabled', '0', 'breezedark');
$isBreezeDarkGlobalEnabled = $this->config->getAppValueBool('theme_enabled', '0', 'breezedark');
if ($this->user) {
$userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]');
$userTopSideMenuApps = $this->config->getUserValueArray($this->user, 'top-side-menu-apps', '[]');
if (!empty($userTopMenuApps) && !$isForced) {
$topMenuApps = $userTopMenuApps;
}
if (!empty($userTopSideMenuApps) && !$isForced) {
$topSideMenuApps = $userTopSideMenuApps;
}
$isDarkThemeUserEnabled = $this->config->getUserValue($this->user, 'theme', '', 'accessibility') === 'dark';
$isBreezeDarkUserEnabled = $this->config->getUserValue($this->user, 'theme_enabled', '', 'breezedark');
$isBreezeDarkUserEnabled = $isBreezeDarkUserEnabled === '1' || ($isBreezeDarkGlobalEnabled && $isBreezeDarkUserEnabled === '');
} else {
$isDarkThemeUserEnabled = false;
$isBreezeDarkUserEnabled = false;
}
$isDarkMode = ($isAccessibilityAppEnabled && $isDarkThemeUserEnabled) || ($isBreezeDarkAppEnabled && $isBreezeDarkUserEnabled);
$primaryColor = $this->theming->getColorPrimary();
$lightenPrimaryColor = $this->color->adjustBrightness($primaryColor, 0.2);
$darkenPrimaryColor = $this->color->adjustBrightness($primaryColor, -0.2);
$darkenPrimaryColor2 = $this->color->adjustBrightness($primaryColor, -0.3);
$textColor = $this->theming->getTextColorPrimary();
if ($isDarkMode) {
$backgroundColor = $this->config->getAppValue('dark-mode-background-color', $darkenPrimaryColor);
$backgroundColorTo = $this->config->getAppValue('dark-mode-background-color-to', $darkenPrimaryColor);
$currentAppBackgroundColor = $this->config->getAppValue('dark-mode-current-app-background-color', $darkenPrimaryColor2);
$loaderColor = $this->config->getAppValue('dark-mode-loader-color', $lightenPrimaryColor);
$textColor = $this->config->getAppValue('dark-mode-text-color', $textColor);
$iconInvertFilter = abs($this->config->getAppValueInt('dark-mode-icon-invert-filter', '0')).'%';
$iconOpacity = abs($this->config->getAppValueInt('dark-mode-icon-opacity', '100') / 100);
$opener = $this->config->getAppValue('dark-mode-opener', 'side-menu-opener');
$backgroundOpacity = dechex($this->config->getAppValueInt('dark-mode-background-color-opacity', '100') * 255 / 100);
} else {
$backgroundColor = $this->config->getAppValue('background-color', $darkenPrimaryColor);
$backgroundColorTo = $this->config->getAppValue('background-color-to', $darkenPrimaryColor);
$currentAppBackgroundColor = $this->config->getAppValue('current-app-background-color', $darkenPrimaryColor2);
$loaderColor = $this->config->getAppValue('loader-color', $lightenPrimaryColor);
$textColor = $this->config->getAppValue('text-color', $textColor);
$iconInvertFilter = abs($this->config->getAppValueInt('icon-invert-filter', '0')).'%';
$iconOpacity = abs($this->config->getAppValueInt('icon-opacity', '100') / 100);
$opener = $this->config->getAppValue('opener', 'side-menu-opener');
$backgroundOpacity = dechex($this->config->getAppValueInt('background-color-opacity', '100') * 255 / 100);
}
$backgroundColor .= $backgroundOpacity;
$backgroundColorTo .= $backgroundOpacity;
return [
'vars' => [
'background-color' => $backgroundColor,
'background-color-to' => $backgroundColorTo,
'current-app-background-color' => $this->config->getAppValue('current-app-background-color', '#444444'),
'loader-color' => $this->config->getAppValue('loader-color', '#0e75ac'),
'text-color' => $this->config->getAppValue('text-color', '#FFFFFF'),
'opener' => $this->config->getAppValue('opener', 'side-menu-opener'),
'icon-invert-filter' => abs($this->config->getAppValueInt('icon-invert-filter', '0')).'%',
'icon-opacity' => abs($this->config->getAppValueInt('icon-opacity', '100') / 100),
'current-app-background-color' => $currentAppBackgroundColor,
'loader-color' => $loaderColor,
'text-color' => $textColor,
'opener' => $opener,
'icon-invert-filter' => $iconInvertFilter,
'icon-opacity' => $iconOpacity,
],
'display-logo' => $this->config->getAppValueBool('display-logo', '1'),
'opener-only' => $this->config->getAppValueBool('opener-only', '0'),
@@ -97,6 +168,7 @@ class CssController extends Controller
'always-displayed' => $this->config->getAppValueBool('always-displayed', '0'),
'big-menu' => $this->config->getAppValueBool('big-menu', '0'),
'top-menu-apps' => $topMenuApps,
'top-side-menu-apps' => $topSideMenuApps,
];
}
}
+58 -9
View File
@@ -28,6 +28,7 @@ use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\L10N\IFactory;
class JsController extends Controller
{
@@ -46,14 +47,25 @@ class JsController extends Controller
*/
protected $themingDefaults;
public function __construct(string $appName, IRequest $request, ConfigProxy $config, ThemingDefaults $themingDefaults)
{
/**
* @var IFactory
*/
protected $l10nFactory;
public function __construct(
string $appName,
IRequest $request,
ConfigProxy $config,
ThemingDefaults $themingDefaults,
IFactory $l10nFactory
) {
parent::__construct($appName, $request);
$this->themingDefaults = $themingDefaults;
$this->user = OC::$server[IUserSession::class]->getUser();
$this->config = $config;
$this->l10nFactory = $l10nFactory;
}
/**
@@ -82,18 +94,33 @@ class JsController extends Controller
protected function getConfig(): array
{
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
$topSideMenuApps = $this->config->getAppValueArray('top-side-menu-apps', '[]');
$topMenuAppsOrder = $this->config->getAppValueArray('top-menu-apps-order', '[]');
$targetBlankApps = $this->config->getAppValueArray('target-blank-apps', '[]');
$useAvatar = $this->config->getAppValueBool('use-avatar', '0');
$isForced = $this->config->getAppValueBool('force', '0');
$addLogoLink = $this->config->getAppValueBool('add-logo-link', '1');
$appsOrder = $this->config->getAppValueArray('apps-order', '[]');
$avatar = null;
$settings = null;
if ($this->user) {
$userAppsOrder = $this->config->getUserValueArray($this->user, 'apps-order', '[]');
$userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]');
$userTopSideMenuApps = $this->config->getUserValueArray($this->user, 'top-side-menu-apps', '[]');
if (!empty($userTopMenuApps) && !$isForced) {
$topMenuApps = $userTopMenuApps;
}
if (!empty($userTopSideMenuApps) && !$isForced) {
$topSideMenuApps = $userTopSideMenuApps;
}
if (!empty($userAppsOrder) && !$isForced) {
$appsOrder = $userAppsOrder;
}
$userTargetBlankMode = $this->config->getUserValueInt($this->user, 'target-blank-mode', '1');
$userTargetBlankApps = $this->config->getUserValueArray($this->user, 'target-blank-apps', '[]');
@@ -104,16 +131,32 @@ class JsController extends Controller
$isAvatarSet = OC::$server->getAvatarManager()->getAvatar($this->user->getUid())->exists();
if ($useAvatar && $isAvatarSet) {
$avatar = OC::$server->getURLGenerator()->linkToRoute(
'core.avatar.getAvatar', [
'userId' => $this->user->getUid(),
'size' => 128,
'v' => $this->config->getUserValueInt($this->user, 'avatar', 'version', 0),
]
);
$avatar = OC::$server->getURLGenerator()->linkToRoute('core.avatar.getAvatar', [
'userId' => $this->user->getUid(),
'size' => 128,
'v' => $this->config->getUserValueInt($this->user, 'avatar', 'version', 0),
]);
}
if ($this->config->getAppValueBool('show-settings', '0')) {
$settingsNav = OC::$server->getNavigationManager()->getAll('settings');
if (isset($settingsNav['settings'])) {
$settings = [
'href' => $settingsNav['settings']['href'],
'name' => $settingsNav['settings']['name'],
'avatar' => OC::$server->getURLGenerator()->linkToRoute('core.avatar.getAvatar', [
'userId' => $this->user->getUid(),
'size' => 32,
'v' => $this->config->getUserValueInt($this->user, 'avatar', 'version', 0),
]),
];
}
}
}
$indexUrl = OC::$server->getURLGenerator()->linkTo('', 'index.php');
return [
'opener-position' => $this->config->getAppValue('opener-position', 'before'),
'opener-hover' => $this->config->getAppValueBool('opener-hover', '0'),
@@ -122,11 +165,17 @@ class JsController extends Controller
'hide-when-no-apps' => $this->config->getAppValueBool('hide-when-no-apps', '0'),
'loader-enabled' => $this->config->getAppValueBool('loader-enabled', '1'),
'always-displayed' => $this->config->getAppValueBool('always-displayed', '0'),
'side-with-categories' => $this->config->getAppValueBool('side-with-categories', '0'),
'big-menu' => $this->config->getAppValueBool('big-menu', '0'),
'big-menu-hidden-apps' => $this->config->getAppValueArray('big-menu-hidden-apps', '[]'),
'apps-order' => $appsOrder,
'avatar' => $avatar,
'top-menu-apps' => $topMenuApps,
'top-side-menu-apps' => $topSideMenuApps,
'target-blank-apps' => $targetBlankApps,
'settings' => $settings,
'logo' => $this->themingDefaults->getLogo(),
'logo-link' => $addLogoLink ? $indexUrl : null,
];
}
}
+41 -47
View File
@@ -21,13 +21,11 @@ namespace OCA\SideMenu\Controller;
use OC;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\URLGenerator;
use OCA\SideMenu\AppInfo\Application;
use OCA\SideMenu\Service\AppRepository;
use OCA\SideMenu\Service\CategoryRepository;
use OCA\SideMenu\Service\ConfigProxy;
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;
@@ -39,11 +37,6 @@ class NavController extends Controller
*/
protected $config;
/**
* @var IConfig
*/
protected $iConfig;
/**
* @var AppRepository
*/
@@ -67,20 +60,17 @@ class NavController extends Controller
public function __construct(
string $appName,
IRequest $request,
IConfig $iConfig,
ConfigProxy $config,
AppRepository $appRepository,
CategoryFetcher $categoryFetcher,
CategoryRepository $categoryRepository,
URLGenerator $router,
IL10N $trans,
IFactory $l10nFactory)
{
IFactory $l10nFactory
) {
parent::__construct($appName, $request);
$this->config = $config;
$this->iConfig = $iConfig;
$this->appRepository = $appRepository;
$this->categoryFetcher = $categoryFetcher;
$this->categoryRepository = $categoryRepository;
$this->l10nFactory = $l10nFactory;
$this->router = $router;
}
@@ -94,13 +84,7 @@ class NavController extends Controller
*/
public function items()
{
$apps = $this->appRepository->getVisibleApps();
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$externalSitesInTopMenu = $this->config->getAppValueBool('external-sites-in-top-menu', '0');
$user = OC::$server[IUserSession::class]->getUser();
$isForced = $this->config->getAppValueBool('force', '0');
$appsCategories = [];
$categoriesAppsCount = [];
$items = [];
if (!$user) {
@@ -109,36 +93,31 @@ class NavController extends Controller
]);
}
$categoriesLabels = $this->config->getAppValueArray('cache-categories', '[]');
if (empty($categoriesLabels)) {
$categoriesLabels = $this->categoryFetcher->get();
$this->iConfig->setAppValue(Application::APP_ID, 'cache-categories', json_encode($categoriesLabels));
}
$apps = $this->appRepository->getOrderedApps($user);
$categoriesLabels = $this->categoryRepository->getOrderedCategories();
$hiddenApps = $this->config->getAppValueArray('big-menu-hidden-apps', '[]');
$isForced = $this->config->getAppValueBool('force', '0');
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
$topSideMenuApps = $this->config->getAppValueArray('top-side-menu-apps', '[]');
$userTopSideMenuApps = $this->config->getUserValueArray($user, 'top-side-menu-apps', '[]');
$userTopMenuApps = $this->config->getUserValueArray($user, 'top-menu-apps', '[]');
$appsCategories = [];
$categoriesAppsCount = [];
if (!$isForced && !empty($userTopMenuApps)) {
$topMenuApps = $userTopMenuApps;
}
foreach ($categoriesLabels as $k => $category) {
$categoriesLabels[$category['id']] = $category['translations'][$currentLanguage]['name'] ?? $category['translations']['en']['name'];
unset($categoriesLabels[$k]);
if (!$isForced && !empty($userTopSideMenuApps)) {
$topSideMenuApps = $userTopSideMenuApps;
}
$categoriesLabels['external_links'] = $this->l10nFactory->get('external')->t('External sites');
$items['other'] = [
'name' => '',
'apps' => [],
];
foreach ($apps as $app) {
if (in_array($app['id'], $topMenuApps)) {
$inTopMenuApps = in_array($app['id'], $topMenuApps);
$inTopSideMenuApps = in_array($app['id'], $topSideMenuApps);
$inHiddenApps = in_array($app['id'], $hiddenApps);
if (($inTopMenuApps && !$inTopSideMenuApps) || $inHiddenApps) {
continue;
}
@@ -153,6 +132,7 @@ class NavController extends Controller
if (!isset($items[$category])) {
$items[$category] = [
'name' => $categoriesLabels[$category] ?? $category,
'categoryId' => $category,
'apps' => [],
];
}
@@ -204,15 +184,29 @@ class NavController extends Controller
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;
usort($items, function ($a, $b) use ($categoriesLabels) {
foreach ($categoriesLabels as $key => $value) {
if ($a['categoryId'] === 'other') {
return -1;
}
if ($b['categoryId'] === 'other') {
return 1;
}
if ($a['categoryId'] === $key) {
return -1;
}
if ($b['categoryId'] === $key) {
return 1;
}
}
return 0;
});
return new JSONResponse([
+4 -3
View File
@@ -18,13 +18,13 @@
namespace OCA\SideMenu\Controller;
use OCA\SideMenu\AppInfo\Application;
use OCA\SideMenu\Service\ConfigProxy;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Response;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserSession;
use OCA\SideMenu\AppInfo\Application;
use OCA\SideMenu\Service\ConfigProxy;
class PersonalSettingController extends Controller
{
@@ -54,6 +54,7 @@ class PersonalSettingController extends Controller
/**
* @NoAdminRequired
* @NoCSRFRequired
*
* @param mixed $name
* @param mixed $value
@@ -96,7 +97,7 @@ class PersonalSettingController extends Controller
}
}
if ('top-menu-apps' === $name) {
if (in_array($name, ['top-menu-apps', 'top-side-menu-apps', 'apps-order'])) {
$doSave = true;
$data = json_decode($value, true);
+65 -8
View File
@@ -2,6 +2,7 @@
namespace OCA\SideMenu\Service;
use OC\User\User;
use OCP\L10N\IFactory;
/**
@@ -21,10 +22,26 @@ class AppRepository
*/
protected $l10nFactory;
public function __construct(\OC_App $ocApp, IFactory $l10nFactory)
{
/**
* @var ConfigProxy
*/
protected $config;
/**
* @var CategoryRepository
*/
protected $categoryRepository;
public function __construct(
\OC_App $ocApp,
IFactory $l10nFactory,
ConfigProxy $config,
CategoryRepository $categoryRepository
) {
$this->ocApp = $ocApp;
$this->l10nFactory = $l10nFactory;
$this->config = $config;
$this->categoryRepository = $categoryRepository;
}
/**
@@ -35,6 +52,8 @@ class AppRepository
public function getVisibleApps()
{
$navigation = $this->ocApp->getNavigation();
$appCategoriesCustom = $this->config->getAppValueArray('apps-categories-custom', '[]');
$categories = $this->categoryRepository->getOrderedCategories();
$apps = $this->ocApp->listAllApps();
$visibleApps = [];
@@ -43,7 +62,7 @@ class AppRepository
foreach ([$app['id'], $app['id'].'_index'] as $id) {
if (isset($navigation[$id])) {
$app['name'] = $this->l10nFactory->get($id)->t($app['name']);
$app['name'] = $this->getAppName($app);
$app['href'] = $navigation[$id]['href'];
$app['icon'] = $navigation[$id]['icon'];
@@ -56,7 +75,7 @@ class AppRepository
if ('external_index' === substr($app['id'], 0, 14)) {
$visibleApps[$app['id']] = [
'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']),
'name' => $this->getAppName($app),
'href' => $app['href'],
'icon' => $app['icon'],
'category' => [
@@ -66,7 +85,7 @@ class AppRepository
} elseif ('files' === $app['id']) {
$visibleApps[$app['id']] = [
'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']),
'name' => $this->getAppName($app),
'href' => $app['href'],
'icon' => $app['icon'],
'category' => [],
@@ -74,10 +93,48 @@ class AppRepository
}
}
usort($visibleApps, function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
foreach ($visibleApps as $id => $app) {
if (isset($appCategoriesCustom[$id], $categories[$appCategoriesCustom[$id]])) {
$visibleApps[$id]['category'] = [$appCategoriesCustom[$id]];
}
}
return $visibleApps;
}
public function getAppName($app)
{
return $this->config->getAppValue(
'app.navigation.name',
$this->l10nFactory->get($app['id'])->t($app['name']),
$app['id']
);
}
public function getOrderedApps(?User $user = null)
{
$apps = $this->getVisibleApps();
$orders = $this->config->getAppValueArray('apps-order', '[]');
if (null !== $user && !$this->config->getAppValueBool('force', '0')) {
$userOrders = $this->config->getUserValueArray($user, 'apps-order', '[]');
if (!empty($userOrders)) {
$orders = $userOrders;
}
}
usort($apps, function ($a, $b) use ($orders) {
$ak = array_keys($orders, $a['id'])[0] ?? null;
$bk = array_keys($orders, $b['id'])[0] ?? null;
if (null === $ak || null === $bk) {
return ($a['name'] < $b['name']) ? -1 : 1;
}
return $ak < $bk ? -1 : 1;
});
return $apps;
}
}
+119
View File
@@ -0,0 +1,119 @@
<?php
namespace OCA\SideMenu\Service;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OCA\SideMenu\AppInfo\Application;
use OCP\IConfig;
use OCP\IUserSession;
use OCP\L10N\IFactory;
/**
* class CategoryRepository.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class CategoryRepository
{
/**
* @var CategoryFetcher
*/
protected $categoryFetcher;
/**
* @var IFactory
*/
protected $l10nFactory;
/**
* @var ConfigProxy
*/
protected $config;
/**
* @var IConfig
*/
protected $iConfig;
/**
* @var IUserSession
*/
protected $userSession;
public function __construct(
CategoryFetcher $categoryFetcher,
ConfigProxy $config,
IConfig $iConfig,
IFactory $l10nFactory,
IUserSession $userSession
) {
$this->categoryFetcher = $categoryFetcher;
$this->l10nFactory = $l10nFactory;
$this->config = $config;
$this->iConfig = $iConfig;
$this->userSession = $userSession;
}
/**
* Retrieves categories.
*
* @return array
*/
public function getOrderedCategories()
{
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$type = $this->config->getAppValue('categories-order-type', 'default');
$order = $this->config->getAppValueArray('categories-order', '[]');
$categoriesLabels = $this->config->getAppValueArray('cache-categories', '[]');
$customCategories = $this->config->getAppValueArray('categories-custom', '[]');
if (empty($categoriesLabels)) {
$categoriesLabels = $this->categoryFetcher->get();
$this->iConfig->setAppValue(Application::APP_ID, 'cache-categories', json_encode($categoriesLabels));
}
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');
$categoriesLabels['other'] = '';
$user = $this->userSession->getUser();
if ($user) {
$lang = $this->iConfig->getUserValue($user->getUid(), 'core', 'lang');
} else {
$lang = 'en';
}
foreach ($customCategories as $category) {
$categoriesLabels[$category['id']] = $category[$lang] ?? $category['en'];
}
asort($categoriesLabels);
if ('custom' === $type) {
$ordered = [];
foreach ($order as $id) {
if (isset($categoriesLabels[$id])) {
$ordered[$id] = $categoriesLabels[$id];
}
}
foreach ($categoriesLabels as $id => $value) {
if (!isset($ordered[$id])) {
$ordered[$id] = $value;
}
}
$categoriesLabels = $ordered;
}
return $categoriesLabels;
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace OCA\SideMenu\Service;
/**
* class Color.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class Color
{
/**
* @thanks https://stackoverflow.com/posts/54393956/revision
*/
public function adjustBrightness(string $hexCode, float $adjustPercent): string
{
$hexCode = ltrim($hexCode, '#');
if (3 == strlen($hexCode)) {
$hexCode = $hexCode[0].$hexCode[0].$hexCode[1].$hexCode[1].$hexCode[2].$hexCode[2];
}
$hexCode = array_map('hexdec', str_split($hexCode, 2));
foreach ($hexCode as &$color) {
$adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
$adjustAmount = ceil($adjustableLimit * $adjustPercent);
$color = str_pad(dechex($color + $adjustAmount), 2, '0', STR_PAD_LEFT);
}
return '#'.implode($hexCode);
}
}
+20 -16
View File
@@ -23,43 +23,47 @@ class ConfigProxy
$this->config = $config;
}
public function getAppValue(string $name, string $default): string
public function getAppValue(string $name, string $default, $appId = null): string
{
return (string) $this->config->getAppValue(Application::APP_ID, $name, $default);
return (string) $this->config->getAppValue($appId ?? Application::APP_ID, $name, $default);
}
public function getUserValue(User $user, string $name, string $default): string
public function getUserValue(User $user, string $name, string $default, $appId = null): string
{
return (string) $this->config->getUserValue($user->getUid(), Application::APP_ID, $name, $default);
return (string) $this->config->getUserValue($user->getUid(), $appId ?? Application::APP_ID, $name, $default);
}
public function getAppValueBool(string $name, string $default): bool
public function getAppValueBool(string $name, string $default, $appId = null): bool
{
return (bool) $this->getAppValue($name, $default);
return (bool) $this->getAppValue($name, $default, $appId);
}
public function getAppValueArray(string $name, string $default): array
public function getAppValueArray(string $name, string $default, $appId = null): array
{
return (array) json_decode($this->getAppValue($name, $default), true);
return (array) json_decode($this->getAppValue($name, $default, $appId), true);
}
public function getAppValueInt(string $name, string $default): int
public function getAppValueInt(string $name, string $default, $appId = null): int
{
return (int) $this->getAppValue($name, $default);
return (int) $this->getAppValue($name, $default, $appId);
}
public function getUserValueBool(User $user, string $name, string $default): bool
public function getUserValueBool(User $user, string $name, string $default, $appId = null): bool
{
return (bool) $this->getUserValue($user, $name, $default);
return (bool) str_replace(
['yes', 'no'],
['1', '0'],
$this->getUserValue($user, $name, $default, $appId)
);
}
public function getUserValueArray(User $user, string $name, string $default): array
public function getUserValueArray(User $user, string $name, string $default, $appId = null): array
{
return (array) json_decode($this->getUserValue($user, $name, $default), true);
return (array) json_decode($this->getUserValue($user, $name, $default, $appId), true);
}
public function getUserValueInt(User $user, string $name, string $default): int
public function getUserValueInt(User $user, string $name, string $default, $appId = null): int
{
return (int) $this->getUserValue($user, $name, $default);
return (int) $this->getUserValue($user, $name, $default, $appId);
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace OCA\SideMenu\Service;
use OCP\IDBConnection;
/**
* class LangRepository.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class LangRepository
{
/**
* @var IDBConnection
*/
protected $db;
public function __construct(IDBConnection $db)
{
$this->db = $db;
}
public function getUsedLangs(): array
{
$qb = $this->db->getQueryBuilder();
$qb->select($qb->createFunction('DISTINCT configvalue'))
->where('configkey=:configkey and appid=:appid and configvalue<>:configvalue')
->setParameters([
'configkey' => 'lang',
'appid' => 'core',
'configvalue' => 'en',
])
->from('preferences')
;
$stmt = $qb->execute();
$langs = ['en'];
foreach ($stmt->fetchAll() as $result) {
$langs[] = $result['configvalue'];
}
return $langs;
}
}
+90 -9
View File
@@ -20,11 +20,15 @@ namespace OCA\SideMenu\Settings;
use OCA\SideMenu\AppInfo\Application;
use OCA\SideMenu\Service\AppRepository;
use OCA\SideMenu\Service\CategoryRepository;
use OCA\SideMenu\Service\ConfigProxy;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IL10N;
use OCP\ILogger;
use OCP\Settings\ISettings;
use OCA\Theming\ThemingDefaults;
use OCA\SideMenu\Service\Color;
use OCA\SideMenu\Service\LangRepository;
class Admin implements ISettings
{
@@ -48,12 +52,44 @@ class Admin implements ISettings
*/
private $appRepository;
public function __construct(IL10N $l, ILogger $logger, ConfigProxy $config, AppRepository $appRepository)
{
/**
* @var CategoryRepository
*/
private $categoryRepository;
/**
* @var ThemingDefaults
*/
protected $theming;
/**
* @var Color
*/
protected $color;
/**
* @var LangRepository
*/
protected $langRepository;
public function __construct(
IL10N $l,
ILogger $logger,
ConfigProxy $config,
AppRepository $appRepository,
CategoryRepository $categoryRepository,
ThemingDefaults $theming,
Color $color,
LangRepository $langRepository
) {
$this->l = $l;
$this->logger = $logger;
$this->config = $config;
$this->appRepository = $appRepository;
$this->categoryRepository = $categoryRepository;
$this->theming = $theming;
$this->color = $color;
$this->langRepository = $langRepository;
}
/**
@@ -61,34 +97,79 @@ class Admin implements ISettings
*/
public function getForm()
{
$backgroundColor = $this->config->getAppValue('background-color', '#333333');
$backgroundColorTo = $this->config->getAppValue('background-color-to', $backgroundColor);
$primaryColor = $this->theming->getColorPrimary();
$lightenPrimaryColor = $this->color->adjustBrightness($primaryColor, 0.2);
$darkenPrimaryColor = $this->color->adjustBrightness($primaryColor, -0.2);
$darkenPrimaryColor2 = $this->color->adjustBrightness($primaryColor, -0.3);
$textColor = $this->theming->getTextColorPrimary();
$backgroundColor = $this->config->getAppValue('background-color', $darkenPrimaryColor);
$backgroundColorTo = $this->config->getAppValue('background-color-to', $darkenPrimaryColor);
$darkModeBackgroundColor = $this->config->getAppValue('dark-mode-background-color', $darkenPrimaryColor);
$darkModeBackgroundColorTo = $this->config->getAppValue('dark-mode-background-color-to', $darkenPrimaryColor);
$parameters = [
'defaults' => [
'background-color' => $darkenPrimaryColor,
'background-color-to' => $darkenPrimaryColor,
'current-app-background-color' => $darkenPrimaryColor2,
'text-color' => $textColor,
'loader-color' => $lightenPrimaryColor,
'dark-mode-background-color' => $darkenPrimaryColor,
'dark-mode-background-color-to' => $darkenPrimaryColor,
'dark-mode-current-app-background-color' => $darkenPrimaryColor2,
'dark-mode-text-color' => $textColor,
'dark-mode-loader-color' => $textColor,
],
'background-color' => $backgroundColor,
'background-color-to' => $backgroundColorTo,
'current-app-background-color' => $this->config->getAppValue('current-app-background-color', '#444444'),
'loader-color' => $this->config->getAppValue('loader-color', '#0e75ac'),
'background-color-opacity' => $this->config->getAppValueInt('background-color-opacity', '100'),
'current-app-background-color' => $this->config->getAppValue('current-app-background-color', $darkenPrimaryColor2),
'loader-color' => $this->config->getAppValue('loader-color', $lightenPrimaryColor),
'icon-invert-filter' => $this->config->getAppValueInt('icon-invert-filter', '0'),
'icon-opacity' => $this->config->getAppValueInt('icon-opacity', '100'),
'loader-enabled' => $this->config->getAppValue('loader-enabled', '1'),
'text-color' => $this->config->getAppValue('text-color', '#FFFFFF'),
'cache' => $this->config->getAppValue('cache', '0'),
'text-color' => $this->config->getAppValue('text-color', $textColor),
'dark-mode-background-color' => $darkModeBackgroundColor,
'dark-mode-background-color-to' => $darkModeBackgroundColorTo,
'dark-mode-background-color-opacity' => $this->config->getAppValueInt('dark-mode-background-color-opacity', '100'),
'dark-mode-current-app-background-color' => $this->config->getAppValue('dark-mode-current-app-background-color', $darkenPrimaryColor2),
'dark-mode-loader-color' => $this->config->getAppValue('dark-mode-loader-color', $textColor),
'dark-mode-icon-invert-filter' => $this->config->getAppValueInt('dark-mode-icon-invert-filter', '0'),
'dark-mode-icon-opacity' => $this->config->getAppValueInt('dark-mode-icon-opacity', '100'),
'dark-mode-text-color' => $this->config->getAppValue('dark-mode-text-color', $textColor),
'dark-mode-opener' => $this->config->getAppValue('dark-mode-opener', 'side-menu-opener'),
'opener' => $this->config->getAppValue('opener', 'side-menu-opener'),
'loader-enabled' => $this->config->getAppValue('loader-enabled', '1'),
'cache' => $this->config->getAppValue('cache', '0'),
'always-displayed' => $this->config->getAppValue('always-displayed', '0'),
'big-menu' => $this->config->getAppValue('big-menu', '0'),
'side-with-categories' => $this->config->getAppValue('side-with-categories', '0'),
'big-menu-hidden-apps' => $this->config->getAppValueArray('big-menu-hidden-apps', '[]'),
'display-logo' => $this->config->getAppValue('display-logo', '1'),
'add-logo-link' => $this->config->getAppValue('add-logo-link', '1'),
'use-avatar' => $this->config->getAppValue('use-avatar', '0'),
'opener-position' => $this->config->getAppValue('opener-position', 'before'),
'opener-hover' => $this->config->getAppValue('opener-hover', '0'),
'opener-only' => $this->config->getAppValue('opener-only', '0'),
'show-settings' => $this->config->getAppValue('show-settings', '0'),
'hide-when-no-apps' => $this->config->getAppValue('hide-when-no-apps', '0'),
'size-icon' => $this->config->getAppValue('size-icon', 'normal'),
'size-text' => $this->config->getAppValue('size-text', 'normal'),
'force' => $this->config->getAppValue('force', '0'),
'target-blank-apps' => $this->config->getAppValueArray('target-blank-apps', '[]'),
'top-menu-apps' => $this->config->getAppValueArray('top-menu-apps', '[]'),
'apps-order' => $this->config->getAppValueArray('apps-order', '[]'),
'ordered-apps' => $this->appRepository->getOrderedApps(),
'top-side-menu-apps' => $this->config->getAppValueArray('top-side-menu-apps', '[]'),
'default-enabled' => $this->config->getAppValue('default-enabled', '1'),
'apps' => $this->appRepository->getVisibleApps(),
'apps-categories-custom' => $this->config->getAppValueArray('apps-categories-custom', '[]'),
'categories-order-type' => $this->config->getAppValue('categories-order-type', 'default'),
'categories-order' => $this->config->getAppValueArray('categories-order', '[]'),
'categories-custom' => $this->config->getAppValueArray('categories-custom', '[]'),
'categories' => $this->categoryRepository->getOrderedCategories(),
'langs' => $this->langRepository->getUsedLangs(),
];
return new TemplateResponse(Application::APP_ID, 'settings/admin-form', $parameters, '');
+4 -8
View File
@@ -18,10 +18,10 @@
namespace OCA\SideMenu\Settings;
use OCA\SideMenu\AppInfo\Application;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
use OCA\SideMenu\AppInfo\Application;
class AdminSection implements IIconSection
{
@@ -35,10 +35,6 @@ class AdminSection implements IIconSection
*/
private $url;
/**
* @param IURLGenerator $url
* @param IL10N $l
*/
public function __construct(IURLGenerator $url, IL10N $l)
{
$this->url = $url;
@@ -47,7 +43,7 @@ class AdminSection implements IIconSection
/**
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
* e.g. 'ldap'.
*
* @returns string
*/
@@ -69,8 +65,8 @@ class AdminSection implements IIconSection
/**
* @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.
* 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
*/
+8 -1
View File
@@ -72,11 +72,18 @@ class Personal implements ISettings
$parameters = [
'force' => $this->config->getAppValueBool('force', '0'),
'enabled' => $this->config->getUserValue($user, 'enabled', '1'),
'enabled' => $this->config->getUserValue(
$user,
'enabled',
$this->config->getAppValue('default-enabled', '1')
),
'top-menu-apps' => $this->config->getUserValueArray($user, 'top-menu-apps', '[]'),
'top-side-menu-apps' => $this->config->getUserValueArray($user, 'top-side-menu-apps', '[]'),
'target-blank-mode' => $this->config->getUserValue($user, 'target-blank-mode', '1'),
'target-blank-apps' => $this->config->getUserValueArray($user, 'target-blank-apps', '[]'),
'apps-order' => $this->config->getUserValueArray($user, 'apps-order', '[]'),
'apps' => $this->appRepository->getVisibleApps(),
'ordered-apps' => $this->appRepository->getOrderedApps($user),
];
return new TemplateResponse(Application::APP_ID, 'settings/personal-form', $parameters, '');
+22 -7
View File
@@ -18,10 +18,11 @@
namespace OCA\SideMenu\Settings;
use OCA\SideMenu\AppInfo\Application;
use OCA\SideMenu\Service\ConfigProxy;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
use OCA\SideMenu\AppInfo\Application;
class PersonalSection implements IIconSection
{
@@ -36,23 +37,29 @@ class PersonalSection implements IIconSection
private $url;
/**
* @param IURLGenerator $url
* @param IL10N $l
* @var ConfigProxy
*/
public function __construct(IURLGenerator $url, IL10N $l)
private $configProxy;
public function __construct(IURLGenerator $url, IL10N $l, ConfigProxy $configProxy)
{
$this->url = $url;
$this->l = $l;
$this->configProxy = $configProxy;
}
/**
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
* e.g. 'ldap'.
*
* @returns string
*/
public function getID()
{
if ($this->configProxy->getAppValueBool('force', '0')) {
return '';
}
return Application::APP_ID;
}
@@ -64,18 +71,26 @@ class PersonalSection implements IIconSection
*/
public function getName()
{
if ($this->configProxy->getAppValueBool('force', '0')) {
return '';
}
return $this->l->t(Application::APP_NAME);
}
/**
* @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.
* 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()
{
if ($this->configProxy->getAppValueBool('force', '0')) {
return null;
}
return 70;
}
+31 -28
View File
@@ -2,58 +2,61 @@
"license": "agpl",
"private": true,
"scripts": {
"build": "NODE_ENV=production webpack --progress --hide-modules --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"stylelint": "stylelint src",
"stylelint:fix": "stylelint src --fix"
"build": "NODE_ENV=production ./node_modules/.bin/webpack-cli --progress --config webpack.js",
"dev": "NODE_ENV=development ./node_modules/.bin/webpack-cli --progress --config webpack.js",
"watch": "NODE_ENV=development ./node_modules/.bin/webpack-cli --progress --watch --config webpack.js",
"lint": "./node_modules/.bin/eslint --ext .js,.vue src",
"lint:fix": "./node_modules/.bin/eslint --ext .js,.vue src --fix",
"stylelint": "./node_modules/.bin/stylelint src",
"stylelint:fix": "./node_modules/.bin/stylelint src --fix"
},
"dependencies": {
"@nextcloud/axios": "^1.3.2",
"@nextcloud/vue": "^1.4.0",
"axios": "^0.19.2",
"trim": "0.0.1",
"axios": "^0.24.0",
"trim": "^1.0.1",
"vue": "^2.6.11"
},
"browserslist": [
"extends @nextcloud/browserslist-config"
],
"engines": {
"node": ">=10.0.0"
"node": ">=16.0.0"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.0",
"@nextcloud/axios": "^1.8.0",
"@nextcloud/browserslist-config": "^1.0.0",
"@nextcloud/eslint-config": "^8.1.2",
"@nextcloud/initial-state": "^2.0.0",
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/vue": "^7.0.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"css-loader": "^3.4.2",
"eslint": "^5.16.0",
"eslint-config-nextcloud": "0.1.1",
"eslint-config-standard": "^12.0.0",
"eslint": "^8.0.0",
"eslint-config-standard": "^17.0.0",
"eslint-import-resolver-webpack": "^0.12.1",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-nextcloud": "^0.3.0",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^5.2.3",
"eslint-plugin-vue": "^9.0.0",
"eslint-webpack-plugin": "^3.0.0",
"file-loader": "^6.0.0",
"node-sass": "^4.13.1",
"sass-loader": "^8.0.2",
"stylelint": "^8.4.0",
"stylelint-config-recommended-scss": "^3.3.0",
"stylelint-scss": "^3.16.0",
"stylelint-webpack-plugin": "^0.10.5",
"sass": "^1.49.9",
"sass-loader": "^13.0.2",
"stylelint": "^14.0.0",
"stylelint-config-recommended-scss": "^7.0.0",
"stylelint-scss": "^4.0.0",
"stylelint-webpack-plugin": "^3.3.0",
"url-loader": "^4.0.0",
"vue-loader": "^15.9.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"vue-loader": "^15",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.7.13",
"webpack": "^5.0.0",
"webpack-cli": "^4.0.0",
"webpack-merge": "^4.2.2",
"webpack-node-externals": "^1.7.2"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 79 KiB

+181
View File
@@ -0,0 +1,181 @@
<!--
@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>
<ul class="side-menu-setting-list" :class="{hide: values.length === 0}">
<li v-for="item in values" class="side-menu-setting-list-item" v-on:click="showEditForm(item)">
<span v-text="item.en"></span>
</li>
</ul>
<NcActions>
<NcActionButton @click="showAddForm" icon="icon-add"></NcActionButton>
</NcActions>
<NcModal v-if="addForm" @close="hideAddForm">
<div class="modal__content">
<div v-for="lang in langs">
<span class="lang" v-text="lang"></span>
<input type="text" v-model="newValue[lang]" required style="width: calc(100% - 100px)">
</div>
<NcActions>
<NcActionButton @click="saveAdd" icon="icon-checkmark"></NcActionButton>
</NcActions>
</div>
</NcModal>
<NcModal v-if="editForm" @close="hideEditForm">
<div class="modal__content">
<div v-for="lang in langs">
<span class="lang" v-text="lang"></span>
<input type="text" v-model="editValue[lang]" required style="width: calc(100% - 100px)">
</div>
<div class="pull-right">
<NcActions>
<NcActionButton @click="removeEdit" icon="icon-delete"></NcActionButton>
</NcActions>
</div>
<NcActions>
<NcActionButton @click="saveEdit" icon="icon-checkmark"></NcActionButton>
</NcActions>
</div>
</NcModal>
</div>
</template>
<style>
.modal__content {
padding: 10px;
}
.modal__content .lang {
width: 60px;
display: inline-block;
padding: 4px;
box-sizing: border-box;
}
.pull-right {
float: right;
}
</style>
<style scoped>
.hide {
display: none;
}
</style>
<script>
import NcModal from '@nextcloud/vue/dist/Components/NcModal'
import NcActions from '@nextcloud/vue/dist/Components/NcActions'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton'
export default {
name: 'AdminCategoriesCustom',
components: {
NcModal,
NcActions,
NcActionButton,
},
data() {
return {
input: null,
values: [],
langs: [],
addForm: false,
editForm: false,
newValue: {},
editValue: {},
}
},
methods: {
init() {
this.values = JSON.parse(this.input.value)
this.langs = JSON.parse(this.input.getAttribute('data-langs'))
},
update() {
this.input.value = JSON.stringify(this.values)
},
showAddForm() {
this.newValue = {id: 'cat' + Math.random().toString().replace('0.', '')}
this.addForm = true
},
showEditForm(value) {
this.editValue = {id: value.id}
for (let i of this.langs) {
this.editValue[i] = typeof value[i] !== 'undefined' ? value[i] : ''
}
this.editForm = true
},
saveAdd() {
for (let i of this.langs) {
if (!this.newValue[i] || /^\s*$/.test(this.newValue[i])) {
return
}
}
this.values.push(this.newValue)
this.update()
this.hideAddForm()
this.newValue = {}
},
saveEdit() {
for (let i of this.langs) {
if (!this.editValue[i] || /^\s*$/.test(this.editValue[i])) {
return
}
}
for (let i in this.values) {
if (this.values[i].id === this.editValue.id) {
this.values[i] = this.editValue
}
}
this.update()
this.hideEditForm()
},
removeEdit() {
for (let i in this.values) {
if (this.values[i].id === this.editValue.id) {
this.values.splice(i, 1);
}
}
this.update()
this.hideEditForm()
},
hideAddForm() {
this.addForm = false
},
hideEditForm() {
this.editForm = false
},
},
mounted() {
this.input = document.querySelector('input[name="categories-custom"]')
this.init()
}
}
</script>
+312
View File
@@ -0,0 +1,312 @@
<!--
- @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
-
- @author Julius Härtl <jus@bitgrid.net>
-
- @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>
<nav class="app-menu show">
<ul class="app-menu-main" v-if="apps !== null">
<li v-for="app in mainAppList()"
:key="app.id"
:data-app-id="app.id"
class="app-menu-entry"
:class="{ 'app-menu-entry__active': app.active }"
:style="makeStyle(app)"
>
<a :href="app.href"
:class="{ 'has-unread': app.unread > 0 }"
:aria-label="appLabel(app)"
:target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined"
:aria-current="app.active ? 'page' : false">
<img :src="app.icon" alt="">
<div class="app-menu-entry--label">
{{ app.name }}
<span v-if="app.unread > 0" class="hidden-visually unread-counter">{{ app.unread }}</span>
</div>
</a>
</li>
</ul>
<NcActions class="app-menu-more" :aria-label="t('core', 'More apps')" v-if="apps !== null">
<NcActionLink v-for="app in popoverAppList()"
:key="app.id"
:aria-label="appLabel(app)"
:aria-current="app.active ? 'page' : false"
:href="app.href"
class="app-menu-popover-entry">
<template #icon>
<div class="app-icon" :class="{ 'has-unread': app.unread > 0 }">
<img :src="app.icon" alt="">
</div>
</template>
{{ app.name }}
<span v-if="app.unread > 0" class="hidden-visually unread-counter">{{ app.unread }}</span>
</NcActionLink>
</NcActions>
</nav>
</template>
<script>
import { loadState } from '@nextcloud/initial-state'
import { NcActions, NcActionLink } from '@nextcloud/vue'
export default {
name: 'AppMenu',
components: {
NcActions, NcActionLink,
},
data() {
return {
apps: null,
appLimit: 0,
observer: null,
targetBlankApps: [],
}
},
mounted() {
const ncApps = loadState('core', 'apps', {})
this.apps = {}
let orders = {}
window.menuAppsOrder.forEach((app, order) => {
orders[app] = order + 1
})
Array.from(window.topMenuApps).forEach((id) => {
if (ncApps.hasOwnProperty(id)) {
this.apps[id] = ncApps[id]
this.apps[id].order = orders[id] || null
}
})
this.targetBlankApps = window.targetBlankApps
this.observer = new ResizeObserver(this.resize)
this.observer.observe(this.$el)
this.resize()
},
beforeDestroy() {
this.observer.disconnect()
},
methods: {
appLabel() {
return (app) => app.name
+ (app.active ? ' (' + t('core', 'Currently open') + ')' : '')
+ (app.unread > 0 ? ' (' + n('core', '{count} notification', '{count} notifications', app.unread, { count: app.unread }) + ')' : '')
},
appList() {
return Object.values(this.apps)
},
mainAppList() {
return this.appList().slice(0, this.appLimit)
},
popoverAppList() {
return this.appList().slice(this.appLimit)
},
setNavigationCounter(id, counter) {
this.$set(this.apps[id], 'unread', counter)
},
resize() {
const availableWidth = this.$el.offsetWidth
let appCount = Math.floor(availableWidth / 50) - 1
const popoverAppCount = this.appList.length - appCount
if (popoverAppCount === 1) {
appCount--
}
if (appCount < 1) {
appCount = 0
}
this.appLimit = appCount
},
makeStyle(app) {
if (app.order !== null) {
return `order: ${app.order}`
}
}
},
}
</script>
<style lang="scss" scoped>
$header-icon-size: 20px;
.app-menu {
width: 100%;
display: flex;
flex-shrink: 1;
flex-wrap: wrap;
}
.app-menu-main {
display: flex;
flex-wrap: nowrap;
.app-menu-entry {
width: 50px;
height: 50px;
position: relative;
display: flex;
opacity: .7;
&.app-menu-entry__active {
opacity: 1;
&::before {
content: " ";
position: absolute;
pointer-events: none;
border-bottom-color: var(--color-main-background);
transform: translateX(-50%);
width: 12px;
height: 5px;
border-radius: 3px;
background-color: var(--color-primary-text);
left: 50%;
bottom: 6px;
display: block;
transition: all 0.1s ease-in-out;
opacity: 1;
}
.app-menu-entry--label {
font-weight: bold;
}
}
a {
width: calc(100% - 4px);
height: calc(100% - 4px);
margin: 2px;
color: var(--color-primary-text);
position: relative;
}
img {
transition: margin 0.1s ease-in-out;
width: $header-icon-size;
height: $header-icon-size;
padding: calc((100% - $header-icon-size) / 2);
filter: var(--primary-invert-if-bright);
}
.app-menu-entry--label {
opacity: 0;
position: absolute;
font-size: 12px;
color: var(--color-primary-text);
text-align: center;
bottom: -5px;
left: 50%;
display: block;
min-width: 100%;
transform: translateX(-50%);
transition: all 0.1s ease-in-out;
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
}
&:hover,
&:focus-within {
opacity: 1;
.app-menu-entry--label {
opacity: 1;
font-weight: bold;
font-size: 14px;
bottom: 0;
width: auto;
overflow: visible;
}
}
}
// Show labels
&:hover,
&:focus-within,
.app-menu-entry:hover,
.app-menu-entry:focus {
opacity: 1;
img {
margin-top: -6px;
}
.app-menu-entry--label {
opacity: 1;
bottom: 0;
}
&::before, .app-menu-entry::before {
opacity: 0;
}
}
}
::v-deep .app-menu-more .button-vue--vue-tertiary {
color: var(--color-primary-text);
opacity: .7;
margin: 3px;
&:hover {
opacity: 1;
background-color: transparent !important;
}
&:focus-visible {
opacity: 1;
background-color: transparent !important;
border-radius: var(--border-radius);
outline: none;
box-shadow: 0 0 0 2px var(--color-primary-text);
}
}
.app-menu-popover-entry {
.app-icon {
position: relative;
height: 44px;
&.has-unread::after {
background-color: var(--color-main-text);
}
img {
filter: var(--background-invert-if-bright);
width: $header-icon-size;
height: $header-icon-size;
padding: calc((50px - $header-icon-size) / 2);
}
}
}
.has-unread::after {
content: "";
width: 8px;
height: 8px;
background-color: var(--color-primary-text);
border-radius: 50%;
position: absolute;
display: block;
top: 10px;
right: 10px;
}
.unread-counter {
display: none;
}
</style>
+25
View File
@@ -0,0 +1,25 @@
<!--
@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>
<button class="side-menu-opener side-menu-closer"></button>
</template>
<script>
export default {
name: 'CloserButton',
}
</script>
+42
View File
@@ -0,0 +1,42 @@
<!--
@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 class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
</template>
<script>
export default {
name: 'Loader',
}
</script>
+44
View File
@@ -0,0 +1,44 @@
<!--
@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 v-bind:class="classes">
<a v-if="link !== null" v-bind:href="link">
<img v-bind:src="image" alt="Logo">
</a>
<img v-else v-bind:src="image" alt="Logo">
</div>
</template>
<script>
export default {
name: 'Logo',
props: {
image: {
type: String,
required: true
},
link: {
type: String,
required: false
},
classes: {
type: Object,
required: true
},
},
}
</script>
+25
View File
@@ -0,0 +1,25 @@
<!--
@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>
<button class="side-menu-opener"></button>
</template>
<script>
export default {
name: 'OpenerButton',
}
</script>
+20
View File
@@ -0,0 +1,20 @@
const createElement = require('./lib/createElement')
const PageLoader = () => {
const pageLoader = createElement('div', {id: 'side-menu-loader'})
const pageLoaderBar = createElement('div', {id: 'side-menu-loader-bar'})
pageLoader.appendChild(pageLoaderBar)
document.querySelector('body').appendChild(pageLoader)
let pageLoaderValue = 0
window.addEventListener('beforeunload', () => {
setInterval(() => {
pageLoaderBar.style.width = pageLoaderValue.toString() + '%'
pageLoaderValue = Math.min(pageLoaderValue + .2, 100)
}, 25)
})
}
module.exports = PageLoader
+47
View File
@@ -0,0 +1,47 @@
<!--
@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 class="side-menu-settings">
<a v-bind:href="href">
{{ label }}
<span class="avatardiv avatardiv-shown">
<img v-bind:src="avatar">
</span>
</a>
</div>
</template>
<script>
export default {
name: 'SettingsButton',
props: {
label: {
type: String,
required: true
},
href: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
},
}
</script>
+39 -18
View File
@@ -16,35 +16,56 @@
*/
import Vue from 'vue'
import AppMenu from './AppMenu.vue'
import SideMenu from './SideMenu.vue'
import SideMenuBig from './SideMenuBig.vue'
import SideMenuWithCategories from './SideMenuWithCategories.vue'
import PageLoader from './PageLoader'
import SMcreateElement from './lib/createElement'
// Vue.prototype.t = t
Vue.prototype.OC = OC
// Vue.prototype.OC = OCP
Vue.prototype.t = OC.L10N.translate
window.SMcreateElement = SMcreateElement
window.PageLoader = PageLoader
const mountSideMenuComponent = () => {
const sideMenuContainer = document.querySelector('#side-menu')
const container = document.querySelector('#side-menu')
if (sideMenuContainer) {
let component
if (!container) {
return window.setTimeout(mountSideMenuComponent, 50)
}
if (sideMenuContainer.getAttribute('data-bigmenu')) {
component = SideMenuBig
} else {
component = SideMenu
}
const View = Vue.extend(component)
const sideMenu = new View({})
sideMenu.$mount('#side-menu')
$('body').trigger('side-menu.ready')
const component = (() => {
if (container.getAttribute('data-bigmenu')) {
return SideMenuBig
} else if(container.getAttribute('data-sidewithcategories')) {
return SideMenuWithCategories
} else {
window.setTimeout(mountSideMenuComponent, 50)
return SideMenu
}
})()
const View = Vue.extend(component)
const App = new View({})
App.$mount('#side-menu')
document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.ready'))
}
const mountAppMenu = () => {
const container = document.querySelector('#header .app-menu')
if (!container) {
return window.setTimeout(mountAppMenu, 50)
}
const View = Vue.extend(AppMenu)
const App = new View({})
App.$mount('#header .app-menu')
}
mountSideMenuComponent()
mountAppMenu()
+109 -109
View File
@@ -15,125 +15,125 @@ 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">
<div class="side-menu-header">
<button class="side-menu-opener"></button>
<div id="side-menu">
<div class="side-menu-header">
<SettingsButton
v-if="settings"
v-bind:href="settings.href"
v-bind:label="settings.name"
v-bind:avatar="settings.avatar" />
<div v-if="!avatar && logo" v-bind:class="{'side-menu-logo': true, 'avatardiv': false}">
<img v-bind:src="logo">
</div>
<div v-if="avatar" v-bind:class="{'side-menu-logo': true, 'avatardiv': true}">
<img v-bind:src="avatar">
</div>
</div>
<OpenerButton />
<ul class="side-menu-apps-list">
<li v-for="app in apps" v-bind:class="{'side-menu-app': true, 'active': app.active}">
<a v-bind:href="app.href" :target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined" v-bind:title="app.name">
<span class="side-menu-app-icon" v-html="app.icon"></span>
<span class="side-menu-app-text" v-html="app.name"></span>
</a>
</li>
</ul>
<Logo
v-if="!avatar && logo" v-bind:classes="{'side-menu-logo': true, 'avatardiv': false}"
v-bind:image="logo"
v-bind:link="logoLink"
/>
<Logo
v-if="avatar" v-bind:classes="{'side-menu-logo': true, 'avatardiv': true}"
v-bind:image="avatar"
v-bind:link="logoLink"
/>
</div>
<ul class="side-menu-apps-list">
<SideMenuApp
v-for="(app, key) in apps"
v-bind:classes="{'side-menu-app': true, 'active': app.active}"
v-bind:key="key"
v-bind:icon="app.icon"
v-bind:label="app.name"
v-bind:href="app.href"
v-bind:target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined"
/>
</ul>
</div>
</template>
<script>
import trim from 'trim'
import axios from 'axios'
import OpenerButton from './OpenerButton'
import SettingsButton from './SettingsButton'
import SideMenuApp from './SideMenuApp'
import Logo from './Logo'
import { loadState } from '@nextcloud/initial-state'
export default {
name: 'SideMenu',
data() {
return {
apps: [],
logo: null,
avatar: null,
forceLightIcon: false,
targetBlankApps: [],
}
},
methods: {
retrieveApps() {
this.apps = []
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) {
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 !== '#') {
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({
id: dataId,
href: href,
name: trim(element.querySelector('span').innerHTML),
icon: svg,
active: element.classList.contains('active')
});
}
}
(function(apps) {
window.setTimeout(function() {
jQuery('body').trigger('side-menu.apps', [apps])
}, 1000)
})(this.apps)
},
retrieveConfig() {
let that = this
axios
.get(OC.generateUrl('/apps/side_menu/js/config'))
.then(function(response) {
const config = response.data
that.targetBlankApps = config['target-blank-apps']
that.forceLightIcon = config['force-light-icon']
that.avatar = config['avatar']
that.logo = config['logo']
});
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
const menu = document.querySelector('#appmenu')
if (menu) {
const config = {attributes: true, childList: true, subtree: true}
const observer = new MutationObserver(this.retrieveApps)
observer.observe(menu, config)
}
name: 'SideMenu',
components: {
SettingsButton,
OpenerButton,
SideMenuApp,
Logo,
},
data() {
return {
apps: [],
logo: null,
logoLink: null,
avatar: null,
forceLightIcon: false,
targetBlankApps: [],
settings: null,
}
},
methods: {
retrieveApps() {
const ncApps = loadState('core', 'apps', {})
let orders = {}
let finalApps = []
window.menuAppsOrder.forEach((app, order) => {
orders[app] = order + 1
})
for (let id in ncApps) {
if (window.topMenuApps.includes(id) && !window.topSideMenuApps.includes(id)) {
continue;
}
let app = ncApps[id]
app.order = orders[id] || null
finalApps.push(app)
}
finalApps.sort((a, b) => {
if (a.order === null || b.order === null) {
return a.name < b.name ? -1 : 1;
}
return a.order < b.order ? -1 : 1;
})
this.apps = finalApps
document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.apps', {
detail: {apps: this.apps},
}))
},
retrieveConfig() {
axios
.get(OC.generateUrl('/apps/side_menu/js/config'))
.then((response) => {
const config = response.data
this.targetBlankApps = config['target-blank-apps']
this.forceLightIcon = config['force-light-icon']
this.avatar = config['avatar']
this.logo = config['logo']
this.logoLink = config['logo-link']
this.settings = config['settings']
})
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
}
}
</script>
+52
View File
@@ -0,0 +1,52 @@
<!--
@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>
<li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label">
<img class="side-menu-app-icon" v-bind:src="icon" v-bind:alt="label" />
<span class="side-menu-app-text" v-text="label"></span>
</a>
</li>
</template>
<script>
export default {
name: 'SideMenuApp',
props: {
label: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
}
</script>
+101 -92
View File
@@ -15,107 +15,116 @@ 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 id="side-menu" class="side-menu-big">
<div class="side-menu-header">
<CloserButton />
<div class="side-menu-categories-wrapper">
<div class="side-menu-categories">
<div v-if="!items.length" class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
<SettingsButton
v-if="settings"
v-bind:href="settings.href"
v-bind:label="settings.name"
v-bind:avatar="settings.avatar"
/>
<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" :target="targetBlankApps.indexOf(appId) !== -1 ? '_blank' : undefined" 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>
<OpenerButton />
</div>
<div class="side-menu-categories-wrapper">
<div class="side-menu-categories">
<Loader v-if="!items.length" />
<div class="side-menu-category" v-for="(category, key) in items" v-bind:key="key">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-text="category.name"></h2>
<ul class="side-menu-apps-list">
<SideMenuBigApp
v-for="(app, appId) in category.apps"
v-bind:key="appId"
v-bind:classes="{'side-menu-app': true, 'active': activeApp === appId}"
v-bind:icon="app.icon"
v-bind:label="app.name"
v-bind:href="app.href"
v-bind:target="targetBlankApps.indexOf(appId) !== -1 ? '_blank' : undefined"
/>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import trim from 'trim'
import axios from 'axios'
import OpenerButton from './OpenerButton'
import CloserButton from './CloserButton'
import SettingsButton from './SettingsButton'
import Loader from './Loader'
import SideMenuBigApp from './SideMenuBigApp'
import { loadState } from '@nextcloud/initial-state'
export default {
name: 'SideMenuBig',
data() {
return {
items: [],
activeApp: null,
targetBlank: false,
targetBlankApps: [],
}
},
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
},
retrieveConfig() {
let that = this
axios
.get(OC.generateUrl('/apps/side_menu/js/config'))
.then(function(response) {
const config = response.data
that.targetBlankApps = config['target-blank-apps']
});
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
this.retrieveActiveApp()
name: 'SideMenuBig',
components: {
SettingsButton,
OpenerButton,
CloserButton,
Loader,
SideMenuBigApp,
},
data() {
return {
items: [],
activeApp: null,
targetBlank: false,
targetBlankApps: [],
settings: null,
}
},
methods: {
retrieveApps() {
axios
.get(OC.generateUrl('/apps/side_menu/nav/items'))
.then((response) => {
this.items = response.data.items
let apps = []
for (let category of this.items) {
for (let a in category.apps) {
apps.push(category.apps[a])
}
}
document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.apps', {
detail: {apps: apps},
}))
})
},
retrieveActiveApp() {
const ncApps = loadState('core', 'apps', {})
for (let id in ncApps) {
if (ncApps[id].active) {
this.activeApp = id
}
}
},
retrieveConfig() {
axios
.get(OC.generateUrl('/apps/side_menu/js/config'))
.then((response) => {
const config = response.data
this.targetBlankApps = config['target-blank-apps']
this.settings = config['settings']
})
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
this.retrieveActiveApp()
}
}
</script>
+52
View File
@@ -0,0 +1,52 @@
<!--
@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>
<li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label">
<img class="side-menu-app-icon" v-bind:src="icon" v-bind:alt="label" />
<span class="side-menu-app-text" v-text="label"></span>
</a>
</li>
</template>
<script>
export default {
name: 'SideMenuBigApp',
props: {
label: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
}
</script>
+126
View File
@@ -0,0 +1,126 @@
<!--
@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-with-categories">
<div class="side-menu-header">
<SettingsButton
v-if="settings"
v-bind:href="settings.href"
v-bind:label="settings.name"
v-bind:avatar="settings.avatar"
/>
<OpenerButton />
</div>
<div class="side-menu-categories-wrapper">
<div class="side-menu-categories">
<Loader v-if="!items.length" />
<div class="side-menu-category" v-for="(category, key) in items" v-bind:key="key">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-text="category.name"></h2>
<ul class="side-menu-apps-list">
<SideMenuBigApp
v-for="(app, appId) in category.apps"
v-bind:key="appId"
v-bind:classes="{'side-menu-app': true, 'active': activeApp === appId}"
v-bind:icon="app.icon"
v-bind:label="app.name"
v-bind:href="app.href"
v-bind:target="targetBlankApps.indexOf(appId) !== -1 ? '_blank' : undefined"
/>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import OpenerButton from './OpenerButton'
import SettingsButton from './SettingsButton'
import Loader from './Loader'
import SideMenuBigApp from './SideMenuBigApp'
import { loadState } from '@nextcloud/initial-state'
export default {
name: 'SideMenuWithCategories',
components: {
SettingsButton,
OpenerButton,
Loader,
SideMenuBigApp,
},
data() {
return {
items: [],
activeApp: null,
targetBlank: false,
targetBlankApps: [],
settings: null,
}
},
methods: {
retrieveApps() {
axios
.get(OC.generateUrl('/apps/side_menu/nav/items'))
.then((response) => {
this.items = response.data.items
let apps = []
for (let category of this.items) {
for (let a in category.apps) {
apps.push(category.apps[a])
}
}
document.querySelector('body').dispatchEvent(new CustomEvent('side-menu.apps', {
detail: {apps: apps},
}))
})
},
retrieveActiveApp() {
const ncApps = loadState('core', 'apps', {})
for (let id in ncApps) {
if (ncApps[id].active) {
this.activeApp = id
}
}
},
retrieveConfig() {
axios
.get(OC.generateUrl('/apps/side_menu/js/config'))
.then((response) => {
const config = response.data
this.targetBlankApps = config['target-blank-apps']
this.settings = config['settings']
})
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
this.retrieveActiveApp()
}
}
</script>
+228 -78
View File
@@ -15,118 +15,268 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import AdminCategoriesCustom from './AdminCategoriesCustom.vue'
import Vue from 'vue'
Vue.prototype.OC = window.OC
Vue.prototype.OCA = window.OCA
let elements = []
const selector = '#side-menu-message';
const selector = '#side-menu-message'
const userConfig = (name, value, callbacks) => {
const url = OC.generateUrl('/apps/side_menu/personalSetting/valueSet')
const url = OC.generateUrl('/apps/side_menu/personalSetting/valueSet')
const formData = []
$.post(url, {name: name, value: value}, callbacks.success)
.fail(callbacks.error)
formData.push('name=' + encodeURIComponent(name))
formData.push('value=' + encodeURIComponent(value))
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData.join('&')
})
.then(callbacks.success)
.catch(callbacks.error)
}
const appConfig = (name, value, callbacks) => {
OCP.AppConfig.setValue('side_menu', name, value, callbacks)
OCP.AppConfig.setValue('side_menu', name, value, callbacks)
}
const saveSettings = (key) => {
const element = elements.get(key)
let value
let name
const element = elements[key]
if (jQuery(element).is('[data-checkbox]')) {
name = jQuery(element).attr('data-name')
const inputs = jQuery('input[name="' + name + '[]"]:checked')
value = []
if (!element) {
return
}
inputs.each((i, v) => {
value.push(v.value)
})
let value
let name
value = JSON.stringify(value)
} else {
name = jQuery(element).attr('name')
value = jQuery(element).val()
if (element.hasAttribute('data-checkbox')) {
name = element.getAttribute('data-name')
value = []
const inputs = document.querySelectorAll('input[name="' + name + '[]"]:checked')
for (let input of inputs) {
value.push(input.value)
}
const size = elements.length
value = JSON.stringify(value)
} else {
name = element.getAttribute('name')
value = element.value
}
if (name === 'cache') {
++value
const size = elements.length
if (name === 'cache') {
++value
}
const progress = document.querySelector('#side-menu-save-progress')
progress.style.width = '40px';
progress.style.marginLeft = '5px';
const callbacks = {
success: () => {
const percent = parseInt((key + 1) * 100 / size);
progress.setAttribute('value', percent)
if (key < size - 1) {
saveSettings(key + 1)
} else {
location.reload()
}
},
error: () => {
OC.msg.finishedError(selector, t('side_menu', 'Error while saving "' + element + '"'))
}
}
const callbacks = {
success: () => {
OC.msg.finishedSuccess(
selector,
t('side_menu', (key + 1) + '/' + size)
)
if (key < size - 1) {
saveSettings(++key)
} else {
OC.msg.finishedSuccess(selector, t('side_menu', 'Saved'))
}
},
error: () => {
OC.msg.finishedError(selector, t('side_menu', 'Error while saving "' + element + '"'))
}
}
if (jQuery(element).is('[data-personal]')) {
userConfig(name, value, callbacks)
} else {
appConfig(name, value, callbacks)
}
if (element.hasAttribute('data-personal')) {
userConfig(name, value, callbacks)
} else {
appConfig(name, value, callbacks)
}
}
const elementToggler = (element) => {
jQuery(element).toggle()
let display = 'none'
if (window.getComputedStyle(element).display === 'none') {
display = 'block'
}
element.style.display = display
}
jQuery(document).ready(() => {
elements = jQuery('.side-menu-setting')
const updateAppsCategoriesCustom = () => {
let values = {}
jQuery('#side-menu-save').on('click', (event) => {
event.preventDefault()
OC.msg.startSaving(selector)
for (let item of document.querySelectorAll('.apps-categories-custom')) {
let app = item.getAttribute('data-app')
let value = item.value
saveSettings(0)
});
if (value) {
values[app] = value
}
}
jQuery('.side-menu-display').on('click', (event) => {
var target = jQuery(event.target)
document.querySelector('#apps-categories-custom').value = JSON.stringify(values)
}
jQuery('.side-menu-display').removeClass('is-active')
target.addClass('is-active')
document.addEventListener('DOMContentLoaded', () => {
$('*[data-toggle="tooltip"]').tooltip();
jQuery('#side-menu-always-displayed').val(target.attr('data-alwaysdiplayed'))
jQuery('#side-menu-big-menu').val(target.attr('data-bigmenu'))
if (document.querySelector('#side-menu-categories-custom')) {
const View = Vue.extend(AdminCategoriesCustom)
const adminCategoriesCustom = new View({})
adminCategoriesCustom.$mount('#side-menu-categories-custom')
}
elements = document.querySelectorAll('.side-menu-setting')
document.querySelector('#side-menu-save').addEventListener('click', (event) => {
event.preventDefault()
OC.msg.startSaving(selector)
saveSettings(0)
})
const resets = document.querySelectorAll('.btn-reset')
for (let btn of resets) {
btn.addEventListener('click', (event) => {
const target = event.target
const values = JSON.parse(target.getAttribute('data-reset'))
target.classList.toggle('btn-reset--progress', true)
for (let i in values) {
document.querySelector(`#${i}`).value = values[i]
}
window.setTimeout(() => {
target.classList.toggle('btn-reset--progress', false)
}, 800)
})
}
jQuery('.side-menu-setting-live').on('change', (event) => {
var target = jQuery(event.target)
var name = target.attr('name')
var value = target.val()
const displays = document.querySelectorAll('.side-menu-display')
if (name === 'opener') {
var url = OC.generateUrl(`/apps/side_menu/img/${value}.svg`).replace('/index.php', '')
for (let display of displays) {
display.addEventListener('click', (event) => {
const target = event.target
value = `url(${url})`;
}
for (let d of displays) {
d.classList.toggle('is-active', d === display)
}
if (name === 'icon-invert-filter' || name === 'icon-opacity') {
value/=100;
}
document.documentElement.style.setProperty('--side-menu-' + name, value)
document.querySelector('#side-menu-always-displayed').value = target.getAttribute('data-alwaysdiplayed')
document.querySelector('#side-menu-big-menu').value = target.getAttribute('data-bigmenu')
document.querySelector('#side-menu-side-with-categories').value = target.getAttribute('data-sidewithcategories')
})
}
jQuery('.side-menu-toggler').on('click', (event) => {
var target = jQuery(event.target)
var element = target.attr('data-target')
elementToggler(element)
for (let item of document.querySelectorAll('.apps-categories-custom')) {
item.addEventListener('change', (event) => {
updateAppsCategoriesCustom()
})
});
}
for (let item of document.querySelectorAll('.side-menu-setting-live')) {
item.addEventListener('change', (event) => {
const target = event.target
const name = target.getAttribute('name')
let value = target.value
let id = null
if (name === 'background-color-opacity') {
id = '#side-menu-background-color, #side-menu-background-color-to'
} else if (name === 'dark-mode-background-color-opacity') {
id = '#side-menu-dark-mode-background-color, #side-menu-dark-mode-background-color-to'
}
if (id) {
document.querySelector(id).dispatchEvent(new CustomEvent('change'))
return
}
if (name === 'opener') {
const url = OC.generateUrl(`/apps/side_menu/img/${value}.svg`).replace('/index.php', '')
value = `url(${url})`
}
if (name === 'icon-invert-filter' || name === 'icon-opacity') {
value/=100
}
if (['dark-mode-background-color', 'dark-mode-background-color-to'].indexOf(name) > -1) {
const opacity = parseInt(document.querySelector('#side-menu-dark-mode-background-color-opacity').value * 255 / 100)
value = [value, opacity.toString(16)].join('')
} else if (['background-color', 'background-color-to'].indexOf(name) > -1) {
const opacity = parseInt(document.querySelector('#side-menu-background-color-opacity').value * 255 / 100)
value = [value, opacity.toString(16)].join('')
}
document.documentElement.style.setProperty('--side-menu-' + name, value)
})
}
for (let toggler of document.querySelectorAll('.side-menu-toggler')) {
toggler.addEventListener('click', (event) => {
const target = event.target
const element = document.querySelector(target.getAttribute('data-target'))
elementToggler(element)
})
}
sortable('#categories-list .side-menu-setting-list', {
placeholderClass: 'side-menu-setting-list-drop'
})
try {
sortable('#categories-list .side-menu-setting-list')[0].addEventListener('sortstop', (e) => {
let value = []
for (let item of document.querySelectorAll('#categories-list .side-menu-setting-list-item')) {
value.push(item.getAttribute('data-id'))
}
document.querySelector('input[name="categories-order"]').value = JSON.stringify(value)
})
} catch (e) {
}
sortable('#apps-order-list .side-menu-setting-list', {
placeholderClass: 'side-menu-setting-list-drop'
})
try {
sortable('#apps-order-list .side-menu-setting-list')[0].addEventListener('sortstop', (e) => {
let value = []
for (let item of document.querySelectorAll('#apps-order-list .side-menu-setting-list-item')) {
value.push(item.getAttribute('data-id'))
}
document.querySelector('input[name="apps-order"]').value = JSON.stringify(value)
})
} catch (e) {
}
})
+92
View File
@@ -0,0 +1,92 @@
"Custom menu": "Uživatelsky určená nabídka"
"Enable the custom menu": "Zapnout uživatelsky určenou nabídku"
"No": "Ne"
"Yes": "Ano"
"Menu": "Nabídka"
? '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.'
: 'Pro otevření/skrytí postranní nabídky použijte zkratku <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">O</span> („O“ jako otevřít). Pro pohyb po použijte klávesu <span class="keyboard-key">Tab</span>.'
"Top menu": "Horní nabídka"
"Apps that not must be moved in the side menu": "Aplikace, které nepřesouvat do postranní nabídky"
"If there is no selection then the global configuration is applied.": "Pokud neexistuje žádný výběr, je uplatněno globální nastavení."
"Experimental": "Experimentální"
"Save": "Uložit"
"You like this app and you want to support me?": "Líbí se vám tato aplikace a chcete podpořit její vývoj?"
"Buy me a coffee ☕": "Kupte mi kafe ☕"
"Hidden": "Skryté"
"Small": "Malé"
"Normal": "Normální"
"Big": "Velké"
"Colors": "Barvy"
"Background color": "Barva pozadí"
"Background color of current app": "Barva pozadí stávající aplikace"
"Text color": "Barva textu"
"Loader": "Nástroj pro načítání"
"Icon": "Ikona"
"Same color": "Stejná barva"
"Opposite color": "Doplňková barva"
"Transparent": "Průhledné"
"Opaque": "Neprůhledné"
"Opener": "Tlačítko pro otevření"
"Default": "Výchozí"
"Default (dark)": "Výchozí (tmavé)"
"Hamburger": "Hamburger"
"Hamburger (dark)": "Hamburger (tmavé)"
"Hamburger 2": "Hamburger 2"
"Hamburger 2 (dark)": "Hamburger 2 (tmavé)"
"Before the logo": "Před logem"
"After the logo": "Za logem"
"Position": "Pozice"
"Show only the opener (hidden logo)": "Zobrazovat pouze otevírací tlačítko (logo skryto)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Nezobrazovat postranní nabídku a její otevírací tlačítko pokud nejsou dostupné žádné aplikace (např. na veřejných stránkách)."
"Panel": "Panel"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Otevřít nabídku při najetím ukazatelem na tlačítko nabídky (automaticky vypnuto pro dotykové obrazovky)"
"Display the big menu": "Zobrazit velkou nabídku"
"Display the logo": "Zobrazit logo"
"Icons and texts": "Ikony a texty"
"Loader enabled": "Načítání zapnuto"
"Tips": "Tipy"
"Always displayed": "Vždy zobrazeno"
"This is the automatic behavior when the menu is always displayed.": "Toto je automatické chování, kdy je nabídka vždy zobrazena."
"Not compatible with touch screens.": "Nekompatibilní s dotykovými obrazovkami."
"Big menu": "Velká nabídka"
"Live preview": "Živý náhled"
"Open apps in new tab": "Otevírat aplikace v novém panelu"
"Use the global setting": "Použít globální nastavení"
"Use my selection": "Použít můj výběr"
"Show and hide the list of applications": "Zobrazit/skrýt seznam aplikací"
"Use the avatar instead of the logo": "Použít namísto loga profilový obrázek uživatele"
"You do not have permission to change the settings.": "Nemáte oprávnění měnit nastavení."
"Force this configuration to users": "Vynutit uplatnění těchto nastavení uživatelům"
"Export the configuration": "Exportovat nastavení"
"Purge the cache": "Vyprázdnit mezipaměť"
"Show the link to settings": "Zobrazit odkaz na nastavení"
"The menu is enabled by default for users": "Nabídka je ve výchozím stavu pro uživatele zapnutá"
"Except when the configuration is forced.": "S výjimkou, kdy je nastavení vynuceno."
"Apps that should not be displayed in the menu": "Aplikace, které by neměly být v nabídce zobrazeny"
"This feature is only compatible with the <code>big menu</code> display.": "Tato funkce je kompatibilní pouze s <code>velkou nabídkou</code>."
"The logo is a link to the default app": "Logo je odkaz na výchozí aplikaci"
"Others": "Ostatní"
"Categories": "Kategorie"
"Customize sorting": "Přizpůsobit si řazení"
"Order by": "Řadit podle"
"Name": "Název"
"Customed": "Přizpůsobeno"
"Show and hide the list of categories": "Zobrazit/skrýt seznam kategorií"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Tyto parametry jsou použity v případě, že je zapnutý (Breeze) tmavý motiv vzhledu."
"Dark mode colors": "Barvy tmavého režimu"
"With categories": "S kategoriemi"
"Custom categories": "Vlastní kategorie"
"Customize application categories": "Přizpůsobte kategorie aplikací"
"Reset to default": "Vrátit zpět na výchozí hodnoty"
"Hidden icon": "Skrytá ikona"
"Small icon": "Malá ikona"
"Normal icon": "Normální ikona"
"Big icon": "Velká ikona"
"Hidden text": "Skrytý text"
"Small text": "Malý text"
"Normal text": "Normální text"
"Big text": "Velký text"
"Applications": "Aplikace"
"Applications kept in the top menu": "Aplikace ponechané v horní nabídce"
"Applications kept in the top menu but also shown in side menu": "Aplikace ponechané v horní nabídce ale také zobrazené v té boční"
"These applications must be selected in the previous option.": "Tyto aplikace je třeba vybrat v předchozí volbě."
+77 -27
View File
@@ -1,31 +1,39 @@
"Custom menu": "Benutzerdefiniertes Menü"
"Enable the custom menu": "Aktiviere das Benutzerdefiniertes Menü"
"Enable the custom menu": "Benutzerdefiniertes Menü aktivieren"
"No": "Nein"
"Yes": "Ja"
"Menu": "Menü"
'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.': 'Verwende die Tastenkombination <span class="keyboard-key">Strg</span>+<span class="keyboard-key">o</span>, um das Seitenmenü ein- und auszublenden. Verwende <span class="keyboard-key">tab</span> zum Navigieren.'
"Top menu": "Hauptmenü"
"Apps that not must be moved in the side menu": "Apps, die nicht ins 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."
? '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.'
: 'Verwende die Tastenkombination <span class="keyboard-key">Strg</span>+<span class="keyboard-key">o</span>,
um das Seitenmenü ein- und auszublenden. Verwende <span class="keyboard-key">tab</span>
zum Navigieren.'
"Top menu": "Obere Navigationsleiste"
"Apps that not must be moved in the side menu": "Anwendungen, die nicht ins Seitenmenü\
\ verschoben werden sollen"
"If there is no selection then the global configuration is applied.": "Wenn keine\
\ Auswahl vorhanden ist, wird die globale Konfiguration angewendet."
"Experimental": "Experimentell"
"Save": "Speichern"
"You like this app and you want to support me?": "Du magst diese App und möchtest mich unterstützen?"
"Buy me a coffee ☕": "Gib mir einen Kaffee ☕"
"Hidden": "Versteckt"
"You like this app and you want to support me?": "Du magst diese Anwendung und möchtest\
\ mich unterstützen?"
"Buy me a coffee ☕": "Gib mir einen Kaffee aus ☕"
"Hidden": "Ausblenden"
"Small": "Klein"
"Normal": "Normal"
"Big": "Groß"
"Colors": "Farben"
"Background color": "Hintergrundfarbe"
"Background color of current app": "Hintergrundfarbe der aktuellen App"
"Background color of current app": "Hintergrundfarbe der aktuellen Anwendung"
"Text color": "Textfarbe"
"Loader": "Ladestandanzeige"
"Icon": "Symbol"
"Same color": "Selbe Farbe"
"Opposite color": "Gegenfarbe"
"Transparent": "Transparent"
"Opaque": "Undurchsichtig"
"Opener": "Öffner"
"Opaque": "Nicht transparent"
"Opener": "Menü-Symbol"
"Default": "Standard"
"Default (dark)": "Standard (dunkel)"
"Hamburger": "Hamburger"
@@ -35,29 +43,71 @@
"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).": "Zeige das Seitenmenü und den Öffner nicht an, wenn keine Anwendung vorhanden ist (z.B. bei öffentlichen Seiten)."
"Show only the opener (hidden logo)": "Nur das Menü-Symbol anzeigen (Logo wird ausgeblendet)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Zeige\
\ das Seitenmenü und das Menü-Symbol nicht an, wenn keine Anwendung vorhanden ist\
\ (z.B. bei öffentlichen Seiten)."
"Panel": "Panel"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Öffne das Menü, wenn die Maus über den Öffner bewegt wird (auf Touchscreens automatisch deaktiviert)."
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Öffne\
\ das Menü, wenn die Maus über das Menü-Symbol bewegt wird (auf Touchscreens automatisch\
\ deaktiviert)"
"Display the big menu": "Großes Menü anzeigen"
"The big menu is not compatible with AppOrder.": "Das große Menü ist nicht mit AppOrder kompatibel."
"Display the logo": "Logo anzeigen"
"This feature is not compatible with the <code>big menu</code> display.": "Diese Funktion ist nicht mit <code>großes Menü</code> kompatibel."
"Icons and texts": "Symbole und Texte"
"Loader enabled": "Loader aktiviert"
"Loader enabled": "Ladestandanzeige aktiviert"
"Tips": "Tipps"
"Always displayed": "Wird immer angezeigt"
"The logo will be hidden when the menu is always displayed.": "Das Logo wird ausgeblendet, wenn das Menü immer angezeigt wird."
"This is the automatic behavior when the menu is always displayed.": "Dies ist das automatische Verhalten, wenn das Menü immer angezeigt wird."
"Always displayed": "Immer anzeigen"
"This is the automatic behavior when the menu is always displayed.": "Dies ist das\
\ automatische Verhalten, wenn das Menü immer angezeigt wird."
"Not compatible with touch screens.": "Nicht kompatibel mit Touchscreens."
"Big menu": "Großes Menü"
"Live preview": "Live Vorschau"
"Open apps in new tab": "Öffne Apps in einem neuen Tab"
"Live preview": "Live-Vorschau"
"Open apps in new tab": "Öffne Anwendungen in einem neuen Tab"
"Use the global setting": "Verwende die globale Einstellung"
"Use my selection": "Verwende meine Auswahl"
"Show and hide the list of applications": "Ein- und Ausblenden der Anwendungsliste"
"Use the avatar instead of the logo": "Verwenden Sie den Avatar anstelle des Logos"
"You do not have permission to change the settings.": "Sie haben keine Berechtigung zum Ändern der Einstellungen."
"Force this configuration to users": "Erzwingen Sie diese Konfiguration für Benutzer"
"Export the configuration": "Exportieren Sie die Konfiguration"
"Purge the cache": "Leeren Sie den Cache"
"Use the avatar instead of the logo": "Avatar anstelle des Logos anzeigen"
"You do not have permission to change the settings.": "Du hast keine Berechtigung,\
\ die Einstellungen dieser Anwendung zu ändern."
"Force this configuration to users": "Konfiguration für alle Benutzer erzwingen"
"Export the configuration": "Konfiguration exportieren"
"Purge the cache": "Cache leeren"
"Show the link to settings": "Link zu den Einstellungen anzeigen"
"The menu is enabled by default for users": "Das Menü ist standardmäßig für alle Benutzer\
\ aktiviert"
"Except when the configuration is forced.": "Gilt nicht, wenn die Konfiguration erzwungen\
\ wird."
"Apps that should not be displayed in the menu": "Anwendungen, die nicht im Menü angezeigt\
\ werden sollen"
"This feature is only compatible with the <code>big menu</code> display.": "Kompatibel\
\ mit dem <code>großen Menü</code>."
"The logo is a link to the default app": "Das Logo ist ein Link zur Standard-App"
"Others": "Andere"
"Categories": "Kategorien"
"Customize sorting": "Sortierung anpassen"
"Order by": "Sortieren nach"
"Name": "Name"
"Customed": "Benutzerdefiniert"
"Show and hide the list of categories": "Liste der Kategorien ein- und ausblenden"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Diese\
\ Optionen werden auf <code>Dark Theme</code> oder <code>Breeze Dark Theme</code>\
\ angewendet."
"Dark mode colors": "Farben für den dunklen Modus"
"With categories": "Mit Kategorien"
"Custom categories": "Benutzerdefinierte Kategorien"
"Customize application categories": "Anwendungskategorien anpassen"
"Reset to default": "Auf Standard zurücksetzen"
"Hidden icon": "Verstecktes Symbol"
"Small icon": "Kleines Symbol"
"Normal icon": "Normales Symbol"
"Big icon": "Große Ikone"
"Hidden text": "Versteckter Text"
"Small text": "Kleiner Text"
"Normal text": "Normaler Text"
"Big text": "Großer Text"
"Applications": "Applications"
"Applications kept in the top menu": "Applications kept in the top menu"
"Applications kept in the top menu but also shown in side menu": "Applications kept\
\ in the top menu but also shown in side menu"
"These applications must be selected in the previous option.": "These applications\
\ must be selected in the previous option."
+34 -5
View File
@@ -3,10 +3,11 @@
"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.'
? '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"
"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 ?"
@@ -15,6 +16,14 @@
"Small": "Petit"
"Normal": "Normal"
"Big": "Gros"
"Hidden icon": "Icône masqué"
"Small icon": "Petit icône"
"Normal icon": "Icône normal"
"Big icon": "Gros icône"
"Hidden text": "Text masqué"
"Small text": "Texte petit"
"Normal text": "Texte normal"
"Big text": "Gros texte"
"Colors": "Couleurs"
"Background color": "Couleur de fond"
"Background color of current app": "Couleur de fond de l'application en cours"
@@ -40,14 +49,11 @@
"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"
"Always displayed": "Toujours affiché"
"The logo will be hidden when the menu is always displayed.": "Le logo sera masque si le menu est toujours affiché."
"This is the automatic behavior when the menu is always displayed.": "C'est le comportement automatique lorsque le menu est toujours affiché."
"Not compatible with touch screens.": "Incompatible avec les écrans tactiles."
"Big menu": "Menu large"
@@ -61,3 +67,26 @@
"Force this configuration to users": "Forcer cette configuration aux utilisateurs"
"Export the configuration": "Exporter la configuration"
"Purge the cache": "Purger le cache"
"Show the link to settings": "Afficher le lien vers les paramètres"
"The menu is enabled by default for users": "Le menu est activé par défaut pour les utilisateurs"
"Except when the configuration is forced.": "Sauf lorsque la configuration est forcée."
"Apps that should not be displayed in the menu": "Applications qui ne doivent pas être affichées dans le menu"
"This feature is only compatible with the <code>big menu</code> display.": "Compatible avec l'affichage <code>Menu large</code>."
"The logo is a link to the default app": "Le logo est un lien vers l'application par défaut"
"Others": "Autres"
"Categories": "Catégories"
"Customize sorting": "Personnaliser le tri"
"Order by": "Trier par"
"Name": "Nom"
"Customed": "Personnalisé"
"Show and hide the list of categories": "Afficher et masquer la liste des catégories"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Ces paramètres sont utilisés lorsque le thème sombre ou le thème Breeze Dark sont activés."
"Dark mode colors": "Couleurs du mode sombre"
"With categories": "Avec les catégories"
"Custom categories": "Catégories personnalisées"
"Customize application categories": "Personnaliser les catégories des applications"
"Reset to default": "Restaurer les valeurs par défaut"
"Applications": "Applications"
"Applications kept in the top menu": "Applications conservées dans le menu supérieur"
"Applications kept in the top menu but also shown in side menu": "Applications conservées dans le menu supérieur mais également affichées dans le menu latéral"
"These applications must be selected in the previous option.": "Ces applications doivent également être sélectionnées dans l'option précédente."
+92
View File
@@ -0,0 +1,92 @@
"Custom menu": "Aangepast menu"
"Enable the custom menu": "Het aangepaste menu inschakelen"
"No": "Nee"
"Yes": "Ja"
"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.'
: 'Gebruik de snelkoppeling <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span> om het zijmenu te openen en te verbergen. Gebruik <span class="keyboard-key">tab</span> om te navigeren.'
"Top menu": "Bovenste menu"
"Apps that not must be moved in the side menu": "Apps die niet moeten worden verplaatst in het zijmenu"
"If there is no selection then the global configuration is applied.": "Als er geen keuze is, wordt de globale configuratie toegepast."
"Experimental": "Experimenteel"
"Save": "Opslaan"
"You like this app and you want to support me?": "Vind je deze app leuk en wil je me steunen?"
"Buy me a coffee ☕": "Koop een koffie voor me ☕"
"Hidden": "Verborgen"
"Small": "Klein"
"Normal": "Normaal"
"Big": "Groot"
"Hidden icon": "Verborgen icoon"
"Small icon": "Klein icoon"
"Normal icon": "Normaal icoon"
"Big icon": "Groot icoon"
"Hidden text": "Verborgen tekst"
"Small text": "Kleine tekst"
"Normal text": "Normale tekst"
"Big text": "Grote tekst"
"Colors": "Kleuren"
"Background color": "Achtergrond kleur"
"Background color of current app": "Achtergrondkleur van huidige app"
"Text color": "Tekst kleur"
"Loader": "Lader"
"Icon": "Icoon"
"Same color": "Zelfde kleur"
"Opposite color": "Tegenovergestelde kleur"
"Transparent": "Transparant"
"Opaque": "Ondoorzichtig"
"Opener": "Opener"
"Default": "Standaard"
"Default (dark)": "Standaard (donker)"
"Hamburger": "Hamburger"
"Hamburger (dark)": "Hamburger (donker)"
"Hamburger 2": "Hamburger 2"
"Hamburger 2 (dark)": "Hamburger 2 (donker)"
"Before the logo": "Voor het logo"
"After the logo": "Na het logo"
"Position": "Positie"
"Show only the opener (hidden logo)": "Toon alleen de opener (verborgen logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Geef het zijmenu en de opener niet weer als er geen toepassing is (bijv. openbare pagina's)."
"Panel": "Paneel"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Open het menu wanneer de muis over de opener gaat (automatisch uitgeschakeld op aanraakschermen)"
"Display the big menu": "Toon het grote menu"
"Display the logo": "Toon het logo"
"Icons and texts": "Iconen en teksten"
"Loader enabled": "Lader ingeschakeld"
"Tips": "Tips"
"Always displayed": "Altijd weergegeven"
"This is the automatic behavior when the menu is always displayed.": "Dit is het automatische gedrag wanneer het menu altijd wordt weergegeven."
"Not compatible with touch screens.": "Niet compatibel met aanraakschermen."
"Big menu": "Groot menu"
"Live preview": "Live voorbeeld"
"Open apps in new tab": "Open apps in nieuwe tab"
"Use the global setting": "Gebruik de globale instellingen"
"Use my selection": "Gebruik mijn selectie"
"Show and hide the list of applications": "De lijst met toepassingen tonen en verbergen"
"Use the avatar instead of the logo": "Gebruik avatar in plaats van het logo"
"You do not have permission to change the settings.": "Je hebt geen toestemming om de instellingen te veranderen."
"Force this configuration to users": "Forceer deze configuratie aan gebruikers"
"Export the configuration": "Exporteer de configuratie"
"Purge the cache": "De cache wissen"
"Show the link to settings": "Toon de link naar de instellingen"
"The menu is enabled by default for users": "Het menu is standaard ingeschakeld voor gebruikers"
"Except when the configuration is forced.": "Behalve als de configuratie geforceerd is."
"Apps that should not be displayed in the menu": "Apps die niet in het menu weergegeven mogen worden"
"This feature is only compatible with the <code>big menu</code> display.": "Deze functie is alleen compatibel met het <code>grote menu</code> scherm."
"The logo is a link to the default app": "Het logo is een link naar de standaard app"
"Others": "Overige"
"Categories": "Categorieën"
"Customize sorting": "Sortering aanpassen"
"Order by": "Sorteer op"
"Name": "Naam"
"Customed": "Aangepast"
"Show and hide the list of categories": "De lijst met categorieën tonen en verbergen"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Deze parameters worden gebruikt wanneer Dark theme of Breeze Dark Theme zijn ingeschakeld."
"Dark mode colors": "Donkere modus kleuren"
"With categories": "Met categorieën"
"Custom categories": "Aangepaste categorieën"
"Customize application categories": "Toepassingscategorieën aanpassen"
"Reset to default": "Terugzetten naar standaard"
"Applications": "Applicaties"
"Applications kept in the top menu": "Applicaties bewaard in het bovenste menu"
"Applications kept in the top menu but also shown in side menu": "Applicaties blijven in het topmenu maar worden ook in het zijmenu getoond"
"These applications must be selected in the previous option.": "Deze toepassingen moeten bij de vorige optie zijn geselecteerd."
+92
View File
@@ -0,0 +1,92 @@
"Custom menu": "Custom menu"
"Enable the custom menu": "Включить пользовательское меню"
"No": "Нет"
"Yes": "Да"
"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.'
: 'Используйте сочетание клавиш <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span>, чтобы открыть или скрыть боковое меню. Используйте <span class="keyboard-key">Tab</span> для навигации.'
"Top menu": "Верхнее меню"
"Apps that not must be moved in the side menu": "Приложения не перемещаемые в боковое меню"
"If there is no selection then the global configuration is applied.": "If there is no selection then the global configuration is applied."
"Experimental": "Экспериментальный"
"Save": "Сохранить"
"You like this app and you want to support me?": "Вам нравится приложение или вы хотите поддержать меня?"
"Buy me a coffee ☕": "Купить мне чашку кофе ☕"
"Hidden": "Скрыто"
"Small": "Маленький"
"Normal": "Средний"
"Big": "Большой"
"Hidden icon": "Скрытая иконка"
"Small icon": "Маленькая иконка"
"Normal icon": "Средняя иконка"
"Big icon": "Большая иконка"
"Hidden text": "Скрытый текст"
"Small text": "Маленький текст"
"Normal text": "Средний текст"
"Big text": "Большой текст"
"Colors": "Цвета"
"Background color": "Цвет фона"
"Background color of current app": "Цвет фона выбранного приложения"
"Text color": "Цвет текста"
"Loader": "Загрузчик"
"Icon": "Иконка"
"Same color": "Такой же цвет"
"Opposite color": "Opposite color"
"Transparent": "Прозрачный"
"Opaque": "Opaque"
"Opener": "Opener"
"Default": "По-умолчанию"
"Default (dark)": "По-умолчанию (тёмный)"
"Hamburger": "Гамбургер"
"Hamburger (dark)": "Гамбургер (тёмный)"
"Hamburger 2": "Гамбургер 2"
"Hamburger 2 (dark)": "Гамбургер 2 (тёмный)"
"Before the logo": "Перед логотипом"
"After the logo": "После логотипа"
"Position": "Позиция"
"Show only the opener (hidden logo)": "Show only the opener (hidden logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Do not display the side menu and the opener if there is no application (eg: public pages)."
"Panel": "Панеот"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "Open the menu when the mouse is hover the opener (automatically disabled on touch screens)"
"Display the big menu": "Отобразить большое меню"
"Display the logo": "Показать лого"
"Icons and texts": "Иконки и текст"
"Loader enabled": "Loader enabled"
"Tips": "Советы"
"Always displayed": "Всегда отображается"
"This is the automatic behavior when the menu is always displayed.": "This is the automatic behavior when the menu is always displayed."
"Not compatible with touch screens.": "Не совместимо с сенсорными экранами"
"Big menu": "Большое меню"
"Live preview": "Live preview"
"Open apps in new tab": "Открывать приложения в новой вкладке"
"Use the global setting": "Use the global setting"
"Use my selection": "Use my selection"
"Show and hide the list of applications": "Показать или скрыть список приложений"
"Use the avatar instead of the logo": "Использовать аватар вместо логотипа"
"You do not have permission to change the settings.": "У вас нет разрешения изменять настройки"
"Force this configuration to users": "Force this configuration to users"
"Export the configuration": "Экспортировать конфигурацию"
"Purge the cache": "Очистить кэш"
"Show the link to settings": "Показать ссылку на настройки"
"The menu is enabled by default for users": "The menu is enabled by default for users"
"Except when the configuration is forced.": "Except when the configuration is forced."
"Apps that should not be displayed in the menu": "Apps that should not be displayed in the menu"
"This feature is only compatible with the <code>big menu</code> display.": "This feature is only compatible with the <code>big menu</code> display."
"The logo is a link to the default app": "The logo is a link to the default app"
"Others": "Прочие"
"Categories": "Категории"
"Customize sorting": "Настроить сортировку"
"Order by": "В порядке"
"Name": "Название"
"Customed": "Customed"
"Show and hide the list of categories": "Показать или скрыть список категорий"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "This parameters are used when Dark theme or Breeze Dark Theme are enabled."
"Dark mode colors": "Цвета тёмной темы"
"With categories": "С категориями"
"Custom categories": "Custom categories"
"Customize application categories": "Customize application categories"
"Reset to default": "Сбросить к значениям по-умолчанию"
"Applications": "Приложения"
"Applications kept in the top menu": "Applications kept in the top menu"
"Applications kept in the top menu but also shown in side menu": "Applications kept in the top menu but also shown in side menu"
"These applications must be selected in the previous option.": "These applications must be selected in the previous option."
+94
View File
@@ -0,0 +1,94 @@
"Custom menu": ""
"Enable the custom menu": ""
"No": ""
"Yes": ""
"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.'
: ''
"Top menu": ""
"Apps that not must be moved in the side menu": ""
"If there is no selection then the global configuration is applied.": ""
"Experimental": ""
"Save": ""
"You like this app and you want to support me?": ""
"Buy me a coffee ☕": ""
"Hidden": ""
"Small": ""
"Normal": ""
"Big": ""
"Hidden icon": ""
"Small icon": ""
"Normal icon": ""
"Big icon": ""
"Hidden text": ""
"Small text": ""
"Normal text": ""
"Big text": ""
"Colors": ""
"Background color": ""
"Background color of current app": ""
"Text color": ""
"Loader": ""
"Icon": ""
"Same color": ""
"Opposite color": ""
"Transparent": ""
"Opaque": ""
"Opener": ""
"Default": ""
"Default (dark)": ""
"Hamburger": ""
"Hamburger (dark)": ""
"Hamburger 2": ""
"Hamburger 2 (dark)": ""
"Before the logo": ""
"After the logo": ""
"Position": ""
"Show only the opener (hidden logo)": ""
"Do not display the side menu and the opener if there is no application (eg: public pages).": ""
"Panel": ""
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": ""
"Display the big menu": ""
"Display the logo": ""
"Icons and texts": ""
"Loader enabled": ""
"Tips": ""
"Always displayed": ""
"This is the automatic behavior when the menu is always displayed.": ""
"Not compatible with touch screens.": ""
"Big menu": ""
"Live preview": ""
"Open apps in new tab": ""
"Use the global setting": ""
"Use my selection": ""
"Show and hide the list of applications": ""
"Use the avatar instead of the logo": ""
"You do not have permission to change the settings.": ""
"Force this configuration to users": ""
"Export the configuration": ""
"Purge the cache": ""
"Show the link to settings": ""
"The menu is enabled by default for users": ""
"Except when the configuration is forced.": ""
"Apps that should not be displayed in the menu": ""
"This feature is only compatible with the <code>big menu</code> display.": ""
"The logo is a link to the default app": ""
"Others": ""
"Categories": ""
"Customize sorting": ""
"Order by": ""
"Name": ""
"Customed": ""
"Show and hide the list of categories": ""
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": ""
"Dark mode colors": ""
"With categories": ""
"Custom categories": ""
"Customize application categories": ""
"Reset to default": ""
"Applications": ""
"Applications kept in the top menu": ""
"Applications kept in the top menu but also shown in side menu": ""
"These applications must be selected in the previous option.": ""
+99
View File
@@ -0,0 +1,99 @@
"Custom menu": "自定义菜单"
"Enable the custom menu": "激活自定义菜单"
"No": "取消"
"Yes": "确定"
"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."
: "使用快捷键 <span class=\"keyboard-key\">Ctrl</span>+<span class=\"keyboard-key\">o</span>\
\ 打开或隐藏侧边栏菜单。使用<span class=\"keyboard-key\">tab</span> 来导航。"
"Top menu": "顶部菜单"
"Apps that not must be moved in the side menu": "禁止在侧边栏菜单移动的应用"
"If there is no selection then the global configuration is applied.": "如不选择,将应用全局设定。"
"Experimental": "实验性"
"Save": "保存"
"You like this app and you want to support me?": "喜欢本应用并支持我一下?"
"Buy me a coffee ☕": "赏一杯咖啡 ☕ 给我"
"Hidden": "隐藏"
"Small": "小型"
"Normal": "标准"
"Big": "大型"
"Colors": "颜色"
"Background color": "背景颜色"
"Background color of current app": "当前应用的背景色"
"Text color": "文字颜色"
"Loader": "菜单指示器"
"Icon": "图标"
"Same color": "相同颜色"
"Opposite color": "相反颜色"
"Transparent": "透明"
"Opaque": "不透明"
"Opener": "容器"
"Default": "默认"
"Default (dark)": "默认(深色)"
"Hamburger": "Hamburger"
"Hamburger (dark)": "Hamburger (深色)"
"Hamburger 2": "Hamburger 2"
"Hamburger 2 (dark)": "Hamburger 2 (深色)"
"Before the logo": "在logo前"
"After the logo": "在logo后"
"Position": "位置"
"Show only the opener (hidden logo)": "只显示容器 (隐藏logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "N如果没有应用,不显示侧边栏菜单和容器\
\ (例如 : 公共页面)。"
"Panel": "面板"
"Open the menu when the mouse is hover the opener (automatically disabled on touch screens)": "鼠标悬停时打开菜单\
\ (触摸屏时将自动禁用)"
"Display the big menu": "显示大型菜单"
"Display the logo": "显示logo"
"Icons and texts": "图标与文字"
"Loader enabled": "菜单指示器已激活"
"Tips": "技巧"
"Always displayed": "一直显示"
"This is the automatic behavior when the menu is always displayed.": "一直显示菜单时的自动动作。"
"Not compatible with touch screens.": "与触屏不兼容。"
"Big menu": "大型菜单"
"Live preview": "实时预览"
"Open apps in new tab": "在新标签中打开应用"
"Use the global setting": "使用全局设定"
"Use my selection": "使用自定义设定"
"Show and hide the list of applications": "显示或隐藏应用列表"
"Use the avatar instead of the logo": "使用头像代替logo"
"You do not have permission to change the settings.": "没有更改设置的权限。"
"Force this configuration to users": "强制用户使用此设置"
"Export the configuration": "导出设置"
"Purge the cache": "清除缓存"
"Show the link to settings": "显示设置链接"
"The menu is enabled by default for users": "用户的默认菜单已激活"
"Except when the configuration is forced.": "除非设置被强制使用。"
"Apps that should not be displayed in the menu": "禁止在菜单中显示的应用"
"This feature is only compatible with the <code>big menu</code> display.": "此功能只和<code>大型菜单</code>兼容。"
"The logo is a link to the default app": "logo链接到默认应用"
"Others": "其他"
"Categories": "类别"
"Customize sorting": "自定义顺序"
"Order by": "排序规则"
"Name": "名称"
"Customed": "自定义"
"Show and hide the list of categories": "显示或隐藏类别列表"
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "此参数将应用于暗黑主题激活时。"
"Dark mode colors": "暗黑模式颜色"
"With categories": "有类别"
"Custom categories": "自定义类别"
"Customize application categories": "自定义应用程序类别"
"Reset to default": "重置为默认设置"
"Hidden icon": "隐藏图标"
"Small icon": "小图标"
"Normal icon": "正常图标"
"Big icon": "大图标"
"Hidden text": "隐藏文字"
"Small text": "小文本"
"Normal text": "普通文本"
"Big text": "大文本"
"Applications": "Applications"
"Applications kept in the top menu": "Applications kept in the top menu"
"Applications kept in the top menu but also shown in side menu": "Applications kept\
\ in the top menu but also shown in side menu"
"These applications must be selected in the previous option.": "These applications\
\ must be selected in the previous option."
+11
View File
@@ -0,0 +1,11 @@
module.exports = (tagName, attributes) => {
const element = document.createElement(tagName)
if (typeof attributes === 'object') {
for (let i in attributes) {
element.setAttribute(i, attributes[i])
}
}
return element
}
+99 -87
View File
@@ -1,116 +1,128 @@
:root {
<?php foreach ($_['vars'] as $key => $value): ?>
<?php if ($key === 'opener'): ?>
--side-menu-<?php echo $key ?>: url('<?php print_unescaped(image_path('side_menu', $value.'.svg')); ?>');
<?php else: ?>
--side-menu-<?php echo $key ?>: <?php echo $value ?>;
<?php endif; ?>
<?php endforeach; ?>
<?php foreach ($_['vars'] as $key => $value): ?>
<?php if ($key === 'opener'): ?>
--side-menu-<?php echo $key ?>: url('<?php print_unescaped(image_path('side_menu', $value.'.svg')); ?>');
<?php else: ?>
--side-menu-<?php echo $key ?>: <?php echo $value ?>;
<?php endif; ?>
<?php endforeach; ?>
}
<?php if (empty($_['top-menu-apps'])): ?>
#appmenu {
display: none;
}
<?php if (empty($_['top-menu-apps']) && empty($_['top-side-menu-apps'])): ?>
#appmenu {
display: none;
}
#appmenu + nav {
display: none;
}
#appmenu + nav {
display: none;
}
<?php else: ?>
.app-hidden {
opacity: 0;
}
.app-hidden {
opacity: 0;
}
<?php endif; ?>
<?php if ($_['opener-only']): ?>
#nextcloud {
display: none;
}
#nextcloud {
display: none;
}
<?php endif; ?>
<?php if (!$_['display-logo']): ?>
.side-menu-logo {
display: none;
.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-header {
height: 50px;
#side-menu .side-menu-opener {
<?php if ($_['size-icon'] === 'big'): ?>
margin-left: 1px;
<?php else: ?>
margin-left: 0px;
<?php endif; ?>
}
.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 endif; ?>
<?php if ($_['size-icon'] === 'hidden'): ?>
.side-menu-app-icon {
display: none;
}
.side-menu-app-icon {
display: none;
}
<?php elseif ($_['size-icon'] === 'small'): ?>
.side-menu-app-icon svg {
width: 15px;
height: 15px;
}
.side-menu-app-icon svg {
width: 15px;
height: 15px;
}
img.side-menu-app-icon {
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;
}
.side-menu-app-icon svg {
width: 20px;
height: 20px;
}
img.side-menu-app-icon {
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;
}
.side-menu-app-icon svg {
width: 23px;
height: 23px;
}
img.side-menu-app-icon {
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;
}
.side-menu-app-text {
display: none;
}
<?php elseif ($_['size-text'] === 'small'): ?>
.side-menu-app-text {
font-size: 12px;
}
.side-menu-app-text {
font-size: 12px;
}
<?php elseif ($_['size-text'] === 'big'): ?>
.side-menu-app-text {
font-size: 16px;
}
.side-menu-app-text {
font-size: 16px;
}
<?php endif; ?>
<?php if ($_['always-displayed']): ?>
#content {
left: 53px;
width: calc(100% - (var(--body-container-margin) * 2) - 62px);
}
#content-vue {
width: calc(100% - (var(--body-container-margin) * 2) - 60px);
margin-left: 11px;
}
<?php endif; ?>
-68
View File
@@ -1,68 +0,0 @@
var alwaysDisplayed = function() {
var elements = document.querySelectorAll('*');
var fixedElements = []
for (var i in elements) {
var element = elements[i]
if (typeof element !== 'object') {
continue
}
var position = window.getComputedStyle(element, null).getPropertyValue('position');
if (position !== 'fixed') {
continue
}
var id = element.getAttribute('id')
if (id === 'header' || id === 'side-menu' || id === 'side-menu-loader') {
continue
}
if (element.classList.contains('oc-dialog')) {
continue
}
if (jQuery(element).parents('#side-menu').length) {
continue
}
fixedElements.push(element)
}
for (var i in fixedElements) {
var element = fixedElements[i]
var value = window.getComputedStyle(element, null).getPropertyValue('left')
var intValue = parseInt(value.replace('px', ''))
element.style.setProperty('transform', 'translateX(' + (intValue + 50) + 'px)')
}
}
let content = document.getElementById('content')
if (content && content.classList.contains('app-settings')) {
let loaded = false
const config = {attributes: false, childList: true, subtree: true}
const observer = new MutationObserver(() => {
if (loaded) {
return;
}
const element = content.querySelector('#app-category-your-apps')
|| content.querySelector('#app-navigation ul')
if (element) {
loaded = true
alwaysDisplayed()
}
})
observer.observe(content, config)
} else {
window.setTimeout(alwaysDisplayed, 200)
}
-15
View File
@@ -1,15 +0,0 @@
var pageLoader = jQuery('<div id="side-menu-loader">')
var pageLoaderBar = jQuery('<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)
})
-172
View File
@@ -1,172 +0,0 @@
var menuCache = null
var updateTopMenu = function() {
var breakpointMobileWidth = 1024
var menu = jQuery('#appmenu')
var apps = menu.find('li')
var minAppsDesktop = 8
var usePercentualAppMenuLimit = 0.8
var isMobile = jQuery(window).width() < breakpointMobileWidth
var lastShownApp = null
var appShown = []
var moreApps = jQuery('#more-apps')
var navigation = jQuery('#navigation')
var navigationApps = jQuery('#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)
}
if (targetBlankApps.indexOf(dataId) !== -1) {
jQuery(app).children('a').attr('target', '_blank');
}
})
var rightHeaderWidth = jQuery('.header-right').outerWidth()
var headerWidth = jQuery('header').outerWidth()
var availableWidth = headerWidth - jQuery('#nextcloud').outerWidth()
- jQuery('#header .side-menu-opener').outerWidth()
- (rightHeaderWidth > 230 ? rightHeaderWidth : 230)
if (!isMobile) {
availableWidth = availableWidth * usePercentualAppMenuLimit
}
appCount = Math.floor(availableWidth / jQuery('#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
jQuery(appShown).each(function(i, app) {
app = jQuery(app)
name = app.data('id')
if (k < appCount && appCount > 0) {
app.removeClass('hidden')
lastShownApp = app
jQuery('#apps li[data-id=' + name + '].app-external-site').addClass('in-header')
} else {
app.addClass('hidden')
notInHeader++
jQuery('#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++
jQuery('#apps li[data-id=' + name + '].app-external-site')
.removeClass('in-header')
.addClass('in-header')
}
}
k++
})
// Hack for https://github.com/nextcloud/server/blob/23b0b63c213f5b31eecae817ffd4a9e26f6624d0/core/src/components/MainMenu.js#L74-L96
menu.undelegate('li:not(#more-apps) > a', 'click')
menu.delegate('li:not(#more-apps) > a', 'click', function(e) {
var a = $(e.target)
if (!a.is('a')) {
a = a.closest('a')
}
if (a.attr('target') !== '_blank' && e.which === 1 && !e.ctrlKey && !e.metaKey && a.parent('#more-apps').length === 0) {
a.find('svg').remove()
a.find('div').remove()
a.prepend(jQuery('<div/>').addClass(
OCA.Theming && OCA.Theming.inverted
? 'icon-loading-small'
: 'icon-loading-small-dark'
))
window.location.href = a.attr('href')
}
})
jQuery('#apps li.app-external-site').each(function(i, app) {
app = jQuery(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)
+151 -114
View File
@@ -1,144 +1,181 @@
<?php
$display = 'default';
if ($_['always-displayed']) {
$display = 'always-displayed';
} elseif ($_['big-menu']) {
$display = 'big-menu';
} elseif ($_['side-with-categories']) {
$display = 'side-with-categories';
}
?>
(function() {
var sideMenuContainer = jQuery('<div id="side-menu-container">')
var sideMenuOpener = jQuery('<button class="side-menu-opener"></button>')
var sideMenu = jQuery('<div id="side-menu">')
var body = jQuery('body')
var html = jQuery('html')
var isTouchDevice = window.matchMedia("(pointer: coarse)").matches
const sideMenuContainer = SMcreateElement('div', {id: 'side-menu-container'})
const sideMenuOpener = SMcreateElement('button', {'class': 'side-menu-opener'})
const sideMenu = SMcreateElement('div', {id: 'side-menu'})
<?php if ($_['big-menu']): ?>
sideMenu.attr('data-bigmenu', '1')
<?php endif; ?>
const body = document.querySelector('body')
const html = document.querySelector('html')
const nextcloud = document.querySelector('#nextcloud')
var targetBlankApps = <?php echo json_encode($_['target-blank-apps']) ?>;
const isTouchDevice = window.matchMedia("(pointer: coarse)").matches
body.on('side-menu.apps', function(e, apps) {
<?php if ($_['hide-when-no-apps']): ?>
sideMenu = jQuery('#side-menu')
window.targetBlankApps = <?php echo json_encode($_['target-blank-apps']), "\n" ?>
window.topMenuApps = <?php echo json_encode($_['top-menu-apps']), "\n"; ?>
window.topSideMenuApps = <?php echo json_encode($_['top-side-menu-apps']), "\n"; ?>
window.menuAppsOrder = <?php echo json_encode($_['apps-order']), "\n"; ?>
if (apps.length === 0) {
sideMenu.removeClass('open')
sideMenu.addClass('hide')
sideMenuOpener.addClass('hide')
} else {
sideMenu.removeClass('hide')
sideMenuOpener.removeClass('hide')
}
<?php if ($display === 'big-menu'): ?>
sideMenu.setAttribute('data-bigmenu', '1')
<?php elseif ($display === 'side-with-categories'): ?>
sideMenu.setAttribute('data-sidewithcategories', '1')
<?php endif; ?>
<?php if ($_['always-displayed'] && !$_['big-menu']): ?>
if (apps.length === 0) {
html.removeClass('side-menu-always-displayed');
} else {
html.addClass('side-menu-always-displayed');
}
<?php endif; ?>
<?php else: ?>
<?php if ($_['always-displayed'] && !$_['big-menu']): ?>
if (apps.length === 0) {
html.removeClass('side-menu-always-displayed');
} else {
html.addClass('side-menu-always-displayed');
}
<?php endif; ?>
<?php endif; ?>
})
document.querySelector('body').addEventListener('side-menu.apps', (e) => {
const apps = e.detail.apps;
body.on('side-menu.ready', function() {
sideMenu = jQuery('#side-menu')
<?php if ($_['hide-when-no-apps']): ?>
const sideMenu = document.querySelector('#side-menu')
var headerMenuOpener = jQuery('#header .side-menu-opener')
var sideMenuOpener = jQuery('#side-menu .side-menu-opener')
if (apps.length === 0) {
sideMenu.classList.remove('open')
sideMenu.classList.add('hide')
sideMenuOpener.classList.add('hide')
} else {
sideMenu.classList.remove('hide')
sideMenuOpener.classList.remove('hide')
}
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 ($display === 'always-displayed'): ?>
if (apps.length === 0) {
html.classList.remove('side-menu-always-displayed')
} else {
html.classList.add('side-menu-always-displayed')
}
<?php endif; ?>
<?php else: ?>
<?php if ($display === 'always-displayed'): ?>
if (apps.length === 0) {
html.classList.remove('side-menu-always-displayed')
} else {
html.classList.add('side-menu-always-displayed')
}
<?php endif; ?>
<?php endif; ?>
})
<?php if ($_['opener-hover'] || ($_['always-displayed'] && !$_['big-menu'])): ?>
var sideMenuMouseLeave = function() {
sideMenu
.removeClass('open')
.off('mouseleave', sideMenuMouseLeave)
}
body.addEventListener('side-menu.ready', () => {
const sideMenu = document.querySelector('#side-menu')
const headerMenuOpener = document.querySelector('#header .side-menu-opener')
const sideMenuOpener = document.querySelectorAll('#side-menu .side-menu-opener')
var sideMenuMouseEnter = function() {
sideMenu.on('mouseleave', sideMenuMouseLeave)
}
sideMenuFocus = () => {
let a = document.querySelector('.side-menu-app.active a', sideMenu)
var sideMenuOpenerMouseEnter = function() {
sideMenu
.addClass('open')
.on('mouseenter', sideMenuMouseEnter)
if (!a) {
return
}
sideMenuFocus()
}
if (a.length === 0) {
a = sideMenu.querySelector('.side-menu-app:first-child a')
}
if (!isTouchDevice) {
<?php if ($_['opener-hover']): ?>
headerMenuOpener.on('mouseenter', sideMenuOpenerMouseEnter)
if (a.length > 0) {
a.focus()
}
}
sideMenu.addClass('hide-opener')
<?php endif ?>
<?php if ($_['opener-hover']): ?>
const sideMenuMouseLeave = () => {
sideMenu.classList.remove('open')
sideMenu.removeEventListener('mouseleave', sideMenuMouseLeave)
}
sideMenu.on('mouseleave', sideMenuMouseLeave)
sideMenu.on('mouseenter', sideMenuOpenerMouseEnter)
}
<?php endif; ?>
const sideMenuMouseEnter = () => {
sideMenu.addEventListener('mouseleave', sideMenuMouseLeave)
}
headerMenuOpener.on('click', function() {
sideMenu.addClass('open')
sideMenu.find('.side-menu-app.active a').focus()
})
const sideMenuOpenerMouseEnter = () => {
sideMenu.classList.add('open')
sideMenu.addEventListener('mouseenter', sideMenuMouseEnter)
<?php if ($_['always-displayed'] && !$_['big-menu']): ?>
sideMenuOpener.on('click', function() {
sideMenu.toggleClass('open')
})
<?php else: ?>
sideMenuOpener.on('click', function() {
sideMenu.removeClass('open')
})
<?php endif; ?>
sideMenuFocus()
}
jQuery(document).keydown(function(e) {
var key = e.key || e.keyCode
if (!isTouchDevice) {
<?php if ($_['opener-hover']): ?>
headerMenuOpener.addEventListener('mouseenter', sideMenuOpenerMouseEnter)
if ((key === 'o' || key === 79) && e.ctrlKey === true) {
e.preventDefault()
sideMenu.classList.add('hide-opener')
<?php endif ?>
sideMenu.toggleClass('open')
sideMenuFocus()
}
})
sideMenu.addEventListener('mouseleave', sideMenuMouseLeave)
sideMenu.addEventListener('mouseenter', sideMenuOpenerMouseEnter)
}
<?php endif; ?>
headerMenuOpener.addEventListener('click', () => {
sideMenu.classList.add('open')
const a = sideMenu.querySelector('.side-menu-app.active a')
if (a !== null) {
a.focus()
}
headerMenuOpener.blur()
})
body.append(sideMenuContainer)
sideMenuContainer.append(sideMenu)
for (let opener of sideMenuOpener) {
opener.addEventListener('click', () => {
<?php if ($display === 'always-displayed'): ?>
sideMenu.classList.toggle('open')
<?php else: ?>
sideMenu.classList.remove('open')
<?php endif; ?>
})
}
<?php if ($_['loader-enabled'] === true): ?>
<?php require_once __DIR__.'/_loaderEnabled.js'; ?>
<?php endif; ?>
document.addEventListener('keydown', (e) => {
var key = e.key || e.keyCode
<?php if ($_['opener-position'] === 'before'): ?>
sideMenuOpener.insertBefore('#nextcloud')
<?php else: ?>
sideMenuOpener.insertAfter('#nextcloud')
<?php endif; ?>
if ((key === 'o' || key === 79) && e.ctrlKey === true) {
e.preventDefault()
<?php if (!empty($_['top-menu-apps'])): ?>
var topMenuApps = <?php echo json_encode($_['top-menu-apps']); ?>;
sideMenu.classList.toggle('open')
sideMenuFocus()
}
})
<?php require_once __DIR__.'/_topMenuApps.js'; ?>
<?php endif; ?>
const sideMenuObserver = new MutationObserver((e) => {
if (body.getAttribute('id') !== 'body-settings') {
return
}
<?php if ($_['always-displayed'] && !$_['big-menu']): ?>
<?php require_once __DIR__.'/_alwaysDisplayed.js'; ?>
<?php endif; ?>
body.classList.toggle('body-settings-side-menu', sideMenu.classList.contains('open'))
})
sideMenuObserver.observe(sideMenu, {
attributes: true,
attributeFilter: ['class'],
childList: false,
characterData: false
})
})
body.appendChild(sideMenuContainer)
sideMenuContainer.appendChild(sideMenu)
<?php if ($_['loader-enabled'] === true): ?>
PageLoader()
<?php endif; ?>
<?php if ($_['opener-position'] === 'before'): ?>
nextcloud.parentNode.insertBefore(sideMenuOpener, nextcloud)
<?php else: ?>
nextcloud.parentNode.insertBefore(sideMenuOpener, nextcloud.nextSibling)
<?php endif; ?>
})();
File diff suppressed because it is too large Load Diff
+186 -99
View File
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
vendor_script('side_menu', 'html5sortable.min');
script('side_menu', 'admin');
style('side_menu', 'admin');
@@ -24,9 +25,10 @@ $choicesYesNo = [
'Yes' => '1',
];
$labelShowHideApps = 'Show and hide the list of applications';
$labelReset = 'Reset to default';
?>
<div id="side-menu-section">
<?php if ($_['force']): ?>
<div class="section">
@@ -40,75 +42,73 @@ $choicesYesNo = [
</div>
<?php else: ?>
<div class="section">
<h2>
<?php p($l->t('Menu')); ?>
</h2>
<div>
<label for="side-menu-enabled">
<?php p($l->t('Enable the custom 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>
<label for="side-menu-target-blank">
<?php p($l->t('Open apps in new tab')); ?>
</label>
</div>
<div>
<?php $choices = [
'Use the global setting' => '1',
'Use my selection' => '2',
]; ?>
<select id="side-menu-loader-enabled" name="target-blank-mode" class="side-menu-setting" data-personal>
<?php foreach ($choices as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['target-blank-mode']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<p>
<a class="side-menu-toggler" data-target="#target-blank-apps" href="#_">
🖱️ <?php p($l->t('Show and hide the list of applications')); ?>
</a>
</p>
<div class="side-menu-setting" data-name="target-blank-apps" id="target-blank-apps" data-personal data-checkbox style="display: none">
<?php foreach ($_['apps'] as $app): ?>
<div>
<input
type="checkbox"
name="target-blank-apps[]"
value="<?php echo $app['id'] ?>"
id="target-blank-app-<?php echo $app['id'] ?>"
<?php if (in_array($app['id'], $_['target-blank-apps'])): ?>checked<?php endif; ?>
/>
<label for="target-blank-app-<?php echo $app['id'] ?>">
<?php echo p($l->t($app['name'])); ?>
</label>
<div class="side-menu-setting-table">
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Enable the custom menu')); ?>
</div>
<?php endforeach; ?>
<div class="side-menu-setting-form">
<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>
<div class="side-menu-setting-table">
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Open apps in new tab')); ?>
</div>
<div class="side-menu-setting-form">
<?php $choices = [
'Use the global setting' => '1',
'Use my selection' => '2',
]; ?>
<select id="side-menu-loader-enabled" name="target-blank-mode" class="side-menu-setting" data-personal>
<?php foreach ($choices as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['target-blank-mode']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?>
</option>
<?php endforeach; ?>
</select>
<p>
<a class="side-menu-toggler" data-target="#target-blank-apps" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
</p>
<div class="side-menu-setting" data-name="target-blank-apps" id="target-blank-apps" data-personal data-checkbox style="display: none">
<ul class="side-menu-setting-list">
<?php foreach ($_['apps'] as $app): ?>
<li class="side-menu-setting-list-item">
<input
type="checkbox"
name="target-blank-apps[]"
value="<?php echo $app['id'] ?>"
id="target-blank-app-<?php echo $app['id'] ?>"
<?php if (in_array($app['id'], $_['target-blank-apps'])): ?>checked<?php endif; ?>
/>
<label for="target-blank-app-<?php echo $app['id'] ?>">
<?php echo p($l->t($app['name'])); ?>
</label>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</div>
</div>
@@ -116,47 +116,134 @@ $choicesYesNo = [
<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')); ?>
</label>
<div class="side-menu-setting-table">
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Applications kept in the top menu')); ?>
<p>
<em>
<?php p($l->t('If there is no selection then the global configuration is applied.')); ?>
</em>
</p>
</div>
<div class="side-menu-setting-form">
<p>
<a class="side-menu-toggler" data-target="#top-menu-apps" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
</p>
<div class="side-menu-setting" data-name="top-menu-apps" data-checkbox data-personal id="top-menu-apps" style="display: none">
<ul class="side-menu-setting-list">
<?php foreach ($_['apps'] as $app): ?>
<li class="side-menu-setting-list-item">
<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>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</div>
<p>
<em>
<?php p($l->t('If there is no selection then the global configuration is applied.')); ?>
</em>
</p>
<p>
<a class="side-menu-toggler" data-target="#top-menu-apps" href="#_">
🖱️ <?php p($l->t('Show and hide the list of applications')); ?>
</a>
</p>
<div class="side-menu-setting" data-name="top-menu-apps" data-checkbox data-personal id="top-menu-apps" style="display: none">
<?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 class="side-menu-setting-table">
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Applications kept in the top menu but also shown in side menu')); ?>
<p>
<em>
<?php p($l->t('These applications must be selected in the previous option.')); ?><br>
<?php p($l->t('If there is no selection then the global configuration is applied.')); ?>
</em>
</p>
</div>
<?php endforeach; ?>
<div class="side-menu-setting-form">
<p>
<a class="side-menu-toggler" data-target="#top-side-menu-apps" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
</p>
<div class="side-menu-setting" data-name="top-side-menu-apps" data-checkbox data-personal id="top-side-menu-apps" style="display: none">
<ul class="side-menu-setting-list">
<?php foreach ($_['apps'] as $app): ?>
<li class="side-menu-setting-list-item">
<input
type="checkbox"
name="top-side-menu-apps[]"
value="<?php echo $app['id'] ?>"
id="top-side-menu-app-<?php echo $app['id'] ?>"
<?php if (in_array($app['id'], $_['top-side-menu-apps'])): ?>checked<?php endif; ?>
/>
<label for="top-side-menu-app-<?php echo $app['id'] ?>">
<?php echo $app['name'] ?>
</label>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h2>
<?php p($l->t('Applications')); ?>
</h2>
<div class="side-menu-setting-table">
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Customize sorting')); ?>
</div>
<div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#apps-order-list" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
<div class="theme-undo icon icon-history btn-reset btn-reset--down" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-apps-order' => '[]',
])) ?>"></div>
<div id="apps-order-list" style="display: none">
<ul class="side-menu-setting-list">
<?php foreach ($_['ordered-apps'] as $key => $app): ?>
<li data-id="<?php echo $app['id']; ?>" class="side-menu-setting-list-item">
<span class="arrow">
⇅
</span>
<?php echo p($l->t($app['name'])); ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<input type="hidden" value='<?php echo json_encode($_['apps-order']) ?>' name="apps-order" class="side-menu-setting" id="side-menu-apps-order" data-personal>
</div>
</div>
</div>
</div>
<?php endif ?>
<div class="section">
<?php if (!$_['force']): ?>
<button id="side-menu-save" class="btn btn-primary"><?php p($l->t('Save')); ?></button>
<button id="side-menu-save" class="btn btn-info">
<?php p($l->t('Save')); ?>
<progress max="100" value="0" id="side-menu-save-progress"></progress>
</button>
<span id="side-menu-message" class="msg"></span>
@@ -167,7 +254,7 @@ $choicesYesNo = [
<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">
<a style="margin-left: 10px" target="_blank" href="https://www.buymeacoffee.com/deblan" rel="noopener">
<button>
<?php p($l->t('Buy me a coffee ☕')); ?>
</button>
+2
View File
File diff suppressed because one or more lines are too long
+48 -47
View File
@@ -3,51 +3,52 @@ const { VueLoaderPlugin } = require('vue-loader')
const StyleLintPlugin = require('stylelint-webpack-plugin')
module.exports = {
entry: {
'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),
},
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js',
filename: '[name].js?v=[hash]',
chunkFilename: 'chunks/[name]-[hash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 8192,
},
},
],
},
plugins: [
new VueLoaderPlugin(),
new StyleLintPlugin(),
],
resolve: {
extensions: ['*', '.js', '.vue'],
symlinks: false,
},
devtool: "source-map",
entry: {
'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),
},
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js',
filename: '[name].js?v=[hash]',
chunkFilename: 'chunks/[name]-[hash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 8192,
},
},
],
},
plugins: [
new VueLoaderPlugin(),
new StyleLintPlugin(),
],
resolve: {
extensions: ['*', '.js', '.vue'],
symlinks: false,
},
}