Compare commits

..

309 Commits

Author SHA1 Message Date
Sercan Yemen 80627bdde9 removed fake-db thingy 2017-10-16 10:50:57 +03:00
Sercan Yemen 6595975f2b Merge branch 'master' into skeleton 2017-10-16 10:45:27 +03:00
Sercan Yemen 895291c37c Updated Fuse version
+ Removed unnecessary dev dependencies and updated couple of them
2017-10-16 10:45:08 +03:00
Sercan Yemen dcb8032758 Merge branch 'master' into skeleton 2017-10-16 10:10:06 +03:00
Sercan Yemen ac7e6f75bc Added theme options openBar function to the navigation as an example
+ Removed duplicate Black and White tabs from colors
2017-10-16 10:08:40 +03:00
Sercan Yemen fb214da5fe Merge branch 'master' into skeleton 2017-10-14 18:53:08 +03:00
Sercan Yemen e20687034f Merge branch 'master' into skeleton 2017-10-14 18:53:00 +03:00
Sercan Yemen bd8b02c82d Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-10-14 18:44:17 +03:00
Sercan Yemen 6d594d63db Added a way of accessing and updating nav items
+ Added an ability to add custom functions to the nav items
2017-10-14 18:44:11 +03:00
mustafahlvc 6656410696 Calendar, Scrumboard Apps datepicker fixes. 2017-10-13 17:50:59 +03:00
mustafahlvc 470b851eae colors styling fix. 2017-10-13 15:43:22 +03:00
mustafahlvc fbe9cb83a2 missing destroy function added for Faq page. 2017-10-13 15:39:18 +03:00
mustafahlvc 13a09164ae Faq page added. 2017-10-13 15:37:30 +03:00
Sercan Yemen 56d9830176 Fixed: Lock page layout issues 2017-10-13 14:39:46 +03:00
Sercan Yemen be820804f2 New mail confirmation page 2017-10-13 14:22:59 +03:00
Sercan Yemen 7615bc1d03 Removed pricing tables from components 2017-10-13 12:24:13 +03:00
Sercan Yemen 3198663430 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-10-13 12:21:07 +03:00
Sercan Yemen ad432ca31d New pricing page design
+ Fixed: Some color issues
+ Fixed: Icons and Quick Nav in memory web api related data issues
2017-10-13 12:21:00 +03:00
mustafahlvc 7d26beff3d angular updated to v4.4.5 2017-10-13 12:13:03 +03:00
mustafahlvc 4711a27814 Merge remote-tracking branch 'origin/master' 2017-10-13 11:58:12 +03:00
mustafahlvc 8205a4d5b5 <agm-map> Google Maps component library added,
+ some style refinements on doc pages.
2017-10-13 11:57:54 +03:00
Sercan Yemen 4f451a74e9 fixed custom colors 2017-10-12 17:40:27 +03:00
Sercan Yemen 8518408254 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-10-12 14:29:13 +03:00
Sercan Yemen 72f968b594 Fix: Auth page v2 styles iOS height issue
+ Fix: Perfect scrollbar causes issues on outside of the zone
+ Fix: Navigation must unsubscribe the nav toggle and clear the timeout
+ Fix: Chat view is not scrollable on mobile
+ Fix: Terms & Conditions checkbox styling issues on Auth forms
+ Fix: Sidenav z-index issue on certain page layouts
+ Fix: Some page layout header heights not correct on small devices
2017-10-12 14:28:58 +03:00
mustafahlvc 688b443ea8 <mat-select> wrapped with <mat-form-field> and fixed relative issues. 2017-10-12 14:05:22 +03:00
mustafahlvc cb89da4647 angular-in-memory-web-api updated to v0.5.0,
(HTTP response data no longer wrapped in object w/ data property by default.)
2017-10-12 13:05:56 +03:00
Sercan Yemen cc4a04afcb Removed fxFlexFill from main-content in an attempt to fix iOS scrolling and sizing issues
+ Updated Perfect scrollbar
+ updated various packages like zone-js & core-js
+ small tweak on contacts list item padding
+ removed md2 datepicker color tweak
2017-10-12 12:42:11 +03:00
mustafahlvc bc239571a1 @angular/material v2.0.0-beta.12 examples updated. 2017-10-10 17:19:07 +03:00
mustafahlvc c025563145 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/app/core/services/config.service.ts
2017-10-10 16:40:29 +03:00
mustafahlvc c06e99dc97 @angular/material v2.0.0-beta.12 compability update,
Lots of breaking changes,
all "md" prefixes changed with "mat" due to angular material deprecation of "md",
md2 package removed, its not compatible with latest material version, will be replaced with another date picker later.
2017-10-10 16:37:24 +03:00
Sercan Yemen c0a1dc7c37 Changed default navbar and footer colorsˆ 2017-10-09 14:22:12 +03:00
Sercan Yemen 55e1d8b2bc New Reset and Forgot password styles 2017-10-09 14:17:27 +03:00
Sercan Yemen 533f5f3f3f removed unnecessary console.logs and added possible route animations 2017-10-09 12:32:40 +03:00
Sercan Yemen f9bda99deb Merge branch 'master' into skeleton 2017-10-02 10:15:00 +03:00
Sercan Yemen 4a7b70c874 Fixes #16: Inconsistent font sizes across elements 2017-10-02 10:14:20 +03:00
Sercan Yemen c101c432dc Fixes #14: Toolbar search bar button collapses on close 2017-10-02 10:01:22 +03:00
Sercan Yemen 04d1b2eff8 Fixes #9: print styles and page breaks 2017-09-29 12:06:47 +03:00
Sercan Yemen 1d81e37a0f removed markdown module imports 2017-09-28 13:00:44 +03:00
Sercan Yemen 83f0ed5ec1 Merge branch 'master' into skeleton 2017-09-28 12:52:59 +03:00
Sercan Yemen f800dc3286 updated footer links 2017-09-28 12:52:34 +03:00
Sercan Yemen e486413872 remove unnecessary stuff from skeleton 2017-09-28 12:51:15 +03:00
Sercan Yemen 576e167ef1 Merge branch 'master' into skeleton 2017-09-28 12:49:18 +03:00
Sercan Yemen 619433f101 updated version number 2017-09-28 12:43:27 +03:00
mustafahlvc 3e9ae83aae Angular Material reference url fix 2017-09-28 12:26:33 +03:00
mustafahlvc 9400c3d748 Responsive refinement on some doc pages,
Navigation scrool fix on collapse toggled.
2017-09-28 12:22:33 +03:00
mustafahlvc 5e4940fed9 IconSvgExample Component path corrected. 2017-09-28 11:05:11 +03:00
mustafahlvc 8910e6f5dc angular-in-memory-web-api updated,
+ Http changed with HttpClient,
+ Angular Material Element examples added,
+ angular2-markdown Library added
2017-09-27 19:41:01 +03:00
mustafahlvc 52c5e6a18b Nested group vertical navigation indentation fix 2017-09-27 18:45:24 +03:00
mustafahlvc 3d9ded9a44 Nested Group feature added to navigation 2017-09-26 11:58:34 +03:00
mustafahlvc 1be3f0066b Angular Material updated to 2.0.0-beta.11:
Do not change the prefixes md to mat for this release; They don't completely migrate.
2017-09-26 10:04:45 +03:00
Sercan Yemen cf9e9fc209 Merge branch 'master' into skeleton 2017-09-22 16:45:47 +03:00
Sercan Yemen ff0f2933d9 Merge branch 'master' into skeleton 2017-09-22 16:45:23 +03:00
mustafahlvc 21c96c76da Merge remote-tracking branch 'origin/master' 2017-09-22 16:18:24 +03:00
mustafahlvc 5e2e2b7d53 Backdrop added to FuseNavBar for mobile 2017-09-22 16:18:05 +03:00
Sercan Yemen dcff423943 Updated version to 1.1.0 since we have couple breaking changes! 2017-09-22 16:07:05 +03:00
Sercan Yemen 6747610771 Fixed: Fullwidth simple page layout doesn't scroll
+ Added: New logo to the various pages
+ Fixed: Mobile zoom is not disabled
+ Fixed: Profile timeline mobile order is not correct
+ Fixed: Quickpanel focusses to the form elements causing it to scroll on mobile devices when opened
+ Various demo page mobile fixes
2017-09-22 16:04:59 +03:00
Sercan Yemen e6ee5d017e small tweaks and ng-* cleanups
+ Fixed: todo item action buttons shouldn't trigger "view todo" action
+ Fixed: contacts selected bar mobile issues
2017-09-22 15:02:07 +03:00
Sercan Yemen cb2b544526 chat, todo & theme options tweaks 2017-09-22 12:11:21 +03:00
mustafahlvc 5ace09f782 Calendar, Contacts, Mail, Scrumboard apps responsive refinements,
+ temporary fix for md-sidenav-locked transition
2017-09-22 12:03:21 +03:00
Sercan Yemen 678dde8c0e calendar, mail and todo tweaks 2017-09-22 11:32:31 +03:00
Sercan Yemen 236cf1eb06 renamed the HMR starting scripts
+ modified the build scripts to use more memory. If you are having `out of memory` issues while building, use these scripts
2017-09-22 11:32:08 +03:00
Sercan Yemen f4efbe07f7 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-09-22 09:23:38 +03:00
mustafahlvc 671287b55a Reverting the sidenav fixes.. 2017-09-21 19:03:19 +03:00
Sercan Yemen 19c85c964b updated the version number to 1.0.6 2017-09-21 15:54:25 +03:00
Sercan Yemen e5cf4fdafb demo component and service page updates 2017-09-21 15:54:11 +03:00
Sercan Yemen 098dacf2a5 removed console warn 2017-09-21 15:13:27 +03:00
mustafahlvc 2f8539e987 Merge remote-tracking branch 'origin/master' 2017-09-21 15:05:36 +03:00
mustafahlvc f688a58656 Animations enhanced for all apps and some pages. 2017-09-21 15:05:18 +03:00
Sercan Yemen 9cb8c0c96b Added a way to swap navigation model on the fly
Moved the navigation service to the app.module since we need it to be a singleton at all times
2017-09-21 14:56:08 +03:00
Sercan Yemen 05575d3f82 Fixed: Navigation model must be public 2017-09-21 14:08:37 +03:00
Sercan Yemen b9198e3717 Entirely changed the navigation model structure (sorry!)
+ Fixed: Horizontal and Vertical navigation must be able to use the same model structure
+ Fixed: Collapsable nav item that has the active menu shouldn't be collapsed when other collapsables toggles
2017-09-21 12:08:52 +03:00
Sercan Yemen 769e67c2f3 Added HMR config. Use 'npm run hmr' for HMR enabled environment. This start script disables the sourcemaps to further increase the re-compile performance. If you need HMR with sourcemaps use 'npm run hmrs' 2017-09-21 10:58:19 +03:00
Sercan Yemen 32960abd7c fixed sidenav for fuse https://github.com/angular/material2/issues/7201 2017-09-20 17:38:14 +03:00
Sercan Yemen 126e32d9e7 updated Angular to 4.4.3 2017-09-20 10:06:43 +03:00
Sercan Yemen d6d74cb998 small tweaks 2017-09-20 10:06:28 +03:00
Sercan Yemen 6d20c1d62d Custom perfect-scrollbar directive for better control (replaced the ngx-perfect-scrollbar with fuse-perfect-scrollbar) 2017-09-18 16:06:15 +03:00
Sercan Yemen b55bce2de4 fixed: navigation collapsable issue on route change
fixed: footer stays on top of the navigation on mobile
2017-09-18 15:58:47 +03:00
Sercan Yemen 6f4dc36a3d locked dev dependency versions to prevent "npm update" errors! 2017-09-18 10:48:02 +03:00
Sercan Yemen fe7e6d173b small tweaks and clean-ups 2017-09-18 10:47:35 +03:00
Sercan Yemen b377d99c66 new fuse logo 2017-09-18 10:47:08 +03:00
Sercan Yemen d4374e6df0 changed 'perfect-scrollbar' to 'perfectScrollbar' 2017-09-18 10:46:09 +03:00
Sercan Yemen c74fad84b6 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-09-18 10:25:04 +03:00
mustafahlvc e09ef05e02 (ngx-perfect-scroolbar) updated to v.4.6.2 2017-09-15 17:40:38 +03:00
Sercan Yemen 62467c8ddf Merge branch 'master' into skeleton 2017-09-12 16:06:21 +03:00
Sercan Yemen 2c0fc76b8a meta tags and description for demo 2017-09-12 14:23:54 +03:00
Sercan Yemen 752660f5dc fix: theme options are not correctly shown on mobile 2017-09-12 10:25:11 +03:00
Sercan Yemen 024ab15b25 Merge branch 'master' into skeleton 2017-09-11 16:34:07 +03:00
Sercan Yemen 01f00121ba Revert "removed md2 + replaced the date/time picker in scrumboard"
This reverts commit dde2333
2017-09-11 16:33:20 +03:00
Sercan Yemen 915ad52863 Merge branch 'master' into skeleton 2017-09-11 16:21:05 +03:00
Sercan Yemen dde2333c8a removed md2
+ replaced the date/time picker in scrumboard
2017-09-11 16:19:46 +03:00
Sercan Yemen 97bfaa9979 Merge branch 'master' into skeleton 2017-09-11 13:06:42 +03:00
Sercan Yemen babf6dc47b updated the readme 2017-09-11 13:06:24 +03:00
Sercan Yemen 6ae3e154c3 Merge branch 'master' into skeleton 2017-09-11 12:59:36 +03:00
Sercan Yemen 55288bbbd4 set the correct default values for layout
+ increased the version number
2017-09-11 12:59:13 +03:00
Sercan Yemen 49b6ff7292 navigation model for horizontal nav 2017-09-11 12:58:24 +03:00
Sercan Yemen 903688ab43 Merge branch 'master' into skeleton 2017-09-11 12:57:59 +03:00
Sercan Yemen 7297a9b4a4 toolbar adjustments 2017-09-11 12:34:16 +03:00
Sercan Yemen 4cbbd3a1d6 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-09-11 12:30:07 +03:00
Sercan Yemen 2f4ce6221e horizontal navigation layout
+ added boxed layout option
+ added a close overlay to theme options
+ moved the buy button to the footer
+ added fade-in-out animation
+ File Manager app min row height
2017-09-11 12:30:01 +03:00
mustafahlvc 44cdadaec9 (Scrumboard, Chat) some css style refinements 2017-09-08 19:21:35 +03:00
Sercan Yemen 19f822cbab removed unnecessary md2 from skeleton 2017-09-01 09:05:56 +03:00
Sercan Yemen 1d21a14d0e Merge branch 'master' into skeleton 2017-08-30 20:52:23 +03:00
Sercan Yemen d5b6dea1a2 update version 2017-08-30 20:52:08 +03:00
Sercan Yemen 4bf2ba73ad merge 'master' into skeleton 2017-08-30 20:08:12 +03:00
Sercan Yemen 31087186f7 Merge branch 'scrumboard-app' 2017-08-30 20:03:21 +03:00
Sercan Yemen 48a47a0876 sidenav helper small tweaks
+ chat & toolbar small mobile tweaks
2017-08-30 20:02:54 +03:00
Sercan Yemen e0a85a19db package lock 2017-08-30 20:01:45 +03:00
mustafahlvc b21526410a (Scrumboard) final touches.. 2017-08-30 18:46:07 +03:00
mustafahlvc ce6797a80b (Scrumboard) Drag-drop support 2017-08-30 15:58:40 +03:00
mustafahlvc 7d5693421f Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
2017-08-30 15:11:21 +03:00
mustafahlvc 9106fcd066 Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
2017-08-30 15:11:07 +03:00
mustafahlvc 58bdf07da0 Style fixes especially for Edge/IE Browser 2017-08-30 15:04:20 +03:00
Sercan Yemen 6a3972fff8 Merge branch 'master' into skeleton 2017-08-30 14:43:10 +03:00
Sercan Yemen 58291058ae update version number 2017-08-30 14:42:55 +03:00
Sercan Yemen dca16238eb Merge branch 'master' into skeleton 2017-08-30 14:41:30 +03:00
Sercan Yemen 9ae746a3ed fix: revert back to Angular 4.3.5 since the animations are not working correctly on 4.3.6 2017-08-30 14:36:54 +03:00
Sercan Yemen a7549a1770 fix: pages not scrolling on various browsers 2017-08-30 14:26:45 +03:00
mustafahlvc 0bf158f8a5 (Scrumboard) board settings added + some refinements. 2017-08-30 14:21:14 +03:00
mustafahlvc a0da9bd81e Merge branch 'master' into scrumboard-app
# Conflicts:
#	package.json
#	src/app/core/modules/shared.module.ts
2017-08-30 14:19:45 +03:00
Sercan Yemen 2b91119d00 Merge branch 'master' into skeleton 2017-08-30 11:50:56 +03:00
Sercan Yemen 56716653b8 added npmrc to force the package version on both install and update
+ updated package-lock.json
2017-08-30 11:48:26 +03:00
mustafahlvc a56e9e6d10 Angular Material Update: 2.0.0-beta.10 2017-08-30 10:37:25 +03:00
mustafahlvc 49af06cdbd Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-30 06:54:43 +03:00
mustafahlvc cd99fbf77a (Scrumboard App) added
+ md2 added for date-time picker,
+ toggleInArray func added to FuseUtils
2017-08-30 06:54:11 +03:00
Sercan Yemen 041a54731d added print styles 2017-08-29 17:41:35 +03:00
Sercan Yemen 95640f8ffe wording 2017-08-29 17:27:27 +03:00
Sercan Yemen 215d1cb78a added cookie saving for shortcuts component
+ services and components pages for the demo
2017-08-29 17:20:13 +03:00
mustafahlvc ffa52909e8 unnecessary env variable removed 2017-08-26 06:10:22 +03:00
mustafahlvc 3a246717a0 this.router.events.filter/map AOT error fix. 2017-08-25 17:34:58 +03:00
mustafahlvc a650ebac97 (@angular/flex-layout) updated to v2.0.0-beta.9 2017-08-25 09:58:59 +03:00
Sercan Yemen ff4899e8d2 Merge branch 'master' into skeleton
# Conflicts:
#	src/app/app.module.ts
#	src/app/main/content/apps/calendar/calendar.component.html
#	src/app/main/content/apps/contacts/contact-list/contact-list.component.html
#	src/app/main/content/apps/contacts/contacts.component.html
#	src/app/main/content/apps/contacts/contacts.component.scss
#	src/app/main/content/apps/contacts/contacts.module.ts
#	src/app/main/content/apps/contacts/contacts.service.ts
#	src/app/main/content/apps/contacts/selected-bar/selected-bar.component.html
#	src/app/main/content/apps/mail/sidenavs/main/main-sidenav.component.html
#	src/app/navigation.model.ts
2017-08-24 11:18:24 +03:00
Sercan Yemen a3844b5556 fuse2 1.0.1 update
+ AoT compatibility
+ Route animation options
+ Locked Angular version to 4.3.5 due to broken Angular Animation
2017-08-24 11:13:12 +03:00
mustafahlvc f1ac166ca6 Roter Animation:
+ animations disabled for child queries (eg. Mail App)
+ New router animations added
+ Router animation option added to config and theme options
+ Disabled delaying fakedb requests
2017-08-23 17:28:15 +03:00
Sercan Yemen cc7af0c2e4 purchase button 2017-08-22 16:23:38 +03:00
Sercan Yemen f865626667 navbar position fixes 2017-08-22 16:06:01 +03:00
Sercan Yemen e818c53f1d navbar fixes 2017-08-22 16:05:32 +03:00
Sercan Yemen ca96fffadf removed fuse fake db 2017-08-22 15:58:35 +03:00
Sercan Yemen 53c52af351 moved navigation model 2017-08-22 15:57:01 +03:00
Sercan Yemen d7003711ee skeleton branch 2017-08-22 15:55:48 +03:00
Sercan Yemen 8cbc2f3ab7 perfect scrollbar update on nav item toggle
+ iconset url fix
2017-08-22 15:42:11 +03:00
Sercan Yemen fcabc1fbff native input color theming 2017-08-22 14:45:35 +03:00
mustafahlvc 37c441f888 SearchBar Mobile fix.
+ disabling custom scrollbars on mobile
2017-08-22 14:17:17 +03:00
mustafahlvc fbd62c1aa9 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-22 13:45:41 +03:00
mustafahlvc 2eb9b3f09e FuseMaterialColorPicker enhanced
+ Navbar, Footer, Toolbar color options added to theme-options
+ FuseLayoutService moved to FuseConfigService
2017-08-22 13:45:07 +03:00
Sercan Yemen fa4b2908e9 Merge remote-tracking branch 'origin/master' 2017-08-22 13:10:57 +03:00
Sercan Yemen c56f3dc35b simple theming
+ modified the native webkit scrollbar styles a bit
+ todo & mail app sidenav header colors
+ added a way to disable perfect-scrollbars
2017-08-22 13:10:46 +03:00
mustafahlvc f39464199e Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-21 16:26:43 +03:00
mustafahlvc 50bbbf18db (FuseMaterialColorPickerComponent) added. 2017-08-21 16:12:51 +03:00
Sercan Yemen 59b7c4a70b page layouts fixed
+ resposive fixes on apps
+ fixed: router animation breaks the perfect-scrollbar
+ updated the perfect-scrollbar version
2017-08-21 15:02:03 +03:00
mustafahlvc faebddd114 Small fixes for todo, mail, projects-dashboard app, ie suppport etc.. 2017-08-20 16:39:22 +03:00
Sercan Yemen e83e0ff07b fuse shortcuts mobile behavior 2017-08-20 13:26:45 +03:00
mustafahlvc d70ad0d3c7 Fuck.n router animation.. 2017-08-19 16:20:09 +03:00
mustafahlvc b8d5c16237 (fuseNavBar) close on route change for mobile. 2017-08-18 16:44:39 +03:00
mustafahlvc 38f83bd905 (fuseNavBar) change media steps for folded feature. 2017-08-18 16:33:19 +03:00
Sercan Yemen 953f8cf44a added header-bg image 2017-08-18 15:09:12 +03:00
Sercan Yemen 723d9e110f put Fuse prefix to all components 2017-08-18 14:50:19 +03:00
Sercan Yemen 0b2c506935 splash screen 2017-08-18 12:31:17 +03:00
mustafahlvc 51a6e864dd Reformatting. 2017-08-17 10:40:25 +03:00
mustafahlvc 1467c22604 Page Layouts: content coloring with helper class "md-white-bg" 2017-08-17 10:37:19 +03:00
mustafahlvc c0fc801208 Code inspections. 2017-08-17 10:31:04 +03:00
mustafahlvc 8dcfcaac4e Responsive stuff. 2017-08-17 09:58:02 +03:00
mustafahlvc 874d401bac Lots of Responsive refinements applied espacially for the apps
+ responsive variations of spacing class helpers added.
2017-08-16 15:19:26 +03:00
mustafahlvc f38cde844a (FuseNavBar) changed folded defaults to false 2017-08-16 09:38:51 +03:00
mustafahlvc 9dc44c2206 (FuseNavBar) no navbar css fixed, missing nav-link-title added to collapse item. 2017-08-15 16:04:12 +03:00
mustafahlvc da97ab7e4b (FuseNavBar) default folded option added, responsive, right/left sidenav issues fixed. 2017-08-15 15:34:24 +03:00
mustafahlvc 117f5a85b2 (Contacts) sidenav toggler fixed and sidenav style refined for mobile. 2017-08-15 13:29:07 +03:00
mustafahlvc 9a420c9599 (File Manager) unnecessary sidenav toggler removed 2017-08-15 13:28:20 +03:00
mustafahlvc 02a67630a4 (Navigation) nav-link badge feature added. 2017-08-15 13:11:20 +03:00
mustafahlvc dad0964563 (Calendar App) unnecessary binding removed. 2017-08-15 11:43:31 +03:00
mustafahlvc f134e10a27 (Mail App) Compose Dialog added. 2017-08-15 11:42:39 +03:00
mustafahlvc a9e5115558 webkit-scrollbar styles added. 2017-08-15 10:34:57 +03:00
mustafahlvc 92c8417a9a Perfect Scrollbar enabled, missing attrs added
+ darken navbar bg color
2017-08-14 18:18:01 +03:00
Sercan Yemen 2fc3ac0997 navbar header 2017-08-14 17:24:10 +03:00
Sercan Yemen 05b051431e rxjs import stuff fixed 2017-08-14 17:17:49 +03:00
Sercan Yemen 429478b828 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	package.json
2017-08-14 17:10:46 +03:00
Sercan Yemen 2b92320185 layout firefox + safari stuff 2017-08-14 17:09:00 +03:00
mustafahlvc 6e93b5fe76 Border class helpers added. 2017-08-14 16:59:36 +03:00
mustafahlvc 495d4eb1e3 (Projects Dashboard) Sidenav widgets small fixes. 2017-08-14 16:52:20 +03:00
mustafahlvc 0cbe978f49 (Projects Dashboard) Now widget date format corrected. 2017-08-14 16:36:54 +03:00
mustafahlvc a522fb3822 (fuseIfOndDom) function changed for ie
+ new polyfills added and activated.
2017-08-14 16:15:19 +03:00
mustafahlvc 7cfbf4d8df (Todo App)(Mail App) tag/label restyling 2017-08-14 12:26:50 +03:00
mustafahlvc 587b1f5661 (Toolbar) missing separator added. 2017-08-14 11:56:50 +03:00
mustafahlvc fbeb2ca7f6 (Project Dashboard) title bottom margin removed 2017-08-14 10:35:58 +03:00
mustafahlvc c389d19963 (fuse-widget) fuseWidgetToggle Directive added for to not use class toggler. 2017-08-14 09:53:18 +03:00
mustafahlvc 71a18758e2 (shortcuts) some refinements (perfect scrollbar, star, width, autofocus)
+ removed !important on some classes of colors
2017-08-12 11:31:16 +03:00
mustafahlvc 71d8c37752 (ngx-color-picker) style refined, material colors presets added in Calendar App 2017-08-11 19:39:54 +03:00
mustafahlvc 5101ff5651 (Project Dashboard) almost finished,
new icon fonts added for meteorology,
widget component added,
fuseIfOnDome directive added,
run npm install..
2017-08-11 16:53:01 +03:00
Sercan Yemen 82440ea9b3 small tweaks... 2017-08-07 15:43:50 +03:00
Sercan Yemen 8d5ed22e0f search bar component for toolbar 2017-08-07 14:27:34 +03:00
Sercan Yemen e8aff89668 shortcuts component done
+ couple fixes in colors.scss
+ added getFlatNavigation() to the navigation service
+ tweaks in navigation files
2017-08-07 13:29:58 +03:00
Sercan Yemen e220a19b4e price tables tweaks 2017-08-04 12:24:05 +03:00
mustafahlvc d86f7b892e Merge remote-tracking branch 'origin/master' 2017-08-04 12:15:50 +03:00
mustafahlvc f08fdf3f54 (Theme Options) component added. 2017-08-04 12:15:36 +03:00
Sercan Yemen fd0f132f17 price tables done... 2017-08-04 12:15:25 +03:00
Sercan Yemen 3ac16afd8f Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-04 11:59:27 +03:00
Sercan Yemen 45da6e81ed forms page done... 2017-08-04 11:59:22 +03:00
mustafahlvc 522a5ec976 Navigation item :hover text underline fix. 2017-08-04 10:05:23 +03:00
Sercan Yemen 3b0e92c102 a typo fix 2017-08-03 17:28:13 +03:00
Sercan Yemen 0bd35d58c4 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-03 17:18:22 +03:00
Sercan Yemen e24a7ea5a4 icons page done..
header fixes on UI pages
2017-08-03 17:18:14 +03:00
mustafahlvc 5f5e9d55ad (Calendar App) Responsive refinement. 2017-08-03 16:53:30 +03:00
mustafahlvc 7847097ea2 .mat-sidenav-content style fix 2017-08-03 16:49:18 +03:00
Sercan Yemen 99128382e2 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	src/app/fuse-fake-db/fuse-fake-db.service.ts
2017-08-03 16:37:27 +03:00
Sercan Yemen 4c3b8edee4 default text colors 2017-08-03 16:36:29 +03:00
mustafahlvc 54da3f4ef5 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-03 16:35:46 +03:00
mustafahlvc ff3fb79448 (Quick Panel) Simplified 2017-08-03 16:35:35 +03:00
Sercan Yemen c02856396f helpers page done... 2017-08-03 14:34:33 +03:00
Sercan Yemen 09cd8b497b Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-03 12:37:56 +03:00
Sercan Yemen 2024a0d645 hljs component now works with multiline stuff
+ typography page done...
2017-08-03 12:37:50 +03:00
mustafahlvc 76ccc83e97 (Contacts App) Done for now. 2017-08-03 11:21:19 +03:00
mustafahlvc 5c27445d19 (Contacts App) ongoing 2017-08-03 00:48:05 +03:00
mustafahlvc 3eeaadf518 Merge remote-tracking branch 'origin/master' 2017-08-03 00:47:34 +03:00
mustafahlvc 5bd2b32f22 (Calendar App) cleaning. 2017-08-03 00:46:56 +03:00
mustafahlvc c4a08dc939 (Contacts App) ongoing 2017-08-02 19:51:02 +03:00
Sercan Yemen b39c52f6c6 little fix 2017-08-02 17:50:49 +03:00
Sercan Yemen c7ab535f46 typography page first tab
+ hljs component
2017-08-02 17:47:45 +03:00
Sercan Yemen eefc691238 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-02 13:29:17 +03:00
Sercan Yemen 50f27de0d6 stufzz 2017-08-02 13:29:12 +03:00
mustafahlvc ccfd711c03 (Contacts App) layouts issues.. 2017-08-02 13:29:00 +03:00
Sercan Yemen 3dde222528 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-02 13:02:02 +03:00
Sercan Yemen 31c35dd5fa simple layout 3 perfect scrollbar
+ simple layout 3 tweaks
+ added modules to all pages
+ moved some stuff to the SharedModule from AppModule
+ typography page structure
2017-08-02 13:01:55 +03:00
mustafahlvc 7fdd6469c8 fix paths for lazy loaded apps 2017-08-02 12:07:48 +03:00
Sercan Yemen e5ce8a0e5f koyduk 2017-08-02 11:53:31 +03:00
mustafahlvc 7e33e36162 (Contacts App) start to build on filemanager app.. 2017-08-02 10:51:11 +03:00
mustafahlvc d7d3a6833d (File Manager App) updated. 2017-08-02 10:18:39 +03:00
mustafahlvc ba3c22d67d (File Manager App) finished for now. 2017-08-01 19:34:58 +03:00
Sercan Yemen 59e58ce4f8 search page 2017-08-01 17:12:26 +03:00
mustafahlvc 4d477561b7 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/app/fuse-fake-db/fuse-fake-db.service.ts
2017-08-01 15:29:59 +03:00
mustafahlvc 9a2acb0e64 (File Manager App) first steps. 2017-08-01 15:27:32 +03:00
Sercan Yemen e0253cd8d2 invoice pages 2017-08-01 14:56:39 +03:00
Sercan Yemen 1c66ccd9e2 added left sidenav 3 & right sidenav 3
+ page layouts header size modifications
+ page layouts header text alignment
2017-08-01 12:32:25 +03:00
Sercan Yemen 0a049ff9f4 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-08-01 11:14:44 +03:00
Sercan Yemen e8a6b0fb3b page layouts 2017-08-01 11:14:39 +03:00
mustafahlvc 84fadda738 layout elements z-index fix. 2017-07-31 19:01:11 +03:00
Sercan Yemen 156b859ecc theming stufz 2017-07-31 18:51:47 +03:00
Sercan Yemen 21cc769dd3 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-31 17:35:43 +03:00
Sercan Yemen 0fc689daed srcn 2017-07-31 17:35:36 +03:00
mustafahlvc f47c0a84fe Merge remote-tracking branch 'origin/master' 2017-07-31 16:59:34 +03:00
mustafahlvc 8ad97ed485 Sidenav missing styles added, unnecessary sidenav component removed. 2017-07-31 16:59:09 +03:00
Sercan Yemen 67380b0543 fix 2017-07-31 16:50:29 +03:00
Sercan Yemen 4ff42b9042 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-31 16:49:37 +03:00
Sercan Yemen d8e964d063 more datatable 2017-07-31 16:49:20 +03:00
Sercan Yemen bc1421976e more datatableˆ 2017-07-31 16:49:13 +03:00
mustafahlvc 3c4cc44045 Some works on toolbar 2017-07-31 16:32:58 +03:00
mustafahlvc fb2dcc0653 Width, height percentage class helpers added. 2017-07-31 16:32:29 +03:00
Sercan Yemen 5ca5400ba7 new helpers.scss + size helpers + ngx-datatable styles + show toolbar by default 2017-07-31 14:58:55 +03:00
Sercan Yemen aa0c1d7a87 color.scss added white and black 2017-07-31 13:17:02 +03:00
Sercan Yemen 2225ace5be color.scss generator refactor 2017-07-31 12:24:41 +03:00
Sercan Yemen a55a4d8eb0 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	src/app/main/ui/colors/colors.component.html

