Compare commits

..

203 Commits

Author SHA1 Message Date
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
263 changed files with 19433 additions and 9618 deletions
+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
View File
@@ -12,7 +12,6 @@
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
+1 -1
View File
@@ -1 +1 @@
14
12
+3
View File
@@ -2,6 +2,9 @@
// @ 3rd party credits
// -----------------------------------------------------------------------------------------------------
// Flags
https://github.com/Yummygum/flagpack-core
// Icons
Material - https://material.io/tools/icons
Feather - https://feathericons.com/
+5 -3
View File
@@ -1,5 +1,7 @@
# Fuse - Admin template and Starter project for Angular
This project was generated with [Angular CLI](https://github.com/angular/angular-cli)
## 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.
@@ -10,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
## 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
@@ -18,8 +20,8 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## 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
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.
+45 -48
View File
@@ -22,7 +22,7 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": [
"apexcharts",
"highlight.js",
@@ -33,7 +33,12 @@
"assets": [
"src/favicon-16x16.png",
"src/favicon-32x32.png",
"src/assets"
"src/assets",
{
"glob": "_redirects",
"input": "src",
"output": "/"
}
],
"stylePreprocessorOptions": {
"includePaths": [
@@ -52,44 +57,48 @@
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "3mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "75kb",
"maximumError": "90kb"
}
],
"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": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumError": "8mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "100kb",
"maximumError": "150kb"
}
]
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "fuse:build"
},
"configurations": {
"production": {
"browserTarget": "fuse:build:production"
},
"development": {
"browserTarget": "fuse:build:development"
}
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
@@ -104,44 +113,32 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon-16x16.png",
"src/favicon-32x32.png",
"src/assets"
],
"styles": [
"src/styles.scss"
"src/styles/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
},
"configurations": {
"production": {
"devServerTarget": "fuse:serve:production"
}
}
}
}
}
},
"defaultProject": "fuse"
"defaultProject": "fuse",
"cli": {
"defaultCollection": "@angular-eslint/schematics"
}
}
-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"
]
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ module.exports = function (config)
suppressAll: true // removes the duplicated traces
},
coverageReporter : {
dir : require('path').join(__dirname, './coverage/angular11'),
dir : require('path').join(__dirname, './coverage/fuse'),
subdir : '.',
reporters: [
{type: 'html'},
+7189 -6377
View File
File diff suppressed because it is too large Load Diff
+54 -46
View File
@@ -1,28 +1,30 @@
{
"name": "@fuse/demo",
"version": "12.1.0",
"name": "@fuse/starter",
"version": "13.6.1",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard",
"private": true,
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"lint": "ng lint"
},
"dependencies": {
"@angular/animations": "11.2.11",
"@angular/cdk": "11.2.10",
"@angular/common": "11.2.11",
"@angular/compiler": "11.2.11",
"@angular/core": "11.2.11",
"@angular/forms": "11.2.11",
"@angular/material": "11.2.10",
"@angular/material-moment-adapter": "11.2.10",
"@angular/platform-browser": "11.2.11",
"@angular/platform-browser-dynamic": "11.2.11",
"@angular/router": "11.2.11",
"@angular/animations": "12.2.3",
"@angular/cdk": "12.2.3",
"@angular/common": "12.2.3",
"@angular/compiler": "12.2.3",
"@angular/core": "12.2.3",
"@angular/forms": "12.2.3",
"@angular/material": "12.2.3",
"@angular/material-moment-adapter": "12.2.3",
"@angular/platform-browser": "12.2.3",
"@angular/platform-browser-dynamic": "12.2.3",
"@angular/router": "12.2.3",
"@fullcalendar/angular": "4.4.5-beta",
"@fullcalendar/core": "4.4.2",
"@fullcalendar/daygrid": "4.4.2",
@@ -31,53 +33,59 @@
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"apexcharts": "3.26.1",
"@ngneat/transloco": "2.22.0",
"apexcharts": "3.28.1",
"crypto-js": "3.3.0",
"highlight.js": "10.7.2",
"highlight.js": "11.2.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"ng-apexcharts": "1.5.9",
"ngx-markdown": "11.1.3",
"ngx-quill": "13.2.0",
"perfect-scrollbar": "1.5.0",
"ng-apexcharts": "1.5.12",
"ngx-markdown": "12.0.1",
"ngx-quill": "14.3.0",
"perfect-scrollbar": "1.5.2",
"quill": "1.3.7",
"rrule": "2.6.8",
"rxjs": "6.6.7",
"tslib": "2.2.0",
"tslib": "2.3.1",
"web-animations-js": "2.3.2",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "0.1102.10",
"@angular/cli": "11.2.10",
"@angular/compiler-cli": "11.2.11",
"@angular/language-service": "11.2.11",
"@tailwindcss/aspect-ratio": "0.2.0",
"@tailwindcss/line-clamp": "0.2.0",
"@tailwindcss/typography": "0.4.0",
"@angular-devkit/build-angular": "12.2.3",
"@angular-eslint/builder": "12.3.1",
"@angular-eslint/eslint-plugin": "12.3.1",
"@angular-eslint/eslint-plugin-template": "12.3.1",
"@angular-eslint/schematics": "12.3.1",
"@angular-eslint/template-parser": "12.3.1",
"@angular/cli": "12.2.3",
"@angular/compiler-cli": "12.2.3",
"@tailwindcss/aspect-ratio": "0.2.1",
"@tailwindcss/line-clamp": "0.2.1",
"@tailwindcss/typography": "0.4.1",
"@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0",
"@types/jasmine": "3.6.9",
"@types/lodash": "4.14.168",
"@types/jasmine": "3.8.2",
"@types/lodash": "4.14.172",
"@types/lodash-es": "4.17.4",
"@types/node": "12.20.10",
"autoprefixer": "10.2.5",
"chroma-js": "2.1.1",
"codelyzer": "6.0.1",
"jasmine-core": "3.6.0",
"jasmine-spec-reporter": "5.0.2",
"karma": "6.1.2",
"@types/node": "12.20.21",
"@typescript-eslint/eslint-plugin": "4.30.0",
"@typescript-eslint/parser": "4.30.0",
"autoprefixer": "10.3.3",
"chroma-js": "2.1.2",
"eslint": "7.32.0",
"eslint-plugin-import": "2.24.2",
"eslint-plugin-jsdoc": "36.0.8",
"eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.8.0",
"karma": "6.3.4",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "2.0.3",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.5.4",
"karma-jasmine-html-reporter": "1.7.0",
"lodash": "4.17.21",
"postcss": "8.2.12",
"protractor": "7.0.0",
"tailwindcss": "2.1.2",
"ts-node": "8.3.0",
"tslint": "6.1.3",
"typescript": "4.1.5"
"postcss": "8.3.6",
"tailwindcss": "2.2.9",
"typescript": "4.3.5"
}
}
+7 -7
View File
@@ -1,14 +1,14 @@
export class FuseAnimationCurves
{
static STANDARD_CURVE = 'cubic-bezier(0.4, 0.0, 0.2, 1)';
static DECELERATION_CURVE = 'cubic-bezier(0.0, 0.0, 0.2, 1)';
static ACCELERATION_CURVE = 'cubic-bezier(0.4, 0.0, 1, 1)';
static SHARP_CURVE = 'cubic-bezier(0.4, 0.0, 0.6, 1)';
static standard = 'cubic-bezier(0.4, 0.0, 0.2, 1)';
static deceleration = 'cubic-bezier(0.0, 0.0, 0.2, 1)';
static acceleration = 'cubic-bezier(0.4, 0.0, 1, 1)';
static sharp = 'cubic-bezier(0.4, 0.0, 0.6, 1)';
}
export class FuseAnimationDurations
{
static COMPLEX = '375ms';
static ENTERING = '225ms';
static EXITING = '195ms';
static complex = '375ms';
static entering = '225ms';
static exiting = '195ms';
}
+1 -1
View File
@@ -24,7 +24,7 @@ const expandCollapse = trigger('expandCollapse',
animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
+10 -10
View File
@@ -25,7 +25,7 @@ const fadeIn = trigger('fadeIn',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -58,7 +58,7 @@ const fadeInTop = trigger('fadeInTop',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -91,7 +91,7 @@ const fadeInBottom = trigger('fadeInBottom',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -124,7 +124,7 @@ const fadeInLeft = trigger('fadeInLeft',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -157,7 +157,7 @@ const fadeInRight = trigger('fadeInRight',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -188,7 +188,7 @@ const fadeOut = trigger('fadeOut',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -221,7 +221,7 @@ const fadeOutTop = trigger('fadeOutTop',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -254,7 +254,7 @@ const fadeOutBottom = trigger('fadeOutBottom',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -287,7 +287,7 @@ const fadeOutLeft = trigger('fadeOutLeft',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -320,7 +320,7 @@ const fadeOutRight = trigger('fadeOutRight',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
+1 -1
View File
@@ -1 +1 @@
export * from './public-api';
export * from '@fuse/animations/public-api';
+6 -6
View File
@@ -1,10 +1,10 @@
import { expandCollapse } from './expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from './fade';
import { shake } from './shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from './slide';
import { zoomIn, zoomOut } from './zoom';
import { expandCollapse } from '@fuse/animations/expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from '@fuse/animations/fade';
import { shake } from '@fuse/animations/shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from '@fuse/animations/slide';
import { zoomIn, zoomOut } from '@fuse/animations/zoom';
export const FuseAnimations = [
export const fuseAnimations = [
expandCollapse,
fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight,
fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight,
+8 -8
View File
@@ -25,7 +25,7 @@ const slideInTop = trigger('slideInTop',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -56,7 +56,7 @@ const slideInBottom = trigger('slideInBottom',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -87,7 +87,7 @@ const slideInLeft = trigger('slideInLeft',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -118,7 +118,7 @@ const slideInRight = trigger('slideInRight',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -149,7 +149,7 @@ const slideOutTop = trigger('slideOutTop',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -180,7 +180,7 @@ const slideOutBottom = trigger('slideOutBottom',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -211,7 +211,7 @@ const slideOutLeft = trigger('slideOutLeft',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -242,7 +242,7 @@ const slideOutRight = trigger('slideOutRight',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
+2 -2
View File
@@ -28,7 +28,7 @@ const zoomIn = trigger('zoomIn',
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.ENTERING} ${FuseAnimationCurves.DECELERATION_CURVE}`
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`
}
}
)
@@ -62,7 +62,7 @@ const zoomOut = trigger('zoomOut',
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.EXITING} ${FuseAnimationCurves.ACCELERATION_CURVE}`
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`
}
}
)
@@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Ho
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { FuseAnimations } from '@fuse/animations';
import { fuseAnimations } from '@fuse/animations';
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
import { FuseAlertService } from '@fuse/components/alert/alert.service';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@@ -13,14 +13,16 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
styleUrls : ['./alert.component.scss'],
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
animations : FuseAnimations,
animations : fuseAnimations,
exportAs : 'fuseAlert'
})
export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_dismissible: BooleanInput;
static ngAcceptInputType_dismissed: BooleanInput;
static ngAcceptInputType_showIcon: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() appearance: FuseAlertAppearance = 'soft';
@Input() dismissed: boolean = false;
@@ -115,7 +117,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
// Subscribe to the dismiss calls
this._fuseAlertService.onDismiss
.pipe(
filter((name) => this.name === name),
filter(name => this.name === name),
takeUntil(this._unsubscribeAll)
)
.subscribe(() => {
@@ -127,7 +129,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
// Subscribe to the show calls
this._fuseAlertService.onShow
.pipe(
filter((name) => this.name === name),
filter(name => this.name === name),
takeUntil(this._unsubscribeAll)
)
.subscribe(() => {
+4 -2
View File
@@ -1,6 +1,6 @@
import { Component, HostBinding, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { FuseAnimations } from '@fuse/animations';
import { fuseAnimations } from '@fuse/animations';
import { FuseCardFace } from '@fuse/components/card/card.types';
@Component({
@@ -8,13 +8,15 @@ import { FuseCardFace } from '@fuse/components/card/card.types';
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : FuseAnimations,
animations : fuseAnimations,
exportAs : 'fuseCard'
})
export class FuseCardComponent implements OnChanges
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_expanded: BooleanInput;
static ngAcceptInputType_flippable: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() expanded: boolean = false;
@Input() face: FuseCardFace = 'front';
@@ -23,14 +23,14 @@ import { Moment } from 'moment';
})
export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnDestroy
{
@Output() readonly rangeChanged: EventEmitter<{ start: string, end: string }> = new EventEmitter<{ start: string; end: string }>();
@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 } = {
activeDates: { month1: Moment | null; month2: Moment | null } = {
month1: null,
month2: null
};
@@ -41,7 +41,7 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
private _onChange: (value: any) => void;
private _onTouched: (value: any) => void;
private _programmaticChange!: boolean;
private _range: { start: Moment | null, end: Moment | null } = {
private _range: { start: Moment | null; end: Moment | null } = {
start: null,
end : null
};
@@ -61,9 +61,9 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
private _viewContainerRef: ViewContainerRef
)
{
this._onChange = () => {
this._onChange = (): void => {
};
this._onTouched = () => {
this._onTouched = (): void => {
};
this.dateFormat = 'DD/MM/YYYY';
this.timeFormat = '12';
@@ -330,7 +330,7 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
*
* @param range
*/
writeValue(range: { start: string, end: string }): void
writeValue(range: { start: string; end: string }): void
{
// Set this change as a programmatic one
this._programmaticChange = true;
@@ -361,7 +361,7 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
this._unsubscribeAll.complete();
// @ TODO: Workaround until "angular/issues/20007" resolved
this.writeValue = () => {
this.writeValue = (): void => {
};
}
@@ -481,11 +481,8 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
*/
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'));
};
// If we are selecting the end date, disable all the dates that comes before the start date
return (date: Moment): boolean => !(this.setWhichDate === 'end' && date.isBefore(this._range.start, 'day'));
}
/**
@@ -667,7 +664,7 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
private _parseTime(value: string): Moment
{
// Parse the time using the time regexp
const timeArr = value.split(this._timeRegExp).filter((part) => part !== '');
const timeArr = value.split(this._timeRegExp).filter(part => part !== '');
// Get the meridiem
const meridiem = timeArr[2] || null;
@@ -116,7 +116,7 @@ fuse-drawer {
left: 0;
right: 0;
z-index: 299;
opacity: 0;
opacity: 1;
background-color: rgba(0, 0, 0, 0.6);
/* Fixed mode */
+55 -30
View File
@@ -14,9 +14,11 @@ import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
})
export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_fixed: BooleanInput;
static ngAcceptInputType_opened: BooleanInput;
static ngAcceptInputType_transparentOverlay: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() fixed: boolean = false;
@Input() mode: FuseDrawerMode = 'side';
@@ -76,6 +78,40 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
};
}
// -----------------------------------------------------------------------------------------------------
// @ 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
// -----------------------------------------------------------------------------------------------------
@@ -175,6 +211,12 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
*/
ngOnDestroy(): void
{
// Finish the animation
if ( this._player )
{
this._player.finish();
}
// Deregister the drawer from the registry
this._fuseDrawerService.deregisterComponent(this.name);
}
@@ -302,9 +344,18 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Create the enter animation and attach it to the player
this._player = this._animationBuilder.build([
style({opacity: 0}),
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1}))
]).create(this._overlay);
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
this._player = null;
});
// Play the animation
this._player.play();
@@ -337,6 +388,10 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
this._player = null;
// If the backdrop still exists...
if ( this._overlay )
{
@@ -347,36 +402,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
});
}
/**
* 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
*
@@ -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-expand'"></mat-icon>
</ng-template>
@@ -0,0 +1,166 @@
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types';
@Component({
selector : 'fuse-fullscreen',
templateUrl : './fullscreen.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseFullscreen'
})
export class FuseFullscreenComponent implements OnInit
{
@Input() iconTpl: TemplateRef<any>;
@Input() tooltip: string;
private _fsDoc: FSDocument;
private _fsDocEl: FSDocumentElement;
private _isFullscreen: boolean = false;
/**
* Constructor
*/
constructor(@Inject(DOCUMENT) private _document: Document)
{
this._fsDoc = _document as FSDocument;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this._fsDocEl = document.documentElement as FSDocumentElement;
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle the fullscreen mode
*/
toggleFullscreen(): void
{
// Check if the fullscreen is open
this._isFullscreen = this._getBrowserFullscreenElement() !== null;
// Toggle the fullscreen
if ( this._isFullscreen )
{
this._closeFullscreen();
}
else
{
this._openFullscreen();
}
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Get browser's fullscreen element
*
* @private
*/
private _getBrowserFullscreenElement(): Element
{
if ( typeof this._fsDoc.fullscreenElement !== 'undefined' )
{
return this._fsDoc.fullscreenElement;
}
if ( typeof this._fsDoc.mozFullScreenElement !== 'undefined' )
{
return this._fsDoc.mozFullScreenElement;
}
if ( typeof this._fsDoc.msFullscreenElement !== 'undefined' )
{
return this._fsDoc.msFullscreenElement;
}
if ( typeof this._fsDoc.webkitFullscreenElement !== 'undefined' )
{
return this._fsDoc.webkitFullscreenElement;
}
throw new Error('Fullscreen mode is not supported by this browser');
}
/**
* Open the fullscreen
*
* @private
*/
private _openFullscreen(): void
{
if ( this._fsDocEl.requestFullscreen )
{
this._fsDocEl.requestFullscreen();
return;
}
// Firefox
if ( this._fsDocEl.mozRequestFullScreen )
{
this._fsDocEl.mozRequestFullScreen();
return;
}
// Chrome, Safari and Opera
if ( this._fsDocEl.webkitRequestFullscreen )
{
this._fsDocEl.webkitRequestFullscreen();
return;
}
// IE/Edge
if ( this._fsDocEl.msRequestFullscreen )
{
this._fsDocEl.msRequestFullscreen();
return;
}
}
/**
* Close the fullscreen
*
* @private
*/
private _closeFullscreen(): void
{
if ( this._fsDoc.exitFullscreen )
{
this._fsDoc.exitFullscreen();
return;
}
// Firefox
if ( this._fsDoc.mozCancelFullScreen )
{
this._fsDoc.mozCancelFullScreen();
return;
}
// Chrome, Safari and Opera
if ( this._fsDoc.webkitExitFullscreen )
{
this._fsDoc.webkitExitFullscreen();
return;
}
// IE/Edge
else if ( this._fsDoc.msExitFullscreen )
{
this._fsDoc.msExitFullscreen();
return;
}
}
}
@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseFullscreenComponent } from '@fuse/components/fullscreen/fullscreen.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
FuseFullscreenComponent
],
imports: [
MatButtonModule,
MatIconModule,
MatTooltipModule,
CommonModule
],
exports : [
FuseFullscreenComponent
]
})
export class FuseFullscreenModule
{
}
@@ -0,0 +1,16 @@
export interface FSDocument extends HTMLDocument
{
mozFullScreenElement?: Element;
mozCancelFullScreen?: () => void;
msFullscreenElement?: Element;
msExitFullscreen?: () => void;
webkitFullscreenElement?: Element;
webkitExitFullscreen?: () => void;
}
export interface FSDocumentElement extends HTMLElement
{
mozRequestFullScreen?: () => void;
msRequestFullscreen?: () => void;
webkitRequestFullscreen?: () => void;
}
+1
View File
@@ -0,0 +1 @@
export * from '@fuse/components/fullscreen/public-api';
@@ -0,0 +1,3 @@
export * from '@fuse/components/fullscreen/fullscreen.component';
export * from '@fuse/components/fullscreen/fullscreen.module';
export * from '@fuse/components/fullscreen/fullscreen.types';
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import * as hljs from 'highlight.js';
import hljs from 'highlight.js';
@Injectable({
providedIn: 'root'
@@ -60,7 +60,7 @@ export class FuseHighlightService
}
// Iterate through the lines
lines.filter((line) => line.length)
lines.filter(line => line.length)
.forEach((line, index) => {
// Always get the indentation of the first line so we can
@@ -77,6 +77,6 @@ export class FuseHighlightService
// Iterate through the lines one more time, remove the extra
// 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
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,87 @@
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',
styleUrls : ['./masonry.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations,
exportAs : 'fuseMasonry'
})
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,18 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FuseMasonryComponent } from '@fuse/components/masonry/masonry.component';
@NgModule({
declarations: [
FuseMasonryComponent
],
imports : [
CommonModule
],
exports : [
FuseMasonryComponent
]
})
export class FuseMasonryModule
{
}
@@ -0,0 +1,2 @@
export * from '@fuse/components/masonry/masonry.component';
export * from '@fuse/components/masonry/masonry.module';
@@ -5,69 +5,83 @@
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[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 -->
<a
class="fuse-horizontal-navigation-item"
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
<a
class="fuse-horizontal-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[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 -->
<a
class="fuse-horizontal-navigation-item"
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link"
(click)="item.function(item)"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
<a
class="fuse-horizontal-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && !item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled -->
<div
class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled"
*ngIf="item.disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.disabled">
<div class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
</div>
@@ -75,11 +89,12 @@
<ng-template #itemTemplate>
<!-- Icon -->
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -88,24 +103,24 @@
{{item.title}}
</span>
</div>
<div
class="fuse-horizontal-navigation-item-subtitle text-hint"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-horizontal-navigation-item-subtitle text-hint">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-horizontal-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-horizontal-navigation-item-badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</ng-template>
@@ -1,14 +1,15 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-horizontal-navigation-basic-item',
templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
@@ -16,6 +17,7 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -24,9 +26,15 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/
constructor(
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,9 +46,20 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/
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
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll)
@@ -1,59 +1,63 @@
<div
*ngIf="!child"
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
<ng-container *ngIf="!child">
<div
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
'fuse-horizontal-navigation-menu-active-forced': item.active}"
[matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div>
[matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div>
</ng-container>
<mat-menu
class="fuse-horizontal-navigation-menu-panel"
[overlapTrigger]="false"
#matMenu="matMenu">
<ng-container *ngFor="let item of item.children">
<ng-container *ngFor="let item of item.children; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'basic'"
[disabled]="item.disabled"
mat-menu-item>
<fuse-horizontal-navigation-basic-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</div>
<ng-container *ngIf="item.type === 'basic'">
<div
class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled"
mat-menu-item>
<fuse-horizontal-navigation-basic-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</div>
</ng-container>
<!-- Branch: aside, collapsable, group -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item
[child]="true"
[item]="item"
[name]="name"
#branch></fuse-horizontal-navigation-branch-item>
</div>
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
<div
class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item
[child]="true"
[item]="item"
[name]="name"
#branch></fuse-horizontal-navigation-branch-item>
</div>
</ng-container>
<!-- Divider -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'divider'"
mat-menu-item>
<fuse-horizontal-navigation-divider-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item>
</div>
<ng-container *ngIf="item.type === 'divider'">
<div
class="fuse-horizontal-navigation-menu-item"
mat-menu-item>
<fuse-horizontal-navigation-divider-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item>
</div>
</ng-container>
</ng-container>
@@ -74,14 +78,16 @@
<div
class="fuse-horizontal-navigation-item"
[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 -->
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -90,25 +96,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-horizontal-navigation-item-subtitle text-hint"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-horizontal-navigation-item-subtitle text-hint">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-horizontal-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-horizontal-navigation-item-badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
</div>
@@ -10,12 +10,13 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-branch-item',
templateUrl : './branch.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_child: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() child: boolean = false;
@Input() item: FuseNavigationItem;
@@ -79,4 +80,15 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-divider-item',
templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-spacer-item',
templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
@@ -1,30 +1,33 @@
<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 -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-horizontal-navigation-basic-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-horizontal-navigation-basic-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</ng-container>
<!-- Branch: aside, collapsable, group -->
<fuse-horizontal-navigation-branch-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item>
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
<fuse-horizontal-navigation-branch-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item>
</ng-container>
<!-- Spacer -->
<fuse-horizontal-navigation-spacer-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-horizontal-navigation-spacer-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -1,6 +1,6 @@
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 { FuseUtilsService } from '@fuse/services/utils/utils.service';
@@ -9,7 +9,7 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
selector : 'fuse-horizontal-navigation',
templateUrl : './horizontal.component.html',
styleUrls : ['./horizontal.component.scss'],
animations : FuseAnimations,
animations : fuseAnimations,
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseHorizontalNavigation'
@@ -46,7 +46,7 @@ export class FuseNavigationService
*
* @param name
*/
getComponent(name: string): any
getComponent<T>(name: string): T
{
return this._componentRegistry.get(name);
}
@@ -67,7 +67,6 @@ export class FuseNavigationService
* Get navigation from storage by key
*
* @param key
* @returns {any}
*/
getNavigation(key: string): FuseNavigationItem[]
{
@@ -97,7 +96,6 @@ export class FuseNavigationService
*
* @param navigation
* @param flatNavigation
* @returns {FuseNavigationItem[]}
*/
getFlatNavigation(navigation: FuseNavigationItem[], flatNavigation: FuseNavigationItem[] = []): FuseNavigationItem[]
{
@@ -1,3 +1,5 @@
import { IsActiveMatchOptions } from '@angular/router';
export interface FuseNavigationItem
{
id?: string;
@@ -13,9 +15,17 @@ export interface FuseNavigationItem
hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean;
disabled?: boolean;
tooltip?: string;
link?: string;
externalLink?: boolean;
target?:
| '_blank'
| '_self'
| '_parent'
| '_top'
| string;
exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void;
classes?: {
title?: string;
@@ -7,14 +7,16 @@
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active': active,
'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 -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -23,25 +25,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
@@ -57,35 +59,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -10,13 +10,14 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-aside-item',
templateUrl : './aside.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput;
static ngAcceptInputType_skipChildren: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() activeItemId: string;
@Input() autoCollapse: boolean;
@@ -101,6 +102,21 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
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
// -----------------------------------------------------------------------------------------------------
@@ -168,19 +184,4 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
// Mark for check
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,84 @@
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[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 -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function -->
<div
class="fuse-vertical-navigation-item"
*ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && item.function && !item.disabled">
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[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 -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function -->
<div
class="fuse-vertical-navigation-item"
*ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && !item.function && !item.disabled">
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled -->
<div
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
*ngIf="item.disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.disabled">
<div
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
</div>
@@ -74,11 +90,12 @@
<ng-template #itemTemplate>
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -87,24 +104,24 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</ng-template>
@@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
@@ -9,7 +10,6 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-vertical-navigation-basic-item',
templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
@@ -17,6 +17,7 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -29,6 +30,11 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
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,9 +46,20 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
*/
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
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll)
@@ -6,14 +6,16 @@
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}"
[matTooltip]="item.tooltip || ''"
(click)="toggleCollapsable()">
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -22,25 +24,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
<!-- Arrow -->
<mat-icon
@@ -62,35 +64,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -3,7 +3,7 @@ import { NavigationEnd, Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { FuseAnimations } from '@fuse/animations';
import { fuseAnimations } from '@fuse/animations';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -11,13 +11,14 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-collapsable-item',
templateUrl : './collapsable.component.html',
styles : [],
animations : FuseAnimations,
animations : fuseAnimations,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() autoCollapse: boolean;
@Input() item: FuseNavigationItem;
@@ -179,84 +180,6 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
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
// -----------------------------------------------------------------------------------------------------
@@ -343,4 +266,81 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
{
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;
}
}
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-divider-item',
templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
@@ -7,11 +7,12 @@
<div class="fuse-vertical-navigation-item">
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -20,25 +21,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
@@ -50,35 +51,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -9,12 +9,13 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-group-item',
templateUrl : './group.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_autoCollapse: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() autoCollapse: boolean;
@Input() item: FuseNavigationItem;
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-spacer-item',
templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
@@ -335,6 +335,7 @@ fuse-vertical-navigation {
}
> .fuse-vertical-navigation-item-children {
margin-top: 6px;
> *:last-child {
padding-bottom: 6px;
@@ -24,46 +24,52 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside -->
<fuse-vertical-navigation-aside-item
*ngIf="item.type === 'aside'"
[item]="item"
[name]="name"
[activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse"
[skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
<ng-container *ngIf="item.type === 'aside'">
<fuse-vertical-navigation-aside-item
[item]="item"
[name]="name"
[activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse"
[skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
</ng-container>
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -84,31 +90,33 @@
</div>
<!-- Aside -->
<div
class="fuse-vertical-navigation-aside-wrapper"
*ngIf="activeAsideItemId"
fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'">
<ng-container *ngIf="activeAsideItemId">
<div
class="fuse-vertical-navigation-aside-wrapper"
fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'">
<!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside -->
<fuse-vertical-navigation-aside-item
*ngIf="item.type === 'aside' && item.id === activeAsideItemId"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
<!-- Aside -->
<ng-container *ngIf="item.type === 'aside' && item.id === activeAsideItemId">
<fuse-vertical-navigation-aside-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</div>
</div>
</ng-container>
@@ -4,7 +4,7 @@ import { NavigationEnd, Router } from '@angular/router';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { merge, ReplaySubject, Subject, Subscription } from 'rxjs';
import { delay, filter, takeUntil } from 'rxjs/operators';
import { FuseAnimations } from '@fuse/animations';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive';
@@ -15,16 +15,18 @@ import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
selector : 'fuse-vertical-navigation',
templateUrl : './vertical.component.html',
styleUrls : ['./vertical.component.scss'],
animations : FuseAnimations,
animations : fuseAnimations,
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseVerticalNavigation'
})
export class FuseVerticalNavigationComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_inner: BooleanInput;
static ngAcceptInputType_opened: BooleanInput;
static ngAcceptInputType_transparentOverlay: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() appearance: FuseVerticalNavigationAppearance = 'default';
@Input() autoCollapse: boolean = true;
@@ -71,10 +73,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
private _fuseUtilsService: FuseUtilsService
)
{
this._handleAsideOverlayClick = () => {
this._handleAsideOverlayClick = (): void => {
this.closeAside();
};
this._handleOverlayClick = () => {
this._handleOverlayClick = (): void => {
this.close();
};
}
@@ -151,6 +153,40 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
});
}
// -----------------------------------------------------------------------------------------------------
// @ 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
// -----------------------------------------------------------------------------------------------------
@@ -338,6 +374,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/
ngOnDestroy(): void
{
// Forcefully close the navigation and aside in case they are opened
this.close();
this.closeAside();
// Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name);
@@ -672,36 +712,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
*
@@ -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';
@@ -17,7 +17,9 @@ import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar
})
export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_fuseScrollbar: BooleanInput;
/* eslint-enable @typescript-eslint/naming-convention */
@Input() fuseScrollbar: boolean = true;
@Input() fuseScrollbarOptions: PerfectScrollbar.Options;
@@ -246,8 +248,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to X
*
* @param {number} x
* @param {number} speed
* @param x
* @param speed
*/
scrollToX(x: number, speed?: number): void
{
@@ -257,8 +259,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to Y
*
* @param {number} y
* @param {number} speed
* @param y
* @param speed
*/
scrollToY(y: number, speed?: number): void
{
@@ -268,8 +270,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to top
*
* @param {number} offset
* @param {number} speed
* @param offset
* @param speed
*/
scrollToTop(offset: number = 0, speed?: number): void
{
@@ -279,8 +281,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to bottom
*
* @param {number} offset
* @param {number} speed
* @param offset
* @param speed
*/
scrollToBottom(offset: number = 0, speed?: number): void
{
@@ -291,8 +293,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to left
*
* @param {number} offset
* @param {number} speed
* @param offset
* @param speed
*/
scrollToLeft(offset: number = 0, speed?: number): void
{
@@ -302,8 +304,8 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to right
*
* @param {number} offset
* @param {number} speed
* @param offset
* @param speed
*/
scrollToRight(offset: number = 0, speed?: number): void
{
@@ -314,10 +316,10 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
/**
* Scroll to element
*
* @param {string} qs
* @param {number} offset
* @param {boolean} ignoreVisible If true, scrollToElement won't happen if element is already inside the current viewport
* @param {number} speed
* @param qs
* @param offset
* @param ignoreVisible If true, scrollToElement won't happen if element is already inside the current viewport
* @param speed
*/
scrollToElement(qs: string, offset: number = 0, ignoreVisible: boolean = false, speed?: number): void
{
@@ -387,7 +389,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp: number) => {
const step = (newTimestamp: number): void => {
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
+12
View File
@@ -1,5 +1,7 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { MATERIAL_SANITY_CHECKS } from '@angular/material/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseConfirmationModule } from '@fuse/services/confirmation';
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';
@@ -7,12 +9,22 @@ import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@NgModule({
imports : [
FuseConfirmationModule,
FuseMediaWatcherModule,
FuseSplashScreenModule,
FuseTailwindConfigModule,
FuseUtilsModule
],
providers: [
{
// 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,
@@ -51,7 +51,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
delay(handler.delay ?? this._defaultDelay ?? 0),
switchMap((response) => {
// If there is no response mock-api,
// If there is no response data,
// throw an error response
if ( !response )
{
@@ -64,7 +64,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
return throwError(response);
}
// Parse the response mock-api
// Parse the response data
const data = {
status: response[0],
body : response[1]
+1 -1
View File
@@ -29,7 +29,7 @@ export class FuseMockApiModule
{
provide : APP_INITIALIZER,
deps : [...mockApiServices],
useFactory: () => () => null,
useFactory: () => (): any => null,
multi : true
},
{
+13 -13
View File
@@ -9,11 +9,11 @@ import { FuseMockApiMethods } from '@fuse/lib/mock-api/mock-api.types';
export class FuseMockApiService
{
private _handlers: { [key: string]: Map<string, FuseMockApiHandler> } = {
DELETE: new Map<string, FuseMockApiHandler>(),
GET : new Map<string, FuseMockApiHandler>(),
PATCH : new Map<string, FuseMockApiHandler>(),
POST : new Map<string, FuseMockApiHandler>(),
PUT : new Map<string, FuseMockApiHandler>()
'delete': new Map<string, FuseMockApiHandler>(),
'get' : new Map<string, FuseMockApiHandler>(),
'patch' : new Map<string, FuseMockApiHandler>(),
'post' : new Map<string, FuseMockApiHandler>(),
'put' : new Map<string, FuseMockApiHandler>()
};
/**
@@ -34,10 +34,10 @@ export class FuseMockApiService
* @param method
* @param url
*/
findHandler(method: string, url: string): { handler: FuseMockApiHandler | undefined, urlParams: { [key: string]: string } }
findHandler(method: string, url: string): { handler: FuseMockApiHandler | undefined; urlParams: { [key: string]: string } }
{
// Prepare the return object
const matchingHandler: { handler: FuseMockApiHandler | undefined, urlParams: { [key: string]: string } } = {
const matchingHandler: { handler: FuseMockApiHandler | undefined; urlParams: { [key: string]: string } } = {
handler : undefined,
urlParams: {}
};
@@ -46,7 +46,7 @@ export class FuseMockApiService
const urlParts = url.split('/');
// Get all related request handlers
const handlers = this._handlers[method.toUpperCase()];
const handlers = this._handlers[method.toLowerCase()];
// Iterate through the handlers
handlers.forEach((handler, handlerUrl) => {
@@ -93,7 +93,7 @@ export class FuseMockApiService
*/
onDelete(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('DELETE', url, delay);
return this._registerHandler('delete', url, delay);
}
/**
@@ -104,7 +104,7 @@ export class FuseMockApiService
*/
onGet(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('GET', url, delay);
return this._registerHandler('get', url, delay);
}
/**
@@ -115,7 +115,7 @@ export class FuseMockApiService
*/
onPatch(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('PATCH', url, delay);
return this._registerHandler('patch', url, delay);
}
/**
@@ -126,7 +126,7 @@ export class FuseMockApiService
*/
onPost(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('POST', url, delay);
return this._registerHandler('post', url, delay);
}
/**
@@ -137,7 +137,7 @@ export class FuseMockApiService
*/
onPut(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('PUT', url, delay);
return this._registerHandler('put', url, delay);
}
// -----------------------------------------------------------------------------------------------------
+5 -5
View File
@@ -6,8 +6,8 @@ export type FuseMockApiReplyCallback =
| undefined;
export type FuseMockApiMethods =
| 'GET'
| 'POST'
| 'PUT'
| 'PATCH'
| 'DELETE';
| 'get'
| 'post'
| 'put'
| 'patch'
| 'delete';
+2 -2
View File
@@ -16,7 +16,7 @@ export class FuseMockApiUtils
*/
static guid(): string
{
/* tslint:disable */
/* eslint-disable */
let d = new Date().getTime();
@@ -32,6 +32,6 @@ export class FuseMockApiUtils
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
/* tslint:enable */
/* eslint-enable */
}
}
@@ -28,9 +28,7 @@ export class FuseFindByKeyPipe implements PipeTransform
// If the given value is an array of strings...
if ( Array.isArray(value) )
{
return value.map((item) => {
return source.find((sourceItem) => sourceItem[key] === item);
});
return value.map(item => source.find(sourceItem => sourceItem[key] === item));
}
// If the value is a string...
@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { FuseConfirmationService } from '@fuse/services/confirmation/confirmation.service';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
FuseConfirmationDialogComponent
],
imports: [
MatButtonModule,
MatDialogModule,
MatIconModule,
CommonModule
],
providers : [
FuseConfirmationService
]
})
export class FuseConfirmationModule
{
/**
* Constructor
*/
constructor(private _fuseConfirmationService: FuseConfirmationService)
{
}
}
@@ -0,0 +1,58 @@
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { merge } from 'lodash-es';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Injectable()
export class FuseConfirmationService
{
private _defaultConfig: FuseConfirmationConfig = {
title : 'Confirm action',
message : 'Are you sure you want to confirm this action?',
icon : {
show : true,
name : 'heroicons_outline:exclamation',
color: 'warn'
},
actions : {
confirm: {
show : true,
label: 'Confirm',
color: 'warn'
},
cancel : {
show : true,
label: 'Cancel'
}
},
dismissible: false
};
/**
* Constructor
*/
constructor(
private _matDialog: MatDialog
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
open(config: FuseConfirmationConfig = {}): MatDialogRef<FuseConfirmationDialogComponent>
{
// Merge the user config with the default config
const userConfig = merge({}, this._defaultConfig, config);
// Open the dialog
return this._matDialog.open(FuseConfirmationDialogComponent, {
autoFocus : false,
disableClose: !userConfig.dismissible,
data : userConfig,
panelClass : 'fuse-confirmation-dialog-panel'
});
}
}
@@ -0,0 +1,22 @@
export interface FuseConfirmationConfig
{
title?: string;
message?: string;
icon?: {
show?: boolean;
name?: string;
color?: 'primary' | 'accent' | 'warn' | 'basic' | 'info' | 'success' | 'warning' | 'error';
};
actions?: {
confirm?: {
show?: boolean;
label?: string;
color?: 'primary' | 'accent' | 'warn';
};
cancel?: {
show?: boolean;
label?: string;
};
};
dismissible?: boolean;
}
@@ -0,0 +1,85 @@
<div class="relative flex flex-col w-full h-full">
<!-- Dismiss button -->
<ng-container *ngIf="data.dismissible">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button
mat-icon-button
[matDialogClose]="undefined">
<mat-icon
class="text-secondary"
[svgIcon]="'heroicons_outline:x'"></mat-icon>
</button>
</div>
</ng-container>
<!-- Content -->
<div class="flex flex-col sm:flex-row flex-auto items-center sm:items-start p-8 pb-6 sm:pb-8">
<!-- Icon -->
<ng-container *ngIf="data.icon.show">
<div
class="flex flex-0 items-center justify-center w-10 h-10 sm:mr-4 rounded-full"
[ngClass]="{'text-primary-600 bg-primary-100 dark:text-primary-50 dark:bg-primary-600': data.icon.color === 'primary',
'text-accent-600 bg-accent-100 dark:text-accent-50 dark:bg-accent-600': data.icon.color === 'accent',
'text-warn-600 bg-warn-100 dark:text-warn-50 dark:bg-warn-600': data.icon.color === 'warn',
'text-gray-600 bg-gray-100 dark:text-gray-50 dark:bg-gray-600': data.icon.color === 'basic',
'text-blue-600 bg-blue-100 dark:text-blue-50 dark:bg-blue-600': data.icon.color === 'info',
'text-green-500 bg-green-100 dark:text-green-50 dark:bg-green-500': data.icon.color === 'success',
'text-amber-500 bg-amber-100 dark:text-amber-50 dark:bg-amber-500': data.icon.color === 'warning',
'text-red-600 bg-red-100 dark:text-red-50 dark:bg-red-600': data.icon.color === 'error'
}">
<mat-icon
class="text-current"
[svgIcon]="data.icon.name"></mat-icon>
</div>
</ng-container>
<ng-container *ngIf="data.title || data.message">
<div class="flex flex-col items-center sm:items-start mt-4 sm:mt-0 sm:pr-8 space-y-1 text-center sm:text-left">
<!-- Title -->
<ng-container *ngIf="data.title">
<div
class="text-xl leading-6 font-medium"
[innerHTML]="data.title"></div>
</ng-container>
<!-- Message -->
<ng-container *ngIf="data.message">
<div
class="text-secondary"
[innerHTML]="data.message"></div>
</ng-container>
</div>
</ng-container>
</div>
<!-- Actions -->
<ng-container *ngIf="data.actions.confirm.show || data.actions.cancel.show">
<div class="flex items-center justify-center sm:justify-end px-6 py-4 space-x-3 bg-gray-50 dark:bg-black dark:bg-opacity-10">
<!-- Cancel -->
<ng-container *ngIf="data.actions.cancel.show">
<button
mat-stroked-button
[matDialogClose]="'cancelled'">
{{data.actions.cancel.label}}
</button>
</ng-container>
<!-- Confirm -->
<ng-container *ngIf="data.actions.confirm.show">
<button
mat-flat-button
[color]="data.actions.confirm.color"
[matDialogClose]="'confirmed'">
{{data.actions.confirm.label}}
</button>
</ng-container>
</div>
</ng-container>
</div>
@@ -0,0 +1,52 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Component({
selector : 'fuse-confirmation-dialog',
templateUrl : './dialog.component.html',
styles : [
/* language=SCSS */
`
.fuse-confirmation-dialog-panel {
@screen md {
@apply w-128;
}
.mat-dialog-container {
padding: 0 !important;
}
}
`
],
encapsulation: ViewEncapsulation.None
})
export class FuseConfirmationDialogComponent implements OnInit
{
/**
* Constructor
*/
constructor(
@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig,
public matDialogRef: MatDialogRef<FuseConfirmationDialogComponent>
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
}
+1
View File
@@ -0,0 +1 @@
export * from '@fuse/services/confirmation/public-api';
@@ -0,0 +1,3 @@
export * from '@fuse/services/confirmation/confirmation.module';
export * from '@fuse/services/confirmation/confirmation.service';
export * from '@fuse/services/confirmation/confirmation.types';
@@ -7,7 +7,7 @@ import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
@Injectable()
export class FuseMediaWatcherService
{
private _onMediaChange: ReplaySubject<{ matchingAliases: string[], matchingQueries: any }> = new ReplaySubject<{ matchingAliases: string[], matchingQueries: any }>(1);
private _onMediaChange: ReplaySubject<{ matchingAliases: string[]; matchingQueries: any }> = new ReplaySubject<{ matchingAliases: string[]; matchingQueries: any }>(1);
/**
* Constructor
@@ -18,7 +18,7 @@ export class FuseMediaWatcherService
)
{
this._fuseTailwindConfigService.tailwindConfig$.pipe(
switchMap((config) => this._breakpointObserver.observe(Object.values(config.breakpoints)).pipe(
switchMap(config => this._breakpointObserver.observe(Object.values(config.breakpoints)).pipe(
map((state) => {
// Prepare the observable values and set their defaults
@@ -57,7 +57,7 @@ export class FuseMediaWatcherService
/**
* Getter for _onMediaChange
*/
get onMediaChange$(): Observable<{ matchingAliases: string[], matchingQueries: any }>
get onMediaChange$(): Observable<{ matchingAliases: string[]; matchingQueries: any }>
{
return this._onMediaChange.asObservable();
}
+1 -1
View File
@@ -1 +1 @@
export * from '@fuse/services/media-watcher/public-api';
export * from '@fuse/services/tailwind/public-api';
+2 -2
View File
@@ -1,2 +1,2 @@
export * from '@fuse/services/media-watcher/media-watcher.module';
export * from '@fuse/services/media-watcher/media-watcher.service';
export * from '@fuse/services/tailwind/tailwind.module';
export * from '@fuse/services/tailwind/tailwind.service';
+1 -1
View File
@@ -1 +1 @@
export * from '@fuse/services/config/public-api';
export * from '@fuse/services/utils/public-api';
+31
View File
@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
@Injectable({
providedIn: 'root'
@@ -12,6 +13,36 @@ export class FuseUtilsService
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = true".
*/
get exactMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'exact',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'exact'
};
}
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = false".
*/
get subsetMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'subset',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'subset'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
@@ -36,7 +36,6 @@
.mat-tab-body-content {
.fuse-highlight {
margin: -24px;
pre {
margin: 0;
+95 -114
View File
@@ -136,11 +136,8 @@
.mat-flat-button,
.mat-raised-button,
.mat-stroked-button {
.fuse-mat-rounded & {
padding: 0 20px;
border-radius: 9999px;
}
padding: 0 20px !important;
border-radius: 9999px !important;
}
/* Target all buttons */
@@ -178,11 +175,7 @@
/* Add hover and focus style on all buttons */
.mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'};
}
/* On palette colored buttons, use a darker color */
@@ -253,11 +246,7 @@
/* Add hover and focus styles */
.mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'};
}
/* On primary colored buttons, use the primary color as focus overlay */
@@ -330,19 +319,11 @@
/* Border color */
&:not(.mat-button-disabled) {
@apply border-gray-300 #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
@apply border-gray-300 dark:border-gray-500 #{'!important'};
}
&.mat-button-disabled {
@apply border-gray-200 #{'!important'};
.dark & {
@apply border-gray-600 #{'!important'};
}
@apply border-gray-200 dark:border-gray-600 #{'!important'};
}
}
@@ -350,6 +331,8 @@
/* @ Button Toggle
/* ----------------------------------------------------------------------------------------------------- */
.mat-button-toggle-group {
border: none !important;
@apply space-x-1;
&.mat-button-toggle-group-appearance-standard {
@@ -357,36 +340,27 @@
background-clip: padding-box;
}
}
}
/* Rounded design */
.fuse-mat-rounded {
.mat-button-toggle-group {
.mat-button-toggle {
border-radius: 9999px;
overflow: hidden;
border: none !important;
@apply space-x-1;
font-weight: 500;
.mat-button-toggle {
border-radius: 9999px;
overflow: hidden;
border: none !important;
font-weight: 500;
&.mat-button-toggle-checked {
.mat-button-toggle-label-content {
@apply text-default #{'!important'};
}
}
&.mat-button-toggle-checked {
.mat-button-toggle-label-content {
padding: 0 20px;
@apply text-secondary;
@apply text-default #{'!important'};
}
}
.mat-ripple {
border-radius: 9999px;
}
.mat-button-toggle-label-content {
padding: 0 20px;
@apply text-secondary;
}
.mat-ripple {
border-radius: 9999px;
}
}
}
@@ -426,6 +400,13 @@
font-weight: 500 !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Dialog
/* ----------------------------------------------------------------------------------------------------- */
.mat-dialog-container {
border-radius: 16px !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Drawer
/* ----------------------------------------------------------------------------------------------------- */
@@ -542,13 +523,7 @@
border-radius: 6px;
padding: 0 16px;
border-width: 1px;
background-color: white;
@apply border-gray-300 shadow-sm #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
@apply border-gray-500 #{'!important'};
}
@apply shadow-sm bg-white border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500 #{'!important'};
.mat-form-field-prefix {
@@ -633,12 +608,28 @@
@apply icon-size-6;
}
/* Make mat-select usable as */
/* prefix and suffix */
/* Make mat-select usable as prefix and suffix */
.mat-select {
display: flex;
align-items: center;
&:focus {
.mat-select-trigger {
.mat-select-value {
@apply text-primary #{'!important'};
}
.mat-select-arrow-wrapper {
.mat-select-arrow {
border-top-color: var(--fuse-primary) !important;
}
}
}
}
.mat-select-trigger {
display: flex;
align-items: center;
@@ -663,6 +654,7 @@
.mat-select-arrow {
min-height: 0;
@apply text-gray-500 dark:text-gray-400 #{'!important'};
}
}
}
@@ -688,8 +680,8 @@
align-self: stretch;
min-height: 36px;
height: auto;
margin: 10px 0;
padding: 4px 6px 4px 0 !important;
margin: 14px 0;
padding: 0 6px 0 0;
transform: none;
}
@@ -1032,11 +1024,7 @@
.mat-form-field-prefix,
.mat-form-field-suffix {
@apply border-gray-300 bg-default #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
@apply bg-default border-gray-300 dark:border-gray-500 #{'!important'};
}
}
}
@@ -1331,62 +1319,55 @@
opacity: 0 !important;
}
}
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
}
.mat-tab-label {
opacity: 1 !important;
}
/* Rounded design */
.fuse-mat-rounded {
.mat-tab-group {
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
}
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Textarea
/* ----------------------------------------------------------------------------------------------------- */
+6 -9
View File
@@ -4,11 +4,12 @@
.ql-toolbar {
border-radius: 6px 6px 0 0;
padding: 0 !important;
@apply bg-gray-100 border-gray-300;
@apply bg-gray-100;
@apply border-gray-300 border-opacity-100 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05);
@apply border-gray-500;
@apply border-gray-500 #{'!important'};
}
.ql-formats {
@@ -81,26 +82,22 @@
.ql-container {
overflow: hidden;
border-radius: 0 0 6px 6px;
@apply border-gray-300 shadow-sm;
@apply border-gray-300 border-opacity-100 shadow-sm #{'!important'};
.dark & {
@apply border-gray-500;
@apply border-gray-500 #{'!important'};
}
.ql-editor {
min-height: 160px;
max-height: 160px;
height: 160px;
@apply bg-gray-50;
@apply bg-card;
.dark & {
background-color: rgba(0, 0, 0, 0.05);
}
&:focus {
@apply bg-card;
}
&.ql-blank::before {
@apply text-hint;
}
+96 -119
View File
@@ -1,99 +1,24 @@
@use '~@angular/material' as mat;
@use "sass:map";
@import '~@angular/material/theming';
/** Include the core Angular Material styles */
@include mat-core();
/* Include the core Angular Material styles */
@include mat.core();
/** Configure the Angular Material typography */
@include angular-material-typography(
mat-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat-typography-level(1.25rem, 2rem, 600),
$body-2: mat-typography-level(0.875rem, 1.5rem, 600),
$button: mat-typography-level(0.875rem, 0.875rem, 500),
$input: mat-typography-level(0.875rem, 1.2857142857, 400) // line-height: 20px
)
);
/* Create a base theme without color.
This will globally set the density and typography for all future color themes. */
@include mat.all-component-themes((
color: null,
density: -2,
typography: mat.define-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat.define-typography-level(1.25rem, 2rem, 600),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
)
));
/** Configure the Angular Material density **/
@include angular-material-density(-2);
/** Prepare the Background and Foreground maps */
$background-light: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* blueGray.100 */
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* blueGray.500 */
selected-button: #E2E8F0, /* blueGray.200 */
selected-disabled-button: #E2E8F0, /* blueGray.200 */
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
unselected-chip: #E2E8F0, /* blueGray.200 */
disabled-list-option: #CBD5E1, /* blueGray.300 */
tooltip: #1E293B /* blueGray.800 */
);
$background-dark: (
status-bar: #0F172A, /* blueGray.900 */
app-bar: #0F172A, /* blueGray.900 */
background: #0F172A, /* blueGray.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* blueGray.800 */
dialog: #1E293B, /* blueGray.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
raised-button: #0F172A, /* blueGray.900 */
focused-button: #E2E8F0, /* blueGray.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* blueGray.800 */
disabled-button-toggle: #0F172A, /* blueGray.900 */
unselected-chip: #475569, /* blueGray.600 */
disabled-list-option: #E2E8F0, /* blueGray.200 */
tooltip: #64748B /* blueGray.500 */
);
$foreground-light: (
base: #000000,
divider: #E2E8F0, /* blueGray.200 */
dividers: #E2E8F0, /* blueGray.200 */
disabled: #94A3B8, /* blueGray.400 */
disabled-button: #94A3B8, /* blueGray.400 */
disabled-text: #94A3B8, /* blueGray.400 */
elevation: #000000,
hint-text: #94A3B8, /* blueGray.400 */
secondary-text: #64748B, /* blueGray.500 */
icon: #64748B, /* blueGray.500 */
icons: #64748B, /* blueGray.500 */
mat-icon: #64748B, /* blueGray.500 */
text: #1E293B, /* blueGray.800 */
slider-min: #1E293B, /* blueGray.800 */
slider-off: #CBD5E1, /* blueGray.300 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
$foreground-dark: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
disabled: #475569, /* blueGray.600 */
disabled-button: #1E293B, /* blueGray.800 */
disabled-text: #475569, /* blueGray.600 */
elevation: #000000,
hint-text: #64748B, /* blueGray.500 */
secondary-text: #94A3B8, /* blueGray.400 */
icon: #F1F5F9, /* blueGray.100 */
icons: #F1F5F9, /* blueGray.100 */
mat-icon: #94A3B8, /* blueGray.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* blueGray.500 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
/** Generate Primary, Accent and Warn palettes */
/* Generate Primary, Accent and Warn palettes */
$palettes: ();
@each $name in (primary, accent, warn) {
$palettes: map.merge($palettes, (#{$name}: (
@@ -129,13 +54,13 @@ $palettes: ();
)));
}
/** Generate Angular Material themes. Since we are using CSS Custom Properties,
/* Generate Angular Material themes. Since we are using CSS Custom Properties,
we don't have to generate a separate Angular Material theme for each color
set. We can just create one light and one dark theme and then switch the
CSS Custom Properties to dynamically switch the colors. */
body.light,
body .light {
$base-light-theme: mat-light-theme((
$base-light-theme: mat.define-light-theme((
color: ($palettes)
));
@@ -145,25 +70,51 @@ body .light {
accent: map.get(map.get($base-light-theme, color), accent),
warn: map.get(map.get($base-light-theme, color), warn),
is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: $foreground-light,
background: $background-light
),
typography: null,
density: null,
primary: map.get(map.get($base-light-theme, color), primary),
accent: map.get(map.get($base-light-theme, color), accent),
warn: map.get(map.get($base-light-theme, color), warn),
is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: $foreground-light,
background: $background-light
foreground: (
base: #000000,
divider: #E2E8F0, /* blueGray.200 */
dividers: #E2E8F0, /* blueGray.200 */
disabled: #94A3B8, /* blueGray.400 */
disabled-button: #94A3B8, /* blueGray.400 */
disabled-text: #94A3B8, /* blueGray.400 */
elevation: #000000,
hint-text: #94A3B8, /* blueGray.400 */
secondary-text: #64748B, /* blueGray.500 */
icon: #64748B, /* blueGray.500 */
icons: #64748B, /* blueGray.500 */
mat-icon: #64748B, /* blueGray.500 */
text: #1E293B, /* blueGray.800 */
slider-min: #1E293B, /* blueGray.800 */
slider-off: #CBD5E1, /* blueGray.300 */
slider-off-active: #94A3B8 /* blueGray.400 */
),
background: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* blueGray.100 */
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* blueGray.500 */
selected-button: #E2E8F0, /* blueGray.200 */
selected-disabled-button: #E2E8F0, /* blueGray.200 */
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
unselected-chip: #E2E8F0, /* blueGray.200 */
disabled-list-option: #CBD5E1, /* blueGray.300 */
tooltip: #1E293B /* blueGray.800 */
)
)
);
@include angular-material-theme($light-theme);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($light-theme);
}
body.dark,
body .dark {
$base-dark-theme: mat-dark-theme((
$base-dark-theme: mat.define-dark-theme((
color: ($palettes)
));
@@ -173,18 +124,44 @@ body .dark {
accent: map.get(map.get($base-dark-theme, color), accent),
warn: map.get(map.get($base-dark-theme, color), warn),
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: $foreground-dark,
background: $background-dark
),
typography: null,
density: null,
primary: map.get(map.get($base-dark-theme, color), primary),
accent: map.get(map.get($base-dark-theme, color), accent),
warn: map.get(map.get($base-dark-theme, color), warn),
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: $foreground-dark,
background: $background-dark
foreground: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
disabled: #475569, /* blueGray.600 */
disabled-button: #1E293B, /* blueGray.800 */
disabled-text: #475569, /* blueGray.600 */
elevation: #000000,
hint-text: #64748B, /* blueGray.500 */
secondary-text: #94A3B8, /* blueGray.400 */
icon: #F1F5F9, /* blueGray.100 */
icons: #F1F5F9, /* blueGray.100 */
mat-icon: #94A3B8, /* blueGray.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* blueGray.500 */
slider-off-active: #94A3B8 /* blueGray.400 */
),
background: (
status-bar: #0F172A, /* blueGray.900 */
app-bar: #0F172A, /* blueGray.900 */
background: #0F172A, /* blueGray.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* blueGray.800 */
dialog: #1E293B, /* blueGray.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
raised-button: #0F172A, /* blueGray.900 */
focused-button: #E2E8F0, /* blueGray.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* blueGray.800 */
disabled-button-toggle: #0F172A, /* blueGray.900 */
unselected-chip: #475569, /* blueGray.600 */
disabled-list-option: #E2E8F0, /* blueGray.200 */
tooltip: #64748B /* blueGray.500 */
)
)
);
@include angular-material-theme($dark-theme);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($dark-theme);
}
+7 -3
View File
@@ -72,13 +72,17 @@ function generateThemesObject(themes)
return _.map(_.cloneDeep(themes), (value, key) =>
{
const theme = normalizeTheme(value);
const primary = (theme && theme.primary && theme.primary.DEFAULT) ? theme.primary.DEFAULT : normalizedDefaultTheme.primary.DEFAULT;
const accent = (theme && theme.accent && theme.accent.DEFAULT) ? theme.accent.DEFAULT : normalizedDefaultTheme.accent.DEFAULT;
const warn = (theme && theme.warn && theme.warn.DEFAULT) ? theme.warn.DEFAULT : normalizedDefaultTheme.warn.DEFAULT;
return _.fromPairs([
[
key,
{
primary: theme?.primary?.DEFAULT ?? normalizedDefaultTheme.primary.DEFAULT,
accent : theme?.accent?.DEFAULT ?? normalizedDefaultTheme.accent.DEFAULT,
warn : theme?.warn?.DEFAULT ?? normalizedDefaultTheme.warn.DEFAULT
primary,
accent,
warn
}
]
]);
+1 -1
View File
@@ -1 +1 @@
export * from './public-api';
export * from '@fuse/validators/public-api';
+1 -1
View File
@@ -1 +1 @@
export * from './validators';
export * from '@fuse/validators/validators';
+1 -2
View File
@@ -1,4 +1,3 @@
import { Version } from '@fuse/version/version';
const __FUSE_VERSION__ = '12.1.0';
export const FUSE_VERSION = new Version(__FUSE_VERSION__).full;
export const FUSE_VERSION = new Version('13.6.1').full;
+1
View File
@@ -0,0 +1 @@
/* /index.html 200
+5 -6
View File
@@ -14,9 +14,8 @@ import { AppComponent } from 'app/app.component';
import { appRoutes } from 'app/app.routing';
const routerConfig: ExtraOptions = {
scrollPositionRestoration: 'enabled',
preloadingStrategy : PreloadAllModules,
relativeLinkResolution : 'legacy'
scrollPositionRestoration: 'enabled'
};
@NgModule({
@@ -28,18 +27,18 @@ const routerConfig: ExtraOptions = {
BrowserAnimationsModule,
RouterModule.forRoot(appRoutes, routerConfig),
// Fuse & Fuse Mock API
// Fuse, FuseConfig & FuseMockAPI
FuseModule,
FuseConfigModule.forRoot(appConfig),
FuseMockApiModule.forRoot(mockApiServices),
// Core
// Core module of your application
CoreModule,
// Layout
// Layout module of your application
LayoutModule,
// 3rd party modules
// 3rd party modules that require global configuration via forRoot
MarkdownModule.forRoot({})
],
bootstrap : [
+22 -25
View File
@@ -1,9 +1,12 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { InitialData } from 'app/app.types';
import { MessagesService } from 'app/layout/common/messages/messages.service';
import { NavigationService } from 'app/core/navigation/navigation.service';
import { NotificationsService } from 'app/layout/common/notifications/notifications.service';
import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service';
import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service';
import { UserService } from 'app/core/user/user.service';
@Injectable({
providedIn: 'root'
@@ -13,7 +16,14 @@ export class InitialDataResolver implements Resolve<any>
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
constructor(
private _messagesService: MessagesService,
private _navigationService: NavigationService,
private _notificationsService: NotificationsService,
private _quickChatService: QuickChatService,
private _shortcutsService: ShortcutsService,
private _userService: UserService
)
{
}
@@ -27,29 +37,16 @@ export class InitialDataResolver implements Resolve<any>
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<InitialData>
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any>
{
// Fork join multiple API endpoint calls to wait all of them to finish
return forkJoin([
this._httpClient.get<any>('api/common/messages'),
this._httpClient.get<any>('api/common/navigation'),
this._httpClient.get<any>('api/common/notifications'),
this._httpClient.get<any>('api/common/shortcuts'),
this._httpClient.get<any>('api/common/user')
]).pipe(
map(([messages, navigation, notifications, shortcuts, user]) => ({
messages,
navigation: {
compact : navigation.compact,
default : navigation.default,
futuristic: navigation.futuristic,
horizontal: navigation.horizontal
},
notifications,
shortcuts,
user
})
)
);
this._navigationService.get(),
this._messagesService.getAll(),
this._notificationsService.getAll(),
this._quickChatService.getChats(),
this._shortcutsService.getAll(),
this._userService.get()
]);
}
}
-19
View File
@@ -1,19 +0,0 @@
import { FuseNavigationItem } from '@fuse/components/navigation';
import { Message } from 'app/layout/common/messages/messages.types';
import { Notification } from 'app/layout/common/notifications/notifications.types';
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
import { User } from 'app/core/user/user.model';
export interface InitialData
{
messages: Message[];
navigation: {
compact: FuseNavigationItem[],
default: FuseNavigationItem[],
futuristic: FuseNavigationItem[],
horizontal: FuseNavigationItem[]
};
notifications: Notification[];
shortcuts: Shortcut[];
user: User;
}
+21
View File
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AuthService } from 'app/core/auth/auth.service';
import { AuthInterceptor } from 'app/core/auth/auth.interceptor';
@NgModule({
imports : [
HttpClientModule
],
providers: [
AuthService,
{
provide : HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi : true
}
]
})
export class AuthModule
{
}
+12 -12
View File
@@ -29,12 +29,12 @@ export class AuthService
*/
set accessToken(token: string)
{
localStorage.setItem('access_token', token);
localStorage.setItem('accessToken', token);
}
get accessToken(): string
{
return localStorage.getItem('access_token') ?? '';
return localStorage.getItem('accessToken') ?? '';
}
// -----------------------------------------------------------------------------------------------------
@@ -66,7 +66,7 @@ export class AuthService
*
* @param credentials
*/
signIn(credentials: { email: string, password: string }): Observable<any>
signIn(credentials: { email: string; password: string }): Observable<any>
{
// Throw error, if the user is already logged in
if ( this._authenticated )
@@ -78,7 +78,7 @@ export class AuthService
switchMap((response: any) => {
// Store the access token in the local storage
this.accessToken = response.access_token;
this.accessToken = response.accessToken;
// Set the authenticated flag to true
this._authenticated = true;
@@ -99,17 +99,17 @@ export class AuthService
{
// Renew token
return this._httpClient.post('api/auth/refresh-access-token', {
access_token: this.accessToken
accessToken: this.accessToken
}).pipe(
catchError(() => {
catchError(() =>
// Return false
return of(false);
}),
of(false)
),
switchMap((response: any) => {
// Store the access token in the local storage
this.accessToken = response.access_token;
this.accessToken = response.accessToken;
// Set the authenticated flag to true
this._authenticated = true;
@@ -129,7 +129,7 @@ export class AuthService
signOut(): Observable<any>
{
// Remove the access token from the local storage
localStorage.removeItem('access_token');
localStorage.removeItem('accessToken');
// Set the authenticated flag to false
this._authenticated = false;
@@ -143,7 +143,7 @@ export class AuthService
*
* @param user
*/
signUp(user: { name: string, email: string, password: string, company: string }): Observable<any>
signUp(user: { name: string; email: string; password: string; company: string }): Observable<any>
{
return this._httpClient.post('api/auth/sign-up', user);
}
@@ -153,7 +153,7 @@ export class AuthService
*
* @param credentials
*/
unlockSession(credentials: { email: string, password: string }): Observable<any>
unlockSession(credentials: { email: string; password: string }): Observable<any>
{
return this._httpClient.post('api/auth/unlock-session', credentials);
}
+35 -37
View File
@@ -14,6 +14,38 @@ export class AuthUtils
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Is token expired?
*
* @param token
* @param offsetSeconds
*/
static isTokenExpired(token: string, offsetSeconds?: number): boolean
{
// Return if there is no token
if ( !token || token === '' )
{
return true;
}
// Get the expiration date
const date = this._getTokenExpirationDate(token);
offsetSeconds = offsetSeconds || 0;
if ( date === null )
{
return true;
}
// Check if the token is expired
return !(date.valueOf() > new Date().valueOf() + offsetSeconds * 1000);
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
@@ -39,7 +71,7 @@ export class AuthUtils
);
}
/* tslint:disable */
/* eslint-disable */
for (
// initialize result and counters
let bc = 0, bs: any, buffer: any, idx = 0;
@@ -60,7 +92,7 @@ export class AuthUtils
// try to find character in table (0-63, not found => -1)
buffer = chars.indexOf(buffer);
}
/* tslint:enable */
/* eslint-enable */
return output;
}
@@ -75,9 +107,7 @@ export class AuthUtils
{
return decodeURIComponent(
Array.prototype.map
.call(this._b64decode(str), (c: any) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
})
.call(this._b64decode(str), (c: any) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
.join('')
);
}
@@ -171,36 +201,4 @@ export class AuthUtils
return date;
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Is token expired?
*
* @param token
* @param offsetSeconds
*/
static isTokenExpired(token: string, offsetSeconds?: number): boolean
{
// Return if there is no token
if ( !token || token === '' )
{
return true;
}
// Get the expiration date
const date = this._getTokenExpirationDate(token);
offsetSeconds = offsetSeconds || 0;
if ( date === null )
{
return true;
}
// Check if the token is expired
return !(date.valueOf() > new Date().valueOf() + offsetSeconds * 1000);
}
}

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