Compare commits

...

391 Commits

Author SHA1 Message Date
Sercan Yemen 5a661aa4e5 Merge branch 'dev-starter' into starter 2024-03-11 11:56:09 +03:00
Sercan Yemen 27c7da18d8 Merge branch 'dev-starter' into starter 2024-03-11 11:51:04 +03:00
Sercan Yemen 4284702b8a Merge branch 'dev' into dev-starter 2024-03-11 11:46:08 +03:00
Sercan Yemen 2d7ac981ba Merge branch 'dev' into dev-starter 2024-03-11 11:41:18 +03:00
Sercan Yemen cc9cf23353 Updated version numbers 2024-03-11 11:27:43 +03:00
Sercan Yemen 63d1fef588 Update version number 2024-03-11 11:15:23 +03:00
Sercan Yemen 39fb77eff7 Updated crypto-js to latest version 2024-03-11 10:44:42 +03:00
Sercan Yemen 16401b13d5 Update Angular and other dependencies 2024-03-11 10:41:37 +03:00
Sercan Yemen ad70ae43ac Fixed: Peer dependency issues caused by quill. Fuse can now use the default peer dependency resolution. 2024-03-11 10:39:03 +03:00
Sercan Yemen cd45a802c8 (@fuse/fullscreen) Refactor FuseFullscreen to use new Fullscreen API 2024-03-11 10:28:32 +03:00
Sercan Yemen cedd61f71b Docs: Updated directory structure guide 2024-01-11 08:59:39 +03:00
Sercan Yemen 2821b90ed8 Fixed: Some disabled icon colors are not correct on dark themes 2024-01-11 08:54:31 +03:00
Sercan Yemen 1025d59d9b Merge remote-tracking branch 'origin/demo' into starter 2023-11-20 12:52:39 +03:00
Sercan Yemen 116e17df26 Updated version numbers and changelog 2023-11-20 12:43:56 +03:00
Sercan Yemen da2cf6a5e5 Updated various other packages 2023-11-20 10:10:29 +03:00
Sercan Yemen e884ccafe8 (core) Use inject for dependencies 2023-11-20 10:06:06 +03:00
Sercan Yemen eb43394ed1 Updated transloco and moved its configuration to standalone 2023-11-20 10:05:24 +03:00
Sercan Yemen 79dd135a26 Fixed: Rotation on paper-airplane icons 2023-11-20 09:49:22 +03:00
Sercan Yemen 4f98e6b111 Updated Angular Material to v17 2023-11-20 09:48:47 +03:00
Sercan Yemen 7546b4ebd2 Updated Angular to v17
Increased version number
2023-11-20 09:41:08 +03:00
Sercan Yemen c05f572e28 Fixed: Autocompleted input colors 2023-11-20 09:27:11 +03:00
Sercan Yemen e64ad63f8a (docs) Small typo 2023-09-04 13:08:56 +03:00
Sercan Yemen f36284e10f (overrides/angular-material) Fix snack bar action label color 2023-09-04 13:08:47 +03:00
Sercan Yemen 42a3dda2f5 (apps/chat) Reset the current selected chat when component destroyed 2023-09-04 13:08:22 +03:00
Sercan Yemen 5a7392cbd1 Merge branch 'dev' into dev-starter 2023-05-30 12:27:04 +03:00
Sercan Yemen e1989ffd64 Merge branch 'dev' into dev-starter 2023-05-30 12:24:21 +03:00
Sercan Yemen 4af04eab4d Standalone components, Angular v16 and more 2023-05-30 12:00:42 +03:00
Sercan Yemen 3175a2faae Updated Heroicons icons 2023-05-30 11:58:30 +03:00
Sercan Yemen e23a21eedf Finalized standalone components conversion 2023-05-30 09:26:50 +03:00
Sercan Yemen 5d42763f1b Second pass through for standalone components. 2023-05-15 14:36:38 +03:00
Sercan Yemen b2cb20634e First pass through updating standalone components. 2023-05-04 13:29:53 +03:00
Sercan Yemen 715ab6a3aa Reverted back to "canActivate" & "canActivateChild"
Converted guards to functional guards
2023-01-22 22:49:25 +03:00
Sercan Yemen 5faab90a7b Merge branch 'dev' into dev-starter 2023-01-19 11:22:48 +03:00
Sercan Yemen 1e8c284c93 Added release date to the changelog 2023-01-19 11:20:22 +03:00
Sercan Yemen 7efe9d5950 Fixed: Tooltip background color 2023-01-19 11:10:04 +03:00
Sercan Yemen e380f754d7 Updated Angular & Angular Material 2023-01-19 11:09:20 +03:00
Sercan Yemen 104a1ceffb Fixed the routing 2022-12-12 14:58:29 +03:00
Sercan Yemen ce0cce00d9 Merge branch 'dev' into dev-starter 2022-12-12 14:51:27 +03:00
Sercan Yemen e39ec222d0 Updated Angular & Angular Material versions
Updated various other packages
Updated changelog and the version number
2022-12-12 14:50:08 +03:00
Sercan Yemen 685e981438 (@fuse/overrides/angular-material) Fixed: Tailwind breaks the disabled mat-checkbox styling 2022-12-07 19:38:51 +03:00
Sercan Yemen ba8689ed0c (core) Use the new "CanMatch" rather than "CanLoad" and "CanActivate" for routes 2022-12-02 14:17:05 +03:00
Sercan Yemen 41a1692e01 (@fuse) Fixed: Autocompleted input background color is not correct 2022-11-25 15:06:42 +03:00
Sercan Yemen d4736e2c02 (@fuse) Removed the unnecessary map wrap 2022-11-25 11:49:21 +03:00
Sercan Yemen 41bd49d45d Merge branch 'dev' into dev-starter 2022-11-21 09:07:40 +03:00
Sercan Yemen 1968227e19 Updated the version number and the changelog 2022-11-21 09:06:42 +03:00
Sercan Yemen 042979269e Merge branch 'dev' into dev-starter 2022-11-21 09:03:30 +03:00
Sercan Yemen 28180c7491 (@fuse/confirmation-dialog) Fixed: Dialog padding is broken because of MDC component class names 2022-11-20 14:11:00 +03:00
Sercan Yemen de7a598c07 Updated the meta tags for the Demo 2022-11-18 11:14:00 +03:00
Sercan Yemen 8ae3cdfbea Updated the changelog 2022-11-18 11:07:04 +03:00
Sercan Yemen b294672452 Merge branch 'dev' into dev-starter 2022-11-18 09:40:19 +03:00
Sercan Yemen 533e39261b (Dependencies) Removed ngx-markdown package, you can keep using it if you need, we will remove anything that slow us down in terms of updates 2022-11-18 09:38:54 +03:00
Sercan Yemen db6fcc208b Merge branch 'dev' into dev-starter 2022-11-17 13:17:47 +03:00
Sercan Yemen 7870e312b9 (Dependencies) Updated various other dependencies 2022-11-17 13:11:55 +03:00
Sercan Yemen 1662042e35 (Dependencies) Updated the Angular & Angular Material to v15 stable 2022-11-17 13:10:53 +03:00
Sercan Yemen 08266c3e51 Updated the application to reflect the changes 2022-11-11 15:30:12 +03:00
Sercan Yemen 8000e53bae (overrides/angular-material) Tweaks and improvements 2022-11-11 15:29:56 +03:00
Sercan Yemen 8fbef029c0 Updated the Fuse version number and the changelog 2022-11-11 13:25:34 +03:00
Sercan Yemen b7b849ee60 Second step of upgrading to Angular Material v15 (MDC). Almost re-wrote the entire override styles to make sure MDC components will look correct. 2022-11-11 13:21:04 +03:00
Sercan Yemen 872dffe42b Updated Angular to v15-rc.3 and Angular Material to v15-rc.2 2022-11-10 14:16:05 +03:00
Sercan Yemen 646b084a12 Only write the user themes file if the map has been changed. This fixes the issue where watcher being triple triggered on cold starts. 2022-11-08 12:47:38 +03:00
Sercan Yemen c88d30a4f4 Removed the linter from the default project since linting mostly done using Editors and IDEs 2022-11-07 11:04:27 +03:00
Sercan Yemen f2d5bf3041 Matched the files and folders to be the same with a newly generated Angular v15 project 2022-11-07 11:01:23 +03:00
Sercan Yemen 388456b937 First step for upgrading to Angular & Angular Material v15 2022-11-07 10:07:27 +03:00
Sercan Yemen 36403c8ebb Merge branch 'dev' into dev-starter 2022-10-04 10:31:18 +03:00
Sercan Yemen 127280c040 Updated version number, packages and the changelog 2022-10-04 10:27:41 +03:00
Sercan Yemen cad7cd43f0 (ui/forms/fields) Added examples of number fields 2022-10-03 11:12:56 +03:00
Sercan Yemen 41756200ca (apps/mailbox) Fixed: Back button on details view is not working 2022-10-02 21:13:30 +03:00
Sercan Yemen 4a5f641c1c (layout/common/quick-chat) Fixed: Firefox doesn't like having sticky positioned elements inside a fixed positioned parent. This fix implements a mutation observer for '.cdk-global-scrollblock'. 2022-09-06 11:49:16 +03:00
Sercan Yemen 39ad558455 (FuseVerticalNavigation) Fixed: Firefox doesn't like having sticky positioned elements inside a fixed positioned parent. This fix implements a mutation observer for '.cdk-global-scrollblock'. 2022-09-06 11:49:05 +03:00
Sercan Yemen 404c4f5c07 Replace Moment with Luxon, closes #183
Big thanks to @steveschmitt for the majority of the work.
2022-08-24 13:15:38 +03:00
Sercan Yemen 51ee16ed93 (app.resolvers) Removed the extra user getter call since the user data already comes with the sign-in process to prevent confusion for the newcomers 2022-08-24 11:06:58 +03:00
Steve Schmitt 607f2afa90 Merge branch 'demo' into luxon 2022-08-22 08:11:29 -07:00
Sercan Yemen baf35619bd Merge branch 'dev' into dev-starter 2022-08-22 11:19:48 +03:00
Sercan Yemen 2a8586ce45 Merge branch 'dev' into dev-starter 2022-08-22 11:18:29 +03:00
Sercan Yemen 6599587e31 (dependencies) Updated Angular & Angular Material & various other packages
Updated the version number and changelog
2022-08-22 11:06:45 +03:00
Sercan Yemen 3fa878b3f2 (apps/mailbox) Better label toggle behavior
(apps/tasks) Better tag toggle behavior
2022-08-22 10:53:19 +03:00
Sercan Yemen a24bc3fc95 (tailwind) Removed the "aspect-ratio" plugin in favor of included "aspect" utility 2022-08-10 13:08:52 +03:00
Sercan Yemen 9b1c0f2541 (dashboards/project) Removed unnecessary classes from the buttons 2022-08-05 13:36:00 +03:00
Sercan Yemen 3ba64abf6e (tailwind.config) Fixed: typo on comment 2022-07-26 10:50:14 +03:00
Sercan Yemen 82ed80e35d (@fuse/tailwind/plugins/theming) Simplified the plugin and added more detailed comments 2022-07-25 15:17:55 +03:00
Sercan Yemen 72a63b30ca (docs) Fixed: Typos 2022-07-24 12:49:29 +03:00
Sercan Yemen d2b37efed4 (layout/common/messages) Fixed: Wrong color classes on "No Messages" icon
(layout/common/notifications) Fixed: Wrong color classes on "No Notifications" icon
(layout/common/shortcuts) Fixed: Wrong color classes on "No Shortcuts" icon
2022-07-24 11:29:02 +03:00
Sercan Yemen d5ec5a6fcd Merge branch 'dev' into dev-starter 2022-07-21 11:56:35 +03:00
Sercan Yemen 6d516a119a (dependencies) Updated Angular & Angular Material to v14.1.0
(dependencies) Updated various other packages
2022-07-21 11:51:28 +03:00
Steve Schmitt 3adf9bee6e Replace moment with luxon 2022-07-13 18:37:31 -07:00
Sercan Yemen bb06bccf91 (@fuse/overrides/angular-material) Fixed: mat-hint position is not working 2022-06-28 08:34:48 +03:00
Sercan Yemen 3018c0235f Added the missing release date to the changelog 2022-06-03 11:00:40 +03:00
Sercan Yemen 8e513ccf1e Merge branch 'dev' into dev-starter 2022-06-03 10:52:35 +03:00
Sercan Yemen a6399c0cf4 (@fuse) Fixed couple lint issues 2022-06-03 10:46:40 +03:00
Sercan Yemen 22d91673ae (dependencies) Updated to Angular and Angular Material v14.0.0 stable
(dependencies) Updated various other packages
2022-06-03 10:41:07 +03:00
Sercan Yemen 3e303a041a Updated the changelog 2022-06-02 11:02:30 +03:00
Sercan Yemen 714bc49c4e Updated the version number and added the changelog 2022-06-02 10:48:17 +03:00
Sercan Yemen 3cc4f31238 (dependencies) Updated Angular & Angular Material 2022-06-02 10:28:07 +03:00
Sercan Yemen c5aa094230 (icons) Removed iconsmind icons pack because of the bundle size concerns 2022-05-27 13:48:31 +03:00
Sercan Yemen cbd35d57f8 (global) Replaced iconsmind icons with heroicons 2022-05-27 13:45:52 +03:00
Sercan Yemen 11d5dcdb9d Updated various other packages 2022-05-26 14:01:50 +03:00
Sercan Yemen 66e5511402 Migrated to Angular Material to 14.rc-1 2022-05-26 13:59:01 +03:00
Sercan Yemen 20a03c3689 Migrated to Angular to 14.rc-2 2022-05-26 13:57:37 +03:00
Sercan Yemen d033470851 (layout) Fixed: The theme settings cog is not positioned correctly in Empty layout 2022-05-25 23:17:12 +03:00
Sercan Yemen c374c2c6cf (global) Replaced linked buttons with a tags + removed unnecessary routerLink attributes from some buttons 2022-05-25 13:29:47 +03:00
Sercan Yemen 30d75c9bd7 (@fuse/navigation) Keep the fragment as null if it's not provided to prevent empty hashtag appearing at the end of the url 2022-05-25 12:28:25 +03:00
Sercan Yemen 54cd21f496 (docs) Updated docs for FuseNavigation 2022-05-25 12:18:24 +03:00
Sercan Yemen 57d87fa1c4 (@fuse/navigation) Added "fragment" and "queryParams" support along with "preserveFragment" and "queryParamsHandling" 2022-05-25 12:17:56 +03:00
Sercan Yemen cd8c6ece0f (@fuse/service/confirmation) Cleaned-up the dialog component 2022-05-25 11:43:23 +03:00
Sercan Yemen 1bf4c48cdc (@fuse/service/platform) Added comments to the service file 2022-05-25 11:25:37 +03:00
Sercan Yemen ea9efc3dc2 (global) Added custom scrollbar styling for platforms other than macOS and iOS 2022-05-24 14:39:02 +03:00
Sercan Yemen 878a6bf191 (@fuse/services/platform) Added platform checker service 2022-05-24 14:38:50 +03:00
Sercan Yemen 099e745a36 (apps/academy) Fixed: Ring outside the current step's number is not visible 2022-05-24 12:58:06 +03:00
Sercan Yemen 150ddc64d7 (mock-api) Replaced the 'refresh-access-token' url with 'sign-in-with-token'
(auth) Changed the url on 'signInUsingToken' method to reflect the mock-api changes
2022-05-24 12:43:51 +03:00
Sercan Yemen a6d64b1747 (auth) Made the renewing token on "sign-in-with-token" process an optional step to simplify the login process 2022-05-24 12:42:23 +03:00
Sercan Yemen 6eff4a1898 (@fuse/overrides/quill) Added tooltip styles for better compatibility, closes #171 2022-05-24 12:17:45 +03:00
Sercan Yemen e3630218b5 (apps/mailbox) Fixed: Quill editor tooltips are not positioning correctly 2022-05-24 12:17:09 +03:00
Sercan Yemen 154095da0f (auth/sign-up) Added missing ngForm reference, closes #165 2022-05-24 11:30:10 +03:00
Sercan Yemen a32970b7c2 (@fuse/navigation) Moved the margin into the children's first child for smoother animations, closes #173 2022-05-24 09:56:44 +03:00
Sercan Yemen 2771d3b1ae (global) Replace @import with @use 2022-05-17 12:40:52 +03:00
Sercan Yemen 9b44793b64 (ui/page-layouts) Fixed: Toggle button selected background is not visible 2022-05-15 15:28:28 +03:00
Sercan Yemen 9521257b4d (apps/mailbox) Fixed: Empty route related issues 2022-05-12 23:50:43 +03:00
Sercan Yemen 5378a6b6ef (apps/chat) Fixed: Empty route related issues 2022-05-12 23:49:42 +03:00
Sercan Yemen c41e48df7f Angular 14 related changes 2022-05-12 23:40:40 +03:00
Sercan Yemen b87173b056 (layout/common/search) Implemented the new MatAutocomplete "autoSelectActiveOption" functionality 2022-05-12 23:37:33 +03:00
Sercan Yemen 6aaa355a48 (ui/icons) Updated the route configuration 2022-05-12 23:28:07 +03:00
Sercan Yemen b96dd041d9 (docs) Updated the directory structure 2022-05-12 23:25:51 +03:00
Sercan Yemen 9786c6baf5 (mock-api/file-manager) Fixed: http params are not working properly because of the new string conversion 2022-05-12 23:18:10 +03:00
Sercan Yemen f5cc14939c (apps/chat) Fixed: Empty route related issues 2022-05-12 23:13:02 +03:00
Sercan Yemen 8fd434600b Updated various other packages 2022-05-12 21:36:32 +03:00
Sercan Yemen 4c82f6749b Updated Angular & Angular Material to 14.0.0-rc.0 2022-05-12 21:23:12 +03:00
Sercan Yemen b0830148a3 (@fuse) Better scrolling for Quill editor 2022-05-12 13:36:40 +03:00
Sercan Yemen cdc54ab05e (Documentation) Updated the FuseDrawer documentation and example 2022-03-29 16:38:49 +03:00
Sercan Yemen e6ad547d27 (FuseDrawer) Updated the overlay and animation handling code for better stability 2022-03-29 16:38:42 +03:00
Sercan Yemen 4430754020 Merge remote-tracking branch 'origin/demo' into starter 2022-02-21 12:08:29 +03:00
Sercan Yemen 9d93a2b060 Merge remote-tracking branch 'origin/demo' into starter 2022-02-21 12:00:18 +03:00
Sercan Yemen afda4b35c9 Updated the changelog 2022-02-21 11:59:41 +03:00
Sercan Yemen 3b88638dee Updated various packages
Re-enabled AngularCLI cache since Tailwind related issues are appeared to be fixed
2022-02-21 11:47:35 +03:00
Sercan Yemen b96182c848 (layouts/dense) Fixed: Navigation appearance doesn't set correctly on small devices 2022-01-14 11:36:38 +03:00
Sercan Yemen 443a103d6f (@fuse/masonry) Removed the unnecessary scss file 2022-01-14 11:35:41 +03:00
Sercan Yemen 42241b279d (@fuse/navigation) Expose the width variables as css custom properties, so they can be overridden from the outside
(@fuse/drawer) Expose the width variable as a css custom property, so it can be overridden from the outside
2022-01-14 11:35:12 +03:00
Sercan Yemen e5eaea5013 Fixed: Typo on changelog 2022-01-01 23:05:09 +03:00
Sercan Yemen 6e85b9ff2a Fixed: Typo on changelog 2022-01-01 23:01:51 +03:00
Sercan Yemen 38a4c392fe Merge remote-tracking branch 'origin/demo' into starter 2022-01-01 22:52:20 +03:00
Sercan Yemen 6e593b1f1e Updated version number and the changelog 2022-01-01 22:50:22 +03:00
Sercan Yemen 57a3f6ae99 Updated various packages 2022-01-01 22:47:49 +03:00
Sercan Yemen 700a117654 Moved to the new syntax on Tailwind config 2022-01-01 22:33:23 +03:00
Sercan Yemen 5337c95782 Fixed: Typo on resolve object 2022-01-01 22:32:39 +03:00
Sercan Yemen 964c4b23a9 Fixed: Accent and Warn colors are not being generated for themes other than the Default 2022-01-01 22:32:24 +03:00
Sercan Yemen d9dee128de Merge remote-tracking branch 'origin/demo' into starter 2021-12-22 14:58:21 +03:00
Sercan Yemen a8337ce617 Removed extra import 2021-12-22 14:36:30 +03:00
Sercan Yemen 3ceda2cf3f Removed extract-config plugin entry 2021-12-22 14:28:13 +03:00
Sercan Yemen 805b50707e Updated Angular to v13.1
Updated ESLint to v13
Updated Tailwind to v3
Updated various other packages
2021-12-22 14:19:21 +03:00
sercan 3fd522de31 Updated changelog 2021-11-11 11:09:49 +03:00
sercan b84fb68a47 Merge remote-tracking branch 'origin/demo' into starter 2021-11-11 11:01:19 +03:00
sercan 4a2c7560e8 Updated Angular to 13.0.1
Updated various packages
2021-11-11 10:55:59 +03:00
sercan 46753d5402 Updated various packages 2021-11-09 13:25:11 +03:00
sercan 9d3e971325 Updated the changelog 2021-11-05 15:36:34 +03:00
sercan 9d7c015fe7 (@fuse/navigation) Don't need to use interpolation on scss variables anymore since Tailwind doesn't cause any problems with them anymore 2021-11-05 14:55:53 +03:00
sercan 4b5cac11f2 (docs) Small typo fix on FuseNavigation docs 2021-11-05 14:24:53 +03:00
sercan 6c62d25c35 Added .npmrc file so we can use npm versions that are bigger than 6
Updated the .nvmrc file
2021-11-05 11:48:26 +03:00
sercan 5c46b1aaa4 Updated changelog 2021-11-05 11:37:05 +03:00
sercan 3a1a7d44b6 Updated RxJS to 7.4.0
Optimized import paths
2021-11-05 11:36:03 +03:00
sercan 0076b1ee8a Updated changelog 2021-11-05 11:00:42 +03:00
sercan c69542679d Updated ngx-quill package 2021-11-05 10:52:33 +03:00
sercan e4ebe2fd7e (Breaking Change) Removed Calendar app due to FullCalendar's Angular component not being properly developed in the new version
(Breaking Change) Removed Fuse DateRange component (alternative: https://github.com/fetrarij/ngx-daterangepicker-material)
2021-11-05 10:50:19 +03:00
sercan f380d8ca16 Updated Angular to v13
Updated Angular Material to v13
Updated version numbers and added the changelog
Updated various packages
2021-11-04 13:20:44 +03:00
sercan 6b14c1db7f (@fuse/loading-bar) Separated the service and interceptor from the component, updated its docs 2021-11-04 12:25:24 +03:00
sercan 20901117d1 (layout/common) Small comment fix 2021-10-25 15:03:33 +03:00
sercan 83e3c85448 (@fuse/mock-api) Added 'head', 'jsonp' & 'options' support 2021-09-21 09:54:53 +03:00
sercan 3d6714008a Merge remote-tracking branch 'origin/demo' into starter 2021-09-10 12:27:59 +03:00
sercan ea954a75de (app.routing) Fixed: Wrong and missing eslint exceptions 2021-09-10 12:26:21 +03:00
sercan 4d4b411f76 (AuthModule) Fixed: Wrong sign in page link 2021-09-10 12:25:23 +03:00
sercan 7b5217d009 (@fuse/loading-bar) Fixed: Don't turn off the auto mode on docs examples 2021-09-06 23:56:39 +03:00
sercan e671100bc5 (@fuse/loading-bar) Fixed: Wrong method name on docs 2021-09-06 23:42:16 +03:00
sercan f910615831 (@fuse/loading-bar) First iteration of the FuseLoadingBar component, service, interceptor and their documentation 2021-09-06 23:32:50 +03:00
sercan 778679e136 (dependencies) Updated Angular & Angular Material to 12.2.4 and updated various other packages 2021-09-06 23:32:03 +03:00
sercan c25610ee4e (docs/other-components) Fixed: Weird mat-drawer issue 2021-09-06 22:52:41 +03:00
sercan 3ddd7e4533 (docs/fuse-components) Fixed: Weird mat-drawer issue 2021-09-06 22:52:09 +03:00
sercan c21c362b84 (QuickChat) Added docs page 2021-09-06 21:18:50 +03:00
sercan 9f97d74911 (@fuse/overrides/angular-material) Fixed: Normal border color of the text field overrides the invalid and focus border colors on dark themes 2021-09-02 23:48:26 +03:00
sercan 4b37f2304a Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 16:44:22 +03:00
sercan 08aec7c3db Increased the version number 2021-08-31 16:43:38 +03:00
sercan 0f249f287e Increased the version number and updated the changelog 2021-08-31 16:43:18 +03:00
sercan c7b8a4564b (QuickChat) Fixed: Wrong css causing a lot of problems 2021-08-31 16:42:57 +03:00
sercan 82244fd40e Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 15:50:30 +03:00
sercan c5433cb917 Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 15:49:55 +03:00
sercan b6a3023ebd Increase the version number 2021-08-31 15:49:10 +03:00
sercan 693e44dbaf (QuickChat) Fixed: Overflowing issue 2021-08-31 15:47:35 +03:00
sercan cf5f13d78e Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:18:08 +03:00
sercan 206ef711a4 (QuickChat) Don't use types from outside 2021-08-31 10:17:57 +03:00
sercan ef85907d1b Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:17:19 +03:00
sercan 7e0cc1249e (QuickChat) Don't use types from outside 2021-08-31 10:17:06 +03:00
sercan 138a43da59 (QuickChat) Don't use types from outside 2021-08-31 10:16:13 +03:00
sercan cafc3188cf Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:07:33 +03:00
sercan fe7e2514a6 Updated dependencies, increased the version number & updated the changelog 2021-08-31 09:43:10 +03:00
sercan b8f0d9f0b2 (QuickChat) Added the Quick Chat bar 2021-08-31 09:21:28 +03:00
sercan 2a4a392153 (layout) Separated the Settings drawer from the layout component 2021-08-31 09:20:55 +03:00
sercan c2fa88f4d4 (fuse/drawer) Fixed: Final opacity of the overlay is not permanent due to player being destroyed right after the animation 2021-08-17 22:05:13 +03:00
sercan 6381362326 Merge remote-tracking branch 'origin/demo' into starter 2021-08-12 17:05:40 +03:00
sercan 67d25012ec Increased the version number & updated the changelog 2021-08-12 17:04:57 +03:00
sercan e1942f46fd Merge remote-tracking branch 'origin/demo' into starter 2021-08-12 16:57:58 +03:00
sercan 6de6a07778 Decreased budget sizes since new Fuse is a lot smaller compared to the one with the old design 2021-08-12 13:57:29 +03:00
sercan e7ab0ea13f (apps/mailbox) Fixed: Compose dialog doesn't work correctly on small height resolutions
(apps/mailbox) Style improvements
2021-08-12 13:45:34 +03:00
sercan 4b686d86cc (@fuse/overrides) Fixed: Quill editor is not styled correctly by default 2021-08-12 13:42:59 +03:00
sercan 190395f14b (@fuse/theming) Better structuring on the themes.scss file
(@fuse) Disabled Angular Material 'theme' sanity check since we use 'all-component-themes' without a color map
2021-08-12 13:17:53 +03:00
sercan 4a9b8ee91e (dependencies) Updated Angular, Angular Material and various other dependencies 2021-08-12 11:32:04 +03:00
sercan 488fe8a1eb (ui/page-layouts) Fixed: Demo layout navigation appearance is not correct 2021-08-11 22:25:49 +03:00
sercan db9a2a2433 (dependencies) Updated Angular, Angular Material and various other dependencies 2021-08-11 22:25:15 +03:00
sercan 3dda8479cf (tailwindcss) Removed old jsdoc from the config file 2021-08-08 22:27:24 +03:00
sercan 7c402670a1 (docs/confirmation) Updated the docs of the confirmation dialog 2021-08-04 10:10:07 +03:00
sercan f6bf0fb5d3 (fuse/confirmation) Fixed: Dialog size cannot be updated using dialogRef's "updateSize" method 2021-08-04 09:54:35 +03:00
sercan d44c004d01 Removed empty "styles" from component decorators 2021-08-04 09:46:36 +03:00
sercan ce656430c8 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:40:12 +03:00
sercan 4ec40271c5 Updated the package.json version number 2021-07-29 10:39:16 +03:00
sercan c93b1ce232 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:23:27 +03:00
sercan b874b37db2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:21:30 +03:00
sercan b21cdf1655 Updated the changelog and increased the version number 2021-07-29 10:19:28 +03:00
sercan 6fff259fe3 (dependencies) Updated Angular, Angular Material and various other dependencies 2021-07-29 10:15:13 +03:00
sercan 8fcb0aea03 (docs) Updated the multi language guide 2021-07-29 10:14:52 +03:00
sercan 2c90770d9b (index) Updated the title, description and keywords 2021-07-23 22:29:45 +03:00
sercan 1581ea74cc (dashboards/finance) Added finance dashboard
(dashboards/crypto) Added crypto dashboard
2021-07-23 22:23:42 +03:00
sercan 569809aabb (dashboards/project) Small tweaks 2021-07-23 22:23:02 +03:00
sercan dde9333120 (dashboards/project) Small tweaks on the header 2021-07-23 21:30:51 +03:00
sercan 10ec1790ca (dashboards/project) Module import order 2021-07-21 12:22:23 +03:00
sercan a2ff55d4c1 (dashboards/project) Light header on light themes, small adjustments in the project selector 2021-07-21 12:22:02 +03:00
sercan 966e2db743 (apps/contacts) Small adjustments for better consistency
(apps/ecommerce/inventory) Small adjustments for better consistency
2021-07-21 11:36:43 +03:00
sercan 4287361a09 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:49:22 +03:00
sercan 4f19eb6171 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:48:48 +03:00
sercan 49cccde93b Increased the version number & updated the changelog 2021-07-16 20:47:50 +03:00
sercan 952b64297b (fuse/confirmation) Fixed: Confirmation dialog colors are not correct for the Dark mode 2021-07-16 20:45:35 +03:00
sercan 9b3ff6a724 Updated changelog 2021-07-16 12:56:35 +03:00
sercan cd13f9d9a4 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:38:44 +03:00
sercan db8c52f093 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:36:58 +03:00
sercan 961b86c8cb (apps/contacts) Added confirmation to the "Delete contact" action using FuseConfirmationService
(apps/ecommerce/inventory) Added confirmation to the "Delete product" action using FuseConfirmationService
(apps/scrumboard) Added confirmation to the "Delete list" action using FuseConfirmationService
(apps/tasks) Added confirmation to the "Delete task" action using FuseConfirmationService
2021-07-16 12:28:43 +03:00
sercan 8b977c0eeb Updated Angular, Angular Material and couple other dependencies & increased the version number 2021-07-16 12:00:46 +03:00
sercan 35e56cd6af (fuse/confirmation) Small tweak on the docs 2021-07-12 12:39:52 +03:00
sercan c04550b887 (ui/confirmation-dialog) Created a separate page for FuseConfirmationService and moved the example configurator to there for better visibility 2021-07-12 12:37:47 +03:00
sercan 747b4f44c8 (ui/advanced-search) Moved the routing information into the module file 2021-07-12 12:37:06 +03:00
sercan c4914c80b3 (fuse/confirmation) Small fix on the docs 2021-07-10 22:11:39 +03:00
sercan 178d09597b (fuse/confirmation) First iteration of the FuseConfirmationService 2021-07-10 22:03:58 +03:00
sercan d206c55e6e (ui/fuse-components) Renamed the component reference 2021-07-09 11:49:21 +03:00
sercan 9abe887df1 (docs) Moved Fuse Components and Other Components into UI for better visibility and better categorization 2021-07-09 11:30:00 +03:00
sercan b87fdc407c (Navigation) Casing fixes on navigation data 2021-07-09 11:12:52 +03:00
sercan 58440b63a7 (ui/material-components) Renamed the component 2021-07-09 11:12:07 +03:00
sercan 63f6edee9a (tailwindcss) Fixed: Ordered lists with "s" modifier causes builder to throw errors 2021-07-05 23:13:38 +03:00
sercan 2189232273 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:11:01 +03:00
sercan ca8e422b21 (app.module) Alphabetical order on Router's extra options 2021-07-02 23:10:41 +03:00
sercan 36b89e75db Update package name 2021-07-02 23:05:27 +03:00
sercan 8c2ff122b2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:01:10 +03:00
sercan cc703081ca (dashboards/analytics) Removed unused chart options declarations 2021-07-02 22:59:47 +03:00
sercan 038c74df50 (transloco) Defined a fallback language 2021-07-02 22:50:25 +03:00
sercan 9abbf5fec2 (karma.conf.js) Updated the default path 2021-07-02 22:50:19 +03:00
sercan 0ebc16ec05 (package.json) Removed "e2e" script since we don't provide e2e testing environment by default 2021-07-02 22:50:10 +03:00
sercan b2cb512b0e Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:29:26 +03:00
sercan 21652570c2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:28:05 +03:00
sercan 56c4eb0356 Updated changelog 2021-07-01 14:26:49 +03:00
sercan a8a4f2b18d Updated changelog and increased the version number 2021-07-01 13:31:41 +03:00
sercan 36c8727616 (layout/settings-drawer) Fixed: Issues on small screen devices 2021-07-01 12:55:02 +03:00
sercan 5ea37aed99 (layouts) Fixed: Header buttons are not fitting on certain layouts
(layouts) Hide the "fuse-fullscreen" button on smaller devices since they don't support fullscreen
2021-07-01 12:50:34 +03:00
sercan cbce71f155 (apps/help-center) Fixed: Small dark mode issues 2021-07-01 12:37:27 +03:00
sercan ed47050232 (apps/ecommerce/inventory) Fixed: Tags selector border colors are not correct on dark mode 2021-07-01 12:37:09 +03:00
sercan c86a538d41 (Angular Material) Apply rounded styles by default 2021-07-01 12:23:49 +03:00
sercan f369206ef8 (layout/common) Explicitly define the overlay position strategy properties
(apps/contacts) Explicitly define the overlay position strategy properties
(apps/mailbox) Explicitly define the overlay position strategy properties
(apps/tasks) Explicitly define the overlay position strategy properties
2021-06-25 22:57:14 +03:00
sercan 1659d4babd (tailwindcss) Fixed: Dark mode classes are not being purged correctly due to the wrong safelist entry 2021-06-25 12:21:34 +03:00
sercan fa37f99d33 (docs) Use alternative spacing since 12s are removed 2021-06-25 11:09:30 +03:00
sercan 331968ac5b (tailwindcss) Breaking: Removed 5, 6 & 12 fractional spacing values since they are not used in Demo by default and they are mostly not needed because of Flex and Grid. If you happen to use them, you can manually add them back. 2021-06-25 11:08:56 +03:00
sercan 27274c84d6 (@fuse/navigation) Fixed: Vertical navigation blocks scroll if it's destroyed while in 'over' mode and opened 2021-06-24 18:04:19 +03:00
sercan 4b8a101a3e (transloco) Fixed: Language files cannot be loaded if using a base href other than "/" 2021-06-24 10:54:03 +03:00
sercan 8080a85d40 (fuse-drawer) Fixed: Memory leak due to the animation player, thanks to Vadym Pidoplichko for coming up the issue and the solution. 2021-06-24 10:29:34 +03:00
sercan 36784c405f (package.json) Added "description" and "author" fields 2021-06-21 18:56:15 +03:00
sercan 8f4f7886d5 (fuse/navigation) Moved *ngIf directives into their own "ng-container" containers 2021-06-20 21:59:24 +03:00
sercan d693a08136 (general) Tweaked the "Angular Material components" navigation item title 2021-06-20 21:30:10 +03:00
sercan 0c0ef40de3 (docs) Added docs about navigation tooltip 2021-06-20 21:29:37 +03:00
sercan f4d737d3a3 (fuse/navigation) Added "tooltip" property to show tooltips on navigation items using MatTooltip 2021-06-20 21:28:47 +03:00
sercan 90891eb201 Merge remote-tracking branch 'origin/demo' into starter 2021-06-15 08:36:32 +03:00
sercan 47d9ddb08c Updated changelog 2021-06-15 08:32:13 +03:00
sercan 4da3612d22 Updated changelog and increased the version number 2021-06-14 14:29:58 +03:00
sercan 403a949d4a (apps/ecommerce/inventory) Small mobile experience tweaks 2021-06-14 12:25:04 +03:00
sercan 5b78a68116 (apps/ecommerce/inventory) Better image containment on row details 2021-06-14 12:22:51 +03:00
sercan 214116e10d (apps/ecommerce/inventory) Replaced the mat-table with a custom grid for better mobile experience and better performance, improved the mobile experience 2021-06-14 12:03:17 +03:00
sercan 5962c80e8d (docs) Added "target" docs to navigation 2021-06-14 08:53:01 +03:00
sercan ff086b1ed0 (fuse/navigation) Added "target" for setting the target attribute on outgoing links. Thanks @danielehrhardt for the original PR, closes #154 2021-06-14 08:52:29 +03:00
sercan efdfa6418a (core) Go back to the 'classy' layout by default 2021-06-10 14:56:21 +03:00
sercan c1c9904b9d (layouts/common/search) Improved the autocomplete design 2021-06-10 14:56:00 +03:00
sercan 39650d3cc9 (layouts) Use navigation service data for horizontal navigation 2021-06-10 10:13:43 +03:00
sercan bafa9adc01 (ui/page-layouts) Added tabbed version of Simple Fullwidth page layout 2021-06-09 11:41:39 +03:00
sercan bb9023f9df (fuse/navigation) Fixed: First children of collapsable items don't have proper spacing at the top 2021-06-09 10:32:26 +03:00
sercan 66096718e0 (docs) Updated the docs to reflect the latest changes 2021-06-09 10:22:18 +03:00
sercan 945d0a2240 (fuse/fullscreen) Added [tooltip] & [iconTpl] inputs for customizing the Fullscreen trigger button 2021-06-08 18:29:49 +03:00
sercan 9005f08ac7 (app.resolver) Use services to request the initial data
(layouts) Common components of layouts now requests their data directly from their service rather than getting it from route data
(core) New navigation service to request and store the navigation data
2021-06-08 17:29:45 +03:00
sercan 89f5a4ec69 (core/user) Renamed user.model to user.types for better consistency 2021-06-07 12:18:39 +03:00
sercan ca7b4c7e5d (ui/advanced-search) Removed unused MatIconModule import 2021-06-07 11:41:29 +03:00
sercan bb57ec2324 (ui/advanced-search) Added an example search form that uses query parameters for Advanced Search forms 2021-06-07 11:40:33 +03:00
sercan 11ad2c89df (apps/file-manager) Added support for nested folder views 2021-06-05 13:57:39 +03:00
sercan fc1e7b02b0 (data/navigation) Fixed the "Invoice" icon, added missing dashboard links to the "futuristicNavigation" data 2021-06-04 22:28:53 +03:00
sercan 446bfe4139 (ui/angular-material) Added a component list that redirects to the related page of the official docs 2021-06-04 22:21:47 +03:00
sercan 6c7201b77a Merge remote-tracking branch 'origin/demo' into starter 2021-06-03 13:28:30 +03:00
sercan 2c5cd60c0a (general) Updated version numbers and changelog 2021-06-03 13:25:07 +03:00
sercan decb238f73 (dependencies) Updated various dependencies to their latest versions
(fuse/highlight) Updated the import path
2021-06-03 13:18:05 +03:00
sercan ab3ad4fd2f (apps/scrumboard) Dark mode fixes and tweaks 2021-06-03 11:27:51 +03:00
sercan c2dd77d7a3 (angular.json) Removed "e2e" entry, fixed the styles file path for "test" 2021-06-02 12:45:12 +03:00
sercan a78b087a68 (apps/scrumboard) New version of the Scrumboard app 2021-06-02 11:42:22 +03:00
sercan 84d40427a1 (apps/ecommerce) Small tweaks
(apps/mailbox) Small tweaks
2021-06-02 11:41:47 +03:00
sercan f295fd9061 (fuse/autogrow) BREAKING: Removed fuseAutogrow in favor of matTextareaAutosize since all of its problems solved, use [matTextareaAutosize] without any vertical padding on the textarea itself. 2021-05-31 17:14:03 +03:00
sercan b98cfc1d37 (Angular Material) Increased default MatDialog border radius to 16px for better consistency 2021-05-31 16:12:08 +03:00
sercan 0ba5677c01 (Dependencies) Updated Angular & Angular Material to v12.0.2 2021-05-31 10:49:51 +03:00
sercan 90f869e7b9 Merge remote-tracking branch 'origin/demo' into starter 2021-05-31 10:46:26 +03:00
sercan 96ef1281ae (Angular Material) Fixed: Density setting is not working for dark themes 2021-05-31 10:45:29 +03:00
sercan 2d2db97416 Merge remote-tracking branch 'origin/demo' into starter 2021-05-24 14:33:12 +03:00
sercan 466bf50de4 Increased the version number
Updated the changelog
2021-05-24 14:32:45 +03:00
sercan 5daa2260e6 Merge remote-tracking branch 'origin/demo' into starter 2021-05-24 14:29:35 +03:00
sercan 95bc7dc4db (apps/ecommerce/inventory) Performance improvements, decreased the mockApi delay 2021-05-24 09:22:18 +03:00
sercan af984fcba1 Merge remote-tracking branch 'origin/demo' into starter 2021-05-23 07:13:28 +03:00
sercan cfca19dc68 (mockApi) Removed typings from data files 2021-05-23 07:11:58 +03:00
sercan a0c20f8d59 (pages/settings) Fixed: Settings container component width is not filling the container 2021-05-22 21:14:42 +03:00
sercan 97d3662417 Merge remote-tracking branch 'origin/demo' into starter 2021-05-21 12:17:06 +03:00
sercan df9f2256cd Increased the version number
Updated the changelog
2021-05-21 12:02:05 +03:00
sercan 6bcd04b799 (eslint) Fixed linting issues 2021-05-21 11:48:42 +03:00
sercan 3c0e326113 (dependencies) Updated various packages to their latest versions 2021-05-21 11:40:50 +03:00
sercan c7158377f7 Revert "(dependencies) Updated Angular & Angular Material to v12.0.1"
This reverts commit 105575d4
2021-05-20 22:46:40 +03:00
sercan 105575d40e (dependencies) Updated Angular & Angular Material to v12.0.1 2021-05-20 22:23:25 +03:00
sercan f470313d72 (pages/activities) Couple data tweaks 2021-05-20 16:51:40 +03:00
sercan 60e9c65505 (pages/activities) Couple data and style tweaks 2021-05-20 16:48:38 +03:00
sercan 3b727fe859 (pages/activities) Added Activities page (timeline) 2021-05-20 15:30:14 +03:00
sercan 4694bb401d (layout/common) Added trackBy functions to ngFor loops in common components 2021-05-19 22:43:16 +03:00
sercan ee86dc6245 (tailwind) Use TAILWIND_MODE environment variable to activate purge on build 2021-05-19 14:45:30 +03:00
sercan 3d09241c64 (fuse/animations) Fixed: Barrel exports
(FuseMasonry) Fixed: Barrel exports
(FuseUtilsService) Fixed: Barrel exports
(FuseValidators) Fixed: Barrel exports
2021-05-19 14:37:38 +03:00
sercan e499c06884 (apps/mailbox) Small tweak on resolver's comment 2021-05-19 13:38:10 +03:00
sercan eca618c95b (FuseNavigation) Fixed: If [routerLinkActiveOptions] is "undefined" initially, router throws an error and stops working 2021-05-19 13:37:37 +03:00
sercan 8524df013a (fuse/tailwind) Fixed: Barrel exports are wrong for FuseTailwindService 2021-05-19 10:57:40 +03:00
sercan d897a244c8 Merge remote-tracking branch 'origin/demo' into starter 2021-05-18 16:25:53 +03:00
sercan e4df408abe (FuseNavigation) Added support for new "isActiveMatchOptions" for Basic navigation items; https://github.com/angular/angular/pull/40303
(docs) Updated FuseNavigation documentation
2021-05-18 16:09:31 +03:00
sercan fd859a8663 (comments) Fixed: The word 'data' replaced with 'mock-api' by mistake in the past causing a lot of comments to make no sense 2021-05-18 15:18:44 +03:00
sercan 59960af7a5 (MultiLang) Added multi language support using @ngneat/transloco
(docs) Added docs about multi language
2021-05-18 15:11:57 +03:00
sercan 74c4dc2ad8 (app.module.ts) Small tweaks on comments 2021-05-18 14:34:46 +03:00
sercan f76f38b812 (FuseVerticalNavigation) Added missing return types 2021-05-18 14:12:38 +03:00
sercan 5c40e99518 (FuseNavigation) Use the generic return type for "getComponent"
(docs) Updated FuseNavigation docs
2021-05-18 13:10:39 +03:00
sercan c1ca701e92 (FuseNavigation) Added a generic return type for "getComponent" method on FuseNavigationService 2021-05-18 13:08:02 +03:00
sercan e00dda98bc (core) Separated the "auth" and "icon registry" to their own modules to keep the CoreModule simple 2021-05-18 11:44:42 +03:00
sercan 9edc62f703 (eslint) Activate explicit return types on functions and methods 2021-05-18 11:42:36 +03:00
sercan f9c8e16778 (fuse/mock-api) Added a return type to the factory function 2021-05-17 15:21:08 +03:00
sercan 4a30e3482c (eslint) Removed e2e tsconfig path as there is no default e2e solution included into Angular since v12.0.0 2021-05-16 16:22:40 +03:00
sercan 837f444cc9 (overrides/angular-material) Use @apply whenever it's possible 2021-05-16 15:55:17 +03:00
sercan d0876eb80c (overrides) Change the text and arrow color of mat-select on focus when it's used as a prefix or suffix in mat-form-field 2021-05-16 15:54:55 +03:00
sercan 3395e7f0bc (docs) Updated docs 2021-05-15 13:44:13 +03:00
sercan d146a92c79 Merge remote-tracking branch 'origin/demo' into starter 2021-05-15 13:18:13 +03:00
sercan ee1caef303 Increased the version number
(changelog) Updated changelog
2021-05-14 17:44:18 +03:00
sercan cad136c0e5 (dependencies) Updated packages 2021-05-14 17:26:28 +03:00
sercan d159ae1458 (linting) Migrated over to the ESLint 2021-05-14 17:17:06 +03:00
sercan 0c5f5b9165 (global) "ng build" automatically builds into production mode by default 2021-05-14 14:15:54 +03:00
sercan f4ca06a9a8 (dependencies) Updated Angular Material to v12.0.0 2021-05-14 14:15:14 +03:00
sercan 6a86deaeec (dependencies) Updated Angular to v12.0.0 2021-05-14 12:12:24 +03:00
sercan 44e7401310 (pages/settings) Moved titles to the same line with sidebar toggle button + small alignment tweaks 2021-05-12 15:49:36 +03:00
sercan 6d1dee8d0d (3rdParty) Fixed: "_redirects" file must be in /src folder 2021-05-12 14:47:53 +03:00
sercan b8b3d1daab (3rdParty) Added a _redirects file for Netlify support 2021-05-12 14:28:16 +03:00
sercan c3ed184853 (pages/settings) Added a close button for the sidebar 2021-05-12 14:14:03 +03:00
sercan a9ada174b4 (routing) Use "corrected" behavior for relative link resolution (https://github.com/angular/angular/pull/22394) as it's the default value starting from Angular v11 (https://github.com/angular/angular/pull/25609) 2021-05-12 12:46:01 +03:00
sercan 57ba071fa5 (pages/settings) Fixed: Drawer shouldn't be closed on 'side' mode when changing the selected panel 2021-05-11 13:09:38 +03:00
sercan cc761d58e5 (pages/settings) Added new Settings page 2021-05-11 12:48:51 +03:00
sercan 5c3db88908 (apps/ecommerce) Tweaked hover color on inventory list for better consistency 2021-05-07 12:43:04 +03:00
sercan 039eef98ee (apps/chat) Tweaked hover colors on lists for better consistency 2021-05-07 12:40:02 +03:00
sercan 83e67e1286 (docs/changelog) Small visual improvement on changelog titles 2021-05-07 12:33:50 +03:00
sercan 2bea991ba3 (refactoring) Move *ngFor directives to their own <ng-container> elements. This is mostly a personal preference but it's a good habit to have as you cannot put more than one structural directive on a single element. This way our main repeated element is free of any common structural directives so we can use ours on them if needed. 2021-05-07 12:10:45 +03:00
sercan 7e430a269c (apps/tasks) Visual improvements
(apps/contacts) Tweaked the hover color on contacts list for better consistency
2021-05-07 11:54:47 +03:00
sercan 27b6858b76 Merge remote-tracking branch 'origin/demo' into starter 2021-05-06 17:12:50 +03:00
sercan 4ccce1b423 Increased the version number
(changelog) Updated the changelog
2021-05-06 17:11:12 +03:00
sercan f6b4ca0880 (apps/notes) Responsive adjustments 2021-05-06 17:05:56 +03:00
sercan 77014174e8 (apps/notes) New version of the Notes app 2021-05-06 17:01:14 +03:00
sercan 5ac7002a98 (fuse/masonry) Fixed: Masonry doesn't work with the data that comes from async pipe 2021-05-06 12:07:07 +03:00
sercan b0f1e1de95 (apps/mailbox) App title font size adjustment for better consistency 2021-05-05 17:52:10 +03:00
sercan cf01383358 (apps/mailbox) Use shadow on threads for better consistency 2021-05-05 17:27:39 +03:00
sercan e4442d683b (apps/tasks) Tweaked the hover color on task list for better consistency 2021-05-05 17:27:12 +03:00
sercan 623b43a94c (fuse/styles) Fixed: fuse-highlight doesn't have a margin around in Docs 2021-05-03 18:49:00 +03:00
sercan e7a1d386a6 (fuse/masonry) Added a new component (and its docs) for creating Masonry layouts 2021-05-03 18:47:57 +03:00
sercan b05763135e (apps/chat) Adjustments and optimizations for smaller devices 2021-04-30 19:55:37 +03:00
sercan fcfba4c9e4 Merge remote-tracking branch 'origin/demo' into starter 2021-04-30 19:40:30 +03:00
sercan 40894e0aa3 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/academy/academy.service.ts
#	src/app/modules/admin/apps/academy/details/details.component.html
#	src/app/modules/admin/apps/academy/list/list.component.html
#	src/app/modules/admin/apps/mailbox/list/list.component.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
#	src/app/modules/admin/pages/pricing/modern/modern.component.html
#	src/app/modules/admin/pages/pricing/simple/simple.component.html
#	src/app/modules/admin/pages/pricing/single/single.component.html
#	src/app/modules/admin/pages/pricing/table/table.component.html
2021-04-30 19:40:07 +03:00
sercan 5dd60c816c (apps/chat) Small adjustments and tweaks for Dark mode 2021-04-30 19:39:02 +03:00
sercan 0ac967a945 Removed optional chaining operators to support Node v12
Set the version on .nvmrc to 12
2021-04-30 19:27:40 +03:00
sercan e3821da077 (apps/chat) New and improved Chat app 2021-04-30 19:18:09 +03:00
sercan ee48e11548 Increased the version number
(dependencies) Updated Angular, Angular Material and various other packages
(changelog) Updated the changelog
2021-04-30 19:07:53 +03:00
sercan 215546cc31 (apps/academy) Removed a misplaced import 2021-04-29 19:57:58 +03:00
sercan 072dbce6d4 (fuse/fullscreen) Added Fullscreen toggle component 2021-04-28 10:55:32 +03:00
sercan 5ffe0d0efa (pages/pricing) Improved the spacing of the CTA section on all pricing pages 2021-04-26 23:42:16 +03:00
sercan e90fb9e618 (apps/academy) Added missing trackBy functions to '*ngFor's 2021-04-26 16:41:21 +03:00
sercan 88e98d002d (apps/mailbox) Removed unused methods 2021-04-26 16:08:19 +03:00
sercan deeef323f9 (apps/academy) Better error handling on courses that are not exist 2021-04-26 15:59:44 +03:00
sercan 8dcf21cb1a Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:23:15 +03:00
sercan d917f03883 Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:20:06 +03:00
sercan 0f2ddbda83 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
2021-04-26 09:56:44 +03:00
sercan fa0d74504b Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 09:56:29 +03:00
sercan ad2b19a07a Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/contacts/details/details.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.ts
#	src/app/modules/landing/home/home.component.html
2021-04-26 09:31:42 +03:00
sercan 4bf11591a2 (Assets) Added avatar images back 2021-04-19 13:08:24 +03:00
sercan f45a605b4e Preparing the starter 2021-04-15 17:43:28 +03:00
sercan c150a8902c Starter 2021-04-15 17:23:49 +03:00
1049 changed files with 33274 additions and 123229 deletions
-17
View File
@@ -1,17 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
+95
View File
@@ -0,0 +1,95 @@
{
"root": true,
"env": {
"es6": true
},
"parserOptions": {
"ecmaVersion": 2018
},
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "",
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "",
"style": "camelCase"
}
],
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/no-inferrable-types": "off",
"arrow-parens": [
"error",
"as-needed",
{
"requireForBlockBody": true
}
],
"brace-style": [
"off",
"off"
],
"import/order": "off",
"max-len": [
"error",
{
"ignorePattern": "^import |^export | implements",
"code": 180
}
],
"no-underscore-dangle": "off",
"object-shorthand": "off",
"quote-props": [
"error",
"consistent"
],
"quotes": [
"error",
"single"
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}
+1 -1
View File
@@ -12,7 +12,6 @@
# profiling files # profiling files
chrome-profiler-events*.json chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors # IDEs and editors
/.idea /.idea
@@ -32,6 +31,7 @@ speed-measure-plugin*.json
.history/* .history/*
# misc # misc
/.angular/cache
/.sass-cache /.sass-cache
/connect.lock /connect.lock
/coverage /coverage
+1 -1
View File
@@ -1 +1 @@
14 20
+3
View File
@@ -2,6 +2,9 @@
// @ 3rd party credits // @ 3rd party credits
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// Flags
https://github.com/Yummygum/flagpack-core
// Icons // Icons
Material - https://material.io/tools/icons Material - https://material.io/tools/icons
Feather - https://feathericons.com/ Feather - https://feathericons.com/
+6 -4
View File
@@ -1,8 +1,10 @@
# Fuse - Admin template and Starter project for Angular # Fuse - Admin template and Starter project for Angular
This project was generated with [Angular CLI](https://github.com/angular/angular-cli)
## Development server ## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
## Code scaffolding ## Code scaffolding
@@ -10,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
## Build ## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests ## Running unit tests
@@ -18,8 +20,8 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests ## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help ## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
+43 -60
View File
@@ -20,20 +20,29 @@
"outputPath": "dist/fuse", "outputPath": "dist/fuse",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": true, "inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": [ "allowedCommonJsDependencies": [
"apexcharts", "apexcharts",
"highlight.js", "highlight.js",
"crypto-js/enc-utf8", "crypto-js/enc-utf8",
"crypto-js/hmac-sha256", "crypto-js/hmac-sha256",
"crypto-js/enc-base64" "crypto-js/enc-base64",
"flat",
"quill-delta"
], ],
"assets": [ "assets": [
"src/favicon-16x16.png", "src/favicon-16x16.png",
"src/favicon-32x32.png", "src/favicon-32x32.png",
"src/assets" "src/assets",
{
"glob": "_redirects",
"input": "src",
"output": "/"
}
], ],
"stylePreprocessorOptions": { "stylePreprocessorOptions": {
"includePaths": [ "includePaths": [
@@ -52,96 +61,70 @@
}, },
"configurations": { "configurations": {
"production": { "production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "5mb", "maximumWarning": "3mb",
"maximumError": "8mb" "maximumError": "5mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "100kb", "maximumWarning": "75kb",
"maximumError": "150kb" "maximumError": "90kb"
} }
] ],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
} }
} },
"defaultConfiguration": "production"
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "fuse:build"
},
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "fuse:build:production" "buildTarget": "fuse:build:production"
},
"development": {
"buildTarget": "fuse:build:development"
} }
} },
"defaultConfiguration": "development"
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "fuse:build" "buildTarget": "fuse:build"
} }
}, },
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"main": "src/test.ts", "polyfills": [
"polyfills": "src/polyfills.ts", "zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js", "inlineStyleLanguage": "scss",
"assets": [ "assets": [
"src/favicon-16x16.png", "src/favicon-16x16.png",
"src/favicon-32x32.png", "src/favicon-32x32.png",
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles/styles.scss"
], ],
"scripts": [] "scripts": []
} }
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
},
"configurations": {
"production": {
"devServerTarget": "fuse:serve:production"
}
}
} }
} }
} }
}, }
"defaultProject": "fuse"
} }
-40
View File
@@ -1,40 +0,0 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const {SpecReporter, StacktraceOption} = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout : 11000,
specs : [
'./src/**/*.e2e-spec.ts'
],
capabilities : {
browserName: 'chrome'
},
directConnect : true,
SELENIUM_PROMISE_MANAGER: false,
baseUrl : 'http://localhost:4200/',
framework : 'jasmine',
jasmineNodeOpts : {
showColors : true,
defaultTimeoutInterval: 30000,
print : function ()
{
}
},
onPrepare()
{
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY
}
}));
}
};
-23
View File
@@ -1,23 +0,0 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', async () => {
await page.navigateTo();
expect(await page.getTitleText()).toEqual('Welcome to Fuse!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE
} as logging.Entry));
});
});
-14
View File
@@ -1,14 +0,0 @@
import { browser, by, element } from 'protractor';
export class AppPage
{
async navigateTo(): Promise<unknown>
{
return browser.get(browser.baseUrl);
}
async getTitleText(): Promise<string>
{
return element(by.css('app-root h1')).getText();
}
}
-13
View File
@@ -1,13 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es2018",
"types": [
"jasmine",
"node"
]
}
}
-45
View File
@@ -1,45 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config)
{
config.set({
basePath : '',
frameworks : ['jasmine', '@angular-devkit/build-angular'],
plugins : [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client : {
jasmine : {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter : {
dir : require('path').join(__dirname, './coverage/angular11'),
subdir : '.',
reporters: [
{type: 'html'},
{type: 'text-summary'}
]
},
reporters : ['progress', 'kjhtml'],
port : 9876,
colors : true,
logLevel : config.LOG_INFO,
autoWatch : true,
browsers : ['Chrome'],
singleRun : false,
restartOnFileChange: true
});
};
+12561 -14705
View File
File diff suppressed because it is too large Load Diff
+50 -68
View File
@@ -1,83 +1,65 @@
{ {
"name": "@fuse/demo", "name": "fuse-angular",
"version": "12.1.0", "version": "19.1.0",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard", "license": "https://themeforest.net/licenses/standard",
"private": true, "private": true,
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build --prod", "build": "ng build",
"test": "ng test", "watch": "ng build --watch --configuration development",
"lint": "ng lint", "test": "ng test"
"e2e": "ng e2e"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "11.2.11", "@angular/animations": "17.2.4",
"@angular/cdk": "11.2.10", "@angular/cdk": "17.2.2",
"@angular/common": "11.2.11", "@angular/common": "17.2.4",
"@angular/compiler": "11.2.11", "@angular/compiler": "17.2.4",
"@angular/core": "11.2.11", "@angular/core": "17.2.4",
"@angular/forms": "11.2.11", "@angular/forms": "17.2.4",
"@angular/material": "11.2.10", "@angular/material": "17.2.2",
"@angular/material-moment-adapter": "11.2.10", "@angular/material-luxon-adapter": "17.2.2",
"@angular/platform-browser": "11.2.11", "@angular/platform-browser": "17.2.4",
"@angular/platform-browser-dynamic": "11.2.11", "@angular/platform-browser-dynamic": "17.2.4",
"@angular/router": "11.2.11", "@angular/router": "17.2.4",
"@fullcalendar/angular": "4.4.5-beta", "@ngneat/transloco": "6.0.4",
"@fullcalendar/core": "4.4.2", "apexcharts": "3.47.0",
"@fullcalendar/daygrid": "4.4.2", "crypto-js": "4.2.0",
"@fullcalendar/interaction": "4.4.2", "highlight.js": "11.9.0",
"@fullcalendar/list": "4.4.2",
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"apexcharts": "3.26.1",
"crypto-js": "3.3.0",
"highlight.js": "10.7.2",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"moment": "2.29.1", "luxon": "3.4.4",
"ng-apexcharts": "1.5.9", "ng-apexcharts": "1.9.0",
"ngx-markdown": "11.1.3", "ngx-quill": "25.1.1",
"ngx-quill": "13.2.0", "perfect-scrollbar": "1.5.5",
"perfect-scrollbar": "1.5.0", "rxjs": "7.8.1",
"quill": "1.3.7", "tslib": "2.6.2",
"rrule": "2.6.8", "zone.js": "0.14.4"
"rxjs": "6.6.7",
"tslib": "2.2.0",
"web-animations-js": "2.3.2",
"zone.js": "0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "0.1102.10", "@angular-devkit/build-angular": "17.2.3",
"@angular/cli": "11.2.10", "@angular/cli": "17.2.3",
"@angular/compiler-cli": "11.2.11", "@angular/compiler-cli": "17.2.4",
"@angular/language-service": "11.2.11", "@tailwindcss/typography": "0.5.10",
"@tailwindcss/aspect-ratio": "0.2.0", "@types/chroma-js": "2.4.4",
"@tailwindcss/line-clamp": "0.2.0", "@types/crypto-js": "4.2.2",
"@tailwindcss/typography": "0.4.0",
"@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0", "@types/highlight.js": "10.1.0",
"@types/jasmine": "3.6.9", "@types/jasmine": "5.1.4",
"@types/lodash": "4.14.168", "@types/lodash": "4.14.202",
"@types/lodash-es": "4.17.4", "@types/lodash-es": "4.17.12",
"@types/node": "12.20.10", "@types/luxon": "3.4.2",
"autoprefixer": "10.2.5", "autoprefixer": "10.4.18",
"chroma-js": "2.1.1", "chroma-js": "2.4.2",
"codelyzer": "6.0.1", "jasmine-core": "5.1.2",
"jasmine-core": "3.6.0", "karma": "6.4.3",
"jasmine-spec-reporter": "5.0.2", "karma-chrome-launcher": "3.2.0",
"karma": "6.1.2", "karma-coverage": "2.2.1",
"karma-chrome-launcher": "3.1.0", "karma-jasmine": "5.1.0",
"karma-coverage": "2.0.3", "karma-jasmine-html-reporter": "2.1.0",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.5.4",
"lodash": "4.17.21", "lodash": "4.17.21",
"postcss": "8.2.12", "postcss": "8.4.35",
"protractor": "7.0.0", "tailwindcss": "3.4.1",
"tailwindcss": "2.1.2", "typescript": "5.3.3"
"ts-node": "8.3.0",
"tslint": "6.1.3",
"typescript": "4.1.5"
} }
} }
+7 -7
View File
@@ -1,14 +1,14 @@
export class FuseAnimationCurves export class FuseAnimationCurves
{ {
static STANDARD_CURVE = 'cubic-bezier(0.4, 0.0, 0.2, 1)'; static standard = 'cubic-bezier(0.4, 0.0, 0.2, 1)';
static DECELERATION_CURVE = 'cubic-bezier(0.0, 0.0, 0.2, 1)'; static deceleration = 'cubic-bezier(0.0, 0.0, 0.2, 1)';
static ACCELERATION_CURVE = 'cubic-bezier(0.4, 0.0, 1, 1)'; static acceleration = 'cubic-bezier(0.4, 0.0, 1, 1)';
static SHARP_CURVE = 'cubic-bezier(0.4, 0.0, 0.6, 1)'; static sharp = 'cubic-bezier(0.4, 0.0, 0.6, 1)';
} }
export class FuseAnimationDurations export class FuseAnimationDurations
{ {
static COMPLEX = '375ms'; static complex = '375ms';
static ENTERING = '225ms'; static entering = '225ms';
static EXITING = '195ms'; static exiting = '195ms';
} }
+8 -8
View File
@@ -8,12 +8,12 @@ const expandCollapse = trigger('expandCollapse',
[ [
state('void, collapsed', state('void, collapsed',
style({ style({
height: '0' height: '0',
}) }),
), ),
state('*, expanded', state('*, expanded',
style('*') style('*'),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -24,11 +24,11 @@ const expandCollapse = trigger('expandCollapse',
animate('{{timings}}'), animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
export { expandCollapse }; export { expandCollapse };
+90 -90
View File
@@ -8,14 +8,14 @@ const fadeIn = trigger('fadeIn',
[ [
state('void', state('void',
style({ style({
opacity: 0 opacity: 0,
}) }),
), ),
state('*', state('*',
style({ style({
opacity: 1 opacity: 1,
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -25,11 +25,11 @@ const fadeIn = trigger('fadeIn',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -40,15 +40,15 @@ const fadeInTop = trigger('fadeInTop',
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(0, -100%, 0)' transform: 'translate3d(0, -100%, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -58,11 +58,11 @@ const fadeInTop = trigger('fadeInTop',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -73,15 +73,15 @@ const fadeInBottom = trigger('fadeInBottom',
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(0, 100%, 0)' transform: 'translate3d(0, 100%, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -91,11 +91,11 @@ const fadeInBottom = trigger('fadeInBottom',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -106,15 +106,15 @@ const fadeInLeft = trigger('fadeInLeft',
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(-100%, 0, 0)' transform: 'translate3d(-100%, 0, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -124,11 +124,11 @@ const fadeInLeft = trigger('fadeInLeft',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -139,15 +139,15 @@ const fadeInRight = trigger('fadeInRight',
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(100%, 0, 0)' transform: 'translate3d(100%, 0, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -157,11 +157,11 @@ const fadeInRight = trigger('fadeInRight',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -171,14 +171,14 @@ const fadeOut = trigger('fadeOut',
[ [
state('*', state('*',
style({ style({
opacity: 1 opacity: 1,
}) }),
), ),
state('void', state('void',
style({ style({
opacity: 0 opacity: 0,
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -188,11 +188,11 @@ const fadeOut = trigger('fadeOut',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -203,15 +203,15 @@ const fadeOutTop = trigger('fadeOutTop',
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(0, -100%, 0)' transform: 'translate3d(0, -100%, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -221,11 +221,11 @@ const fadeOutTop = trigger('fadeOutTop',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -236,15 +236,15 @@ const fadeOutBottom = trigger('fadeOutBottom',
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(0, 100%, 0)' transform: 'translate3d(0, 100%, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -254,11 +254,11 @@ const fadeOutBottom = trigger('fadeOutBottom',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -269,15 +269,15 @@ const fadeOutLeft = trigger('fadeOutLeft',
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(-100%, 0, 0)' transform: 'translate3d(-100%, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -287,11 +287,11 @@ const fadeOutLeft = trigger('fadeOutLeft',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -302,15 +302,15 @@ const fadeOutRight = trigger('fadeOutRight',
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'translate3d(100%, 0, 0)' transform: 'translate3d(100%, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -320,11 +320,11 @@ const fadeOutRight = trigger('fadeOutRight',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
export { fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight, fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight }; export { fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight, fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight };
+1 -1
View File
@@ -1 +1 @@
export * from './public-api'; export * from '@fuse/animations/public-api';
+7 -7
View File
@@ -1,15 +1,15 @@
import { expandCollapse } from './expand-collapse'; import { expandCollapse } from '@fuse/animations/expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from './fade'; import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from '@fuse/animations/fade';
import { shake } from './shake'; import { shake } from '@fuse/animations/shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from './slide'; import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from '@fuse/animations/slide';
import { zoomIn, zoomOut } from './zoom'; import { zoomIn, zoomOut } from '@fuse/animations/zoom';
export const FuseAnimations = [ export const fuseAnimations = [
expandCollapse, expandCollapse,
fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight, fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight,
fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight,
shake, shake,
slideInTop, slideInBottom, slideInLeft, slideInRight, slideInTop, slideInBottom, slideInLeft, slideInRight,
slideOutTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop, slideOutBottom, slideOutLeft, slideOutRight,
zoomIn, zoomOut zoomIn, zoomOut,
]; ];
+19 -19
View File
@@ -16,58 +16,58 @@ const shake = trigger('shake',
keyframes([ keyframes([
style({ style({
transform: 'translate3d(0, 0, 0)', transform: 'translate3d(0, 0, 0)',
offset : 0 offset : 0,
}), }),
style({ style({
transform: 'translate3d(-10px, 0, 0)', transform: 'translate3d(-10px, 0, 0)',
offset : 0.1 offset : 0.1,
}), }),
style({ style({
transform: 'translate3d(10px, 0, 0)', transform: 'translate3d(10px, 0, 0)',
offset : 0.2 offset : 0.2,
}), }),
style({ style({
transform: 'translate3d(-10px, 0, 0)', transform: 'translate3d(-10px, 0, 0)',
offset : 0.3 offset : 0.3,
}), }),
style({ style({
transform: 'translate3d(10px, 0, 0)', transform: 'translate3d(10px, 0, 0)',
offset : 0.4 offset : 0.4,
}), }),
style({ style({
transform: 'translate3d(-10px, 0, 0)', transform: 'translate3d(-10px, 0, 0)',
offset : 0.5 offset : 0.5,
}), }),
style({ style({
transform: 'translate3d(10px, 0, 0)', transform: 'translate3d(10px, 0, 0)',
offset : 0.6 offset : 0.6,
}), }),
style({ style({
transform: 'translate3d(-10px, 0, 0)', transform: 'translate3d(-10px, 0, 0)',
offset : 0.7 offset : 0.7,
}), }),
style({ style({
transform: 'translate3d(10px, 0, 0)', transform: 'translate3d(10px, 0, 0)',
offset : 0.8 offset : 0.8,
}), }),
style({ style({
transform: 'translate3d(-10px, 0, 0)', transform: 'translate3d(-10px, 0, 0)',
offset : 0.9 offset : 0.9,
}), }),
style({ style({
transform: 'translate3d(0, 0, 0)', transform: 'translate3d(0, 0, 0)',
offset : 1 offset : 1,
}) }),
]) ]),
) ),
], ],
{ {
params: { params: {
timings: '0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955)' timings: '0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955)',
} },
} },
) ),
] ],
); );
export { shake }; export { shake };
+72 -72
View File
@@ -8,14 +8,14 @@ const slideInTop = trigger('slideInTop',
[ [
state('void', state('void',
style({ style({
transform: 'translate3d(0, -100%, 0)' transform: 'translate3d(0, -100%, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -25,11 +25,11 @@ const slideInTop = trigger('slideInTop',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -39,14 +39,14 @@ const slideInBottom = trigger('slideInBottom',
[ [
state('void', state('void',
style({ style({
transform: 'translate3d(0, 100%, 0)' transform: 'translate3d(0, 100%, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -56,11 +56,11 @@ const slideInBottom = trigger('slideInBottom',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -70,14 +70,14 @@ const slideInLeft = trigger('slideInLeft',
[ [
state('void', state('void',
style({ style({
transform: 'translate3d(-100%, 0, 0)' transform: 'translate3d(-100%, 0, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -87,11 +87,11 @@ const slideInLeft = trigger('slideInLeft',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -101,14 +101,14 @@ const slideInRight = trigger('slideInRight',
[ [
state('void', state('void',
style({ style({
transform: 'translate3d(100%, 0, 0)' transform: 'translate3d(100%, 0, 0)',
}) }),
), ),
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -118,11 +118,11 @@ const slideInRight = trigger('slideInRight',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -132,14 +132,14 @@ const slideOutTop = trigger('slideOutTop',
[ [
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
transform: 'translate3d(0, -100%, 0)' transform: 'translate3d(0, -100%, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -149,11 +149,11 @@ const slideOutTop = trigger('slideOutTop',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -163,14 +163,14 @@ const slideOutBottom = trigger('slideOutBottom',
[ [
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
transform: 'translate3d(0, 100%, 0)' transform: 'translate3d(0, 100%, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -180,11 +180,11 @@ const slideOutBottom = trigger('slideOutBottom',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -194,14 +194,14 @@ const slideOutLeft = trigger('slideOutLeft',
[ [
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
transform: 'translate3d(-100%, 0, 0)' transform: 'translate3d(-100%, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -211,11 +211,11 @@ const slideOutLeft = trigger('slideOutLeft',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -225,14 +225,14 @@ const slideOutRight = trigger('slideOutRight',
[ [
state('*', state('*',
style({ style({
transform: 'translate3d(0, 0, 0)' transform: 'translate3d(0, 0, 0)',
}) }),
), ),
state('void', state('void',
style({ style({
transform: 'translate3d(100%, 0, 0)' transform: 'translate3d(100%, 0, 0)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -242,11 +242,11 @@ const slideOutRight = trigger('slideOutRight',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
export { slideInTop, slideInBottom, slideInLeft, slideInRight, slideOutTop, slideOutBottom, slideOutLeft, slideOutRight }; export { slideInTop, slideInBottom, slideInLeft, slideInRight, slideOutTop, slideOutBottom, slideOutLeft, slideOutRight };
+18 -18
View File
@@ -10,15 +10,15 @@ const zoomIn = trigger('zoomIn',
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'scale(0.5)' transform: 'scale(0.5)',
}) }),
), ),
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'scale(1)' transform: 'scale(1)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -28,11 +28,11 @@ const zoomIn = trigger('zoomIn',
transition('void => *', animate('{{timings}}'), transition('void => *', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}` timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
} },
} },
) ),
] ],
); );
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -44,15 +44,15 @@ const zoomOut = trigger('zoomOut',
state('*', state('*',
style({ style({
opacity : 1, opacity : 1,
transform: 'scale(1)' transform: 'scale(1)',
}) }),
), ),
state('void', state('void',
style({ style({
opacity : 0, opacity : 0,
transform: 'scale(0.5)' transform: 'scale(0.5)',
}) }),
), ),
// Prevent the transition if the state is false // Prevent the transition if the state is false
@@ -62,11 +62,11 @@ const zoomOut = trigger('zoomOut',
transition('* => void', animate('{{timings}}'), transition('* => void', animate('{{timings}}'),
{ {
params: { params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}` timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
} },
} },
) ),
] ],
); );
export { zoomIn, zoomOut }; export { zoomIn, zoomOut };
@@ -48,7 +48,7 @@
<mat-icon <mat-icon
*ngIf="type === 'warning'" *ngIf="type === 'warning'"
[svgIcon]="'heroicons_solid:exclamation'"></mat-icon> [svgIcon]="'heroicons_solid:exclamation-triangle'"></mat-icon>
<mat-icon <mat-icon
*ngIf="type === 'error'" *ngIf="type === 'error'"
@@ -76,7 +76,7 @@
class="fuse-alert-dismiss-button" class="fuse-alert-dismiss-button"
mat-icon-button mat-icon-button
(click)="dismiss()"> (click)="dismiss()">
<mat-icon [svgIcon]="'heroicons_solid:x'"></mat-icon> <mat-icon [svgIcon]="'heroicons_solid:x-mark'"></mat-icon>
</button> </button>
</div> </div>
+26 -18
View File
@@ -1,11 +1,13 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { FuseAnimations } from '@fuse/animations'; import { NgIf } from '@angular/common';
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { fuseAnimations } from '@fuse/animations';
import { FuseAlertService } from '@fuse/components/alert/alert.service'; import { FuseAlertService } from '@fuse/components/alert/alert.service';
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service'; import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-alert', selector : 'fuse-alert',
@@ -13,14 +15,18 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
styleUrls : ['./alert.component.scss'], styleUrls : ['./alert.component.scss'],
encapsulation : ViewEncapsulation.None, encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
animations : FuseAnimations, animations : fuseAnimations,
exportAs : 'fuseAlert' exportAs : 'fuseAlert',
standalone : true,
imports : [NgIf, MatIconModule, MatButtonModule],
}) })
export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_dismissible: BooleanInput; static ngAcceptInputType_dismissible: BooleanInput;
static ngAcceptInputType_dismissed: BooleanInput; static ngAcceptInputType_dismissed: BooleanInput;
static ngAcceptInputType_showIcon: BooleanInput; static ngAcceptInputType_showIcon: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() appearance: FuseAlertAppearance = 'soft'; @Input() appearance: FuseAlertAppearance = 'soft';
@Input() dismissed: boolean = false; @Input() dismissed: boolean = false;
@@ -38,7 +44,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseAlertService: FuseAlertService, private _fuseAlertService: FuseAlertService,
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService,
) )
{ {
} }
@@ -52,6 +58,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-alert-appearance-border' : this.appearance === 'border', 'fuse-alert-appearance-border' : this.appearance === 'border',
'fuse-alert-appearance-fill' : this.appearance === 'fill', 'fuse-alert-appearance-fill' : this.appearance === 'fill',
@@ -67,8 +74,9 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
'fuse-alert-type-info' : this.type === 'info', 'fuse-alert-type-info' : this.type === 'info',
'fuse-alert-type-success' : this.type === 'success', 'fuse-alert-type-success' : this.type === 'success',
'fuse-alert-type-warning' : this.type === 'warning', 'fuse-alert-type-warning' : this.type === 'warning',
'fuse-alert-type-error' : this.type === 'error' 'fuse-alert-type-error' : this.type === 'error',
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -115,11 +123,11 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
// Subscribe to the dismiss calls // Subscribe to the dismiss calls
this._fuseAlertService.onDismiss this._fuseAlertService.onDismiss
.pipe( .pipe(
filter((name) => this.name === name), filter(name => this.name === name),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
) )
.subscribe(() => { .subscribe(() =>
{
// Dismiss the alert // Dismiss the alert
this.dismiss(); this.dismiss();
}); });
@@ -127,11 +135,11 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
// Subscribe to the show calls // Subscribe to the show calls
this._fuseAlertService.onShow this._fuseAlertService.onShow
.pipe( .pipe(
filter((name) => this.name === name), filter(name => this.name === name),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
) )
.subscribe(() => { .subscribe(() =>
{
// Show the alert // Show the alert
this.show(); this.show();
}); });
@@ -143,7 +151,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -1,22 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { FuseAlertComponent } from '@fuse/components/alert/alert.component';
@NgModule({
declarations: [
FuseAlertComponent
],
imports : [
CommonModule,
MatButtonModule,
MatIconModule
],
exports : [
FuseAlertComponent
]
})
export class FuseAlertModule
{
}
+1 -3
View File
@@ -1,9 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs'; import { Observable, ReplaySubject } from 'rxjs';
@Injectable({ @Injectable({providedIn: 'root'})
providedIn: 'root'
})
export class FuseAlertService export class FuseAlertService
{ {
private readonly _onDismiss: ReplaySubject<string> = new ReplaySubject<string>(1); private readonly _onDismiss: ReplaySubject<string> = new ReplaySubject<string>(1);
-1
View File
@@ -1,4 +1,3 @@
export * from '@fuse/components/alert/alert.component'; export * from '@fuse/components/alert/alert.component';
export * from '@fuse/components/alert/alert.module';
export * from '@fuse/components/alert/alert.service'; export * from '@fuse/components/alert/alert.service';
export * from '@fuse/components/alert/alert.types'; export * from '@fuse/components/alert/alert.types';
+12 -5
View File
@@ -1,6 +1,7 @@
import { Component, HostBinding, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { FuseAnimations } from '@fuse/animations'; import { NgIf } from '@angular/common';
import { Component, HostBinding, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { FuseCardFace } from '@fuse/components/card/card.types'; import { FuseCardFace } from '@fuse/components/card/card.types';
@Component({ @Component({
@@ -8,13 +9,17 @@ import { FuseCardFace } from '@fuse/components/card/card.types';
templateUrl : './card.component.html', templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'], styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
animations : FuseAnimations, animations : fuseAnimations,
exportAs : 'fuseCard' exportAs : 'fuseCard',
standalone : true,
imports : [NgIf],
}) })
export class FuseCardComponent implements OnChanges export class FuseCardComponent implements OnChanges
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_expanded: BooleanInput; static ngAcceptInputType_expanded: BooleanInput;
static ngAcceptInputType_flippable: BooleanInput; static ngAcceptInputType_flippable: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() expanded: boolean = false; @Input() expanded: boolean = false;
@Input() face: FuseCardFace = 'front'; @Input() face: FuseCardFace = 'front';
@@ -36,12 +41,14 @@ export class FuseCardComponent implements OnChanges
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-card-expanded' : this.expanded, 'fuse-card-expanded' : this.expanded,
'fuse-card-face-back' : this.flippable && this.face === 'back', 'fuse-card-face-back' : this.flippable && this.face === 'back',
'fuse-card-face-front': this.flippable && this.face === 'front', 'fuse-card-face-front': this.flippable && this.face === 'front',
'fuse-card-flippable' : this.flippable 'fuse-card-flippable' : this.flippable,
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
-18
View File
@@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FuseCardComponent } from '@fuse/components/card/card.component';
@NgModule({
declarations: [
FuseCardComponent
],
imports : [
CommonModule
],
exports : [
FuseCardComponent
]
})
export class FuseCardModule
{
}
-1
View File
@@ -1,2 +1 @@
export * from '@fuse/components/card/card.component'; export * from '@fuse/components/card/card.component';
export * from '@fuse/components/card/card.module';
@@ -1,101 +0,0 @@
<div
class="range"
(click)="openPickerPanel()"
#pickerPanelOrigin>
<div class="start">
<div class="date">{{range.startDate}}</div>
<div
class="time"
*ngIf="range.startTime">{{range.startTime}}</div>
</div>
<div class="separator">-</div>
<div class="end">
<div class="date">{{range.endDate}}</div>
<div
class="time"
*ngIf="range.endTime">{{range.endTime}}</div>
</div>
</div>
<ng-template #pickerPanel>
<!-- Start -->
<div class="start">
<div class="month">
<div class="month-header">
<button
class="previous-button"
mat-icon-button
(click)="prev()"
tabindex="1">
<mat-icon [svgIcon]="'heroicons_outline:chevron-left'"></mat-icon>
</button>
<div class="month-label">{{getMonthLabel(1)}}</div>
</div>
<mat-month-view
[(activeDate)]="activeDates.month1"
[dateFilter]="dateFilter()"
[dateClass]="dateClass()"
(click)="$event.stopImmediatePropagation()"
(selectedChange)="onSelectedDateChange($event)"
#matMonthView1>
</mat-month-view>
</div>
<mat-form-field
class="fuse-mat-no-subscript time start-time"
*ngIf="timeRange">
<input
matInput
[autocomplete]="'off'"
[formControl]="startTimeFormControl"
(blur)="updateStartTime($event)"
tabindex="3">
<mat-label>Start time</mat-label>
</mat-form-field>
</div>
<!-- End -->
<div class="end">
<div class="month">
<div class="month-header">
<div class="month-label">{{getMonthLabel(2)}}</div>
<button
class="next-button"
mat-icon-button
(click)="next()"
tabindex="2">
<mat-icon [svgIcon]="'heroicons_outline:chevron-right'"></mat-icon>
</button>
</div>
<mat-month-view
[(activeDate)]="activeDates.month2"
[dateFilter]="dateFilter()"
[dateClass]="dateClass()"
(click)="$event.stopImmediatePropagation()"
(selectedChange)="onSelectedDateChange($event)"
#matMonthView2>
</mat-month-view>
</div>
<mat-form-field
class="fuse-mat-no-subscript time end-time"
*ngIf="timeRange">
<input
matInput
[formControl]="endTimeFormControl"
(blur)="updateEndTime($event)"
tabindex="4">
<mat-label>End time</mat-label>
</mat-form-field>
</div>
</ng-template>
@@ -1,292 +0,0 @@
/* Variables */
$body-cell-padding: 2px;
fuse-date-range {
display: flex;
.range {
display: flex;
align-items: center;
height: 48px;
min-height: 48px;
max-height: 48px;
cursor: pointer;
.start,
.end {
display: flex;
align-items: center;
height: 100%;
padding: 0 16px;
border-radius: 6px;
border-width: 1px;
line-height: 1;
@apply shadow-sm border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500;
.date {
white-space: nowrap;
+ .time {
margin-left: 8px;
}
}
.time {
white-space: nowrap;
}
}
.separator {
margin: 0 2px;
@screen sm {
margin: 0 12px;
}
}
}
}
.fuse-date-range-panel {
border-radius: 4px;
padding: 24px;
@apply shadow-2xl bg-card;
.start,
.end {
display: flex;
flex-direction: column;
.month {
max-width: 196px;
min-width: 196px;
width: 196px;
.month-header {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 32px;
margin-bottom: 16px;
.previous-button,
.next-button {
position: absolute;
width: 24px !important;
height: 24px !important;
min-height: 24px !important;
max-height: 24px !important;
line-height: 24px !important;
.mat-icon {
@apply icon-size-5;
}
}
.previous-button {
left: 0;
}
.next-button {
right: 0;
}
.month-label {
font-weight: 500;
@apply text-secondary;
}
}
mat-month-view {
display: flex;
min-height: 188px;
.mat-calendar-table {
width: 100%;
border-collapse: collapse;
tbody {
tr {
&[aria-hidden=true] {
display: none !important;
}
&:first-child {
td:first-child {
&[aria-hidden=true] {
visibility: hidden;
pointer-events: none;
opacity: 0;
}
}
}
td,
td:hover {
&.fuse-date-range {
&:before {
@apply bg-primary-200;
}
.mat-calendar-body-cell-content {
background-color: transparent;
}
}
&.fuse-date-range-start,
&.fuse-date-range-end {
.mat-calendar-body-cell-content {
@apply bg-primary text-on-primary;
}
}
.mat-calendar-body-today {
border: none;
}
}
td.mat-calendar-body-cell {
width: 28px !important;
height: 28px !important;
padding: $body-cell-padding !important;
&.fuse-date-range {
position: relative;
&:before {
content: '';
position: absolute;
top: $body-cell-padding;
right: 0;
bottom: $body-cell-padding;
left: 0;
}
&.fuse-date-range-start {
&:before {
left: $body-cell-padding;
border-radius: 999px 0 0 999px;
}
&.fuse-date-range-end,
&:last-child {
&:before {
right: $body-cell-padding;
border-radius: 999px;
}
}
}
&.fuse-date-range-end {
&:before {
right: $body-cell-padding;
border-radius: 0 999px 999px 0;
}
&:first-child {
&:before {
left: $body-cell-padding;
border-radius: 999px;
}
}
}
&:first-child {
&:before {
border-radius: 999px 0 0 999px;
}
}
&:last-child {
&:before {
border-radius: 0 999px 999px 0;
}
}
}
.mat-calendar-body-cell-content {
position: relative;
top: 0;
left: 0;
width: 24px;
height: 24px;
font-size: 12px;
}
}
td.mat-calendar-body-label {
+ td.mat-calendar-body-cell {
&.fuse-date-range {
&:before {
border-radius: 999px 0 0 999px;
}
&.fuse-date-range-start {
&.fuse-date-range-end {
border-radius: 999px;
}
}
&.fuse-date-range-end {
&:before {
left: $body-cell-padding;
border-radius: 999px;
}
}
}
}
}
}
}
}
}
}
.time {
width: 100%;
max-width: 196px;
}
}
.start {
align-items: flex-start;
margin-right: 20px;
.month {
.month-label {
margin-left: 8px;
}
}
}
.end {
align-items: flex-end;
margin-left: 20px;
.month {
.month-label {
margin-right: 8px;
}
}
}
}
@@ -1,685 +0,0 @@
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, HostBinding, Input, OnDestroy, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Overlay } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { MatCalendarCellCssClasses, MatMonthView } from '@angular/material/datepicker';
import { Subject } from 'rxjs';
import * as moment from 'moment';
import { Moment } from 'moment';
@Component({
selector : 'fuse-date-range',
templateUrl : './date-range.component.html',
styleUrls : ['./date-range.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseDateRange',
providers : [
{
provide : NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FuseDateRangeComponent),
multi : true
}
]
})
export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnDestroy
{
@Output() readonly rangeChanged: EventEmitter<{ start: string, end: string }> = new EventEmitter<{ start: string; end: string }>();
@ViewChild('matMonthView1') private _matMonthView1: MatMonthView<any>;
@ViewChild('matMonthView2') private _matMonthView2: MatMonthView<any>;
@ViewChild('pickerPanelOrigin', {read: ElementRef}) private _pickerPanelOrigin: ElementRef;
@ViewChild('pickerPanel') private _pickerPanel: TemplateRef<any>;
@HostBinding('class.fuse-date-range') private _defaultClassNames = true;
activeDates: { month1: Moment | null, month2: Moment | null } = {
month1: null,
month2: null
};
setWhichDate: 'start' | 'end' = 'start';
startTimeFormControl: FormControl;
endTimeFormControl: FormControl;
private _dateFormat: string;
private _onChange: (value: any) => void;
private _onTouched: (value: any) => void;
private _programmaticChange!: boolean;
private _range: { start: Moment | null, end: Moment | null } = {
start: null,
end : null
};
private _timeFormat: string;
private _timeRange: boolean;
private readonly _timeRegExp: RegExp = new RegExp('^(0[0-9]|1[0-9]|2[0-4]|[0-9]):([0-5][0-9])(A|(?:AM)|P|(?:PM))?$', 'i');
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _elementRef: ElementRef,
private _overlay: Overlay,
private _renderer2: Renderer2,
private _viewContainerRef: ViewContainerRef
)
{
this._onChange = () => {
};
this._onTouched = () => {
};
this.dateFormat = 'DD/MM/YYYY';
this.timeFormat = '12';
// Initialize the component
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Setter & getter for dateFormat input
*
* @param value
*/
@Input()
set dateFormat(value: string)
{
// Return if the values are the same
if ( this._dateFormat === value )
{
return;
}
// Store the value
this._dateFormat = value;
}
get dateFormat(): string
{
return this._dateFormat;
}
/**
* Setter & getter for timeFormat input
*
* @param value
*/
@Input()
set timeFormat(value: string)
{
// Return if the values are the same
if ( this._timeFormat === value )
{
return;
}
// Set format based on the time format input
this._timeFormat = value === '12' ? 'hh:mmA' : 'HH:mm';
}
get timeFormat(): string
{
return this._timeFormat;
}
/**
* Setter & getter for timeRange input
*
* @param value
*/
@Input()
set timeRange(value: boolean)
{
// Return if the values are the same
if ( this._timeRange === value )
{
return;
}
// Store the value
this._timeRange = value;
// If the time range turned off...
if ( !value )
{
this.range = {
start: this._range.start.clone().startOf('day'),
end : this._range.end.clone().endOf('day')
};
}
}
get timeRange(): boolean
{
return this._timeRange;
}
/**
* Setter & getter for range input
*
* @param value
*/
@Input()
set range(value)
{
if ( !value )
{
return;
}
// Check if the value is an object and has 'start' and 'end' values
if ( !value.start || !value.end )
{
console.error('Range input must have "start" and "end" properties!');
return;
}
// Check if we are setting an individual date or both of them
const whichDate = value.whichDate || null;
// Get the start and end dates as moment
const start = moment(value.start);
const end = moment(value.end);
// If we are only setting the start date...
if ( whichDate === 'start' )
{
// Set the start date
this._range.start = start.clone();
// If the selected start date is after the end date...
if ( this._range.start.isAfter(this._range.end) )
{
// Set the end date to the start date but keep the end date's time
const endDate = start.clone().hours(this._range.end.hours()).minutes(this._range.end.minutes()).seconds(this._range.end.seconds());
// Test this new end date to see if it's ahead of the start date
if ( this._range.start.isBefore(endDate) )
{
// If it's, set the new end date
this._range.end = endDate;
}
else
{
// Otherwise, set the end date same as the start date
this._range.end = start.clone();
}
}
}
// If we are only setting the end date...
if ( whichDate === 'end' )
{
// Set the end date
this._range.end = end.clone();
// If the selected end date is before the start date...
if ( this._range.start.isAfter(this._range.end) )
{
// Set the start date to the end date but keep the start date's time
const startDate = end.clone().hours(this._range.start.hours()).minutes(this._range.start.minutes()).seconds(this._range.start.seconds());
// Test this new end date to see if it's ahead of the start date
if ( this._range.end.isAfter(startDate) )
{
// If it's, set the new start date
this._range.start = startDate;
}
else
{
// Otherwise, set the start date same as the end date
this._range.start = end.clone();
}
}
}
// If we are setting both dates...
if ( !whichDate )
{
// Set the start date
this._range.start = start.clone();
// If the start date is before the end date, set the end date as normal.
// If the start date is after the end date, set the end date same as the start date.
this._range.end = start.isBefore(end) ? end.clone() : start.clone();
}
// Prepare another range object that holds the ISO formatted range dates
const range = {
start: this._range.start.clone().toISOString(),
end : this._range.end.clone().toISOString()
};
// Emit the range changed event with the range
this.rangeChanged.emit(range);
// Update the model with the range if the change was not a programmatic change
// Because programmatic changes trigger writeValue which triggers onChange and onTouched
// internally causing them to trigger twice which breaks the form's pristine and touched
// statuses.
if ( !this._programmaticChange )
{
this._onTouched(range);
this._onChange(range);
}
// Set the active dates
this.activeDates = {
month1: this._range.start.clone(),
month2: this._range.start.clone().add(1, 'month')
};
// Set the time form controls
this.startTimeFormControl.setValue(this._range.start.clone().format(this._timeFormat).toString());
this.endTimeFormControl.setValue(this._range.end.clone().format(this._timeFormat).toString());
// Run ngAfterContentInit on month views to trigger
// re-render on month views if they are available
if ( this._matMonthView1 && this._matMonthView2 )
{
this._matMonthView1.ngAfterContentInit();
this._matMonthView2.ngAfterContentInit();
}
// Reset the programmatic change status
this._programmaticChange = false;
}
get range(): any
{
// Clone the range start and end
const start = this._range.start.clone();
const end = this._range.end.clone();
// Build and return the range object
return {
startDate: start.clone().format(this.dateFormat),
startTime: this.timeRange ? start.clone().format(this.timeFormat) : null,
endDate : end.clone().format(this.dateFormat),
endTime : this.timeRange ? end.clone().format(this.timeFormat) : null
};
}
// -----------------------------------------------------------------------------------------------------
// @ Control Value Accessor
// -----------------------------------------------------------------------------------------------------
/**
* Update the form model on change
*
* @param fn
*/
registerOnChange(fn: any): void
{
this._onChange = fn;
}
/**
* Update the form model on blur
*
* @param fn
*/
registerOnTouched(fn: any): void
{
this._onTouched = fn;
}
/**
* Write to view from model when the form model changes programmatically
*
* @param range
*/
writeValue(range: { start: string, end: string }): void
{
// Set this change as a programmatic one
this._programmaticChange = true;
// Set the range
this.range = range;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
// @ TODO: Workaround until "angular/issues/20007" resolved
this.writeValue = () => {
};
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the picker panel
*/
openPickerPanel(): void
{
// Create the overlay
const overlayRef = this._overlay.create({
panelClass : 'fuse-date-range-panel',
backdropClass : '',
hasBackdrop : true,
scrollStrategy : this._overlay.scrollStrategies.reposition(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._pickerPanelOrigin)
.withPositions([
{
originX : 'start',
originY : 'bottom',
overlayX: 'start',
overlayY: 'top',
offsetY : 8
},
{
originX : 'start',
originY : 'top',
overlayX: 'start',
overlayY: 'bottom',
offsetY : -8
}
])
});
// Create a portal from the template
const templatePortal = new TemplatePortal(this._pickerPanel, this._viewContainerRef);
// On backdrop click
overlayRef.backdropClick().subscribe(() => {
// If template portal exists and attached...
if ( templatePortal && templatePortal.isAttached )
{
// Detach it
templatePortal.detach();
}
// If overlay exists and attached...
if ( overlayRef && overlayRef.hasAttached() )
{
// Detach it
overlayRef.detach();
overlayRef.dispose();
}
});
// Attach the portal to the overlay
overlayRef.attach(templatePortal);
}
/**
* Get month label
*
* @param month
*/
getMonthLabel(month: number): string
{
if ( month === 1 )
{
return this.activeDates.month1.clone().format('MMMM Y');
}
return this.activeDates.month2.clone().format('MMMM Y');
}
/**
* Date class function to add/remove class names to calendar days
*/
dateClass(): any
{
return (date: Moment): MatCalendarCellCssClasses => {
// If the date is both start and end date...
if ( date.isSame(this._range.start, 'day') && date.isSame(this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-start', 'fuse-date-range-end'];
}
// If the date is the start date...
if ( date.isSame(this._range.start, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-start'];
}
// If the date is the end date...
if ( date.isSame(this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-end'];
}
// If the date is in between start and end dates...
if ( date.isBetween(this._range.start, this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-mid'];
}
return undefined;
};
}
/**
* Date filter to enable/disable calendar days
*/
dateFilter(): any
{
return (date: Moment): boolean => {
// If we are selecting the end date, disable all the dates that comes before the start date
return !(this.setWhichDate === 'end' && date.isBefore(this._range.start, 'day'));
};
}
/**
* On selected date change
*
* @param date
*/
onSelectedDateChange(date: Moment): void
{
// Create a new range object
const newRange = {
start : this._range.start.clone().toISOString(),
end : this._range.end.clone().toISOString(),
whichDate: null
};
// Replace either the start or the end date with the new one
// depending on which date we are setting
if ( this.setWhichDate === 'start' )
{
newRange.start = moment(newRange.start).year(date.year()).month(date.month()).date(date.date()).toISOString();
}
else
{
newRange.end = moment(newRange.end).year(date.year()).month(date.month()).date(date.date()).toISOString();
}
// Append the which date to the new range object
newRange.whichDate = this.setWhichDate;
// Switch which date to set on the next run
this.setWhichDate = this.setWhichDate === 'start' ? 'end' : 'start';
// Set the range
this.range = newRange;
}
/**
* Go to previous month on both views
*/
prev(): void
{
this.activeDates.month1 = moment(this.activeDates.month1).subtract(1, 'month');
this.activeDates.month2 = moment(this.activeDates.month2).subtract(1, 'month');
}
/**
* Go to next month on both views
*/
next(): void
{
this.activeDates.month1 = moment(this.activeDates.month1).add(1, 'month');
this.activeDates.month2 = moment(this.activeDates.month2).add(1, 'month');
}
/**
* Update the start time
*
* @param event
*/
updateStartTime(event): void
{
// Parse the time
const parsedTime = this._parseTime(event.target.value);
// Go back to the previous value if the form control is not valid
if ( this.startTimeFormControl.invalid )
{
// Override the time
const time = this._range.start.clone().format(this._timeFormat);
// Set the time
this.startTimeFormControl.setValue(time);
// Do not update the range
return;
}
// Append the new time to the start date
const startDate = this._range.start.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
// If the new start date is after the current end date,
// use the end date's time and set the start date again
if ( startDate.isAfter(this._range.end) )
{
const endDateHours = this._range.end.hours();
const endDateMinutes = this._range.end.minutes();
// Set the start date
startDate.hours(endDateHours).minutes(endDateMinutes);
}
// If everything is okay, set the new date
this.range = {
start : startDate.toISOString(),
end : this._range.end.clone().toISOString(),
whichDate: 'start'
};
}
/**
* Update the end time
*
* @param event
*/
updateEndTime(event): void
{
// Parse the time
const parsedTime = this._parseTime(event.target.value);
// Go back to the previous value if the form control is not valid
if ( this.endTimeFormControl.invalid )
{
// Override the time
const time = this._range.end.clone().format(this._timeFormat);
// Set the time
this.endTimeFormControl.setValue(time);
// Do not update the range
return;
}
// Append the new time to the end date
const endDate = this._range.end.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
// If the new end date is before the current start date,
// use the start date's time and set the end date again
if ( endDate.isBefore(this._range.start) )
{
const startDateHours = this._range.start.hours();
const startDateMinutes = this._range.start.minutes();
// Set the end date
endDate.hours(startDateHours).minutes(startDateMinutes);
}
// If everything is okay, set the new date
this.range = {
start : this._range.start.clone().toISOString(),
end : endDate.toISOString(),
whichDate: 'end'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
// Start and end time form controls
this.startTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
this.endTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
// Set the default range
this._programmaticChange = true;
this.range = {
start: moment().startOf('day').toISOString(),
end : moment().add(1, 'day').endOf('day').toISOString()
};
// Set the default time range
this._programmaticChange = true;
this.timeRange = true;
}
/**
* Parse the time from the inputs
*
* @param value
* @private
*/
private _parseTime(value: string): Moment
{
// Parse the time using the time regexp
const timeArr = value.split(this._timeRegExp).filter((part) => part !== '');
// Get the meridiem
const meridiem = timeArr[2] || null;
// If meridiem exists...
if ( meridiem )
{
// Create a moment using 12-hours format and return it
return moment(value, 'hh:mmA').seconds(0);
}
// If meridiem doesn't exist, create a moment using 24-hours format and return in
return moment(value, 'HH:mm').seconds(0);
}
}
@@ -1,32 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
import { FuseDateRangeComponent } from '@fuse/components/date-range/date-range.component';
@NgModule({
declarations: [
FuseDateRangeComponent
],
imports : [
CommonModule,
ReactiveFormsModule,
MatButtonModule,
MatDatepickerModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatMomentDateModule
],
exports : [
FuseDateRangeComponent
]
})
export class FuseDateRangeModule
{
}
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/date-range/public-api';
@@ -1,2 +0,0 @@
export * from '@fuse/components/date-range/date-range.component';
export * from '@fuse/components/date-range/date-range.module';
@@ -1,14 +1,16 @@
/* Variables */ /* Variables */
$fuse-drawer-width: 320; :root {
--fuse-drawer-width: 320px;
}
fuse-drawer { fuse-drawer {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1 1 auto;
width: #{$fuse-drawer-width}px; width: var(--fuse-drawer-width);
min-width: #{$fuse-drawer-width}px; min-width: var(--fuse-drawer-width);
max-width: #{$fuse-drawer-width}px; max-width: var(--fuse-drawer-width);
z-index: 300; z-index: 300;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .35); box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .35);
@apply bg-card; @apply bg-card;
@@ -43,7 +45,7 @@ fuse-drawer {
/* Side mode */ /* Side mode */
&.fuse-drawer-mode-side { &.fuse-drawer-mode-side {
margin-left: -#{$fuse-drawer-width}px; margin-left: calc(var(--fuse-drawer-width) * -1);
&.fuse-drawer-opened { &.fuse-drawer-opened {
margin-left: 0; margin-left: 0;
@@ -71,7 +73,7 @@ fuse-drawer {
/* Side mode */ /* Side mode */
&.fuse-drawer-mode-side { &.fuse-drawer-mode-side {
margin-right: -#{$fuse-drawer-width}px; margin-right: calc(var(--fuse-drawer-width) * -1);
&.fuse-drawer-opened { &.fuse-drawer-opened {
margin-right: 0; margin-right: 0;
@@ -116,7 +118,7 @@ fuse-drawer {
left: 0; left: 0;
right: 0; right: 0;
z-index: 299; z-index: 299;
opacity: 0; opacity: 1;
background-color: rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0.6);
/* Fixed mode */ /* Fixed mode */
+72 -55
View File
@@ -1,22 +1,25 @@
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { FuseDrawerMode, FuseDrawerPosition } from '@fuse/components/drawer/drawer.types';
import { FuseDrawerService } from '@fuse/components/drawer/drawer.service';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { FuseDrawerService } from '@fuse/components/drawer/drawer.service';
import { FuseDrawerMode, FuseDrawerPosition } from '@fuse/components/drawer/drawer.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({ @Component({
selector : 'fuse-drawer', selector : 'fuse-drawer',
templateUrl : './drawer.component.html', templateUrl : './drawer.component.html',
styleUrls : ['./drawer.component.scss'], styleUrls : ['./drawer.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
exportAs : 'fuseDrawer' exportAs : 'fuseDrawer',
standalone : true,
}) })
export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_fixed: BooleanInput; static ngAcceptInputType_fixed: BooleanInput;
static ngAcceptInputType_opened: BooleanInput; static ngAcceptInputType_opened: BooleanInput;
static ngAcceptInputType_transparentOverlay: BooleanInput; static ngAcceptInputType_transparentOverlay: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() fixed: boolean = false; @Input() fixed: boolean = false;
@Input() mode: FuseDrawerMode = 'side'; @Input() mode: FuseDrawerMode = 'side';
@@ -30,6 +33,7 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
@Output() readonly positionChanged: EventEmitter<FuseDrawerPosition> = new EventEmitter<FuseDrawerPosition>(); @Output() readonly positionChanged: EventEmitter<FuseDrawerPosition> = new EventEmitter<FuseDrawerPosition>();
private _animationsEnabled: boolean = false; private _animationsEnabled: boolean = false;
private readonly _handleOverlayClick: any;
private _hovered: boolean = false; private _hovered: boolean = false;
private _overlay: HTMLElement; private _overlay: HTMLElement;
private _player: AnimationPlayer; private _player: AnimationPlayer;
@@ -42,9 +46,13 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _fuseDrawerService: FuseDrawerService, private _fuseDrawerService: FuseDrawerService,
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService,
) )
{ {
this._handleOverlayClick = (): void =>
{
this.close();
};
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -56,14 +64,16 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-drawer-animations-enabled' : this._animationsEnabled, 'fuse-drawer-animations-enabled' : this._animationsEnabled,
'fuse-drawer-fixed' : this.fixed, 'fuse-drawer-fixed' : this.fixed,
'fuse-drawer-hover' : this._hovered, 'fuse-drawer-hover' : this._hovered,
[`fuse-drawer-mode-${this.mode}`] : true, [`fuse-drawer-mode-${this.mode}`] : true,
'fuse-drawer-opened' : this.opened, 'fuse-drawer-opened' : this.opened,
[`fuse-drawer-position-${this.position}`]: true [`fuse-drawer-position-${this.position}`]: true,
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
/** /**
@@ -72,10 +82,44 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
@HostBinding('style') get styleList(): any @HostBinding('style') get styleList(): any
{ {
return { return {
'visibility': this.opened ? 'visible' : 'hidden' 'visibility': this.opened ? 'visible' : 'hidden',
}; };
} }
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks // @ Lifecycle hooks
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -131,7 +175,8 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Enable the animations after a delay // Enable the animations after a delay
// The delay must be bigger than the current transition-duration // The delay must be bigger than the current transition-duration
// to make sure nothing will be animated while the mode is changing // to make sure nothing will be animated while the mode is changing
setTimeout(() => { setTimeout(() =>
{
this._enableAnimations(); this._enableAnimations();
}, 500); }, 500);
} }
@@ -175,6 +220,12 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Finish the animation
if ( this._player )
{
this._player.finish();
}
// Deregister the drawer from the registry // Deregister the drawer from the registry
this._fuseDrawerService.deregisterComponent(this.name); this._fuseDrawerService.deregisterComponent(this.name);
} }
@@ -276,12 +327,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Create the backdrop element // Create the backdrop element
this._overlay = this._renderer2.createElement('div'); this._overlay = this._renderer2.createElement('div');
// Return if overlay couldn't be create for some reason
if ( !this._overlay )
{
return;
}
// Add a class to the backdrop element // Add a class to the backdrop element
this._overlay.classList.add('fuse-drawer-overlay'); this._overlay.classList.add('fuse-drawer-overlay');
@@ -300,18 +345,17 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Append the backdrop to the parent of the drawer // Append the backdrop to the parent of the drawer
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay); this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay);
// Create the enter animation and attach it to the player // Create enter animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})) style({opacity: 0}),
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})),
]).create(this._overlay); ]).create(this._overlay);
// Play the animation // Play the animation
this._player.play(); this._player.play();
// Add an event listener to the overlay // Add an event listener to the overlay
this._overlay.addEventListener('click', () => { this._overlay.addEventListener('click', this._handleOverlayClick);
this.close();
});
} }
/** /**
@@ -328,55 +372,28 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Create the leave animation and attach it to the player // Create the leave animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._overlay); ]).create(this._overlay);
// Play the animation // Play the animation
this._player.play(); this._player.play();
// Once the animation is done... // Once the animation is done...
this._player.onDone(() => { this._player.onDone(() =>
{
// If the backdrop still exists... // If the overlay still exists...
if ( this._overlay ) if ( this._overlay )
{ {
// Remove the backdrop // Remove the event listener
this._overlay.removeEventListener('click', this._handleOverlayClick);
// Remove the overlay
this._overlay.parentNode.removeChild(this._overlay); this._overlay.parentNode.removeChild(this._overlay);
this._overlay = null; this._overlay = null;
} }
}); });
} }
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
/** /**
* Open/close the drawer * Open/close the drawer
* *
@@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FuseDrawerComponent } from '@fuse/components/drawer/drawer.component';
@NgModule({
declarations: [
FuseDrawerComponent
],
imports : [
CommonModule
],
exports : [
FuseDrawerComponent
]
})
export class FuseDrawerModule
{
}
@@ -1,9 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { FuseDrawerComponent } from '@fuse/components/drawer/drawer.component'; import { FuseDrawerComponent } from '@fuse/components/drawer/drawer.component';
@Injectable({ @Injectable({providedIn: 'root'})
providedIn: 'root'
})
export class FuseDrawerService export class FuseDrawerService
{ {
private _componentRegistry: Map<string, FuseDrawerComponent> = new Map<string, FuseDrawerComponent>(); private _componentRegistry: Map<string, FuseDrawerComponent> = new Map<string, FuseDrawerComponent>();
@@ -1,4 +1,3 @@
export * from '@fuse/components/drawer/drawer.component'; export * from '@fuse/components/drawer/drawer.component';
export * from '@fuse/components/drawer/drawer.module';
export * from '@fuse/components/drawer/drawer.service'; export * from '@fuse/components/drawer/drawer.service';
export * from '@fuse/components/drawer/drawer.types'; export * from '@fuse/components/drawer/drawer.types';
@@ -0,0 +1,12 @@
<!-- Button -->
<button
mat-icon-button
[matTooltip]="tooltip || 'Toggle Fullscreen'"
(click)="toggleFullscreen()">
<ng-container [ngTemplateOutlet]="iconTpl || defaultIconTpl"></ng-container>
</button>
<!-- Default icon -->
<ng-template #defaultIconTpl>
<mat-icon [svgIcon]="'heroicons_outline:arrows-pointing-out'"></mat-icon>
</ng-template>
@@ -0,0 +1,58 @@
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, Input, TemplateRef, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
@Component({
selector: 'fuse-fullscreen',
templateUrl: './fullscreen.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'fuseFullscreen',
standalone: true,
imports: [MatButtonModule, MatTooltipModule, NgTemplateOutlet, MatIconModule],
})
export class FuseFullscreenComponent
{
@Input() iconTpl: TemplateRef<any>;
@Input() tooltip: string;
/**
* Constructor
*/
constructor(@Inject(DOCUMENT) private _document: Document) { }
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle the fullscreen mode
*/
toggleFullscreen(): void
{
if (!this._document.fullscreenEnabled)
{
console.log('Fullscreen is not available in this browser.');
return;
}
// Check if the fullscreen is already open
const fullScreen = this._document.fullscreenElement;
// Toggle the fullscreen
if (fullScreen)
{
this._document.exitFullscreen();
}
else
{
this._document.documentElement.requestFullscreen()
.catch(() =>
{
console.error('Entering fullscreen mode failed.');
});
}
}
}
+1
View File
@@ -0,0 +1 @@
export * from '@fuse/components/fullscreen/public-api';
@@ -0,0 +1 @@
export * from '@fuse/components/fullscreen/fullscreen.component';
@@ -1,3 +1,4 @@
import { NgClass } from '@angular/common';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EmbeddedViewRef, Input, OnChanges, Renderer2, SecurityContext, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EmbeddedViewRef, Input, OnChanges, Renderer2, SecurityContext, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
import { FuseHighlightService } from '@fuse/components/highlight/highlight.service'; import { FuseHighlightService } from '@fuse/components/highlight/highlight.service';
@@ -8,7 +9,9 @@ import { FuseHighlightService } from '@fuse/components/highlight/highlight.servi
styleUrls : ['./highlight.component.scss'], styleUrls : ['./highlight.component.scss'],
encapsulation : ViewEncapsulation.None, encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseHighlight' exportAs : 'fuseHighlight',
standalone : true,
imports : [NgClass],
}) })
export class FuseHighlightComponent implements OnChanges, AfterViewInit export class FuseHighlightComponent implements OnChanges, AfterViewInit
{ {
@@ -28,7 +31,7 @@ export class FuseHighlightComponent implements OnChanges, AfterViewInit
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _fuseHighlightService: FuseHighlightService, private _fuseHighlightService: FuseHighlightService,
private _viewContainerRef: ViewContainerRef private _viewContainerRef: ViewContainerRef,
) )
{ {
} }
@@ -123,7 +126,7 @@ export class FuseHighlightComponent implements OnChanges, AfterViewInit
// Render and insert the template // Render and insert the template
this._viewRef = this._viewContainerRef.createEmbeddedView(this.templateRef, { this._viewRef = this._viewContainerRef.createEmbeddedView(this.templateRef, {
highlightedCode: this.highlightedCode, highlightedCode: this.highlightedCode,
lang : this.lang lang : this.lang,
}); });
// Detect the changes // Detect the changes
@@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FuseHighlightComponent } from '@fuse/components/highlight/highlight.component';
@NgModule({
declarations: [
FuseHighlightComponent
],
imports : [
CommonModule
],
exports : [
FuseHighlightComponent
]
})
export class FuseHighlightModule
{
}
@@ -1,9 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import * as hljs from 'highlight.js'; import hljs from 'highlight.js';
@Injectable({ @Injectable({providedIn: 'root'})
providedIn: 'root'
})
export class FuseHighlightService export class FuseHighlightService
{ {
/** /**
@@ -60,23 +58,23 @@ export class FuseHighlightService
} }
// Iterate through the lines // Iterate through the lines
lines.filter((line) => line.length) lines.filter(line => line.length)
.forEach((line, index) => { .forEach((line, index) =>
{
// Always get the indentation of the first line so we can
// have something to compare with
if ( index === 0 )
{
indentation = line.search(/\S|$/);
return;
}
// Always get the indentation of the first line so we can // Look at all the remaining lines to figure out the smallest indentation.
// have something to compare with indentation = Math.min(line.search(/\S|$/), indentation);
if ( index === 0 ) });
{
indentation = line.search(/\S|$/);
return;
}
// Look at all the remaining lines to figure out the smallest indentation.
indentation = Math.min(line.search(/\S|$/), indentation);
});
// Iterate through the lines one more time, remove the extra // Iterate through the lines one more time, remove the extra
// indentation, join them together and return it // indentation, join them together and return it
return lines.map((line) => line.substring(indentation)).join('\n'); return lines.map(line => line.substring(indentation)).join('\n');
} }
} }
@@ -1,3 +1,2 @@
export * from '@fuse/components/highlight/highlight.component'; export * from '@fuse/components/highlight/highlight.component';
export * from '@fuse/components/highlight/highlight.module';
export * from '@fuse/components/highlight/highlight.service'; export * from '@fuse/components/highlight/highlight.service';
@@ -0,0 +1 @@
export * from '@fuse/components/loading-bar/public-api';
@@ -0,0 +1,5 @@
<ng-container *ngIf="show">
<mat-progress-bar
[mode]="mode"
[value]="progress"></mat-progress-bar>
</ng-container>
@@ -0,0 +1,7 @@
fuse-loading-bar {
position: fixed;
top: 0;
z-index: 999;
width: 100%;
height: 6px;
}
@@ -0,0 +1,89 @@
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { NgIf } from '@angular/common';
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { FuseLoadingService } from '@fuse/services/loading';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-loading-bar',
templateUrl : './loading-bar.component.html',
styleUrls : ['./loading-bar.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseLoadingBar',
standalone : true,
imports : [NgIf, MatProgressBarModule],
})
export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy
{
@Input() autoMode: boolean = true;
mode: 'determinate' | 'indeterminate';
progress: number = 0;
show: boolean = false;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(private _fuseLoadingService: FuseLoadingService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Auto mode
if ( 'autoMode' in changes )
{
// Set the auto mode in the service
this._fuseLoadingService.setAutoMode(coerceBooleanProperty(changes.autoMode.currentValue));
}
}
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to the service
this._fuseLoadingService.mode$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.mode = value;
});
this._fuseLoadingService.progress$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.progress = value;
});
this._fuseLoadingService.show$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.show = value;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -0,0 +1 @@
export * from '@fuse/components/loading-bar/loading-bar.component';
+1
View File
@@ -0,0 +1 @@
export * from '@fuse/components/masonry/public-api';
@@ -0,0 +1,3 @@
<div class="flex">
<ng-container *ngTemplateOutlet="columnsTemplate; context: { $implicit: distributedColumns }"></ng-container>
</div>
@@ -0,0 +1,89 @@
import { NgTemplateOutlet } from '@angular/common';
import { AfterViewInit, Component, Input, OnChanges, SimpleChanges, TemplateRef, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
@Component({
selector : 'fuse-masonry',
templateUrl : './masonry.component.html',
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations,
exportAs : 'fuseMasonry',
standalone : true,
imports : [NgTemplateOutlet],
})
export class FuseMasonryComponent implements OnChanges, AfterViewInit
{
@Input() columnsTemplate: TemplateRef<any>;
@Input() columns: number;
@Input() items: any[] = [];
distributedColumns: any[] = [];
/**
* Constructor
*/
constructor(private _fuseMediaWatcherService: FuseMediaWatcherService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Columns
if ( 'columns' in changes )
{
// Distribute the items
this._distributeItems();
}
// Items
if ( 'items' in changes )
{
// Distribute the items
this._distributeItems();
}
}
/**
* After view init
*/
ngAfterViewInit(): void
{
// Distribute the items for the first time
this._distributeItems();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Distribute items into columns
*/
private _distributeItems(): void
{
// Return an empty array if there are no items
if ( this.items.length === 0 )
{
this.distributedColumns = [];
return;
}
// Prepare the distributed columns array
this.distributedColumns = Array.from(Array(this.columns), item => ({items: []}));
// Distribute the items to columns
for ( let i = 0; i < this.items.length; i++ )
{
this.distributedColumns[i % this.columns].items.push(this.items[i]);
}
}
}
@@ -0,0 +1 @@
export * from '@fuse/components/masonry/masonry.component';
@@ -5,69 +5,91 @@
[ngClass]="item.classes?.wrapper"> [ngClass]="item.classes?.wrapper">
<!-- Item with an internal link --> <!-- Item with an internal link -->
<div <ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <div
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [fragment]="item.fragment ?? null"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"> [preserveFragment]="item.preserveFragment ?? false"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [queryParams]="item.queryParams ?? null"
</div> [queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an external link --> <!-- Item with an external link -->
<a <ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <a
*ngIf="item.link && item.externalLink && !item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[href]="item.link"> [href]="item.link"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [target]="item.target || '_self'"
</a> [matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function --> <!-- Item with a function -->
<div <ng-container *ngIf="!item.link && item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <div
*ngIf="!item.link && item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
(click)="item.function(item)"> [matTooltip]="item.tooltip || ''"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> (click)="item.function(item)">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function --> <!-- Item with an internal link and function -->
<div <ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <div
*ngIf="item.link && !item.externalLink && item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [fragment]="item.fragment ?? null"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" [preserveFragment]="item.preserveFragment ?? false"
(click)="item.function(item)"> [queryParams]="item.queryParams ?? null"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [queryParamsHandling]="item.queryParamsHandling ?? null"
</div> [routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an external link and function --> <!-- Item with an external link and function -->
<a <ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <a
*ngIf="item.link && item.externalLink && item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[href]="item.link" [href]="item.link"
(click)="item.function(item)" [target]="item.target || '_self'"
mat-menu-item> [matTooltip]="item.tooltip || ''"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> (click)="item.function(item)"
</a> mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function --> <!-- Item with a no link and no function -->
<div <ng-container *ngIf="!item.link && !item.function && !item.disabled">
class="fuse-horizontal-navigation-item" <div
*ngIf="!item.link && !item.function && !item.disabled" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"> [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [matTooltip]="item.tooltip || ''">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled --> <!-- Item is disabled -->
<div <ng-container *ngIf="item.disabled">
class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled" <div class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled">
*ngIf="item.disabled"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div> </ng-container>
</div> </div>
@@ -75,11 +97,12 @@
<ng-template #itemTemplate> <ng-template #itemTemplate>
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-horizontal-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-horizontal-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper"> <div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -88,24 +111,24 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-horizontal-navigation-item-subtitle text-hint" <div class="fuse-horizontal-navigation-item-subtitle text-hint">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-horizontal-navigation-item-badge" <div class="fuse-horizontal-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-horizontal-navigation-item-badge-content"
class="fuse-horizontal-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
</ng-template> </ng-template>
@@ -1,21 +1,28 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs'; import { MatIconModule } from '@angular/material/icon';
import { takeUntil } from 'rxjs/operators'; import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IsActiveMatchOptions, RouterLink, RouterLinkActive } from '@angular/router';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-horizontal-navigation-basic-item', selector : 'fuse-horizontal-navigation-basic-item',
templateUrl : './basic.component.html', templateUrl : './basic.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass, NgIf, RouterLink, RouterLinkActive, MatTooltipModule, NgTemplateOutlet, MatMenuModule, MatIconModule],
}) })
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
{ {
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@Input() name: string; @Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -24,9 +31,15 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService,
) )
{ {
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -38,14 +51,25 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/ */
ngOnInit(): void ngOnInit(): void
{ {
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component // Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name); this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe( this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -57,7 +81,7 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -1,59 +1,63 @@
<div <ng-container *ngIf="!child">
*ngIf="!child" <div
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen, [ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
'fuse-horizontal-navigation-menu-active-forced': item.active}" 'fuse-horizontal-navigation-menu-active-forced': item.active}"
[matMenuTriggerFor]="matMenu" [matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()" (onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()" (onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger"> #trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container> <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div> </div>
</ng-container>
<mat-menu <mat-menu
class="fuse-horizontal-navigation-menu-panel" class="fuse-horizontal-navigation-menu-panel"
[overlapTrigger]="false" [overlapTrigger]="false"
#matMenu="matMenu"> #matMenu="matMenu">
<ng-container *ngFor="let item of item.children"> <ng-container *ngFor="let item of item.children; trackBy: trackByFn">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<div <ng-container *ngIf="item.type === 'basic'">
class="fuse-horizontal-navigation-menu-item" <div
*ngIf="item.type === 'basic'" class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled" [disabled]="item.disabled"
mat-menu-item> mat-menu-item>
<fuse-horizontal-navigation-basic-item <fuse-horizontal-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item> [name]="name"></fuse-horizontal-navigation-basic-item>
</div> </div>
</ng-container>
<!-- Branch: aside, collapsable, group --> <!-- Branch: aside, collapsable, group -->
<div <ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
class="fuse-horizontal-navigation-menu-item" <div
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'" class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled" [disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu" [matMenuTriggerFor]="branch.matMenu"
mat-menu-item> mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container> <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item <fuse-horizontal-navigation-branch-item
[child]="true" [child]="true"
[item]="item" [item]="item"
[name]="name" [name]="name"
#branch></fuse-horizontal-navigation-branch-item> #branch></fuse-horizontal-navigation-branch-item>
</div> </div>
</ng-container>
<!-- Divider --> <!-- Divider -->
<div <ng-container *ngIf="item.type === 'divider'">
class="fuse-horizontal-navigation-menu-item" <div
*ngIf="item.type === 'divider'" class="fuse-horizontal-navigation-menu-item"
mat-menu-item> mat-menu-item>
<fuse-horizontal-navigation-divider-item <fuse-horizontal-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item> [name]="name"></fuse-horizontal-navigation-divider-item>
</div> </div>
</ng-container>
</ng-container> </ng-container>
@@ -74,14 +78,16 @@
<div <div
class="fuse-horizontal-navigation-item" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled, [ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled,
'fuse-horizontal-navigation-item-active-forced': item.active}"> 'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-horizontal-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-horizontal-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper"> <div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -90,25 +96,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-horizontal-navigation-item-subtitle text-hint" <div class="fuse-horizontal-navigation-item-subtitle text-hint">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-horizontal-navigation-item-badge" <div class="fuse-horizontal-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-horizontal-navigation-item-badge-content"
class="fuse-horizontal-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
</div> </div>
</div> </div>
@@ -1,21 +1,28 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { MatMenu } from '@angular/material/menu'; import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
import { Subject } from 'rxjs'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { takeUntil } from 'rxjs/operators'; import { MatIconModule } from '@angular/material/icon';
import { MatMenu, MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseHorizontalNavigationBasicItemComponent } from '@fuse/components/navigation/horizontal/components/basic/basic.component';
import { FuseHorizontalNavigationDividerItemComponent } from '@fuse/components/navigation/horizontal/components/divider/divider.component';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-horizontal-navigation-branch-item', selector : 'fuse-horizontal-navigation-branch-item',
templateUrl : './branch.component.html', templateUrl : './branch.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgIf, NgClass, MatMenuModule, NgTemplateOutlet, NgFor, FuseHorizontalNavigationBasicItemComponent, forwardRef(() => FuseHorizontalNavigationBranchItemComponent), FuseHorizontalNavigationDividerItemComponent, MatTooltipModule, MatIconModule],
}) })
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_child: BooleanInput; static ngAcceptInputType_child: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() child: boolean = false; @Input() child: boolean = false;
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@@ -30,7 +37,7 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -49,9 +56,9 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe( this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -63,7 +70,7 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -79,4 +86,15 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
} }
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
} }
@@ -1,15 +1,16 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-horizontal-navigation-divider-item', selector : 'fuse-horizontal-navigation-divider-item',
templateUrl : './divider.component.html', templateUrl : './divider.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass],
}) })
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
{ {
@@ -24,7 +25,7 @@ export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnD
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -43,9 +44,9 @@ export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnD
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe( this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -57,7 +58,7 @@ export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnD
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -1,15 +1,16 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-horizontal-navigation-spacer-item', selector : 'fuse-horizontal-navigation-spacer-item',
templateUrl : './spacer.component.html', templateUrl : './spacer.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass],
}) })
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
{ {
@@ -24,7 +25,7 @@ export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDe
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -43,9 +44,9 @@ export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDe
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe( this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -57,7 +58,7 @@ export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDe
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -1,30 +1,33 @@
<div class="fuse-horizontal-navigation-wrapper"> <div class="fuse-horizontal-navigation-wrapper">
<ng-container *ngFor="let item of navigation"> <ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<fuse-horizontal-navigation-basic-item <ng-container *ngIf="item.type === 'basic'">
class="fuse-horizontal-navigation-menu-item" <fuse-horizontal-navigation-basic-item
*ngIf="item.type === 'basic'" class="fuse-horizontal-navigation-menu-item"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item> [name]="name"></fuse-horizontal-navigation-basic-item>
</ng-container>
<!-- Branch: aside, collapsable, group --> <!-- Branch: aside, collapsable, group -->
<fuse-horizontal-navigation-branch-item <ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
class="fuse-horizontal-navigation-menu-item" <fuse-horizontal-navigation-branch-item
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'" class="fuse-horizontal-navigation-menu-item"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item> [name]="name"></fuse-horizontal-navigation-branch-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<fuse-horizontal-navigation-spacer-item <ng-container *ngIf="item.type === 'spacer'">
class="fuse-horizontal-navigation-menu-item" <fuse-horizontal-navigation-spacer-item
*ngIf="item.type === 'spacer'" class="fuse-horizontal-navigation-menu-item"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item> [name]="name"></fuse-horizontal-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -1,18 +1,24 @@
import { NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { ReplaySubject, Subject } from 'rxjs'; import { fuseAnimations } from '@fuse/animations';
import { FuseAnimations } from '@fuse/animations';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service'; import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { ReplaySubject, Subject } from 'rxjs';
import { FuseHorizontalNavigationBasicItemComponent } from './components/basic/basic.component';
import { FuseHorizontalNavigationBranchItemComponent } from './components/branch/branch.component';
import { FuseHorizontalNavigationSpacerItemComponent } from './components/spacer/spacer.component';
@Component({ @Component({
selector : 'fuse-horizontal-navigation', selector : 'fuse-horizontal-navigation',
templateUrl : './horizontal.component.html', templateUrl : './horizontal.component.html',
styleUrls : ['./horizontal.component.scss'], styleUrls : ['./horizontal.component.scss'],
animations : FuseAnimations, animations : fuseAnimations,
encapsulation : ViewEncapsulation.None, encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseHorizontalNavigation' exportAs : 'fuseHorizontalNavigation',
standalone : true,
imports : [NgFor, NgIf, FuseHorizontalNavigationBasicItemComponent, FuseHorizontalNavigationBranchItemComponent, FuseHorizontalNavigationSpacerItemComponent],
}) })
export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnDestroy export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnDestroy
{ {
@@ -28,7 +34,7 @@ export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnD
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService, private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService,
) )
{ {
} }
@@ -76,7 +82,7 @@ export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnD
this._fuseNavigationService.deregisterComponent(this.name); this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -1,55 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseScrollbarModule } from '@fuse/directives/scrollbar/public-api';
import { FuseHorizontalNavigationBasicItemComponent } from '@fuse/components/navigation/horizontal/components/basic/basic.component';
import { FuseHorizontalNavigationBranchItemComponent } from '@fuse/components/navigation/horizontal/components/branch/branch.component';
import { FuseHorizontalNavigationDividerItemComponent } from '@fuse/components/navigation/horizontal/components/divider/divider.component';
import { FuseHorizontalNavigationSpacerItemComponent } from '@fuse/components/navigation/horizontal/components/spacer/spacer.component';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseVerticalNavigationAsideItemComponent } from '@fuse/components/navigation/vertical/components/aside/aside.component';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
@NgModule({
declarations: [
FuseHorizontalNavigationBasicItemComponent,
FuseHorizontalNavigationBranchItemComponent,
FuseHorizontalNavigationDividerItemComponent,
FuseHorizontalNavigationSpacerItemComponent,
FuseHorizontalNavigationComponent,
FuseVerticalNavigationAsideItemComponent,
FuseVerticalNavigationBasicItemComponent,
FuseVerticalNavigationCollapsableItemComponent,
FuseVerticalNavigationDividerItemComponent,
FuseVerticalNavigationGroupItemComponent,
FuseVerticalNavigationSpacerItemComponent,
FuseVerticalNavigationComponent
],
imports : [
CommonModule,
RouterModule,
MatButtonModule,
MatDividerModule,
MatIconModule,
MatMenuModule,
MatTooltipModule,
FuseScrollbarModule
],
exports : [
FuseHorizontalNavigationComponent,
FuseVerticalNavigationComponent
]
})
export class FuseNavigationModule
{
}
@@ -1,9 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@Injectable({ @Injectable({providedIn: 'root'})
providedIn: 'root'
})
export class FuseNavigationService export class FuseNavigationService
{ {
private _componentRegistry: Map<string, any> = new Map<string, any>(); private _componentRegistry: Map<string, any> = new Map<string, any>();
@@ -46,7 +44,7 @@ export class FuseNavigationService
* *
* @param name * @param name
*/ */
getComponent(name: string): any getComponent<T>(name: string): T
{ {
return this._componentRegistry.get(name); return this._componentRegistry.get(name);
} }
@@ -67,7 +65,6 @@ export class FuseNavigationService
* Get navigation from storage by key * Get navigation from storage by key
* *
* @param key * @param key
* @returns {any}
*/ */
getNavigation(key: string): FuseNavigationItem[] getNavigation(key: string): FuseNavigationItem[]
{ {
@@ -97,7 +94,6 @@ export class FuseNavigationService
* *
* @param navigation * @param navigation
* @param flatNavigation * @param flatNavigation
* @returns {FuseNavigationItem[]}
*/ */
getFlatNavigation(navigation: FuseNavigationItem[], flatNavigation: FuseNavigationItem[] = []): FuseNavigationItem[] getFlatNavigation(navigation: FuseNavigationItem[], flatNavigation: FuseNavigationItem[] = []): FuseNavigationItem[]
{ {
@@ -162,7 +158,7 @@ export class FuseNavigationService
getItemParent( getItemParent(
id: string, id: string,
navigation: FuseNavigationItem[], navigation: FuseNavigationItem[],
parent: FuseNavigationItem[] | FuseNavigationItem parent: FuseNavigationItem[] | FuseNavigationItem,
): FuseNavigationItem[] | FuseNavigationItem | null ): FuseNavigationItem[] | FuseNavigationItem | null
{ {
for ( const item of navigation ) for ( const item of navigation )
@@ -1,3 +1,5 @@
import { IsActiveMatchOptions, Params, QueryParamsHandling } from '@angular/router';
export interface FuseNavigationItem export interface FuseNavigationItem
{ {
id?: string; id?: string;
@@ -13,9 +15,21 @@ export interface FuseNavigationItem
hidden?: (item: FuseNavigationItem) => boolean; hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean; active?: boolean;
disabled?: boolean; disabled?: boolean;
tooltip?: string;
link?: string; link?: string;
fragment?: string;
preserveFragment?: boolean;
queryParams?: Params | null;
queryParamsHandling?: QueryParamsHandling | null;
externalLink?: boolean; externalLink?: boolean;
target?:
| '_blank'
| '_self'
| '_parent'
| '_top'
| string;
exactMatch?: boolean; exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void; function?: (item: FuseNavigationItem) => void;
classes?: { classes?: {
title?: string; title?: string;
@@ -1,5 +1,4 @@
export * from '@fuse/components/navigation/horizontal/horizontal.component'; export * from '@fuse/components/navigation/horizontal/horizontal.component';
export * from '@fuse/components/navigation/vertical/vertical.component'; export * from '@fuse/components/navigation/vertical/vertical.component';
export * from '@fuse/components/navigation/navigation.module';
export * from '@fuse/components/navigation/navigation.service'; export * from '@fuse/components/navigation/navigation.service';
export * from '@fuse/components/navigation/navigation.types'; export * from '@fuse/components/navigation/navigation.types';
@@ -7,14 +7,16 @@
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active': active, [ngClass]="{'fuse-vertical-navigation-item-active': active,
'fuse-vertical-navigation-item-disabled': item.disabled, 'fuse-vertical-navigation-item-disabled': item.disabled,
'fuse-vertical-navigation-item-active-forced': item.active}"> 'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-vertical-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-vertical-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -23,25 +25,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-vertical-navigation-item-subtitle" <div class="fuse-vertical-navigation-item-subtitle">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge" <div class="fuse-vertical-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge-content"
class="fuse-vertical-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
</div> </div>
@@ -57,35 +59,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<fuse-vertical-navigation-basic-item <ng-container *ngIf="item.type === 'basic'">
*ngIf="item.type === 'basic'" <fuse-vertical-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item <ng-container *ngIf="item.type === 'collapsable'">
*ngIf="item.type === 'collapsable'" <fuse-vertical-navigation-collapsable-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<fuse-vertical-navigation-divider-item <ng-container *ngIf="item.type === 'divider'">
*ngIf="item.type === 'divider'" <fuse-vertical-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<fuse-vertical-navigation-group-item <ng-container *ngIf="item.type === 'group'">
*ngIf="item.type === 'group'" <fuse-vertical-navigation-group-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<fuse-vertical-navigation-spacer-item <ng-container *ngIf="item.type === 'spacer'">
*ngIf="item.type === 'spacer'" <fuse-vertical-navigation-spacer-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -1,22 +1,32 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { Subject } from 'rxjs'; import { NgClass, NgFor, NgIf } from '@angular/common';
import { filter, takeUntil } from 'rxjs/operators'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { NavigationEnd, Router } from '@angular/router';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-aside-item', selector : 'fuse-vertical-navigation-aside-item',
templateUrl : './aside.component.html', templateUrl : './aside.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass, MatTooltipModule, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
}) })
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput; static ngAcceptInputType_autoCollapse: BooleanInput;
static ngAcceptInputType_skipChildren: BooleanInput; static ngAcceptInputType_skipChildren: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() activeItemId: string; @Input() activeItemId: string;
@Input() autoCollapse: boolean; @Input() autoCollapse: boolean;
@@ -34,7 +44,7 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _router: Router, private _router: Router,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -70,10 +80,10 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
this._router.events this._router.events
.pipe( .pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd), filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
) )
.subscribe((event: NavigationEnd) => { .subscribe((event: NavigationEnd) =>
{
// Mark if active // Mark if active
this._markIfActive(event.urlAfterRedirects); this._markIfActive(event.urlAfterRedirects);
}); });
@@ -83,9 +93,9 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -97,10 +107,25 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Private methods // @ Private methods
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -168,19 +193,4 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
} }
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
} }
@@ -5,68 +5,92 @@
[ngClass]="item.classes?.wrapper"> [ngClass]="item.classes?.wrapper">
<!-- Item with an internal link --> <!-- Item with an internal link -->
<a <ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
class="fuse-vertical-navigation-item" <a
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [fragment]="item.fragment ?? null"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"> [preserveFragment]="item.preserveFragment ?? false"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [queryParams]="item.queryParams ?? null"
</a> [queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with an external link --> <!-- Item with an external link -->
<a <ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
class="fuse-vertical-navigation-item" <a
*ngIf="item.link && item.externalLink && !item.function && !item.disabled" class="fuse-vertical-navigation-item"
[href]="item.link"> [href]="item.link"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [target]="item.target || '_self'"
</a> [matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function --> <!-- Item with a function -->
<div <ng-container *ngIf="!item.link && item.function && !item.disabled">
class="fuse-vertical-navigation-item" <div
*ngIf="!item.link && item.function && !item.disabled" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
(click)="item.function(item)"> [matTooltip]="item.tooltip || ''"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> (click)="item.function(item)">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function --> <!-- Item with an internal link and function -->
<a <ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
class="fuse-vertical-navigation-item" <a
*ngIf="item.link && !item.externalLink && item.function && !item.disabled" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [fragment]="item.fragment ?? null"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" [preserveFragment]="item.preserveFragment ?? false"
(click)="item.function(item)"> [queryParams]="item.queryParams ?? null"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [queryParamsHandling]="item.queryParamsHandling ?? null"
</a> [routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with an external link and function --> <!-- Item with an external link and function -->
<a <ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
class="fuse-vertical-navigation-item" <a
*ngIf="item.link && item.externalLink && item.function && !item.disabled" class="fuse-vertical-navigation-item"
[href]="item.link" [href]="item.link"
(click)="item.function(item)"> [target]="item.target || '_self'"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [matTooltip]="item.tooltip || ''"
</a> (click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function --> <!-- Item with a no link and no function -->
<div <ng-container *ngIf="!item.link && !item.function && !item.disabled">
class="fuse-vertical-navigation-item" <div
*ngIf="!item.link && !item.function && !item.disabled" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"> [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [matTooltip]="item.tooltip || ''">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled --> <!-- Item is disabled -->
<div <ng-container *ngIf="item.disabled">
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled" <div
*ngIf="item.disabled"> class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> [matTooltip]="item.tooltip || ''">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
</div> </div>
@@ -74,11 +98,12 @@
<ng-template #itemTemplate> <ng-template #itemTemplate>
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-vertical-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-vertical-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -87,24 +112,24 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-vertical-navigation-item-subtitle" <div class="fuse-vertical-navigation-item-subtitle">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge" <div class="fuse-vertical-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge-content"
class="fuse-vertical-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
</ng-template> </ng-template>
@@ -1,22 +1,27 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs'; import { MatIconModule } from '@angular/material/icon';
import { takeUntil } from 'rxjs/operators'; import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { IsActiveMatchOptions, RouterLink, RouterLinkActive } from '@angular/router';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseUtilsService } from '@fuse/services/utils/utils.service'; import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-basic-item', selector : 'fuse-vertical-navigation-basic-item',
templateUrl : './basic.component.html', templateUrl : './basic.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass, NgIf, RouterLink, RouterLinkActive, MatTooltipModule, NgTemplateOutlet, MatIconModule],
}) })
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
{ {
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@Input() name: string; @Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -26,9 +31,14 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService, private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService,
) )
{ {
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -40,14 +50,25 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
*/ */
ngOnInit(): void ngOnInit(): void
{ {
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component // Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name); this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -59,7 +80,7 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -6,14 +6,16 @@
<div <div
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}" [ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}"
[matTooltip]="item.tooltip || ''"
(click)="toggleCollapsable()"> (click)="toggleCollapsable()">
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-vertical-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-vertical-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -22,25 +24,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-vertical-navigation-item-subtitle" <div class="fuse-vertical-navigation-item-subtitle">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge" <div class="fuse-vertical-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge-content"
class="fuse-vertical-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
<!-- Arrow --> <!-- Arrow -->
<mat-icon <mat-icon
@@ -62,35 +64,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<fuse-vertical-navigation-basic-item <ng-container *ngIf="item.type === 'basic'">
*ngIf="item.type === 'basic'" <fuse-vertical-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item <ng-container *ngIf="item.type === 'collapsable'">
*ngIf="item.type === 'collapsable'" <fuse-vertical-navigation-collapsable-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<fuse-vertical-navigation-divider-item <ng-container *ngIf="item.type === 'divider'">
*ngIf="item.type === 'divider'" <fuse-vertical-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<fuse-vertical-navigation-group-item <ng-container *ngIf="item.type === 'group'">
*ngIf="item.type === 'group'" <fuse-vertical-navigation-group-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<fuse-vertical-navigation-spacer-item <ng-container *ngIf="item.type === 'spacer'">
*ngIf="item.type === 'spacer'" <fuse-vertical-navigation-spacer-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -1,23 +1,32 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { Subject } from 'rxjs'; import { NgClass, NgFor, NgIf } from '@angular/common';
import { filter, takeUntil } from 'rxjs/operators'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { FuseAnimations } from '@fuse/animations'; import { MatIconModule } from '@angular/material/icon';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { MatTooltipModule } from '@angular/material/tooltip';
import { NavigationEnd, Router } from '@angular/router';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-collapsable-item', selector : 'fuse-vertical-navigation-collapsable-item',
templateUrl : './collapsable.component.html', templateUrl : './collapsable.component.html',
styles : [], animations : fuseAnimations,
animations : FuseAnimations, changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass, MatTooltipModule, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, forwardRef(() => FuseVerticalNavigationCollapsableItemComponent), FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
}) })
export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput; static ngAcceptInputType_autoCollapse: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() autoCollapse: boolean; @Input() autoCollapse: boolean;
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@@ -34,7 +43,7 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _router: Router, private _router: Router,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -48,10 +57,12 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-vertical-navigation-item-collapsed': this.isCollapsed, 'fuse-vertical-navigation-item-collapsed': this.isCollapsed,
'fuse-vertical-navigation-item-expanded' : this.isExpanded 'fuse-vertical-navigation-item-expanded' : this.isExpanded,
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -84,8 +95,8 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
// Listen for the onCollapsableItemCollapsed from the service // Listen for the onCollapsableItemCollapsed from the service
this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed
.pipe(takeUntil(this._unsubscribeAll)) .pipe(takeUntil(this._unsubscribeAll))
.subscribe((collapsedItem) => { .subscribe((collapsedItem) =>
{
// Check if the collapsed item is null // Check if the collapsed item is null
if ( collapsedItem === null ) if ( collapsedItem === null )
{ {
@@ -104,8 +115,8 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
{ {
this._fuseVerticalNavigationComponent.onCollapsableItemExpanded this._fuseVerticalNavigationComponent.onCollapsableItemExpanded
.pipe(takeUntil(this._unsubscribeAll)) .pipe(takeUntil(this._unsubscribeAll))
.subscribe((expandedItem) => { .subscribe((expandedItem) =>
{
// Check if the expanded item is null // Check if the expanded item is null
if ( expandedItem === null ) if ( expandedItem === null )
{ {
@@ -139,10 +150,10 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
this._router.events this._router.events
.pipe( .pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd), filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
) )
.subscribe((event: NavigationEnd) => { .subscribe((event: NavigationEnd) =>
{
// If the item has a children that has a matching url with the current url, expand... // If the item has a children that has a matching url with the current url, expand...
if ( this._hasActiveChild(this.item, event.urlAfterRedirects) ) if ( this._hasActiveChild(this.item, event.urlAfterRedirects) )
{ {
@@ -161,9 +172,9 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -175,88 +186,10 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Check if the given item has the given url
* in one of its children
*
* @param item
* @param currentUrl
* @private
*/
private _hasActiveChild(item: FuseNavigationItem, currentUrl: string): boolean
{
const children = item.children;
if ( !children )
{
return false;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._hasActiveChild(child, currentUrl) )
{
return true;
}
}
// Check if the child has a link and is active
if ( child.link && this._router.isActive(child.link, child.exactMatch || false) )
{
return true;
}
}
return false;
}
/**
* Check if this is a children
* of the given item
*
* @param parent
* @param item
* @return {boolean}
* @private
*/
private _isChildrenOf(parent: FuseNavigationItem, item: FuseNavigationItem): boolean
{
const children = parent.children;
if ( !children )
{
return false;
}
if ( children.indexOf(item) > -1 )
{
return true;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._isChildrenOf(child, item) )
{
return true;
}
}
}
return false;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Public methods // @ Public methods
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -343,4 +276,81 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
{ {
return item.id || index; return item.id || index;
} }
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Check if the given item has the given url
* in one of its children
*
* @param item
* @param currentUrl
* @private
*/
private _hasActiveChild(item: FuseNavigationItem, currentUrl: string): boolean
{
const children = item.children;
if ( !children )
{
return false;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._hasActiveChild(child, currentUrl) )
{
return true;
}
}
// Check if the child has a link and is active
if ( child.link && this._router.isActive(child.link, child.exactMatch || false) )
{
return true;
}
}
return false;
}
/**
* Check if this is a children
* of the given item
*
* @param parent
* @param item
* @private
*/
private _isChildrenOf(parent: FuseNavigationItem, item: FuseNavigationItem): boolean
{
const children = parent.children;
if ( !children )
{
return false;
}
if ( children.indexOf(item) > -1 )
{
return true;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._isChildrenOf(child, item) )
{
return true;
}
}
}
return false;
}
} }
@@ -1,15 +1,16 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-divider-item', selector : 'fuse-vertical-navigation-divider-item',
templateUrl : './divider.component.html', templateUrl : './divider.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass],
}) })
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
{ {
@@ -24,7 +25,7 @@ export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDes
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -43,9 +44,9 @@ export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDes
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -57,7 +58,7 @@ export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDes
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -7,11 +7,12 @@
<div class="fuse-vertical-navigation-item"> <div class="fuse-vertical-navigation-item">
<!-- Icon --> <!-- Icon -->
<mat-icon <ng-container *ngIf="item.icon">
class="fuse-vertical-navigation-item-icon" <mat-icon
[ngClass]="item.classes?.icon" class="fuse-vertical-navigation-item-icon"
*ngIf="item.icon" [ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -20,25 +21,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<div <ng-container *ngIf="item.subtitle">
class="fuse-vertical-navigation-item-subtitle" <div class="fuse-vertical-navigation-item-subtitle">
*ngIf="item.subtitle"> <span [ngClass]="item.classes?.subtitle">
<span [ngClass]="item.classes?.subtitle"> {{item.subtitle}}
{{item.subtitle}} </span>
</span> </div>
</div> </ng-container>
</div> </div>
<!-- Badge --> <!-- Badge -->
<div <ng-container *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge" <div class="fuse-vertical-navigation-item-badge">
*ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge-content"
class="fuse-vertical-navigation-item-badge-content" [ngClass]="item.badge.classes">
[ngClass]="item.badge.classes"> {{item.badge.title}}
{{item.badge.title}} </div>
</div> </div>
</div> </ng-container>
</div> </div>
@@ -50,35 +51,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<fuse-vertical-navigation-basic-item <ng-container *ngIf="item.type === 'basic'">
*ngIf="item.type === 'basic'" <fuse-vertical-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item <ng-container *ngIf="item.type === 'collapsable'">
*ngIf="item.type === 'collapsable'" <fuse-vertical-navigation-collapsable-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<fuse-vertical-navigation-divider-item <ng-container *ngIf="item.type === 'divider'">
*ngIf="item.type === 'divider'" <fuse-vertical-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<fuse-vertical-navigation-group-item <ng-container *ngIf="item.type === 'group'">
*ngIf="item.type === 'group'" <fuse-vertical-navigation-group-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<fuse-vertical-navigation-spacer-item <ng-container *ngIf="item.type === 'spacer'">
*ngIf="item.type === 'spacer'" <fuse-vertical-navigation-spacer-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -1,20 +1,28 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { Subject } from 'rxjs'; import { NgClass, NgFor, NgIf } from '@angular/common';
import { takeUntil } from 'rxjs/operators'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { MatIconModule } from '@angular/material/icon';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-group-item', selector : 'fuse-vertical-navigation-group-item',
templateUrl : './group.component.html', templateUrl : './group.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, forwardRef(() => FuseVerticalNavigationGroupItemComponent), FuseVerticalNavigationSpacerItemComponent],
}) })
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput; static ngAcceptInputType_autoCollapse: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() autoCollapse: boolean; @Input() autoCollapse: boolean;
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@@ -28,7 +36,7 @@ export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestr
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -47,9 +55,9 @@ export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestr
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -61,7 +69,7 @@ export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestr
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -1,15 +1,16 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation-spacer-item', selector : 'fuse-vertical-navigation-spacer-item',
templateUrl : './spacer.component.html', templateUrl : './spacer.component.html',
styles : [], changeDetection: ChangeDetectionStrategy.OnPush,
changeDetection: ChangeDetectionStrategy.OnPush standalone : true,
imports : [NgClass],
}) })
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
{ {
@@ -24,7 +25,7 @@ export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDest
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService private _fuseNavigationService: FuseNavigationService,
) )
{ {
} }
@@ -43,9 +44,9 @@ export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDest
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
}); });
@@ -57,7 +58,7 @@ export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDest
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -1,20 +1,22 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-compact-width: 112; :root {
--fuse-vertical-navigation-compact-width: 112px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
/* Compact appearance overrides */ /* Compact appearance overrides */
&.fuse-vertical-navigation-appearance-compact { &.fuse-vertical-navigation-appearance-compact {
width: #{$fuse-vertical-navigation-compact-width}px; width: var(--fuse-vertical-navigation-compact-width);
min-width: #{$fuse-vertical-navigation-compact-width}px; min-width: var(--fuse-vertical-navigation-compact-width);
max-width: #{$fuse-vertical-navigation-compact-width}px; max-width: var(--fuse-vertical-navigation-compact-width);
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -#{$fuse-vertical-navigation-compact-width}px; margin-left: calc(var(--fuse-vertical-navigation-compact-width) * -1);
} }
/* Opened */ /* Opened */
@@ -28,7 +30,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -#{$fuse-vertical-navigation-compact-width}px; margin-right: calc(var(--fuse-vertical-navigation-compact-width) * -1);
} }
/* Opened */ /* Opened */
@@ -39,7 +41,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: #{$fuse-vertical-navigation-compact-width}px; right: var(--fuse-vertical-navigation-compact-width);
} }
} }
@@ -104,7 +106,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: #{$fuse-vertical-navigation-compact-width}px; left: var(--fuse-vertical-navigation-compact-width);
} }
} }
} }
@@ -1,5 +1,7 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-width: 280; :root {
--fuse-vertical-navigation-width: 280px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
position: sticky; position: sticky;
@@ -7,9 +9,9 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
flex: 1 0 auto; flex: 1 0 auto;
top: 0; top: 0;
width: #{$fuse-vertical-navigation-width}px; width: var(--fuse-vertical-navigation-width);
min-width: #{$fuse-vertical-navigation-width}px; min-width: var(--fuse-vertical-navigation-width);
max-width: #{$fuse-vertical-navigation-width}px; max-width: var(--fuse-vertical-navigation-width);
height: 100vh; height: 100vh;
min-height: 100vh; min-height: 100vh;
max-height: 100vh; max-height: 100vh;
@@ -45,7 +47,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -#{$fuse-vertical-navigation-width}px; margin-left: calc(#{var(--fuse-vertical-navigation-width)} * -1);
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-left: 0; margin-left: 0;
@@ -73,7 +75,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -#{$fuse-vertical-navigation-width}px; margin-right: calc(var(--fuse-vertical-navigation-width) * -1);
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-right: 0; margin-right: 0;
@@ -170,8 +172,8 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: #{$fuse-vertical-navigation-width}px; left: var(--fuse-vertical-navigation-width);
width: #{$fuse-vertical-navigation-width}px; width: var(--fuse-vertical-navigation-width);
height: 100%; height: 100%;
z-index: 5; z-index: 5;
overflow-x: hidden; overflow-x: hidden;
@@ -196,7 +198,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: #{$fuse-vertical-navigation-width}px; right: var(--fuse-vertical-navigation-width);
} }
} }
@@ -336,6 +338,10 @@ fuse-vertical-navigation {
> .fuse-vertical-navigation-item-children { > .fuse-vertical-navigation-item-children {
> *:first-child {
margin-top: 6px;
}
> *:last-child { > *:last-child {
padding-bottom: 6px; padding-bottom: 6px;
@@ -1,6 +1,8 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-width: 280; :root {
$fuse-vertical-navigation-dense-width: 80; --fuse-vertical-navigation-width: 280px;
--fuse-vertical-navigation-dense-width: 80px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
@@ -8,16 +10,16 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-appearance-dense { &.fuse-vertical-navigation-appearance-dense {
&:not(.fuse-vertical-navigation-mode-over) { &:not(.fuse-vertical-navigation-mode-over) {
width: #{$fuse-vertical-navigation-dense-width}px; width: var(--fuse-vertical-navigation-dense-width);
min-width: #{$fuse-vertical-navigation-dense-width}px; min-width: var(--fuse-vertical-navigation-dense-width);
max-width: #{$fuse-vertical-navigation-dense-width}px; max-width: var(--fuse-vertical-navigation-dense-width);
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -#{$fuse-vertical-navigation-dense-width}px; margin-left: calc(var(--fuse-vertical-navigation-dense-width) * -1);
} }
/* Opened */ /* Opened */
@@ -31,7 +33,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -#{$fuse-vertical-navigation-dense-width}px; margin-right: calc(var(--fuse-vertical-navigation-dense-width) * -1);
} }
/* Opened */ /* Opened */
@@ -42,14 +44,14 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: #{$fuse-vertical-navigation-dense-width}px; right: var(--fuse-vertical-navigation-dense-width);
} }
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: #{$fuse-vertical-navigation-width}px; right: var(--fuse-vertical-navigation-width);
} }
} }
} }
@@ -69,9 +71,9 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: #{$fuse-vertical-navigation-width}px - 24px; width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
min-width: #{$fuse-vertical-navigation-width}px - 24px; min-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
max-width: #{$fuse-vertical-navigation-width}px - 24px; max-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -142,20 +144,23 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: #{$fuse-vertical-navigation-dense-width}px; left: var(--fuse-vertical-navigation-dense-width);
} }
/* Hover */ /* Hover */
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-wrapper { .fuse-vertical-navigation-wrapper {
width: #{$fuse-vertical-navigation-width}px; width: var(--fuse-vertical-navigation-width);
.fuse-vertical-navigation-content { .fuse-vertical-navigation-content {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: calc(var(--fuse-vertical-navigation-width) - 24px);
min-width: calc(var(--fuse-vertical-navigation-width) - 24px);
max-width: calc(var(--fuse-vertical-navigation-width) - 24px);
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -170,7 +175,7 @@ fuse-vertical-navigation {
} }
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: #{$fuse-vertical-navigation-width}px; left: var(--fuse-vertical-navigation-width);
} }
} }
} }
@@ -1,19 +1,21 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-thin-width: 80; :root {
--fuse-vertical-navigation-thin-width: 80px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
/* Thin appearance overrides */ /* Thin appearance overrides */
&.fuse-vertical-navigation-appearance-thin { &.fuse-vertical-navigation-appearance-thin {
width: #{$fuse-vertical-navigation-thin-width}px; width: var(--fuse-vertical-navigation-thin-width);
min-width: #{$fuse-vertical-navigation-thin-width}px; min-width: var(--fuse-vertical-navigation-thin-width);
max-width: #{$fuse-vertical-navigation-thin-width}px; max-width: var(--fuse-vertical-navigation-thin-width);
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -#{$fuse-vertical-navigation-thin-width}px; margin-left: calc(var(--fuse-vertical-navigation-thin-width) * -1);
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -25,7 +27,7 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-position-right { &.fuse-vertical-navigation-position-right {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -#{$fuse-vertical-navigation-thin-width}px; margin-right: calc(var(--fuse-vertical-navigation-thin-width) * -1);
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -34,7 +36,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: #{$fuse-vertical-navigation-thin-width}px; right: var(--fuse-vertical-navigation-thin-width);
} }
} }
@@ -91,7 +93,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: #{$fuse-vertical-navigation-thin-width}px; left: var(--fuse-vertical-navigation-thin-width);
} }
} }
} }
@@ -24,46 +24,52 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside --> <!-- Aside -->
<fuse-vertical-navigation-aside-item <ng-container *ngIf="item.type === 'aside'">
*ngIf="item.type === 'aside'" <fuse-vertical-navigation-aside-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[activeItemId]="activeAsideItemId" [activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse" [autoCollapse]="autoCollapse"
[skipChildren]="true" [skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item> (click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
</ng-container>
<!-- Basic --> <!-- Basic -->
<fuse-vertical-navigation-basic-item <ng-container *ngIf="item.type === 'basic'">
*ngIf="item.type === 'basic'" <fuse-vertical-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item <ng-container *ngIf="item.type === 'collapsable'">
*ngIf="item.type === 'collapsable'" <fuse-vertical-navigation-collapsable-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<fuse-vertical-navigation-divider-item <ng-container *ngIf="item.type === 'divider'">
*ngIf="item.type === 'divider'" <fuse-vertical-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<fuse-vertical-navigation-group-item <ng-container *ngIf="item.type === 'group'">
*ngIf="item.type === 'group'" <fuse-vertical-navigation-group-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<fuse-vertical-navigation-spacer-item <ng-container *ngIf="item.type === 'spacer'">
*ngIf="item.type === 'spacer'" <fuse-vertical-navigation-spacer-item
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -84,31 +90,33 @@
</div> </div>
<!-- Aside --> <!-- Aside -->
<div <ng-container *ngIf="activeAsideItemId">
class="fuse-vertical-navigation-aside-wrapper" <div
*ngIf="activeAsideItemId" class="fuse-vertical-navigation-aside-wrapper"
fuseScrollbar fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}" [fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'" [@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'" [@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'" [@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'"> [@fadeOutRight]="position === 'right'">
<!-- Items --> <!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn"> <ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside --> <!-- Aside -->
<fuse-vertical-navigation-aside-item <ng-container *ngIf="item.type === 'aside' && item.id === activeAsideItemId">
*ngIf="item.type === 'aside' && item.id === activeAsideItemId" <fuse-vertical-navigation-aside-item
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
</ng-container>
</ng-container>
</ng-container> </ng-container>
</ng-container> </div>
</ng-container>
</div>
@@ -1,4 +1,4 @@
@import 'styles/appearances/default'; @use 'styles/appearances/default';
@import 'styles/appearances/compact'; @use 'styles/appearances/compact';
@import 'styles/appearances/dense'; @use 'styles/appearances/dense';
@import 'styles/appearances/thin'; @use 'styles/appearances/thin';
@@ -1,30 +1,40 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { NavigationEnd, Router } from '@angular/router'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay'; import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { merge, ReplaySubject, Subject, Subscription } from 'rxjs'; import { DOCUMENT, NgFor, NgIf } from '@angular/common';
import { delay, filter, takeUntil } from 'rxjs/operators'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Inject, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { FuseAnimations } from '@fuse/animations'; import { NavigationEnd, Router } from '@angular/router';
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types'; import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationAsideItemComponent } from '@fuse/components/navigation/vertical/components/aside/aside.component';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive'; import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive';
import { FuseUtilsService } from '@fuse/services/utils/utils.service'; import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs';
@Component({ @Component({
selector : 'fuse-vertical-navigation', selector : 'fuse-vertical-navigation',
templateUrl : './vertical.component.html', templateUrl : './vertical.component.html',
styleUrls : ['./vertical.component.scss'], styleUrls : ['./vertical.component.scss'],
animations : FuseAnimations, animations : fuseAnimations,
encapsulation : ViewEncapsulation.None, encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseVerticalNavigation' exportAs : 'fuseVerticalNavigation',
standalone : true,
imports : [FuseScrollbarDirective, NgFor, NgIf, FuseVerticalNavigationAsideItemComponent, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
}) })
export class FuseVerticalNavigationComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy export class FuseVerticalNavigationComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_inner: BooleanInput; static ngAcceptInputType_inner: BooleanInput;
static ngAcceptInputType_opened: BooleanInput; static ngAcceptInputType_opened: BooleanInput;
static ngAcceptInputType_transparentOverlay: BooleanInput; static ngAcceptInputType_transparentOverlay: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() appearance: FuseVerticalNavigationAppearance = 'default'; @Input() appearance: FuseVerticalNavigationAppearance = 'default';
@Input() autoCollapse: boolean = true; @Input() autoCollapse: boolean = true;
@@ -50,6 +60,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
private readonly _handleAsideOverlayClick: any; private readonly _handleAsideOverlayClick: any;
private readonly _handleOverlayClick: any; private readonly _handleOverlayClick: any;
private _hovered: boolean = false; private _hovered: boolean = false;
private _mutationObserver: MutationObserver;
private _overlay: HTMLElement; private _overlay: HTMLElement;
private _player: AnimationPlayer; private _player: AnimationPlayer;
private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block(); private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
@@ -63,18 +74,21 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
constructor( constructor(
private _animationBuilder: AnimationBuilder, private _animationBuilder: AnimationBuilder,
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
@Inject(DOCUMENT) private _document: Document,
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _router: Router, private _router: Router,
private _scrollStrategyOptions: ScrollStrategyOptions, private _scrollStrategyOptions: ScrollStrategyOptions,
private _fuseNavigationService: FuseNavigationService, private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService,
) )
{ {
this._handleAsideOverlayClick = () => { this._handleAsideOverlayClick = (): void =>
{
this.closeAside(); this.closeAside();
}; };
this._handleOverlayClick = () => { this._handleOverlayClick = (): void =>
{
this.close(); this.close();
}; };
} }
@@ -88,6 +102,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-vertical-navigation-animations-enabled' : this._animationsEnabled, 'fuse-vertical-navigation-animations-enabled' : this._animationsEnabled,
[`fuse-vertical-navigation-appearance-${this.appearance}`]: true, [`fuse-vertical-navigation-appearance-${this.appearance}`]: true,
@@ -97,8 +112,9 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
'fuse-vertical-navigation-mode-side' : this.mode === 'side', 'fuse-vertical-navigation-mode-side' : this.mode === 'side',
'fuse-vertical-navigation-opened' : this.opened, 'fuse-vertical-navigation-opened' : this.opened,
'fuse-vertical-navigation-position-left' : this.position === 'left', 'fuse-vertical-navigation-position-left' : this.position === 'left',
'fuse-vertical-navigation-position-right' : this.position === 'right' 'fuse-vertical-navigation-position-right' : this.position === 'right',
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
/** /**
@@ -107,7 +123,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
@HostBinding('style') get styleList(): any @HostBinding('style') get styleList(): any
{ {
return { return {
'visibility': this.opened ? 'visible' : 'hidden' 'visibility': this.opened ? 'visible' : 'hidden',
}; };
} }
@@ -136,21 +152,56 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
this._fuseScrollbarDirectivesSubscription = this._fuseScrollbarDirectivesSubscription =
merge( merge(
this.onCollapsableItemCollapsed, this.onCollapsableItemCollapsed,
this.onCollapsableItemExpanded this.onCollapsableItemExpanded,
) )
.pipe( .pipe(
takeUntil(this._unsubscribeAll), takeUntil(this._unsubscribeAll),
delay(250) delay(250),
) )
.subscribe(() => { .subscribe(() =>
{
// Loop through the scrollbars and update them // Loop through the scrollbars and update them
fuseScrollbarDirectives.forEach((fuseScrollbarDirective) => { fuseScrollbarDirectives.forEach((fuseScrollbarDirective) =>
{
fuseScrollbarDirective.update(); fuseScrollbarDirective.update();
}); });
}); });
} }
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks // @ Lifecycle hooks
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -213,7 +264,8 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
// Enable the animations after a delay // Enable the animations after a delay
// The delay must be bigger than the current transition-duration // The delay must be bigger than the current transition-duration
// to make sure nothing will be animated while the mode changing // to make sure nothing will be animated while the mode changing
setTimeout(() => { setTimeout(() =>
{
this._enableAnimations(); this._enableAnimations();
}, 500); }, 500);
} }
@@ -268,10 +320,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
this._router.events this._router.events
.pipe( .pipe(
filter(event => event instanceof NavigationEnd), filter(event => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
) )
.subscribe(() => { .subscribe(() =>
{
// If the mode is 'over' and the navigation is opened... // If the mode is 'over' and the navigation is opened...
if ( this.mode === 'over' && this.opened ) if ( this.mode === 'over' && this.opened )
{ {
@@ -293,8 +345,38 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
ngAfterViewInit(): void ngAfterViewInit(): void
{ {
setTimeout(() => { // Fix for Firefox.
//
// Because 'position: sticky' doesn't work correctly inside a 'position: fixed' parent,
// adding the '.cdk-global-scrollblock' to the html element breaks the navigation's position.
// This fixes the problem by reading the 'top' value from the html element and adding it as a
// 'marginTop' to the navigation itself.
this._mutationObserver = new MutationObserver((mutations) =>
{
mutations.forEach((mutation) =>
{
const mutationTarget = mutation.target as HTMLElement;
if ( mutation.attributeName === 'class' )
{
if ( mutationTarget.classList.contains('cdk-global-scrollblock') )
{
const top = parseInt(mutationTarget.style.top, 10);
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', `${Math.abs(top)}px`);
}
else
{
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', null);
}
}
});
});
this._mutationObserver.observe(this._document.documentElement, {
attributes : true,
attributeFilter: ['class'],
});
setTimeout(() =>
{
// Return if 'navigation content' element does not exist // Return if 'navigation content' element does not exist
if ( !this._navigationContentEl ) if ( !this._navigationContentEl )
{ {
@@ -318,8 +400,8 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
else else
{ {
// Go through all the scrollbar directives // Go through all the scrollbar directives
this._fuseScrollbarDirectives.forEach((fuseScrollbarDirective) => { this._fuseScrollbarDirectives.forEach((fuseScrollbarDirective) =>
{
// Skip if not enabled // Skip if not enabled
if ( !fuseScrollbarDirective.isEnabled() ) if ( !fuseScrollbarDirective.isEnabled() )
{ {
@@ -338,11 +420,18 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Disconnect the mutation observer
this._mutationObserver.disconnect();
// Forcefully close the navigation and aside in case they are opened
this.close();
this.closeAside();
// Deregister the navigation component from the registry // Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name); this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -549,7 +638,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
// Create the enter animation and attach it to the player // Create the enter animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})),
]).create(this._overlay); ]).create(this._overlay);
// Play the animation // Play the animation
@@ -573,15 +662,15 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
// Create the leave animation and attach it to the player // Create the leave animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._overlay); ]).create(this._overlay);
// Play the animation // Play the animation
this._player.play(); this._player.play();
// Once the animation is done... // Once the animation is done...
this._player.onDone(() => { this._player.onDone(() =>
{
// If the overlay still exists... // If the overlay still exists...
if ( this._overlay ) if ( this._overlay )
{ {
@@ -624,7 +713,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
this._player = this._player =
this._animationBuilder this._animationBuilder
.build([ .build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})),
]).create(this._asideOverlay); ]).create(this._asideOverlay);
// Play the animation // Play the animation
@@ -650,15 +739,15 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
this._player = this._player =
this._animationBuilder this._animationBuilder
.build([ .build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._asideOverlay); ]).create(this._asideOverlay);
// Play the animation // Play the animation
this._player.play(); this._player.play();
// Once the animation is done... // Once the animation is done...
this._player.onDone(() => { this._player.onDone(() =>
{
// If the aside overlay still exists... // If the aside overlay still exists...
if ( this._asideOverlay ) if ( this._asideOverlay )
{ {
@@ -672,36 +761,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
}); });
} }
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
/** /**
* Open/close the navigation * Open/close the navigation
* *
@@ -1,114 +0,0 @@
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, HostListener, Input, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Subject } from 'rxjs';
@Directive({
selector: 'textarea[fuseAutogrow]',
exportAs: 'fuseAutogrow'
})
export class FuseAutogrowDirective implements OnChanges, OnInit, OnDestroy
{
// tslint:disable-next-line:no-input-rename
@Input('fuseAutogrowVerticalPadding') padding: number = 8;
@HostBinding('rows') private _rows: number = 1;
private _height: string = 'auto';
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private _ngZone: NgZone
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'height' : this._height,
'overflow': 'hidden',
'resize' : 'none'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Padding
if ( 'fuseAutogrowVerticalPadding' in changes )
{
// Resize
this._resize();
}
}
/**
* On init
*/
ngOnInit(): void
{
// Resize for the first time
this._resize();
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Resize on 'input' and 'ngModelChange' events
*
* @private
*/
@HostListener('input')
@HostListener('ngModelChange')
private _resize(): void
{
// This doesn't need to trigger Angular's change detection by itself
this._ngZone.runOutsideAngular(() => {
setTimeout(() => {
// Set the height to 'auto' so we can correctly read the scrollHeight
this._height = 'auto';
// Detect the changes so the height is applied
this._changeDetectorRef.detectChanges();
// Get the scrollHeight and subtract the vertical padding
this._height = `${this._elementRef.nativeElement.scrollHeight - this.padding}px`;
// Detect the changes one more time to apply the final height
this._changeDetectorRef.detectChanges();
});
});
}
}
@@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FuseAutogrowDirective } from '@fuse/directives/autogrow/autogrow.directive';
@NgModule({
declarations: [
FuseAutogrowDirective
],
exports : [
FuseAutogrowDirective
]
})
export class FuseAutogrowModule
{
}
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/directives/autogrow/public-api';
@@ -1,2 +0,0 @@
export * from '@fuse/directives/autogrow/autogrow.directive';
export * from '@fuse/directives/autogrow/autogrow.module';
@@ -1,2 +1 @@
export * from '@fuse/directives/scroll-reset/scroll-reset.directive'; export * from '@fuse/directives/scroll-reset/scroll-reset.directive';
export * from '@fuse/directives/scroll-reset/scroll-reset.module';
@@ -1,11 +1,11 @@
import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core'; import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { Subject } from 'rxjs'; import { filter, Subject, takeUntil } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[fuseScrollReset]', selector : '[fuseScrollReset]',
exportAs: 'fuseScrollReset' exportAs : 'fuseScrollReset',
standalone: true,
}) })
export class FuseScrollResetDirective implements OnInit, OnDestroy export class FuseScrollResetDirective implements OnInit, OnDestroy
{ {
@@ -16,7 +16,7 @@ export class FuseScrollResetDirective implements OnInit, OnDestroy
*/ */
constructor( constructor(
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _router: Router private _router: Router,
) )
{ {
} }
@@ -33,9 +33,9 @@ export class FuseScrollResetDirective implements OnInit, OnDestroy
// Subscribe to NavigationEnd event // Subscribe to NavigationEnd event
this._router.events.pipe( this._router.events.pipe(
filter(event => event instanceof NavigationEnd), filter(event => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll),
).subscribe(() => { ).subscribe(() =>
{
// Reset the element's scroll position to the top // Reset the element's scroll position to the top
this._elementRef.nativeElement.scrollTop = 0; this._elementRef.nativeElement.scrollTop = 0;
}); });
@@ -47,7 +47,7 @@ export class FuseScrollResetDirective implements OnInit, OnDestroy
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }
@@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FuseScrollResetDirective } from '@fuse/directives/scroll-reset/scroll-reset.directive';
@NgModule({
declarations: [
FuseScrollResetDirective
],
exports : [
FuseScrollResetDirective
]
})
export class FuseScrollResetModule
{
}
@@ -1,2 +1 @@
export * from '@fuse/directives/scrollbar/scrollbar.directive'; export * from '@fuse/directives/scrollbar/scrollbar.directive';
export * from '@fuse/directives/scrollbar/scrollbar.module';
@@ -1,23 +1,25 @@
import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Router } from '@angular/router';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { Platform } from '@angular/cdk/platform'; import { Platform } from '@angular/cdk/platform';
import { fromEvent, Subject } from 'rxjs'; import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { Router } from '@angular/router';
import PerfectScrollbar from 'perfect-scrollbar';
import { merge } from 'lodash-es';
import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types'; import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types';
import { merge } from 'lodash-es';
import PerfectScrollbar from 'perfect-scrollbar';
import { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs';
/** /**
* Wrapper directive for the Perfect Scrollbar: https://github.com/mdbootstrap/perfect-scrollbar * Wrapper directive for the Perfect Scrollbar: https://github.com/mdbootstrap/perfect-scrollbar
*/ */
@Directive({ @Directive({
selector: '[fuseScrollbar]', selector : '[fuseScrollbar]',
exportAs: 'fuseScrollbar' exportAs : 'fuseScrollbar',
standalone: true,
}) })
export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
{ {
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_fuseScrollbar: BooleanInput; static ngAcceptInputType_fuseScrollbar: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() fuseScrollbar: boolean = true; @Input() fuseScrollbar: boolean = true;
@Input() fuseScrollbarOptions: PerfectScrollbar.Options; @Input() fuseScrollbarOptions: PerfectScrollbar.Options;
@@ -33,7 +35,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
constructor( constructor(
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _platform: Platform, private _platform: Platform,
private _router: Router private _router: Router,
) )
{ {
} }
@@ -100,11 +102,13 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
} }
// Destroy and re-init the PerfectScrollbar to update its options // Destroy and re-init the PerfectScrollbar to update its options
setTimeout(() => { setTimeout(() =>
{
this._destroy(); this._destroy();
}); });
setTimeout(() => { setTimeout(() =>
{
this._init(); this._init();
}); });
} }
@@ -119,10 +123,10 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
fromEvent(window, 'resize') fromEvent(window, 'resize')
.pipe( .pipe(
takeUntil(this._unsubscribeAll), takeUntil(this._unsubscribeAll),
debounceTime(150) debounceTime(150),
) )
.subscribe(() => { .subscribe(() =>
{
// Update the PerfectScrollbar // Update the PerfectScrollbar
this.update(); this.update();
}); });
@@ -136,7 +140,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
this._destroy(); this._destroy();
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -202,14 +206,14 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
{ {
scrollbarPosition = new ScrollbarPosition( scrollbarPosition = new ScrollbarPosition(
this._ps.reach.x || 0, this._ps.reach.x || 0,
this._ps.reach.y || 0 this._ps.reach.y || 0,
); );
} }
else else
{ {
scrollbarPosition = new ScrollbarPosition( scrollbarPosition = new ScrollbarPosition(
this._elementRef.nativeElement.scrollLeft, this._elementRef.nativeElement.scrollLeft,
this._elementRef.nativeElement.scrollTop this._elementRef.nativeElement.scrollTop,
); );
} }
@@ -246,8 +250,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to X * Scroll to X
* *
* @param {number} x * @param x
* @param {number} speed * @param speed
*/ */
scrollToX(x: number, speed?: number): void scrollToX(x: number, speed?: number): void
{ {
@@ -257,8 +261,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to Y * Scroll to Y
* *
* @param {number} y * @param y
* @param {number} speed * @param speed
*/ */
scrollToY(y: number, speed?: number): void scrollToY(y: number, speed?: number): void
{ {
@@ -268,8 +272,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to top * Scroll to top
* *
* @param {number} offset * @param offset
* @param {number} speed * @param speed
*/ */
scrollToTop(offset: number = 0, speed?: number): void scrollToTop(offset: number = 0, speed?: number): void
{ {
@@ -279,8 +283,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to bottom * Scroll to bottom
* *
* @param {number} offset * @param offset
* @param {number} speed * @param speed
*/ */
scrollToBottom(offset: number = 0, speed?: number): void scrollToBottom(offset: number = 0, speed?: number): void
{ {
@@ -291,8 +295,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to left * Scroll to left
* *
* @param {number} offset * @param offset
* @param {number} speed * @param speed
*/ */
scrollToLeft(offset: number = 0, speed?: number): void scrollToLeft(offset: number = 0, speed?: number): void
{ {
@@ -302,8 +306,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to right * Scroll to right
* *
* @param {number} offset * @param offset
* @param {number} speed * @param speed
*/ */
scrollToRight(offset: number = 0, speed?: number): void scrollToRight(offset: number = 0, speed?: number): void
{ {
@@ -314,10 +318,10 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/** /**
* Scroll to element * Scroll to element
* *
* @param {string} qs * @param qs
* @param {number} offset * @param offset
* @param {boolean} ignoreVisible If true, scrollToElement won't happen if element is already inside the current viewport * @param ignoreVisible If true, scrollToElement won't happen if element is already inside the current viewport
* @param {number} speed * @param speed
*/ */
scrollToElement(qs: string, offset: number = 0, ignoreVisible: boolean = false, speed?: number): void scrollToElement(qs: string, offset: number = 0, ignoreVisible: boolean = false, speed?: number): void
{ {
@@ -387,7 +391,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
const cosParameter = (oldValue - value) / 2; const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp: number) => { const step = (newTimestamp: number): void =>
{
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp)); scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount)); newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
@@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive';
@NgModule({
declarations: [
FuseScrollbarDirective
],
exports : [
FuseScrollbarDirective
]
})
export class FuseScrollbarModule
{
}
-37
View File
@@ -1,37 +0,0 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module';
import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module';
import { FuseTailwindConfigModule } from '@fuse/services/tailwind/tailwind.module';
import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@NgModule({
imports : [
FuseMediaWatcherModule,
FuseSplashScreenModule,
FuseTailwindConfigModule,
FuseUtilsModule
],
providers: [
{
// Use the 'fill' appearance on Angular Material form fields by default
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: {
appearance: 'fill'
}
}
]
})
export class FuseModule
{
/**
* Constructor
*/
constructor(@Optional() @SkipSelf() parentModule?: FuseModule)
{
if ( parentModule )
{
throw new Error('FuseModule has already been loaded. Import this module in the AppModule only!');
}
}
}
+108
View File
@@ -0,0 +1,108 @@
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { APP_INITIALIZER, ENVIRONMENT_INITIALIZER, EnvironmentProviders, importProvidersFrom, inject, Provider } from '@angular/core';
import { MATERIAL_SANITY_CHECKS } from '@angular/material/core';
import { MatDialogModule } from '@angular/material/dialog';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FUSE_MOCK_API_DEFAULT_DELAY, mockApiInterceptor } from '@fuse/lib/mock-api';
import { FuseConfig } from '@fuse/services/config';
import { FUSE_CONFIG } from '@fuse/services/config/config.constants';
import { FuseConfirmationService } from '@fuse/services/confirmation';
import { fuseLoadingInterceptor, FuseLoadingService } from '@fuse/services/loading';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FusePlatformService } from '@fuse/services/platform';
import { FuseSplashScreenService } from '@fuse/services/splash-screen';
import { FuseUtilsService } from '@fuse/services/utils';
export type FuseProviderConfig = {
mockApi?: {
delay?: number;
services?: any[];
},
fuse?: FuseConfig
}
/**
* Fuse provider
*/
export const provideFuse = (config: FuseProviderConfig): Array<Provider | EnvironmentProviders> =>
{
// Base providers
const providers: Array<Provider | EnvironmentProviders> = [
{
// Disable 'theme' sanity check
provide : MATERIAL_SANITY_CHECKS,
useValue: {
doctype: true,
theme : false,
version: true,
},
},
{
// Use the 'fill' appearance on Angular Material form fields by default
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: {
appearance: 'fill',
},
},
{
provide : FUSE_MOCK_API_DEFAULT_DELAY,
useValue: config?.mockApi?.delay ?? 0,
},
{
provide : FUSE_CONFIG,
useValue: config?.fuse ?? {},
},
importProvidersFrom(MatDialogModule),
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FuseConfirmationService),
multi : true,
},
provideHttpClient(withInterceptors([fuseLoadingInterceptor])),
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FuseLoadingService),
multi : true,
},
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FuseMediaWatcherService),
multi : true,
},
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FusePlatformService),
multi : true,
},
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FuseSplashScreenService),
multi : true,
},
{
provide : ENVIRONMENT_INITIALIZER,
useValue: () => inject(FuseUtilsService),
multi : true,
},
];
// Mock Api services
if ( config?.mockApi?.services )
{
providers.push(
provideHttpClient(withInterceptors([mockApiInterceptor])),
{
provide : APP_INITIALIZER,
deps : [...config.mockApi.services],
useFactory: () => (): any => null,
multi : true,
},
);
}
// Return the providers
return providers;
};
+1 -1
View File
@@ -1 +1 @@
export * from './fuse.module'; export * from './fuse.provider';

Some files were not shown because too many files have changed in this diff Show More