+ Simplified color.scss by re-defining the hue variable depending on its value
+ Page layouts & apps colors
2017-07-31 12:15:56 +03:00
Sercan Yemen b48110ee2c removed paddings from page-layouts + fixed apps paddings + page layouts coloring 2017-07-31 11:49:43 +03:00
mustafahlvc d79068a734 Color helper updated. 2017-07-30 00:53:43 +03:00
Sercan Yemen 8fdca9f2ec Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-29 16:43:04 +03:00
Sercan Yemen 0123d62774 ngx-datatable 2017-07-29 16:42:53 +03:00
mustafahlvc ef9a1bdc86 Colors updated. 2017-07-29 16:00:24 +03:00
Sercan Yemen 6f7809ac3e color tweaks 2017-07-29 15:26:46 +03:00
Sercan Yemen da433711be Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-29 14:25:30 +03:00
Sercan Yemen abf8c61d8c profile page + some more tweaks 2017-07-29 14:25:23 +03:00
mustafahlvc 33f80e659b MatColors cleanup. 2017-07-29 14:19:40 +03:00
mustafahlvc 01609920bb MatColors small fix. 2017-07-29 14:17:32 +03:00
mustafahlvc 196e1644ff camelCaseToDash pipe added,
material colors added class helpers and global  class added.
Material Colors Demo page added.
2017-07-29 14:12:19 +03:00
mustafahlvc 5f34825189 package.json updated. 2017-07-28 17:45:13 +03:00
mustafahlvc 3e096e7b7d Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-28 17:40:53 +03:00
mustafahlvc 0339874110 (Todo app) ongoing.. 2017-07-28 17:40:11 +03:00
Sercan Yemen be8195663e Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-28 16:03:41 +03:00
Sercan Yemen cdbae74d6c pages + typography + some scss tweaks 2017-07-28 16:03:32 +03:00
mustafahlvc 1f8b1a3f27 Filtering updated for mail, todo app. 2017-07-28 12:26:56 +03:00
mustafahlvc 2d459864f1 Filter Pipe updated,
FuseUtils added,
Filtering applied for mail, todo, chat app.
2017-07-28 11:29:29 +03:00
Sercan Yemen 0b3a7ef919 reverted layout service 2017-07-27 19:10:03 +03:00
Sercan Yemen 66e8e82049 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	src/app/app.module.ts
2017-07-27 18:07:45 +03:00
Sercan Yemen d44a76b8c6 fixed layout service + some auth pages + simple page layouts + mail tweaks 2017-07-27 18:05:50 +03:00
mustafahlvc 76f2a7c8df (Todo App) some fixes about tag routing etc.. 2017-07-27 00:41:11 +03:00
mustafahlvc 46ad46bb02 (Todo App) Todo app created,
drag drop libarary added,
(Chat App) Chat app module name changed.
2017-07-27 00:33:17 +03:00
mustafahlvc 6237b1132a Merge remote-tracking branch 'origin/master' 2017-07-26 14:04:06 +03:00
mustafahlvc 1f06e30a17 Navigation icon styles updated again. 2017-07-26 14:03:49 +03:00
Sercan Yemen 3b955184d1 Merge branch 'master' of https://github.com/withinpixels/fuse2 2017-07-26 13:59:04 +03:00
Sercan Yemen 3541d68994 mail sidenav scroll issue + toolbar separator global class + renamed MailModule to FuseMailModule 2017-07-26 13:58:55 +03:00
mustafahlvc 96b7584e76 package.json updated. 2017-07-26 13:39:49 +03:00
mustafahlvc 6006faf4e1 Navigation icon styles fixed. 2017-07-26 13:39:30 +03:00
mustafahlvc 906799c694 (Calendar App) Event form disabling button with pristine. 2017-07-26 13:38:58 +03:00
Sercan Yemen 7c770d6bf0 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	package.json
#	src/app/app.module.ts
2017-07-26 12:45:28 +03:00
Sercan Yemen 141b4b1528 mail.. 2017-07-26 12:43:45 +03:00
mustafahlvc ed06e26647 (Calendar App) Calendar app added. 2017-07-26 10:02:26 +03:00
mustafahlvc 0270405353 (Chat App) Adding chat service function fixed 2017-07-23 18:27:17 +03:00
mustafahlvc 31df82fe09 (Calendar App) Started to build, run npm install.. 2017-07-23 18:20:48 +03:00
mustafahlvc f73564c464 Unnecessary searchpipe removed.. 2017-07-23 10:43:30 +03:00
mustafahlvc 4da5f8e8e8 Merge branch 'master' of https://github.com/withinpixels/fuse2
# Conflicts:
#	src/app/core/pipes/pipes.module.ts
#	src/app/fuse-fake-db/fuse-fake-db.service.ts
2017-07-23 10:42:29 +03:00
mustafahlvc 56e6b854c2 Filter pipe added,
spacing class helpers added(margin, padding),
Normalize css added,
Icon size class helpers added,
slideInLeft, slideInRight animation added,
Chat app almost completed.
2017-07-23 10:32:13 +03:00
Sercan Yemen b0e4f87a8a mail.. 2017-07-20 18:12:09 +03:00
Sercan Yemen b9569a5ba8 mail.. 2017-07-19 17:58:36 +03:00
mustafahlvc 2e4d040139 Mail: Navigation styling 2017-07-19 00:26:09 +03:00
Sercan Yemen c3cb5c8942 mail.. 2017-07-18 19:34:12 +03:00
mustafahlvc 29bb2198d3 fuse-fake-db.service added, mail routes update.. 2017-07-17 23:17:18 +03:00
Sercan Yemen 0c3bbb241c mail.. 2017-07-17 18:11:34 +03:00
mustafahlvc 96e20ac312 package.json updated. 2017-07-17 10:16:23 +03:00
mustafahlvc e33b16c727 Mail App: mail item, list style, selected mail.. 2017-07-16 21:41:01 +03:00
mustafahlvc c4f03469f9 HtmlToPlaintext pipe,
images added to assets,
@angular/flex-layout package version updated,
some workin on the mail app..
2017-07-16 18:24:09 +03:00
mustafahlvc 4563931090 Keys pipe, some workin on the mail app.. 2017-07-16 16:12:40 +03:00
Sercan Yemen ac870a9613 fuse2... 2017-07-15 18:03:40 +03:00
Sercan Yemen 51ab577b71 fuse2... 2017-07-13 17:43:22 +03:00
Sercan Yemen 6e219181da fuse2... 2017-07-12 18:13:08 +03:00
Sercan Yemen 6f159f54c8 fuse2... 2017-07-12 17:34:32 +03:00
Sercan Yemen a8844e8b46 fuse2... 2017-07-12 15:35:07 +03:00
mustafahlvc 829f570913 Nav Collapse arrow icon and animation added 2017-07-10 05:59:30 +03:00
mustafahlvc b7ef64154d Making navigation better 2017-07-09 13:38:38 +03:00
mustafahlvc e98e37402a Navigation service added, basic collapse functionality added to navigation, expand navigated item.. 2017-07-09 01:21:25 +03:00
mustafahlvc b5cc591ccc Removed unnecessary components 2017-07-08 19:14:57 +03:00
mustafahlvc c3e241c81c Layout Service created,
Starting the build navigation,
Some Components added for tests.
2017-07-08 19:12:52 +03:00
mustafahlvc f21eaa57bb Init. 2017-07-04 12:42:00 +03:00
Angular CLI 18e3c4abb8 chore: initial commit from @angular/cli 2017-06-27 11:08:19 +03:00
686 changed files with 24709 additions and 90834 deletions
+58
View File
@@ -0,0 +1,58 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "fuse2"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.scss"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"hmr": "environments/environment.hmr.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"component": {}
}
}
+1 -5
View File
@@ -1,16 +1,12 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false
-95
View File
@@ -1,95 +0,0 @@
{
"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": {}
}
]
}
+4 -8
View File
@@ -4,15 +4,10 @@
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
# IDEs and editors
/.idea
.project
@@ -28,19 +23,20 @@ chrome-profiler-events*.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db
+1 -1
View File
@@ -1 +1 @@
legacy-peer-deps=true
save-prefix=''
-1
View File
@@ -1 +0,0 @@
20
-72
View File
@@ -1,72 +0,0 @@
// -----------------------------------------------------------------------------------------------------
// @ 3rd party credits
// -----------------------------------------------------------------------------------------------------
// Flags
https://github.com/Yummygum/flagpack-core
// Icons
Material - https://material.io/tools/icons
Feather - https://feathericons.com/
Heroicons - https://github.com/refactoringui/heroicons
Iconsmind - https://iconsmind.com/
// Avatars
https://uifaces.co
// 404, 500 & Maintenance
https://undraw.co
// Mail app
Photo by Riccardo Chiarini on Unsplash - https://unsplash.com/photos/2VDa8bnLM8c
Photo by Johannes Plenio on Unsplash - https://unsplash.com/photos/RwHv7LgeC7s
Photo by Jamie Davies on Unsplash - https://unsplash.com/photos/Hao52Fu9-F8
Photo by Christian Joudrey on Unsplash - https://unsplash.com/photos/mWRR1xj95hg
// Profile page
Photo by Alex Knight on Unsplash - https://unsplash.com/photos/DpPutJwgyW8
// Cards
Photo by Kym Ellis on Unsplash - https://unsplash.com/photos/RPT3AjdXlZc
Photo by Patrick Hendry on Unsplash - https://unsplash.com/photos/Qgxk3PQsMiI
Photo by Hailey Kean on Unsplash - https://unsplash.com/photos/QxjsOlFNr_4
Photo by Nathan Anderson on Unsplash - https://unsplash.com/photos/mG8ShlWrMDI
Photo by Adrian Infernus on Unsplash - https://unsplash.com/photos/5apewqWk978
Photo by freestocks.org on Unsplash - https://unsplash.com/photos/c73TZ2sIU38
Photo by Tim Marshall on Unsplash - https://unsplash.com/photos/PKSCrmZdvwA
Photo by Daniel Koponyas on Unsplash - https://unsplash.com/photos/rbiLY6ZwvXQ
Photo by John Westrock on Unsplash - https://unsplash.com/photos/LCesauDseu8
Photo by Gabriel Sollmann on Unsplash - https://unsplash.com/photos/kFWj9y-tJB4
Photo by Kevin Wolf on Unsplash - https://unsplash.com/photos/BJyjgEdNTPs
Photo by Luca Bravo on Unsplash - https://unsplash.com/photos/hFzIoD0F_i8
Photo by Ian Baldwin on Unsplash - https://unsplash.com/photos/Dlj-SxxTlQ0
Photo by Ben Kolde on Unsplash - https://unsplash.com/photos/KRTFIBOfcFw
Photo by Chad Peltola on Unsplash - https://unsplash.com/photos/BTvQ2ET_iKc
Photo by rocknwool on Unsplash - https://unsplash.com/photos/r56oO1V5oms
Photo by Vita Vilcina on Unsplash - https://unsplash.com/photos/KtOid0FLjqU
Photo by Jia Ye on Unsplash - https://unsplash.com/photos/y8ZnQqgohLk
Photo by Parker Whitson on Unsplash - https://unsplash.com/photos/OlTYIqTjmVM
Photo by Dorian Hurst on Unsplash - https://unsplash.com/photos/a9uWPQlIbYc
Photo by Everaldo Coelho on Unsplash - https://unsplash.com/photos/KPaSCpklCZw
Photo by eberhard grossgasteiger on Unsplash - https://unsplash.com/photos/fh2JefbNlII
Photo by Orlova Maria on Unsplash - https://unsplash.com/photos/p8y4dWEMGMU
Photo by Jake Blucker on Unsplash - https://unsplash.com/photos/tMzCrBkM99Y
Photo by Jerry Zhang on Unsplash - https://unsplash.com/photos/oIBcow6n36s
Photo by John Cobb on Unsplash - https://unsplash.com/photos/IE_sifhay7o
Photo by Dan Gold on Unsplash - https://unsplash.com/photos/mDlhOIfGxNI
Photo by Ana Toma on Unsplash - https://unsplash.com/photos/XsGwe6gYg0c
Photo by Andrea on Unsplash - https://unsplash.com/photos/1AWY0N960Sk
Photo by Aswin on Unsplash - https://unsplash.com/photos/_roUcFWstas
Photo by Justin Kauffman on Unsplash - https://unsplash.com/photos/aWG_dqyhI0A
Photo by Barna Bartis on Unsplash - https://unsplash.com/photos/VVoBQqWrvkc
Photo by Kyle Hinkson on Unsplash - https://unsplash.com/photos/3439EnvnAGo
Photo by Spencer Watson on Unsplash - https://unsplash.com/photos/5TBf16GnHKg
Photo by adrian on Unsplash - https://unsplash.com/photos/1wrzvwoK8A4
Photo by Christopher Rusev on Unsplash - https://unsplash.com/photos/7gKWgCRixf0
Photo by Stephen Leonardi on Unsplash - https://unsplash.com/photos/MDmwQVgDHHM
Photo by Dwinanda Nurhanif Mujito on Unsplash - https://unsplash.com/photos/pKT5Mg16w_w
Photo by Humphrey Muleba on Unsplash - https://unsplash.com/photos/Zuvf5mxT5fs
Photo by adrian on Unsplash - https://unsplash.com/photos/PNRxLFPMyJY
Photo by Dahee Son on Unsplash - https://unsplash.com/photos/tV06QVJXVxU
Photo by Zachary Kyra-Derksen on Unsplash - https://unsplash.com/photos/vkqS7vLQUtg
Photo by Rodrigo Soares on Unsplash - https://unsplash.com/photos/8BFWBUkSqQo
-6
View File
@@ -1,6 +0,0 @@
Envato Standard License
Copyright (c) Sercan Yemen <sercanyemen@gmail.com>
This project is protected by Envato's Standard License. For more information,
check the official license page at [https://themeforest.net/licenses/standard](https://themeforest.net/licenses/standard)
+7 -10
View File
@@ -1,18 +1,18 @@
# Fuse - Admin template and Starter project for Angular
# Fuse2
This project was generated with [Angular CLI](https://github.com/angular/angular-cli)
Material Design Admin Template with Angular 4+ and Angular Material 2
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
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.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
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.
## Running unit tests
@@ -20,8 +20,5 @@ 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 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 Overview and Command Reference](https://angular.io/cli) page.
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
-130
View File
@@ -1,130 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"fuse": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/fuse",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": [
"apexcharts",
"highlight.js",
"crypto-js/enc-utf8",
"crypto-js/hmac-sha256",
"crypto-js/enc-base64",
"flat",
"quill"
],
"assets": [
"src/favicon-16x16.png",
"src/favicon-32x32.png",
"src/assets",
{
"glob": "_redirects",
"input": "src",
"output": "/"
}
],
"stylePreprocessorOptions": {
"includePaths": [
"src/@fuse/styles"
]
},
"styles": [
"src/@fuse/styles/tailwind.scss",
"src/@fuse/styles/themes.scss",
"src/styles/vendors.scss",
"src/@fuse/styles/main.scss",
"src/styles/styles.scss",
"src/styles/tailwind.scss"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "3mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "75kb",
"maximumError": "90kb"
}
],
"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",
"configurations": {
"production": {
"buildTarget": "fuse:build:production"
},
"development": {
"buildTarget": "fuse:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "fuse:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon-16x16.png",
"src/favicon-32x32.png",
"src/assets"
],
"styles": [
"src/styles/styles.scss"
],
"scripts": []
}
}
}
}
}
}
+14
View File
@@ -0,0 +1,14 @@
import { Fuse2Page } from './app.po';
describe('fuse2 App', () => {
let page: Fuse2Page;
beforeEach(() => {
page = new Fuse2Page();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!!');
});
});
+11
View File
@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class Fuse2Page {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"node"
]
}
}
+33
View File
@@ -0,0 +1,33 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
+10391 -24961
View File
File diff suppressed because it is too large Load Diff
+70 -64
View File
@@ -1,66 +1,72 @@
{
"name": "fuse-angular",
"version": "19.0.0",
"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",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"dependencies": {
"@angular/animations": "17.0.3",
"@angular/cdk": "17.0.1",
"@angular/common": "17.0.3",
"@angular/compiler": "17.0.3",
"@angular/core": "17.0.3",
"@angular/forms": "17.0.3",
"@angular/material": "17.0.1",
"@angular/material-luxon-adapter": "17.0.1",
"@angular/platform-browser": "17.0.3",
"@angular/platform-browser-dynamic": "17.0.3",
"@angular/router": "17.0.3",
"@ngneat/transloco": "6.0.0",
"apexcharts": "3.44.0",
"crypto-js": "3.3.0",
"highlight.js": "11.9.0",
"lodash-es": "4.17.21",
"luxon": "3.4.4",
"ng-apexcharts": "1.8.0",
"ngx-quill": "24.0.2",
"perfect-scrollbar": "1.5.5",
"quill": "1.3.7",
"rxjs": "7.8.1",
"tslib": "2.6.2",
"zone.js": "0.14.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "17.0.1",
"@angular/cli": "17.0.1",
"@angular/compiler-cli": "17.0.3",
"@tailwindcss/typography": "0.5.10",
"@types/chroma-js": "2.4.3",
"@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0",
"@types/jasmine": "5.1.2",
"@types/lodash": "4.14.201",
"@types/lodash-es": "4.17.11",
"@types/luxon": "3.3.4",
"autoprefixer": "10.4.16",
"chroma-js": "2.4.2",
"jasmine-core": "5.1.1",
"karma": "6.4.2",
"karma-chrome-launcher": "3.2.0",
"karma-coverage": "2.2.1",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.0.0",
"lodash": "4.17.21",
"postcss": "8.4.31",
"tailwindcss": "3.3.5",
"typescript": "5.2.2"
}
"name": "fuse2",
"version": "1.1.2",
"license": "",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build",
"build-prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@agm/core": "1.0.0-beta.1",
"@angular/animations": "4.4.5",
"@angular/cdk": "2.0.0-beta.12",
"@angular/common": "4.4.5",
"@angular/compiler": "4.4.5",
"@angular/core": "4.4.5",
"@angular/flex-layout": "2.0.0-beta.9",
"@angular/forms": "4.4.5",
"@angular/http": "4.4.5",
"@angular/material": "2.0.0-beta.12",
"@angular/platform-browser": "4.4.5",
"@angular/platform-browser-dynamic": "4.4.5",
"@angular/router": "4.4.5",
"@swimlane/ngx-charts": "6.0.2",
"@swimlane/ngx-datatable": "9.3.1",
"@swimlane/ngx-dnd": "3.0.0",
"angular-calendar": "0.21.2",
"angular-in-memory-web-api": "0.5.0",
"classlist.js": "1.1.20150312",
"core-js": "2.5.1",
"d3": "4.10.0",
"hammerjs": "2.0.8",
"highlight.js": "9.12.0",
"intl": "1.2.5",
"moment": "2.19.1",
"ngx-color-picker": "4.4.0",
"ngx-cookie-service": "1.0.9",
"perfect-scrollbar": "1.0.3",
"rxjs": "5.4.3",
"web-animations-js": "2.3.1",
"zone.js": "0.8.18"
},
"devDependencies": {
"@angular/cli": "1.4.7",
"@angular/compiler-cli": "4.4.5",
"@angular/language-service": "4.4.5",
"@angularclass/hmr": "2.1.3",
"@types/jasmine": "2.6.0",
"@types/jasminewd2": "2.0.2",
"@types/node": "6.0.88",
"codelyzer": "3.2.0",
"jasmine-core": "2.6.2",
"jasmine-spec-reporter": "4.1.0",
"karma": "1.7.1",
"karma-chrome-launcher": "2.1.1",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.2.1",
"karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "0.2.2",
"protractor": "5.1.2",
"ts-node": "3.2.0",
"tslint": "5.7.0",
"typescript": "2.3.3"
}
}
+28
View File
@@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
-14
View File
@@ -1,14 +0,0 @@
export class FuseAnimationCurves
{
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';
}
-34
View File
@@ -1,34 +0,0 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { FuseAnimationCurves, FuseAnimationDurations } from '@fuse/animations/defaults';
// -----------------------------------------------------------------------------------------------------
// @ Expand / collapse
// -----------------------------------------------------------------------------------------------------
const expandCollapse = trigger('expandCollapse',
[
state('void, collapsed',
style({
height: '0',
}),
),
state('*, expanded',
style('*'),
),
// Prevent the transition if the state is false
transition('void <=> false, collapsed <=> false, expanded <=> false', []),
// Transition
transition('void <=> *, collapsed <=> expanded',
animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
export { expandCollapse };
-330
View File
@@ -1,330 +0,0 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { FuseAnimationCurves, FuseAnimationDurations } from '@fuse/animations/defaults';
// -----------------------------------------------------------------------------------------------------
// @ Fade in
// -----------------------------------------------------------------------------------------------------
const fadeIn = trigger('fadeIn',
[
state('void',
style({
opacity: 0,
}),
),
state('*',
style({
opacity: 1,
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade in top
// -----------------------------------------------------------------------------------------------------
const fadeInTop = trigger('fadeInTop',
[
state('void',
style({
opacity : 0,
transform: 'translate3d(0, -100%, 0)',
}),
),
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade in bottom
// -----------------------------------------------------------------------------------------------------
const fadeInBottom = trigger('fadeInBottom',
[
state('void',
style({
opacity : 0,
transform: 'translate3d(0, 100%, 0)',
}),
),
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade in left
// -----------------------------------------------------------------------------------------------------
const fadeInLeft = trigger('fadeInLeft',
[
state('void',
style({
opacity : 0,
transform: 'translate3d(-100%, 0, 0)',
}),
),
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade in right
// -----------------------------------------------------------------------------------------------------
const fadeInRight = trigger('fadeInRight',
[
state('void',
style({
opacity : 0,
transform: 'translate3d(100%, 0, 0)',
}),
),
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade out
// -----------------------------------------------------------------------------------------------------
const fadeOut = trigger('fadeOut',
[
state('*',
style({
opacity: 1,
}),
),
state('void',
style({
opacity: 0,
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade out top
// -----------------------------------------------------------------------------------------------------
const fadeOutTop = trigger('fadeOutTop',
[
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
opacity : 0,
transform: 'translate3d(0, -100%, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade out bottom
// -----------------------------------------------------------------------------------------------------
const fadeOutBottom = trigger('fadeOutBottom',
[
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
opacity : 0,
transform: 'translate3d(0, 100%, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade out left
// -----------------------------------------------------------------------------------------------------
const fadeOutLeft = trigger('fadeOutLeft',
[
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
opacity : 0,
transform: 'translate3d(-100%, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Fade out right
// -----------------------------------------------------------------------------------------------------
const fadeOutRight = trigger('fadeOutRight',
[
state('*',
style({
opacity : 1,
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
opacity : 0,
transform: 'translate3d(100%, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
export { fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight, fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight };
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/animations/public-api';
-15
View File
@@ -1,15 +0,0 @@
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 = [
expandCollapse,
fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight,
fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight,
shake,
slideInTop, slideInBottom, slideInLeft, slideInRight,
slideOutTop, slideOutBottom, slideOutLeft, slideOutRight,
zoomIn, zoomOut,
];
-73
View File
@@ -1,73 +0,0 @@
import { animate, keyframes, style, transition, trigger } from '@angular/animations';
// -----------------------------------------------------------------------------------------------------
// @ Shake
// -----------------------------------------------------------------------------------------------------
const shake = trigger('shake',
[
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *, * => true',
[
animate('{{timings}}',
keyframes([
style({
transform: 'translate3d(0, 0, 0)',
offset : 0,
}),
style({
transform: 'translate3d(-10px, 0, 0)',
offset : 0.1,
}),
style({
transform: 'translate3d(10px, 0, 0)',
offset : 0.2,
}),
style({
transform: 'translate3d(-10px, 0, 0)',
offset : 0.3,
}),
style({
transform: 'translate3d(10px, 0, 0)',
offset : 0.4,
}),
style({
transform: 'translate3d(-10px, 0, 0)',
offset : 0.5,
}),
style({
transform: 'translate3d(10px, 0, 0)',
offset : 0.6,
}),
style({
transform: 'translate3d(-10px, 0, 0)',
offset : 0.7,
}),
style({
transform: 'translate3d(10px, 0, 0)',
offset : 0.8,
}),
style({
transform: 'translate3d(-10px, 0, 0)',
offset : 0.9,
}),
style({
transform: 'translate3d(0, 0, 0)',
offset : 1,
}),
]),
),
],
{
params: {
timings: '0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955)',
},
},
),
],
);
export { shake };
-252
View File
@@ -1,252 +0,0 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { FuseAnimationCurves, FuseAnimationDurations } from '@fuse/animations/defaults';
// -----------------------------------------------------------------------------------------------------
// @ Slide in top
// -----------------------------------------------------------------------------------------------------
const slideInTop = trigger('slideInTop',
[
state('void',
style({
transform: 'translate3d(0, -100%, 0)',
}),
),
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide in bottom
// -----------------------------------------------------------------------------------------------------
const slideInBottom = trigger('slideInBottom',
[
state('void',
style({
transform: 'translate3d(0, 100%, 0)',
}),
),
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide in left
// -----------------------------------------------------------------------------------------------------
const slideInLeft = trigger('slideInLeft',
[
state('void',
style({
transform: 'translate3d(-100%, 0, 0)',
}),
),
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide in right
// -----------------------------------------------------------------------------------------------------
const slideInRight = trigger('slideInRight',
[
state('void',
style({
transform: 'translate3d(100%, 0, 0)',
}),
),
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide out top
// -----------------------------------------------------------------------------------------------------
const slideOutTop = trigger('slideOutTop',
[
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
transform: 'translate3d(0, -100%, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide out bottom
// -----------------------------------------------------------------------------------------------------
const slideOutBottom = trigger('slideOutBottom',
[
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
transform: 'translate3d(0, 100%, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide out left
// -----------------------------------------------------------------------------------------------------
const slideOutLeft = trigger('slideOutLeft',
[
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
transform: 'translate3d(-100%, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Slide out right
// -----------------------------------------------------------------------------------------------------
const slideOutRight = trigger('slideOutRight',
[
state('*',
style({
transform: 'translate3d(0, 0, 0)',
}),
),
state('void',
style({
transform: 'translate3d(100%, 0, 0)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
export { slideInTop, slideInBottom, slideInLeft, slideInRight, slideOutTop, slideOutBottom, slideOutLeft, slideOutRight };
-73
View File
@@ -1,73 +0,0 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { FuseAnimationCurves, FuseAnimationDurations } from '@fuse/animations/defaults';
// -----------------------------------------------------------------------------------------------------
// @ Zoom in
// -----------------------------------------------------------------------------------------------------
const zoomIn = trigger('zoomIn',
[
state('void',
style({
opacity : 0,
transform: 'scale(0.5)',
}),
),
state('*',
style({
opacity : 1,
transform: 'scale(1)',
}),
),
// Prevent the transition if the state is false
transition('void => false', []),
// Transition
transition('void => *', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
},
},
),
],
);
// -----------------------------------------------------------------------------------------------------
// @ Zoom out
// -----------------------------------------------------------------------------------------------------
const zoomOut = trigger('zoomOut',
[
state('*',
style({
opacity : 1,
transform: 'scale(1)',
}),
),
state('void',
style({
opacity : 0,
transform: 'scale(0.5)',
}),
),
// Prevent the transition if the state is false
transition('false => void', []),
// Transition
transition('* => void', animate('{{timings}}'),
{
params: {
timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
},
},
),
],
);
export { zoomIn, zoomOut };
@@ -1,82 +0,0 @@
<div
class="fuse-alert-container"
*ngIf="!dismissible || dismissible && !dismissed"
[@fadeIn]="!dismissed"
[@fadeOut]="!dismissed">
<!-- Border -->
<div
class="fuse-alert-border"
*ngIf="appearance === 'border'"></div>
<!-- Icon -->
<div
class="fuse-alert-icon"
*ngIf="showIcon">
<!-- Custom icon -->
<div class="fuse-alert-custom-icon">
<ng-content select="[fuseAlertIcon]"></ng-content>
</div>
<!-- Default icons -->
<div class="fuse-alert-default-icon">
<mat-icon
*ngIf="type === 'primary'"
[svgIcon]="'heroicons_solid:check-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'accent'"
[svgIcon]="'heroicons_solid:check-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'warn'"
[svgIcon]="'heroicons_solid:x-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'basic'"
[svgIcon]="'heroicons_solid:check-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'info'"
[svgIcon]="'heroicons_solid:information-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'success'"
[svgIcon]="'heroicons_solid:check-circle'"></mat-icon>
<mat-icon
*ngIf="type === 'warning'"
[svgIcon]="'heroicons_solid:exclamation-triangle'"></mat-icon>
<mat-icon
*ngIf="type === 'error'"
[svgIcon]="'heroicons_solid:x-circle'"></mat-icon>
</div>
</div>
<!-- Content -->
<div class="fuse-alert-content">
<div class="fuse-alert-title">
<ng-content select="[fuseAlertTitle]"></ng-content>
</div>
<div class="fuse-alert-message">
<ng-content></ng-content>
</div>
</div>
<!-- Dismiss button -->
<button
class="fuse-alert-dismiss-button"
mat-icon-button
(click)="dismiss()">
<mat-icon [svgIcon]="'heroicons_solid:x-mark'"></mat-icon>
</button>
</div>
File diff suppressed because it is too large Load Diff
@@ -1,219 +0,0 @@
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { fuseAnimations } from '@fuse/animations';
import { FuseAlertService } from '@fuse/components/alert/alert.service';
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-alert',
templateUrl : './alert.component.html',
styleUrls : ['./alert.component.scss'],
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
animations : fuseAnimations,
exportAs : 'fuseAlert',
standalone : true,
imports : [NgIf, MatIconModule, MatButtonModule],
})
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;
@Input() dismissible: boolean = false;
@Input() name: string = this._fuseUtilsService.randomId();
@Input() showIcon: boolean = true;
@Input() type: FuseAlertType = 'primary';
@Output() readonly dismissedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseAlertService: FuseAlertService,
private _fuseUtilsService: FuseUtilsService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component classes
*/
@HostBinding('class') get classList(): any
{
/* eslint-disable @typescript-eslint/naming-convention */
return {
'fuse-alert-appearance-border' : this.appearance === 'border',
'fuse-alert-appearance-fill' : this.appearance === 'fill',
'fuse-alert-appearance-outline': this.appearance === 'outline',
'fuse-alert-appearance-soft' : this.appearance === 'soft',
'fuse-alert-dismissed' : this.dismissed,
'fuse-alert-dismissible' : this.dismissible,
'fuse-alert-show-icon' : this.showIcon,
'fuse-alert-type-primary' : this.type === 'primary',
'fuse-alert-type-accent' : this.type === 'accent',
'fuse-alert-type-warn' : this.type === 'warn',
'fuse-alert-type-basic' : this.type === 'basic',
'fuse-alert-type-info' : this.type === 'info',
'fuse-alert-type-success' : this.type === 'success',
'fuse-alert-type-warning' : this.type === 'warning',
'fuse-alert-type-error' : this.type === 'error',
};
/* eslint-enable @typescript-eslint/naming-convention */
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Dismissed
if ( 'dismissed' in changes )
{
// Coerce the value to a boolean
this.dismissed = coerceBooleanProperty(changes.dismissed.currentValue);
// Dismiss/show the alert
this._toggleDismiss(this.dismissed);
}
// Dismissible
if ( 'dismissible' in changes )
{
// Coerce the value to a boolean
this.dismissible = coerceBooleanProperty(changes.dismissible.currentValue);
}
// Show icon
if ( 'showIcon' in changes )
{
// Coerce the value to a boolean
this.showIcon = coerceBooleanProperty(changes.showIcon.currentValue);
}
}
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to the dismiss calls
this._fuseAlertService.onDismiss
.pipe(
filter(name => this.name === name),
takeUntil(this._unsubscribeAll),
)
.subscribe(() =>
{
// Dismiss the alert
this.dismiss();
});
// Subscribe to the show calls
this._fuseAlertService.onShow
.pipe(
filter(name => this.name === name),
takeUntil(this._unsubscribeAll),
)
.subscribe(() =>
{
// Show the alert
this.show();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Dismiss the alert
*/
dismiss(): void
{
// Return if the alert is already dismissed
if ( this.dismissed )
{
return;
}
// Dismiss the alert
this._toggleDismiss(true);
}
/**
* Show the dismissed alert
*/
show(): void
{
// Return if the alert is already showing
if ( !this.dismissed )
{
return;
}
// Show the alert
this._toggleDismiss(false);
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Dismiss/show the alert
*
* @param dismissed
* @private
*/
private _toggleDismiss(dismissed: boolean): void
{
// Return if the alert is not dismissible
if ( !this.dismissible )
{
return;
}
// Set the dismissed
this.dismissed = dismissed;
// Execute the observable
this.dismissedChanged.next(this.dismissed);
// Notify the change detector
this._changeDetectorRef.markForCheck();
}
}
@@ -1,75 +0,0 @@
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
@Injectable({providedIn: 'root'})
export class FuseAlertService
{
private readonly _onDismiss: ReplaySubject<string> = new ReplaySubject<string>(1);
private readonly _onShow: ReplaySubject<string> = new ReplaySubject<string>(1);
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for onDismiss
*/
get onDismiss(): Observable<any>
{
return this._onDismiss.asObservable();
}
/**
* Getter for onShow
*/
get onShow(): Observable<any>
{
return this._onShow.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Dismiss the alert
*
* @param name
*/
dismiss(name: string): void
{
// Return if the name is not provided
if ( !name )
{
return;
}
// Execute the observable
this._onDismiss.next(name);
}
/**
* Show the dismissed alert
*
* @param name
*/
show(name: string): void
{
// Return if the name is not provided
if ( !name )
{
return;
}
// Execute the observable
this._onShow.next(name);
}
}
-15
View File
@@ -1,15 +0,0 @@
export type FuseAlertAppearance =
| 'border'
| 'fill'
| 'outline'
| 'soft';
export type FuseAlertType =
| 'primary'
| 'accent'
| 'warn'
| 'basic'
| 'info'
| 'success'
| 'warning'
| 'error';
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/alert/public-api';
-3
View File
@@ -1,3 +0,0 @@
export * from '@fuse/components/alert/alert.component';
export * from '@fuse/components/alert/alert.service';
export * from '@fuse/components/alert/alert.types';
@@ -1,30 +0,0 @@
<!-- Flippable card -->
<ng-container *ngIf="flippable">
<!-- Front -->
<div class="fuse-card-front">
<ng-content select="[fuseCardFront]"></ng-content>
</div>
<!-- Back -->
<div class="fuse-card-back">
<ng-content select="[fuseCardBack]"></ng-content>
</div>
</ng-container>
<!-- Normal card -->
<ng-container *ngIf="!flippable">
<!-- Content -->
<ng-content></ng-content>
<!-- Expansion -->
<div
class="fuse-card-expansion"
*ngIf="expanded"
[@expandCollapse]>
<ng-content select="[fuseCardExpansion]"></ng-content>
</div>
</ng-container>
@@ -1,63 +0,0 @@
fuse-card {
position: relative;
display: flex;
overflow: hidden;
@apply rounded-2xl shadow bg-card;
/* Flippable */
&.fuse-card-flippable {
border-radius: 0;
overflow: visible;
transform-style: preserve-3d;
transition: transform 1s;
perspective: 600px;
background: transparent;
@apply shadow-none;
&.fuse-card-face-back {
.fuse-card-front {
visibility: hidden;
opacity: 0;
transform: rotateY(180deg);
}
.fuse-card-back {
visibility: visible;
opacity: 1;
transform: rotateY(360deg);
}
}
.fuse-card-front,
.fuse-card-back {
display: flex;
flex-direction: column;
flex: 1 1 auto;
z-index: 10;
transition: transform 0.5s ease-out 0s, visibility 0s ease-in 0.2s, opacity 0s ease-in 0.2s;
backface-visibility: hidden;
@apply rounded-2xl shadow bg-card;
}
.fuse-card-front {
position: relative;
opacity: 1;
visibility: visible;
transform: rotateY(0deg);
overflow: hidden;
}
.fuse-card-back {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
visibility: hidden;
transform: rotateY(180deg);
overflow: hidden auto;
}
}
}
@@ -1,79 +0,0 @@
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { NgIf } from '@angular/common';
import { Component, HostBinding, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { FuseCardFace } from '@fuse/components/card/card.types';
@Component({
selector : 'fuse-card',
templateUrl : './card.component.html',
styleUrls : ['./card.component.scss'],
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations,
exportAs : 'fuseCard',
standalone : true,
imports : [NgIf],
})
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';
@Input() flippable: boolean = false;
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component classes
*/
@HostBinding('class') get classList(): any
{
/* eslint-disable @typescript-eslint/naming-convention */
return {
'fuse-card-expanded' : this.expanded,
'fuse-card-face-back' : this.flippable && this.face === 'back',
'fuse-card-face-front': this.flippable && this.face === 'front',
'fuse-card-flippable' : this.flippable,
};
/* eslint-enable @typescript-eslint/naming-convention */
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Expanded
if ( 'expanded' in changes )
{
// Coerce the value to a boolean
this.expanded = coerceBooleanProperty(changes.expanded.currentValue);
}
// Flippable
if ( 'flippable' in changes )
{
// Coerce the value to a boolean
this.flippable = coerceBooleanProperty(changes.flippable.currentValue);
}
}
}
-3
View File
@@ -1,3 +0,0 @@
export type FuseCardFace =
| 'front'
| 'back';
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/card/public-api';
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/card/card.component';
@@ -1,3 +0,0 @@
<div class="fuse-drawer-content">
<ng-content></ng-content>
</div>
@@ -1,133 +0,0 @@
/* Variables */
:root {
--fuse-drawer-width: 320px;
}
fuse-drawer {
position: relative;
display: flex;
flex-direction: column;
flex: 1 1 auto;
width: var(--fuse-drawer-width);
min-width: var(--fuse-drawer-width);
max-width: var(--fuse-drawer-width);
z-index: 300;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .35);
@apply bg-card;
/* Animations */
&.fuse-drawer-animations-enabled {
transition-duration: 400ms;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
transition-property: visibility, margin-left, margin-right, transform, width, max-width, min-width;
.fuse-drawer-content {
transition-duration: 400ms;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
transition-property: width, max-width, min-width;
}
}
/* Over mode */
&.fuse-drawer-mode-over {
position: absolute;
top: 0;
bottom: 0;
/* Fixed mode */
&.fuse-drawer-fixed {
position: fixed;
}
}
/* Left position */
&.fuse-drawer-position-left {
/* Side mode */
&.fuse-drawer-mode-side {
margin-left: calc(var(--fuse-drawer-width) * -1);
&.fuse-drawer-opened {
margin-left: 0;
}
}
/* Over mode */
&.fuse-drawer-mode-over {
left: 0;
transform: translate3d(-100%, 0, 0);
&.fuse-drawer-opened {
transform: translate3d(0, 0, 0);
}
}
/* Content */
.fuse-drawer-content {
left: 0;
}
}
/* Right position */
&.fuse-drawer-position-right {
/* Side mode */
&.fuse-drawer-mode-side {
margin-right: calc(var(--fuse-drawer-width) * -1);
&.fuse-drawer-opened {
margin-right: 0;
}
}
/* Over mode */
&.fuse-drawer-mode-over {
right: 0;
transform: translate3d(100%, 0, 0);
&.fuse-drawer-opened {
transform: translate3d(0, 0, 0);
}
}
/* Content */
.fuse-drawer-content {
right: 0;
}
}
/* Content */
.fuse-drawer-content {
position: absolute;
display: flex;
flex: 1 1 auto;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
overflow: hidden;
@apply bg-card;
}
}
/* Overlay */
.fuse-drawer-overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 299;
opacity: 1;
background-color: rgba(0, 0, 0, 0.6);
/* Fixed mode */
&.fuse-drawer-overlay-fixed {
position: fixed;
}
/* Transparent overlay */
&.fuse-drawer-overlay-transparent {
background-color: transparent;
}
}
@@ -1,429 +0,0 @@
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { FuseDrawerService } from '@fuse/components/drawer/drawer.service';
import { FuseDrawerMode, FuseDrawerPosition } from '@fuse/components/drawer/drawer.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-drawer',
templateUrl : './drawer.component.html',
styleUrls : ['./drawer.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseDrawer',
standalone : true,
})
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';
@Input() name: string = this._fuseUtilsService.randomId();
@Input() opened: boolean = false;
@Input() position: FuseDrawerPosition = 'left';
@Input() transparentOverlay: boolean = false;
@Output() readonly fixedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() readonly modeChanged: EventEmitter<FuseDrawerMode> = new EventEmitter<FuseDrawerMode>();
@Output() readonly openedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() readonly positionChanged: EventEmitter<FuseDrawerPosition> = new EventEmitter<FuseDrawerPosition>();
private _animationsEnabled: boolean = false;
private readonly _handleOverlayClick: any;
private _hovered: boolean = false;
private _overlay: HTMLElement;
private _player: AnimationPlayer;
/**
* Constructor
*/
constructor(
private _animationBuilder: AnimationBuilder,
private _elementRef: ElementRef,
private _renderer2: Renderer2,
private _fuseDrawerService: FuseDrawerService,
private _fuseUtilsService: FuseUtilsService,
)
{
this._handleOverlayClick = (): void =>
{
this.close();
};
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component classes
*/
@HostBinding('class') get classList(): any
{
/* eslint-disable @typescript-eslint/naming-convention */
return {
'fuse-drawer-animations-enabled' : this._animationsEnabled,
'fuse-drawer-fixed' : this.fixed,
'fuse-drawer-hover' : this._hovered,
[`fuse-drawer-mode-${this.mode}`] : true,
'fuse-drawer-opened' : this.opened,
[`fuse-drawer-position-${this.position}`]: true,
};
/* eslint-enable @typescript-eslint/naming-convention */
}
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'visibility': this.opened ? 'visible' : 'hidden',
};
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Fixed
if ( 'fixed' in changes )
{
// Coerce the value to a boolean
this.fixed = coerceBooleanProperty(changes.fixed.currentValue);
// Execute the observable
this.fixedChanged.next(this.fixed);
}
// Mode
if ( 'mode' in changes )
{
// Get the previous and current values
const previousMode = changes.mode.previousValue;
const currentMode = changes.mode.currentValue;
// Disable the animations
this._disableAnimations();
// If the mode changes: 'over -> side'
if ( previousMode === 'over' && currentMode === 'side' )
{
// Hide the overlay
this._hideOverlay();
}
// If the mode changes: 'side -> over'
if ( previousMode === 'side' && currentMode === 'over' )
{
// If the drawer is opened
if ( this.opened )
{
// Show the overlay
this._showOverlay();
}
}
// Execute the observable
this.modeChanged.next(currentMode);
// Enable the animations after a delay
// The delay must be bigger than the current transition-duration
// to make sure nothing will be animated while the mode is changing
setTimeout(() =>
{
this._enableAnimations();
}, 500);
}
// Opened
if ( 'opened' in changes )
{
// Coerce the value to a boolean
const open = coerceBooleanProperty(changes.opened.currentValue);
// Open/close the drawer
this._toggleOpened(open);
}
// Position
if ( 'position' in changes )
{
// Execute the observable
this.positionChanged.next(this.position);
}
// Transparent overlay
if ( 'transparentOverlay' in changes )
{
// Coerce the value to a boolean
this.transparentOverlay = coerceBooleanProperty(changes.transparentOverlay.currentValue);
}
}
/**
* On init
*/
ngOnInit(): void
{
// Register the drawer
this._fuseDrawerService.registerComponent(this.name, this);
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Finish the animation
if ( this._player )
{
this._player.finish();
}
// Deregister the drawer from the registry
this._fuseDrawerService.deregisterComponent(this.name);
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the drawer
*/
open(): void
{
// Return if the drawer has already opened
if ( this.opened )
{
return;
}
// Open the drawer
this._toggleOpened(true);
}
/**
* Close the drawer
*/
close(): void
{
// Return if the drawer has already closed
if ( !this.opened )
{
return;
}
// Close the drawer
this._toggleOpened(false);
}
/**
* Toggle the drawer
*/
toggle(): void
{
if ( this.opened )
{
this.close();
}
else
{
this.open();
}
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Enable the animations
*
* @private
*/
private _enableAnimations(): void
{
// Return if the animations are already enabled
if ( this._animationsEnabled )
{
return;
}
// Enable the animations
this._animationsEnabled = true;
}
/**
* Disable the animations
*
* @private
*/
private _disableAnimations(): void
{
// Return if the animations are already disabled
if ( !this._animationsEnabled )
{
return;
}
// Disable the animations
this._animationsEnabled = false;
}
/**
* Show the backdrop
*
* @private
*/
private _showOverlay(): void
{
// Create the backdrop element
this._overlay = this._renderer2.createElement('div');
// Add a class to the backdrop element
this._overlay.classList.add('fuse-drawer-overlay');
// Add a class depending on the fixed option
if ( this.fixed )
{
this._overlay.classList.add('fuse-drawer-overlay-fixed');
}
// Add a class depending on the transparentOverlay option
if ( this.transparentOverlay )
{
this._overlay.classList.add('fuse-drawer-overlay-transparent');
}
// Append the backdrop to the parent of the drawer
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay);
// Create 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);
// Play the animation
this._player.play();
// Add an event listener to the overlay
this._overlay.addEventListener('click', this._handleOverlayClick);
}
/**
* Hide the backdrop
*
* @private
*/
private _hideOverlay(): void
{
if ( !this._overlay )
{
return;
}
// Create the leave animation and attach it to the player
this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._overlay);
// Play the animation
this._player.play();
// Once the animation is done...
this._player.onDone(() =>
{
// If the overlay still exists...
if ( this._overlay )
{
// Remove the event listener
this._overlay.removeEventListener('click', this._handleOverlayClick);
// Remove the overlay
this._overlay.parentNode.removeChild(this._overlay);
this._overlay = null;
}
});
}
/**
* Open/close the drawer
*
* @param open
* @private
*/
private _toggleOpened(open: boolean): void
{
// Set the opened
this.opened = open;
// Enable the animations
this._enableAnimations();
// If the mode is 'over'
if ( this.mode === 'over' )
{
// If the drawer opens, show the overlay
if ( open )
{
this._showOverlay();
}
// Otherwise, close the overlay
else
{
this._hideOverlay();
}
}
// Execute the observable
this.openedChanged.next(open);
}
}
@@ -1,50 +0,0 @@
import { Injectable } from '@angular/core';
import { FuseDrawerComponent } from '@fuse/components/drawer/drawer.component';
@Injectable({providedIn: 'root'})
export class FuseDrawerService
{
private _componentRegistry: Map<string, FuseDrawerComponent> = new Map<string, FuseDrawerComponent>();
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register drawer component
*
* @param name
* @param component
*/
registerComponent(name: string, component: FuseDrawerComponent): void
{
this._componentRegistry.set(name, component);
}
/**
* Deregister drawer component
*
* @param name
*/
deregisterComponent(name: string): void
{
this._componentRegistry.delete(name);
}
/**
* Get drawer component from the registry
*
* @param name
*/
getComponent(name: string): FuseDrawerComponent | undefined
{
return this._componentRegistry.get(name);
}
}
@@ -1,7 +0,0 @@
export type FuseDrawerMode =
| 'over'
| 'side';
export type FuseDrawerPosition =
| 'left'
| 'right';
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/drawer/public-api';
@@ -1,3 +0,0 @@
export * from '@fuse/components/drawer/drawer.component';
export * from '@fuse/components/drawer/drawer.service';
export * from '@fuse/components/drawer/drawer.types';
@@ -1,12 +0,0 @@
<!-- Button -->
<button
mat-icon-button
[matTooltip]="tooltip || 'Toggle Fullscreen'"
(click)="toggleFullscreen()">
<ng-container [ngTemplateOutlet]="iconTpl || defaultIconTpl"></ng-container>
</button>
<!-- Default icon -->
<ng-template #defaultIconTpl>
<mat-icon [svgIcon]="'heroicons_outline:arrows-pointing-out'"></mat-icon>
</ng-template>
@@ -1,171 +0,0 @@
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
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',
standalone : true,
imports : [MatButtonModule, MatTooltipModule, NgTemplateOutlet, MatIconModule],
})
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;
}
}
}
@@ -1,16 +0,0 @@
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
@@ -1 +0,0 @@
export * from '@fuse/components/fullscreen/public-api';
@@ -1,2 +0,0 @@
export * from '@fuse/components/fullscreen/fullscreen.component';
export * from '@fuse/components/fullscreen/fullscreen.types';
@@ -1,9 +0,0 @@
<ng-content></ng-content>
<!-- @formatter:off -->
<ng-template let-highlightedCode="highlightedCode" let-lang="lang">
<div class="fuse-highlight fuse-highlight-code-container">
<pre [ngClass]="'language-' + lang"><code [ngClass]="'language-' + lang" [innerHTML]="highlightedCode"></code></pre>
</div>
</ng-template>
<!-- @formatter:on -->
@@ -1,3 +0,0 @@
textarea[fuse-highlight] {
display: none;
}
@@ -1,135 +0,0 @@
import { NgClass } from '@angular/common';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EmbeddedViewRef, Input, OnChanges, Renderer2, SecurityContext, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { FuseHighlightService } from '@fuse/components/highlight/highlight.service';
@Component({
selector : 'textarea[fuse-highlight]',
templateUrl : './highlight.component.html',
styleUrls : ['./highlight.component.scss'],
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseHighlight',
standalone : true,
imports : [NgClass],
})
export class FuseHighlightComponent implements OnChanges, AfterViewInit
{
@Input() code: string;
@Input() lang: string;
@ViewChild(TemplateRef) templateRef: TemplateRef<any>;
highlightedCode: string;
private _viewRef: EmbeddedViewRef<any>;
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _domSanitizer: DomSanitizer,
private _elementRef: ElementRef,
private _renderer2: Renderer2,
private _fuseHighlightService: FuseHighlightService,
private _viewContainerRef: ViewContainerRef,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Code & Lang
if ( 'code' in changes || 'lang' in changes )
{
// Return if the viewContainerRef is not available
if ( !this._viewContainerRef.length )
{
return;
}
// Highlight and insert the code
this._highlightAndInsert();
}
}
/**
* After view init
*/
ngAfterViewInit(): void
{
// Return if there is no language set
if ( !this.lang )
{
return;
}
// If there is no code input, get the code from
// the textarea
if ( !this.code )
{
// Get the code
this.code = this._elementRef.nativeElement.value;
}
// Highlight and insert
this._highlightAndInsert();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Highlight and insert the highlighted code
*
* @private
*/
private _highlightAndInsert(): void
{
// Return if the template reference is not available
if ( !this.templateRef )
{
return;
}
// Return if the code or language is not defined
if ( !this.code || !this.lang )
{
return;
}
// Destroy the component if there is already one
if ( this._viewRef )
{
this._viewRef.destroy();
this._viewRef = null;
}
// Highlight and sanitize the code just in case
this.highlightedCode = this._domSanitizer.sanitize(SecurityContext.HTML, this._fuseHighlightService.highlight(this.code, this.lang));
// Return if the highlighted code is null
if ( this.highlightedCode === null )
{
return;
}
// Render and insert the template
this._viewRef = this._viewContainerRef.createEmbeddedView(this.templateRef, {
highlightedCode: this.highlightedCode,
lang : this.lang,
});
// Detect the changes
this._viewRef.detectChanges();
}
}
@@ -1,80 +0,0 @@
import { Injectable } from '@angular/core';
import hljs from 'highlight.js';
@Injectable({providedIn: 'root'})
export class FuseHighlightService
{
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Highlight
*/
highlight(code: string, language: string): string
{
// Format the code
code = this._format(code);
// Highlight and return the code
return hljs.highlight(code, {language}).value;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Remove the empty lines around the code block
* and re-align the indentation based on the first
* non-whitespace indented character
*
* @param code
* @private
*/
private _format(code: string): string
{
let indentation = 0;
// Split the code into lines and store the lines
const lines = code.split('\n');
// Trim the empty lines around the code block
while ( lines.length && lines[0].trim() === '' )
{
lines.shift();
}
while ( lines.length && lines[lines.length - 1].trim() === '' )
{
lines.pop();
}
// Iterate through the lines
lines.filter(line => line.length)
.forEach((line, index) =>
{
// Always get the indentation of the first line so we can
// have something to compare with
if ( index === 0 )
{
indentation = line.search(/\S|$/);
return;
}
// Look at all the remaining lines to figure out the smallest indentation.
indentation = Math.min(line.search(/\S|$/), indentation);
});
// Iterate through the lines one more time, remove the extra
// indentation, join them together and return it
return lines.map(line => line.substring(indentation)).join('\n');
}
}
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/highlight/public-api';
@@ -1,2 +0,0 @@
export * from '@fuse/components/highlight/highlight.component';
export * from '@fuse/components/highlight/highlight.service';
@@ -1 +0,0 @@
export * from '@fuse/components/loading-bar/public-api';
@@ -1,5 +0,0 @@
<ng-container *ngIf="show">
<mat-progress-bar
[mode]="mode"
[value]="progress"></mat-progress-bar>
</ng-container>
@@ -1,7 +0,0 @@
fuse-loading-bar {
position: fixed;
top: 0;
z-index: 999;
width: 100%;
height: 6px;
}
@@ -1,89 +0,0 @@
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { NgIf } from '@angular/common';
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { FuseLoadingService } from '@fuse/services/loading';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-loading-bar',
templateUrl : './loading-bar.component.html',
styleUrls : ['./loading-bar.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseLoadingBar',
standalone : true,
imports : [NgIf, MatProgressBarModule],
})
export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy
{
@Input() autoMode: boolean = true;
mode: 'determinate' | 'indeterminate';
progress: number = 0;
show: boolean = false;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(private _fuseLoadingService: FuseLoadingService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Auto mode
if ( 'autoMode' in changes )
{
// Set the auto mode in the service
this._fuseLoadingService.setAutoMode(coerceBooleanProperty(changes.autoMode.currentValue));
}
}
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to the service
this._fuseLoadingService.mode$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.mode = value;
});
this._fuseLoadingService.progress$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.progress = value;
});
this._fuseLoadingService.show$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) =>
{
this.show = value;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1 +0,0 @@
export * from '@fuse/components/loading-bar/loading-bar.component';
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/masonry/public-api';
@@ -1,3 +0,0 @@
<div class="flex">
<ng-container *ngTemplateOutlet="columnsTemplate; context: { $implicit: distributedColumns }"></ng-container>
</div>
@@ -1,89 +0,0 @@
import { NgTemplateOutlet } from '@angular/common';
import { AfterViewInit, Component, Input, OnChanges, SimpleChanges, TemplateRef, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
@Component({
selector : 'fuse-masonry',
templateUrl : './masonry.component.html',
encapsulation: ViewEncapsulation.None,
animations : fuseAnimations,
exportAs : 'fuseMasonry',
standalone : true,
imports : [NgTemplateOutlet],
})
export class FuseMasonryComponent implements OnChanges, AfterViewInit
{
@Input() columnsTemplate: TemplateRef<any>;
@Input() columns: number;
@Input() items: any[] = [];
distributedColumns: any[] = [];
/**
* Constructor
*/
constructor(private _fuseMediaWatcherService: FuseMediaWatcherService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Columns
if ( 'columns' in changes )
{
// Distribute the items
this._distributeItems();
}
// Items
if ( 'items' in changes )
{
// Distribute the items
this._distributeItems();
}
}
/**
* After view init
*/
ngAfterViewInit(): void
{
// Distribute the items for the first time
this._distributeItems();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Distribute items into columns
*/
private _distributeItems(): void
{
// Return an empty array if there are no items
if ( this.items.length === 0 )
{
this.distributedColumns = [];
return;
}
// Prepare the distributed columns array
this.distributedColumns = Array.from(Array(this.columns), item => ({items: []}));
// Distribute the items to columns
for ( let i = 0; i < this.items.length; i++ )
{
this.distributedColumns[i % this.columns].items.push(this.items[i]);
}
}
}
@@ -1 +0,0 @@
export * from '@fuse/components/masonry/masonry.component';
@@ -1,134 +0,0 @@
<!-- Item wrapper -->
<div
class="fuse-horizontal-navigation-item-wrapper"
[class.fuse-horizontal-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<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]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an external link -->
<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 -->
<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 -->
<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]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[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 -->
<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 -->
<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 -->
<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>
<!-- Item template -->
<ng-template #itemTemplate>
<!-- 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">
<div class="fuse-horizontal-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
</ng-template>
@@ -1,87 +0,0 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IsActiveMatchOptions, RouterLink, RouterLinkActive } from '@angular/router';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-horizontal-navigation-basic-item',
templateUrl : './basic.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass, NgIf, RouterLink, RouterLinkActive, MatTooltipModule, NgTemplateOutlet, MatMenuModule, MatIconModule],
})
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
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;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
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),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,121 +0,0 @@
<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>
</ng-container>
<mat-menu
class="fuse-horizontal-navigation-menu-panel"
[overlapTrigger]="false"
#matMenu="matMenu">
<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 -->
<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 -->
<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 -->
<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>
</ng-container>
</mat-menu>
<!-- Item template -->
<ng-template
let-item
#itemTemplate>
<div
class="fuse-horizontal-navigation-item-wrapper"
[class.fuse-horizontal-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled,
'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<!-- 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">
<div class="fuse-horizontal-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
</div>
</div>
</ng-template>
@@ -1,100 +0,0 @@
import { BooleanInput } from '@angular/cdk/coercion';
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatMenu, MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseHorizontalNavigationBasicItemComponent } from '@fuse/components/navigation/horizontal/components/basic/basic.component';
import { FuseHorizontalNavigationDividerItemComponent } from '@fuse/components/navigation/horizontal/components/divider/divider.component';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-horizontal-navigation-branch-item',
templateUrl : './branch.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgIf, NgClass, MatMenuModule, NgTemplateOutlet, NgFor, FuseHorizontalNavigationBasicItemComponent, forwardRef(() => FuseHorizontalNavigationBranchItemComponent), FuseHorizontalNavigationDividerItemComponent, MatTooltipModule, MatIconModule],
})
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;
@Input() name: string;
@ViewChild('matMenu', {static: true}) matMenu: MatMenu;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Trigger the change detection
*/
triggerChangeDetection(): void
{
// 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;
}
}
@@ -1,4 +0,0 @@
<!-- Divider -->
<div
class="fuse-horizontal-navigation-item-wrapper divider"
[ngClass]="item.classes?.wrapper"></div>
@@ -1,64 +0,0 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
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 { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-horizontal-navigation-divider-item',
templateUrl : './divider.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass],
})
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,4 +0,0 @@
<!-- Spacer -->
<div
class="fuse-horizontal-navigation-item-wrapper"
[ngClass]="item.classes?.wrapper"></div>
@@ -1,64 +0,0 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
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 { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-horizontal-navigation-spacer-item',
templateUrl : './spacer.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass],
})
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,36 +0,0 @@
<div class="fuse-horizontal-navigation-wrapper">
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<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 -->
<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 -->
<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>
</ng-container>
</div>
@@ -1,180 +0,0 @@
/* Root navigation specific */
fuse-horizontal-navigation {
.fuse-horizontal-navigation-wrapper {
display: flex;
align-items: center;
/* Basic, Branch */
fuse-horizontal-navigation-basic-item,
fuse-horizontal-navigation-branch-item {
@screen sm {
&:hover {
.fuse-horizontal-navigation-item-wrapper {
@apply bg-hover;
}
}
}
.fuse-horizontal-navigation-item-wrapper {
border-radius: 4px;
overflow: hidden;
.fuse-horizontal-navigation-item {
padding: 0 16px;
cursor: pointer;
user-select: none;
.fuse-horizontal-navigation-item-icon {
margin-right: 12px;
}
}
}
}
/* Basic - When item active (current link) */
fuse-horizontal-navigation-basic-item {
.fuse-horizontal-navigation-item-active,
.fuse-horizontal-navigation-item-active-forced {
.fuse-horizontal-navigation-item-title {
@apply text-primary #{'!important'};
}
.fuse-horizontal-navigation-item-subtitle {
@apply text-primary-400 #{'!important'};
.dark & {
@apply text-primary-600 #{'!important'};
}
}
.fuse-horizontal-navigation-item-icon {
@apply text-primary #{'!important'};
}
}
}
/* Branch - When menu open */
fuse-horizontal-navigation-branch-item {
.fuse-horizontal-navigation-menu-active,
.fuse-horizontal-navigation-menu-active-forced {
.fuse-horizontal-navigation-item-wrapper {
@apply bg-hover;
}
}
}
/* Spacer */
fuse-horizontal-navigation-spacer-item {
margin: 12px 0;
}
}
}
/* Menu panel specific */
.fuse-horizontal-navigation-menu-panel {
.fuse-horizontal-navigation-menu-item {
height: auto;
min-height: 0;
line-height: normal;
white-space: normal;
/* Basic, Branch */
fuse-horizontal-navigation-basic-item,
fuse-horizontal-navigation-branch-item,
fuse-horizontal-navigation-divider-item {
display: flex;
flex: 1 1 auto;
}
/* Divider */
fuse-horizontal-navigation-divider-item {
margin: 8px -16px;
.fuse-horizontal-navigation-item-wrapper {
height: 1px;
box-shadow: 0 1px 0 0;
}
}
}
}
/* Navigation menu item common */
.fuse-horizontal-navigation-menu-item {
/* Basic - When item active (current link) */
fuse-horizontal-navigation-basic-item {
.fuse-horizontal-navigation-item-active,
.fuse-horizontal-navigation-item-active-forced {
.fuse-horizontal-navigation-item-title {
@apply text-primary #{'!important'};
}
.fuse-horizontal-navigation-item-subtitle {
@apply text-primary-400 #{'!important'};
.dark & {
@apply text-primary-600 #{'!important'};
}
}
.fuse-horizontal-navigation-item-icon {
@apply text-primary #{'!important'};
}
}
}
.fuse-horizontal-navigation-item-wrapper {
width: 100%;
&.fuse-horizontal-navigation-item-has-subtitle {
.fuse-horizontal-navigation-item {
min-height: 56px;
}
}
.fuse-horizontal-navigation-item {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 48px;
width: 100%;
font-size: 13px;
font-weight: 500;
text-decoration: none;
.fuse-horizontal-navigation-item-title-wrapper {
.fuse-horizontal-navigation-item-subtitle {
font-size: 12px;
}
}
.fuse-horizontal-navigation-item-badge {
margin-left: auto;
.fuse-horizontal-navigation-item-badge-content {
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
white-space: nowrap;
height: 20px;
}
}
}
}
}
@@ -1,115 +0,0 @@
import { NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { ReplaySubject, Subject } from 'rxjs';
import { FuseHorizontalNavigationBasicItemComponent } from './components/basic/basic.component';
import { FuseHorizontalNavigationBranchItemComponent } from './components/branch/branch.component';
import { FuseHorizontalNavigationSpacerItemComponent } from './components/spacer/spacer.component';
@Component({
selector : 'fuse-horizontal-navigation',
templateUrl : './horizontal.component.html',
styleUrls : ['./horizontal.component.scss'],
animations : fuseAnimations,
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseHorizontalNavigation',
standalone : true,
imports : [NgFor, NgIf, FuseHorizontalNavigationBasicItemComponent, FuseHorizontalNavigationBranchItemComponent, FuseHorizontalNavigationSpacerItemComponent],
})
export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnDestroy
{
@Input() name: string = this._fuseUtilsService.randomId();
@Input() navigation: FuseNavigationItem[];
onRefreshed: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Navigation
if ( 'navigation' in changes )
{
// Mark for check
this._changeDetectorRef.markForCheck();
}
}
/**
* On init
*/
ngOnInit(): void
{
// Make sure the name input is not an empty string
if ( this.name === '' )
{
this.name = this._fuseUtilsService.randomId();
}
// Register the navigation component
this._fuseNavigationService.registerComponent(this.name, this);
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Refresh the component to apply the changes
*/
refresh(): void
{
// Mark for check
this._changeDetectorRef.markForCheck();
// Execute the observable
this.onRefreshed.next(true);
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}
-1
View File
@@ -1 +0,0 @@
export * from '@fuse/components/navigation/public-api';
@@ -1,184 +0,0 @@
import { Injectable } from '@angular/core';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@Injectable({providedIn: 'root'})
export class FuseNavigationService
{
private _componentRegistry: Map<string, any> = new Map<string, any>();
private _navigationStore: Map<string, FuseNavigationItem[]> = new Map<string, any>();
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register navigation component
*
* @param name
* @param component
*/
registerComponent(name: string, component: any): void
{
this._componentRegistry.set(name, component);
}
/**
* Deregister navigation component
*
* @param name
*/
deregisterComponent(name: string): void
{
this._componentRegistry.delete(name);
}
/**
* Get navigation component from the registry
*
* @param name
*/
getComponent<T>(name: string): T
{
return this._componentRegistry.get(name);
}
/**
* Store the given navigation with the given key
*
* @param key
* @param navigation
*/
storeNavigation(key: string, navigation: FuseNavigationItem[]): void
{
// Add to the store
this._navigationStore.set(key, navigation);
}
/**
* Get navigation from storage by key
*
* @param key
*/
getNavigation(key: string): FuseNavigationItem[]
{
return this._navigationStore.get(key) ?? [];
}
/**
* Delete the navigation from the storage
*
* @param key
*/
deleteNavigation(key: string): void
{
// Check if the navigation exists
if ( !this._navigationStore.has(key) )
{
console.warn(`Navigation with the key '${key}' does not exist in the store.`);
}
// Delete from the storage
this._navigationStore.delete(key);
}
/**
* Utility function that returns a flattened
* version of the given navigation array
*
* @param navigation
* @param flatNavigation
*/
getFlatNavigation(navigation: FuseNavigationItem[], flatNavigation: FuseNavigationItem[] = []): FuseNavigationItem[]
{
for ( const item of navigation )
{
if ( item.type === 'basic' )
{
flatNavigation.push(item);
continue;
}
if ( item.type === 'aside' || item.type === 'collapsable' || item.type === 'group' )
{
if ( item.children )
{
this.getFlatNavigation(item.children, flatNavigation);
}
}
}
return flatNavigation;
}
/**
* Utility function that returns the item
* with the given id from given navigation
*
* @param id
* @param navigation
*/
getItem(id: string, navigation: FuseNavigationItem[]): FuseNavigationItem | null
{
for ( const item of navigation )
{
if ( item.id === id )
{
return item;
}
if ( item.children )
{
const childItem = this.getItem(id, item.children);
if ( childItem )
{
return childItem;
}
}
}
return null;
}
/**
* Utility function that returns the item's parent
* with the given id from given navigation
*
* @param id
* @param navigation
* @param parent
*/
getItemParent(
id: string,
navigation: FuseNavigationItem[],
parent: FuseNavigationItem[] | FuseNavigationItem,
): FuseNavigationItem[] | FuseNavigationItem | null
{
for ( const item of navigation )
{
if ( item.id === id )
{
return parent;
}
if ( item.children )
{
const childItem = this.getItemParent(id, item.children, item);
if ( childItem )
{
return childItem;
}
}
}
return null;
}
}
@@ -1,61 +0,0 @@
import { IsActiveMatchOptions, Params, QueryParamsHandling } from '@angular/router';
export interface FuseNavigationItem
{
id?: string;
title?: string;
subtitle?: string;
type:
| 'aside'
| 'basic'
| 'collapsable'
| 'divider'
| 'group'
| 'spacer';
hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean;
disabled?: boolean;
tooltip?: string;
link?: string;
fragment?: string;
preserveFragment?: boolean;
queryParams?: Params | null;
queryParamsHandling?: QueryParamsHandling | null;
externalLink?: boolean;
target?:
| '_blank'
| '_self'
| '_parent'
| '_top'
| string;
exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void;
classes?: {
title?: string;
subtitle?: string;
icon?: string;
wrapper?: string;
};
icon?: string;
badge?: {
title?: string;
classes?: string;
};
children?: FuseNavigationItem[];
meta?: any;
}
export type FuseVerticalNavigationAppearance =
| 'default'
| 'compact'
| 'dense'
| 'thin';
export type FuseVerticalNavigationMode =
| 'over'
| 'side';
export type FuseVerticalNavigationPosition =
| 'left'
| 'right';
@@ -1,4 +0,0 @@
export * from '@fuse/components/navigation/horizontal/horizontal.component';
export * from '@fuse/components/navigation/vertical/vertical.component';
export * from '@fuse/components/navigation/navigation.service';
export * from '@fuse/components/navigation/navigation.types';
@@ -1,103 +0,0 @@
<div
class="fuse-vertical-navigation-item-wrapper"
[class.fuse-vertical-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<div
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}"
[matTooltip]="item.tooltip || ''">
<!-- 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">
<div class="fuse-vertical-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
</div>
</div>
<ng-container *ngIf="!skipChildren">
<div class="fuse-vertical-navigation-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 -->
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<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 -->
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
</ng-container>
</div>
</ng-container>
@@ -1,196 +0,0 @@
import { BooleanInput } from '@angular/cdk/coercion';
import { NgClass, NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { NavigationEnd, Router } from '@angular/router';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-aside-item',
templateUrl : './aside.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass, MatTooltipModule, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
})
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;
@Input() item: FuseNavigationItem;
@Input() name: string;
@Input() skipChildren: boolean;
active: boolean = false;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _router: Router,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Active item id
if ( 'activeItemId' in changes )
{
// Mark if active
this._markIfActive(this._router.url);
}
}
/**
* On init
*/
ngOnInit(): void
{
// Mark if active
this._markIfActive(this._router.url);
// Attach a listener to the NavigationEnd event
this._router.events
.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll),
)
.subscribe((event: NavigationEnd) =>
{
// Mark if active
this._markIfActive(event.urlAfterRedirects);
});
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
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
// -----------------------------------------------------------------------------------------------------
/**
* 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;
}
}
// Skip items other than 'basic'
if ( child.type !== 'basic' )
{
continue;
}
// 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;
}
/**
* Decide and mark if the item is active
*
* @private
*/
private _markIfActive(currentUrl: string): void
{
// Check if the activeItemId is equals to this item id
this.active = this.activeItemId === this.item.id;
// If the aside has a children that is active,
// always mark it as active
if ( this._hasActiveChild(this.item, currentUrl) )
{
this.active = true;
}
// Mark for check
this._changeDetectorRef.markForCheck();
}
}
@@ -1,135 +0,0 @@
<!-- Item wrapper -->
<div
class="fuse-vertical-navigation-item-wrapper"
[class.fuse-vertical-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<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]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with an external link -->
<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 -->
<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 -->
<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]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[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 -->
<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 -->
<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 -->
<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>
<!-- Item template -->
<ng-template #itemTemplate>
<!-- 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">
<div class="fuse-vertical-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
</ng-template>
@@ -1,86 +0,0 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IsActiveMatchOptions, RouterLink, RouterLinkActive } from '@angular/router';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-basic-item',
templateUrl : './basic.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass, NgIf, RouterLink, RouterLinkActive, MatTooltipModule, NgTemplateOutlet, MatIconModule],
})
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
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;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
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),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,106 +0,0 @@
<div
class="fuse-vertical-navigation-item-wrapper"
[class.fuse-vertical-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}"
[matTooltip]="item.tooltip || ''"
(click)="toggleCollapsable()">
<!-- 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">
<div class="fuse-vertical-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
<!-- Arrow -->
<mat-icon
class="fuse-vertical-navigation-item-arrow icon-size-4"
[svgIcon]="'heroicons_solid:chevron-right'"></mat-icon>
</div>
</div>
<div
class="fuse-vertical-navigation-item-children"
*ngIf="!isCollapsed"
@expandCollapse>
<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 -->
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<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 -->
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
</ng-container>
</div>
@@ -1,356 +0,0 @@
import { BooleanInput } from '@angular/cdk/coercion';
import { NgClass, NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { NavigationEnd, Router } from '@angular/router';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { filter, Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-collapsable-item',
templateUrl : './collapsable.component.html',
animations : fuseAnimations,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass, MatTooltipModule, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, forwardRef(() => FuseVerticalNavigationCollapsableItemComponent), FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
})
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;
@Input() name: string;
isCollapsed: boolean = true;
isExpanded: boolean = false;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _router: Router,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component classes
*/
@HostBinding('class') get classList(): any
{
/* eslint-disable @typescript-eslint/naming-convention */
return {
'fuse-vertical-navigation-item-collapsed': this.isCollapsed,
'fuse-vertical-navigation-item-expanded' : this.isExpanded,
};
/* eslint-enable @typescript-eslint/naming-convention */
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// If the item has a children that has a matching url with the current url, expand...
if ( this._hasActiveChild(this.item, this._router.url) )
{
this.expand();
}
// Otherwise...
else
{
// If the autoCollapse is on, collapse...
if ( this.autoCollapse )
{
this.collapse();
}
}
// Listen for the onCollapsableItemCollapsed from the service
this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((collapsedItem) =>
{
// Check if the collapsed item is null
if ( collapsedItem === null )
{
return;
}
// Collapse if this is a children of the collapsed item
if ( this._isChildrenOf(collapsedItem, this.item) )
{
this.collapse();
}
});
// Listen for the onCollapsableItemExpanded from the service if the autoCollapse is on
if ( this.autoCollapse )
{
this._fuseVerticalNavigationComponent.onCollapsableItemExpanded
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((expandedItem) =>
{
// Check if the expanded item is null
if ( expandedItem === null )
{
return;
}
// Check if this is a parent of the expanded item
if ( this._isChildrenOf(this.item, expandedItem) )
{
return;
}
// Check if this has a children with a matching url with the current active url
if ( this._hasActiveChild(this.item, this._router.url) )
{
return;
}
// Check if this is the expanded item
if ( this.item === expandedItem )
{
return;
}
// If none of the above conditions are matched, collapse this item
this.collapse();
});
}
// Attach a listener to the NavigationEnd event
this._router.events
.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll),
)
.subscribe((event: NavigationEnd) =>
{
// If the item has a children that has a matching url with the current url, expand...
if ( this._hasActiveChild(this.item, event.urlAfterRedirects) )
{
this.expand();
}
// Otherwise...
else
{
// If the autoCollapse is on, collapse...
if ( this.autoCollapse )
{
this.collapse();
}
}
});
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Collapse
*/
collapse(): void
{
// Return if the item is disabled
if ( this.item.disabled )
{
return;
}
// Return if the item is already collapsed
if ( this.isCollapsed )
{
return;
}
// Collapse it
this.isCollapsed = true;
this.isExpanded = !this.isCollapsed;
// Mark for check
this._changeDetectorRef.markForCheck();
// Execute the observable
this._fuseVerticalNavigationComponent.onCollapsableItemCollapsed.next(this.item);
}
/**
* Expand
*/
expand(): void
{
// Return if the item is disabled
if ( this.item.disabled )
{
return;
}
// Return if the item is already expanded
if ( !this.isCollapsed )
{
return;
}
// Expand it
this.isCollapsed = false;
this.isExpanded = !this.isCollapsed;
// Mark for check
this._changeDetectorRef.markForCheck();
// Execute the observable
this._fuseVerticalNavigationComponent.onCollapsableItemExpanded.next(this.item);
}
/**
* Toggle collapsable
*/
toggleCollapsable(): void
{
// Toggle collapse/expand
if ( this.isCollapsed )
{
this.expand();
}
else
{
this.collapse();
}
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Check if the given item has the given url
* in one of its children
*
* @param item
* @param currentUrl
* @private
*/
private _hasActiveChild(item: FuseNavigationItem, currentUrl: string): boolean
{
const children = item.children;
if ( !children )
{
return false;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._hasActiveChild(child, currentUrl) )
{
return true;
}
}
// Check if the child has a link and is active
if ( child.link && this._router.isActive(child.link, child.exactMatch || false) )
{
return true;
}
}
return false;
}
/**
* Check if this is a children
* of the given item
*
* @param parent
* @param item
* @private
*/
private _isChildrenOf(parent: FuseNavigationItem, item: FuseNavigationItem): boolean
{
const children = parent.children;
if ( !children )
{
return false;
}
if ( children.indexOf(item) > -1 )
{
return true;
}
for ( const child of children )
{
if ( child.children )
{
if ( this._isChildrenOf(child, item) )
{
return true;
}
}
}
return false;
}
}
@@ -1,4 +0,0 @@
<!-- Divider -->
<div
class="fuse-vertical-navigation-item-wrapper divider"
[ngClass]="item.classes?.wrapper"></div>
@@ -1,64 +0,0 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-divider-item',
templateUrl : './divider.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass],
})
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,91 +0,0 @@
<!-- Item wrapper -->
<div
class="fuse-vertical-navigation-item-wrapper"
[class.fuse-vertical-navigation-item-has-subtitle]="!!item.subtitle"
[ngClass]="item.classes?.wrapper">
<div class="fuse-vertical-navigation-item">
<!-- 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">
<div class="fuse-vertical-navigation-item-title">
<span [ngClass]="item.classes?.title">
{{item.title}}
</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 -->
<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>
</ng-container>
</div>
</div>
<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 -->
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<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 -->
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
</ng-container>
@@ -1,90 +0,0 @@
import { BooleanInput } from '@angular/cdk/coercion';
import { NgClass, NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-group-item',
templateUrl : './group.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass, NgIf, MatIconModule, NgFor, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, forwardRef(() => FuseVerticalNavigationGroupItemComponent), FuseVerticalNavigationSpacerItemComponent],
})
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;
@Input() name: string;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
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;
}
}
@@ -1,4 +0,0 @@
<!-- Spacer -->
<div
class="fuse-vertical-navigation-item-wrapper"
[ngClass]="item.classes?.wrapper"></div>
@@ -1,64 +0,0 @@
import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation-spacer-item',
templateUrl : './spacer.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone : true,
imports : [NgClass],
})
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
{
@Input() item: FuseNavigationItem;
@Input() name: string;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll),
).subscribe(() =>
{
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}
@@ -1,112 +0,0 @@
/* Variables */
:root {
--fuse-vertical-navigation-compact-width: 112px;
}
fuse-vertical-navigation {
/* Compact appearance overrides */
&.fuse-vertical-navigation-appearance-compact {
width: var(--fuse-vertical-navigation-compact-width);
min-width: var(--fuse-vertical-navigation-compact-width);
max-width: var(--fuse-vertical-navigation-compact-width);
/* Left positioned */
&.fuse-vertical-navigation-position-left {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-compact-width) * -1);
}
/* Opened */
&.fuse-vertical-navigation-opened {
margin-left: 0;
}
}
/* Right positioned */
&.fuse-vertical-navigation-position-right {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-compact-width) * -1);
}
/* Opened */
&.fuse-vertical-navigation-opened {
margin-right: 0;
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
left: auto;
right: var(--fuse-vertical-navigation-compact-width);
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
/* Content */
.fuse-vertical-navigation-content {
> fuse-vertical-navigation-aside-item,
> fuse-vertical-navigation-basic-item {
.fuse-vertical-navigation-item-wrapper {
margin: 4px 8px 0 8px;
.fuse-vertical-navigation-item {
flex-direction: column;
justify-content: center;
padding: 12px;
border-radius: 6px;
.fuse-vertical-navigation-item-icon {
margin-right: 0;
}
.fuse-vertical-navigation-item-title-wrapper {
margin-top: 8px;
.fuse-vertical-navigation-item-title {
font-size: 12px;
font-weight: 500;
text-align: center;
line-height: 16px;
}
.fuse-vertical-navigation-item-subtitle {
display: none !important;
}
}
.fuse-vertical-navigation-item-badge {
position: absolute;
top: 12px;
left: 64px;
}
}
}
> fuse-vertical-navigation-collapsable-item {
display: none
}
> fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
display: none
}
}
}
}
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-compact-width);
}
}
}
@@ -1,597 +0,0 @@
/* Variables */
:root {
--fuse-vertical-navigation-width: 280px;
}
fuse-vertical-navigation {
position: sticky;
display: flex;
flex-direction: column;
flex: 1 0 auto;
top: 0;
width: var(--fuse-vertical-navigation-width);
min-width: var(--fuse-vertical-navigation-width);
max-width: var(--fuse-vertical-navigation-width);
height: 100vh;
min-height: 100vh;
max-height: 100vh;
z-index: 200;
/* ----------------------------------------------------------------------------------------------------- */
/* @ Navigation Drawer
/* ----------------------------------------------------------------------------------------------------- */
/* Animations */
&.fuse-vertical-navigation-animations-enabled {
transition-duration: 400ms;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
transition-property: visibility, margin-left, margin-right, transform, width, max-width, min-width;
/* Wrapper */
.fuse-vertical-navigation-wrapper {
transition-duration: 400ms;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
transition-property: width, max-width, min-width;
}
}
/* Over mode */
&.fuse-vertical-navigation-mode-over {
position: fixed;
top: 0;
bottom: 0;
}
/* Left position */
&.fuse-vertical-navigation-position-left {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-left: calc(#{var(--fuse-vertical-navigation-width)} * -1);
&.fuse-vertical-navigation-opened {
margin-left: 0;
}
}
/* Over mode */
&.fuse-vertical-navigation-mode-over {
left: 0;
transform: translate3d(-100%, 0, 0);
&.fuse-vertical-navigation-opened {
transform: translate3d(0, 0, 0);
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
left: 0;
}
}
/* Right position */
&.fuse-vertical-navigation-position-right {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-width) * -1);
&.fuse-vertical-navigation-opened {
margin-right: 0;
}
}
/* Over mode */
&.fuse-vertical-navigation-mode-over {
right: 0;
transform: translate3d(100%, 0, 0);
&.fuse-vertical-navigation-opened {
transform: translate3d(0, 0, 0);
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
right: 0;
}
}
/* Inner mode */
&.fuse-vertical-navigation-inner {
position: relative;
width: auto;
min-width: 0;
max-width: none;
height: auto;
min-height: 0;
max-height: none;
box-shadow: none;
.fuse-vertical-navigation-wrapper {
position: relative;
overflow: visible;
height: auto;
.fuse-vertical-navigation-content {
overflow: visible !important;
}
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
position: absolute;
display: flex;
flex: 1 1 auto;
flex-direction: column;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 10;
background: inherit;
box-shadow: inset -1px 0 0 var(--fuse-border);
/* Header */
.fuse-vertical-navigation-header {
}
/* Content */
.fuse-vertical-navigation-content {
flex: 1 1 auto;
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
/* Divider */
> fuse-vertical-navigation-divider-item {
margin: 24px 0;
}
/* Group */
> fuse-vertical-navigation-group-item {
margin-top: 24px;
}
}
/* Footer */
.fuse-vertical-navigation-footer {
}
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
position: absolute;
display: flex;
flex: 1 1 auto;
flex-direction: column;
top: 0;
bottom: 0;
left: var(--fuse-vertical-navigation-width);
width: var(--fuse-vertical-navigation-width);
height: 100%;
z-index: 5;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
transition-duration: 400ms;
transition-property: left, right;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
background: inherit;
> fuse-vertical-navigation-aside-item {
padding: 24px 0;
/* First item of the aside */
> .fuse-vertical-navigation-item-wrapper {
display: none !important;
}
}
}
&.fuse-vertical-navigation-position-right {
.fuse-vertical-navigation-aside-wrapper {
left: auto;
right: var(--fuse-vertical-navigation-width);
}
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Navigation Items
/* ----------------------------------------------------------------------------------------------------- */
/* Navigation items common */
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item,
fuse-vertical-navigation-divider-item,
fuse-vertical-navigation-group-item,
fuse-vertical-navigation-spacer-item {
display: flex;
flex-direction: column;
flex: 1 0 auto;
user-select: none;
.fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 10px 16px;
font-size: 13px;
font-weight: 500;
line-height: 20px;
text-decoration: none;
border-radius: 6px;
/* Disabled state */
&.fuse-vertical-navigation-item-disabled {
cursor: default;
opacity: 0.4;
}
.fuse-vertical-navigation-item-icon {
margin-right: 16px;
}
.fuse-vertical-navigation-item-title-wrapper {
.fuse-vertical-navigation-item-subtitle {
font-size: 11px;
line-height: 1.5;
}
}
.fuse-vertical-navigation-item-badge {
margin-left: auto;
.fuse-vertical-navigation-item-badge-content {
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
white-space: nowrap;
height: 20px;
}
}
}
}
}
/* Aside, Basic, Collapsable, Group */
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item,
fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
margin: 0 12px;
}
}
/* Aside, Basic, Collapsable */
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item {
margin-bottom: 4px;
.fuse-vertical-navigation-item {
cursor: pointer;
}
}
/* Aside */
fuse-vertical-navigation-aside-item {
}
/* Basic */
fuse-vertical-navigation-basic-item {
}
/* Collapsable */
fuse-vertical-navigation-collapsable-item {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
.fuse-vertical-navigation-item-badge {
+ .fuse-vertical-navigation-item-arrow {
margin-left: 8px;
}
}
.fuse-vertical-navigation-item-arrow {
height: 20px;
line-height: 20px;
margin-left: auto;
transition: transform 300ms cubic-bezier(0.25, 0.8, 0.25, 1),
color 375ms cubic-bezier(0.25, 0.8, 0.25, 1);
}
}
}
&.fuse-vertical-navigation-item-expanded {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
.fuse-vertical-navigation-item-arrow {
transform: rotate(90deg);
}
}
}
}
> .fuse-vertical-navigation-item-children {
> *:first-child {
margin-top: 6px;
}
> *:last-child {
padding-bottom: 6px;
> .fuse-vertical-navigation-item-children {
> *:last-child {
padding-bottom: 0;
}
}
}
.fuse-vertical-navigation-item {
padding: 10px 16px;
}
}
/* 1st level */
.fuse-vertical-navigation-item-children {
overflow: hidden;
.fuse-vertical-navigation-item {
padding-left: 56px;
}
/* 2nd level */
.fuse-vertical-navigation-item-children {
.fuse-vertical-navigation-item {
padding-left: 72px;
}
/* 3rd level */
.fuse-vertical-navigation-item-children {
.fuse-vertical-navigation-item {
padding-left: 88px;
}
/* 4th level */
.fuse-vertical-navigation-item-children {
.fuse-vertical-navigation-item {
padding-left: 104px;
}
}
}
}
}
}
/* Divider */
fuse-vertical-navigation-divider-item {
margin: 12px 0;
.fuse-vertical-navigation-item-wrapper {
height: 1px;
box-shadow: 0 1px 0 0;
}
}
/* Group */
fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
.fuse-vertical-navigation-item-badge,
.fuse-vertical-navigation-item-icon {
display: none !important;
}
.fuse-vertical-navigation-item-title-wrapper {
.fuse-vertical-navigation-item-title {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
}
}
}
}
}
/* Spacer */
fuse-vertical-navigation-spacer-item {
margin: 6px 0;
}
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Overlay
/* ----------------------------------------------------------------------------------------------------- */
.fuse-vertical-navigation-overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 170;
opacity: 0;
background-color: rgba(0, 0, 0, 0.6);
+ .fuse-vertical-navigation-aside-overlay {
background-color: transparent;
}
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Aside overlay
/* ----------------------------------------------------------------------------------------------------- */
.fuse-vertical-navigation-aside-overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 169;
opacity: 0;
background-color: rgba(0, 0, 0, 0.3);
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Navigation Items Colors
/* ----------------------------------------------------------------------------------------------------- */
/* Navigation items common */
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item,
fuse-vertical-navigation-group-item {
.fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
color: currentColor;
.fuse-vertical-navigation-item-icon {
@apply text-current opacity-60;
}
.fuse-vertical-navigation-item-title-wrapper {
.fuse-vertical-navigation-item-title {
@apply text-current opacity-80;
}
.fuse-vertical-navigation-item-subtitle {
@apply text-current opacity-50;
}
}
}
}
}
/* Aside, Basic, Collapsable */
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
/* Active state */
&:not(.fuse-vertical-navigation-item-disabled) {
&.fuse-vertical-navigation-item-active,
&.fuse-vertical-navigation-item-active-forced {
@apply bg-gray-800 bg-opacity-5 dark:bg-white dark:bg-opacity-12;
.fuse-vertical-navigation-item-icon {
@apply opacity-100;
}
.fuse-vertical-navigation-item-title {
@apply opacity-100;
}
.fuse-vertical-navigation-item-subtitle {
@apply opacity-100;
}
}
}
/* Hover state */
&:not(.fuse-vertical-navigation-item-active-forced):not(.fuse-vertical-navigation-item-active):not(.fuse-vertical-navigation-item-disabled) {
&:hover {
@apply bg-gray-800 bg-opacity-5 dark:bg-white dark:bg-opacity-12;
.fuse-vertical-navigation-item-icon {
@apply opacity-100;
}
.fuse-vertical-navigation-item-title,
.fuse-vertical-navigation-item-arrow {
@apply opacity-100;
}
.fuse-vertical-navigation-item-subtitle {
@apply opacity-100;
}
}
}
}
}
}
/* Collapsable */
fuse-vertical-navigation-collapsable-item {
/* Expanded state */
&.fuse-vertical-navigation-item-expanded {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
.fuse-vertical-navigation-item-icon {
@apply opacity-100;
}
.fuse-vertical-navigation-item-title,
.fuse-vertical-navigation-item-arrow {
@apply opacity-100;
}
.fuse-vertical-navigation-item-subtitle {
@apply opacity-100;
}
}
}
}
}
/* Group */
fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
.fuse-vertical-navigation-item-title-wrapper {
.fuse-vertical-navigation-item-title {
@apply opacity-100 text-primary-600 dark:text-primary-400;
}
}
}
}
}
@@ -1,194 +0,0 @@
/* Variables */
:root {
--fuse-vertical-navigation-width: 280px;
--fuse-vertical-navigation-dense-width: 80px;
}
fuse-vertical-navigation {
/* Dense appearance overrides */
&.fuse-vertical-navigation-appearance-dense {
&:not(.fuse-vertical-navigation-mode-over) {
width: var(--fuse-vertical-navigation-dense-width);
min-width: var(--fuse-vertical-navigation-dense-width);
max-width: var(--fuse-vertical-navigation-dense-width);
/* Left positioned */
&.fuse-vertical-navigation-position-left {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-dense-width) * -1);
}
/* Opened */
&.fuse-vertical-navigation-opened {
margin-left: 0;
}
}
/* Right positioned */
&.fuse-vertical-navigation-position-right {
/* Side mode */
&.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-dense-width) * -1);
}
/* Opened */
&.fuse-vertical-navigation-opened {
margin-right: 0;
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
left: auto;
right: var(--fuse-vertical-navigation-dense-width);
}
&.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-aside-wrapper {
left: auto;
right: var(--fuse-vertical-navigation-width);
}
}
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
/* Content */
.fuse-vertical-navigation-content {
fuse-vertical-navigation-aside-item,
fuse-vertical-navigation-basic-item,
fuse-vertical-navigation-collapsable-item,
fuse-vertical-navigation-group-item {
.fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
min-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
max-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
.fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge,
.fuse-vertical-navigation-item-title-wrapper {
transition: opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1);
}
}
}
}
fuse-vertical-navigation-group-item {
&:first-of-type {
margin-top: 0;
}
}
}
}
&:not(.fuse-vertical-navigation-hover):not(.fuse-vertical-navigation-mode-over) {
/* Wrapper */
.fuse-vertical-navigation-wrapper {
/* Content */
.fuse-vertical-navigation-content {
.fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
padding: 10px 16px;
.fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge,
.fuse-vertical-navigation-item-title-wrapper {
white-space: nowrap;
opacity: 0;
}
}
}
fuse-vertical-navigation-collapsable-item {
.fuse-vertical-navigation-item-children {
display: none;
}
}
fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
&:before {
content: '';
position: absolute;
top: 20px;
width: 23px;
border-top-width: 2px;
}
}
}
}
}
}
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-dense-width);
}
/* Hover */
&.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-wrapper {
width: var(--fuse-vertical-navigation-width);
.fuse-vertical-navigation-content {
.fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item {
width: calc(var(--fuse-vertical-navigation-width) - 24px);
min-width: calc(var(--fuse-vertical-navigation-width) - 24px);
max-width: calc(var(--fuse-vertical-navigation-width) - 24px);
.fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge,
.fuse-vertical-navigation-item-title-wrapper {
white-space: nowrap;
animation: removeWhiteSpaceNoWrap 1ms linear 350ms;
animation-fill-mode: forwards;
}
}
}
}
}
.fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-width);
}
}
}
}
@keyframes removeWhiteSpaceNoWrap {
0% {
white-space: nowrap
}
99% {
white-space: nowrap
}
100% {
white-space: normal;
}
}
@@ -1,99 +0,0 @@
/* Variables */
:root {
--fuse-vertical-navigation-thin-width: 80px;
}
fuse-vertical-navigation {
/* Thin appearance overrides */
&.fuse-vertical-navigation-appearance-thin {
width: var(--fuse-vertical-navigation-thin-width);
min-width: var(--fuse-vertical-navigation-thin-width);
max-width: var(--fuse-vertical-navigation-thin-width);
/* Left positioned */
&.fuse-vertical-navigation-position-left {
&.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-thin-width) * -1);
}
&.fuse-vertical-navigation-opened {
margin-left: 0;
}
}
/* Right positioned */
&.fuse-vertical-navigation-position-right {
&.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-thin-width) * -1);
}
&.fuse-vertical-navigation-opened {
margin-right: 0;
}
.fuse-vertical-navigation-aside-wrapper {
left: auto;
right: var(--fuse-vertical-navigation-thin-width);
}
}
/* Wrapper */
.fuse-vertical-navigation-wrapper {
/* Content */
.fuse-vertical-navigation-content {
> fuse-vertical-navigation-aside-item,
> fuse-vertical-navigation-basic-item {
flex-direction: column;
justify-content: center;
height: 64px;
min-height: 64px;
max-height: 64px;
padding: 0 16px;
.fuse-vertical-navigation-item-wrapper {
display: flex;
align-items: center;
justify-content: center;
.fuse-vertical-navigation-item {
justify-content: center;
padding: 12px;
border-radius: 4px;
.fuse-vertical-navigation-item-icon {
margin: 0;
}
.fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge-content,
.fuse-vertical-navigation-item-title-wrapper {
display: none;
}
}
}
}
> fuse-vertical-navigation-collapsable-item {
display: none
}
> fuse-vertical-navigation-group-item {
> .fuse-vertical-navigation-item-wrapper {
display: none
}
}
}
}
/* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-thin-width);
}
}
}
@@ -1,122 +0,0 @@
<div class="fuse-vertical-navigation-wrapper">
<!-- Header -->
<div class="fuse-vertical-navigation-header">
<ng-content select="[fuseVerticalNavigationHeader]"></ng-content>
</div>
<!-- Content -->
<div
class="fuse-vertical-navigation-content"
fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: inner, suppressScrollX: true}"
#navigationContent>
<!-- Content header -->
<div class="fuse-vertical-navigation-content-header">
<ng-content select="[fuseVerticalNavigationContentHeader]"></ng-content>
</div>
<!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside -->
<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 -->
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<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 -->
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<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 -->
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
</ng-container>
<!-- Content footer -->
<div class="fuse-vertical-navigation-content-footer">
<ng-content select="[fuseVerticalNavigationContentFooter]"></ng-content>
</div>
</div>
<!-- Footer -->
<div class="fuse-vertical-navigation-footer">
<ng-content select="[fuseVerticalNavigationFooter]"></ng-content>
</div>
</div>
<!-- Aside -->
<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">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- 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>
</div>
</ng-container>
@@ -1,4 +0,0 @@
@use 'styles/appearances/default';
@use 'styles/appearances/compact';
@use 'styles/appearances/dense';
@use 'styles/appearances/thin';
@@ -1,795 +0,0 @@
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { DOCUMENT, NgFor, NgIf } from '@angular/common';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Inject, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
import { FuseVerticalNavigationAsideItemComponent } from '@fuse/components/navigation/vertical/components/aside/aside.component';
import { FuseVerticalNavigationBasicItemComponent } from '@fuse/components/navigation/vertical/components/basic/basic.component';
import { FuseVerticalNavigationCollapsableItemComponent } from '@fuse/components/navigation/vertical/components/collapsable/collapsable.component';
import { FuseVerticalNavigationDividerItemComponent } from '@fuse/components/navigation/vertical/components/divider/divider.component';
import { FuseVerticalNavigationGroupItemComponent } from '@fuse/components/navigation/vertical/components/group/group.component';
import { FuseVerticalNavigationSpacerItemComponent } from '@fuse/components/navigation/vertical/components/spacer/spacer.component';
import { FuseScrollbarDirective } from '@fuse/directives/scrollbar/scrollbar.directive';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs';
@Component({
selector : 'fuse-vertical-navigation',
templateUrl : './vertical.component.html',
styleUrls : ['./vertical.component.scss'],
animations : fuseAnimations,
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseVerticalNavigation',
standalone : true,
imports : [FuseScrollbarDirective, NgFor, NgIf, FuseVerticalNavigationAsideItemComponent, FuseVerticalNavigationBasicItemComponent, FuseVerticalNavigationCollapsableItemComponent, FuseVerticalNavigationDividerItemComponent, FuseVerticalNavigationGroupItemComponent, FuseVerticalNavigationSpacerItemComponent],
})
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;
@Input() inner: boolean = false;
@Input() mode: FuseVerticalNavigationMode = 'side';
@Input() name: string = this._fuseUtilsService.randomId();
@Input() navigation: FuseNavigationItem[];
@Input() opened: boolean = true;
@Input() position: FuseVerticalNavigationPosition = 'left';
@Input() transparentOverlay: boolean = false;
@Output() readonly appearanceChanged: EventEmitter<FuseVerticalNavigationAppearance> = new EventEmitter<FuseVerticalNavigationAppearance>();
@Output() readonly modeChanged: EventEmitter<FuseVerticalNavigationMode> = new EventEmitter<FuseVerticalNavigationMode>();
@Output() readonly openedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() readonly positionChanged: EventEmitter<FuseVerticalNavigationPosition> = new EventEmitter<FuseVerticalNavigationPosition>();
@ViewChild('navigationContent') private _navigationContentEl: ElementRef;
activeAsideItemId: string | null = null;
onCollapsableItemCollapsed: ReplaySubject<FuseNavigationItem> = new ReplaySubject<FuseNavigationItem>(1);
onCollapsableItemExpanded: ReplaySubject<FuseNavigationItem> = new ReplaySubject<FuseNavigationItem>(1);
onRefreshed: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
private _animationsEnabled: boolean = false;
private _asideOverlay: HTMLElement;
private readonly _handleAsideOverlayClick: any;
private readonly _handleOverlayClick: any;
private _hovered: boolean = false;
private _mutationObserver: MutationObserver;
private _overlay: HTMLElement;
private _player: AnimationPlayer;
private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
private _fuseScrollbarDirectives!: QueryList<FuseScrollbarDirective>;
private _fuseScrollbarDirectivesSubscription: Subscription;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _animationBuilder: AnimationBuilder,
private _changeDetectorRef: ChangeDetectorRef,
@Inject(DOCUMENT) private _document: Document,
private _elementRef: ElementRef,
private _renderer2: Renderer2,
private _router: Router,
private _scrollStrategyOptions: ScrollStrategyOptions,
private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService,
)
{
this._handleAsideOverlayClick = (): void =>
{
this.closeAside();
};
this._handleOverlayClick = (): void =>
{
this.close();
};
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component classes
*/
@HostBinding('class') get classList(): any
{
/* eslint-disable @typescript-eslint/naming-convention */
return {
'fuse-vertical-navigation-animations-enabled' : this._animationsEnabled,
[`fuse-vertical-navigation-appearance-${this.appearance}`]: true,
'fuse-vertical-navigation-hover' : this._hovered,
'fuse-vertical-navigation-inner' : this.inner,
'fuse-vertical-navigation-mode-over' : this.mode === 'over',
'fuse-vertical-navigation-mode-side' : this.mode === 'side',
'fuse-vertical-navigation-opened' : this.opened,
'fuse-vertical-navigation-position-left' : this.position === 'left',
'fuse-vertical-navigation-position-right' : this.position === 'right',
};
/* eslint-enable @typescript-eslint/naming-convention */
}
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'visibility': this.opened ? 'visible' : 'hidden',
};
}
/**
* Setter for fuseScrollbarDirectives
*/
@ViewChildren(FuseScrollbarDirective)
set fuseScrollbarDirectives(fuseScrollbarDirectives: QueryList<FuseScrollbarDirective>)
{
// Store the directives
this._fuseScrollbarDirectives = fuseScrollbarDirectives;
// Return if there are no directives
if ( fuseScrollbarDirectives.length === 0 )
{
return;
}
// Unsubscribe the previous subscriptions
if ( this._fuseScrollbarDirectivesSubscription )
{
this._fuseScrollbarDirectivesSubscription.unsubscribe();
}
// Update the scrollbars on collapsable items' collapse/expand
this._fuseScrollbarDirectivesSubscription =
merge(
this.onCollapsableItemCollapsed,
this.onCollapsableItemExpanded,
)
.pipe(
takeUntil(this._unsubscribeAll),
delay(250),
)
.subscribe(() =>
{
// Loop through the scrollbars and update them
fuseScrollbarDirectives.forEach((fuseScrollbarDirective) =>
{
fuseScrollbarDirective.update();
});
});
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* On mouseenter
*
* @private
*/
@HostListener('mouseenter')
private _onMouseenter(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = true;
}
/**
* On mouseleave
*
* @private
*/
@HostListener('mouseleave')
private _onMouseleave(): void
{
// Enable the animations
this._enableAnimations();
// Set the hovered
this._hovered = false;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Appearance
if ( 'appearance' in changes )
{
// Execute the observable
this.appearanceChanged.next(changes.appearance.currentValue);
}
// Inner
if ( 'inner' in changes )
{
// Coerce the value to a boolean
this.inner = coerceBooleanProperty(changes.inner.currentValue);
}
// Mode
if ( 'mode' in changes )
{
// Get the previous and current values
const currentMode = changes.mode.currentValue;
const previousMode = changes.mode.previousValue;
// Disable the animations
this._disableAnimations();
// If the mode changes: 'over -> side'
if ( previousMode === 'over' && currentMode === 'side' )
{
// Hide the overlay
this._hideOverlay();
}
// If the mode changes: 'side -> over'
if ( previousMode === 'side' && currentMode === 'over' )
{
// Close the aside
this.closeAside();
// If the navigation is opened
if ( this.opened )
{
// Show the overlay
this._showOverlay();
}
}
// Execute the observable
this.modeChanged.next(currentMode);
// Enable the animations after a delay
// The delay must be bigger than the current transition-duration
// to make sure nothing will be animated while the mode changing
setTimeout(() =>
{
this._enableAnimations();
}, 500);
}
// Navigation
if ( 'navigation' in changes )
{
// Mark for check
this._changeDetectorRef.markForCheck();
}
// Opened
if ( 'opened' in changes )
{
// Coerce the value to a boolean
this.opened = coerceBooleanProperty(changes.opened.currentValue);
// Open/close the navigation
this._toggleOpened(this.opened);
}
// Position
if ( 'position' in changes )
{
// Execute the observable
this.positionChanged.next(changes.position.currentValue);
}
// Transparent overlay
if ( 'transparentOverlay' in changes )
{
// Coerce the value to a boolean
this.transparentOverlay = coerceBooleanProperty(changes.transparentOverlay.currentValue);
}
}
/**
* On init
*/
ngOnInit(): void
{
// Make sure the name input is not an empty string
if ( this.name === '' )
{
this.name = this._fuseUtilsService.randomId();
}
// Register the navigation component
this._fuseNavigationService.registerComponent(this.name, this);
// Subscribe to the 'NavigationEnd' event
this._router.events
.pipe(
filter(event => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll),
)
.subscribe(() =>
{
// If the mode is 'over' and the navigation is opened...
if ( this.mode === 'over' && this.opened )
{
// Close the navigation
this.close();
}
// If the mode is 'side' and the aside is active...
if ( this.mode === 'side' && this.activeAsideItemId )
{
// Close the aside
this.closeAside();
}
});
}
/**
* After view init
*/
ngAfterViewInit(): void
{
// Fix for Firefox.
//
// Because 'position: sticky' doesn't work correctly inside a 'position: fixed' parent,
// adding the '.cdk-global-scrollblock' to the html element breaks the navigation's position.
// This fixes the problem by reading the 'top' value from the html element and adding it as a
// 'marginTop' to the navigation itself.
this._mutationObserver = new MutationObserver((mutations) =>
{
mutations.forEach((mutation) =>
{
const mutationTarget = mutation.target as HTMLElement;
if ( mutation.attributeName === 'class' )
{
if ( mutationTarget.classList.contains('cdk-global-scrollblock') )
{
const top = parseInt(mutationTarget.style.top, 10);
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', `${Math.abs(top)}px`);
}
else
{
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', null);
}
}
});
});
this._mutationObserver.observe(this._document.documentElement, {
attributes : true,
attributeFilter: ['class'],
});
setTimeout(() =>
{
// Return if 'navigation content' element does not exist
if ( !this._navigationContentEl )
{
return;
}
// If 'navigation content' element doesn't have
// perfect scrollbar activated on it...
if ( !this._navigationContentEl.nativeElement.classList.contains('ps') )
{
// Find the active item
const activeItem = this._navigationContentEl.nativeElement.querySelector('.fuse-vertical-navigation-item-active');
// If the active item exists, scroll it into view
if ( activeItem )
{
activeItem.scrollIntoView();
}
}
// Otherwise
else
{
// Go through all the scrollbar directives
this._fuseScrollbarDirectives.forEach((fuseScrollbarDirective) =>
{
// Skip if not enabled
if ( !fuseScrollbarDirective.isEnabled() )
{
return;
}
// Scroll to the active element
fuseScrollbarDirective.scrollToElement('.fuse-vertical-navigation-item-active', -120, true);
});
}
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Disconnect the mutation observer
this._mutationObserver.disconnect();
// Forcefully close the navigation and aside in case they are opened
this.close();
this.closeAside();
// Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Refresh the component to apply the changes
*/
refresh(): void
{
// Mark for check
this._changeDetectorRef.markForCheck();
// Execute the observable
this.onRefreshed.next(true);
}
/**
* Open the navigation
*/
open(): void
{
// Return if the navigation is already open
if ( this.opened )
{
return;
}
// Set the opened
this._toggleOpened(true);
}
/**
* Close the navigation
*/
close(): void
{
// Return if the navigation is already closed
if ( !this.opened )
{
return;
}
// Close the aside
this.closeAside();
// Set the opened
this._toggleOpened(false);
}
/**
* Toggle the navigation
*/
toggle(): void
{
// Toggle
if ( this.opened )
{
this.close();
}
else
{
this.open();
}
}
/**
* Open the aside
*
* @param item
*/
openAside(item: FuseNavigationItem): void
{
// Return if the item is disabled
if ( item.disabled || !item.id )
{
return;
}
// Open
this.activeAsideItemId = item.id;
// Show the aside overlay
this._showAsideOverlay();
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Close the aside
*/
closeAside(): void
{
// Close
this.activeAsideItemId = null;
// Hide the aside overlay
this._hideAsideOverlay();
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Toggle the aside
*
* @param item
*/
toggleAside(item: FuseNavigationItem): void
{
// Toggle
if ( this.activeAsideItemId === item.id )
{
this.closeAside();
}
else
{
this.openAside(item);
}
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Enable the animations
*
* @private
*/
private _enableAnimations(): void
{
// Return if the animations are already enabled
if ( this._animationsEnabled )
{
return;
}
// Enable the animations
this._animationsEnabled = true;
}
/**
* Disable the animations
*
* @private
*/
private _disableAnimations(): void
{
// Return if the animations are already disabled
if ( !this._animationsEnabled )
{
return;
}
// Disable the animations
this._animationsEnabled = false;
}
/**
* Show the overlay
*
* @private
*/
private _showOverlay(): void
{
// Return if there is already an overlay
if ( this._asideOverlay )
{
return;
}
// Create the overlay element
this._overlay = this._renderer2.createElement('div');
// Add a class to the overlay element
this._overlay.classList.add('fuse-vertical-navigation-overlay');
// Add a class depending on the transparentOverlay option
if ( this.transparentOverlay )
{
this._overlay.classList.add('fuse-vertical-navigation-overlay-transparent');
}
// Append the overlay to the parent of the navigation
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay);
// Enable block scroll strategy
this._scrollStrategy.enable();
// Create the enter animation and attach it to the player
this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})),
]).create(this._overlay);
// Play the animation
this._player.play();
// Add an event listener to the overlay
this._overlay.addEventListener('click', this._handleOverlayClick);
}
/**
* Hide the overlay
*
* @private
*/
private _hideOverlay(): void
{
if ( !this._overlay )
{
return;
}
// Create the leave animation and attach it to the player
this._player = this._animationBuilder.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._overlay);
// Play the animation
this._player.play();
// Once the animation is done...
this._player.onDone(() =>
{
// If the overlay still exists...
if ( this._overlay )
{
// Remove the event listener
this._overlay.removeEventListener('click', this._handleOverlayClick);
// Remove the overlay
this._overlay.parentNode.removeChild(this._overlay);
this._overlay = null;
}
// Disable block scroll strategy
this._scrollStrategy.disable();
});
}
/**
* Show the aside overlay
*
* @private
*/
private _showAsideOverlay(): void
{
// Return if there is already an overlay
if ( this._asideOverlay )
{
return;
}
// Create the aside overlay element
this._asideOverlay = this._renderer2.createElement('div');
// Add a class to the aside overlay element
this._asideOverlay.classList.add('fuse-vertical-navigation-aside-overlay');
// Append the aside overlay to the parent of the navigation
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._asideOverlay);
// Create the enter animation and attach it to the player
this._player =
this._animationBuilder
.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})),
]).create(this._asideOverlay);
// Play the animation
this._player.play();
// Add an event listener to the aside overlay
this._asideOverlay.addEventListener('click', this._handleAsideOverlayClick);
}
/**
* Hide the aside overlay
*
* @private
*/
private _hideAsideOverlay(): void
{
if ( !this._asideOverlay )
{
return;
}
// Create the leave animation and attach it to the player
this._player =
this._animationBuilder
.build([
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 0})),
]).create(this._asideOverlay);
// Play the animation
this._player.play();
// Once the animation is done...
this._player.onDone(() =>
{
// If the aside overlay still exists...
if ( this._asideOverlay )
{
// Remove the event listener
this._asideOverlay.removeEventListener('click', this._handleAsideOverlayClick);
// Remove the aside overlay
this._asideOverlay.parentNode.removeChild(this._asideOverlay);
this._asideOverlay = null;
}
});
}
/**
* Open/close the navigation
*
* @param open
* @private
*/
private _toggleOpened(open: boolean): void
{
// Set the opened
this.opened = open;
// Enable the animations
this._enableAnimations();
// If the navigation opened, and the mode
// is 'over', show the overlay
if ( this.mode === 'over' )
{
if ( this.opened )
{
this._showOverlay();
}
else
{
this._hideOverlay();
}
}
// Execute the observable
this.openedChanged.next(open);
}
}
@@ -1 +0,0 @@
export * from '@fuse/directives/scroll-reset/public-api';

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