Compare commits

..

272 Commits

Author SHA1 Message Date
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
66 changed files with 3124 additions and 3309 deletions
+1
View File
@@ -4,3 +4,4 @@
/releases /releases
/package-lock.json /package-lock.json
!/l10n/.gitkeep !/l10n/.gitkeep
/yarn*.log
+5
View File
@@ -0,0 +1,5 @@
{
"rules": {
"indentation": 2
}
}
+42
View File
@@ -0,0 +1,42 @@
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:
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]
+122
View File
@@ -1,5 +1,127 @@
## [Unreleased] ## [Unreleased]
## 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 ## 1.28.0
### Added ### Added
- fix #63: add a new side menu with categories - fix #63: add a new side menu with categories
+3 -1025
View File
File diff suppressed because one or more lines are too long
+20 -7
View File
@@ -1,20 +1,28 @@
npm-build: build: dep
npm run build npm run build
npm-watch: watch: dep
npm run watch npm run watch
dep:
npm i
npm link @nextcloud/vue || sudo npm link @nextcloud/vue
.ONESHELL: .ONESHELL:
release: npm-build translations release: build translations
if [ -z "$$VERSION" ]; then if [ -z "$$VERSION" ]; then
echo "VERSION required" echo "VERSION required"
exit 1 exit 1
fi fi
test -d releases/$$VERSION && rm -fr releases/$$VERSION if [ -z "$$RELEASE_DIRECTORY" ]; then
mkdir -p releases/$$VERSION/side_menu RELEASE_DIRECTORY=releases
cp -r README.md CHANGELOG.md appinfo css lib img l10n js src templates screenshots releases/$$VERSION/side_menu fi
cd releases/$$VERSION
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 zip -r side_menu_v$$VERSION.zip side_menu
tar cvzf side_menu_v$$VERSION.tar.gz side_menu tar cvzf side_menu_v$$VERSION.tar.gz side_menu
rm -fr side_menu rm -fr side_menu
@@ -22,3 +30,8 @@ release: npm-build translations
translations: translations:
php bin/generate_l10n.php 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
+26 -6
View File
@@ -1,15 +1,19 @@
🤙 Nextcloud app / Custom menu 🎨 🤙 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. 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. This application is rather suitable for instances that activate a lot of applications.
You can customize colors depending of the theme (Dark theme and Breeze Dark). Comptatible with AppOrder. You can customize colors depending of the theme (Dark theme and Breeze Dark).
* [Installation and upgrade](#installation-and-upgrade) * [Installation and upgrade](#installation-and-upgrade)
* [How to contribute?](#how-to-contribute) * [How to contribute?](#how-to-contribute)
* [Support](#support)
* [Screenshots](https://gitnet.fr/deblan/side_menu/src/branch/master/screenshots/) * [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) or [Donate with liberapay](https://liberapay.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)
@@ -17,7 +21,7 @@ You like this app and you want to support me? ☕ [Buy me a coffee](https://www.
Requirements Requirements
------------ ------------
* PHP >= 7.3 * PHP >= 7.4
* App `theming` enabled * App `theming` enabled
Installation and upgrade Installation and upgrade
@@ -48,13 +52,29 @@ How to contribute?
You can report a bug or request a feature by opening an issue: https://gitnet.fr/deblan/side_menu/issues 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 * fork the repository
* install an instance of Nextcloud * install an instance of Nextcloud
* go to `apps/` and clone your repository * 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. 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();
}
+13 -5
View File
@@ -11,13 +11,13 @@ 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. Use the shortcut `Ctrl`+`o` to open and to hide the side menu. Use `tab` to navigate.
You can customize colors depending of the theme (Dark theme and Breeze Dark). 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. You can report a bug or request a feature by opening an issue.
Requirements: Requirements:
* PHP >= 7.3 * PHP >= 7.4
* App `theming` enabled * App `theming` enabled
If you like this application and if you want to support the development: If you like this application and if you want to support the development:
@@ -25,8 +25,14 @@ If you like this application and if you want to support the development:
* [Buy me a coffee](https://www.buymeacoffee.com/deblan) * [Buy me a coffee](https://www.buymeacoffee.com/deblan)
* [Donate with liberapay](https://liberapay.com/deblan) * [Donate with liberapay](https://liberapay.com/deblan)
* [Leave a comment](https://apps.nextcloud.com/apps/side_menu#comments) * [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> ]]></description>
<version>1.28.0</version> <version>3.2.0</version>
<licence>agpl</licence> <licence>agpl</licence>
<author mail="contact@deblan.fr" homepage="https://www.deblan.io/">Simon Vieille</author> <author mail="contact@deblan.fr" homepage="https://www.deblan.io/">Simon Vieille</author>
<namespace>SideMenu</namespace> <namespace>SideMenu</namespace>
@@ -45,9 +51,11 @@ If you like this application and if you 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/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/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/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> <dependencies>
<nextcloud min-version="18" max-version="22"/> <nextcloud min-version="25" max-version="25"/>
<php min-version="7.3"/> <php min-version="7.4"/>
</dependencies> </dependencies>
<settings> <settings>
<admin>OCA\SideMenu\Settings\Admin</admin> <admin>OCA\SideMenu\Settings\Admin</admin>
+101 -45
View File
@@ -16,106 +16,162 @@
*/ */
#side-menu-section input[type="color"] { #side-menu-section input[type="color"] {
width: 100px; width: 100px;
margin: 10px 0 10px 0; margin: 10px 0 10px 0;
padding: 0;
border-radius: 0;
} }
#side-menu-section input[type="checkbox"] { #-dropside-menu-section input[type="checkbox"] {
vertical-align: middle; vertical-align: middle;
} }
#side-menu-section input[type="range"] { #side-menu-section input[type="range"] {
vertical-align: middle; vertical-align: middle;
} }
#side-menu-section select { #side-menu-section select {
margin: 10px 0 10px 0; margin: 10px 0 10px 0;
} }
.keyboard-key { .keyboard-key {
padding: 1px 9px; padding: 1px 9px;
margin: 0 2px; margin: 0 2px;
background: #eee; background: #eee;
border: 1px solid #aaa; border: 1px solid #aaa;
color: #555; color: #555;
border-radius: 3px; border-radius: 3px;
} }
.side-menu-display { .side-menu-display {
padding: 10px; padding: 10px;
border: 2px solid transparent; border: 2px solid transparent;
max-width: 100%; max-width: 100%;
cursor: pointer; cursor: pointer;
} }
.side-menu-display.is-active { .side-menu-display.is-active {
border: 2px solid #91cb7f; border: 2px solid #91cb7f;
} }
.info { .info {
margin-top: 8px; margin-top: 8px;
padding: 5px; padding: 5px;
background: #91cb7f; background: #91cb7f;
color: #fff; color: #fff;
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
#side-menu-section h2 small { #side-menu-section h2 small {
font-size: 11px; font-size: 11px;
font-weight: normal; font-weight: normal;
} }
.side-menu-toggler { .side-menu-toggler {
cursor: pointer; cursor: pointer;
} }
.side-menu-setting-list { .side-menu-setting-list {
margin: 10px 4px 4px 0px; margin: 10px 4px 4px 0px;
border: 1px solid var(--color-border-dark);
border-radius: 15px;
} }
.side-menu-setting-list-item { .side-menu-setting-list-item {
padding: 5px 10px; padding: 5px 10px;
border: 1px solid var(--color-border-dark); border-bottom: 1px solid var(--color-border-dark);
max-width: 300px; max-width: 300px;
margin: -1px 0 0 0; margin: -1px 0 0 0;
cursor: pointer; 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 { .side-menu-setting.arrow {
color: #ccc; color: #ccc;
padding-right: 5px; padding-right: 5px;
} }
.side-menu-setting-list-item input { .side-menu-setting-list-item input {
min-height: auto; margin-top: 0;
margin-top: -1px; height: 21px !important;
min-height: auto !important;
} }
#apps-categories-custom-list select {
width: 100%;
}
.side-menu-setting-table { .side-menu-setting-table {
display: table; display: table;
width: 100%; width: 100%;
} }
.side-menu-setting-row { .side-menu-setting-row {
display: table; 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 { .side-menu-setting-label {
display: table-cell; display: table-cell;
width: 400px; width: 430px;
padding-right: 20px; padding-right: 20px;
} }
.side-menu-setting-form { .side-menu-setting-form {
display: table-cell; display: table-cell;
width: 300px; min-width: 300px;
} }
.side-menu-setting-label-short { .side-menu-setting-label-short {
width: 300px; width: 300px;
} }
.side-menu-setting-form-long { .side-menu-setting-form-long {
width: 400px; 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);
} }
+178 -155
View File
@@ -16,302 +16,325 @@
*/ */
#side-menu { #side-menu {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
height: 100vh; height: 100vh;
width: 100%; width: 100%;
max-width: 250px; max-width: 290px;
background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%); background: linear-gradient(90deg, var(--side-menu-background-color, #333) 0%, var(--side-menu-background-color-to, #333) 100%);
z-index: 3000; z-index: 3000;
color: var(--side-menu-text-color, #fff); color: var(--side-menu-text-color, #fff);
box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px; box-shadow: rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px;
display: none; display: none;
}
#side-menu a {
transition: 0.2s;
} }
#side-menu.open { #side-menu.open {
display: block; display: block;
} }
#header .side-menu-opener { #header .side-menu-opener {
margin-left: 5px; margin-left: 0px;
} }
.side-menu-settings { .side-menu-settings {
margin-right: 9px; margin-right: 9px;
margin-top: 2px; margin-top: 2px;
float: right; float: right;
line-height: 34px; line-height: 34px;
height: 28px; height: 28px;
display: none; display: none;
} }
.side-menu-settings a { .side-menu-settings a {
color: var(--side-menu-text-color, #fff); color: var(--side-menu-text-color, #fff);
display: block; display: block;
padding: 4px 7px; padding: 4px 7px;
} }
.side-menu-settings:hover a, .side-menu-settings a:active, .side-menu-settings a:focus { .side-menu-settings:hover a, .side-menu-settings a:active, .side-menu-settings a:focus {
background: var(--side-menu-current-app-background-color, #444); background: var(--side-menu-current-app-background-color, #444);
} }
.side-menu-settings img { .side-menu-settings img {
vertical-align: bottom; vertical-align: bottom;
margin-left: 3px; margin-left: 3px;
width: 32px;
height: 32px;
} }
#side-menu.open .side-menu-settings { #side-menu.open .side-menu-settings {
display: block; display: block;
} }
.side-menu-opener { .side-menu-opener {
background: var(--side-menu-opener, url('../img/side-menu-opener.svg')); background: var(--side-menu-opener, url('../img/side-menu-opener.svg'));
height: 40px; background-color: transparent !important;
width: 40px; height: 40px !important;
border-radius: 0; width: 40px !important;
border: 0; 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 { .side-menu-closer {
background: url('../img/side-menu-opener-closer.svg'); background: url('../img/side-menu-opener-closer.svg');
display: none; display: none;
} }
#side-menu.hide-opener .side-menu-opener, .side-menu-opener.hide, #side-menu.hide { #side-menu.hide-opener .side-menu-opener, .side-menu-opener.hide, #side-menu.hide {
display: none !important; display: none !important;
} }
.side-menu-apps-list { .side-menu-apps-list {
height: calc(100vh - 150px); height: calc(100vh - 150px);
z-index: 2200; z-index: 2200;
position: fixed; position: fixed;
top: 150px; top: 150px;
width: 100%; width: 100%;
max-width: 250px; max-width: 290px;
overflow: auto; overflow: auto;
} }
.side-menu-app-icon { .side-menu-app-icon {
width: 20px; width: 20px;
vertical-align: top; vertical-align: middle;
margin-right: 10px; margin-top: -4px;
filter: invert(var(--side-menu-icon-invert-filter, 0%)); margin-right: 10px;
opacity: var(--side-menu-icon-opacity, 1); filter: invert(var(--side-menu-icon-invert-filter, 0%));
} opacity: var(--side-menu-icon-opacity, 1);
.side-menu-app-icon svg {
vertical-align: middle;
margin-top: -3px;
}
.side-menu-app-icon .app-icon-notification {
display: none;
} }
.side-menu-app a { .side-menu-app a {
line-height: 30px; line-height: 30px;
color: var(--side-menu-text-color, #fff); color: var(--side-menu-text-color, #fff);
display: block; display: block;
padding: 7px 0 5px 15px; padding: 7px 0 5px 15px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.side-menu-app a:hover, .side-menu-app.active, .side-menu-app a:focus { .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 { .side-menu-logo {
text-align: center; text-align: center;
} }
.side-menu-logo img { .side-menu-logo img {
max-width: 60%; max-width: 60%;
max-height: 100px; max-height: 100px;
} }
.side-menu-header { .enu-header {
height: 150px; height: 150px;
width: 100%; width: 100%;
z-index: 2300; z-index: 2300;
max-width: 250px; max-width: 290px;
position: fixed; position: fixed;
padding-top: 2px; padding-top: 2px;
padding-left: 5px; top: 0;
top: 0; }
#side-menu.side-menu-with-categories .side-menu-header {
max-width: 295px;
} }
#side-menu.hide-opener .side-menu-logo { #side-menu.hide-opener .side-menu-logo {
margin-top: 20px; margin-top: 20px;
} }
#side-menu-loader { #side-menu-loader {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
z-index: 3001; z-index: 3001;
} }
#side-menu-loader-bar { #side-menu-loader-bar {
height: 4px; height: 4px;
background: var(--side-menu-loader-color, #0e75ac); background: var(--side-menu-loader-color, #0e75ac);
width: 0; width: 0;
transition-property: width; transition-property: width;
} }
#side-menu.side-menu-big, #side-menu.side-menu-with-categories { #side-menu.side-menu-big, #side-menu.side-menu-with-categories {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
.side-menu-big .side-menu-header, .side-menu-with-categories .side-menu-header { .side-menu-big .side-menu-header, .side-menu-with-categories .side-menu-header {
height: auto; height: auto;
} }
.side-menu-big .side-menu-apps-list, .side-menu-with-categories .side-menu-apps-list { .side-menu-big .side-menu-apps-list, .side-menu-with-categories .side-menu-apps-list {
height: auto; height: auto;
position: static; position: static;
max-width: 100vw; max-width: 100vw;
overflow: auto; overflow: auto;
} }
.side-menu-big .side-menu-app a, .side-menu-with-categories .side-menu-app a { .side-menu-big .side-menu-app a, .side-menu-with-categories .side-menu-app a {
padding: 7px 0 7px 7px; padding: 7px 0 7px 7px;
} }
.side-menu-categories-wrapper { .side-menu-categories-wrapper {
padding-bottom: 70px; padding-bottom: 70px;
} }
.side-menu-categories { .side-menu-categories {
max-height: calc(100vh - 50px); max-height: calc(100vh - 5px);
overflow: auto; overflow: auto;
position: relative; position: relative;
top: 50px; top: 5px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
padding: 0 10% 0 10%; padding: 0 10% 0 10%;
} }
.side-menu-category { .side-menu-category {
padding: 10px 20px; padding: 10px 20px;
flex: 1 1 auto; flex: 1 1 auto;
} }
.side-menu-category-title { .side-menu-category-title {
padding-left: 10px; padding-left: 10px;
color: var(--side-menu-text-color, #fff); color: var(--side-menu-text-color, #fff);
} }
.side-menu-loader { .side-menu-loader {
text-align: center; text-align: center;
} }
.side-menu-loader svg { .side-menu-loader svg {
width: 38px; width: 38px;
margin: auto; margin: auto;
stroke: var(--side-menu-text-color, #fff); stroke: var(--side-menu-text-color, #fff);
} }
.side-menu-with-categories .side-menu-app-icon, .side-menu-big .side-menu-app-icon { .side-menu-with-categories .side-menu-app-icon, .side-menu-big .side-menu-app-icon {
vertical-align: middle; vertical-align: middle;
margin-top: -2px; margin-top: -2px;
}
.side-menu-always-displayed #header,
.side-menu-always-displayed body {
width: calc(100% - 50px) !important;
} }
.side-menu-always-displayed body { .side-menu-always-displayed body {
position: absolute; width: calc(100% - 50px) !important;
left: 50px; }
.side-menu-always-displayed body {
position: absolute;
left: 50px;
} }
.side-menu-always-displayed #side-menu { .side-menu-always-displayed #side-menu {
display: block; display: block;
} }
.side-menu-always-displayed .side-menu-apps-list { .side-menu-always-displayed .side-menu-apps-list {
height: calc(100vh - 49px); height: calc(100vh - 49px);
top: 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,
.side-menu-always-displayed .side-menu-header, .side-menu-always-displayed .side-menu-header,
.side-menu-always-displayed .side-menu-apps-list { .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 #side-menu .side-menu-app-text,
.side-menu-always-displayed #header .side-menu-opener, .side-menu-always-displayed #header .side-menu-opener,
.side-menu-always-displayed .side-menu-logo { .side-menu-always-displayed .side-menu-logo {
display: none; display: none;
} }
.side-menu-always-displayed #side-menu .side-menu-header { .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-always-displayed #side-menu.open .side-menu-apps-list, .side-menu-always-displayed #side-menu.open .side-menu-apps-list,
.side-menu-always-displayed #side-menu.open .side-menu-header { .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 { .side-menu-always-displayed #side-menu.open .side-menu-app-text {
display: inline; display: inline;
} }
.side-menu-always-displayed .app-navigation--close { .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 { #side-menu.side-menu-with-categories {
max-width: 290px; max-width: 290px;
height: 100vh; height: 100vh;
} }
.side-menu-with-categories .side-menu-categories { .side-menu-with-categories .side-menu-categories {
display: block; display: block;
padding: 0; padding: 0;
} }
.side-menu-with-categories .side-menu-category { .side-menu-with-categories .side-menu-category {
padding: 10px 0; padding: 10px 0;
}
.side-menu-always-displayed #body-settings, #body-settings.body-settings-side-menu {
overflow-x: visible;
}
.app-menu {
visibility: hidden;
}
.app-menu.show {
visibility: visible;
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
#side-menu.side-menu-big { #side-menu.side-menu-big {
max-width: 290px; max-width: 290px;
} height: 100vh;
}
.side-menu-categories { .side-menu-categories {
display: block; display: block;
padding: 0; padding: 0;
} }
.side-menu-category { .side-menu-category {
padding: 10px 0; padding: 10px 0;
} }
#side-menu.side-menu-big {
height: 100vh;
}
} }
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
.side-menu-closer { .side-menu-closer {
display: block; display: block;
float: right; float: right;
margin-right: 9px; margin-right: 9px;
} }
.side-menu-big .side-menu-header { .side-menu-big .side-menu-header {
max-width: 100%; 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

+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"> <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>
<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>

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="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>
<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>

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="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>
<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>

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="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>
<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>

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="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>
<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>

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="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>
<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>

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="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>
<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>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+59 -62
View File
@@ -9,6 +9,9 @@ use OCA\SideMenu\Service\AppRepository;
use OCA\SideMenu\Service\CategoryRepository; use OCA\SideMenu\Service\CategoryRepository;
use OCA\SideMenu\Service\ConfigProxy; use OCA\SideMenu\Service\ConfigProxy;
use OCP\AppFramework\App; use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\Util; use OCP\Util;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
@@ -18,7 +21,7 @@ use Psr\Container\ContainerInterface;
* *
* @author Simon Vieille <simon@deblan.fr> * @author Simon Vieille <simon@deblan.fr>
*/ */
class Application extends App class Application extends App implements IBootstrap
{ {
public const APP_ID = 'side_menu'; public const APP_ID = 'side_menu';
@@ -44,16 +47,9 @@ class Application extends App
public function __construct(array $urlParams = []) public function __construct(array $urlParams = [])
{ {
parent::__construct(self::APP_ID, $urlParams); parent::__construct(self::APP_ID, $urlParams);
$this->config = OC::$server->getConfig();
$this->cspnm = OC::$server->getContentSecurityPolicyNonceManager();
$this->user = OC::$server[IUserSession::class]->getUser();
} }
/** protected function isEnabled(): bool
* Checks if this app is enabled.
*/
public function isEnabled(): bool
{ {
$enabled = true; $enabled = true;
$isForced = (bool) $this->config->getAppValue(self::APP_ID, 'force', '0'); $isForced = (bool) $this->config->getAppValue(self::APP_ID, 'force', '0');
@@ -74,64 +70,65 @@ class Application extends App
return $enabled; return $enabled;
} }
/** protected function addAssets()
* Registes services.
*/
public function registerServices()
{
$container = $this->getContainer();
$container->registerService('AppRepository', function (ContainerInterface $c) {
return new AppRepository();
});
$container->registerService('CategoryRepository', function (ContainerInterface $c) {
return new CategoryRepository();
});
$container->registerService('ConfigProxy', function (ContainerInterface $c) {
return new ConfigProxy();
});
}
/**
* Registers assets.
*/
public function registerAssets()
{ {
Util::addScript(self::APP_ID, 'sideMenu'); Util::addScript(self::APP_ID, 'sideMenu');
Util::addStyle(self::APP_ID, 'sideMenu'); Util::addStyle(self::APP_ID, 'sideMenu');
$stylesheet = OC::$server->getURLGenerator()->linkToRoute( $assets = [
'side_menu.Css.stylesheet', 'stylesheet' => [
[ 'route' => 'side_menu.Css.stylesheet',
'v' => $this->config->getAppValue(self::APP_ID, 'cache', '0'), 'type' => 'link',
] 'route_attr' => 'href',
); 'attr' => [
'rel' => 'stylesheet',
$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',
], ],
'' 'script' => [
); 'route' => 'side_menu.Js.script',
'type' => 'script',
Util::addHeader( 'route_attr' => 'src',
'script', 'attr' => [
[ 'nonce' => $this->cspnm->getNonce(),
'src' => $script, ],
'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() public function exportConfiguration()
{ {
$keys = $this->config->getAppKeys(Application::APP_ID); $keys = $this->config->getAppKeys(Application::APP_ID);
$config = []; $appConfig = [];
$excludedKeys = [ $excludedKeys = [
'cache', 'cache',
'cache-categories', 'cache-categories',
@@ -80,11 +80,11 @@ class AdminSettingController extends Controller
continue; continue;
} }
$config[$key] = $this->config->getAppValue(Application::APP_ID, $key); $appConfig[$key] = $this->config->getAppValue(Application::APP_ID, $key);
} }
return new DataDownloadResponse( return new DataDownloadResponse(
json_encode($config, JSON_PRETTY_PRINT), json_encode($appConfig, JSON_PRETTY_PRINT),
'config.json', 'config.json',
'text/json' 'text/json'
); );
+44 -11
View File
@@ -27,6 +27,8 @@ use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest; use OCP\IRequest;
use OCP\IUserSession; use OCP\IUserSession;
use OCA\Theming\ThemingDefaults;
use OCA\SideMenu\Service\Color;
class CssController extends Controller class CssController extends Controller
{ {
@@ -40,12 +42,30 @@ class CssController extends Controller
*/ */
protected $user; 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); parent::__construct($appName, $request);
$this->user = OC::$server[IUserSession::class]->getUser(); $this->user = OC::$server[IUserSession::class]->getUser();
$this->config = $config; $this->config = $config;
$this->theming = $theming;
$this->color = $color;
} }
/** /**
@@ -67,6 +87,7 @@ class CssController extends Controller
{ {
$isForced = $this->config->getAppValueBool('force', '0'); $isForced = $this->config->getAppValueBool('force', '0');
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]'); $topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
$topSideMenuApps = $this->config->getAppValueArray('top-side-menu-apps', '[]');
$isAccessibilityAppEnabled = $this->config->getAppValueBool('enabled', '0', 'accessibility'); $isAccessibilityAppEnabled = $this->config->getAppValueBool('enabled', '0', 'accessibility');
$isBreezeDarkAppEnabled = $this->config->getAppValueBool('enabled', '0', 'breezedark'); $isBreezeDarkAppEnabled = $this->config->getAppValueBool('enabled', '0', 'breezedark');
@@ -74,11 +95,16 @@ class CssController extends Controller
if ($this->user) { if ($this->user) {
$userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]'); $userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]');
$userTopSideMenuApps = $this->config->getUserValueArray($this->user, 'top-side-menu-apps', '[]');
if (!empty($userTopMenuApps) && !$isForced) { if (!empty($userTopMenuApps) && !$isForced) {
$topMenuApps = $userTopMenuApps; $topMenuApps = $userTopMenuApps;
} }
if (!empty($userTopSideMenuApps) && !$isForced) {
$topSideMenuApps = $userTopSideMenuApps;
}
$isDarkThemeUserEnabled = $this->config->getUserValue($this->user, 'theme', '', 'accessibility') === 'dark'; $isDarkThemeUserEnabled = $this->config->getUserValue($this->user, 'theme', '', 'accessibility') === 'dark';
$isBreezeDarkUserEnabled = $this->config->getUserValue($this->user, 'theme_enabled', '', 'breezedark'); $isBreezeDarkUserEnabled = $this->config->getUserValue($this->user, 'theme_enabled', '', 'breezedark');
@@ -90,23 +116,29 @@ class CssController extends Controller
$isDarkMode = ($isAccessibilityAppEnabled && $isDarkThemeUserEnabled) || ($isBreezeDarkAppEnabled && $isBreezeDarkUserEnabled); $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) { if ($isDarkMode) {
$backgroundColor = $this->config->getAppValue('dark-mode-background-color', '#333333'); $backgroundColor = $this->config->getAppValue('dark-mode-background-color', $darkenPrimaryColor);
$backgroundColorTo = $this->config->getAppValue('dark-mode-background-color-to', $backgroundColor); $backgroundColorTo = $this->config->getAppValue('dark-mode-background-color-to', $darkenPrimaryColor);
$currentAppBackgroundColor = $this->config->getAppValue('dark-mode-current-app-background-color', '#444444'); $currentAppBackgroundColor = $this->config->getAppValue('dark-mode-current-app-background-color', $darkenPrimaryColor2);
$loaderColor = $this->config->getAppValue('dark-mode-loader-color', '#cccccc'); $loaderColor = $this->config->getAppValue('dark-mode-loader-color', $lightenPrimaryColor);
$textColor = $this->config->getAppValue('dark-mode-text-color', '#FFFFFF'); $textColor = $this->config->getAppValue('dark-mode-text-color', $textColor);
$iconInvertFilter = abs($this->config->getAppValueInt('dark-mode-icon-invert-filter', '0')).'%'; $iconInvertFilter = abs($this->config->getAppValueInt('dark-mode-icon-invert-filter', '0')).'%';
$iconOpacity = abs($this->config->getAppValueInt('dark-mode-icon-opacity', '100') / 100); $iconOpacity = abs($this->config->getAppValueInt('dark-mode-icon-opacity', '100') / 100);
$opener = $this->config->getAppValue('dark-mode-opener', 'side-menu-opener'); $opener = $this->config->getAppValue('dark-mode-opener', 'side-menu-opener');
$backgroundOpacity = dechex($this->config->getAppValueInt('dark-mode-background-color-opacity', '100') * 255 / 100); $backgroundOpacity = dechex($this->config->getAppValueInt('dark-mode-background-color-opacity', '100') * 255 / 100);
} else { } else {
$backgroundColor = $this->config->getAppValue('background-color', '#333333'); $backgroundColor = $this->config->getAppValue('background-color', $darkenPrimaryColor);
$backgroundColorTo = $this->config->getAppValue('background-color-to', $backgroundColor); $backgroundColorTo = $this->config->getAppValue('background-color-to', $darkenPrimaryColor);
$currentAppBackgroundColor = $this->config->getAppValue('current-app-background-color', '#444444'); $currentAppBackgroundColor = $this->config->getAppValue('current-app-background-color', $darkenPrimaryColor2);
$loaderColor = $this->config->getAppValue('loader-color', '#0e75ac'); $loaderColor = $this->config->getAppValue('loader-color', $lightenPrimaryColor);
$textColor = $this->config->getAppValue('text-color', '#FFFFFF'); $textColor = $this->config->getAppValue('text-color', $textColor);
$iconInvertFilter = abs($this->config->getAppValueInt('icon-invert-filter', '0')).'%'; $iconInvertFilter = abs($this->config->getAppValueInt('icon-invert-filter', '0')).'%';
$iconOpacity = abs($this->config->getAppValueInt('icon-opacity', '100') / 100); $iconOpacity = abs($this->config->getAppValueInt('icon-opacity', '100') / 100);
$opener = $this->config->getAppValue('opener', 'side-menu-opener'); $opener = $this->config->getAppValue('opener', 'side-menu-opener');
@@ -136,6 +168,7 @@ class CssController extends Controller
'always-displayed' => $this->config->getAppValueBool('always-displayed', '0'), 'always-displayed' => $this->config->getAppValueBool('always-displayed', '0'),
'big-menu' => $this->config->getAppValueBool('big-menu', '0'), 'big-menu' => $this->config->getAppValueBool('big-menu', '0'),
'top-menu-apps' => $topMenuApps, 'top-menu-apps' => $topMenuApps,
'top-side-menu-apps' => $topSideMenuApps,
]; ];
} }
} }
+9
View File
@@ -94,6 +94,8 @@ class JsController extends Controller
protected function getConfig(): array protected function getConfig(): array
{ {
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]'); $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', '[]'); $targetBlankApps = $this->config->getAppValueArray('target-blank-apps', '[]');
$useAvatar = $this->config->getAppValueBool('use-avatar', '0'); $useAvatar = $this->config->getAppValueBool('use-avatar', '0');
$isForced = $this->config->getAppValueBool('force', '0'); $isForced = $this->config->getAppValueBool('force', '0');
@@ -103,11 +105,16 @@ class JsController extends Controller
if ($this->user) { if ($this->user) {
$userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]'); $userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]');
$userTopSideMenuApps = $this->config->getUserValueArray($this->user, 'top-side-menu-apps', '[]');
if (!empty($userTopMenuApps) && !$isForced) { if (!empty($userTopMenuApps) && !$isForced) {
$topMenuApps = $userTopMenuApps; $topMenuApps = $userTopMenuApps;
} }
if (!empty($userTopSideMenuApps) && !$isForced) {
$topSideMenuApps = $userTopSideMenuApps;
}
$userTargetBlankMode = $this->config->getUserValueInt($this->user, 'target-blank-mode', '1'); $userTargetBlankMode = $this->config->getUserValueInt($this->user, 'target-blank-mode', '1');
$userTargetBlankApps = $this->config->getUserValueArray($this->user, 'target-blank-apps', '[]'); $userTargetBlankApps = $this->config->getUserValueArray($this->user, 'target-blank-apps', '[]');
@@ -155,8 +162,10 @@ class JsController extends Controller
'side-with-categories' => $this->config->getAppValueBool('side-with-categories', '0'), 'side-with-categories' => $this->config->getAppValueBool('side-with-categories', '0'),
'big-menu' => $this->config->getAppValueBool('big-menu', '0'), 'big-menu' => $this->config->getAppValueBool('big-menu', '0'),
'big-menu-hidden-apps' => $this->config->getAppValueArray('big-menu-hidden-apps', '[]'), 'big-menu-hidden-apps' => $this->config->getAppValueArray('big-menu-hidden-apps', '[]'),
'apps-order' => $this->config->getAppValueArray('apps-order', '[]'),
'avatar' => $avatar, 'avatar' => $avatar,
'top-menu-apps' => $topMenuApps, 'top-menu-apps' => $topMenuApps,
'top-side-menu-apps' => $topSideMenuApps,
'target-blank-apps' => $targetBlankApps, 'target-blank-apps' => $targetBlankApps,
'settings' => $settings, 'settings' => $settings,
'logo' => $this->themingDefaults->getLogo(), 'logo' => $this->themingDefaults->getLogo(),
+10 -5
View File
@@ -93,7 +93,7 @@ class NavController extends Controller
]); ]);
} }
$apps = $this->appRepository->getVisibleApps(); $apps = $this->appRepository->getOrderedApps();
$categoriesLabels = $this->categoryRepository->getOrderedCategories(); $categoriesLabels = $this->categoryRepository->getOrderedCategories();
$hiddenApps = $this->config->getAppValueArray('big-menu-hidden-apps', '[]'); $hiddenApps = $this->config->getAppValueArray('big-menu-hidden-apps', '[]');
$isForced = $this->config->getAppValueBool('force', '0'); $isForced = $this->config->getAppValueBool('force', '0');
@@ -178,18 +178,23 @@ class NavController extends Controller
foreach ($items as $category => $value) { foreach ($items as $category => $value) {
if (empty($items[$category]['apps'])) { if (empty($items[$category]['apps'])) {
unset($items[$category]); unset($items[$category]);
} else {
uasort($items[$category]['apps'], function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
} }
} }
usort($items, function ($a, $b) use ($categoriesLabels) { usort($items, function ($a, $b) use ($categoriesLabels) {
foreach ($categoriesLabels as $key => $value) { foreach ($categoriesLabels as $key => $value) {
if ($a['categoryId'] === 'other') {
return -1;
}
if ($b['categoryId'] === 'other') {
return 1;
}
if ($a['categoryId'] === $key) { if ($a['categoryId'] === $key) {
return -1; return -1;
} }
if ($b['categoryId'] === $key) { if ($b['categoryId'] === $key) {
return 1; return 1;
} }
+2 -1
View File
@@ -54,6 +54,7 @@ class PersonalSettingController extends Controller
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired
* *
* @param mixed $name * @param mixed $name
* @param mixed $value * @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'])) {
$doSave = true; $doSave = true;
$data = json_decode($value, true); $data = json_decode($value, true);
+56 -8
View File
@@ -21,10 +21,26 @@ class AppRepository
*/ */
protected $l10nFactory; 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->ocApp = $ocApp;
$this->l10nFactory = $l10nFactory; $this->l10nFactory = $l10nFactory;
$this->config = $config;
$this->categoryRepository = $categoryRepository;
} }
/** /**
@@ -35,6 +51,8 @@ class AppRepository
public function getVisibleApps() public function getVisibleApps()
{ {
$navigation = $this->ocApp->getNavigation(); $navigation = $this->ocApp->getNavigation();
$appCategoriesCustom = $this->config->getAppValueArray('apps-categories-custom', '[]');
$categories = $this->categoryRepository->getOrderedCategories();
$apps = $this->ocApp->listAllApps(); $apps = $this->ocApp->listAllApps();
$visibleApps = []; $visibleApps = [];
@@ -43,7 +61,7 @@ class AppRepository
foreach ([$app['id'], $app['id'].'_index'] as $id) { foreach ([$app['id'], $app['id'].'_index'] as $id) {
if (isset($navigation[$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['href'] = $navigation[$id]['href'];
$app['icon'] = $navigation[$id]['icon']; $app['icon'] = $navigation[$id]['icon'];
@@ -56,7 +74,7 @@ class AppRepository
if ('external_index' === substr($app['id'], 0, 14)) { if ('external_index' === substr($app['id'], 0, 14)) {
$visibleApps[$app['id']] = [ $visibleApps[$app['id']] = [
'id' => $app['id'], 'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']), 'name' => $this->getAppName($app),
'href' => $app['href'], 'href' => $app['href'],
'icon' => $app['icon'], 'icon' => $app['icon'],
'category' => [ 'category' => [
@@ -66,7 +84,7 @@ class AppRepository
} elseif ('files' === $app['id']) { } elseif ('files' === $app['id']) {
$visibleApps[$app['id']] = [ $visibleApps[$app['id']] = [
'id' => $app['id'], 'id' => $app['id'],
'name' => $this->l10nFactory->get($app['id'])->t($app['name']), 'name' => $this->getAppName($app),
'href' => $app['href'], 'href' => $app['href'],
'icon' => $app['icon'], 'icon' => $app['icon'],
'category' => [], 'category' => [],
@@ -74,10 +92,40 @@ class AppRepository
} }
} }
usort($visibleApps, function ($a, $b) { foreach ($visibleApps as $id => $app) {
return ($a['name'] < $b['name']) ? -1 : 1; if (isset($appCategoriesCustom[$id], $categories[$appCategoriesCustom[$id]])) {
}); $visibleApps[$id]['category'] = [$appCategoriesCustom[$id]];
}
}
return $visibleApps; 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()
{
$apps = $this->getVisibleApps();
$orders = $this->config->getAppValueArray('apps-order', '[]');
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;
}
} }
+22 -2
View File
@@ -5,6 +5,7 @@ namespace OCA\SideMenu\Service;
use OC\App\AppStore\Fetcher\CategoryFetcher; use OC\App\AppStore\Fetcher\CategoryFetcher;
use OCA\SideMenu\AppInfo\Application; use OCA\SideMenu\AppInfo\Application;
use OCP\IConfig; use OCP\IConfig;
use OCP\IUserSession;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
/** /**
@@ -34,16 +35,23 @@ class CategoryRepository
*/ */
protected $iConfig; protected $iConfig;
/**
* @var IUserSession
*/
protected $userSession;
public function __construct( public function __construct(
CategoryFetcher $categoryFetcher, CategoryFetcher $categoryFetcher,
ConfigProxy $config, ConfigProxy $config,
IConfig $iConfig, IConfig $iConfig,
IFactory $l10nFactory IFactory $l10nFactory,
IUserSession $userSession
) { ) {
$this->categoryFetcher = $categoryFetcher; $this->categoryFetcher = $categoryFetcher;
$this->l10nFactory = $l10nFactory; $this->l10nFactory = $l10nFactory;
$this->config = $config; $this->config = $config;
$this->iConfig = $iConfig; $this->iConfig = $iConfig;
$this->userSession = $userSession;
} }
/** /**
@@ -56,8 +64,8 @@ class CategoryRepository
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2); $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$type = $this->config->getAppValue('categories-order-type', 'default'); $type = $this->config->getAppValue('categories-order-type', 'default');
$order = $this->config->getAppValueArray('categories-order', '[]'); $order = $this->config->getAppValueArray('categories-order', '[]');
$categoriesLabels = $this->config->getAppValueArray('cache-categories', '[]'); $categoriesLabels = $this->config->getAppValueArray('cache-categories', '[]');
$customCategories = $this->config->getAppValueArray('categories-custom', '[]');
if (empty($categoriesLabels)) { if (empty($categoriesLabels)) {
$categoriesLabels = $this->categoryFetcher->get(); $categoriesLabels = $this->categoryFetcher->get();
@@ -74,6 +82,18 @@ class CategoryRepository
$categoriesLabels['external_links'] = $this->l10nFactory->get('external')->t('External sites'); $categoriesLabels['external_links'] = $this->l10nFactory->get('external')->t('External sites');
$categoriesLabels['other'] = ''; $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); asort($categoriesLabels);
if ('custom' === $type) { if ('custom' === $type) {
+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);
}
}
+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;
}
}
+60 -12
View File
@@ -26,6 +26,9 @@ use OCP\AppFramework\Http\TemplateResponse;
use OCP\IL10N; use OCP\IL10N;
use OCP\ILogger; use OCP\ILogger;
use OCP\Settings\ISettings; use OCP\Settings\ISettings;
use OCA\Theming\ThemingDefaults;
use OCA\SideMenu\Service\Color;
use OCA\SideMenu\Service\LangRepository;
class Admin implements ISettings class Admin implements ISettings
{ {
@@ -54,18 +57,39 @@ class Admin implements ISettings
*/ */
private $categoryRepository; private $categoryRepository;
/**
* @var ThemingDefaults
*/
protected $theming;
/**
* @var Color
*/
protected $color;
/**
* @var LangRepository
*/
protected $langRepository;
public function __construct( public function __construct(
IL10N $l, IL10N $l,
ILogger $logger, ILogger $logger,
ConfigProxy $config, ConfigProxy $config,
AppRepository $appRepository, AppRepository $appRepository,
CategoryRepository $categoryRepository CategoryRepository $categoryRepository,
ThemingDefaults $theming,
Color $color,
LangRepository $langRepository
) { ) {
$this->l = $l; $this->l = $l;
$this->logger = $logger; $this->logger = $logger;
$this->config = $config; $this->config = $config;
$this->appRepository = $appRepository; $this->appRepository = $appRepository;
$this->categoryRepository = $categoryRepository; $this->categoryRepository = $categoryRepository;
$this->theming = $theming;
$this->color = $color;
$this->langRepository = $langRepository;
} }
/** /**
@@ -73,29 +97,47 @@ class Admin implements ISettings
*/ */
public function getForm() public function getForm()
{ {
$backgroundColor = $this->config->getAppValue('background-color', '#333333'); $primaryColor = $this->theming->getColorPrimary();
$backgroundColorTo = $this->config->getAppValue('background-color-to', $backgroundColor); $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();
$darkModeBackgroundColor = $this->config->getAppValue('dark-mode-background-color', '#333333'); $backgroundColor = $this->config->getAppValue('background-color', $darkenPrimaryColor);
$darkModeBackgroundColorTo = $this->config->getAppValue('dark-mode-background-color-to', $darkModeBackgroundColor); $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 = [ $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' => $backgroundColor,
'background-color-to' => $backgroundColorTo, 'background-color-to' => $backgroundColorTo,
'background-color-opacity' => $this->config->getAppValueInt('background-color-opacity', '100'), 'background-color-opacity' => $this->config->getAppValueInt('background-color-opacity', '100'),
'current-app-background-color' => $this->config->getAppValue('current-app-background-color', '#444444'), 'current-app-background-color' => $this->config->getAppValue('current-app-background-color', $darkenPrimaryColor2),
'loader-color' => $this->config->getAppValue('loader-color', '#0e75ac'), 'loader-color' => $this->config->getAppValue('loader-color', $lightenPrimaryColor),
'icon-invert-filter' => $this->config->getAppValueInt('icon-invert-filter', '0'), 'icon-invert-filter' => $this->config->getAppValueInt('icon-invert-filter', '0'),
'icon-opacity' => $this->config->getAppValueInt('icon-opacity', '100'), 'icon-opacity' => $this->config->getAppValueInt('icon-opacity', '100'),
'text-color' => $this->config->getAppValue('text-color', '#FFFFFF'), 'text-color' => $this->config->getAppValue('text-color', $textColor),
'dark-mode-background-color' => $darkModeBackgroundColor, 'dark-mode-background-color' => $darkModeBackgroundColor,
'dark-mode-background-color-to' => $darkModeBackgroundColorTo, 'dark-mode-background-color-to' => $darkModeBackgroundColorTo,
'dark-mode-background-color-opacity' => $this->config->getAppValueInt('dark-mode-background-color-opacity', '100'), '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', '#444444'), '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', '#cccccc'), '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-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-icon-opacity' => $this->config->getAppValueInt('dark-mode-icon-opacity', '100'),
'dark-mode-text-color' => $this->config->getAppValue('dark-mode-text-color', '#FFFFFF'), 'dark-mode-text-color' => $this->config->getAppValue('dark-mode-text-color', $textColor),
'dark-mode-opener' => $this->config->getAppValue('dark-mode-opener', 'side-menu-opener'), 'dark-mode-opener' => $this->config->getAppValue('dark-mode-opener', 'side-menu-opener'),
'opener' => $this->config->getAppValue('opener', 'side-menu-opener'), 'opener' => $this->config->getAppValue('opener', 'side-menu-opener'),
'loader-enabled' => $this->config->getAppValue('loader-enabled', '1'), 'loader-enabled' => $this->config->getAppValue('loader-enabled', '1'),
@@ -117,11 +159,17 @@ class Admin implements ISettings
'force' => $this->config->getAppValue('force', '0'), 'force' => $this->config->getAppValue('force', '0'),
'target-blank-apps' => $this->config->getAppValueArray('target-blank-apps', '[]'), 'target-blank-apps' => $this->config->getAppValueArray('target-blank-apps', '[]'),
'top-menu-apps' => $this->config->getAppValueArray('top-menu-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'), '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-type' => $this->config->getAppValue('categories-order-type', 'default'),
'categories-order' => $this->config->getAppValueArray('categories-order', '[]'), 'categories-order' => $this->config->getAppValueArray('categories-order', '[]'),
'apps' => $this->appRepository->getVisibleApps(), 'categories-custom' => $this->config->getAppValueArray('categories-custom', '[]'),
'categories' => $this->categoryRepository->getOrderedCategories(), 'categories' => $this->categoryRepository->getOrderedCategories(),
'langs' => $this->langRepository->getUsedLangs(),
]; ];
return new TemplateResponse(Application::APP_ID, 'settings/admin-form', $parameters, ''); return new TemplateResponse(Application::APP_ID, 'settings/admin-form', $parameters, '');
+1
View File
@@ -78,6 +78,7 @@ class Personal implements ISettings
$this->config->getAppValue('default-enabled', '1') $this->config->getAppValue('default-enabled', '1')
), ),
'top-menu-apps' => $this->config->getUserValueArray($user, 'top-menu-apps', '[]'), '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-mode' => $this->config->getUserValue($user, 'target-blank-mode', '1'),
'target-blank-apps' => $this->config->getUserValueArray($user, 'target-blank-apps', '[]'), 'target-blank-apps' => $this->config->getUserValueArray($user, 'target-blank-apps', '[]'),
'apps' => $this->appRepository->getVisibleApps(), 'apps' => $this->appRepository->getVisibleApps(),
+31 -28
View File
@@ -2,58 +2,61 @@
"license": "agpl", "license": "agpl",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "NODE_ENV=production webpack --progress --hide-modules --config webpack.js", "build": "NODE_ENV=production ./node_modules/.bin/webpack-cli --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js", "dev": "NODE_ENV=development ./node_modules/.bin/webpack-cli --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js", "watch": "NODE_ENV=development ./node_modules/.bin/webpack-cli --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src", "lint": "./node_modules/.bin/eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix", "lint:fix": "./node_modules/.bin/eslint --ext .js,.vue src --fix",
"stylelint": "stylelint src", "stylelint": "./node_modules/.bin/stylelint src",
"stylelint:fix": "stylelint src --fix" "stylelint:fix": "./node_modules/.bin/stylelint src --fix"
}, },
"dependencies": { "dependencies": {
"@nextcloud/axios": "^1.3.2", "axios": "^0.24.0",
"@nextcloud/vue": "^1.4.0", "trim": "^1.0.1",
"axios": "^0.19.2",
"trim": "0.0.1",
"vue": "^2.6.11" "vue": "^2.6.11"
}, },
"browserslist": [ "browserslist": [
"extends @nextcloud/browserslist-config" "extends @nextcloud/browserslist-config"
], ],
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=16.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.0", "@babel/core": "^7.9.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.0", "@babel/preset-env": "^7.9.0",
"@nextcloud/axios": "^1.8.0",
"@nextcloud/browserslist-config": "^1.0.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-eslint": "^10.1.0",
"babel-loader": "^8.1.0", "babel-loader": "^8.1.0",
"css-loader": "^3.4.2", "css-loader": "^3.4.2",
"eslint": "^5.16.0", "eslint": "^8.0.0",
"eslint-config-nextcloud": "0.1.1", "eslint-config-standard": "^17.0.0",
"eslint-config-standard": "^12.0.0",
"eslint-import-resolver-webpack": "^0.12.1", "eslint-import-resolver-webpack": "^0.12.1",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.0", "eslint-plugin-import": "^2.20.0",
"eslint-plugin-nextcloud": "^0.3.0", "eslint-plugin-nextcloud": "^0.3.0",
"eslint-plugin-node": "^10.0.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-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", "file-loader": "^6.0.0",
"node-sass": "^4.13.1", "sass": "^1.49.9",
"sass-loader": "^8.0.2", "sass-loader": "^13.0.2",
"stylelint": "^8.4.0", "stylelint": "^14.0.0",
"stylelint-config-recommended-scss": "^3.3.0", "stylelint-config-recommended-scss": "^7.0.0",
"stylelint-scss": "^3.16.0", "stylelint-scss": "^4.0.0",
"stylelint-webpack-plugin": "^0.10.5", "stylelint-webpack-plugin": "^3.3.0",
"url-loader": "^4.0.0", "url-loader": "^4.0.0",
"vue-loader": "^15.9.1", "vue-loader": "^15",
"vue-template-compiler": "^2.6.11", "vue-style-loader": "^4.1.3",
"webpack": "^4.42.0", "vue-template-compiler": "^2.7.13",
"webpack-cli": "^3.3.11", "webpack": "^5.0.0",
"webpack-cli": "^4.0.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-node-externals": "^1.7.2" "webpack-node-externals": "^1.7.2"
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 321 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: 57 KiB

+175
View File
@@ -0,0 +1,175 @@
<!--
@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">
<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>
<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>
+309
View File
@@ -0,0 +1,309 @@
<!--
- @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)"
: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,
}
},
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.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>
+2 -2
View File
@@ -15,11 +15,11 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<button class="side-menu-opener side-menu-closer"></button> <button class="side-menu-opener side-menu-closer"></button>
</template> </template>
<script> <script>
export default { export default {
name: 'CloserButton', name: 'CloserButton',
} }
</script> </script>
+19 -19
View File
@@ -15,28 +15,28 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div class="side-menu-loader"> <div class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg"> <svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2"> <g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/> <circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18"> <path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform <animateTransform
attributeName="transform" attributeName="transform"
type="rotate" type="rotate"
from="0 18 18" from="0 18 18"
to="360 18 18" to="360 18 18"
dur="1s" dur="1s"
repeatCount="indefinite"/> repeatCount="indefinite"/>
</path> </path>
</g> </g>
</g> </g>
</svg> </svg>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'Loader', name: 'Loader',
} }
</script> </script>
+20 -20
View File
@@ -15,30 +15,30 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div v-bind:class="classes"> <div v-bind:class="classes">
<a v-if="link !== null" v-bind:href="link"> <a v-if="link !== null" v-bind:href="link">
<img v-bind:src="image"> <img v-bind:src="image" alt="Logo">
</a> </a>
<img v-else v-bind:src="image"> <img v-else v-bind:src="image" alt="Logo">
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'Logo', name: 'Logo',
props: { props: {
image: { image: {
type: String, type: String,
required: true required: true
},
link: {
type: String,
required: false
},
classes: {
type: Object,
required: true
},
}, },
link: {
type: String,
required: false
},
classes: {
type: Object,
required: true
},
},
} }
</script> </script>
+2 -2
View File
@@ -15,11 +15,11 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<button class="side-menu-opener"></button> <button class="side-menu-opener"></button>
</template> </template>
<script> <script>
export default { export default {
name: 'OpenerButton', name: 'OpenerButton',
} }
</script> </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
+22 -22
View File
@@ -15,33 +15,33 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div class="side-menu-settings"> <div class="side-menu-settings">
<a v-bind:href="href"> <a v-bind:href="href">
{{ label }} {{ label }}
<span class="avatardiv avatardiv-shown"> <span class="avatardiv avatardiv-shown">
<img v-bind:src="avatar" v-bind:alt="name" v-bind:title="name"> <img v-bind:src="avatar">
</span> </span>
</a> </a>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'SettingsButton', name: 'SettingsButton',
props: { props: {
label: { label: {
type: String, type: String,
required: true required: true
},
href: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
}, },
href: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
},
} }
</script> </script>
+39 -18
View File
@@ -16,35 +16,56 @@
*/ */
import Vue from 'vue' import Vue from 'vue'
import AppMenu from './AppMenu.vue'
import SideMenu from './SideMenu.vue' import SideMenu from './SideMenu.vue'
import SideMenuBig from './SideMenuBig.vue' import SideMenuBig from './SideMenuBig.vue'
import SideMenuWithCategories from './SideMenuWithCategories.vue' import SideMenuWithCategories from './SideMenuWithCategories.vue'
import PageLoader from './PageLoader'
import SMcreateElement from './lib/createElement'
Vue.prototype.OC = OC Vue.prototype.OC = OC
Vue.prototype.t = OC.L10N.translate
window.SMcreateElement = SMcreateElement
window.PageLoader = PageLoader
const mountSideMenuComponent = () => { const mountSideMenuComponent = () => {
const sideMenuContainer = document.querySelector('#side-menu') const container = document.querySelector('#side-menu')
if (sideMenuContainer) { if (!container) {
let component return window.setTimeout(mountSideMenuComponent, 50)
}
if (sideMenuContainer.getAttribute('data-bigmenu')) { const component = (() => {
component = SideMenuBig if (container.getAttribute('data-bigmenu')) {
} else if(sideMenuContainer.getAttribute('data-sidewithcategories')) { return SideMenuBig
component = SideMenuWithCategories } else if(container.getAttribute('data-sidewithcategories')) {
} else { return SideMenuWithCategories
component = SideMenu
}
const View = Vue.extend(component)
const sideMenu = new View({})
sideMenu.$mount('#side-menu')
$('body').trigger('side-menu.ready')
} else { } 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() mountSideMenuComponent()
mountAppMenu()
+104 -131
View File
@@ -15,40 +15,41 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div id="side-menu"> <div id="side-menu">
<div class="side-menu-header"> <div class="side-menu-header">
<SettingsButton <SettingsButton
v-if="settings" v-if="settings"
v-bind:href="settings.href" v-bind:href="settings.href"
v-bind:label="settings.name" v-bind:label="settings.name"
v-bind:avatar="settings.avatar" /> v-bind:avatar="settings.avatar" />
<OpenerButton /> <OpenerButton />
<Logo <Logo
v-if="!avatar && logo" v-bind:classes="{'side-menu-logo': true, 'avatardiv': false}" v-if="!avatar && logo" v-bind:classes="{'side-menu-logo': true, 'avatardiv': false}"
v-bind:image="logo" v-bind:image="logo"
v-bind:link="logoLink" v-bind:link="logoLink"
/> />
<Logo <Logo
v-if="avatar" v-bind:classes="{'side-menu-logo': true, 'avatardiv': true}" v-if="avatar" v-bind:classes="{'side-menu-logo': true, 'avatardiv': true}"
v-bind:image="avatar" v-bind:image="avatar"
v-bind:link="logoLink" v-bind:link="logoLink"
/> />
</div>
<ul class="side-menu-apps-list">
<SideMenuApp
v-for="app in apps"
v-bind:classes="{'side-menu-app': true, 'active': app.active}"
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> </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> </template>
<script> <script>
@@ -58,109 +59,81 @@ import OpenerButton from './OpenerButton'
import SettingsButton from './SettingsButton' import SettingsButton from './SettingsButton'
import SideMenuApp from './SideMenuApp' import SideMenuApp from './SideMenuApp'
import Logo from './Logo' import Logo from './Logo'
import { loadState } from '@nextcloud/initial-state'
export default { export default {
name: 'SideMenu', name: 'SideMenu',
components: { components: {
SettingsButton, SettingsButton,
OpenerButton, OpenerButton,
SideMenuApp, SideMenuApp,
Logo, Logo,
}, },
data() { data() {
return { return {
apps: [], apps: [],
logo: null, logo: null,
logoLink: null, logoLink: null,
avatar: null, avatar: null,
forceLightIcon: false, forceLightIcon: false,
targetBlankApps: [], targetBlankApps: [],
settings: null, settings: null,
}
},
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']
that.logoLink = config['logo-link']
that.settings = config['settings']
});
},
},
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)
}
} }
},
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> </script>
+28 -28
View File
@@ -15,38 +15,38 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<li v-bind:class="classes"> <li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label"> <a v-bind:href="href" :target="target" v-bind:title="label">
<span class="side-menu-app-icon" v-html="icon"></span> <img class="side-menu-app-icon" v-bind:src="icon" v-bind:alt="label" />
<span class="side-menu-app-text" v-html="label"></span> <span class="side-menu-app-text" v-text="label"></span>
</a> </a>
</li> </li>
</template> </template>
<script> <script>
export default { export default {
name: 'SideMenuApp', name: 'SideMenuApp',
props: { props: {
label: { label: {
type: String, type: String,
required: true required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
}, },
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
} }
</script> </script>
+90 -94
View File
@@ -15,45 +15,45 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div id="side-menu" class="side-menu-big"> <div id="side-menu" class="side-menu-big">
<div class="side-menu-header"> <div class="side-menu-header">
<CloserButton /> <CloserButton />
<SettingsButton <SettingsButton
v-if="settings" v-if="settings"
v-bind:href="settings.href" v-bind:href="settings.href"
v-bind:label="settings.name" v-bind:label="settings.name"
v-bind:avatar="settings.avatar" v-bind:avatar="settings.avatar"
/> />
<OpenerButton /> <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 in items">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-html="category.name"></h2>
<ul class="side-menu-apps-list">
<SideMenuBigApp
v-for="(app, appId) in category.apps"
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> </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> </template>
<script> <script>
import trim from 'trim'
import axios from 'axios' import axios from 'axios'
import OpenerButton from './OpenerButton' import OpenerButton from './OpenerButton'
import CloserButton from './CloserButton' import CloserButton from './CloserButton'
@@ -62,67 +62,63 @@ import Loader from './Loader'
import SideMenuBigApp from './SideMenuBigApp' import SideMenuBigApp from './SideMenuBigApp'
export default { export default {
name: 'SideMenuBig', name: 'SideMenuBig',
components: { components: {
SettingsButton, SettingsButton,
OpenerButton, OpenerButton,
CloserButton, CloserButton,
Loader, Loader,
SideMenuBigApp, SideMenuBigApp,
}, },
data() { data() {
return { return {
items: [], items: [],
activeApp: null, activeApp: null,
targetBlank: false, targetBlank: false,
targetBlankApps: [], targetBlankApps: [],
settings: null, settings: null,
}
},
methods: {
retrieveApps() {
this.apps = []
let that = this
axios
.get(OC.generateUrl('/apps/side_menu/nav/items'))
.then(function(response) {
that.items = response.data.items
let apps = []
for (let category of that.items) {
for (let a in category.apps) {
apps.push(category.apps[a])
}
}
jQuery('body').trigger('side-menu.apps', [apps])
});
},
retrieveActiveApp() {
let activeAppLink = document.querySelector('#appmenu a.active')
this.activeApp = activeAppLink ? activeAppLink.parentNode.getAttribute('data-id') : null
},
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.settings = config['settings']
});
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
this.retrieveActiveApp()
} }
},
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() {
let activeAppLink = document.querySelector('#appmenu a.active')
this.activeApp = activeAppLink ? activeAppLink.parentNode.getAttribute('data-id') : null
},
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> </script>
+28 -28
View File
@@ -15,38 +15,38 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<li v-bind:class="classes"> <li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label"> <a v-bind:href="href" :target="target" v-bind:title="label">
<img class="side-menu-app-icon" v-bind:src="icon"></span> <img class="side-menu-app-icon" v-bind:src="icon" v-bind:alt="label" />
<span class="side-menu-app-text" v-html="label"></span> <span class="side-menu-app-text" v-text="label"></span>
</a> </a>
</li> </li>
</template> </template>
<script> <script>
export default { export default {
name: 'SideMenuBigApp', name: 'SideMenuBigApp',
props: { props: {
label: { label: {
type: String, type: String,
required: true required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
}, },
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
} }
</script> </script>
+89 -93
View File
@@ -15,43 +15,43 @@ 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div id="side-menu" class="side-menu-with-categories"> <div id="side-menu" class="side-menu-with-categories">
<div class="side-menu-header"> <div class="side-menu-header">
<SettingsButton <SettingsButton
v-if="settings" v-if="settings"
v-bind:href="settings.href" v-bind:href="settings.href"
v-bind:label="settings.name" v-bind:label="settings.name"
v-bind:avatar="settings.avatar" v-bind:avatar="settings.avatar"
/> />
<OpenerButton /> <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 in items">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-html="category.name"></h2>
<ul class="side-menu-apps-list">
<SideMenuBigApp
v-for="(app, appId) in category.apps"
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> </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> </template>
<script> <script>
import trim from 'trim'
import axios from 'axios' import axios from 'axios'
import OpenerButton from './OpenerButton' import OpenerButton from './OpenerButton'
import CloserButton from './CloserButton' import CloserButton from './CloserButton'
@@ -60,67 +60,63 @@ import Loader from './Loader'
import SideMenuBigApp from './SideMenuBigApp' import SideMenuBigApp from './SideMenuBigApp'
export default { export default {
name: 'SideMenuWithCategories', name: 'SideMenuWithCategories',
components: { components: {
SettingsButton, SettingsButton,
OpenerButton, OpenerButton,
CloserButton, CloserButton,
Loader, Loader,
SideMenuBigApp, SideMenuBigApp,
}, },
data() { data() {
return { return {
items: [], items: [],
activeApp: null, activeApp: null,
targetBlank: false, targetBlank: false,
targetBlankApps: [], targetBlankApps: [],
settings: null, settings: null,
}
},
methods: {
retrieveApps() {
this.apps = []
let that = this
axios
.get(OC.generateUrl('/apps/side_menu/nav/items'))
.then(function(response) {
that.items = response.data.items
let apps = []
for (let category of that.items) {
for (let a in category.apps) {
apps.push(category.apps[a])
}
}
jQuery('body').trigger('side-menu.apps', [apps])
});
},
retrieveActiveApp() {
let activeAppLink = document.querySelector('#appmenu a.active')
this.activeApp = activeAppLink ? activeAppLink.parentNode.getAttribute('data-id') : null
},
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.settings = config['settings']
});
},
},
mounted() {
this.retrieveConfig()
this.retrieveApps()
this.retrieveActiveApp()
} }
},
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() {
let activeAppLink = document.querySelector('#appmenu a.active')
this.activeApp = activeAppLink ? activeAppLink.parentNode.getAttribute('data-id') : null
},
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> </script>
+224 -107
View File
@@ -15,151 +15,268 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * 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 = [] let elements = []
const selector = '#side-menu-message'; const selector = '#side-menu-message'
const userConfig = (name, value, callbacks) => { 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) formData.push('name=' + encodeURIComponent(name))
.fail(callbacks.error) 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) => { 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 saveSettings = (key) => {
const element = elements.get(key) const element = elements[key]
let value
let name
if (jQuery(element).is('[data-checkbox]')) { if (!element) {
name = jQuery(element).attr('data-name') return
const inputs = jQuery('input[name="' + name + '[]"]:checked') }
value = []
inputs.each((i, v) => { let value
value.push(v.value) let name
})
value = JSON.stringify(value) if (element.hasAttribute('data-checkbox')) {
} else { name = element.getAttribute('data-name')
name = jQuery(element).attr('name') value = []
value = jQuery(element).val()
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') { const size = elements.length
++value
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 = { if (element.hasAttribute('data-personal')) {
success: () => { userConfig(name, value, callbacks)
OC.msg.finishedSuccess( } else {
selector, appConfig(name, value, callbacks)
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)
}
} }
const elementToggler = (element) => { const elementToggler = (element) => {
jQuery(element).toggle() let display = 'none'
if (window.getComputedStyle(element).display === 'none') {
display = 'block'
}
element.style.display = display
} }
jQuery(document).ready(() => { const updateAppsCategoriesCustom = () => {
elements = jQuery('.side-menu-setting') let values = {}
jQuery('#side-menu-save').on('click', (event) => { for (let item of document.querySelectorAll('.apps-categories-custom')) {
event.preventDefault() let app = item.getAttribute('data-app')
OC.msg.startSaving(selector) let value = item.value
saveSettings(0) if (value) {
}); values[app] = value
}
}
jQuery('.side-menu-display').on('click', (event) => { document.querySelector('#apps-categories-custom').value = JSON.stringify(values)
var target = jQuery(event.target) }
jQuery('.side-menu-display').removeClass('is-active') document.addEventListener('DOMContentLoaded', () => {
target.addClass('is-active') $('*[data-toggle="tooltip"]').tooltip();
jQuery('#side-menu-always-displayed').val(target.attr('data-alwaysdiplayed')) if (document.querySelector('#side-menu-categories-custom')) {
jQuery('#side-menu-big-menu').val(target.attr('data-bigmenu')) const View = Vue.extend(AdminCategoriesCustom)
jQuery('#side-menu-side-with-categories').val(target.attr('data-sidewithcategories')) 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) => { const displays = document.querySelectorAll('.side-menu-display')
var target = jQuery(event.target)
var name = target.attr('name')
var value = target.val()
if ('background-color-opacity' === name) { for (let display of displays) {
return $('#side-menu-background-color, #side-menu-background-color-to').trigger('change'); display.addEventListener('click', (event) => {
} else if ('dark-mode-background-color-opacity' === name) { const target = event.target
return $('#side-menu-dark-mode-background-color, #side-menu-dark-mode-background-color-to').trigger('change');
}
if (name === 'opener') { for (let d of displays) {
var url = OC.generateUrl(`/apps/side_menu/img/${value}.svg`).replace('/index.php', '') d.classList.toggle('is-active', d === display)
}
value = `url(${url})`; 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')
if (name === 'icon-invert-filter' || name === 'icon-opacity') {
value/=100;
}
if (['dark-mode-background-color', 'dark-mode-background-color-to'].indexOf(name) > -1) {
var opacity = parseInt($('#side-menu-dark-mode-background-color-opacity').val() * 255 / 100);
value = [value, opacity.toString(16)].join('');
} else if (['background-color', 'background-color-to'].indexOf(name) > -1) {
var opacity = parseInt($('#side-menu-background-color-opacity').val() * 255 / 100);
value = [value, opacity.toString(16)].join('');
}
document.documentElement.style.setProperty('--side-menu-' + name, value)
}) })
}
jQuery('.side-menu-toggler').on('click', (event) => { for (let item of document.querySelectorAll('.apps-categories-custom')) {
var target = jQuery(event.target) item.addEventListener('change', (event) => {
var element = target.attr('data-target') updateAppsCategoriesCustom()
elementToggler(element)
}) })
}
jQuery("#categories-list .side-menu-setting-list").sortable({ for (let item of document.querySelectorAll('.side-menu-setting-live')) {
forcePlaceholderSize: true, item.addEventListener('change', (event) => {
placeholder: 'placeholder', const target = event.target
stop: function (event, ui) { const name = target.getAttribute('name')
let value = []
jQuery('#categories-list .side-menu-setting-list-item').each(function() { let value = target.value
value.push(jQuery(this).attr('data-id')) let id = null
});
value = JSON.stringify(value) 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'
}
jQuery('input[name="categories-order"]').val(value) 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) {
}
})
+47 -15
View File
@@ -3,13 +3,21 @@
"No": "Ne" "No": "Ne"
"Yes": "Ano" "Yes": "Ano"
"Menu": "Nabídka" "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>. Pro pohyb po použijte klávesu <span class="keyboard-key">tab</span>.' ? 'Use the shortcut <span class="keyboard-key">Ctrl</span>+<span class="keyboard-key">o</span>
"Top menu": "Hlavní nabídka" to open and to hide the side menu. Use <span class="keyboard-key">tab</span> to
"Apps that not must be moved in the side menu": "Aplikace, které nepřesouvat do postranní nabídky" navigate.'
"If there is no selection then the global configuration is applied.": "Pokud neexistuje žádný výběr, je uplatněno globální nastavení." : '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í" "Experimental": "Experimentální"
"Save": "Uložit" "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?" "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 ☕" "Buy me a coffee ☕": "Kupte mi kafe ☕"
"Hidden": "Skryté" "Hidden": "Skryté"
"Small": "Malé" "Small": "Malé"
@@ -36,19 +44,25 @@
"After the logo": "Za logem" "After the logo": "Za logem"
"Position": "Pozice" "Position": "Pozice"
"Show only the opener (hidden logo)": "Zobrazovat pouze otevírací tlačítko (logo skryto)" "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)." "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" "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)." "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 big menu": "Zobrazit velkou nabídku"
"This menu is not compatible with AppOrder.": "Nabídka není kompatibilní s jinou aplikací (doplňkem) „Pořadí aplikací“."
"Display the logo": "Zobrazit logo" "Display the logo": "Zobrazit logo"
"This feature is not compatible with the <code>big menu</code> display.": "Tato funkce není kompatibilní se zobrazením <code>velké nabídky</code>." "This feature is not compatible with the <code>big menu</code> display.": "Tato funkce\
\ není kompatibilní se zobrazením <code>velké nabídky</code>."
"Icons and texts": "Ikony a texty" "Icons and texts": "Ikony a texty"
"Loader enabled": "Načítání zapnuto" "Loader enabled": "Načítání zapnuto"
"Tips": "Tipy" "Tips": "Tipy"
"Always displayed": "Vždy zobrazeno" "Always displayed": "Vždy zobrazeno"
"The logo will be hidden when the menu is always displayed.": "Pokud je nabídka zobrazena trvale, logo bude skryto." "The logo will be hidden when the menu is always displayed.": "Pokud je nabídka zobrazena\
"This is the automatic behavior when the menu is always displayed.": "Toto je automatické chování, kdy je nabídka vždy zobrazena." \ trvale, logo bude skryto."
"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." "Not compatible with touch screens.": "Nekompatibilní s dotykovými obrazovkami."
"Big menu": "Velká nabídka" "Big menu": "Velká nabídka"
"Live preview": "Živý náhled" "Live preview": "Živý náhled"
@@ -62,10 +76,13 @@
"Export the configuration": "Exportovat nastavení" "Export the configuration": "Exportovat nastavení"
"Purge the cache": "Vyprázdnit mezipaměť" "Purge the cache": "Vyprázdnit mezipaměť"
"Show the link to settings": "Zobrazit odkaz na nastavení" "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 zapnutá pro uživatele" "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." "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" "Apps that should not be displayed in the menu": "Aplikace, které by neměly být v\
"This feature is only compatible with the <code>big menu</code> display.": "Tato funkce je kompatibilní pouze s <code>velkou nabídkou</ code>." \ 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" "The logo is a link to the default app": "Logo je odkaz na výchozí aplikaci"
"Others": "Ostatní" "Others": "Ostatní"
"Categories": "Kategorie" "Categories": "Kategorie"
@@ -74,6 +91,21 @@
"Name": "Název" "Name": "Název"
"Customed": "Přizpůsobeno" "Customed": "Přizpůsobeno"
"Show and hide the list of categories": "Zobrazit/skrýt seznam kategorií" "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." "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" "Dark mode colors": "Barvy tmavého režimu"
"With categories": "S kategoriemi" "With categories": "S kategoriemi"
"Custom categories": "Vlastní kategorie"
"Customize application categories": "Přizpůsobte kategorie aplikací"
"Apps only visible in the top menu": "Aplikace jsou viditelné pouze v horní nabídce"
"Apps visible in the top and side menus": "Aplikace viditelné v horní a boční nabídce"
"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": "Applications"
+51 -16
View File
@@ -3,13 +3,21 @@
"No": "Nein" "No": "Nein"
"Yes": "Ja" "Yes": "Ja"
"Menu": "Menü" "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.' ? '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" "Top menu": "Obere Navigationsleiste"
"Apps that not must be moved in the side menu": "Anwendungen, die nicht ins Seitenmenü verschoben werden sollen" "Apps that not must be moved in the side menu": "Anwendungen, die nicht ins Seitenmenü\
"If there is no selection then the global configuration is applied.": "Wenn keine Auswahl vorhanden ist, wird die globale Konfiguration angewendet." \ 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" "Experimental": "Experimentell"
"Save": "Speichern" "Save": "Speichern"
"You like this app and you want to support me?": "Du magst diese Anwendung und möchtest mich unterstützen?" "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 ☕" "Buy me a coffee ☕": "Gib mir einen Kaffee aus ☕"
"Hidden": "Ausblenden" "Hidden": "Ausblenden"
"Small": "Klein" "Small": "Klein"
@@ -36,19 +44,25 @@
"After the logo": "Nach dem Logo" "After the logo": "Nach dem Logo"
"Position": "Position" "Position": "Position"
"Show only the opener (hidden logo)": "Nur das Menü-Symbol anzeigen (Logo wird ausgeblendet)" "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)." "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" "Panel": "Panel"
"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)." "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" "Display the big menu": "Großes Menü anzeigen"
"This menu is not compatible with AppOrder.": "Dieses Menü ist nicht mit <code>AppOrder</code> kompatibel."
"Display the logo": "Logo anzeigen" "Display the logo": "Logo anzeigen"
"This feature is not compatible with the <code>big menu</code> display.": "Diese Funktion ist nicht mit dem <code>großen Menü</code> kompatibel." "This feature is not compatible with the <code>big menu</code> display.": "Diese Funktion\
\ ist nicht mit dem <code>großen Menü</code> kompatibel."
"Icons and texts": "Symbole und Texte" "Icons and texts": "Symbole und Texte"
"Loader enabled": "Ladestandanzeige aktiviert" "Loader enabled": "Ladestandanzeige aktiviert"
"Tips": "Tipps" "Tips": "Tipps"
"Always displayed": "Immer anzeigen" "Always displayed": "Immer anzeigen"
"The logo will be hidden when the menu is always displayed.": "Das Logo wird ausgeblendet, wenn das Menü immer angezeigt wird." "The logo will be hidden when the menu is always displayed.": "Das Logo wird ausgeblendet,\
"This is the automatic behavior when the menu is always displayed.": "Dies ist das automatische Verhalten, wenn das Menü immer angezeigt wird." \ 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."
"Not compatible with touch screens.": "Nicht kompatibel mit Touchscreens." "Not compatible with touch screens.": "Nicht kompatibel mit Touchscreens."
"Big menu": "Großes Menü" "Big menu": "Großes Menü"
"Live preview": "Live-Vorschau" "Live preview": "Live-Vorschau"
@@ -57,15 +71,20 @@
"Use my selection": "Verwende meine Auswahl" "Use my selection": "Verwende meine Auswahl"
"Show and hide the list of applications": "Ein- und Ausblenden der Anwendungsliste" "Show and hide the list of applications": "Ein- und Ausblenden der Anwendungsliste"
"Use the avatar instead of the logo": "Avatar anstelle des Logos anzeigen" "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." "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" "Force this configuration to users": "Konfiguration für alle Benutzer erzwingen"
"Export the configuration": "Konfiguration exportieren" "Export the configuration": "Konfiguration exportieren"
"Purge the cache": "Cache leeren" "Purge the cache": "Cache leeren"
"Show the link to settings": "Link zu den Einstellungen anzeigen" "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" "The menu is enabled by default for users": "Das Menü ist standardmäßig für alle Benutzer\
"Except when the configuration is forced.": "Gilt nicht, wenn die Konfiguration erzwungen wird." \ aktiviert"
"Apps that should not be displayed in the menu": "Anwendungen, die nicht im Menü angezeigt werden sollen" "Except when the configuration is forced.": "Gilt nicht, wenn die Konfiguration erzwungen\
"This feature is only compatible with the <code>big menu</code> display.": "Kompatibel mit dem <code>großen Menü</code>." \ 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" "The logo is a link to the default app": "Das Logo ist ein Link zur Standard-App"
"Others": "Andere" "Others": "Andere"
"Categories": "Kategorien" "Categories": "Kategorien"
@@ -74,6 +93,22 @@
"Name": "Name" "Name": "Name"
"Customed": "Benutzerdefiniert" "Customed": "Benutzerdefiniert"
"Show and hide the list of categories": "Liste der Kategorien ein- und ausblenden" "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." "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" "Dark mode colors": "Farben für den dunklen Modus"
"With categories": "Mit Kategorien" "With categories": "Mit Kategorien"
"Custom categories": "Benutzerdefinierte Kategorien"
"Customize application categories": "Anwendungskategorien anpassen"
"Apps only visible in the top menu": "Apps nur im oberen Menü sichtbar"
"Apps visible in the top and side menus": "Apps im oberen und seitlichen Menü sichtbar"
"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"
+54 -17
View File
@@ -3,18 +3,34 @@
"No": "Non" "No": "Non"
"Yes": "Oui" "Yes": "Oui"
"Menu": "Menu" "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" "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" "Apps that not must be moved in the side menu": "Les applications qui ne doivent pas\
"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" \ être affichées dans le menu latéral"
"If there is no selection then the global configuration is applied.": "Si il n'y a\
\ aucune sélection alors la configuration globale sera appliquée."
"Experimental": "Expérimental" "Experimental": "Expérimental"
"Save": "Sauvegarder" "Save": "Sauvegarder"
"You like this app and you want to support me?": "Vous aimer cette application et vous souhaitez m'aider ?" "You like this app and you want to support me?": "Vous aimer cette application et\
\ vous souhaitez m'aider ?"
"Buy me a coffee ☕": "Offrez moi un café ☕" "Buy me a coffee ☕": "Offrez moi un café ☕"
"Hidden": "Caché" "Hidden": "Caché"
"Small": "Petit" "Small": "Petit"
"Normal": "Normal" "Normal": "Normal"
"Big": "Gros" "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" "Colors": "Couleurs"
"Background color": "Couleur de fond" "Background color": "Couleur de fond"
"Background color of current app": "Couleur de fond de l'application en cours" "Background color of current app": "Couleur de fond de l'application en cours"
@@ -35,20 +51,26 @@
"Before the logo": "Avant le logo" "Before the logo": "Avant le logo"
"After the logo": "Après le logo" "After the logo": "Après le logo"
"Position": "Position" "Position": "Position"
"Show only the opener (hidden logo)": "Afficher uniquement le bouton d'ouverture (masquer le logo)" "Show only the opener (hidden logo)": "Afficher uniquement le bouton d'ouverture (masquer\
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Ne pas afficher le menu latéral et le bouton d'ouverture s'il n'y a aucune application (exemple : page publiques)." \ le logo)"
"Do not display the side menu and the opener if there is no application (eg: public pages).": "Ne\
\ pas afficher le menu latéral et le bouton d'ouverture s'il n'y a aucune application\
\ (exemple : page publiques)."
"Panel": "Panneau" "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)" "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" "Display the big menu": "Afficher le menu large"
"This menu is not compatible with AppOrder.": "Ce menu n'est pas compatible avec l'application AppOrder"
"Display the logo": "Afficher le logo" "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." "This feature is not compatible with the <code>big menu</code> display.": "Cette fonctionnalité\
\ n'est pas compatible avec l'affichage <code>Menu large</code>."
"Icons and texts": "Icônes et textes" "Icons and texts": "Icônes et textes"
"Loader enabled": "Activation de l'indicateur de chargement" "Loader enabled": "Activation de l'indicateur de chargement"
"Tips": "Astuces" "Tips": "Astuces"
"Always displayed": "Toujours affiché" "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é." "The logo will be hidden when the menu is always displayed.": "Le logo sera masque\
"This is the automatic behavior when the menu is always displayed.": "C'est le comportement automatique lorsque le menu est toujours affiché." \ 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." "Not compatible with touch screens.": "Incompatible avec les écrans tactiles."
"Big menu": "Menu large" "Big menu": "Menu large"
"Live preview": "Aperçu en direct" "Live preview": "Aperçu en direct"
@@ -57,16 +79,21 @@
"Use my selection": "Utiliser ma sélection" "Use my selection": "Utiliser ma sélection"
"Show and hide the list of applications": "Afficher et masquer la liste des applications" "Show and hide the list of applications": "Afficher et masquer la liste des applications"
"Use the avatar instead of the logo": "Utiliser l'avatar à la place du logo" "Use the avatar instead of the logo": "Utiliser l'avatar à la place du logo"
"You do not have permission to change the settings.": "Vous n'avez pas la permission de changer les paramètres." "You do not have permission to change the settings.": "Vous n'avez pas la permission\
\ de changer les paramètres."
"Force this configuration to users": "Forcer cette configuration aux utilisateurs" "Force this configuration to users": "Forcer cette configuration aux utilisateurs"
"Export the configuration": "Exporter la configuration" "Export the configuration": "Exporter la configuration"
"Purge the cache": "Purger le cache" "Purge the cache": "Purger le cache"
"Show the link to settings": "Afficher le lien vers les paramètres" "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" "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." "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" "Apps that should not be displayed in the menu": "Applications qui ne doivent pas\
"This feature is only compatible with the <code>big menu</code> display.": "Compatible avec l'affichage <code>Menu large</code>." \ être affichées dans le menu"
"The logo is a link to the default app": "Le logo est un lien vers l'application par défaut" "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" "Others": "Autres"
"Categories": "Catégories" "Categories": "Catégories"
"Customize sorting": "Personnaliser le tri" "Customize sorting": "Personnaliser le tri"
@@ -74,6 +101,16 @@
"Name": "Nom" "Name": "Nom"
"Customed": "Personnalisé" "Customed": "Personnalisé"
"Show and hide the list of categories": "Afficher et masquer la liste des catégories" "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." "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" "Dark mode colors": "Couleurs du mode sombre"
"With categories": "Avec les catégories" "With categories": "Avec les catégories"
"Custom categories": "Catégories personnalisées"
"Customize application categories": "Personnaliser les catégories des applications"
"Apps only visible in the top menu": "Applications visibles uniquement dans le menu\
\ supérieur"
"Apps visible in the top and side menus": "Applications visibles dans le menus supérieur\
\ et latéral"
"Reset to default": "Restaurer les valeurs par défaut"
"Applications": "Applications"
+95
View File
@@ -0,0 +1,95 @@
"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": ""
"This feature is not compatible with the <code>big menu</code> display.": ""
"Icons and texts": ""
"Loader enabled": ""
"Tips": ""
"Always displayed": ""
"The logo will be hidden 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": ""
"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": ""
"Apps only visible in the top menu": ""
"Apps visible in the top and side menus": ""
"Reset to default": ""
"Applications": ""
+14 -1
View File
@@ -40,7 +40,6 @@
"Panel": "面板" "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 big menu": "显示大型菜单"
"This menu is not compatible with AppOrder.": "型菜单与应用顺序不兼容"
"Display the logo": "显示logo" "Display the logo": "显示logo"
"This feature is not compatible with the <code>big menu<\/code> display.": "此功能与显示<code>大型菜单<\/code>不兼容。" "This feature is not compatible with the <code>big menu<\/code> display.": "此功能与显示<code>大型菜单<\/code>不兼容。"
"Icons and texts": "图标与文字" "Icons and texts": "图标与文字"
@@ -77,3 +76,17 @@
"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": "暗黑模式颜色" "Dark mode colors": "暗黑模式颜色"
"With categories": "有类别" "With categories": "有类别"
"Custom categories": "自定义类别"
"Customize application categories": "自定义应用程序类别"
"Apps only visible in the top menu": "应用程序仅在顶部菜单中可见"
"Apps visible in the top and side menus": "顶部和侧边菜单中可见的应用程序"
"Reset to default": "重置为默认设置"
"Hidden icon": "隐藏图标"
"Small icon": "小图标"
"Normal icon": "正常图标"
"Big icon": "大图标"
"Hidden text": "隐藏文字"
"Small text": "小文本"
"Normal text": "普通文本"
"Big text": "大文本"
"Applications": "Applications"
+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 { :root {
<?php foreach ($_['vars'] as $key => $value): ?> <?php foreach ($_['vars'] as $key => $value): ?>
<?php if ($key === 'opener'): ?> <?php if ($key === 'opener'): ?>
--side-menu-<?php echo $key ?>: url('<?php print_unescaped(image_path('side_menu', $value.'.svg')); ?>'); --side-menu-<?php echo $key ?>: url('<?php print_unescaped(image_path('side_menu', $value.'.svg')); ?>');
<?php else: ?> <?php else: ?>
--side-menu-<?php echo $key ?>: <?php echo $value ?>; --side-menu-<?php echo $key ?>: <?php echo $value ?>;
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
} }
<?php if (empty($_['top-menu-apps'])): ?> <?php if (empty($_['top-menu-apps']) && empty($_['top-side-menu-apps'])): ?>
#appmenu { #appmenu {
display: none; display: none;
} }
#appmenu + nav { #appmenu + nav {
display: none; display: none;
} }
<?php else: ?> <?php else: ?>
.app-hidden { .app-hidden {
opacity: 0; opacity: 0;
} }
<?php endif; ?> <?php endif; ?>
<?php if ($_['opener-only']): ?> <?php if ($_['opener-only']): ?>
#nextcloud { #nextcloud {
display: none; display: none;
} }
<?php endif; ?> <?php endif; ?>
<?php if (!$_['display-logo']): ?> <?php if (!$_['display-logo']): ?>
.side-menu-logo { .side-menu-logo {
display: none; 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 { #side-menu .side-menu-opener {
height: 50px; <?php if ($_['size-icon'] === 'big'): ?>
margin-left: 1px;
<?php else: ?>
margin-left: 0px;
<?php endif; ?>
} }
<?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'): ?> <?php if ($_['size-icon'] === 'hidden'): ?>
.side-menu-app-icon { .side-menu-app-icon {
display: none; display: none;
} }
<?php elseif ($_['size-icon'] === 'small'): ?> <?php elseif ($_['size-icon'] === 'small'): ?>
.side-menu-app-icon svg { .side-menu-app-icon svg {
width: 15px; width: 15px;
height: 15px; height: 15px;
} }
img.side-menu-app-icon { img.side-menu-app-icon {
width: 15px; width: 15px;
height: 15px; height: 15px;
} }
<?php elseif ($_['size-icon'] === 'normal'): ?> <?php elseif ($_['size-icon'] === 'normal'): ?>
.side-menu-app-icon svg { .side-menu-app-icon svg {
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
img.side-menu-app-icon { img.side-menu-app-icon {
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
<?php elseif ($_['size-icon'] === 'big'): ?> <?php elseif ($_['size-icon'] === 'big'): ?>
.side-menu-app-icon svg { .side-menu-app-icon svg {
width: 23px; width: 23px;
height: 23px; height: 23px;
} }
img.side-menu-app-icon { img.side-menu-app-icon {
width: 23px; width: 23px;
height: 23px; height: 23px;
} }
<?php endif; ?> <?php endif; ?>
<?php if ($_['size-text'] === 'hidden'): ?> <?php if ($_['size-text'] === 'hidden'): ?>
.side-menu-app-text { .side-menu-app-text {
display: none; display: none;
} }
<?php elseif ($_['size-text'] === 'small'): ?> <?php elseif ($_['size-text'] === 'small'): ?>
.side-menu-app-text { .side-menu-app-text {
font-size: 12px; font-size: 12px;
} }
<?php elseif ($_['size-text'] === 'big'): ?> <?php elseif ($_['size-text'] === 'big'): ?>
.side-menu-app-text { .side-menu-app-text {
font-size: 16px; 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; ?> <?php endif; ?>
-74
View File
@@ -1,74 +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 computedStyle = window.getComputedStyle(element, null)
var left = computedStyle.getPropertyValue('left')
var right = computedStyle.getPropertyValue('right')
if (right !== '0px') {
var intValue = parseInt(left.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)
+137 -116
View File
@@ -13,148 +13,169 @@ if ($_['always-displayed']) {
?> ?>
(function() { (function() {
var sideMenuContainer = jQuery('<div id="side-menu-container">') const sideMenuContainer = SMcreateElement('div', {id: 'side-menu-container'})
var sideMenuOpener = jQuery('<button class="side-menu-opener"></button>') const sideMenuOpener = SMcreateElement('button', {'class': 'side-menu-opener'})
var sideMenu = jQuery('<div id="side-menu">') const sideMenu = SMcreateElement('div', {id: 'side-menu'})
var body = jQuery('body')
var html = jQuery('html')
var isTouchDevice = window.matchMedia("(pointer: coarse)").matches
<?php if ($display === 'big-menu'): ?> const body = document.querySelector('body')
sideMenu.attr('data-bigmenu', '1') const html = document.querySelector('html')
<?php elseif ($display === 'side-with-categories'): ?> const nextcloud = document.querySelector('#nextcloud')
sideMenu.attr('data-sidewithcategories', '1')
<?php endif; ?>
var targetBlankApps = <?php echo json_encode($_['target-blank-apps']) ?>; const isTouchDevice = window.matchMedia("(pointer: coarse)").matches
const targetBlankApps = <?php echo json_encode($_['target-blank-apps']) ?>
body.on('side-menu.apps', function(e, apps) { window.topMenuApps = <?php echo json_encode($_['top-menu-apps']), "\n"; ?>
<?php if ($_['hide-when-no-apps']): ?> window.topSideMenuApps = <?php echo json_encode($_['top-side-menu-apps'])."\n"; ?>
sideMenu = jQuery('#side-menu') window.menuAppsOrder = <?php echo json_encode($_['apps-order']), "\n"; ?>
if (apps.length === 0) { <?php if ($display === 'big-menu'): ?>
sideMenu.removeClass('open') sideMenu.setAttribute('data-bigmenu', '1')
sideMenu.addClass('hide') <?php elseif ($display === 'side-with-categories'): ?>
sideMenuOpener.addClass('hide') sideMenu.setAttribute('data-sidewithcategories', '1')
} else { <?php endif; ?>
sideMenu.removeClass('hide')
sideMenuOpener.removeClass('hide')
}
<?php if ($display === 'always-displayed'): ?> document.querySelector('body').addEventListener('side-menu.apps', (e) => {
if (apps.length === 0) { const apps = e.detail.apps;
html.removeClass('side-menu-always-displayed');
} else {
html.addClass('side-menu-always-displayed');
}
<?php endif; ?>
<?php else: ?>
<?php if ($display === 'always-displayed'): ?>
if (apps.length === 0) {
html.removeClass('side-menu-always-displayed');
} else {
html.addClass('side-menu-always-displayed');
}
<?php endif; ?>
<?php endif; ?>
})
body.on('side-menu.ready', function() { <?php if ($_['hide-when-no-apps']): ?>
sideMenu = jQuery('#side-menu') const sideMenu = document.querySelector('#side-menu')
var headerMenuOpener = jQuery('#header .side-menu-opener') if (apps.length === 0) {
var sideMenuOpener = jQuery('#side-menu .side-menu-opener') sideMenu.classList.remove('open')
sideMenu.classList.add('hide')
sideMenuOpener.classList.add('hide')
} else {
sideMenu.classList.remove('hide')
sideMenuOpener.classList.remove('hide')
}
sideMenuFocus = function() { <?php if ($display === 'always-displayed'): ?>
var a = sideMenu.find('.side-menu-app.active a') if (apps.length === 0) {
html.classList.remove('side-menu-always-displayed')
if (a.length === 0) { } else {
a = sideMenu.find('.side-menu-app:first-child a') html.classList.add('side-menu-always-displayed')
}
if (a.length > 0) {
a.focus()
}
} }
<?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'] || $display === 'always-displayed'): ?> body.addEventListener('side-menu.ready', () => {
var sideMenuMouseLeave = function() { const sideMenu = document.querySelector('#side-menu')
sideMenu const headerMenuOpener = document.querySelector('#header .side-menu-opener')
.removeClass('open') const sideMenuOpener = document.querySelectorAll('#side-menu .side-menu-opener')
.off('mouseleave', sideMenuMouseLeave)
}
var sideMenuMouseEnter = function() { sideMenuFocus = () => {
sideMenu.on('mouseleave', sideMenuMouseLeave) let a = document.querySelector('.side-menu-app.active a', sideMenu)
}
var sideMenuOpenerMouseEnter = function() { if (!a) {
sideMenu return
.addClass('open') }
.on('mouseenter', sideMenuMouseEnter)
sideMenuFocus() if (a.length === 0) {
} a = sideMenu.querySelector('.side-menu-app:first-child a')
}
if (!isTouchDevice) { if (a.length > 0) {
<?php if ($_['opener-hover']): ?> a.focus()
headerMenuOpener.on('mouseenter', sideMenuOpenerMouseEnter) }
}
sideMenu.addClass('hide-opener') <?php if ($_['opener-hover']): ?>
<?php endif ?> const sideMenuMouseLeave = () => {
sideMenu.classList.remove('open')
sideMenu.removeEventListener('mouseleave', sideMenuMouseLeave)
}
sideMenu.on('mouseleave', sideMenuMouseLeave) const sideMenuMouseEnter = () => {
sideMenu.on('mouseenter', sideMenuOpenerMouseEnter) sideMenu.addEventListener('mouseleave', sideMenuMouseLeave)
} }
<?php endif; ?>
headerMenuOpener.on('click', function() { const sideMenuOpenerMouseEnter = () => {
sideMenu.addClass('open') sideMenu.classList.add('open')
sideMenu.find('.side-menu-app.active a').focus() sideMenu.addEventListener('mouseenter', sideMenuMouseEnter)
})
<?php if ($display === 'always-displayed'): ?> sideMenuFocus()
sideMenuOpener.on('click', function() { }
sideMenu.toggleClass('open')
})
<?php else: ?>
sideMenuOpener.on('click', function() {
sideMenu.removeClass('open')
})
<?php endif; ?>
jQuery(document).keydown(function(e) { if (!isTouchDevice) {
var key = e.key || e.keyCode <?php if ($_['opener-hover']): ?>
headerMenuOpener.addEventListener('mouseenter', sideMenuOpenerMouseEnter)
if ((key === 'o' || key === 79) && e.ctrlKey === true) { sideMenu.classList.add('hide-opener')
e.preventDefault() <?php endif ?>
sideMenu.toggleClass('open') sideMenu.addEventListener('mouseleave', sideMenuMouseLeave)
sideMenuFocus() 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) for (let opener of sideMenuOpener) {
sideMenuContainer.append(sideMenu) 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): ?> document.addEventListener('keydown', (e) => {
<?php require_once __DIR__.'/_loaderEnabled.js'; ?> var key = e.key || e.keyCode
<?php endif; ?>
<?php if ($_['opener-position'] === 'before'): ?> if ((key === 'o' || key === 79) && e.ctrlKey === true) {
sideMenuOpener.insertBefore('#nextcloud') e.preventDefault()
<?php else: ?>
sideMenuOpener.insertAfter('#nextcloud')
<?php endif; ?>
<?php if (!empty($_['top-menu-apps'])): ?> sideMenu.classList.toggle('open')
var topMenuApps = <?php echo json_encode($_['top-menu-apps']); ?>; sideMenuFocus()
}
})
<?php require_once __DIR__.'/_topMenuApps.js'; ?> const sideMenuObserver = new MutationObserver((e) => {
<?php endif; ?> if (body.getAttribute('id') !== 'body-settings') {
return
}
<?php if ($display === 'always-displayed'): ?> body.classList.toggle('body-settings-side-menu', sideMenu.classList.contains('open'))
<?php require_once __DIR__.'/_alwaysDisplayed.js'; ?> })
<?php endif; ?>
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; ?>
})(); })();
+175 -15
View File
@@ -20,6 +20,7 @@ use OCP\IURLGenerator;
use OCP\IConfig; use OCP\IConfig;
use OCA\SideMenu\AppInfo\Application; use OCA\SideMenu\AppInfo\Application;
vendor_script('side_menu', 'html5sortable.min');
script('side_menu', 'admin'); script('side_menu', 'admin');
style('side_menu', 'admin'); style('side_menu', 'admin');
@@ -38,8 +39,9 @@ $choicesSizes = [
'Big' => 'big', 'Big' => 'big',
]; ];
$labelShowHideApps = 'Show and hide the list of applications';
$labelReset = 'Reset to default';
?> ?>
<div id="side-menu-section"> <div id="side-menu-section">
<div class="section"> <div class="section">
<h2> <h2>
@@ -67,6 +69,10 @@ $choicesSizes = [
class="side-menu-setting side-menu-setting-live" class="side-menu-setting side-menu-setting-live"
value="<?php print_unescaped($_['background-color-to']); ?>"> value="<?php print_unescaped($_['background-color-to']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-background-color' => $_['defaults']['background-color'],
'side-menu-background-color-to' => $_['defaults']['background-color-to'],
])) ?>"></div>
<div> <div>
<em> <em>
<?php p($l->t('Transparent')); ?> <?php p($l->t('Transparent')); ?>
@@ -102,6 +108,10 @@ $choicesSizes = [
type="color" type="color"
class="side-menu-setting side-menu-setting-live" class="side-menu-setting side-menu-setting-live"
value="<?php print_unescaped($_['current-app-background-color']); ?>"> value="<?php print_unescaped($_['current-app-background-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-current-app-background-color' => $_['defaults']['current-app-background-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -118,6 +128,10 @@ $choicesSizes = [
type="color" type="color"
class="side-menu-setting side-menu-setting-live" class="side-menu-setting side-menu-setting-live"
value="<?php print_unescaped($_['text-color']); ?>"> value="<?php print_unescaped($_['text-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-text-color' => $_['defaults']['text-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -134,6 +148,10 @@ $choicesSizes = [
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['loader-color']); ?>"> value="<?php print_unescaped($_['loader-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-loader-color' => $_['defaults']['loader-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -227,16 +245,23 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form side-menu-setting-form-long"> <div class="side-menu-setting-form side-menu-setting-form-long">
<input <input
id="side-menu-dark-mode-background-color"
name="dark-mode-background-color" name="dark-mode-background-color"
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['dark-mode-background-color']); ?>"> value="<?php print_unescaped($_['dark-mode-background-color']); ?>">
<input <input
id="side-menu-dark-mode-background-color-to"
name="dark-mode-background-color-to" name="dark-mode-background-color-to"
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['dark-mode-background-color-to']); ?>"> value="<?php print_unescaped($_['dark-mode-background-color-to']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-dark-mode-background-color' => $_['defaults']['dark-mode-background-color'],
'side-menu-dark-mode-background-color-to' => $_['defaults']['dark-mode-background-color-to'],
])) ?>"></div>
<div> <div>
<em> <em>
<?php p($l->t('Transparent')); ?> <?php p($l->t('Transparent')); ?>
@@ -266,10 +291,15 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form side-menu-setting-form-long"> <div class="side-menu-setting-form side-menu-setting-form-long">
<input <input
id="side-menu-dark-mode-current-app-background-color"
name="dark-mode-current-app-background-color" name="dark-mode-current-app-background-color"
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['dark-mode-current-app-background-color']); ?>"> value="<?php print_unescaped($_['dark-mode-current-app-background-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-dark-mode-current-app-background-color' => $_['defaults']['dark-mode-current-app-background-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -281,10 +311,15 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form side-menu-setting-form-long"> <div class="side-menu-setting-form side-menu-setting-form-long">
<input <input
id="side-menu-dark-mode-text-color"
name="dark-mode-text-color" name="dark-mode-text-color"
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['dark-mode-text-color']); ?>"> value="<?php print_unescaped($_['dark-mode-text-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-dark-mode-text-color' => $_['defaults']['dark-mode-text-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -296,10 +331,15 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form side-menu-setting-form-long"> <div class="side-menu-setting-form side-menu-setting-form-long">
<input <input
id="side-menu-dark-mode-loader-color"
name="dark-mode-loader-color" name="dark-mode-loader-color"
type="color" type="color"
class="side-menu-setting" class="side-menu-setting"
value="<?php print_unescaped($_['dark-mode-loader-color']); ?>"> value="<?php print_unescaped($_['dark-mode-loader-color']); ?>">
<div class="theme-undo icon icon-history btn-reset" data-toggle="tooltip" data-original-title="<?php echo p($l->t($labelReset)); ?>" data-reset="<?php echo htmlentities(json_encode([
'side-menu-dark-mode-loader-color' => $_['defaults']['dark-mode-loader-color'],
])) ?>"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -469,7 +509,6 @@ $choicesSizes = [
<?php p($l->t('With categories')); ?> <?php p($l->t('With categories')); ?>
</label> </label>
</div> </div>
<p><em><?php echo $l->t('This menu is not compatible with AppOrder.'); ?></em></p>
<p> <p>
<img <img
class="side-menu-display <?php echo $displays['side-with-categories'] ? 'is-active' : '' ?>" class="side-menu-display <?php echo $displays['side-with-categories'] ? 'is-active' : '' ?>"
@@ -484,7 +523,6 @@ $choicesSizes = [
<?php p($l->t('Big menu')); ?> <?php p($l->t('Big menu')); ?>
</label> </label>
</div> </div>
<p><em><?php echo $l->t('This menu is not compatible with AppOrder.'); ?></em></p>
<p> <p>
<img <img
class="side-menu-display <?php echo $displays['big-menu'] ? 'is-active' : '' ?>" class="side-menu-display <?php echo $displays['big-menu'] ? 'is-active' : '' ?>"
@@ -497,7 +535,6 @@ $choicesSizes = [
<div> <div>
<label for="side-menu-opener"> <label for="side-menu-opener">
<?php p($l->t('Always displayed')); ?> <?php p($l->t('Always displayed')); ?>
<small><span class="warning"><?php p($l->t('Experimental')); ?></span></small>
</label> </label>
</div> </div>
<p><em><?php p($l->t('Not compatible with touch screens.')); ?></em></p> <p><em><?php p($l->t('Not compatible with touch screens.')); ?></em></p>
@@ -612,7 +649,7 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form"> <div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#big-menu-hidden-apps" href="#_"> <a class="side-menu-toggler" data-target="#big-menu-hidden-apps" href="#_">
🖱️ <?php p($l->t('Show and hide the list of applications')); ?> 🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a> </a>
<div class="side-menu-setting" data-name="big-menu-hidden-apps" id="big-menu-hidden-apps" data-checkbox style="display: none"> <div class="side-menu-setting" data-name="big-menu-hidden-apps" id="big-menu-hidden-apps" data-checkbox style="display: none">
@@ -660,7 +697,7 @@ $choicesSizes = [
<select id="side-menu-size-icon" name="size-icon" class="side-menu-setting"> <select id="side-menu-size-icon" name="size-icon" class="side-menu-setting">
<?php foreach ($choicesSizes as $label => $value): ?> <?php foreach ($choicesSizes as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['size-icon']): ?>selected<?php endif; ?>> <option value="<?php echo $value ?>" <?php if ($value === $_['size-icon']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?> icon <?php echo $l->t($label.' icon'); ?>
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
@@ -668,7 +705,7 @@ $choicesSizes = [
<select id="side-menu-size-text" name="size-text" class="side-menu-setting"> <select id="side-menu-size-text" name="size-text" class="side-menu-setting">
<?php foreach ($choicesSizes as $label => $value): ?> <?php foreach ($choicesSizes as $label => $value): ?>
<option value="<?php echo $value ?>" <?php if ($value === $_['size-text']): ?>selected<?php endif; ?>> <option value="<?php echo $value ?>" <?php if ($value === $_['size-text']): ?>selected<?php endif; ?>>
<?php echo $l->t($label); ?> text <?php echo $l->t($label.' text'); ?>
</option> </option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
@@ -681,7 +718,7 @@ $choicesSizes = [
</div> </div>
<div class="side-menu-setting-form"> <div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#target-blank-apps" href="#_"> <a class="side-menu-toggler" data-target="#target-blank-apps" href="#_">
🖱️ <?php p($l->t('Show and hide the list of applications')); ?> 🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a> </a>
<div class="side-menu-setting" data-name="target-blank-apps" id="target-blank-apps" data-checkbox style="display: none"> <div class="side-menu-setting" data-name="target-blank-apps" id="target-blank-apps" data-checkbox style="display: none">
@@ -731,11 +768,11 @@ $choicesSizes = [
<div class="side-menu-setting-table"> <div class="side-menu-setting-table">
<div class="side-menu-setting-row"> <div class="side-menu-setting-row">
<div class="side-menu-setting-label"> <div class="side-menu-setting-label">
<?php p($l->t('Apps that not must be moved in the side menu')); ?> <?php p($l->t('Apps only visible in the top menu')); ?>
</div> </div>
<div class="side-menu-setting-form"> <div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#top-menu-apps" href="#_"> <a class="side-menu-toggler" data-target="#top-menu-apps" href="#_">
🖱️ <?php p($l->t('Show and hide the list of applications')); ?> 🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a> </a>
<div class="side-menu-setting" data-name="top-menu-apps" id="top-menu-apps" data-checkbox style="display: none"> <div class="side-menu-setting" data-name="top-menu-apps" id="top-menu-apps" data-checkbox style="display: none">
@@ -759,6 +796,76 @@ $choicesSizes = [
</div> </div>
</div> </div>
</div> </div>
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Apps visible in the top and side menus')); ?>
</div>
<div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#top-side-menu-apps" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
<div class="side-menu-setting" data-name="top-side-menu-apps" id="top-side-menu-apps" 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="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 p($l->t($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">
</div>
</div>
</div> </div>
</div> </div>
@@ -790,6 +897,60 @@ $choicesSizes = [
</div> </div>
</div> </div>
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Custom categories')); ?>
</div>
<div class="side-menu-setting-form">
<input type="hidden" name="categories-custom" class="side-menu-setting" data-langs="<?php echo htmlentities(json_encode($langs)) ?>" value="<?php echo htmlentities(json_encode($_['categories-custom'])) ?>">
<div id="side-menu-categories-custom">
</div>
</div>
</div>
<div class="side-menu-setting-row">
<div class="side-menu-setting-label">
<?php p($l->t('Customize application categories')); ?>
</div>
<div class="side-menu-setting-form">
<a class="side-menu-toggler" data-target="#apps-categories-custom-list" href="#_">
🖱️ <?php p($l->t($labelShowHideApps)); ?>
</a>
<div id="apps-categories-custom-list" style="display: none">
<ul class="side-menu-setting-list">
<?php foreach ($_['apps'] as $app): ?>
<li class="side-menu-setting-list-item">
<label for="apps-categories-custom-<?php echo $app['id'] ?>">
<?php echo p($l->t($app['name'])); ?>
</label>
<br>
<select data-app="<?php echo $app['id'] ?>" class="apps-categories-custom">
<option value=""></option>
<?php foreach ($_['categories'] as $id => $category): ?>
<?php if ($category): ?>
<option
value="<?php echo $id ?>"
<?php if (($_['apps-categories-custom'][$app['id']] ?? '') === $id): ?>
selected
<?php endif; ?>
><?php echo $category ?></option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</li>
<?php endforeach; ?>
</ul>
</div>
<input type="hidden" class="side-menu-setting" id="apps-categories-custom" name="apps-categories-custom" value="<?php echo htmlentities(json_encode($_['apps-categories-custom'])) ?>">
</div>
</div>
<div class="side-menu-setting-row"> <div class="side-menu-setting-row">
<div class="side-menu-setting-label"> <div class="side-menu-setting-label">
<?php p($l->t('Customize sorting')); ?> <?php p($l->t('Customize sorting')); ?>
@@ -799,7 +960,7 @@ $choicesSizes = [
🖱️ <?php p($l->t('Show and hide the list of categories')); ?> 🖱️ <?php p($l->t('Show and hide the list of categories')); ?>
</a> </a>
<div class="side-menu-setting" data-name="categories" id="categories-list" style="display: none"> <div id="categories-list" style="display: none">
<ul class="side-menu-setting-list"> <ul class="side-menu-setting-list">
<?php foreach ($_['categories'] as $key => $label): ?> <?php foreach ($_['categories'] as $key => $label): ?>
<li data-id="<?php echo $key; ?>" class="side-menu-setting-list-item"> <li data-id="<?php echo $key; ?>" class="side-menu-setting-list-item">
@@ -870,11 +1031,10 @@ $choicesSizes = [
<div class="section" id="more"> <div class="section" id="more">
<button id="side-menu-save" class="btn btn-info"> <button id="side-menu-save" class="btn btn-info">
<?php p($l->t('Save')); ?> <?php p($l->t('Save')); ?>
<progress max="100" value="0" id="side-menu-save-progress"></progress>
</button> </button>
<span id="side-menu-message" class="msg"></span> <a href="<?php echo $urlGenerator->linkToRoute('side_menu.AdminSetting.exportConfiguration') ?>" target="_blank" rel="noopener">
<a href="<?php echo $urlGenerator->linkToRoute('side_menu.AdminSetting.exportConfiguration') ?>" target="_blank">
<button class="btn btn-primary" > <button class="btn btn-primary" >
<?php p($l->t('Export the configuration')); ?> <?php p($l->t('Export the configuration')); ?>
</button> </button>
@@ -892,7 +1052,7 @@ $choicesSizes = [
<span for="side-menu-opener"> <span for="side-menu-opener">
<?php p($l->t('You like this app and you want to support me?')); ?> <?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> <button>
<?php p($l->t('Buy me a coffee ☕')); ?> <?php p($l->t('Buy me a coffee ☕')); ?>
</button> </button>
+146 -95
View File
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
vendor_script('side_menu', 'html5sortable.min');
script('side_menu', 'admin'); script('side_menu', 'admin');
style('side_menu', 'admin'); style('side_menu', 'admin');
@@ -24,9 +25,9 @@ $choicesYesNo = [
'Yes' => '1', 'Yes' => '1',
]; ];
$labelShowHideApps = 'Show and hide the list of applications';
?> ?>
<div id="side-menu-section"> <div id="side-menu-section">
<?php if ($_['force']): ?> <?php if ($_['force']): ?>
<div class="section"> <div class="section">
@@ -44,71 +45,73 @@ $choicesYesNo = [
<?php p($l->t('Menu')); ?> <?php p($l->t('Menu')); ?>
</h2> </h2>
<div>
<label for="side-menu-enabled">
<?php p($l->t('Enable the custom menu')); ?>
</label>
</div>
<p> <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> <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> </p>
<div> <div class="side-menu-setting-table">
<select id="side-menu-enabled" name="enabled" class="side-menu-setting" data-personal> <div class="side-menu-setting-row">
<?php foreach ($choicesYesNo as $label => $value): ?> <div class="side-menu-setting-label">
<option value="<?php echo $value ?>" <?php if ($value === $_['enabled']): ?>selected<?php endif; ?>> <?php p($l->t('Enable the custom menu')); ?>
<?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> </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>
</div> </div>
@@ -116,47 +119,95 @@ $choicesYesNo = [
<h2> <h2>
<?php p($l->t('Top menu')); ?> <?php p($l->t('Top menu')); ?>
</h2> </h2>
<div>
<label for="side-menu-top-menu-apps"> <div class="side-menu-setting-table">
<?php p($l->t('Apps that not must be moved in the side menu')); ?> <div class="side-menu-setting-row">
</label> <div class="side-menu-setting-label">
<?php p($l->t('Apps only visible 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> </div>
<p> <div class="side-menu-setting-table">
<em> <div class="side-menu-setting-row">
<?php p($l->t('If there is no selection then the global configuration is applied.')); ?> <div class="side-menu-setting-label">
</em> <?php p($l->t('Apps visible in the top and side menus')); ?>
</p> <p>
<em>
<p> <?php p($l->t('If there is no selection then the global configuration is applied.')); ?>
<a class="side-menu-toggler" data-target="#top-menu-apps" href="#_"> </em>
🖱️ <?php p($l->t('Show and hide the list of applications')); ?> </p>
</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> </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> </div>
<?php endif ?> <?php endif ?>
<div class="section"> <div class="section">
<?php if (!$_['force']): ?> <?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> <span id="side-menu-message" class="msg"></span>
@@ -167,7 +218,7 @@ $choicesYesNo = [
<span for="side-menu-opener"> <span for="side-menu-opener">
<?php p($l->t('You like this app and you want to support me?')); ?> <?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> <button>
<?php p($l->t('Buy me a coffee ☕')); ?> <?php p($l->t('Buy me a coffee ☕')); ?>
</button> </button>
+2
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -3,6 +3,7 @@ const { VueLoaderPlugin } = require('vue-loader')
const StyleLintPlugin = require('stylelint-webpack-plugin') const StyleLintPlugin = require('stylelint-webpack-plugin')
module.exports = { module.exports = {
devtool: "source-map",
entry: { entry: {
'admin': path.join(__dirname, 'src', 'admin.js'), 'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'), 'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),