Compare commits

...

62 Commits

Author SHA1 Message Date
sercan
67d25012ec Increased the version number & updated the changelog 2021-08-12 17:04:57 +03:00
sercan
6de6a07778 Decreased budget sizes since new Fuse is a lot smaller compared to the one with the old design 2021-08-12 13:57:29 +03:00
sercan
e7ab0ea13f (apps/mailbox) Fixed: Compose dialog doesn't work correctly on small height resolutions
(apps/mailbox) Style improvements
2021-08-12 13:45:34 +03:00
sercan
4b686d86cc (@fuse/overrides) Fixed: Quill editor is not styled correctly by default 2021-08-12 13:42:59 +03:00
sercan
190395f14b (@fuse/theming) Better structuring on the themes.scss file
(@fuse) Disabled Angular Material 'theme' sanity check since we use 'all-component-themes' without a color map
2021-08-12 13:17:53 +03:00
sercan
4a9b8ee91e (dependencies) Updated Angular, Angular Material and various other dependencies 2021-08-12 11:32:04 +03:00
sercan
488fe8a1eb (ui/page-layouts) Fixed: Demo layout navigation appearance is not correct 2021-08-11 22:25:49 +03:00
sercan
db9a2a2433 (dependencies) Updated Angular, Angular Material and various other dependencies 2021-08-11 22:25:15 +03:00
sercan
3dda8479cf (tailwindcss) Removed old jsdoc from the config file 2021-08-08 22:27:24 +03:00
sercan
7c402670a1 (docs/confirmation) Updated the docs of the confirmation dialog 2021-08-04 10:10:07 +03:00
sercan
f6bf0fb5d3 (fuse/confirmation) Fixed: Dialog size cannot be updated using dialogRef's "updateSize" method 2021-08-04 09:54:35 +03:00
sercan
d44c004d01 Removed empty "styles" from component decorators 2021-08-04 09:46:36 +03:00
sercan
4ec40271c5 Updated the package.json version number 2021-07-29 10:39:16 +03:00
sercan
b21cdf1655 Updated the changelog and increased the version number 2021-07-29 10:19:28 +03:00
sercan
6fff259fe3 (dependencies) Updated Angular, Angular Material and various other dependencies 2021-07-29 10:15:13 +03:00
sercan
8fcb0aea03 (docs) Updated the multi language guide 2021-07-29 10:14:52 +03:00
sercan
2c90770d9b (index) Updated the title, description and keywords 2021-07-23 22:29:45 +03:00
sercan
1581ea74cc (dashboards/finance) Added finance dashboard
(dashboards/crypto) Added crypto dashboard
2021-07-23 22:23:42 +03:00
sercan
569809aabb (dashboards/project) Small tweaks 2021-07-23 22:23:02 +03:00
sercan
dde9333120 (dashboards/project) Small tweaks on the header 2021-07-23 21:30:51 +03:00
sercan
10ec1790ca (dashboards/project) Module import order 2021-07-21 12:22:23 +03:00
sercan
a2ff55d4c1 (dashboards/project) Light header on light themes, small adjustments in the project selector 2021-07-21 12:22:02 +03:00
sercan
966e2db743 (apps/contacts) Small adjustments for better consistency
(apps/ecommerce/inventory) Small adjustments for better consistency
2021-07-21 11:36:43 +03:00
sercan
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
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
ca8e422b21 (app.module) Alphabetical order on Router's extra options 2021-07-02 23:10:41 +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
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
189 changed files with 7839 additions and 2834 deletions

View File

@@ -12,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
## Running unit tests
@@ -20,7 +20,7 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice.
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
## Further help

View File

