Compare commits

...

82 Commits

Author SHA1 Message Date
sercan
4287361a09 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:49:22 +03:00
sercan
4f19eb6171 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:48:48 +03:00
sercan
49cccde93b Increased the version number & updated the changelog 2021-07-16 20:47:50 +03:00
sercan
952b64297b (fuse/confirmation) Fixed: Confirmation dialog colors are not correct for the Dark mode 2021-07-16 20:45:35 +03:00
sercan
9b3ff6a724 Updated changelog 2021-07-16 12:56:35 +03:00
sercan
cd13f9d9a4 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:38:44 +03:00
sercan
db8c52f093 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:36:58 +03:00
sercan
961b86c8cb (apps/contacts) Added confirmation to the "Delete contact" action using FuseConfirmationService
(apps/ecommerce/inventory) Added confirmation to the "Delete product" action using FuseConfirmationService
(apps/scrumboard) Added confirmation to the "Delete list" action using FuseConfirmationService
(apps/tasks) Added confirmation to the "Delete task" action using FuseConfirmationService
2021-07-16 12:28:43 +03:00
sercan
8b977c0eeb Updated Angular, Angular Material and couple other dependencies & increased the version number 2021-07-16 12:00:46 +03:00
sercan
35e56cd6af (fuse/confirmation) Small tweak on the docs 2021-07-12 12:39:52 +03:00
sercan
c04550b887 (ui/confirmation-dialog) Created a separate page for FuseConfirmationService and moved the example configurator to there for better visibility 2021-07-12 12:37:47 +03:00
sercan
747b4f44c8 (ui/advanced-search) Moved the routing information into the module file 2021-07-12 12:37:06 +03:00
sercan
c4914c80b3 (fuse/confirmation) Small fix on the docs 2021-07-10 22:11:39 +03:00
sercan
178d09597b (fuse/confirmation) First iteration of the FuseConfirmationService 2021-07-10 22:03:58 +03:00
sercan
d206c55e6e (ui/fuse-components) Renamed the component reference 2021-07-09 11:49:21 +03:00
sercan
9abe887df1 (docs) Moved Fuse Components and Other Components into UI for better visibility and better categorization 2021-07-09 11:30:00 +03:00
sercan
b87fdc407c (Navigation) Casing fixes on navigation data 2021-07-09 11:12:52 +03:00
sercan
58440b63a7 (ui/material-components) Renamed the component 2021-07-09 11:12:07 +03:00
sercan
63f6edee9a (tailwindcss) Fixed: Ordered lists with "s" modifier causes builder to throw errors 2021-07-05 23:13:38 +03:00
sercan
2189232273 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:11:01 +03:00
sercan
ca8e422b21 (app.module) Alphabetical order on Router's extra options 2021-07-02 23:10:41 +03:00
sercan
36b89e75db Update package name 2021-07-02 23:05:27 +03:00
sercan
8c2ff122b2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:01:10 +03:00
sercan
cc703081ca (dashboards/analytics) Removed unused chart options declarations 2021-07-02 22:59:47 +03:00
sercan
038c74df50 (transloco) Defined a fallback language 2021-07-02 22:50:25 +03:00
sercan
9abbf5fec2 (karma.conf.js) Updated the default path 2021-07-02 22:50:19 +03:00
sercan
0ebc16ec05 (package.json) Removed "e2e" script since we don't provide e2e testing environment by default 2021-07-02 22:50:10 +03:00
sercan
b2cb512b0e Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:29:26 +03:00
sercan
21652570c2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:28:05 +03:00
sercan
56c4eb0356 Updated changelog 2021-07-01 14:26:49 +03:00
sercan
a8a4f2b18d Updated changelog and increased the version number 2021-07-01 13:31:41 +03:00
sercan
36c8727616 (layout/settings-drawer) Fixed: Issues on small screen devices 2021-07-01 12:55:02 +03:00
sercan
5ea37aed99 (layouts) Fixed: Header buttons are not fitting on certain layouts
(layouts) Hide the "fuse-fullscreen" button on smaller devices since they don't support fullscreen
2021-07-01 12:50:34 +03:00
sercan
cbce71f155 (apps/help-center) Fixed: Small dark mode issues 2021-07-01 12:37:27 +03:00
sercan
ed47050232 (apps/ecommerce/inventory) Fixed: Tags selector border colors are not correct on dark mode 2021-07-01 12:37:09 +03:00
sercan
c86a538d41 (Angular Material) Apply rounded styles by default 2021-07-01 12:23:49 +03:00
sercan
f369206ef8 (layout/common) Explicitly define the overlay position strategy properties
(apps/contacts) Explicitly define the overlay position strategy properties
(apps/mailbox) Explicitly define the overlay position strategy properties
(apps/tasks) Explicitly define the overlay position strategy properties
2021-06-25 22:57:14 +03:00
sercan
1659d4babd (tailwindcss) Fixed: Dark mode classes are not being purged correctly due to the wrong safelist entry 2021-06-25 12:21:34 +03:00
sercan
fa37f99d33 (docs) Use alternative spacing since 12s are removed 2021-06-25 11:09:30 +03:00
sercan
331968ac5b (tailwindcss) Breaking: Removed 5, 6 & 12 fractional spacing values since they are not used in Demo by default and they are mostly not needed because of Flex and Grid. If you happen to use them, you can manually add them back. 2021-06-25 11:08:56 +03:00
sercan
27274c84d6 (@fuse/navigation) Fixed: Vertical navigation blocks scroll if it's destroyed while in 'over' mode and opened 2021-06-24 18:04:19 +03:00
sercan
4b8a101a3e (transloco) Fixed: Language files cannot be loaded if using a base href other than "/" 2021-06-24 10:54:03 +03:00
sercan
8080a85d40 (fuse-drawer) Fixed: Memory leak due to the animation player, thanks to Vadym Pidoplichko for coming up the issue and the solution. 2021-06-24 10:29:34 +03:00
sercan
36784c405f (package.json) Added "description" and "author" fields 2021-06-21 18:56:15 +03:00
sercan
8f4f7886d5 (fuse/navigation) Moved *ngIf directives into their own "ng-container" containers 2021-06-20 21:59:24 +03:00
sercan
d693a08136 (general) Tweaked the "Angular Material components" navigation item title 2021-06-20 21:30:10 +03:00
sercan
0c0ef40de3 (docs) Added docs about navigation tooltip 2021-06-20 21:29:37 +03:00
sercan
f4d737d3a3 (fuse/navigation) Added "tooltip" property to show tooltips on navigation items using MatTooltip 2021-06-20 21:28:47 +03:00
sercan
90891eb201 Merge remote-tracking branch 'origin/demo' into starter 2021-06-15 08:36:32 +03:00
sercan
47d9ddb08c Updated changelog 2021-06-15 08:32:13 +03:00
sercan
4da3612d22 Updated changelog and increased the version number 2021-06-14 14:29:58 +03:00
sercan
403a949d4a (apps/ecommerce/inventory) Small mobile experience tweaks 2021-06-14 12:25:04 +03:00
sercan
5b78a68116 (apps/ecommerce/inventory) Better image containment on row details 2021-06-14 12:22:51 +03:00
sercan
214116e10d (apps/ecommerce/inventory) Replaced the mat-table with a custom grid for better mobile experience and better performance, improved the mobile experience 2021-06-14 12:03:17 +03:00
sercan
5962c80e8d (docs) Added "target" docs to navigation 2021-06-14 08:53:01 +03:00
sercan
ff086b1ed0 (fuse/navigation) Added "target" for setting the target attribute on outgoing links. Thanks @danielehrhardt for the original PR, closes #154 2021-06-14 08:52:29 +03:00
sercan
efdfa6418a (core) Go back to the 'classy' layout by default 2021-06-10 14:56:21 +03:00
sercan
c1c9904b9d (layouts/common/search) Improved the autocomplete design 2021-06-10 14:56:00 +03:00
sercan
39650d3cc9 (layouts) Use navigation service data for horizontal navigation 2021-06-10 10:13:43 +03:00
sercan
bafa9adc01 (ui/page-layouts) Added tabbed version of Simple Fullwidth page layout 2021-06-09 11:41:39 +03:00
sercan
bb9023f9df (fuse/navigation) Fixed: First children of collapsable items don't have proper spacing at the top 2021-06-09 10:32:26 +03:00
sercan
66096718e0 (docs) Updated the docs to reflect the latest changes 2021-06-09 10:22:18 +03:00
sercan
945d0a2240 (fuse/fullscreen) Added [tooltip] & [iconTpl] inputs for customizing the Fullscreen trigger button 2021-06-08 18:29:49 +03:00
sercan
9005f08ac7 (app.resolver) Use services to request the initial data
(layouts) Common components of layouts now requests their data directly from their service rather than getting it from route data
(core) New navigation service to request and store the navigation data
2021-06-08 17:29:45 +03:00
sercan
89f5a4ec69 (core/user) Renamed user.model to user.types for better consistency 2021-06-07 12:18:39 +03:00
sercan
ca7b4c7e5d (ui/advanced-search) Removed unused MatIconModule import 2021-06-07 11:41:29 +03:00
sercan
bb57ec2324 (ui/advanced-search) Added an example search form that uses query parameters for Advanced Search forms 2021-06-07 11:40:33 +03:00
sercan
11ad2c89df (apps/file-manager) Added support for nested folder views 2021-06-05 13:57:39 +03:00
sercan
fc1e7b02b0 (data/navigation) Fixed the "Invoice" icon, added missing dashboard links to the "futuristicNavigation" data 2021-06-04 22:28:53 +03:00
sercan
446bfe4139 (ui/angular-material) Added a component list that redirects to the related page of the official docs 2021-06-04 22:21:47 +03:00
sercan
6c7201b77a Merge remote-tracking branch 'origin/demo' into starter 2021-06-03 13:28:30 +03:00
sercan
2c5cd60c0a (general) Updated version numbers and changelog 2021-06-03 13:25:07 +03:00
sercan
decb238f73 (dependencies) Updated various dependencies to their latest versions
(fuse/highlight) Updated the import path
2021-06-03 13:18:05 +03:00
sercan
ab3ad4fd2f (apps/scrumboard) Dark mode fixes and tweaks 2021-06-03 11:27:51 +03:00
sercan
c2dd77d7a3 (angular.json) Removed "e2e" entry, fixed the styles file path for "test" 2021-06-02 12:45:12 +03:00
sercan
a78b087a68 (apps/scrumboard) New version of the Scrumboard app 2021-06-02 11:42:22 +03:00
sercan
84d40427a1 (apps/ecommerce) Small tweaks
(apps/mailbox) Small tweaks
2021-06-02 11:41:47 +03:00
sercan
f295fd9061 (fuse/autogrow) BREAKING: Removed fuseAutogrow in favor of matTextareaAutosize since all of its problems solved, use [matTextareaAutosize] without any vertical padding on the textarea itself. 2021-05-31 17:14:03 +03:00
sercan
b98cfc1d37 (Angular Material) Increased default MatDialog border radius to 16px for better consistency 2021-05-31 16:12:08 +03:00
sercan
0ba5677c01 (Dependencies) Updated Angular & Angular Material to v12.0.2 2021-05-31 10:49:51 +03:00
sercan
90f869e7b9 Merge remote-tracking branch 'origin/demo' into starter 2021-05-31 10:46:26 +03:00
sercan
96ef1281ae (Angular Material) Fixed: Density setting is not working for dark themes 2021-05-31 10:45:29 +03:00
137 changed files with 6039 additions and 3429 deletions

View File

@@ -120,7 +120,7 @@
"src/assets"
],
"styles": [
"src/styles.scss"
"src/styles/styles.scss"
],
"scripts": []
}
@@ -133,18 +133,6 @@
"src/**/*.html"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
},
"configurations": {
"production": {
"devServerTarget": "fuse:serve:production"
}
}
}
}
}

View File

@@ -26,7 +26,7 @@ module.exports = function (config)
suppressAll: true // removes the duplicated traces
},
coverageReporter : {
dir : require('path').join(__dirname, './coverage/angular12'),
dir : require('path').join(__dirname, './coverage/fuse'),
subdir : '.',
reporters: [
{type: 'html'},

5851
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
{
"name": "@fuse/demo",
"version": "13.0.2",
"name": "@fuse/starter",
"version": "13.3.1",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard",
"private": true,
"scripts": {
@@ -8,21 +10,20 @@
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"lint": "ng lint"
},
"dependencies": {
"@angular/animations": "12.0.0",
"@angular/cdk": "12.0.0",
"@angular/common": "12.0.0",
"@angular/compiler": "12.0.0",
"@angular/core": "12.0.0",
"@angular/forms": "12.0.0",
"@angular/material": "12.0.0",
"@angular/material-moment-adapter": "12.0.0",
"@angular/platform-browser": "12.0.0",
"@angular/platform-browser-dynamic": "12.0.0",
"@angular/router": "12.0.0",
"@angular/animations": "12.1.2",
"@angular/cdk": "12.1.2",
"@angular/common": "12.1.2",
"@angular/compiler": "12.1.2",
"@angular/core": "12.1.2",
"@angular/forms": "12.1.2",
"@angular/material": "12.1.2",
"@angular/material-moment-adapter": "12.1.2",
"@angular/platform-browser": "12.1.2",
"@angular/platform-browser-dynamic": "12.1.2",
"@angular/router": "12.1.2",
"@fullcalendar/angular": "4.4.5-beta",
"@fullcalendar/core": "4.4.2",
"@fullcalendar/daygrid": "4.4.2",
@@ -31,62 +32,59 @@
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"@ngneat/transloco": "2.20.1",
"apexcharts": "3.26.3",
"@ngneat/transloco": "2.22.0",
"apexcharts": "3.27.2",
"crypto-js": "3.3.0",
"highlight.js": "10.7.2",
"highlight.js": "11.1.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"ng-apexcharts": "1.5.10",
"ngx-markdown": "12.0.0",
"ngx-quill": "14.0.0",
"ng-apexcharts": "1.5.12",
"ngx-markdown": "12.0.1",
"ngx-quill": "14.1.2",
"perfect-scrollbar": "1.5.1",
"quill": "1.3.7",
"rrule": "2.6.8",
"rxjs": "6.6.7",
"tslib": "2.2.0",
"tslib": "2.3.0",
"web-animations-js": "2.3.2",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "12.0.0",
"@angular-eslint/builder": "12.0.0",
"@angular-eslint/eslint-plugin": "12.0.0",
"@angular-eslint/eslint-plugin-template": "12.0.0",
"@angular-eslint/schematics": "12.0.0",
"@angular-eslint/template-parser": "12.0.0",
"@angular/cli": "12.0.0",
"@angular/compiler-cli": "12.0.0",
"@angular/language-service": "12.0.0",
"@tailwindcss/aspect-ratio": "0.2.0",
"@tailwindcss/line-clamp": "0.2.0",
"@tailwindcss/typography": "0.4.0",
"@angular-devkit/build-angular": "12.1.2",
"@angular-eslint/builder": "12.3.1",
"@angular-eslint/eslint-plugin": "12.3.1",
"@angular-eslint/eslint-plugin-template": "12.3.1",
"@angular-eslint/schematics": "12.3.1",
"@angular-eslint/template-parser": "12.3.1",
"@angular/cli": "12.1.2",
"@angular/compiler-cli": "12.1.2",
"@tailwindcss/aspect-ratio": "0.2.1",
"@tailwindcss/line-clamp": "0.2.1",
"@tailwindcss/typography": "0.4.1",
"@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0",
"@types/jasmine": "3.6.11",
"@types/lodash": "4.14.169",
"@types/jasmine": "3.8.1",
"@types/lodash": "4.14.171",
"@types/lodash-es": "4.17.4",
"@types/node": "12.20.13",
"@typescript-eslint/eslint-plugin": "4.24.0",
"@typescript-eslint/parser": "4.24.0",
"autoprefixer": "10.2.5",
"@types/node": "12.20.16",
"@typescript-eslint/eslint-plugin": "4.28.3",
"@typescript-eslint/parser": "4.28.3",
"autoprefixer": "10.3.1",
"chroma-js": "2.1.2",
"eslint": "7.26.0",
"eslint-plugin-import": "2.23.2",
"eslint-plugin-jsdoc": "34.8.2",
"eslint": "7.30.0",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-jsdoc": "35.4.3",
"eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.7.1",
"jasmine-spec-reporter": "5.0.2",
"karma": "6.3.2",
"jasmine-core": "3.8.0",
"karma": "6.3.4",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "2.0.3",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.6.0",
"karma-jasmine-html-reporter": "1.7.0",
"lodash": "4.17.21",
"postcss": "8.3.0",
"protractor": "7.0.0",
"tailwindcss": "2.1.2",
"typescript": "4.2.4"
"postcss": "8.3.5",
"tailwindcss": "2.2.4",
"typescript": "4.3.5"
}
}

View File

@@ -341,6 +341,13 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1}))
]).create(this._overlay);
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
});
// Play the animation
this._player.play();
@@ -373,6 +380,9 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
// If the backdrop still exists...
if ( this._overlay )
{

View File

@@ -1,7 +1,12 @@
<!-- Button -->
<button
mat-icon-button
[matTooltip]="'Toggle Fullscreen'"
[matTooltip]="tooltip || 'Toggle Fullscreen'"
(click)="toggleFullscreen()">
<mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon>
<ng-container [ngTemplateOutlet]="iconTpl || defaultIconTpl"></ng-container>
</button>
<!-- Default icon -->
<ng-template #defaultIconTpl>
<mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon>
</ng-template>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types';
@@ -11,6 +11,8 @@ import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fulls
})
export class FuseFullscreenComponent implements OnInit
{
@Input() iconTpl: TemplateRef<any>;
@Input() tooltip: string;
private _fsDoc: FSDocument;
private _fsDocEl: FSDocumentElement;
private _isFullscreen: boolean = false;

View File

@@ -3,15 +3,17 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseFullscreenComponent } from '@fuse/components/fullscreen/fullscreen.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
FuseFullscreenComponent
],
imports : [
imports: [
MatButtonModule,
MatIconModule,
MatTooltipModule
MatTooltipModule,
CommonModule
],
exports : [
FuseFullscreenComponent

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import * as hljs from 'highlight.js';
import hljs from 'highlight.js';
@Injectable({
providedIn: 'root'

View File

@@ -5,69 +5,83 @@
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an external link -->
<a
class="fuse-horizontal-navigation-item"
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
<a
class="fuse-horizontal-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an external link and function -->
<a
class="fuse-horizontal-navigation-item"
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link"
(click)="item.function(item)"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
<a
class="fuse-horizontal-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function -->
<div
class="fuse-horizontal-navigation-item"
*ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && !item.function && !item.disabled">
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled -->
<div
class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled"
*ngIf="item.disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.disabled">
<div class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
</div>
@@ -75,11 +89,12 @@
<ng-template #itemTemplate>
<!-- Icon -->
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -88,24 +103,24 @@
{{item.title}}
</span>
</div>
<div
class="fuse-horizontal-navigation-item-subtitle text-hint"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-horizontal-navigation-item-subtitle text-hint">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-horizontal-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-horizontal-navigation-item-badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</ng-template>

View File

@@ -1,59 +1,63 @@
<div
*ngIf="!child"
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
<ng-container *ngIf="!child">
<div
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
'fuse-horizontal-navigation-menu-active-forced': item.active}"
[matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div>
[matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div>
</ng-container>
<mat-menu
class="fuse-horizontal-navigation-menu-panel"
[overlapTrigger]="false"
#matMenu="matMenu">
<ng-container *ngFor="let item of item.children">
<ng-container *ngFor="let item of item.children; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'basic'"
[disabled]="item.disabled"
mat-menu-item>
<fuse-horizontal-navigation-basic-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</div>
<ng-container *ngIf="item.type === 'basic'">
<div
class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled"
mat-menu-item>
<fuse-horizontal-navigation-basic-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</div>
</ng-container>
<!-- Branch: aside, collapsable, group -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item
[child]="true"
[item]="item"
[name]="name"
#branch></fuse-horizontal-navigation-branch-item>
</div>
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
<div
class="fuse-horizontal-navigation-menu-item"
[disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu"
mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item
[child]="true"
[item]="item"
[name]="name"
#branch></fuse-horizontal-navigation-branch-item>
</div>
</ng-container>
<!-- Divider -->
<div
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'divider'"
mat-menu-item>
<fuse-horizontal-navigation-divider-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item>
</div>
<ng-container *ngIf="item.type === 'divider'">
<div
class="fuse-horizontal-navigation-menu-item"
mat-menu-item>
<fuse-horizontal-navigation-divider-item
[item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item>
</div>
</ng-container>
</ng-container>
@@ -74,14 +78,16 @@
<div
class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled,
'fuse-horizontal-navigation-item-active-forced': item.active}">
'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<!-- Icon -->
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-horizontal-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -90,25 +96,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-horizontal-navigation-item-subtitle text-hint"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-horizontal-navigation-item-subtitle text-hint">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-horizontal-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-horizontal-navigation-item-badge">
<div
class="fuse-horizontal-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
</div>

View File

@@ -81,4 +81,15 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -1,30 +1,33 @@
<div class="fuse-horizontal-navigation-wrapper">
<ng-container *ngFor="let item of navigation">
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-horizontal-navigation-basic-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-horizontal-navigation-basic-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item>
</ng-container>
<!-- Branch: aside, collapsable, group -->
<fuse-horizontal-navigation-branch-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item>
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'">
<fuse-horizontal-navigation-branch-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item>
</ng-container>
<!-- Spacer -->
<fuse-horizontal-navigation-spacer-item
class="fuse-horizontal-navigation-menu-item"
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-horizontal-navigation-spacer-item
class="fuse-horizontal-navigation-menu-item"
[item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item>
</ng-container>
</ng-container>

View File

@@ -15,8 +15,15 @@ export interface FuseNavigationItem
hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean;
disabled?: boolean;
tooltip?: string;
link?: string;
externalLink?: boolean;
target?:
| '_blank'
| '_self'
| '_parent'
| '_top'
| string;
exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void;

View File

@@ -7,14 +7,16 @@
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active': active,
'fuse-vertical-navigation-item-disabled': item.disabled,
'fuse-vertical-navigation-item-active-forced': item.active}">
'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -23,25 +25,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
@@ -57,35 +59,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>

View File

@@ -5,68 +5,84 @@
[ngClass]="item.classes?.wrapper">
<!-- Item with an internal link -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with an external link -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function -->
<div
class="fuse-vertical-navigation-item"
*ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && item.function && !item.disabled">
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item with an internal link and function -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with an external link and function -->
<a
class="fuse-vertical-navigation-item"
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled">
<a
class="fuse-vertical-navigation-item"
[href]="item.link"
[target]="item.target || '_self'"
[matTooltip]="item.tooltip || ''"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function -->
<div
class="fuse-vertical-navigation-item"
*ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="!item.link && !item.function && !item.disabled">
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
<!-- Item is disabled -->
<div
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
*ngIf="item.disabled">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
<ng-container *ngIf="item.disabled">
<div
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
[matTooltip]="item.tooltip || ''">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
</ng-container>
</div>
@@ -74,11 +90,12 @@
<ng-template #itemTemplate>
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -87,24 +104,24 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</ng-template>

View File

@@ -6,14 +6,16 @@
<div
class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}"
[matTooltip]="item.tooltip || ''"
(click)="toggleCollapsable()">
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -22,25 +24,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
<!-- Arrow -->
<mat-icon
@@ -62,35 +64,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>

View File

@@ -7,11 +7,12 @@
<div class="fuse-vertical-navigation-item">
<!-- Icon -->
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
*ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon>
<ng-container *ngIf="item.icon">
<mat-icon
class="fuse-vertical-navigation-item-icon"
[ngClass]="item.classes?.icon"
[svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper">
@@ -20,25 +21,25 @@
{{item.title}}
</span>
</div>
<div
class="fuse-vertical-navigation-item-subtitle"
*ngIf="item.subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
<ng-container *ngIf="item.subtitle">
<div class="fuse-vertical-navigation-item-subtitle">
<span [ngClass]="item.classes?.subtitle">
{{item.subtitle}}
</span>
</div>
</ng-container>
</div>
<!-- Badge -->
<div
class="fuse-vertical-navigation-item-badge"
*ngIf="item.badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
<ng-container *ngIf="item.badge">
<div class="fuse-vertical-navigation-item-badge">
<div
class="fuse-vertical-navigation-item-badge-content"
[ngClass]="item.badge.classes">
{{item.badge.title}}
</div>
</div>
</div>
</ng-container>
</div>
@@ -50,35 +51,40 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>

View File

@@ -335,6 +335,7 @@ fuse-vertical-navigation {
}
> .fuse-vertical-navigation-item-children {
margin-top: 6px;
> *:last-child {
padding-bottom: 6px;

View File

@@ -24,46 +24,52 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside -->
<fuse-vertical-navigation-aside-item
*ngIf="item.type === 'aside'"
[item]="item"
[name]="name"
[activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse"
[skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
<ng-container *ngIf="item.type === 'aside'">
<fuse-vertical-navigation-aside-item
[item]="item"
[name]="name"
[activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse"
[skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
</ng-container>
<!-- Basic -->
<fuse-vertical-navigation-basic-item
*ngIf="item.type === 'basic'"
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
<ng-container *ngIf="item.type === 'basic'">
<fuse-vertical-navigation-basic-item
[item]="item"
[name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable -->
<fuse-vertical-navigation-collapsable-item
*ngIf="item.type === 'collapsable'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
<ng-container *ngIf="item.type === 'collapsable'">
<fuse-vertical-navigation-collapsable-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider -->
<fuse-vertical-navigation-divider-item
*ngIf="item.type === 'divider'"
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
<ng-container *ngIf="item.type === 'divider'">
<fuse-vertical-navigation-divider-item
[item]="item"
[name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group -->
<fuse-vertical-navigation-group-item
*ngIf="item.type === 'group'"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
<ng-container *ngIf="item.type === 'group'">
<fuse-vertical-navigation-group-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer -->
<fuse-vertical-navigation-spacer-item
*ngIf="item.type === 'spacer'"
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
<ng-container *ngIf="item.type === 'spacer'">
<fuse-vertical-navigation-spacer-item
[item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container>
@@ -84,31 +90,33 @@
</div>
<!-- Aside -->
<div
class="fuse-vertical-navigation-aside-wrapper"
*ngIf="activeAsideItemId"
fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'">
<ng-container *ngIf="activeAsideItemId">
<div
class="fuse-vertical-navigation-aside-wrapper"
fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'">
<!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside -->
<fuse-vertical-navigation-aside-item
*ngIf="item.type === 'aside' && item.id === activeAsideItemId"
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
<!-- Aside -->
<ng-container *ngIf="item.type === 'aside' && item.id === activeAsideItemId">
<fuse-vertical-navigation-aside-item
[item]="item"
[name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</div>
</div>
</ng-container>

View File

@@ -374,6 +374,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/
ngOnDestroy(): void
{
// Forcefully close the navigation and aside in case they are opened
this.close();
this.closeAside();
// Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name);

View File

@@ -1,114 +0,0 @@
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, HostListener, Input, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Subject } from 'rxjs';
@Directive({
selector: 'textarea[fuseAutogrow]',
exportAs: 'fuseAutogrow'
})
export class FuseAutogrowDirective implements OnChanges, OnInit, OnDestroy
{
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('fuseAutogrowVerticalPadding') padding: number = 8;
@HostBinding('rows') private _rows: number = 1;
private _height: string = 'auto';
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private _ngZone: NgZone
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'height' : this._height,
'overflow': 'hidden',
'resize' : 'none'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* Resize on 'input' and 'ngModelChange' events
*
* @private
*/
@HostListener('input')
@HostListener('ngModelChange')
private _resize(): void
{
// This doesn't need to trigger Angular's change detection by itself
this._ngZone.runOutsideAngular(() => {
setTimeout(() => {
// Set the height to 'auto' so we can correctly read the scrollHeight
this._height = 'auto';
// Detect the changes so the height is applied
this._changeDetectorRef.detectChanges();
// Get the scrollHeight and subtract the vertical padding
this._height = `${this._elementRef.nativeElement.scrollHeight - this.padding}px`;
// Detect the changes one more time to apply the final height
this._changeDetectorRef.detectChanges();
});
});
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Padding
if ( 'fuseAutogrowVerticalPadding' in changes )
{
// Resize
this._resize();
}
}
/**
* On init
*/
ngOnInit(): void
{
// Resize for the first time
this._resize();
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

@@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FuseAutogrowDirective } from '@fuse/directives/autogrow/autogrow.directive';
@NgModule({
declarations: [
FuseAutogrowDirective
],
exports : [
FuseAutogrowDirective
]
})
export class FuseAutogrowModule
{
}

View File

@@ -1 +0,0 @@
export * from '@fuse/directives/autogrow/public-api';

View File

@@ -1,2 +0,0 @@
export * from '@fuse/directives/autogrow/autogrow.directive';
export * from '@fuse/directives/autogrow/autogrow.module';

View File

@@ -1,5 +1,6 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseConfirmationModule } from '@fuse/services/confirmation';
import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module';
import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module';
import { FuseTailwindConfigModule } from '@fuse/services/tailwind/tailwind.module';
@@ -7,6 +8,7 @@ import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@NgModule({
imports : [
FuseConfirmationModule,
FuseMediaWatcherModule,
FuseSplashScreenModule,
FuseTailwindConfigModule,

View File

@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { FuseConfirmationService } from '@fuse/services/confirmation/confirmation.service';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
FuseConfirmationDialogComponent
],
imports: [
MatButtonModule,
MatDialogModule,
MatIconModule,
CommonModule
],
providers : [
FuseConfirmationService
]
})
export class FuseConfirmationModule
{
/**
* Constructor
*/
constructor(private _fuseConfirmationService: FuseConfirmationService)
{
}
}

View File

@@ -0,0 +1,57 @@
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { merge } from 'lodash-es';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Injectable()
export class FuseConfirmationService
{
private _defaultConfig: FuseConfirmationConfig = {
title : 'Confirm action',
message : 'Are you sure you want to confirm this action?',
icon : {
show : true,
name : 'heroicons_outline:exclamation',
color: 'warn'
},
actions : {
confirm: {
show : true,
label: 'Confirm',
color: 'warn'
},
cancel : {
show : true,
label: 'Cancel'
}
},
dismissible: false
};
/**
* Constructor
*/
constructor(
private _matDialog: MatDialog
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
open(config: FuseConfirmationConfig = {}): MatDialogRef<FuseConfirmationDialogComponent>
{
// Merge the user config with the default config
const userConfig = merge({}, this._defaultConfig, config);
// Open the dialog
return this._matDialog.open(FuseConfirmationDialogComponent, {
autoFocus : false,
disableClose: !userConfig.dismissible,
data : userConfig
});
}
}

View File

@@ -0,0 +1,22 @@
export interface FuseConfirmationConfig
{
title?: string;
message?: string;
icon?: {
show?: boolean;
name?: string;
color?: 'primary' | 'accent' | 'warn' | 'basic' | 'info' | 'success' | 'warning' | 'error';
};
actions?: {
confirm?: {
show?: boolean;
label?: string;
color?: 'primary' | 'accent' | 'warn';
};
cancel?: {
show?: boolean;
label?: string;
};
};
dismissible?: boolean;
}

View File

@@ -0,0 +1,85 @@
<div class="relative flex flex-col md:w-128 -m-6">
<!-- Dismiss button -->
<ng-container *ngIf="data.dismissible">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button
mat-icon-button
[matDialogClose]="undefined">
<mat-icon
class="text-secondary"
[svgIcon]="'heroicons_outline:x'"></mat-icon>
</button>
</div>
</ng-container>
<!-- Content -->
<div class="flex flex-col sm:flex-row items-center sm:items-start p-8 pb-6 sm:pb-8">
<!-- Icon -->
<ng-container *ngIf="data.icon.show">
<div
class="flex flex-0 items-center justify-center w-10 h-10 sm:mr-4 rounded-full"
[ngClass]="{'text-primary-600 bg-primary-100 dark:text-primary-50 dark:bg-primary-600': data.icon.color === 'primary',
'text-accent-600 bg-accent-100 dark:text-accent-50 dark:bg-accent-600': data.icon.color === 'accent',
'text-warn-600 bg-warn-100 dark:text-warn-50 dark:bg-warn-600': data.icon.color === 'warn',
'text-gray-600 bg-gray-100 dark:text-gray-50 dark:bg-gray-600': data.icon.color === 'basic',
'text-blue-600 bg-blue-100 dark:text-blue-50 dark:bg-blue-600': data.icon.color === 'info',
'text-green-500 bg-green-100 dark:text-green-50 dark:bg-green-500': data.icon.color === 'success',
'text-amber-500 bg-amber-100 dark:text-amber-50 dark:bg-amber-500': data.icon.color === 'warning',
'text-red-600 bg-red-100 dark:text-red-50 dark:bg-red-600': data.icon.color === 'error'
}">
<mat-icon
class="text-current"
[svgIcon]="data.icon.name"></mat-icon>
</div>
</ng-container>
<ng-container *ngIf="data.title || data.message">
<div class="flex flex-col items-center sm:items-start mt-4 sm:mt-0 sm:pr-8 space-y-1 text-center sm:text-left">
<!-- Title -->
<ng-container *ngIf="data.title">
<div
class="text-xl leading-6 font-medium"
[innerHTML]="data.title"></div>
</ng-container>
<!-- Message -->
<ng-container *ngIf="data.message">
<div
class="text-secondary"
[innerHTML]="data.message"></div>
</ng-container>
</div>
</ng-container>
</div>
<!-- Actions -->
<ng-container *ngIf="data.actions.confirm.show || data.actions.cancel.show">
<div class="flex items-center justify-center sm:justify-end px-6 py-4 space-x-3 bg-gray-50 dark:bg-black dark:bg-opacity-10">
<!-- Cancel -->
<ng-container *ngIf="data.actions.cancel.show">
<button
mat-stroked-button
[matDialogClose]="'cancelled'">
{{data.actions.cancel.label}}
</button>
</ng-container>
<!-- Confirm -->
<ng-container *ngIf="data.actions.confirm.show">
<button
mat-flat-button
[color]="data.actions.confirm.color"
[matDialogClose]="'confirmed'">
{{data.actions.confirm.label}}
</button>
</ng-container>
</div>
</ng-container>
</div>

View File

@@ -0,0 +1,38 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Component({
selector : 'fuse-confirmation-dialog',
templateUrl : './dialog.component.html',
encapsulation: ViewEncapsulation.None
})
export class FuseConfirmationDialogComponent implements OnInit
{
/**
* Constructor
*/
constructor(
@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig,
public matDialogRef: MatDialogRef<FuseConfirmationDialogComponent>
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
}

View File

@@ -0,0 +1 @@
export * from '@fuse/services/confirmation/public-api';

View File

@@ -0,0 +1,3 @@
export * from '@fuse/services/confirmation/confirmation.module';
export * from '@fuse/services/confirmation/confirmation.service';
export * from '@fuse/services/confirmation/confirmation.types';

View File

@@ -136,11 +136,8 @@
.mat-flat-button,
.mat-raised-button,
.mat-stroked-button {
.fuse-mat-rounded & {
padding: 0 20px;
border-radius: 9999px;
}
padding: 0 20px !important;
border-radius: 9999px !important;
}
/* Target all buttons */
@@ -334,6 +331,8 @@
/* @ Button Toggle
/* ----------------------------------------------------------------------------------------------------- */
.mat-button-toggle-group {
border: none !important;
@apply space-x-1;
&.mat-button-toggle-group-appearance-standard {
@@ -341,36 +340,27 @@
background-clip: padding-box;
}
}
}
/* Rounded design */
.fuse-mat-rounded {
.mat-button-toggle-group {
.mat-button-toggle {
border-radius: 9999px;
overflow: hidden;
border: none !important;
@apply space-x-1;
font-weight: 500;
.mat-button-toggle {
border-radius: 9999px;
overflow: hidden;
border: none !important;
font-weight: 500;
&.mat-button-toggle-checked {
.mat-button-toggle-label-content {
@apply text-default #{'!important'};
}
}
&.mat-button-toggle-checked {
.mat-button-toggle-label-content {
padding: 0 20px;
@apply text-secondary;
@apply text-default #{'!important'};
}
}
.mat-ripple {
border-radius: 9999px;
}
.mat-button-toggle-label-content {
padding: 0 20px;
@apply text-secondary;
}
.mat-ripple {
border-radius: 9999px;
}
}
}
@@ -410,6 +400,13 @@
font-weight: 500 !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Dialog
/* ----------------------------------------------------------------------------------------------------- */
.mat-dialog-container {
border-radius: 16px !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Drawer
/* ----------------------------------------------------------------------------------------------------- */
@@ -683,8 +680,8 @@
align-self: stretch;
min-height: 36px;
height: auto;
margin: 10px 0;
padding: 4px 6px 4px 0 !important;
margin: 14px 0;
padding: 0 6px 0 0;
transform: none;
}
@@ -1322,62 +1319,55 @@
opacity: 0 !important;
}
}
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
}
.mat-tab-label {
opacity: 1 !important;
}
/* Rounded design */
.fuse-mat-rounded {
.mat-tab-group {
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
}
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Textarea
/* ----------------------------------------------------------------------------------------------------- */

View File

@@ -1,21 +1,24 @@
@use '~@angular/material' as mat;
@use "sass:map";
/** Include the core Angular Material styles */
/* Include the core Angular Material styles */
@include mat.core();
/** Configure the Angular Material typography */
@include mat.all-component-typographies(
mat.define-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat.define-typography-level(1.25rem, 2rem, 600),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) // line-height: 20px
)
);
/* Create a base theme without color.
This will globally set the density and typography for all future color themes. */
@include mat.all-component-themes((
color: null,
density: -2,
typography: mat.define-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat.define-typography-level(1.25rem, 2rem, 600),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
)
));
/** Prepare the Background and Foreground maps */
/* Prepare the Background and Foreground maps */
$background-light: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
@@ -90,7 +93,7 @@ $foreground-dark: (
slider-off-active: #94A3B8 /* blueGray.400 */
);
/** Generate Primary, Accent and Warn palettes */
/* Generate Primary, Accent and Warn palettes */
$palettes: ();
@each $name in (primary, accent, warn) {
$palettes: map.merge($palettes, (#{$name}: (
@@ -126,7 +129,7 @@ $palettes: ();
)));
}
/** Generate Angular Material themes. Since we are using CSS Custom Properties,
/* Generate Angular Material themes. Since we are using CSS Custom Properties,
we don't have to generate a separate Angular Material theme for each color
set. We can just create one light and one dark theme and then switch the
CSS Custom Properties to dynamically switch the colors. */
@@ -144,11 +147,11 @@ body .light {
is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: $foreground-light,
background: $background-light
),
density: -2
)
);
@include mat.all-component-themes($light-theme);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($light-theme);
}
body.dark,
@@ -165,9 +168,9 @@ body .dark {
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: $foreground-dark,
background: $background-dark
),
density: -2
)
);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($dark-theme);
}

View File

@@ -1,3 +1,3 @@
import { Version } from '@fuse/version/version';
export const FUSE_VERSION = new Version('13.0.2').full;
export const FUSE_VERSION = new Version('13.3.1').full;

View File

@@ -14,8 +14,8 @@ import { AppComponent } from 'app/app.component';
import { appRoutes } from 'app/app.routing';
const routerConfig: ExtraOptions = {
scrollPositionRestoration: 'enabled',
preloadingStrategy : PreloadAllModules
preloadingStrategy : PreloadAllModules,
scrollPositionRestoration: 'enabled'
};
@NgModule({

View File

@@ -1,9 +1,11 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { InitialData } from 'app/app.types';
import { MessagesService } from 'app/layout/common/messages/messages.service';
import { NavigationService } from 'app/core/navigation/navigation.service';
import { NotificationsService } from 'app/layout/common/notifications/notifications.service';
import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service';
import { UserService } from 'app/core/user/user.service';
@Injectable({
providedIn: 'root'
@@ -13,7 +15,13 @@ export class InitialDataResolver implements Resolve<any>
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
constructor(
private _messagesService: MessagesService,
private _navigationService: NavigationService,
private _notificationsService: NotificationsService,
private _shortcutsService: ShortcutsService,
private _userService: UserService
)
{
}
@@ -27,29 +35,15 @@ export class InitialDataResolver implements Resolve<any>
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<InitialData>
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any>
{
// Fork join multiple API endpoint calls to wait all of them to finish
return forkJoin([
this._httpClient.get<any>('api/common/messages'),
this._httpClient.get<any>('api/common/navigation'),
this._httpClient.get<any>('api/common/notifications'),
this._httpClient.get<any>('api/common/shortcuts'),
this._httpClient.get<any>('api/common/user')
]).pipe(
map(([messages, navigation, notifications, shortcuts, user]) => ({
messages,
navigation: {
compact : navigation.compact,
default : navigation.default,
futuristic: navigation.futuristic,
horizontal: navigation.horizontal
},
notifications,
shortcuts,
user
})
)
);
this._navigationService.get(),
this._messagesService.getAll(),
this._notificationsService.getAll(),
this._shortcutsService.getAll(),
this._userService.get()
]);
}
}

View File

@@ -1,19 +0,0 @@
import { FuseNavigationItem } from '@fuse/components/navigation';
import { Message } from 'app/layout/common/messages/messages.types';
import { Notification } from 'app/layout/common/notifications/notifications.types';
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
import { User } from 'app/core/user/user.model';
export interface InitialData
{
messages: Message[];
navigation: {
compact: FuseNavigationItem[];
default: FuseNavigationItem[];
futuristic: FuseNavigationItem[];
horizontal: FuseNavigationItem[];
};
notifications: Notification[];
shortcuts: Shortcut[];
user: User;
}

View File

@@ -0,0 +1,48 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Navigation } from 'app/core/navigation/navigation.types';
@Injectable({
providedIn: 'root'
})
export class NavigationService
{
private _navigation: ReplaySubject<Navigation> = new ReplaySubject<Navigation>(1);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for navigation
*/
get navigation$(): Observable<Navigation>
{
return this._navigation.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get all navigation data
*/
get(): Observable<Navigation>
{
return this._httpClient.get<Navigation>('api/common/navigation').pipe(
tap((navigation) => {
this._navigation.next(navigation);
})
);
}
}

View File

@@ -0,0 +1,9 @@
import { FuseNavigationItem } from '@fuse/components/navigation';
export interface Navigation
{
compact: FuseNavigationItem[];
default: FuseNavigationItem[];
futuristic: FuseNavigationItem[];
horizontal: FuseNavigationItem[];
}

View File

@@ -27,6 +27,6 @@ export class TranslocoHttpLoader implements TranslocoLoader
*/
getTranslation(lang: string): Observable<Translation>
{
return this._httpClient.get<Translation>(`/assets/i18n/${lang}.json`);
return this._httpClient.get<Translation>(`./assets/i18n/${lang}.json`);
}
}

View File

@@ -23,6 +23,7 @@ import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
}
],
defaultLang : 'en',
fallbackLang : 'en',
reRenderOnLangChange: true,
prodMode : environment.production
})

View File

@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { User } from 'app/core/user/user.model';
import { map, tap } from 'rxjs/operators';
import { User } from 'app/core/user/user.types';
@Injectable({
providedIn: 'root'
@@ -42,6 +42,18 @@ export class UserService
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get the current logged in user data
*/
get(): Observable<User>
{
return this._httpClient.get<User>('api/common/user').pipe(
tap((user) => {
this._user.next(user);
})
);
}
/**
* Update the user
*
@@ -51,7 +63,6 @@ export class UserService
{
return this._httpClient.patch<User>('api/common/user', {user}).pipe(
map((response) => {
// Execute the observable
this._user.next(response);
})
);

View File

@@ -4,13 +4,13 @@ import { AvailableLangs, TranslocoService } from '@ngneat/transloco';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
@Component({
selector : 'language',
templateUrl : './language.component.html',
selector : 'languages',
templateUrl : './languages.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'language'
exportAs : 'languages'
})
export class LanguageComponent implements OnInit, OnDestroy
export class LanguagesComponent implements OnInit, OnDestroy
{
availableLangs: AvailableLangs;
activeLang: string;

View File

@@ -2,12 +2,12 @@ import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { LanguageComponent } from 'app/layout/common/language/language.component';
import { LanguagesComponent } from 'app/layout/common/languages/languages.component';
import { SharedModule } from 'app/shared/shared.module';
@NgModule({
declarations: [
LanguageComponent
LanguagesComponent
],
imports : [
MatButtonModule,
@@ -16,9 +16,9 @@ import { SharedModule } from 'app/shared/shared.module';
SharedModule
],
exports : [
LanguageComponent
LanguagesComponent
]
})
export class LanguageModule
export class LanguagesModule
{
}

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { MatButton } from '@angular/material/button';
@@ -14,12 +14,12 @@ import { MessagesService } from 'app/layout/common/messages/messages.service';
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'messages'
})
export class MessagesComponent implements OnInit, OnChanges, OnDestroy
export class MessagesComponent implements OnInit, OnDestroy
{
@Input() messages: Message[];
@ViewChild('messagesOrigin') private _messagesOrigin: MatButton;
@ViewChild('messagesPanel') private _messagesPanel: TemplateRef<any>;
messages: Message[];
unreadCount: number = 0;
private _overlayRef: OverlayRef;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -40,21 +40,6 @@ export class MessagesComponent implements OnInit, OnChanges, OnDestroy
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Messages
if ( 'messages' in changes )
{
// Store the messages on the service
this._messagesService.store(changes.messages.currentValue);
}
}
/**
* On init
*/
@@ -182,7 +167,7 @@ export class MessagesComponent implements OnInit, OnChanges, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._messagesOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { Message } from 'app/layout/common/messages/messages.types';
import { map, switchMap, take } from 'rxjs/operators';
import { map, switchMap, take, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
@@ -35,17 +35,15 @@ export class MessagesService
// -----------------------------------------------------------------------------------------------------
/**
* Store messages on the service
*
* @param messages
* Get all messages
*/
store(messages: Message[]): Observable<Message[]>
getAll(): Observable<Message[]>
{
// Load the messages
this._messages.next(messages);
// Return the messages
return this.messages$;
return this._httpClient.get<Message[]>('api/common/messages').pipe(
tap((messages) => {
this._messages.next(messages);
})
);
}
/**

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { MatButton } from '@angular/material/button';
@@ -14,12 +14,12 @@ import { NotificationsService } from 'app/layout/common/notifications/notificati
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'notifications'
})
export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
export class NotificationsComponent implements OnInit, OnDestroy
{
@Input() notifications: Notification[];
@ViewChild('notificationsOrigin') private _notificationsOrigin: MatButton;
@ViewChild('notificationsPanel') private _notificationsPanel: TemplateRef<any>;
notifications: Notification[];
unreadCount: number = 0;
private _overlayRef: OverlayRef;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -40,21 +40,6 @@ export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Notifications
if ( 'notifications' in changes )
{
// Store the notifications on the service
this._notificationsService.store(changes.notifications.currentValue);
}
}
/**
* On init
*/
@@ -182,7 +167,7 @@ export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._notificationsOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { Notification } from 'app/layout/common/notifications/notifications.types';
import { map, switchMap, take } from 'rxjs/operators';
import { map, switchMap, take, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
@@ -35,17 +35,15 @@ export class NotificationsService
// -----------------------------------------------------------------------------------------------------
/**
* Store notifications on the service
*
* @param notifications
* Get all notifications
*/
store(notifications: Notification[]): Observable<Notification[]>
getAll(): Observable<Notification[]>
{
// Load the notifications
this._notifications.next(notifications);
// Return the notifications
return this.notifications$;
return this._httpClient.get<Notification[]>('api/common/notifications').pipe(
tap((notifications) => {
this._notifications.next(notifications);
})
);
}
/**

View File

@@ -6,7 +6,6 @@
(click)="open()">
<mat-icon [svgIcon]="'heroicons_outline:search'"></mat-icon>
</button>
<div
class="absolute inset-0 flex items-center flex-shrink-0 z-99 bg-card"
*ngIf="opened"
@@ -23,22 +22,36 @@
(keydown)="onKeydown($event)"
#barSearchInput>
<mat-autocomplete
class="max-h-128 border-t rounded-b shadow-md"
class="max-h-128 sm:px-2 border-t rounded-b shadow-md"
[disableRipple]="true"
#matAutocomplete="matAutocomplete">
<mat-option
class="h-14 px-6 py-0 sm:px-8 text-md pointer-events-none text-secondary bg-transparent"
*ngIf="results && !results.length">
class="py-0 px-6 text-md pointer-events-none text-secondary bg-transparent"
*ngIf="resultSets && !resultSets.length">
No results found!
</mat-option>
<ng-container *ngFor="let result of results; trackBy: trackByFn">
<mat-option
class="group relative h-14 px-6 py-0 sm:px-8 text-md"
[routerLink]="result.link">
<ng-container
[ngTemplateOutlet]="searchResult"
[ngTemplateOutletContext]="{$implicit: result}"></ng-container>
</mat-option>
<ng-container *ngFor="let resultSet of resultSets; trackBy: trackByFn">
<mat-optgroup class="flex items-center mt-2 px-2">
<span class="text-sm font-semibold tracking-wider text-secondary">{{resultSet.label.toUpperCase()}}</span>
</mat-optgroup>
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
<mat-option
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
[routerLink]="result.link">
<!-- Contacts -->
<ng-container *ngIf="resultSet.id === 'contacts'">
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>
</ng-container>
<!-- Pages -->
<ng-container *ngIf="resultSet.id === 'pages'">
<ng-container *ngTemplateOutlet="pageResult; context: {$implicit: result}"></ng-container>
</ng-container>
<!-- Tasks -->
<ng-container *ngIf="resultSet.id === 'tasks'">
<ng-container *ngTemplateOutlet="taskResult; context: {$implicit: result}"></ng-container>
</ng-container>
</mat-option>
</ng-container>
</ng-container>
</mat-autocomplete>
<button
@@ -69,62 +82,89 @@
[disableRipple]="true"
#matAutocomplete="matAutocomplete">
<mat-option
class="h-14 px-5 py-0 text-md pointer-events-none text-secondary bg-transparent"
*ngIf="results && !results.length">
class="py-0 px-6 text-md pointer-events-none text-secondary bg-transparent"
*ngIf="resultSets && !resultSets.length">
No results found!
</mat-option>
<ng-container *ngFor="let result of results; trackBy: trackByFn">
<mat-option
class="group relative h-14 px-5 py-0 text-md"
[routerLink]="result.link">
<ng-container
[ngTemplateOutlet]="searchResult"
[ngTemplateOutletContext]="{$implicit: result}"></ng-container>
</mat-option>
<ng-container *ngFor="let resultSet of resultSets; trackBy: trackByFn">
<mat-optgroup class="flex items-center mt-2 px-2">
<span class="text-sm font-semibold tracking-wider text-secondary">{{resultSet.label.toUpperCase()}}</span>
</mat-optgroup>
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
<mat-option
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
[routerLink]="result.link">
<!-- Contacts -->
<ng-container *ngIf="resultSet.id === 'contacts'">
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>
</ng-container>
<!-- Pages -->
<ng-container *ngIf="resultSet.id === 'pages'">
<ng-container *ngTemplateOutlet="pageResult; context: {$implicit: result}"></ng-container>
</ng-container>
<!-- Tasks -->
<ng-container *ngIf="resultSet.id === 'tasks'">
<ng-container *ngTemplateOutlet="taskResult; context: {$implicit: result}"></ng-container>
</ng-container>
</mat-option>
</ng-container>
</ng-container>
</mat-autocomplete>
</div>
</ng-container>
<!-- Contact result template -->
<ng-template
#searchResult
#contactResult
let-result>
<!-- Hover indicator -->
<div class="absolute inset-y-0 left-0 hidden w-1 bg-primary group-hover:flex"></div>
<!-- Contact result -->
<ng-container *ngIf="result.resultType === 'contact'">
<div class="flex items-center">
<div class="px-1.5 py-1 mr-4 text-xs font-semibold leading-normal rounded text-indigo-50 bg-indigo-600">Contact</div>
<div class="overflow-hidden overflow-ellipsis">
<span [innerHTML]="result.title"></span>
</div>
<div class="flex flex-shrink-0 items-center justify-center w-8 h-8 ml-auto rounded-full overflow-hidden bg-primary-100 dark:bg-black dark:bg-opacity-5">
<img
*ngIf="result.avatar"
[src]="result.avatar">
<mat-icon
class="m-0 icon-size-5 text-primary"
*ngIf="!result.avatar"
[svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
</div>
<div class="flex items-center">
<div class="flex flex-shrink-0 items-center justify-center w-8 h-8 rounded-full overflow-hidden bg-primary-100 dark:bg-primary-800">
<img
*ngIf="result.avatar"
[src]="result.avatar">
<mat-icon
class="m-0 icon-size-5 text-primary dark:text-primary-400"
*ngIf="!result.avatar"
[svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
</div>
</ng-container>
<!-- Page result -->
<ng-container *ngIf="result.resultType === 'page'">
<div class="flex items-center">
<div class="px-1.5 py-1 mr-4 text-xs font-semibold leading-normal rounded text-teal-50 bg-teal-600">Page</div>
<div class="flex flex-col overflow-hidden overflow-ellipsis">
<span
class="overflow-hidden overflow-ellipsis whitespace-nowrap leading-normal"
[innerHTML]="result.title"></span>
<span
class="mt-1 text-secondary overflow-hidden overflow-ellipsis whitespace-nowrap leading-normal text-sm no-underline"
[routerLink]="result.link">{{result.link}}</span>
</div>
<div class="ml-3 truncate">
<span [innerHTML]="result.name"></span>
</div>
</ng-container>
</div>
</ng-template>
<!-- Page result template -->
<ng-template
#pageResult
let-result>
<div class="flex flex-col">
<div
class="truncate leading-normal"
[innerHTML]="result.title"></div>
<div class="truncate leading-normal text-sm text-secondary">
{{result.link}}
</div>
</div>
</ng-template>
<!-- Task result template -->
<ng-template
#taskResult
let-result>
<div class="flex items-center">
<ng-container *ngIf="result.completed">
<mat-icon
class="mr-0 text-primary dark:text-primary-400"
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
</ng-container>
<ng-container *ngIf="!result.completed">
<mat-icon
class="mr-0 text-hint"
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
</ng-container>
<div
class="ml-3 truncate leading-normal"
[ngClass]="{'line-through text-hint': result.completed}"
[innerHTML]="result.title"></div>
</div>
</ng-template>

View File

@@ -20,7 +20,7 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
@Output() search: EventEmitter<any> = new EventEmitter<any>();
opened: boolean = false;
results: any[];
resultSets: any[];
searchControl: FormControl = new FormControl();
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -104,12 +104,12 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
takeUntil(this._unsubscribeAll),
map((value) => {
// Set the search results to null if there is no value or
// Set the resultSets to null if there is no value or
// the length of the value is smaller than the minLength
// so the autocomplete panel can be closed
if ( !value || value.length < this.minLength )
{
this.results = null;
this.resultSets = null;
}
// Continue
@@ -121,13 +121,13 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
)
.subscribe((value) => {
this._httpClient.post('api/common/search', {query: value})
.subscribe((response: any) => {
.subscribe((resultSets: any) => {
// Store the results
this.results = response.results;
// Store the result sets
this.resultSets = resultSets;
// Execute the event
this.search.next(this.results);
this.search.next(resultSets);
});
});
}

View File

@@ -21,7 +21,15 @@
[svgIcon]="'heroicons_solid:x'"></mat-icon>
</button>
</div>
<div class="text-lg font-medium leading-10">Shortcuts</div>
<div class="flex items-center text-lg font-medium leading-10">
<span class="">Shortcuts</span>
<ng-container *ngIf="mode !== 'view'">
<span class="ml-1">
<ng-container *ngIf="mode === 'add'">- Add new</ng-container>
<ng-container *ngIf="mode === 'modify' || mode === 'edit'">- Editing</ng-container>
</span>
</ng-container>
</div>
<div class="ml-auto">
<!-- View mode -->

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
@@ -15,14 +15,14 @@ import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service'
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'shortcuts'
})
export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
export class ShortcutsComponent implements OnInit, OnDestroy
{
@Input() shortcuts: Shortcut[];
@ViewChild('shortcutsOrigin') private _shortcutsOrigin: MatButton;
@ViewChild('shortcutsPanel') private _shortcutsPanel: TemplateRef<any>;
mode: 'view' | 'modify' | 'add' | 'edit' = 'view';
shortcutForm: FormGroup;
shortcuts: Shortcut[];
private _overlayRef: OverlayRef;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -43,21 +43,6 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Shortcuts
if ( 'shortcuts' in changes )
{
// Store the shortcuts on the service
this._shortcutsService.store(changes.shortcuts.currentValue);
}
}
/**
* On init
*/
@@ -236,7 +221,7 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._shortcutsOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, ReplaySubject } from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';
import { map, switchMap, take, tap } from 'rxjs/operators';
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
@Injectable({
@@ -35,17 +35,15 @@ export class ShortcutsService
// -----------------------------------------------------------------------------------------------------
/**
* Store shortcuts on the service
*
* @param shortcuts
* Get all messages
*/
store(shortcuts: Shortcut[]): Observable<Shortcut[]>
getAll(): Observable<Shortcut[]>
{
// Load the shortcuts
this._shortcuts.next(shortcuts);
// Return the shortcuts
return this.shortcuts$;
return this._httpClient.get<Shortcut[]>('api/common/shortcuts').pipe(
tap((shortcuts) => {
this._shortcuts.next(shortcuts);
})
);
}
/**

View File

@@ -3,17 +3,17 @@ import { Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { User } from 'app/core/user/user.model';
import { User } from 'app/core/user/user.types';
import { UserService } from 'app/core/user/user.service';
@Component({
selector : 'user-menu',
templateUrl : './user-menu.component.html',
selector : 'user',
templateUrl : './user.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'userMenu'
exportAs : 'user'
})
export class UserMenuComponent implements OnInit, OnDestroy
export class UserComponent implements OnInit, OnDestroy
{
/* eslint-disable @typescript-eslint/naming-convention */
static ngAcceptInputType_showAvatar: BooleanInput;

View File

@@ -3,12 +3,12 @@ import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { UserMenuComponent } from 'app/layout/common/user-menu/user-menu.component';
import { UserComponent } from 'app/layout/common/user/user.component';
import { SharedModule } from 'app/shared/shared.module';
@NgModule({
declarations: [
UserMenuComponent
UserComponent
],
imports : [
MatButtonModule,
@@ -18,9 +18,9 @@ import { SharedModule } from 'app/shared/shared.module';
SharedModule
],
exports : [
UserMenuComponent
UserComponent
]
})
export class UserMenuModule
export class UserModule
{
}

View File

@@ -54,7 +54,7 @@
</div>
<fuse-drawer
class="w-100 min-w-100"
class="w-screen min-w-screen sm:w-100 sm:min-w-100"
fixed
transparentOverlay
[mode]="'over'"
@@ -74,17 +74,17 @@
<!-- Theme -->
<div class="text-md font-semibold text-secondary">THEME</div>
<div class="grid grid-cols-3 gap-3 mt-6">
<div class="grid grid-cols-2 sm:grid-cols-3 gap-3 mt-6">
<ng-container *ngFor="let theme of themes">
<div
class="flex items-center px-4 py-3 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
class="flex items-center justify-center px-4 py-3 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
[class.ring-2]="config.theme === theme[0]"
(click)="setTheme(theme[0])">
<div
class="w-4 h-4 rounded-full"
class="flex-0 w-3 h-3 rounded-full"
[style.background-color]="theme[1].primary"></div>
<div
class="ml-2.5 font-medium leading-5"
class="ml-2.5 font-medium leading-5 truncate"
[class.text-secondary]="config.theme !== theme[0]">
{{theme[0] | titlecase}}
</div>

View File

@@ -6,7 +6,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="'over'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="false">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -50,7 +50,7 @@
<fuse-horizontal-navigation
class="mr-2"
[name]="'mainNavigation'"
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
</ng-container>
<!-- Navigation toggle button -->
<ng-container *ngIf="isScreenSmall">
@@ -62,14 +62,14 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -4,7 +4,8 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'centered-layout',
@@ -13,7 +14,7 @@ import { InitialData } from 'app/app.types';
})
export class CenteredLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
navigation: Navigation;
isScreenSmall: boolean;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -23,6 +24,7 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/centered.component';
@@ -29,12 +29,12 @@ import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="'over'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="false">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -45,14 +45,14 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>
</div>
@@ -63,7 +63,7 @@
<fuse-horizontal-navigation
class="-mx-4"
[name]="'mainNavigation'"
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
</div>
</div>
</ng-container>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'enterprise-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class EnterpriseLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterprise/enterprise.component';
@@ -29,12 +29,12 @@ import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterpr
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="'over'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="false">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -51,14 +51,14 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>
<!-- Bottom bar -->
@@ -66,7 +66,7 @@
<div class="relative flex flex-auto flex-0 items-center h-16 px-4">
<fuse-horizontal-navigation
[name]="'mainNavigation'"
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
</div>
</ng-container>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'material-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class MaterialLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { MaterialLayoutComponent } from 'app/layout/layouts/horizontal/material/material.component';
@@ -29,12 +29,12 @@ import { MaterialLayoutComponent } from 'app/layout/layouts/horizontal/material/
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="'over'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="false">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -43,7 +43,7 @@
<fuse-horizontal-navigation
class="mr-2"
[name]="'mainNavigation'"
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
</ng-container>
<!-- Navigation toggle button -->
<ng-container *ngIf="isScreenSmall">
@@ -54,14 +54,14 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'modern-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class ModernLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/modern.component';
@@ -29,12 +29,12 @@ import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/mode
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -3,7 +3,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -35,14 +35,14 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'classic-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class ClassicLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/classic.component';
@@ -29,12 +29,12 @@ import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/clas
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -3,7 +3,7 @@
class="dark bg-gray-900 print:hidden"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -16,8 +16,8 @@
</div>
<!-- Components -->
<div class="flex items-center ml-auto">
<notifications [notifications]="data.notifications"></notifications>
<user-menu [showAvatar]="false"></user-menu>
<notifications></notifications>
<user [showAvatar]="false"></user>
</div>
</div>
<!-- User -->
@@ -25,20 +25,20 @@
<div class="relative w-24 h-24">
<img
class="w-full h-full rounded-full"
*ngIf="data.user.avatar"
[src]="data.user.avatar"
*ngIf="user.avatar"
[src]="user.avatar"
alt="User avatar">
<mat-icon
class="icon-size-24"
*ngIf="!data.user.avatar"
*ngIf="!user.avatar"
[svgIcon]="'heroicons_solid:user-circle'"></mat-icon>
</div>
<div class="flex flex-col items-center justify-center w-full mt-6">
<div class="w-full whitespace-nowrap overflow-ellipsis overflow-hidden text-center leading-normal font-medium">
{{data.user.name}}
{{user.name}}
</div>
<div class="w-full mt-0.5 whitespace-nowrap overflow-ellipsis overflow-hidden text-center text-md leading-normal font-medium text-secondary">
{{data.user.email}}
{{user.email}}
</div>
</div>
</div>
@@ -65,12 +65,12 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<shortcuts></shortcuts>
<messages></messages>
</div>
</div>

View File

@@ -1,10 +1,13 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
import { User } from 'app/core/user/user.types';
import { UserService } from 'app/core/user/user.service';
@Component({
selector : 'classy-layout',
@@ -13,8 +16,9 @@ import { InitialData } from 'app/app.types';
})
export class ClassyLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
user: User;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +27,8 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _userService: UserService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +56,19 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to the user service
this._userService.user$
.pipe((takeUntil(this._unsubscribeAll)))
.subscribe((user: User) => {
this.user = user;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { FuseFullscreenModule } from '@fuse/components/fullscreen/fullscreen.module';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy.component';
@@ -29,12 +29,12 @@ import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
[appearance]="'compact'"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.compact"
[navigation]="navigation.compact"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -30,14 +30,14 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'compact-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class CompactLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/compact.component';
@@ -29,12 +29,12 @@ import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/comp
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
[appearance]="navigationAppearance"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.default"
[navigation]="navigation.default"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -39,14 +39,14 @@
</button>
</div>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'dense-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class DenseLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
navigationAppearance: 'default' | 'dense' = 'dense';
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -24,6 +25,7 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -51,10 +53,12 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.component';
@@ -29,12 +29,12 @@ import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.co
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -3,7 +3,7 @@
class="dark bg-indigo-800 text-white print:hidden"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.futuristic"
[navigation]="navigation.futuristic"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationHeader>
@@ -18,10 +18,10 @@
<ng-container fuseVerticalNavigationFooter>
<!-- User -->
<div class="flex items-center w-full px-6 py-8 border-t">
<user-menu></user-menu>
<user></user>
<div class="flex flex-col w-full ml-4 overflow-hidden">
<div class="w-full whitespace-nowrap overflow-ellipsis overflow-hidden leading-normal text-current opacity-80">
{{data.user.name}}
{{user.name}}
</div>
<div class="w-full mt-0.5 whitespace-nowrap text-sm overflow-ellipsis overflow-hidden leading-normal text-current opacity-50">
brian.hughes@company.com
@@ -44,13 +44,13 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
</div>
</div>

View File

@@ -1,10 +1,13 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
import { User } from 'app/core/user/user.types';
import { UserService } from 'app/core/user/user.service';
@Component({
selector : 'futuristic-layout',
@@ -13,8 +16,9 @@ import { InitialData } from 'app/app.types';
})
export class FuturisticLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
user: User;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +27,8 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _userService: UserService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +56,19 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to the user service
this._userService.user$
.pipe((takeUntil(this._unsubscribeAll)))
.subscribe((user: User) => {
this.user = user;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristic/futuristic.component';
@@ -29,12 +29,12 @@ import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristi
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -4,7 +4,7 @@
[appearance]="'thin'"
[mode]="isScreenSmall ? 'over' : 'side'"
[name]="'mainNavigation'"
[navigation]="data.navigation.compact"
[navigation]="navigation.compact"
[opened]="!isScreenSmall">
<!-- Navigation header hook -->
<ng-container fuseVerticalNavigationContentHeader>
@@ -31,14 +31,14 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
<messages [messages]="data.messages"></messages>
<notifications [notifications]="data.notifications"></notifications>
<user-menu></user-menu>
<shortcuts></shortcuts>
<messages></messages>
<notifications></notifications>
<user></user>
</div>
</div>

View File

@@ -1,10 +1,11 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Data, Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
import { Navigation } from 'app/core/navigation/navigation.types';
import { NavigationService } from 'app/core/navigation/navigation.service';
@Component({
selector : 'thin-layout',
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
})
export class ThinLayoutComponent implements OnInit, OnDestroy
{
data: InitialData;
isScreenSmall: boolean;
navigation: Navigation;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
@@ -23,6 +24,7 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _navigationService: NavigationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _fuseNavigationService: FuseNavigationService
)
@@ -50,10 +52,12 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
// Subscribe to navigation data
this._navigationService.navigation$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((navigation: Navigation) => {
this.navigation = navigation;
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$

View File

@@ -7,12 +7,12 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
import { UserModule } from 'app/layout/common/user/user.module';
import { SharedModule } from 'app/shared/shared.module';
import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.component';
@@ -29,12 +29,12 @@ import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.compo
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
LanguagesModule,
MessagesModule,
NotificationsModule,
SearchModule,
ShortcutsModule,
UserMenuModule,
UserModule,
SharedModule
],
exports : [

View File

@@ -33,10 +33,18 @@ export class FileManagerMockApi
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/file-manager')
.reply(() => {
.reply(({request}) => {
// Clone the items
const items = cloneDeep(this._items);
let items = cloneDeep(this._items);
// See if a folder id exist
const folderId = request.params.get('folderId') ?? null;
// Filter the items by folder id. If folder id is null,
// that means we want to root items which have folder id
// of null
items = items.filter(item => item.folderId === folderId);
// Separate the items by folders and files
const folders = items.filter(item => item.type === 'folder');
@@ -46,11 +54,38 @@ export class FileManagerMockApi
folders.sort((a, b) => a.name.localeCompare(b.name));
files.sort((a, b) => a.name.localeCompare(b.name));
// Figure out the path and attach it to the response
// Prepare the empty paths array
const pathItems = cloneDeep(this._items);
const path = [];
// Prepare the current folder
let currentFolder = null;
// Get the current folder and add it as the first entry
if ( folderId )
{
currentFolder = pathItems.find(item => item.id === folderId);
path.push(currentFolder);
}
// Start traversing and storing the folders as a path array
// until we hit null on the folder id
while ( currentFolder?.folderId )
{
currentFolder = pathItems.find(item => item.id === currentFolder.folderId);
if ( currentFolder )
{
path.unshift(currentFolder);
}
}
return [
200,
{
folders,
files
files,
path
}
];
});

View File

@@ -2,6 +2,7 @@
export const items = [
{
id : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
folderId : null,
name : 'Personal',
createdBy : 'Brian Hughes',
createdAt : 'April 24, 2018',
@@ -13,6 +14,7 @@ export const items = [
},
{
id : '6da8747f-b474-4c9a-9eba-5ef212285500',
folderId : null,
name : 'Photos',
createdBy : 'Brian Hughes',
createdAt : 'November 01, 2021',
@@ -24,6 +26,7 @@ export const items = [
},
{
id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
folderId : null,
name : 'Work',
createdBy : 'Brian Hughes',
createdAt : 'May 8, 2020',
@@ -35,6 +38,7 @@ export const items = [
},
{
id : '5cb66e32-d1ac-4b9a-8c34-5991ce25add2',
folderId : null,
name : 'Contract #123',
createdBy : 'Brian Hughes',
createdAt : 'January 14, 2021',
@@ -46,6 +50,7 @@ export const items = [
},
{
id : '3ffc3d84-8f2d-4929-903a-ef6fc21657a7',
folderId : null,
name : 'Estimated budget',
createdBy : 'Brian Hughes',
createdAt : 'December 14, 2020',
@@ -57,6 +62,7 @@ export const items = [
},
{
id : '157adb9a-14f8-4559-ac93-8be893c9f80a',
folderId : null,
name : 'DMCA notice #42',
createdBy : 'Brian Hughes',
createdAt : 'May 8, 2021',
@@ -68,6 +74,7 @@ export const items = [
},
{
id : '4f64597a-df7e-461c-ad60-f33e5f7e0747',
folderId : null,
name : 'Invoices',
createdBy : 'Brian Hughes',
createdAt : 'January 12, 2020',
@@ -79,6 +86,7 @@ export const items = [
},
{
id : 'e445c445-57b2-4476-8c62-b068e3774b8e',
folderId : null,
name : 'Crash logs',
createdBy : 'Brian Hughes',
createdAt : 'June 8, 2020',
@@ -90,6 +98,7 @@ export const items = [
},
{
id : 'b482f93e-7847-4614-ad48-b78b78309f81',
folderId : null,
name : 'System logs',
createdBy : 'Brian Hughes',
createdAt : 'June 8, 2020',
@@ -101,6 +110,7 @@ export const items = [
},
{
id : 'ec07a98d-2e5b-422c-a9b2-b5d1c0e263f5',
folderId : null,
name : 'Personal projects',
createdBy : 'Brian Hughes',
createdAt : 'March 18, 2020',
@@ -112,6 +122,7 @@ export const items = [
},
{
id : 'ae908d59-07da-4dd8-aba0-124e50289295',
folderId : null,
name : 'Biometric portrait',
createdBy : 'Brian Hughes',
createdAt : 'August 29, 2020',
@@ -123,6 +134,7 @@ export const items = [
},
{
id : '4038a5b6-5b1a-432d-907c-e037aeb817a8',
folderId : null,
name : 'Scanned image 20201012-1',
createdBy : 'Brian Hughes',
createdAt : 'September 13, 2020',
@@ -134,6 +146,7 @@ export const items = [
},
{
id : '630d2e9a-d110-47a0-ac03-256073a0f56d',
folderId : null,
name : 'Scanned image 20201012-2',
createdBy : 'Brian Hughes',
createdAt : 'September 14, 2020',
@@ -145,6 +158,7 @@ export const items = [
},
{
id : '1417d5ed-b616-4cff-bfab-286677b69d79',
folderId : null,
name : 'Prices',
createdBy : 'Brian Hughes',
createdAt : 'April 07, 2020',
@@ -156,6 +170,7 @@ export const items = [
},
{
id : 'bd2817c7-6751-40dc-b252-b6b5634c0689',
folderId : null,
name : 'Shopping list',
createdBy : 'Brian Hughes',
createdAt : 'March 26, 2021',
@@ -167,6 +182,7 @@ export const items = [
},
{
id : '14fb47c9-6eeb-4070-919c-07c8133285d1',
folderId : null,
name : 'Summer budget',
createdBy : 'Brian Hughes',
createdAt : 'June 02, 2020',
@@ -175,5 +191,67 @@ export const items = [
type : 'XLS',
contents : null,
description: null
},
{
id : '894e8514-03d3-4f5e-bb28-f6c092501fae',
folderId : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
name : 'A personal file',
createdBy : 'Brian Hughes',
createdAt : 'June 02, 2020',
modifiedAt : 'June 02, 2020',
size : '943 KB',
type : 'XLS',
contents : null,
description: null
},
{
id : '74010810-16cf-441d-a1aa-c9fb620fceea',
folderId : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
name : 'A personal folder',
createdBy : 'Brian Hughes',
createdAt : 'November 01, 2021',
modifiedAt : 'November 01, 2021',
size : '3015 MB',
type : 'folder',
contents : '907 files',
description: 'Personal photos; selfies, family, vacation and etc.'
},
{
id : 'a8c73e5a-8114-436d-ab54-d900b50b3762',
folderId : '74010810-16cf-441d-a1aa-c9fb620fceea',
name : 'A personal file within the personal folder',
createdBy : 'Brian Hughes',
createdAt : 'June 02, 2020',
modifiedAt : 'June 02, 2020',
size : '943 KB',
type : 'XLS',
contents : null,
description: null
},
{
id : '12d851a8-4f60-473e-8a59-abe4b422ea99',
folderId : '6da8747f-b474-4c9a-9eba-5ef212285500',
name : 'Photos file',
createdBy : 'Brian Hughes',
createdAt : 'June 02, 2020',
modifiedAt : 'June 02, 2020',
size : '943 KB',
type : 'XLS',
contents : null,
description: null
},
{
id : '2836766d-27e1-4f40-a31a-5a8419105e7e',
folderId : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
name : 'Work file',
createdBy : 'Brian Hughes',
createdAt : 'June 02, 2020',
modifiedAt : 'June 02, 2020',
size : '943 KB',
type : 'XLS',
contents : null,
description: null
}
];

View File

@@ -0,0 +1,454 @@
import { Injectable } from '@angular/core';
import { assign, cloneDeep } from 'lodash-es';
import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api';
import { boards as boardsData, cards as cardsData, labels as labelsData, lists as listsData, members as membersData } from 'app/mock-api/apps/scrumboard/data';
@Injectable({
providedIn: 'root'
})
export class ScrumboardMockApi
{
// Private
private _boards: any[] = boardsData;
private _cards: any[] = cardsData;
private _labels: any[] = labelsData;
private _lists: any[] = listsData;
private _members: any[] = membersData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Boards - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/boards')
.reply(({request}) => {
// Clone the boards
let boards = cloneDeep(this._boards);
// Go through the boards and inject the members
boards = boards.map(board => ({
...board,
members: board.members.map(boardMember => this._members.find(member => boardMember === member.id))
}));
return [
200,
boards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Board - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/board')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the board
const board = this._boards.find(item => item.id === id);
// Attach the board lists
board.lists = this._lists.filter(item => item.boardId === id).sort((a, b) => a.position - b.position);
// Grab all cards that belong to this board and attach labels to them
let cards = this._cards.filter(item => item.boardId === id);
cards = cards.map(card => (
{
...card,
labels: card.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId))
}
));
// Attach the board cards into corresponding lists
board.lists.forEach((list, index, array) => {
array[index].cards = cards.filter(item => item.boardId === id && item.listId === list.id).sort((a, b) => a.position - b.position);
});
// Attach the board labels
board.labels = this._labels.filter(item => item.boardId === id);
return [
200,
cloneDeep(board)
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the list
const newList = cloneDeep(request.body.list);
// Generate a new GUID
newList.id = FuseMockApiUtils.guid();
// Store the new list
this._lists.push(newList);
return [
200,
newList
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the list
const list = cloneDeep(request.body.list);
// Prepare the updated list
let updatedList = null;
// Find the list and update it
this._lists.forEach((item, index, lists) => {
if ( item.id === list.id )
{
// Update the list
lists[index] = assign({}, lists[index], list);
// Store the updated list
updatedList = lists[index];
}
});
return [
200,
updatedList
];
});
// -----------------------------------------------------------------------------------------------------
// @ Lists - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/lists')
.reply(({request}) => {
// Get the lists
const lists = cloneDeep(request.body.lists);
// Prepare the updated lists
const updatedLists = [];
// Go through the lists
lists.forEach((item) => {
// Find the list
const index = this._lists.findIndex(list => item.id === list.id);
// Update the list
this._lists[index] = assign({}, this._lists[index], item);
// Store in the updated lists
updatedLists.push(item);
});
return [
200,
updatedLists
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the list and delete it
const index = this._lists.findIndex(item => item.id === id);
this._lists.splice(index, 1);
// Filter out the cards that belonged to the list to delete them
this._cards = this._cards.filter(card => card.listId !== id);
return [
200,
true
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - PUT
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPut('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the card
const newCard = cloneDeep(request.body.card);
// Generate a new GUID
newCard.id = FuseMockApiUtils.guid();
// Unshift the new card
this._cards.push(newCard);
return [
200,
newCard
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the id and card
const id = request.body.id;
const card = cloneDeep(request.body.card);
// Prepare the updated card
let updatedCard = null;
// Go through the labels and leave only ids of them
card.labels = card.labels.map(itemLabel => itemLabel.id);
// Find the card and update it
this._cards.forEach((item, index, cards) => {
if ( item.id === id )
{
// Update the card
cards[index] = assign({}, cards[index], card);
// Store the updated card
updatedCard = cloneDeep(cards[index]);
}
});
// Attach the labels of the card
updatedCard.labels = updatedCard.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId));
return [
200,
updatedCard
];
});
// -----------------------------------------------------------------------------------------------------
// @ Cards - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/cards')
.reply(({request}) => {
// Get the cards
const cards = cloneDeep(request.body.cards);
// Prepare the updated cards
const updatedCards = [];
// Go through the cards
cards.forEach((item) => {
// Find the card
const index = this._cards.findIndex(card => item.id === card.id);
// Go through the labels and leave only ids of them
item.labels = item.labels.map(itemLabel => itemLabel.id);
// Update the card
this._cards[index] = assign({}, this._cards[index], item);
// Attach the labels of the card
item.labels = item.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId));
// Store in the updated cards
updatedCards.push(item);
});
return [
200,
updatedCards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the card and delete it
const index = this._cards.findIndex(item => item.id === id);
this._cards.splice(index, 1);
return [
200,
true
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card Positions - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/card/positions')
.reply(({request}) => {
// Get the cards
const cards = request.body.cards;
// Go through the cards
this._cards.forEach((card) => {
// Find this card's index within the cards array that comes with the request
// and assign that index as the new position number for the card
card.position = cards.findIndex(item => item.id === card.id && item.listId === card.listId && item.boardId === card.boardId);
});
// Clone the cards
const updatedCards = cloneDeep(this._cards);
return [
200,
updatedCards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Labels - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/board/labels')
.reply(({request}) => {
// Get the board id
const boardId = request.params.get('boardId');
// Filter the labels
const labels = this._labels.filter(item => item.boardId === boardId);
return [
200,
cloneDeep(labels)
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - PUT
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPut('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the label
const newLabel = cloneDeep(request.body.label);
// Generate a new GUID
newLabel.id = FuseMockApiUtils.guid();
// Unshift the new label
this._labels.unshift(newLabel);
return [
200,
newLabel
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the id and label
const id = request.body.id;
const label = cloneDeep(request.body.label);
// Prepare the updated label
let updatedLabel = null;
// Find the label and update it
this._labels.forEach((item, index, labels) => {
if ( item.id === id )
{
// Update the label
labels[index] = assign({}, labels[index], label);
// Store the updated label
updatedLabel = labels[index];
}
});
return [
200,
updatedLabel
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the label and delete it
const index = this._labels.findIndex(item => item.id === id);
this._labels.splice(index, 1);
// Get the cards that have the label
const cardsWithLabel = this._cards.filter(card => card.labels.indexOf(id) > -1);
// Iterate through them and remove the label
cardsWithLabel.forEach((card) => {
card.tags.splice(card.tags.indexOf(id), 1);
});
return [
200,
true
];
});
}
}

View File

@@ -0,0 +1,334 @@
/* eslint-disable */
import * as moment from 'moment';
export const boards = [
{
id : '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Admin Dashboard',
description : 'Roadmap for the new project',
icon : 'heroicons_outline:template',
lastActivity: moment().startOf('day').subtract(1, 'day').toISOString(),
members : [
'9c510cf3-460d-4a8c-b3be-bcc3db578c08',
'baa88231-0ee6-4028-96d5-7f187e0f4cd5',
'18bb18f3-ea7d-4465-8913-e8c9adf6f568'
]
},
{
id : '0168b519-3dab-4b46-b2ea-0e678e38a583',
title : 'Weekly Planning',
description : 'Job related tasks for the week',
icon : 'heroicons_outline:calendar',
lastActivity: moment().startOf('day').subtract(2, 'days').toISOString(),
members : [
'79ebb9ee-1e57-4706-810c-03edaec8f56d',
'319ecb5b-f99c-4ee4-81b2-3aeffd1d4735',
'5bf7ed5b-8b04-46b7-b364-005958b7d82e',
'd1f612e6-3e3b-481f-a8a9-f917e243b06e',
'fe0fec0d-002b-406f-87ab-47eb87ba577c',
'23a47d2c-c6cb-40cc-af87-e946a9df5028',
'6726643d-e8dc-42fa-83a6-b4ec06921a6b',
'0d1eb062-13d5-4286-b8d4-e0bea15f3d56'
]
},
{
id : 'bc7db965-3c4f-4233-abf5-69bd70c3c175',
title : 'Personal Tasks',
description : 'Personal tasks around the house',
icon : 'heroicons_outline:home',
lastActivity: moment().startOf('day').subtract(1, 'week').toISOString(),
members : [
'6f6a1c34-390b-4b2e-97c8-ff0e0d787839'
]
}
];
export const lists = [
{
id : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 65536,
title : 'To do'
},
{
id : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 131072,
title : 'In progress'
},
{
id : 'a85ea483-f8f7-42d9-a314-3fed6aac22ab',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 196608,
title : 'In review'
},
{
id : '34cbef38-5687-4813-bd66-141a6df6d832',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 262144,
title : 'Completed'
}
];
export const cards = [
{
id : 'e74e66e9-fe0f-441e-a8ce-28ed6eccc48d',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position : 65536,
title : 'Example that showcase all of the available bits on the card with a fairly long title compared to other cards',
description: 'Example that showcase all of the available bits on the card with a fairly long title compared to other cards. Example that showcase all of the available bits on the card with a fairly long title compared to other cards.',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3',
'51779701-818a-4a53-bc16-137c3bd7a564',
'e8364d69-9595-46ce-a0f9-ce428632a0ac',
'caff9c9b-a198-4564-b1f4-8b3df1d345bb',
'f9eeb436-13a3-4208-a239-0d555960a567'
],
dueDate : moment().subtract(10, 'days').startOf('day').toISOString()
},
{
id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 131072,
title : 'Do a research about most needed admin applications',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 196608,
title : 'Implement the Project dashboard',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : moment().startOf('day').toISOString()
},
{
id : '6da8747f-b474-4c9a-9eba-5ef212285500',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 262144,
title : 'Implement the Analytics dashboard',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : moment().subtract(1, 'day').startOf('day').toISOString()
},
{
id : '94fb1dee-dd83-4cca-acdd-02e96d3cc4f1',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
position: 65536,
title : 'Analytics dashboard design',
labels : [
'e8364d69-9595-46ce-a0f9-ce428632a0ac'
],
dueDate : null
},
{
id : 'fc16f7d8-957d-43ed-ba85-20f99b5ce011',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
position: 131072,
title : 'Project dashboard design',
labels : [
'e8364d69-9595-46ce-a0f9-ce428632a0ac'
],
dueDate : null
},
{
id : 'c0b32f1f-64ec-4f8d-8b11-a8dc809df331',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a85ea483-f8f7-42d9-a314-3fed6aac22ab',
position: 65536,
title : 'JWT Auth implementation',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : null
},
{
id : '532c2747-be79-464a-9897-6a682bf22b64',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 65536,
title : 'Create low fidelity wireframes',
labels : [],
dueDate : null
},
{
id : '1d908efe-c830-476e-9e87-d06e30d89bc2',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 131072,
title : 'Create high fidelity wireframes',
labels : [],
dueDate : moment().subtract(10, 'day').startOf('day').toISOString()
},
{
id : 'b1da11ed-7896-4826-962d-4b7b718896d4',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 196608,
title : 'Collect information about most used admin layouts',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : '3b7f3ceb-107f-42bc-a204-c268c9a56cb4',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 262144,
title : 'Do a research about latest UI trends',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : 'cd7f01c5-a941-4076-8cef-37da0354e643',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 327680,
title : 'Learn more about UX',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
}
];
export const labels = [
{
id : 'e0175175-2784-48f1-a519-a1d2e397c9b3',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Research'
},
{
id : '51779701-818a-4a53-bc16-137c3bd7a564',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Wireframing'
},
{
id : 'e8364d69-9595-46ce-a0f9-ce428632a0ac',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Design'
},
{
id : 'caff9c9b-a198-4564-b1f4-8b3df1d345bb',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Development'
},
{
id : 'f9eeb436-13a3-4208-a239-0d555960a567',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Bug'
}
];
export const members = [
{
id : '6f6a1c34-390b-4b2e-97c8-ff0e0d787839',
name : 'Angeline Vinson',
avatar: 'assets/images/avatars/female-01.jpg'
},
{
id : '4ce4be48-c8c0-468d-9df8-ddfda14cdb37',
name : 'Roseann Greer',
avatar: 'assets/images/avatars/female-02.jpg'
},
{
id : '9c510cf3-460d-4a8c-b3be-bcc3db578c08',
name : 'Lorraine Barnett',
avatar: 'assets/images/avatars/female-03.jpg'
},
{
id : '7ec887d9-b01a-4057-b5dc-aaed18637cc1',
name : 'Middleton Bradford',
avatar: 'assets/images/avatars/male-01.jpg'
},
{
id : '74975a82-addb-427b-9b43-4d2e03331b68',
name : 'Sue Hays',
avatar: 'assets/images/avatars/female-04.jpg'
},
{
id : '18bb18f3-ea7d-4465-8913-e8c9adf6f568',
name : 'Keith Neal',
avatar: 'assets/images/avatars/male-02.jpg'
},
{
id : 'baa88231-0ee6-4028-96d5-7f187e0f4cd5',
name : 'Wilkins Gilmore',
avatar: 'assets/images/avatars/male-03.jpg'
},
{
id : '0d1eb062-13d5-4286-b8d4-e0bea15f3d56',
name : 'Baldwin Stein',
avatar: 'assets/images/avatars/male-04.jpg'
},
{
id : '5bf7ed5b-8b04-46b7-b364-005958b7d82e',
name : 'Bobbie Cohen',
avatar: 'assets/images/avatars/female-05.jpg'
},
{
id : '93b1a72b-e2db-4f77-82d6-272047433508',
name : 'Melody Peters',
avatar: 'assets/images/avatars/female-06.jpg'
},
{
id : 'd1f612e6-3e3b-481f-a8a9-f917e243b06e',
name : 'Marquez Ryan',
avatar: 'assets/images/avatars/male-05.jpg'
},
{
id : '79ebb9ee-1e57-4706-810c-03edaec8f56d',
name : 'Roberta Briggs',
avatar: 'assets/images/avatars/female-07.jpg'
},
{
id : '6726643d-e8dc-42fa-83a6-b4ec06921a6b',
name : 'Robbie Buckley',
avatar: 'assets/images/avatars/female-08.jpg'
},
{
id : '8af617d7-898e-4992-beda-d5ac1d7ceda4',
name : 'Garcia Whitney',
avatar: 'assets/images/avatars/male-06.jpg'
},
{
id : 'bcff44c4-9943-4adc-9049-08b1d922a658',
name : 'Spencer Pate',
avatar: 'assets/images/avatars/male-07.jpg'
},
{
id : '54160ca2-29c9-4475-88a1-31a9307ad913',
name : 'Monica Mcdaniel',
avatar: 'assets/images/avatars/female-09.jpg'
},
{
id : '51286603-3a43-444e-9242-f51fe57d5363',
name : 'Mcmillan Durham',
avatar: 'assets/images/avatars/male-08.jpg'
},
{
id : '319ecb5b-f99c-4ee4-81b2-3aeffd1d4735',
name : 'Jeoine Hebert',
avatar: 'assets/images/avatars/female-10.jpg'
},
{
id : 'fe0fec0d-002b-406f-87ab-47eb87ba577c',
name : 'Susanna Kline',
avatar: 'assets/images/avatars/female-11.jpg'
},
{
id : '23a47d2c-c6cb-40cc-af87-e946a9df5028',
name : 'Suzette Singleton',
avatar: 'assets/images/avatars/female-12.jpg'
}
];

View File

@@ -4,7 +4,7 @@ import * as moment from 'moment';
export const notifications = [
{
id : '493190c9-5b61-4912-afe5-78c21f1044d7',
icon : 'heroicons_outline:star',
icon : 'heroicons_solid:star',
title : 'Daily challenges',
description: 'Your submission has been accepted',
time : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
@@ -21,7 +21,7 @@ export const notifications = [
},
{
id : 'b91ccb58-b06c-413b-b389-87010e03a120',
icon : 'heroicons_outline:mail',
icon : 'heroicons_solid:mail',
title : 'Mailbox',
description: 'You have 15 unread mails across 3 mailboxes',
time : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
@@ -31,7 +31,7 @@ export const notifications = [
},
{
id : '541416c9-84a7-408a-8d74-27a43c38d797',
icon : 'heroicons_outline:refresh',
icon : 'heroicons_solid:refresh',
title : 'Cron jobs',
description: 'Your <em>Docker container</em> is ready to publish',
time : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
@@ -59,7 +59,7 @@ export const notifications = [
},
{
id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e',
icon : 'heroicons_outline:mail',
icon : 'heroicons_solid:mail',
title : 'Mailbox',
description: 'You have 3 new mails',
time : moment().subtract(1, 'day').toISOString(), // 1 day ago
@@ -69,7 +69,7 @@ export const notifications = [
},
{
id : '8f8e1bf9-4661-4939-9e43-390957b60f42',
icon : 'heroicons_outline:star',
icon : 'heroicons_solid:star',
title : 'Daily challenges',
description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
time : moment().subtract(3, 'days').toISOString(), // 3 days ago
@@ -79,7 +79,7 @@ export const notifications = [
},
{
id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69',
icon : 'heroicons_outline:refresh',
icon : 'heroicons_solid:refresh',
title : 'Cron jobs',
description: 'Your Vagrant container is ready to download',
time : moment().subtract(4, 'day').toISOString(), // 4 days ago

View File

@@ -4,6 +4,7 @@ import { FuseNavigationItem, FuseNavigationService } from '@fuse/components/navi
import { FuseMockApiService } from '@fuse/lib/mock-api';
import { defaultNavigation } from 'app/mock-api/common/navigation/data';
import { contacts } from 'app/mock-api/apps/contacts/data';
import { tasks } from 'app/mock-api/apps/tasks/data';
@Injectable({
providedIn: 'root'
@@ -12,6 +13,7 @@ export class SearchMockApi
{
private readonly _defaultNavigation: FuseNavigationItem[] = defaultNavigation;
private readonly _contacts: any[] = contacts;
private readonly _tasks: any[] = tasks;
/**
* Constructor
@@ -54,58 +56,75 @@ export class SearchMockApi
return [200, {results: []}];
}
// Filter the navigation
const navigationResults = cloneDeep(flatNavigation).filter(item => (item.title?.toLowerCase().includes(query) || (item.subtitle && item.subtitle.includes(query))));
// Filter the contacts
const contactsResults = cloneDeep(this._contacts).filter(user => user.name.toLowerCase().includes(query));
const contactsResults = cloneDeep(this._contacts)
.filter(contact => contact.name.toLowerCase().includes(query));
// Create the results array
// Filter the navigation
const pagesResults = cloneDeep(flatNavigation)
.filter(page => (page.title?.toLowerCase().includes(query) || (page.subtitle && page.subtitle.includes(query))));
// Filter the tasks
const tasksResults = cloneDeep(this._tasks)
.filter(task => task.title.toLowerCase().includes(query));
// Prepare the results array
const results = [];
// If there are navigation results...
if ( navigationResults.length > 0 )
{
// Normalize the results while marking the found chars
navigationResults.forEach((result: any) => {
// Normalize
result['hint'] = result.link;
result['resultType'] = 'page';
// Mark the found chars
const re = new RegExp('(' + query.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + ')', 'ig');
result.title = result.title.replace(re, '<mark>$1</mark>');
});
// Add the results
results.push(...navigationResults);
}
// If there are contacts results...
if ( contactsResults.length > 0 )
{
// Normalize the results while marking the found chars
// Normalize the results
contactsResults.forEach((result) => {
// Normalize
result.title = result.name;
result.resultType = 'contact';
// Make the found chars bold
const re = new RegExp('(' + query.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + ')', 'ig');
result.title = result.title.replace(re, '<mark>$1</mark>');
// Add a link
result.link = '/apps/contacts/' + result.id;
});
// Add the results to the results object
results.push(...contactsResults);
// Add to the results
results.push({
id : 'contacts',
label : 'Contacts',
results: contactsResults
});
}
// If there are page results...
if ( pagesResults.length > 0 )
{
// Normalize the results
pagesResults.forEach((result: any) => {
});
// Add to the results
results.push({
id : 'pages',
label : 'Pages',
results: pagesResults
});
}
// If there are tasks results...
if ( tasksResults.length > 0 )
{
// Normalize the results
tasksResults.forEach((result) => {
// Add a link
result.link = '/apps/tasks/' + result.id;
});
// Add to the results
results.push({
id : 'tasks',
label : 'Tasks',
results: tasksResults
});
}
// Return the response
return [200, {results}];
return [200, results];
});
}
}

View File

@@ -3,9 +3,9 @@ export const shortcuts = [
{
id : 'a1ae91d3-e2cb-459b-9be9-a184694f548b',
label : 'Changelog',
description: 'Latest version: v1.2',
description: 'List of changes',
icon : 'heroicons_outline:clipboard-list',
link : '/dashboards/project',
link : '/docs/changelog',
useRouter : true
},
{
@@ -13,7 +13,7 @@ export const shortcuts = [
label : 'Documentation',
description: 'Getting started',
icon : 'heroicons_outline:book-open',
link : '/dashboards/project',
link : '/docs/guides/getting-started/introduction',
useRouter : true
},
{
@@ -21,7 +21,7 @@ export const shortcuts = [
label : 'Help center',
description: 'FAQs and guides',
icon : 'heroicons_outline:support',
link : '/pages/help-center',
link : '/apps/help-center',
useRouter : true
},
{
@@ -29,7 +29,7 @@ export const shortcuts = [
label : 'Dashboard',
description: 'User analytics',
icon : 'heroicons_outline:chart-pie',
link : '/dashboards/project',
link : '/dashboards/analytics',
useRouter : true
},
{
@@ -67,7 +67,7 @@ export const shortcuts = [
{
id : '0a240ab8-e19d-4503-bf68-20013030d526',
label : 'Reload',
description: 'Restart the app',
description: 'Reload the app',
icon : 'heroicons_outline:refresh',
link : '/dashboards/project',
useRouter : false

View File

@@ -16,6 +16,7 @@ import { NotesMockApi } from 'app/mock-api/apps/notes/api';
import { NotificationsMockApi } from 'app/mock-api/common/notifications/api';
import { ProjectMockApi } from 'app/mock-api/dashboards/project/api';
import { SearchMockApi } from 'app/mock-api/common/search/api';
import { ScrumboardMockApi } from 'app/mock-api/apps/scrumboard/api';
import { ShortcutsMockApi } from 'app/mock-api/common/shortcuts/api';
import { TasksMockApi } from 'app/mock-api/apps/tasks/api';
import { UserMockApi } from 'app/mock-api/common/user/api';
@@ -39,6 +40,7 @@ export const mockApiServices = [
NotificationsMockApi,
ProjectMockApi,
SearchMockApi,
ScrumboardMockApi,
ShortcutsMockApi,
TasksMockApi,
UserMockApi

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

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