@@ -60,13 +60,13 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumError": "8mb"
"maximumWarning": "3mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "100kb",
"maximumError": "150kb"
"maximumWarning": "75kb",
"maximumError": "90kb"
}
],
"fileReplacements": [

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'},

3187
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,30 @@
{
"name": "@fuse/demo",
"version": "13.1.0",
"version": "13.5.0",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard",
"private": true,
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"lint": "ng lint"
},
"dependencies": {
"@angular/animations": "12.0.4",
"@angular/cdk": "12.0.4",
"@angular/common": "12.0.4",
"@angular/compiler": "12.0.4",
"@angular/core": "12.0.4",
"@angular/forms": "12.0.4",
"@angular/material": "12.0.4",
"@angular/material-moment-adapter": "12.0.4",
"@angular/platform-browser": "12.0.4",
"@angular/platform-browser-dynamic": "12.0.4",
"@angular/router": "12.0.4",
"@angular/animations": "12.2.1",
"@angular/cdk": "12.2.1",
"@angular/common": "12.2.1",
"@angular/compiler": "12.2.1",
"@angular/core": "12.2.1",
"@angular/forms": "12.2.1",
"@angular/material": "12.2.1",
"@angular/material-moment-adapter": "12.2.1",
"@angular/platform-browser": "12.2.1",
"@angular/platform-browser-dynamic": "12.2.1",
"@angular/router": "12.2.1",
"@fullcalendar/angular": "4.4.5-beta",
"@fullcalendar/core": "4.4.2",
"@fullcalendar/daygrid": "4.4.2",
@@ -31,60 +33,59 @@
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"@ngneat/transloco": "2.21.0",
"apexcharts": "3.27.1",
"@ngneat/transloco": "2.22.0",
"apexcharts": "3.27.3",
"crypto-js": "3.3.0",
"highlight.js": "11.0.1",
"highlight.js": "11.2.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"ng-apexcharts": "1.5.12",
"ngx-markdown": "12.0.1",
"ngx-quill": "14.0.0",
"perfect-scrollbar": "1.5.1",
"ngx-quill": "14.2.0",
"perfect-scrollbar": "1.5.2",
"quill": "1.3.7",
"rrule": "2.6.8",
"rxjs": "6.6.7",
"tslib": "2.3.0",
"tslib": "2.3.1",
"web-animations-js": "2.3.2",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "12.0.4",
"@angular-eslint/builder": "12.1.0",
"@angular-eslint/eslint-plugin": "12.1.0",
"@angular-eslint/eslint-plugin-template": "12.1.0",
"@angular-eslint/schematics": "12.1.0",
"@angular-eslint/template-parser": "12.1.0",
"@angular/cli": "12.0.4",
"@angular/compiler-cli": "12.0.4",
"@angular/language-service": "12.0.4",
"@angular-devkit/build-angular": "12.2.1",
"@angular-eslint/builder": "12.3.1",
"@angular-eslint/eslint-plugin": "12.3.1",
"@angular-eslint/eslint-plugin-template": "12.3.1",
"@angular-eslint/schematics": "12.3.1",
"@angular-eslint/template-parser": "12.3.1",
"@angular/cli": "12.2.1",
"@angular/compiler-cli": "12.2.1",
"@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.170",
"@types/jasmine": "3.8.2",
"@types/lodash": "4.14.172",
"@types/lodash-es": "4.17.4",
"@types/node": "12.20.15",
"@typescript-eslint/eslint-plugin": "4.26.1",
"@typescript-eslint/parser": "4.26.1",
"autoprefixer": "10.2.6",
"@types/node": "12.20.19",
"@typescript-eslint/eslint-plugin": "4.29.1",
"@typescript-eslint/parser": "4.29.1",
"autoprefixer": "10.3.1",
"chroma-js": "2.1.2",
"eslint": "7.28.0",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-jsdoc": "35.2.0",
"eslint": "7.32.0",
"eslint-plugin-import": "2.24.0",
"eslint-plugin-jsdoc": "36.0.7",
"eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.7.1",
"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.3",
"tailwindcss": "2.1.4",
"typescript": "4.2.4"
"postcss": "8.3.6",
"tailwindcss": "2.2.7",
"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

@@ -5,71 +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"
[target]="item.target || '_self'">
<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"
[target]="item.target || '_self'"
(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>
@@ -77,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">
@@ -90,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

@@ -10,7 +10,6 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-horizontal-navigation-basic-item',
templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy

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

@@ -10,7 +10,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-branch-item',
templateUrl : './branch.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
@@ -81,4 +80,15 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-divider-item',
templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy

View File

@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-horizontal-navigation-spacer-item',
templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy

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,6 +15,7 @@ export interface FuseNavigationItem
hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean;
disabled?: boolean;
tooltip?: string;
link?: string;
externalLink?: boolean;
target?:

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

@@ -10,7 +10,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-aside-item',
templateUrl : './aside.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy

View File

@@ -5,70 +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"
[target]="item.target || '_self'">
<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"
[target]="item.target || '_self'"
(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>
@@ -76,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">
@@ -89,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

@@ -10,7 +10,6 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-vertical-navigation-basic-item',
templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy

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

@@ -11,7 +11,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-collapsable-item',
templateUrl : './collapsable.component.html',
styles : [],
animations : fuseAnimations,
changeDetection: ChangeDetectionStrategy.OnPush
})

View File

@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-divider-item',
templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy

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

@@ -9,7 +9,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-group-item',
templateUrl : './group.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy

View File

@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({
selector : 'fuse-vertical-navigation-spacer-item',
templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy

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,5 +1,7 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { MATERIAL_SANITY_CHECKS } from '@angular/material/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseConfirmationModule } from '@fuse/services/confirmation';
import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module';
import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module';
import { FuseTailwindConfigModule } from '@fuse/services/tailwind/tailwind.module';
@@ -7,12 +9,22 @@ import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@NgModule({
imports : [
FuseConfirmationModule,
FuseMediaWatcherModule,
FuseSplashScreenModule,
FuseTailwindConfigModule,
FuseUtilsModule
],
providers: [
{
// Disable 'theme' sanity check
provide : MATERIAL_SANITY_CHECKS,
useValue: {
doctype: true,
theme : false,
version: true
}
},
{
// Use the 'fill' appearance on Angular Material form fields by default
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,

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

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

View File

@@ -0,0 +1,52 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Component({
selector : 'fuse-confirmation-dialog',
templateUrl : './dialog.component.html',
styles : [
/* language=SCSS */
`
.fuse-confirmation-dialog-panel {
@screen md {
@apply w-128;
}
.mat-dialog-container {
padding: 0 !important;
}
}
`
],
encapsulation: ViewEncapsulation.None
})
export class FuseConfirmationDialogComponent implements OnInit
{
/**
* Constructor
*/
constructor(
@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig,
public matDialogRef: MatDialogRef<FuseConfirmationDialogComponent>
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
}

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;
}
}
}
@@ -1329,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

@@ -4,11 +4,12 @@
.ql-toolbar {
border-radius: 6px 6px 0 0;
padding: 0 !important;
@apply bg-gray-100 border-gray-300;
@apply bg-gray-100;
@apply border-gray-300 border-opacity-100 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05);
@apply border-gray-500;
@apply border-gray-500 #{'!important'};
}
.ql-formats {
@@ -81,26 +82,22 @@
.ql-container {
overflow: hidden;
border-radius: 0 0 6px 6px;
@apply border-gray-300 shadow-sm;
@apply border-gray-300 border-opacity-100 shadow-sm #{'!important'};
.dark & {
@apply border-gray-500;
@apply border-gray-500 #{'!important'};
}
.ql-editor {
min-height: 160px;
max-height: 160px;
height: 160px;
@apply bg-gray-50;
@apply bg-card;
.dark & {
background-color: rgba(0, 0, 0, 0.05);
}
&:focus {
@apply bg-card;
}
&.ql-blank::before {
@apply text-hint;
}

View File

@@ -18,81 +18,6 @@
)
));
/* Prepare the Background and Foreground maps */
$background-light: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* blueGray.100 */
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* blueGray.500 */
selected-button: #E2E8F0, /* blueGray.200 */
selected-disabled-button: #E2E8F0, /* blueGray.200 */
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
unselected-chip: #E2E8F0, /* blueGray.200 */
disabled-list-option: #CBD5E1, /* blueGray.300 */
tooltip: #1E293B /* blueGray.800 */
);
$background-dark: (
status-bar: #0F172A, /* blueGray.900 */
app-bar: #0F172A, /* blueGray.900 */
background: #0F172A, /* blueGray.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* blueGray.800 */
dialog: #1E293B, /* blueGray.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
raised-button: #0F172A, /* blueGray.900 */
focused-button: #E2E8F0, /* blueGray.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* blueGray.800 */
disabled-button-toggle: #0F172A, /* blueGray.900 */
unselected-chip: #475569, /* blueGray.600 */
disabled-list-option: #E2E8F0, /* blueGray.200 */
tooltip: #64748B /* blueGray.500 */
);
$foreground-light: (
base: #000000,
divider: #E2E8F0, /* blueGray.200 */
dividers: #E2E8F0, /* blueGray.200 */
disabled: #94A3B8, /* blueGray.400 */
disabled-button: #94A3B8, /* blueGray.400 */
disabled-text: #94A3B8, /* blueGray.400 */
elevation: #000000,
hint-text: #94A3B8, /* blueGray.400 */
secondary-text: #64748B, /* blueGray.500 */
icon: #64748B, /* blueGray.500 */
icons: #64748B, /* blueGray.500 */
mat-icon: #64748B, /* blueGray.500 */
text: #1E293B, /* blueGray.800 */
slider-min: #1E293B, /* blueGray.800 */
slider-off: #CBD5E1, /* blueGray.300 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
$foreground-dark: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
disabled: #475569, /* blueGray.600 */
disabled-button: #1E293B, /* blueGray.800 */
disabled-text: #475569, /* blueGray.600 */
elevation: #000000,
hint-text: #64748B, /* blueGray.500 */
secondary-text: #94A3B8, /* blueGray.400 */
icon: #F1F5F9, /* blueGray.100 */
icons: #F1F5F9, /* blueGray.100 */
mat-icon: #94A3B8, /* blueGray.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* blueGray.500 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
/* Generate Primary, Accent and Warn palettes */
$palettes: ();
@each $name in (primary, accent, warn) {
@@ -145,8 +70,41 @@ body .light {
accent: map.get(map.get($base-light-theme, color), accent),
warn: map.get(map.get($base-light-theme, color), warn),
is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: $foreground-light,
background: $background-light
foreground: (
base: #000000,
divider: #E2E8F0, /* blueGray.200 */
dividers: #E2E8F0, /* blueGray.200 */
disabled: #94A3B8, /* blueGray.400 */
disabled-button: #94A3B8, /* blueGray.400 */
disabled-text: #94A3B8, /* blueGray.400 */
elevation: #000000,
hint-text: #94A3B8, /* blueGray.400 */
secondary-text: #64748B, /* blueGray.500 */
icon: #64748B, /* blueGray.500 */
icons: #64748B, /* blueGray.500 */
mat-icon: #64748B, /* blueGray.500 */
text: #1E293B, /* blueGray.800 */
slider-min: #1E293B, /* blueGray.800 */
slider-off: #CBD5E1, /* blueGray.300 */
slider-off-active: #94A3B8 /* blueGray.400 */
),
background: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* blueGray.100 */
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* blueGray.500 */
selected-button: #E2E8F0, /* blueGray.200 */
selected-disabled-button: #E2E8F0, /* blueGray.200 */
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
unselected-chip: #E2E8F0, /* blueGray.200 */
disabled-list-option: #CBD5E1, /* blueGray.300 */
tooltip: #1E293B /* blueGray.800 */
)
)
);
@@ -166,8 +124,41 @@ body .dark {
accent: map.get(map.get($base-dark-theme, color), accent),
warn: map.get(map.get($base-dark-theme, color), warn),
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: $foreground-dark,
background: $background-dark
foreground: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
disabled: #475569, /* blueGray.600 */
disabled-button: #1E293B, /* blueGray.800 */
disabled-text: #475569, /* blueGray.600 */
elevation: #000000,
hint-text: #64748B, /* blueGray.500 */
secondary-text: #94A3B8, /* blueGray.400 */
icon: #F1F5F9, /* blueGray.100 */
icons: #F1F5F9, /* blueGray.100 */
mat-icon: #94A3B8, /* blueGray.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* blueGray.500 */
slider-off-active: #94A3B8 /* blueGray.400 */
),
background: (
status-bar: #0F172A, /* blueGray.900 */
app-bar: #0F172A, /* blueGray.900 */
background: #0F172A, /* blueGray.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* blueGray.800 */
dialog: #1E293B, /* blueGray.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
raised-button: #0F172A, /* blueGray.900 */
focused-button: #E2E8F0, /* blueGray.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* blueGray.800 */
disabled-button-toggle: #0F172A, /* blueGray.900 */
unselected-chip: #475569, /* blueGray.600 */
disabled-list-option: #E2E8F0, /* blueGray.200 */
tooltip: #64748B /* blueGray.500 */
)
)
);

View File

@@ -1,3 +1,3 @@
import { Version } from '@fuse/version/version';
export const FUSE_VERSION = new Version('13.1.0').full;
export const FUSE_VERSION = new Version('13.5.0').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

@@ -79,6 +79,8 @@ export const appRoutes: Route[] = [
{path: 'dashboards', children: [
{path: 'project', loadChildren: () => import('app/modules/admin/dashboards/project/project.module').then(m => m.ProjectModule)},
{path: 'analytics', loadChildren: () => import('app/modules/admin/dashboards/analytics/analytics.module').then(m => m.AnalyticsModule)},
{path: 'finance', loadChildren: () => import('app/modules/admin/dashboards/finance/finance.module').then(m => m.FinanceModule)},
{path: 'crypto', loadChildren: () => import('app/modules/admin/dashboards/crypto/crypto.module').then(m => m.CryptoModule)},
]},
// Apps
@@ -105,7 +107,7 @@ export const appRoutes: Route[] = [
// Authentication
{path: 'authentication', loadChildren: () => import('app/modules/admin/pages/authentication/authentication.module').then(m => m.AuthenticationModule)},
// Coming soon
// Coming Soon
{path: 'coming-soon', loadChildren: () => import('app/modules/admin/pages/coming-soon/coming-soon.module').then(m => m.ComingSoonModule)},
// Error
@@ -140,16 +142,22 @@ export const appRoutes: Route[] = [
{path: 'settings', loadChildren: () => import('app/modules/admin/pages/settings/settings.module').then(m => m.SettingsModule)},
]},
// User interface
// User Interface
{path: 'ui', children: [
// Angular Material
{path: 'angular-material', loadChildren: () => import('app/modules/admin/ui/angular-material/angular-material.module').then(m => m.AngularMaterialModule)},
// Material Components
{path: 'material-components', loadChildren: () => import('app/modules/admin/ui/material-components/material-components.module').then(m => m.MaterialComponentsModule)},
// Fuse Components
{path: 'fuse-components', loadChildren: () => import('app/modules/admin/ui/fuse-components/fuse-components.module').then(m => m.FuseComponentsModule)},
// Other Components
{path: 'other-components', loadChildren: () => import('app/modules/admin/ui/other-components/other-components.module').then(m => m.OtherComponentsModule)},
// TailwindCSS
{path: 'tailwindcss', loadChildren: () => import('app/modules/admin/ui/tailwindcss/tailwindcss.module').then(m => m.TailwindCSSModule)},
// Advanced search
// Advanced Search
{path: 'advanced-search', loadChildren: () => import('app/modules/admin/ui/advanced-search/advanced-search.module').then(m => m.AdvancedSearchModule)},
// Animations
@@ -161,6 +169,9 @@ export const appRoutes: Route[] = [
// Colors
{path: 'colors', loadChildren: () => import('app/modules/admin/ui/colors/colors.module').then(m => m.ColorsModule)},
// Confirmation Dialog
{path: 'confirmation-dialog', loadChildren: () => import('app/modules/admin/ui/confirmation-dialog/confirmation-dialog.module').then(m => m.ConfirmationDialogModule)},
// Datatable
{path: 'datatable', loadChildren: () => import('app/modules/admin/ui/datatable/datatable.module').then(m => m.DatatableModule)},
@@ -174,7 +185,7 @@ export const appRoutes: Route[] = [
// Icons
{path: 'icons', loadChildren: () => import('app/modules/admin/ui/icons/icons.module').then(m => m.IconsModule)},
// Page layouts
// Page Layouts
{path: 'page-layouts', loadChildren: () => import('app/modules/admin/ui/page-layouts/page-layouts.module').then(m => m.PageLayoutsModule)},
// Typography
@@ -188,13 +199,7 @@ export const appRoutes: Route[] = [
{path: 'changelog', loadChildren: () => import('app/modules/admin/docs/changelog/changelog.module').then(m => m.ChangelogModule)},
// Guides
{path: 'guides', loadChildren: () => import('app/modules/admin/docs/guides/guides.module').then(m => m.GuidesModule)},
// Core features
{path: 'core-features', loadChildren: () => import('app/modules/admin/docs/core-features/core-features.module').then(m => m.CoreFeaturesModule)},
// Other components
{path: 'other-components', loadChildren: () => import('app/modules/admin/docs/other-components/other-components.module').then(m => m.OtherComponentsModule)},
{path: 'guides', loadChildren: () => import('app/modules/admin/docs/guides/guides.module').then(m => m.GuidesModule)}
]},
// 404 & Catch all

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

@@ -167,7 +167,7 @@ export class MessagesComponent implements OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._messagesOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

View File

@@ -167,7 +167,7 @@ export class NotificationsComponent implements OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._notificationsOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

View File

@@ -221,7 +221,7 @@ export class ShortcutsComponent implements OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._shortcutsOrigin._elementRef.nativeElement)
.withLockedPosition()
.withLockedPosition(true)
.withPush(true)
.withPositions([
{

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

@@ -62,9 +62,9 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -45,9 +45,9 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -51,9 +51,9 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -54,9 +54,9 @@
</button>
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -35,9 +35,9 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -65,9 +65,9 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -30,9 +30,9 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -39,9 +39,9 @@
</button>
</div>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -44,9 +44,9 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -31,9 +31,9 @@
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
<languages></languages>
<fuse-fullscreen></fuse-fullscreen>
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts></shortcuts>
<messages></messages>

View File

@@ -22,6 +22,20 @@ export const defaultNavigation: FuseNavigationItem[] = [
type : 'basic',
icon : 'heroicons_outline:chart-pie',
link : '/dashboards/analytics'
},
{
id : 'dashboards.finance',
title: 'Finance',
type : 'basic',
icon : 'heroicons_outline:cash',
link : '/dashboards/finance'
},
{
id : 'dashboards.crypto',
title: 'Crypto',
type : 'basic',
icon : 'heroicons_outline:currency-dollar',
link : '/dashboards/crypto'
}
]
},
@@ -77,14 +91,14 @@ export const defaultNavigation: FuseNavigationItem[] = [
},
{
id : 'apps.file-manager',
title: 'File manager',
title: 'File Manager',
type : 'basic',
icon : 'heroicons_outline:cloud',
link : '/apps/file-manager'
},
{
id : 'apps.help-center',
title : 'Help center',
title : 'Help Center',
type : 'collapsable',
icon : 'heroicons_outline:support',
link : '/apps/help-center',
@@ -523,7 +537,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
},
{
id : 'pages.coming-soon',
title : 'Coming soon',
title : 'Coming Soon',
type : 'collapsable',
icon : 'heroicons_outline:clock',
link : '/pages/coming-soon',
@@ -682,11 +696,25 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:collection',
children: [
{
id : 'user-interface.angular-material',
title: 'Angular Material components',
id : 'user-interface.material-components',
title: 'Material Components',
type : 'basic',
icon : 'heroicons_outline:chip',
link : '/ui/angular-material'
link : '/ui/material-components'
},
{
id : 'user-interface.fuse-components',
title: 'Fuse Components',
type : 'basic',
icon : 'heroicons_outline:chip',
link : '/ui/fuse-components'
},
{
id : 'user-interface.other-components',
title: 'Other Components',
type : 'basic',
icon : 'heroicons_outline:chip',
link : '/ui/other-components'
},
{
id : 'user-interface.tailwindcss',
@@ -697,7 +725,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
},
{
id : 'user-interface.advanced-search',
title: 'Advanced search',
title: 'Advanced Search',
type : 'basic',
icon : 'heroicons_outline:search-circle',
link : '/ui/advanced-search'
@@ -723,6 +751,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:color-swatch',
link : '/ui/colors'
},
{
id : 'user-interface.confirmation-dialog',
title: 'Confirmation Dialog',
type : 'basic',
icon : 'heroicons_outline:question-mark-circle',
link : '/ui/confirmation-dialog'
},
{
id : 'user-interface.datatable',
title: 'Datatable',
@@ -808,7 +843,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
},
{
id : 'user-interface.page-layouts',
title : 'Page layouts',
title : 'Page Layouts',
type : 'collapsable',
icon : 'heroicons_outline:template',
children: [
@@ -946,7 +981,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:speakerphone',
link : '/docs/changelog',
badge: {
title : '13.1.0',
title : '13.5.0',
classes: 'px-2 bg-yellow-300 text-black rounded-full'
}
},
@@ -956,20 +991,6 @@ export const defaultNavigation: FuseNavigationItem[] = [
type : 'basic',
icon : 'heroicons_outline:book-open',
link : '/docs/guides'
},
{
id : 'documentation.core-features',
title: 'Core features',
type : 'basic',
icon : 'heroicons_outline:book-open',
link : '/docs/core-features'
},
{
id : 'documentation.other-components',
title: 'Other components',
type : 'basic',
icon : 'heroicons_outline:book-open',
link : '/docs/other-components'
}
]
},
@@ -1135,6 +1156,7 @@ export const compactNavigation: FuseNavigationItem[] = [
{
id : 'dashboards',
title : 'Dashboards',
tooltip : 'Dashboards',
type : 'aside',
icon : 'heroicons_outline:home',
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
@@ -1142,6 +1164,7 @@ export const compactNavigation: FuseNavigationItem[] = [
{
id : 'apps',
title : 'Apps',
tooltip : 'Apps',
type : 'aside',
icon : 'heroicons_outline:qrcode',
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
@@ -1149,6 +1172,7 @@ export const compactNavigation: FuseNavigationItem[] = [
{
id : 'pages',
title : 'Pages',
tooltip : 'Pages',
type : 'aside',
icon : 'heroicons_outline:document-duplicate',
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
@@ -1156,6 +1180,7 @@ export const compactNavigation: FuseNavigationItem[] = [
{
id : 'user-interface',
title : 'UI',
tooltip : 'UI',
type : 'aside',
icon : 'heroicons_outline:collection',
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
@@ -1163,6 +1188,7 @@ export const compactNavigation: FuseNavigationItem[] = [
{
id : 'navigation-features',
title : 'Navigation',
tooltip : 'Navigation',
type : 'aside',
icon : 'heroicons_outline:menu',
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation

View File

@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { cloneDeep } from 'lodash-es';
import { FuseMockApiService } from '@fuse/lib/mock-api';
import { crypto as cryptoData } from 'app/mock-api/dashboards/crypto/data';
@Injectable({
providedIn: 'root'
})
export class CryptoMockApi
{
private _crypto: any = cryptoData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Crypto - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/dashboards/crypto')
.reply(() => [200, cloneDeep(this._crypto)]);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { cloneDeep } from 'lodash-es';
import { FuseMockApiService } from '@fuse/lib/mock-api';
import { finance as financeData } from 'app/mock-api/dashboards/finance/data';
@Injectable({
providedIn: 'root'
})
export class FinanceMockApi
{
private _finance: any = financeData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Sales - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/dashboards/finance')
.reply(() => [200, cloneDeep(this._finance)]);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,10 @@ import { AuthMockApi } from 'app/mock-api/common/auth/api';
import { CalendarMockApi } from 'app/mock-api/apps/calendar/api';
import { ChatMockApi } from 'app/mock-api/apps/chat/api';
import { ContactsMockApi } from 'app/mock-api/apps/contacts/api';
import { CryptoMockApi } from 'app/mock-api/dashboards/crypto/api';
import { ECommerceInventoryMockApi } from 'app/mock-api/apps/ecommerce/inventory/api';
import { FileManagerMockApi } from 'app/mock-api/apps/file-manager/api';
import { FinanceMockApi } from 'app/mock-api/dashboards/finance/api';
import { HelpCenterMockApi } from 'app/mock-api/apps/help-center/api';
import { IconsMockApi } from 'app/mock-api/ui/icons/api';
import { MailboxMockApi } from 'app/mock-api/apps/mailbox/api';
@@ -29,8 +31,10 @@ export const mockApiServices = [
CalendarMockApi,
ChatMockApi,
ContactsMockApi,
CryptoMockApi,
ECommerceInventoryMockApi,
FileManagerMockApi,
FinanceMockApi,
HelpCenterMockApi,
IconsMockApi,
MailboxMockApi,

View File

@@ -6,6 +6,7 @@ import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { MatDrawerToggleResult } from '@angular/material/sidenav';
import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { FuseConfirmationService } from '@fuse/services/confirmation';
import { Contact, Country, Tag } from 'app/modules/admin/apps/contacts/contacts.types';
import { ContactsListComponent } from 'app/modules/admin/apps/contacts/list/list.component';
import { ContactsService } from 'app/modules/admin/apps/contacts/contacts.service';
@@ -42,6 +43,7 @@ export class ContactsDetailsComponent implements OnInit, OnDestroy
private _contactsListComponent: ContactsListComponent,
private _contactsService: ContactsService,
private _formBuilder: FormBuilder,
private _fuseConfirmationService: FuseConfirmationService,
private _renderer2: Renderer2,
private _router: Router,
private _overlay: Overlay,
@@ -276,41 +278,61 @@ export class ContactsDetailsComponent implements OnInit, OnDestroy
*/
deleteContact(): void
{
// Get the current contact's id
const id = this.contact.id;
// Get the next/previous contact's id
const currentContactIndex = this.contacts.findIndex(item => item.id === id);
const nextContactIndex = currentContactIndex + ((currentContactIndex === (this.contacts.length - 1)) ? -1 : 1);
const nextContactId = (this.contacts.length === 1 && this.contacts[0].id === id) ? null : this.contacts[nextContactIndex].id;
// Delete the contact
this._contactsService.deleteContact(id)
.subscribe((isDeleted) => {
// Return if the contact wasn't deleted...
if ( !isDeleted )
{
return;
// Open the confirmation dialog
const confirmation = this._fuseConfirmationService.open({
title : 'Delete contact',
message: 'Are you sure you want to delete this contact? This action cannot be undone!',
actions: {
confirm: {
label: 'Delete'
}
}
});
// Navigate to the next contact if available
if ( nextContactId )
{
this._router.navigate(['../', nextContactId], {relativeTo: this._activatedRoute});
}
// Otherwise, navigate to the parent
else
{
this._router.navigate(['../'], {relativeTo: this._activatedRoute});
}
// Subscribe to the confirmation dialog closed action
confirmation.afterClosed().subscribe((result) => {
// Toggle the edit mode off
this.toggleEditMode(false);
});
// If the confirm button pressed...
if ( result === 'confirmed' )
{
// Get the current contact's id
const id = this.contact.id;
// Get the next/previous contact's id
const currentContactIndex = this.contacts.findIndex(item => item.id === id);
const nextContactIndex = currentContactIndex + ((currentContactIndex === (this.contacts.length - 1)) ? -1 : 1);
const nextContactId = (this.contacts.length === 1 && this.contacts[0].id === id) ? null : this.contacts[nextContactIndex].id;
// Delete the contact
this._contactsService.deleteContact(id)
.subscribe((isDeleted) => {
// Return if the contact wasn't deleted...
if ( !isDeleted )
{
return;
}
// Navigate to the next contact if available
if ( nextContactId )
{
this._router.navigate(['../', nextContactId], {relativeTo: this._activatedRoute});
}
// Otherwise, navigate to the parent
else
{
this._router.navigate(['../'], {relativeTo: this._activatedRoute});
}
// Toggle the edit mode off
this.toggleEditMode(false);
});
// Mark for check
this._changeDetectorRef.markForCheck();
}
});
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
@@ -369,9 +391,9 @@ export class ContactsDetailsComponent implements OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._tagsPanelOrigin.nativeElement)
.withFlexibleDimensions()
.withFlexibleDimensions(true)
.withViewportMargin(64)
.withLockedPosition()
.withLockedPosition(true)
.withPositions([
{
originX : 'start',

View File

@@ -42,7 +42,7 @@
<div class="flex items-center mt-4 sm:mt-0 md:mt-4">
<!-- Search -->
<div class="flex-auto">
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript w-full min-w-50">
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded w-full min-w-50">
<mat-icon
class="icon-size-5"
matPrefix

View File

@@ -13,10 +13,11 @@
<!-- Actions -->
<div class="flex flex-shrink-0 items-center mt-6 sm:mt-0 sm:ml-4">
<!-- Search -->
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript min-w-50">
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded min-w-64">
<mat-icon
class="icon-size-5"
matPrefix
[svgIcon]="'heroicons_outline:search'"></mat-icon>
[svgIcon]="'heroicons_solid:search'"></mat-icon>
<input
matInput
[formControl]="searchInputControl"
@@ -361,7 +362,7 @@
<!-- Tags -->
<span class="mb-px font-medium leading-tight">Tags</span>
<div class="mt-1.5 rounded-md border border-gray-300 shadow-sm overflow-hidden">
<div class="mt-1.5 rounded-md border border-gray-300 dark:border-gray-500 shadow-sm overflow-hidden">
<!-- Header -->
<div class="flex items-center -my-px py-2 px-3">
<div class="flex items-center flex-auto min-w-0">
@@ -392,7 +393,7 @@
</button>
</div>
<!-- Available tags -->
<div class="h-44 leading-none overflow-y-auto border-t">
<div class="h-44 leading-none overflow-y-auto border-t border-gray-300 dark:border-gray-500">
<!-- Tags -->
<ng-container *ngIf="!tagsEditMode">
<ng-container *ngFor="let tag of filteredTags; trackBy: trackByFn">

View File

@@ -6,6 +6,7 @@ import { MatSort } from '@angular/material/sort';
import { merge, Observable, Subject } from 'rxjs';
import { debounceTime, map, switchMap, takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { FuseConfirmationService } from '@fuse/services/confirmation';
import { InventoryBrand, InventoryCategory, InventoryPagination, InventoryProduct, InventoryTag, InventoryVendor } from 'app/modules/admin/apps/ecommerce/inventory/inventory.types';
import { InventoryService } from 'app/modules/admin/apps/ecommerce/inventory/inventory.service';
@@ -62,6 +63,7 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseConfirmationService: FuseConfirmationService,
private _formBuilder: FormBuilder,
private _inventoryService: InventoryService
)
@@ -525,14 +527,34 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
*/
deleteSelectedProduct(): void
{
// Get the product object
const product = this.selectedProductForm.getRawValue();
// Open the confirmation dialog
const confirmation = this._fuseConfirmationService.open({
title : 'Delete product',
message: 'Are you sure you want to remove this product? This action cannot be undone!',
actions: {
confirm: {
label: 'Delete'
}
}
});
// Delete the product on the server
this._inventoryService.deleteProduct(product.id).subscribe(() => {
// Subscribe to the confirmation dialog closed action
confirmation.afterClosed().subscribe((result) => {
// Close the details
this.closeDetails();
// If the confirm button pressed...
if ( result === 'confirmed' )
{
// Get the product object
const product = this.selectedProductForm.getRawValue();
// Delete the product on the server
this._inventoryService.deleteProduct(product.id).subscribe(() => {
// Close the details
this.closeDetails();
});
}
});
}

View File

@@ -1,7 +1,7 @@
<div class="flex flex-col flex-auto min-w-0">
<!-- Header -->
<div class="relative pt-8 pb-28 px-4 sm:pt-20 sm:pb-48 sm:px-16 overflow-hidden bg-gray-800 dark">
<div class="relative pt-8 pb-28 px-4 sm:pt-20 sm:pb-48 sm:px-16 overflow-hidden bg-gray-800 dark:bg-gray-900 dark">
<!-- Background - @formatter:off -->
<!-- Rings -->
<svg class="absolute inset-0 pointer-events-none"
@@ -40,7 +40,7 @@
<div class="text-2xl font-semibold">FAQs</div>
<div class="md:max-w-40 mt-1 text-secondary">Frequently asked questions and answers</div>
</div>
<div class="flex items-center justify-center py-4 px-8 text-primary bg-gray-50 dark:bg-transparent dark:border-t">
<div class="flex items-center justify-center py-4 px-8 text-primary-500 dark:text-primary-400 bg-gray-50 dark:bg-transparent dark:border-t">
<a
class="flex items-center"
[routerLink]="['faqs']">
@@ -58,7 +58,7 @@
<div class="text-2xl font-semibold">Guides</div>
<div class="md:max-w-40 mt-1 text-secondary">Articles and resources to guide you</div>
</div>
<div class="flex items-center justify-center py-4 px-8 text-primary-500 bg-gray-50 dark:bg-transparent dark:border-t">
<div class="flex items-center justify-center py-4 px-8 text-primary-500 dark:text-primary-400 bg-gray-50 dark:bg-transparent dark:border-t">
<a
class="flex items-center"
[routerLink]="['guides']">
@@ -76,7 +76,7 @@
<div class="text-2xl font-semibold">Support</div>
<div class="md:max-w-40 mt-1 text-secondary">Contact us for more detailed support</div>
</div>
<div class="flex items-center justify-center py-4 px-8 text-primary-500 bg-gray-50 dark:bg-transparent dark:border-t">
<div class="flex items-center justify-center py-4 px-8 text-primary-500 dark:text-primary-400 bg-gray-50 dark:bg-transparent dark:border-t">
<a
class="flex items-center"
[routerLink]="['support']">

View File

@@ -16,7 +16,7 @@
Contact support
</div>
<!-- Form -->
<div class="mt-8 sm:mt-12 p-6 pb-7 sm:p-10 sm:pb-7 shadow rounded-2xl bg-white">
<div class="mt-8 sm:mt-12 p-6 pb-7 sm:p-10 sm:pb-7 shadow rounded-2xl bg-card">
<!-- Alert -->
<fuse-alert
class="mb-8"

View File

@@ -1,4 +1,4 @@
<div class="flex flex-col max-w-240 md:min-w-160 -m-6">
<div class="flex flex-col max-w-240 md:min-w-160 max-h-screen -m-6">
<!-- Header -->
<div class="flex flex-0 items-center justify-between h-16 pr-3 sm:pr-5 pl-6 sm:pl-8 bg-primary text-on-primary">
@@ -107,14 +107,14 @@
<!-- Discard -->
<button
class="ml-auto sm:ml-0"
mat-button
mat-stroked-button
(click)="discard()">
Discard
</button>
<!-- Save as draft -->
<button
class="sm:mx-3"
mat-button
mat-stroked-button
(click)="saveAsDraft()">
<span>Save as draft</span>
</button>

View File

@@ -304,9 +304,9 @@ export class MailboxDetailsComponent implements OnInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._infoDetailsPanelOrigin._elementRef.nativeElement)
.withFlexibleDimensions()
.withFlexibleDimensions(true)
.withViewportMargin(16)
.withLockedPosition()
.withLockedPosition(true)
.withPositions([
{
originX : 'start',

View File

@@ -85,7 +85,7 @@
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:pencil-alt'"></mat-icon>
Rename List
Rename list
</button>
<button
mat-menu-item
@@ -93,7 +93,7 @@
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:trash'"></mat-icon>
Delete List
Delete list
</button>
</mat-menu>
</div>

View File

@@ -3,9 +3,10 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import * as moment from 'moment';
import { FuseConfirmationService } from '@fuse/services/confirmation';
import { ScrumboardService } from 'app/modules/admin/apps/scrumboard/scrumboard.service';
import { Board, Card, List } from 'app/modules/admin/apps/scrumboard/scrumboard.models';
import * as moment from 'moment';
@Component({
selector : 'scrumboard-board',
@@ -31,6 +32,7 @@ export class ScrumboardBoardComponent implements OnInit, OnDestroy
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _formBuilder: FormBuilder,
private _fuseConfirmationService: FuseConfirmationService,
private _scrumboardService: ScrumboardService
)
{
@@ -148,8 +150,28 @@ export class ScrumboardBoardComponent implements OnInit, OnDestroy
*/
deleteList(id): void
{
// Delete the list
this._scrumboardService.deleteList(id).subscribe();
// Open the confirmation dialog
const confirmation = this._fuseConfirmationService.open({
title : 'Delete list',
message: 'Are you sure you want to delete this list and its cards? This action cannot be undone!',
actions: {
confirm: {
label: 'Delete'
}
}
});
// Subscribe to the confirmation dialog closed action
confirmation.afterClosed().subscribe((result) => {
// If the confirm button pressed...
if ( result === 'confirmed' )
{
// Delete the list
this._scrumboardService.deleteList(id).subscribe();
}
});
}
/**

View File

@@ -4,6 +4,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { TemplatePortal } from '@angular/cdk/portal';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { MatDrawerToggleResult } from '@angular/material/sidenav';
import { FuseConfirmationService } from '@fuse/services/confirmation';
import { Subject } from 'rxjs';
import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators';
import { assign } from 'lodash-es';
@@ -40,6 +41,7 @@ export class TasksDetailsComponent implements OnInit, AfterViewInit, OnDestroy
private _activatedRoute: ActivatedRoute,
private _changeDetectorRef: ChangeDetectorRef,
private _formBuilder: FormBuilder,
private _fuseConfirmationService: FuseConfirmationService,
private _renderer2: Renderer2,
private _router: Router,
private _tasksListComponent: TasksListComponent,
@@ -217,9 +219,9 @@ export class TasksDetailsComponent implements OnInit, AfterViewInit, OnDestroy
scrollStrategy : this._overlay.scrollStrategies.block(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._tagsPanelOrigin.nativeElement)
.withFlexibleDimensions()
.withFlexibleDimensions(true)
.withViewportMargin(64)
.withLockedPosition()
.withLockedPosition(true)
.withPositions([
{
originX : 'start',
@@ -472,38 +474,58 @@ export class TasksDetailsComponent implements OnInit, AfterViewInit, OnDestroy
*/
deleteTask(): void
{
// Get the current task's id
const id = this.task.id;
// Get the next/previous task's id
const currentTaskIndex = this.tasks.findIndex(item => item.id === id);
const nextTaskIndex = currentTaskIndex + ((currentTaskIndex === (this.tasks.length - 1)) ? -1 : 1);
const nextTaskId = (this.tasks.length === 1 && this.tasks[0].id === id) ? null : this.tasks[nextTaskIndex].id;
// Delete the task
this._tasksService.deleteTask(id)
.subscribe((isDeleted) => {
// Return if the task wasn't deleted...
if ( !isDeleted )
{
return;
// Open the confirmation dialog
const confirmation = this._fuseConfirmationService.open({
title : 'Delete task',
message: 'Are you sure you want to delete this task? This action cannot be undone!',
actions: {
confirm: {
label: 'Delete'
}
}
});
// Navigate to the next task if available
if ( nextTaskId )
{
this._router.navigate(['../', nextTaskId], {relativeTo: this._activatedRoute});
}
// Otherwise, navigate to the parent
else
{
this._router.navigate(['../'], {relativeTo: this._activatedRoute});
}
});
// Subscribe to the confirmation dialog closed action
confirmation.afterClosed().subscribe((result) => {
// Mark for check
this._changeDetectorRef.markForCheck();
// If the confirm button pressed...
if ( result === 'confirmed' )
{
// Get the current task's id
const id = this.task.id;
// Get the next/previous task's id
const currentTaskIndex = this.tasks.findIndex(item => item.id === id);
const nextTaskIndex = currentTaskIndex + ((currentTaskIndex === (this.tasks.length - 1)) ? -1 : 1);
const nextTaskId = (this.tasks.length === 1 && this.tasks[0].id === id) ? null : this.tasks[nextTaskIndex].id;
// Delete the task
this._tasksService.deleteTask(id)
.subscribe((isDeleted) => {
// Return if the task wasn't deleted...
if ( !isDeleted )
{
return;
}
// Navigate to the next task if available
if ( nextTaskId )
{
this._router.navigate(['../', nextTaskId], {relativeTo: this._activatedRoute});
}
// Otherwise, navigate to the parent
else
{
this._router.navigate(['../'], {relativeTo: this._activatedRoute});
}
});
// Mark for check
this._changeDetectorRef.markForCheck();
}
});
}
/**

View File

@@ -18,20 +18,11 @@ export class AnalyticsComponent implements OnInit, OnDestroy
chartImpressions: ApexOptions;
chartVisits: ApexOptions;
chartVisitorsVsPageViews: ApexOptions;
data: any;
chartAge: ApexOptions;
averagePurchaseValueOptions: ApexOptions;
browsersOptions: ApexOptions;
channelsOptions: ApexOptions;
devicesOptions: ApexOptions;
chartGender: ApexOptions;
chartLanguage: ApexOptions;
chartNewVsReturning: ApexOptions;
refundsOptions: ApexOptions;
totalVisitsOptions: ApexOptions;
uniqueVisitorsOptions: ApexOptions;
uniquePurchasesOptions: ApexOptions;
chartGender: ApexOptions;
chartAge: ApexOptions;
chartLanguage: ApexOptions;
data: any;
private _unsubscribeAll: Subject<any> = new Subject<any>();

View File

@@ -0,0 +1,277 @@
<div class="absolute inset-0 flex flex-col min-w-0 overflow-hidden">
<mat-drawer-container class="flex-auto h-full">
<!-- Drawer -->
<mat-drawer
class="w-80"
[autoFocus]="false"
[mode]="drawerMode"
[opened]="drawerOpened"
#matDrawer>
<div class="flex flex-col flex-auto h-full dark:bg-default">
<!-- Watchlist -->
<div class="flex flex-col flex-0">
<div
class="flex flex-0 items-center p-5 border-b"
*ngFor="let item of data.watchlist">
<div class="flex flex-col flex-auto pr-6">
<div class="flex items-baseline">
<div class="mr-1 font-medium text-md text-secondary">{{item.title}}</div>
<div class="font-medium text-sm text-hint uppercase tracking-wider">({{item.iso}})</div>
</div>
<div class="flex items-end mt-2">
<div class="min-w-20 font-mono text-2xl tracking-tighter leading-none">
{{item.amount | currency:'USD':'symbol':'1.2-4'}}
</div>
<mat-icon
class="text-green-500 icon-size-3.5 mx-0.5 mb-px"
[ngClass]="{'text-green-500': item.trend.dir === 'up', 'text-red-500': item.trend.dir === 'down'}"
[svgIcon]="item.trend.dir === 'up' ? 'heroicons_solid:arrow-narrow-up' : 'heroicons_solid:arrow-narrow-down'"></mat-icon>
<div
class="font-mono font-medium text-sm leading-none mb-px"
[ngClass]="{'text-green-500': item.trend.dir === 'up', 'text-red-500': item.trend.dir === 'down'}">
{{item.trend.amount}}%
</div>
</div>
</div>
<apx-chart
class="flex flex-auto items-center h-10 overflow-hidden"
[chart]="watchlistChartOptions.chart"
[colors]="item.trend.dir === 'up' ? ['#48BB78']: ['#F56565']"
[series]="item.series"
[stroke]="watchlistChartOptions.stroke"
[tooltip]="watchlistChartOptions.tooltip"
[xaxis]="watchlistChartOptions.xaxis"></apx-chart>
</div>
</div>
<!-- Buy / Sell -->
<div class="flex flex-col flex-auto flex-shrink-0 pt-6 bg-gray-50 dark:bg-transparent">
<!-- Action -->
<div class="flex flex-col px-6 pb-2">
<mat-form-field>
<mat-label>Action</mat-label>
<span
class="flex items-center justify-center"
matPrefix>
<ng-container *ngIf="buySellSelect.value === 'buy'">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:download'"></mat-icon>
</ng-container>
<ng-container *ngIf="buySellSelect.value === 'sell'">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:upload'"></mat-icon>
</ng-container>
</span>
<mat-select
[value]="'buy'"
#buySellSelect="matSelect">
<mat-option [value]="'buy'">Buy</mat-option>
<mat-option [value]="'sell'">Sell</mat-option>
</mat-select>
</mat-form-field>
</div>
<!-- Wallet -->
<div class="flex flex-col px-6 pb-2">
<mat-form-field class="w-full">
<mat-label>Wallet</mat-label>
<mat-select
[value]="'btc'"
#walletSelector="matSelect">
<mat-select-trigger>
<span class="flex items-center">
<span>{{walletSelector.triggerValue}}</span>
<span class="mx-1 text-hint">-</span>
<span class="flex items-center font-mono">
<span>{{data.wallets[walletSelector.value]}}</span>
<span class="ml-1">{{walletSelector.value | uppercase}}</span>
</span>
</span>
</mat-select-trigger>
<mat-option [value]="'btc'">Bitcoin</mat-option>
<mat-option [value]="'eth'">Ethereum</mat-option>
<mat-option [value]="'bch'">Bitcoin Cash</mat-option>
<mat-option [value]="'xrp'">XRP</mat-option>
</mat-select>
<mat-hint class="flex items-center">
<span class="mr-1">USD:</span>
<span class="font-mono font-medium text-normal">
{{data.wallets[walletSelector.value] * data.prices[walletSelector.value] | currency:'USD'}}
</span>
</mat-hint>
</mat-form-field>
</div>
<!-- Buy form -->
<form
class="flex flex-col px-6"
*ngIf="buySellSelect.value === 'buy'">
<mat-form-field class="w-full">
<mat-label>Amount</mat-label>
<input
matInput
autocomplete="off"
#buyAmount>
<mat-select
[value]="'coin'"
matSuffix
#buyType="matSelect">
<mat-option [value]="'coin'">{{walletSelector.value | uppercase}}</mat-option>
<mat-option [value]="'usd'">USD</mat-option>
</mat-select>
<span
matPrefix
*ngIf="buyType.value === 'usd'">
$
</span>
<mat-hint class="flex items-center">
<ng-container *ngIf="buyType.value === 'coin'">
<span class="mr-1">It will cost:</span>
<span class="font-mono font-medium text-normal">
{{buyAmount.value * data.prices[walletSelector.value] | currency:'USD':'symbol':'1.2-4'}}
</span>
</ng-container>
<ng-container *ngIf="buyType.value === 'usd'">
<span class="mr-1">You will receive:</span>
<span class="font-mono font-medium text-normal">
{{buyAmount.value / data.prices[walletSelector.value] | number:'1.2-6'}} {{walletSelector.value | uppercase}}
</span>
</ng-container>
</mat-hint>
</mat-form-field>
<button
class="mt-4 mb-8"
mat-flat-button
[color]="'primary'">
BUY
</button>
</form>
<!-- Sell form -->
<form
class="flex flex-col px-6"
*ngIf="buySellSelect.value === 'sell'">
<mat-form-field class="w-full">
<mat-label>Amount</mat-label>
<input
matInput
autocomplete="off"
#sellAmount>
<mat-select
[value]="'coin'"
matSuffix
#sellType="matSelect">
<mat-option [value]="'coin'">{{walletSelector.value | uppercase}}</mat-option>
<mat-option [value]="'usd'">USD</mat-option>
</mat-select>
<span
matPrefix
*ngIf="sellType.value === 'usd'">
$
</span>
<mat-hint class="flex items-center">
<ng-container *ngIf="sellType.value === 'coin'">
<span class="mr-1">You will receive:</span>
<span class="font-mono font-medium text-normal">
{{sellAmount.value * data.prices[walletSelector.value] | currency:'USD':'symbol':'1.2-4'}}
</span>
</ng-container>
<ng-container *ngIf="sellType.value === 'usd'">
<span class="mr-1">You will sell:</span>
<span class="font-mono font-medium text-normal">
{{sellAmount.value / data.prices[walletSelector.value] | number:'1.2-6'}} {{walletSelector.value | uppercase}}
</span>
</ng-container>
</mat-hint>
</mat-form-field>
<button
class="mt-4 mb-8"
mat-flat-button
[color]="'primary'">
SELL
</button>
</form>
</div>
</div>
</mat-drawer>
<!-- Content -->
<mat-drawer-content class="flex flex-col">
<!-- BTC Price -->
<div class="flex flex-col flex-auto min-h-full bg-card dark:bg-default">
<div class="flex flex-wrap items-center pl-4 pr-6 py-3 md:pl-6 border-b">
<button
class="mr-6 lg:hidden"
mat-icon-button
(click)="matDrawer.toggle()">
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
</button>
<div class="flex flex-col flex-auto my-3 mr-6">
<div class="flex items-center">
<div class="font-medium text-2xl text-secondary mr-2">Bitcoin</div>
<div class="font-medium text-lg text-hint tracking-wider">(BTC)</div>
</div>
<div class="flex items-end mt-1">
<div class="mr-2 font-mono text-3xl leading-none tracking-tight">{{data.btc.amount | currency:'USD':'symbol':'1.2-2'}}</div>
<mat-icon
class="text-green-500 icon-size-5 mr-0.5 mb-px"
[ngClass]="{'text-green-500': data.btc.trend.dir === 'up', 'text-red-500': data.btc.trend.dir === 'down'}"
[svgIcon]="data.btc.trend.dir === 'up' ? 'heroicons_solid:arrow-narrow-up' : 'heroicons_solid:arrow-narrow-down'"></mat-icon>
<div
class="font-mono font-medium text-lg leading-none mb-px"
[ngClass]="{'text-green-500': data.btc.trend.dir === 'up', 'text-red-500': data.btc.trend.dir === 'down'}">
{{data.btc.trend.amount}}%
</div>
</div>
</div>
<div class="hidden sm:flex items-center my-3">
<div class="p-4 leading-none rounded-l-xl border border-r-0">
<div class="text-sm font-medium text-secondary">Market Cap</div>
<div class="mt-2 font-mono text-xl">{{(data.btc.marketCap / 1000000000) | number: '1.0-2' | currency}}B</div>
</div>
<div class="p-4 leading-none border border-r-0">
<div class="text-sm font-medium text-secondary">Volume</div>
<div class="mt-2 font-mono text-xl">{{(data.btc.volume / 1000000000) | number: '1.0-2' | currency}}B</div>
</div>
<div class="p-4 leading-none border border-r-0">
<div class="text-sm font-medium text-secondary">Supply</div>
<div class="mt-2 font-mono text-xl">{{(data.btc.supply / 1000000) | number: '1.0-2'}}M</div>
</div>
<div class="p-4 leading-none rounded-r-xl border">
<div class="text-sm font-medium text-secondary">All Time High</div>
<div class="mt-2 font-mono text-xl">{{data.btc.allTimeHigh | currency:'USD'}}</div>
</div>
</div>
</div>
<div class="relative flex flex-auto bg-gray-50 dark:bg-transparent">
<apx-chart
class="relative w-full h-160 md:absolute md:inset-0 md:h-auto overflow-hidden"
[chart]="btcOptions.chart"
[colors]="btcOptions.colors"
[dataLabels]="btcOptions.dataLabels"
[grid]="btcOptions.grid"
[legend]="btcOptions.legend"
[series]="btcOptions.series"
[stroke]="btcOptions.stroke"
[tooltip]="btcOptions.tooltip"
[xaxis]="btcOptions.xaxis"
[yaxis]="btcOptions.yaxis"
#btcChartComponent></apx-chart>
</div>
</div>
</mat-drawer-content>
</mat-drawer-container>
</div>

View File

@@ -0,0 +1,238 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import * as moment from 'moment';
import { ApexOptions, ChartComponent } from 'ng-apexcharts';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { CryptoService } from 'app/modules/admin/dashboards/crypto/crypto.service';
@Component({
selector : 'crypto',
templateUrl : './crypto.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CryptoComponent implements OnInit, OnDestroy
{
@ViewChild('btcChartComponent') btcChartComponent: ChartComponent;
appConfig: any;
btcOptions: ApexOptions = {};
data: any;
drawerMode: 'over' | 'side' = 'side';
drawerOpened: boolean = true;
watchlistChartOptions: ApexOptions = {};
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _cryptoService: CryptoService,
private _changeDetectorRef: ChangeDetectorRef,
private _fuseMediaWatcherService: FuseMediaWatcherService
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(({matchingAliases}) => {
// Set the drawerMode and drawerOpened if 'lg' breakpoint is active
if ( matchingAliases.includes('lg') )
{
this.drawerMode = 'side';
this.drawerOpened = true;
}
else
{
this.drawerMode = 'over';
this.drawerOpened = false;
}
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Get the data
this._cryptoService.data$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((data) => {
// Store the data
this.data = data;
// Prepare the chart data
this._prepareChartData();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Prepare the chart data from the data
*
* @private
*/
private _prepareChartData(): void
{
// BTC
this.btcOptions = {
chart : {
animations: {
enabled: false
},
fontFamily: 'inherit',
foreColor : 'inherit',
width : '100%',
height : '100%',
type : 'line',
toolbar : {
show: false
},
zoom : {
enabled: false
}
},
colors : ['#5A67D8'],
dataLabels: {
enabled: false
},
grid : {
borderColor : 'var(--fuse-border)',
position : 'back',
show : true,
strokeDashArray: 6,
xaxis : {
lines: {
show: true
}
},
yaxis : {
lines: {
show: true
}
}
},
legend : {
show: false
},
series : this.data.btc.price.series,
stroke : {
width: 2,
curve: 'straight'
},
tooltip : {
shared: true,
theme : 'dark',
y : {
formatter: (value: number): string => '$' + value.toFixed(2)
}
},
xaxis : {
type : 'numeric',
crosshairs: {
show : true,
position: 'back',
fill : {
type : 'color',
color: 'var(--fuse-border)'
},
width : 3,
stroke : {
dashArray: 0,
width : 0
},
opacity : 0.9
},
tickAmount: 8,
axisTicks : {
show : true,
color: 'var(--fuse-border)'
},
axisBorder: {
show: false
},
tooltip : {
enabled: false
},
labels : {
show : true,
trim : false,
rotate : 0,
minHeight : 40,
hideOverlappingLabels: true,
formatter : (value): string => moment().subtract(Math.abs(parseInt(value, 10)), 'minutes').format('HH:mm'),
style : {
colors: 'currentColor'
}
}
},
yaxis : {
axisTicks : {
show : true,
color: 'var(--fuse-border)'
},
axisBorder : {
show: false
},
forceNiceScale: true,
labels : {
minWidth : 40,
formatter: (value: number): string => '$' + value.toFixed(0),
style : {
colors: 'currentColor'
}
}
}
};
// Watchlist options
this.watchlistChartOptions = {
chart : {
animations: {
enabled: false
},
width : '100%',
height : '100%',
type : 'line',
sparkline : {
enabled: true
}
},
colors : ['#A0AEC0'],
stroke : {
width: 2,
curve: 'smooth'
},
tooltip: {
enabled: false
},
xaxis : {
type: 'category'
}
};
}
}

View File

@@ -0,0 +1,42 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
import { NgApexchartsModule } from 'ng-apexcharts';
import { SharedModule } from 'app/shared/shared.module';
import { CryptoComponent } from 'app/modules/admin/dashboards/crypto/crypto.component';
import { cryptoRoutes } from 'app/modules/admin/dashboards/crypto/crypto.routing';
@NgModule({
declarations: [
CryptoComponent
],
imports : [
RouterModule.forChild(cryptoRoutes),
MatButtonModule,
MatButtonToggleModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatSelectModule,
MatSidenavModule,
MatSortModule,
MatTableModule,
MatTabsModule,
NgApexchartsModule,
SharedModule
]
})
export class CryptoModule
{
}

View File

@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { CryptoService } from 'app/modules/admin/dashboards/crypto/crypto.service';
@Injectable({
providedIn: 'root'
})
export class CryptoResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(private _cryptoService: CryptoService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any>
{
return this._cryptoService.getData();
}
}

View File

@@ -0,0 +1,13 @@
import { Route } from '@angular/router';
import { CryptoComponent } from 'app/modules/admin/dashboards/crypto/crypto.component';
import { CryptoResolver } from 'app/modules/admin/dashboards/crypto/crypto.resolvers';
export const cryptoRoutes: Route[] = [
{
path : '',
component: CryptoComponent,
resolve : {
data: CryptoResolver
}
}
];

View File

@@ -0,0 +1,47 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class CryptoService
{
private _data: BehaviorSubject<any> = new BehaviorSubject(null);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for data
*/
get data$(): Observable<any>
{
return this._data.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get data
*/
getData(): Observable<any>
{
return this._httpClient.get('api/dashboards/crypto').pipe(
tap((response: any) => {
this._data.next(response);
})
);
}
}

View File

@@ -0,0 +1,526 @@
<div class="flex flex-col flex-auto w-full">
<div class="flex flex-wrap w-full max-w-screen-xl mx-auto p-6 md:p-8">
<!-- Title and action buttons -->
<div class="flex items-center justify-between w-full">
<div>
<h2 class="text-3xl font-semibold tracking-tight leading-8">Finance dashboard</h2>
<div class="font-medium tracking-tight text-secondary">Keep track of your financial status</div>
</div>
<div class="flex items-center ml-6">
<button
class="hidden sm:inline-flex"
mat-stroked-button>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:document-report'"></mat-icon>
<span class="ml-2">Reports</span>
</button>
<button
class="hidden sm:inline-flex ml-3"
mat-stroked-button>
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:cog'"></mat-icon>
<span class="ml-2">Settings</span>
</button>
<button
class="hidden sm:inline-flex ml-3"
mat-flat-button
[color]="'primary'">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:save'"></mat-icon>
<span class="ml-2">Export</span>
</button>
<!-- Actions menu (visible on xs) -->
<div class="sm:hidden">
<button
[matMenuTriggerFor]="actionsMenu"
mat-icon-button>
<mat-icon [svgIcon]="'heroicons_outline:dots-vertical'"></mat-icon>
</button>
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item>Export</button>
<button mat-menu-item>Reports</button>
<button mat-menu-item>Settings</button>
</mat-menu>
</div>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-8 w-full mt-8">
<div class="grid gap-8 sm:grid-flow-col xl:grid-flow-row">
<!-- Previous statement -->
<div class="relative flex flex-col flex-auto p-6 pr-3 pb-3 bg-card rounded-2xl shadow overflow-hidden">
<div class="absolute bottom-0 right-0 w-24 h-24 -m-6">
<mat-icon
class="icon-size-24 opacity-25 text-green-500 dark:text-green-400"
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
</div>
<div class="flex items-center">
<div class="flex flex-col">
<div class="text-lg font-medium tracking-tight leading-6 truncate">Previous Statement</div>
<div class="text-green-600 font-medium text-sm">
Paid on {{data.previousStatement.date}}
</div>
</div>
<div class="ml-auto -mt-2">
<button
mat-icon-button
[matMenuTriggerFor]="previousStatementMenu">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:dots-vertical'"></mat-icon>
</button>
<mat-menu #previousStatementMenu="matMenu">
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:credit-card'"></mat-icon>
<span>View statement</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:cash'"></mat-icon>
<span>Spending breakdown</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:receipt-tax'"></mat-icon>
<span>Tax breakdown</span>
</span>
</button>
<mat-divider class="my-2"></mat-divider>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:printer'"></mat-icon>
<span>Print statement</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:mail'"></mat-icon>
<span>Email statement</span>
</span>
</button>
</mat-menu>
</div>
</div>
<div class="flex flex-row flex-wrap mt-4 -mx-6">
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Card Limit</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.previousStatement.limit | currency:'USD'}}</div>
</div>
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Spent</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.previousStatement.spent | currency:'USD'}}</div>
</div>
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Minimum</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.previousStatement.minimum | currency:'USD'}}</div>
</div>
</div>
</div>
<!-- Current statement -->
<div class="relative flex flex-col flex-auto p-6 pr-3 pb-3 bg-card rounded-2xl shadow overflow-hidden">
<div class="absolute bottom-0 right-0 w-24 h-24 -m-6">
<mat-icon
class="icon-size-24 opacity-25 text-red-500 dark:text-red-400"
[svgIcon]="'heroicons_outline:exclamation-circle'"></mat-icon>
</div>
<div class="flex items-center">
<div class="flex flex-col">
<div class="text-lg font-medium tracking-tight leading-6 truncate">Current Statement</div>
<div class="text-red-600 font-medium text-sm">
Must be paid before {{data.currentStatement.date}}
</div>
</div>
<div class="ml-auto -mt-2">
<button
mat-icon-button
[matMenuTriggerFor]="currentStatementMenu">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:dots-vertical'"></mat-icon>
</button>
<mat-menu #currentStatementMenu="matMenu">
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:credit-card'"></mat-icon>
<span>View statement</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:cash'"></mat-icon>
<span>Spending breakdown</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:receipt-tax'"></mat-icon>
<span>Tax breakdown</span>
</span>
</button>
<mat-divider class="my-2"></mat-divider>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:printer'"></mat-icon>
<span>Print statement</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:mail'"></mat-icon>
<span>Email statement</span>
</span>
</button>
</mat-menu>
</div>
</div>
<div class="flex flex-row flex-wrap mt-4 -mx-6">
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Card Limit</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.currentStatement.limit | currency:'USD'}}</div>
</div>
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Spent</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.currentStatement.spent | currency:'USD'}}</div>
</div>
<div class="flex flex-col mx-6 my-3">
<div class="text-sm font-medium leading-none text-secondary">Minimum</div>
<div class="mt-2 font-medium text-3xl leading-none">{{data.currentStatement.minimum | currency:'USD'}}</div>
</div>
</div>
</div>
</div>
<!-- Account balance -->
<div class="flex flex-col flex-auto bg-card shadow rounded-2xl overflow-hidden">
<div class="flex flex-col p-6 pb-4">
<div class="flex items-center justify-between">
<div class="flex flex-col">
<div class="mr-4 text-lg font-medium tracking-tight leading-6 truncate">Account Balance</div>
<div class="text-secondary font-medium">Monthly balance growth and avg. monthly income</div>
</div>
<div class="ml-2">
<button
class="h-6 min-h-6 px-2 rounded-full bg-hover"
mat-button
[matMenuTriggerFor]="accountBalanceMenu">
<span class="font-medium text-sm text-secondary">12 months</span>
</button>
<mat-menu #accountBalanceMenu="matMenu">
<button mat-menu-item>3 months</button>
<button mat-menu-item>6 months</button>
<button mat-menu-item>9 months</button>
<button mat-menu-item>12 months</button>
</mat-menu>
</div>
</div>
<div class="flex items-start mt-6 mr-2">
<div class="flex flex-col">
<div class="font-semibold text-3xl md:text-5xl tracking-tighter">{{data.accountBalance.growRate}}%</div>
<div class="font-medium text-sm text-secondary leading-none">Average Monthly Growth</div>
</div>
<div class="flex flex-col ml-8 md:ml-16">
<div class="font-semibold text-3xl md:text-5xl tracking-tighter">{{data.accountBalance.ami | currency:'USD'}}</div>
<div class="font-medium text-sm text-secondary leading-none">Average Monthly Income</div>
</div>
</div>
</div>
<div class="flex flex-col flex-auto">
<apx-chart
class="flex-auto w-full h-full"
[chart]="accountBalanceOptions.chart"
[colors]="accountBalanceOptions.colors"
[fill]="accountBalanceOptions.fill"
[series]="accountBalanceOptions.series"
[stroke]="accountBalanceOptions.stroke"
[tooltip]="accountBalanceOptions.tooltip"
[xaxis]="accountBalanceOptions.xaxis"></apx-chart>
</div>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-3 gap-8 w-full mt-8">
<!-- Recent transactions table -->
<div class="xl:col-span-2 flex flex-col flex-auto bg-card shadow rounded-2xl overflow-hidden">
<div class="p-6">
<div class="mr-4 text-lg font-medium tracking-tight leading-6 truncate">Recent transactions</div>
<div class="text-secondary font-medium">1 pending, 4 completed</div>
</div>
<div class="overflow-x-auto mx-6">
<table
class="w-full bg-transparent"
mat-table
matSort
[dataSource]="recentTransactionsDataSource"
[trackBy]="trackByFn"
#recentTransactionsTable>
<!-- Transaction ID -->
<ng-container matColumnDef="transactionId">
<th
mat-header-cell
mat-sort-header
*matHeaderCellDef>
Transaction ID
</th>
<td
mat-cell
*matCellDef="let transaction">
<span class="pr-6 font-medium text-sm text-secondary whitespace-nowrap">
{{transaction.transactionId}}
</span>
</td>
</ng-container>
<!-- Date -->
<ng-container matColumnDef="date">
<th
mat-header-cell
mat-sort-header
*matHeaderCellDef>
Date
</th>
<td
mat-cell
*matCellDef="let transaction">
<span class="pr-6 whitespace-nowrap">
{{transaction.date | date:'MMM dd, y'}}
</span>
</td>
</ng-container>
<!-- Name -->
<ng-container matColumnDef="name">
<th
mat-header-cell
mat-sort-header
*matHeaderCellDef>
Name
</th>
<td
mat-cell
*matCellDef="let transaction">
<span class="pr-6 whitespace-nowrap">
{{transaction.name}}
</span>
</td>
</ng-container>
<!-- Amount -->
<ng-container matColumnDef="amount">
<th
mat-header-cell
mat-sort-header
*matHeaderCellDef>
Amount
</th>
<td
mat-cell
*matCellDef="let transaction">
<span class="pr-6 font-medium whitespace-nowrap">
{{transaction.amount | currency:'USD'}}
</span>
</td>
</ng-container>
<!-- Status -->
<ng-container matColumnDef="status">
<th
mat-header-cell
mat-sort-header
*matHeaderCellDef>
Status
</th>
<td
mat-cell
*matCellDef="let transaction">
<span
class="inline-flex items-center font-bold text-xs px-2.5 py-0.5 rounded-full tracking-wide uppercase"
[ngClass]="{'bg-red-200 text-red-800 dark:bg-red-600 dark:text-red-50': transaction.status === 'pending',
'bg-green-200 text-green-800 dark:bg-green-600 dark:text-green-50': transaction.status === 'completed'}">
<span class="leading-relaxed whitespace-nowrap">{{transaction.status}}</span>
</span>
</td>
</ng-container>
<!-- Footer -->
<ng-container matColumnDef="recentOrdersTableFooter">
<td
class="py-6 px-0 border-0"
mat-footer-cell
*matFooterCellDef
colspan="6">
<button mat-stroked-button>See all transactions</button>
</td>
</ng-container>
<tr
mat-header-row
*matHeaderRowDef="recentTransactionsTableColumns"></tr>
<tr
class="order-row h-16"
mat-row
*matRowDef="let row; columns: recentTransactionsTableColumns;"></tr>
<tr
class="h-16 border-0"
mat-footer-row
*matFooterRowDef="['recentOrdersTableFooter']"></tr>
</table>
</div>
</div>
<!-- Budget -->
<div class="flex flex-col flex-auto p-6 bg-card rounded-2xl shadow">
<div class="flex items-center">
<div class="flex flex-col">
<div class="mr-4 text-lg font-medium tracking-tight leading-6 truncate">Budget</div>
<div class="text-secondary font-medium">Monthly budget summary</div>
</div>
<div class="ml-auto -mt-2 -mr-2">
<button
mat-icon-button
[matMenuTriggerFor]="budgetMenu">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:dots-vertical'"></mat-icon>
</button>
<mat-menu #budgetMenu="matMenu">
<button mat-menu-item>Expenses breakdown</button>
<button mat-menu-item>Savings breakdown</button>
<button mat-menu-item>Bills breakdown</button>
<mat-divider class="my-2"></mat-divider>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:printer'"></mat-icon>
<span>Print budget summary</span>
</span>
</button>
<button mat-menu-item>
<span class="flex items-center">
<mat-icon
class="icon-size-5 mr-3"
[svgIcon]="'heroicons_solid:mail'"></mat-icon>
<span>Email budget summary</span>
</span>
</button>
</mat-menu>
</div>
</div>
<div class="mt-6">
Last month; you had <strong>223</strong> expense transactions, <strong>12</strong> savings entries and <strong>4</strong> bills.
</div>
<div class="my-8 space-y-8">
<div class="flex flex-col">
<div class="flex items-center">
<div class="flex items-center justify-center w-14 h-14 rounded bg-red-100 text-red-800 dark:bg-red-600 dark:text-red-50">
<mat-icon
class="text-current"
[svgIcon]="'heroicons_outline:credit-card'"></mat-icon>
</div>
<div class="flex-auto ml-4 leading-none">
<div class="text-sm font-medium text-secondary">Expenses</div>
<div class="mt-2 font-medium text-2xl">{{data.budget.expenses | currency:'USD'}}</div>
<mat-progress-bar
class="mt-3 rounded-full"
[color]="'warn'"
[mode]="'determinate'"
[value]="(data.budget.expenses * 100) / data.budget.expensesLimit"></mat-progress-bar>
</div>
<div class="flex items-end justify-end min-w-18 mt-auto ml-6">
<div class="text-lg leading-none">2.6%</div>
<mat-icon
class="text-green-600 icon-size-4 ml-1"
[svgIcon]="'heroicons_solid:arrow-narrow-down'"></mat-icon>
</div>
</div>
</div>
<div class="flex flex-col">
<div class="flex items-center">
<div class="flex items-center justify-center w-14 h-14 rounded bg-indigo-100 text-indigo-800 dark:bg-indigo-600 dark:text-indigo-50">
<mat-icon
class="text-current"
[svgIcon]="'heroicons_outline:cash'"></mat-icon>
</div>
<div class="flex-auto ml-4 leading-none">
<div class="text-sm font-medium text-secondary">Savings</div>
<div class="mt-2 font-medium text-2xl">{{data.budget.savings | currency:'USD'}}</div>
<mat-progress-bar
class="mt-3 rounded-full"
[mode]="'determinate'"
[value]="(data.budget.savings * 100) / data.budget.savingsGoal"></mat-progress-bar>
</div>
<div class="flex items-end justify-end min-w-18 mt-auto ml-6">
<div class="text-lg leading-none">12.7%</div>
<mat-icon
class="text-red-600 icon-size-4 ml-1"
[svgIcon]="'heroicons_solid:arrow-narrow-up'"></mat-icon>
</div>
</div>
</div>
<div class="flex flex-col">
<div class="flex items-center">
<div class="flex items-center justify-center w-14 h-14 rounded bg-teal-100 text-teal-800 dark:bg-teal-600 dark:text-teal-50">
<mat-icon
class="text-current"
[svgIcon]="'heroicons_outline:light-bulb'"></mat-icon>
</div>
<div class="flex-auto ml-4 leading-none">
<div class="text-sm font-medium text-secondary">Bills</div>
<div class="mt-2 font-medium text-2xl">{{data.budget.bills | currency:'USD'}}</div>
<mat-progress-bar
class="mt-3 rounded-full"
[mode]="'determinate'"
[value]="(data.budget.bills * 100) / data.budget.billsLimit"></mat-progress-bar>
</div>
<div class="flex items-end justify-end min-w-18 mt-auto ml-6">
<div class="text-lg leading-none">105.7%</div>
<mat-icon
class="text-red-600 icon-size-4 ml-1"
[svgIcon]="'heroicons_solid:arrow-narrow-up'"></mat-icon>
</div>
</div>
<div class="mt-3 text-md text-secondary">Exceeded your personal limit! Be careful next month.</div>
</div>
</div>
<div class="flex items-center mt-auto">
<button
class="mt-2"
mat-stroked-button>
Download Summary
</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,146 @@
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ApexOptions } from 'ng-apexcharts';
import { FinanceService } from 'app/modules/admin/dashboards/finance/finance.service';
@Component({
selector : 'finance',
templateUrl : './finance.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FinanceComponent implements OnInit, AfterViewInit, OnDestroy
{
@ViewChild('recentTransactionsTable', {read: MatSort}) recentTransactionsTableMatSort: MatSort;
data: any;
accountBalanceOptions: ApexOptions;
recentTransactionsDataSource: MatTableDataSource<any> = new MatTableDataSource();
recentTransactionsTableColumns: string[] = ['transactionId', 'date', 'name', 'amount', 'status'];
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(private _financeService: FinanceService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the data
this._financeService.data$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((data) => {
// Store the data
this.data = data;
// Store the table data
this.recentTransactionsDataSource.data = data.recentTransactions;
// Prepare the chart data
this._prepareChartData();
});
}
/**
* After view init
*/
ngAfterViewInit(): void
{
// Make the data source sortable
this.recentTransactionsDataSource.sort = this.recentTransactionsTableMatSort;
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Prepare the chart data from the data
*
* @private
*/
private _prepareChartData(): void
{
// Account balance
this.accountBalanceOptions = {
chart : {
animations: {
speed : 400,
animateGradually: {
enabled: false
}
},
fontFamily: 'inherit',
foreColor : 'inherit',
width : '100%',
height : '100%',
type : 'area',
sparkline : {
enabled: true
}
},
colors : ['#A3BFFA', '#667EEA'],
fill : {
colors : ['#CED9FB', '#AECDFD'],
opacity: 0.5,
type : 'solid'
},
series : this.data.accountBalance.series,
stroke : {
curve: 'straight',
width: 2
},
tooltip: {
followCursor: true,
theme : 'dark',
x : {
format: 'MMM dd, yyyy'
},
y : {
formatter: (value): string => value + '%'
}
},
xaxis : {
type: 'datetime'
}
};
}
}

View File

@@ -0,0 +1,34 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { NgApexchartsModule } from 'ng-apexcharts';
import { SharedModule } from 'app/shared/shared.module';
import { FinanceComponent } from 'app/modules/admin/dashboards/finance/finance.component';
import { financeRoutes } from 'app/modules/admin/dashboards/finance/finance.routing';
@NgModule({
declarations: [
FinanceComponent
],
imports : [
RouterModule.forChild(financeRoutes),
MatButtonModule,
MatDividerModule,
MatIconModule,
MatMenuModule,
MatProgressBarModule,
MatSortModule,
MatTableModule,
NgApexchartsModule,
SharedModule
]
})
export class FinanceModule
{
}

View File

@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { FinanceService } from 'app/modules/admin/dashboards/finance/finance.service';
@Injectable({
providedIn: 'root'
})
export class FinanceResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(private _financeService: FinanceService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any>
{
return this._financeService.getData();
}
}

View File

@@ -0,0 +1,13 @@
import { Route } from '@angular/router';
import { FinanceComponent } from 'app/modules/admin/dashboards/finance/finance.component';
import { FinanceResolver } from 'app/modules/admin/dashboards/finance/finance.resolvers';
export const financeRoutes: Route[] = [
{
path : '',
component: FinanceComponent,
resolve : {
data: FinanceResolver
}
}
];

View File

@@ -0,0 +1,47 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class FinanceService
{
private _data: BehaviorSubject<any> = new BehaviorSubject(null);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for data
*/
get data$(): Observable<any>
{
return this._data.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get data
*/
getData(): Observable<any>
{
return this._httpClient.get('api/dashboards/finance').pipe(
tap((response: any) => {
this._data.next(response);
})
);
}
}

View File

@@ -1,7 +1,7 @@
<div class="flex flex-col flex-auto min-w-0">
<!-- Header -->
<div class="dark bg-card dark:border-b">
<div class="bg-card">
<div class="flex flex-col w-full max-w-screen-xl mx-auto px-6 sm:px-8">
<div class="flex flex-col sm:flex-row flex-auto sm:items-center min-w-0 my-8 sm:my-12">
<!-- Avatar and name -->
@@ -26,7 +26,7 @@
<!-- Actions -->
<div class="flex items-center mt-6 sm:mt-0 sm:ml-2 space-x-3">
<button
class="fuse-mat-button-rounded bg-accent-600"
class="fuse-mat-button-rounded bg-accent-700"
mat-flat-button
[color]="'accent'">
<mat-icon
@@ -46,43 +46,47 @@
</div>
</div>
<!-- Project selector -->
<div class="flex items-center">
<div class="px-4 py-2 rounded-tl-xl overflow-hidden bg-hover">
<div class="sm:text-lg leading-6 truncate">{{selectedProject}}</div>
<div
class="relative flex self-start pt-2 pb-1 pl-5 pr-4 cursor-pointer overflow-hidden rounded-t-xl border border-b-0 bg-default"
matRipple
[matMenuTriggerFor]="projectsMenu">
<div class="flex items-center">
<div class="overflow-hidden">
<div class="font-medium leading-6 truncate">{{selectedProject}}</div>
</div>
<div class="flex items-center justify-center pl-2">
<mat-icon
class="icon-size-5"
[svgIcon]="'heroicons_solid:chevron-down'"></mat-icon>
</div>
</div>
<div class="ml-px rounded-tr-xl bg-hover">
<mat-menu
#projectsMenu="matMenu"
[xPosition]="'before'">
<button
[matMenuTriggerFor]="projectsMenu"
mat-icon-button>
<mat-icon [svgIcon]="'heroicons_outline:dots-horizontal'"></mat-icon>
mat-menu-item
(click)="selectedProject='ACME Corp. Backend App'">ACME Corp. Backend App
</button>
<mat-menu #projectsMenu="matMenu">
<button
mat-menu-item
(click)="selectedProject='ACME Corp. Backend App'">ACME Corp. Backend App
</button>
<button
mat-menu-item
(click)="selectedProject='ACME Corp. Frontend App'">ACME Corp. Frontend App
</button>
<button
mat-menu-item
(click)="selectedProject='Creapond'">Creapond
</button>
<button
mat-menu-item
(click)="selectedProject='Withinpixels'">Withinpixels
</button>
</mat-menu>
</div>
<button
mat-menu-item
(click)="selectedProject='ACME Corp. Frontend App'">ACME Corp. Frontend App
</button>
<button
mat-menu-item
(click)="selectedProject='Creapond'">Creapond
</button>
<button
mat-menu-item
(click)="selectedProject='Withinpixels'">Withinpixels
</button>
</mat-menu>
</div>
</div>
</div>
<!-- Main -->
<div class="flex-auto mt-4 sm:mt-6">
<div class="flex-auto border-t -mt-px pt-4 sm:pt-6">
<div class="w-full max-w-screen-xl mx-auto">
<!-- Tabs -->
<mat-tab-group
class="sm:px-2"
@@ -114,7 +118,7 @@
<div class="flex flex-col items-center mt-2">
<div class="text-7xl sm:text-8xl font-bold tracking-tight leading-none text-blue-500">21</div>
<div class="text-lg font-medium text-blue-600 dark:text-blue-500">Due Tasks</div>
<div class="flex items-center justify-center w-full mt-5 text-secondary">
<div class="flex items-baseline justify-center w-full mt-5 text-secondary">
<div class="text-md font-medium truncate">Completed:</div>
<div class="ml-1.5 text-lg font-semibold">13</div>
</div>
@@ -142,7 +146,7 @@
<div class="flex flex-col items-center mt-2">
<div class="text-7xl sm:text-8xl font-bold tracking-tight leading-none text-red-500">17</div>
<div class="text-lg font-medium text-red-600 dark:text-red-500">Tasks</div>
<div class="flex items-center justify-center w-full mt-5 text-secondary">
<div class="flex items-baseline justify-center w-full mt-5 text-secondary">
<div class="text-md font-medium truncate">From yesterday:</div>
<div class="ml-1.5 text-lg font-semibold">9</div>
</div>
@@ -170,7 +174,7 @@
<div class="flex flex-col items-center mt-2">
<div class="text-7xl sm:text-8xl font-bold tracking-tight leading-none text-amber-500">24</div>
<div class="text-lg font-medium text-amber-600 dark:text-amber-500">Open</div>
<div class="flex items-center justify-center w-full mt-5 text-secondary">
<div class="flex items-baseline justify-center w-full mt-5 text-secondary">
<div class="text-md font-medium truncate">Closed today:</div>
<div class="ml-1.5 text-lg font-semibold">19</div>
</div>
@@ -198,7 +202,7 @@
<div class="flex flex-col items-center mt-2">
<div class="text-7xl sm:text-8xl font-bold tracking-tight leading-none text-green-500">38</div>
<div class="text-lg font-medium text-green-600 dark:text-green-500">Proposals</div>
<div class="flex items-center justify-center w-full mt-5 text-secondary">
<div class="flex items-baseline justify-center w-full mt-5 text-secondary">
<div class="text-md font-medium truncate">Implemented:</div>
<div class="ml-1.5 text-lg font-semibold">16</div>
</div>
@@ -680,7 +684,6 @@
mat-row
*matRowDef="let row; columns: data.budgetDetails.columns;"></tr>
</table>
</div>
</div>
</div>
@@ -729,7 +732,6 @@
</mat-tab>
</mat-tab-group>
</div>
</div>

View File

@@ -6,6 +6,7 @@ import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatRippleModule } from '@angular/material/core';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
@@ -28,6 +29,7 @@ import { projectRoutes } from 'app/modules/admin/dashboards/project/project.rout
MatIconModule,
MatMenuModule,
MatProgressBarModule,
MatRippleModule,
MatSidenavModule,
MatSortModule,
MatTableModule,

View File

@@ -4,13 +4,159 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector : 'changelog',
templateUrl : './changelog.html',
styles : [''],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChangelogComponent
{
changelog: any[] = [
// v13.5.0
{
version : 'v13.5.0',
releaseDate: 'Aug 13, 2021',
changes : [
{
type: 'Changed',
list: [
'Huge performance improvement due to Angular v12.2.0',
'(dependencies) Updated Angular & Angular Material to v12.2.1',
'(dependencies) Updated various other packages',
'(tailwindcss) Removed old jsdoc from the config file',
'(@fuse/theming) Better structuring on the themes.scss file',
'(@fuse) Disabled Angular Material "theme" sanity check since we use "all-component-themes" without a color map',
'(apps/mailbox) Style improvements',
'Removed empty "styles" from component decorators',
'Decreased budget sizes since new Fuse is a lot smaller compared to the one with the old design'
]
},
{
type: 'Fixed',
list: [
'(@fuse/overrides) Quill editor is not styled correctly by default',
'(@fuse/confirmation) Dialog size cannot be updated using dialogRef\'s "updateSize" method',
'(apps/mailbox) Compose dialog doesn\'t work correctly on small height resolutions',
'(ui/page-layouts) Demo layout navigation appearance is not correct'
]
}
]
},
// v13.4.0
{
version : 'v13.4.0',
releaseDate: 'July 29, 2021',
changes : [
{
type: 'Added',
list: [
'(dashboards/finance) Added finance dashboard',
'(dashboards/crypto) Added crypto dashboard'
]
},
{
type: 'Changed',
list: [
'(dependencies) Updated Angular & Angular Material to v12.1.4',
'(dependencies) Updated various other packages',
'(index) Updated the title, description and keywords',
'(dashboards/project) Light header on light themes and small adjustments in various places',
'(apps/contacts) Small adjustments for better consistency',
'(apps/ecommerce/inventory) Small adjustments for better consistency',
'(docs) Updated the multi language guide'
]
}
]
},
// v13.3.1
{
version : 'v13.3.1',
releaseDate: 'July 17, 2021',
changes : [
{
type: 'Fixed',
list: [
'(fuse/confirmation) Confirmation dialog colors are not optimized for the Dark mode'
]
}
]
},
// v13.3.0
{
version : 'v13.3.0',
releaseDate: 'July 16, 2021',
changes : [
{
type: 'Added',
list: [
'(fuse/confirmation) A service to quickly configure and show confirmation dialogs'
]
},
{
type: 'Changed',
list: [
'(dependencies) Updated Angular & Angular Material to v12.1.2',
'(dependencies) Updated various other packages',
'(dashboards/analytics) Removed unused chart options declarations',
'(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',
'(ui/confirmation-dialog) Created a separate page for FuseConfirmationService and put the example configurator in there for better visibility',
'(docs) Moved Fuse Components and Other Components into UI for better visibility and better categorization'
]
},
{
type: 'Fixed',
list: [
'(transloco) Undefined fallback language causes issues in some cases',
'(tailwindcss) Ordered lists with "s" modifier causes builder to throw errors'
]
}
]
},
// v13.2.0
{
version : 'v13.2.0',
releaseDate: 'July 01, 2021',
changes : [
{
type: 'Added',
list: [
'(fuse/navigation) "tooltip" property to show tooltips on navigation items using MatTooltip'
]
},
{
type: 'Changed',
list: [
'(dependencies) Updated Angular & Angular Material to v12.1.1',
'(dependencies) Updated various other packages',
'(dev-dependencies) Removed "@angular/language-service" as IDEs and Code editors include them either natively or through plugins',
'(Angular Material) Apply rounded styles by default',
'(fuse/navigation) Moved *ngIf directives into their own "ng-container" containers',
'(layouts) Hide the "fuse-fullscreen" button on smaller devices since they don\'t support fullscreen',
'(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',
'(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.',
'(docs) Updated docs',
'(package.json) Added "description" and "author" fields'
]
},
{
type: 'Fixed',
list: [
'(fuse/drawer) Memory leak due to the animation player, thanks to Vadym Pidoplichko for coming up the issue and the solution.',
'(fuse/navigation) Vertical navigation blocks scroll if it\'s destroyed while in "over" mode and opened',
'(layouts) Header buttons are not fitting on certain layouts',
'(layout/settings-drawer) Issues on small screen devices',
'(apps/ecommerce/inventory) Tags selector border colors are not correct on dark mode',
'(apps/help-center) Small dark mode issues',
'(transloco) Language files cannot be loaded if using a base href other than "/"',
'(tailwindcss) Dark mode classes are not being purged correctly due to the wrong safelist entry'
]
}
]
},
// v13.1.0
{
version : 'v13.1.0',

View File

@@ -1,76 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTabsModule } from '@angular/material/tabs';
import { MatTreeModule } from '@angular/material/tree';
import { FuseCardModule } from '@fuse/components/card';
import { FuseDateRangeModule } from '@fuse/components/date-range';
import { FuseDrawerModule } from '@fuse/components/drawer';
import { FuseHighlightModule } from '@fuse/components/highlight';
import { FuseAlertModule } from '@fuse/components/alert';
import { FuseMasonryModule } from '@fuse/components/masonry/masonry.module';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { FuseScrollResetModule } from '@fuse/directives/scroll-reset';
import { SharedModule } from 'app/shared/shared.module';
import { CoreFeaturesComponent } from 'app/modules/admin/docs/core-features/core-features.component';
import { MockApiComponent } from 'app/modules/admin/docs/core-features/libraries/mock-api/mock-api.component';
import { AlertComponent } from 'app/modules/admin/docs/core-features/components/alert/alert.component';
import { CardComponent } from 'app/modules/admin/docs/core-features/components/card/card.component';
import { DateRangeComponent } from 'app/modules/admin/docs/core-features/components/date-range/date-range.component';
import { DrawerComponent } from 'app/modules/admin/docs/core-features/components/drawer/drawer.component';
import { FullscreenComponent } from 'app/modules/admin/docs/core-features/components/fullscreen/fullscreen.component';
import { HighlightComponent } from 'app/modules/admin/docs/core-features/components/highlight/highlight.component';
import { NavigationComponent } from 'app/modules/admin/docs/core-features/components/navigation/navigation.component';
import { MasonryComponent } from 'app/modules/admin/docs/core-features/components/masonry/masonry.component';
import { ScrollbarComponent } from 'app/modules/admin/docs/core-features/directives/scrollbar/scrollbar.component';
import { ScrollResetComponent } from 'app/modules/admin/docs/core-features/directives/scroll-reset/scroll-reset.component';
import { ConfigComponent } from 'app/modules/admin/docs/core-features/services/config/config.component';
import { MediaWatcherComponent } from 'app/modules/admin/docs/core-features/services/media-watcher/media-watcher.component';
import { SplashScreenComponent } from 'app/modules/admin/docs/core-features/services/splash-screen/splash-screen.component';
import { FindByKeyComponent } from 'app/modules/admin/docs/core-features/pipes/find-by-key/find-by-key.component';
import { MustMatchComponent } from 'app/modules/admin/docs/core-features/validators/must-match/must-match.component';
import { coreFeaturesRoutes } from 'app/modules/admin/docs/core-features/core-features.routing';
@NgModule({
declarations: [
CoreFeaturesComponent,
MockApiComponent,
AlertComponent,
CardComponent,
DateRangeComponent,
DrawerComponent,
FullscreenComponent,
HighlightComponent,
MasonryComponent,
NavigationComponent,
ScrollbarComponent,
ScrollResetComponent,
ConfigComponent,
SplashScreenComponent,
MediaWatcherComponent,
FindByKeyComponent,
MustMatchComponent
],
imports : [
RouterModule.forChild(coreFeaturesRoutes),
MatButtonModule,
MatIconModule,
MatSidenavModule,
MatTabsModule,
MatTreeModule,
FuseAlertModule,
FuseCardModule,
FuseDateRangeModule,
FuseDrawerModule,
FuseHighlightModule,
FuseMasonryModule,
FuseNavigationModule,
FuseScrollResetModule,
SharedModule
]
})
export class CoreFeaturesModule
{
}

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'jwt',
templateUrl: './jwt.html',
styles : ['']
templateUrl: './jwt.html'
})
export class JwtComponent
{

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'component-theming',
templateUrl: './component-theming.html',
styles : ['']
templateUrl: './component-theming.html'
})
export class ComponentThemingComponent
{

View File

@@ -65,7 +65,7 @@
<ol>
<li>Navigate to <code>src/app/core/core.module.ts</code> file and remove imports of <code>TranslocoCoreModule</code></li>
<li>Remove the <code>src/app/core/transloco</code> directory</li>
<li>Do a project wide search for <code>&lt;language&gt;&lt;/language&gt;</code> and remove all instances</li>
<li>Do a project wide search for <code>&lt;languages&gt;&lt;/languages&gt;</code> and remove all instances</li>
<li>Do a project wide search for <code>LanguageModule</code> and remove all imports</li>
<li>Remove the <code>src/app/layout/common/language</code> directory</li>
<li>Finally navigate to the <code>package.json</code> file, remove the <strong>"@ngneat/transloco"</strong> from dependencies list and run <code>npm install</code> command</li>

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'multi-language',
templateUrl: './multi-language.html',
styles : ['']
templateUrl: './multi-language.html'
})
export class MultiLanguageCustomizationComponent
{

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'page-layouts',
templateUrl: './page-layouts.html',
styles : ['']
templateUrl: './page-layouts.html'
})
export class PageLayoutsComponent
{

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'splash-screen',
templateUrl: './splash-screen.html',
styles : ['']
templateUrl: './splash-screen.html'
})
export class SplashScreenCustomizationComponent
{

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'tailwindcss',
templateUrl: './tailwindcss.html',
styles : ['']
templateUrl: './tailwindcss.html'
})
export class TailwindCSSComponent
{

View File

@@ -51,8 +51,8 @@
[appearance]="'border'"
[type]="'info'">
More detailed information about <code>FuseConfigService</code> can be found in the
<a [routerLink]="['../../../core-features/services/config']">Core features > Services >
Config
<a [routerLink]="['/ui/fuse-components/services/config']">
Fuse Components > Services > Config
</a>
section of this documentation.
</fuse-alert>

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'theme-layouts',
templateUrl: './theme-layouts.html',
styles : ['']
templateUrl: './theme-layouts.html'
})
export class ThemeLayoutsComponent
{

View File

@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
@Component({
selector : 'theming',
templateUrl: './theming.html',
styles : ['']
templateUrl: './theming.html'
})
export class ThemingComponent
{

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