mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2026-01-14 07:57:10 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
206ef711a4 | ||
|
|
7e0cc1249e | ||
|
|
138a43da59 | ||
|
|
fe7e2514a6 | ||
|
|
b8f0d9f0b2 | ||
|
|
2a4a392153 | ||
|
|
c2fa88f4d4 | ||
|
|
67d25012ec | ||
|
|
6de6a07778 | ||
|
|
e7ab0ea13f | ||
|
|
4b686d86cc | ||
|
|
190395f14b | ||
|
|
4a9b8ee91e | ||
|
|
488fe8a1eb | ||
|
|
db9a2a2433 | ||
|
|
3dda8479cf | ||
|
|
7c402670a1 | ||
|
|
f6bf0fb5d3 | ||
|
|
d44c004d01 | ||
|
|
4ec40271c5 | ||
|
|
b21cdf1655 | ||
|
|
6fff259fe3 | ||
|
|
8fcb0aea03 | ||
|
|
2c90770d9b | ||
|
|
1581ea74cc | ||
|
|
569809aabb | ||
|
|
dde9333120 | ||
|
|
10ec1790ca | ||
|
|
a2ff55d4c1 | ||
|
|
966e2db743 | ||
|
|
49cccde93b | ||
|
|
952b64297b | ||
|
|
9b3ff6a724 | ||
|
|
961b86c8cb | ||
|
|
8b977c0eeb | ||
|
|
35e56cd6af | ||
|
|
c04550b887 | ||
|
|
747b4f44c8 | ||
|
|
c4914c80b3 | ||
|
|
178d09597b | ||
|
|
d206c55e6e | ||
|
|
9abe887df1 | ||
|
|
b87fdc407c | ||
|
|
58440b63a7 | ||
|
|
63f6edee9a | ||
|
|
ca8e422b21 | ||
|
|
cc703081ca | ||
|
|
038c74df50 | ||
|
|
9abbf5fec2 | ||
|
|
0ebc16ec05 |
@@ -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
|
||||
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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'},
|
||||
|
||||
2550
package-lock.json
generated
2550
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fuse/demo",
|
||||
"version": "13.2.0",
|
||||
"version": "13.6.0",
|
||||
"description": "Fuse - Angular Admin Template and Starter Project",
|
||||
"author": "https://themeforest.net/user/srcn",
|
||||
"license": "https://themeforest.net/licenses/standard",
|
||||
@@ -9,22 +9,22 @@
|
||||
"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.1.1",
|
||||
"@angular/cdk": "12.1.1",
|
||||
"@angular/common": "12.1.1",
|
||||
"@angular/compiler": "12.1.1",
|
||||
"@angular/core": "12.1.1",
|
||||
"@angular/forms": "12.1.1",
|
||||
"@angular/material": "12.1.1",
|
||||
"@angular/material-moment-adapter": "12.1.1",
|
||||
"@angular/platform-browser": "12.1.1",
|
||||
"@angular/platform-browser-dynamic": "12.1.1",
|
||||
"@angular/router": "12.1.1",
|
||||
"@angular/animations": "12.2.3",
|
||||
"@angular/cdk": "12.2.3",
|
||||
"@angular/common": "12.2.3",
|
||||
"@angular/compiler": "12.2.3",
|
||||
"@angular/core": "12.2.3",
|
||||
"@angular/forms": "12.2.3",
|
||||
"@angular/material": "12.2.3",
|
||||
"@angular/material-moment-adapter": "12.2.3",
|
||||
"@angular/platform-browser": "12.2.3",
|
||||
"@angular/platform-browser-dynamic": "12.2.3",
|
||||
"@angular/router": "12.2.3",
|
||||
"@fullcalendar/angular": "4.4.5-beta",
|
||||
"@fullcalendar/core": "4.4.2",
|
||||
"@fullcalendar/daygrid": "4.4.2",
|
||||
@@ -33,59 +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.28.1",
|
||||
"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.1.1",
|
||||
"perfect-scrollbar": "1.5.1",
|
||||
"ngx-quill": "14.3.0",
|
||||
"perfect-scrollbar": "1.5.2",
|
||||
"quill": "1.3.7",
|
||||
"rrule": "2.6.8",
|
||||
"rxjs": "6.6.7",
|
||||
"tslib": "2.3.0",
|
||||
"tslib": "2.3.1",
|
||||
"web-animations-js": "2.3.2",
|
||||
"zone.js": "0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "12.1.0",
|
||||
"@angular-eslint/builder": "12.2.0",
|
||||
"@angular-eslint/eslint-plugin": "12.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "12.2.0",
|
||||
"@angular-eslint/schematics": "12.2.0",
|
||||
"@angular-eslint/template-parser": "12.2.0",
|
||||
"@angular/cli": "12.1.0",
|
||||
"@angular/compiler-cli": "12.1.1",
|
||||
"@angular-devkit/build-angular": "12.2.3",
|
||||
"@angular-eslint/builder": "12.3.1",
|
||||
"@angular-eslint/eslint-plugin": "12.3.1",
|
||||
"@angular-eslint/eslint-plugin-template": "12.3.1",
|
||||
"@angular-eslint/schematics": "12.3.1",
|
||||
"@angular-eslint/template-parser": "12.3.1",
|
||||
"@angular/cli": "12.2.3",
|
||||
"@angular/compiler-cli": "12.2.3",
|
||||
"@tailwindcss/aspect-ratio": "0.2.1",
|
||||
"@tailwindcss/line-clamp": "0.2.1",
|
||||
"@tailwindcss/typography": "0.4.1",
|
||||
"@types/chroma-js": "2.1.3",
|
||||
"@types/crypto-js": "3.1.47",
|
||||
"@types/highlight.js": "10.1.0",
|
||||
"@types/jasmine": "3.6.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.28.1",
|
||||
"@typescript-eslint/parser": "4.28.1",
|
||||
"autoprefixer": "10.2.6",
|
||||
"@types/node": "12.20.21",
|
||||
"@typescript-eslint/eslint-plugin": "4.30.0",
|
||||
"@typescript-eslint/parser": "4.30.0",
|
||||
"autoprefixer": "10.3.3",
|
||||
"chroma-js": "2.1.2",
|
||||
"eslint": "7.29.0",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-jsdoc": "35.4.1",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"eslint-plugin-jsdoc": "36.0.8",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"jasmine-core": "3.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.5",
|
||||
"tailwindcss": "2.2.4",
|
||||
"postcss": "8.3.6",
|
||||
"tailwindcss": "2.2.9",
|
||||
"typescript": "4.3.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ fuse-drawer {
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 299;
|
||||
opacity: 0;
|
||||
opacity: 1;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
|
||||
/* Fixed mode */
|
||||
|
||||
@@ -211,6 +211,12 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
||||
*/
|
||||
ngOnDestroy(): void
|
||||
{
|
||||
// Finish the animation
|
||||
if ( this._player )
|
||||
{
|
||||
this._player.finish();
|
||||
}
|
||||
|
||||
// Deregister the drawer from the registry
|
||||
this._fuseDrawerService.deregisterComponent(this.name);
|
||||
}
|
||||
@@ -338,6 +344,7 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
||||
|
||||
// Create the enter animation and attach it to the player
|
||||
this._player = this._animationBuilder.build([
|
||||
style({opacity: 0}),
|
||||
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1}))
|
||||
]).create(this._overlay);
|
||||
|
||||
@@ -346,6 +353,7 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
||||
|
||||
// Destroy the player
|
||||
this._player.destroy();
|
||||
this._player = null;
|
||||
});
|
||||
|
||||
// Play the animation
|
||||
@@ -382,6 +390,7 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
||||
|
||||
// Destroy the player
|
||||
this._player.destroy();
|
||||
this._player = null;
|
||||
|
||||
// If the backdrop still exists...
|
||||
if ( this._overlay )
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
||||
@Component({
|
||||
selector : 'fuse-horizontal-navigation-divider-item',
|
||||
templateUrl : './divider.component.html',
|
||||
styles : [],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
|
||||
|
||||
@@ -8,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
||||
@Component({
|
||||
selector : 'fuse-horizontal-navigation-spacer-item',
|
||||
templateUrl : './spacer.component.html',
|
||||
styles : [],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
31
src/@fuse/services/confirmation/confirmation.module.ts
Normal file
31
src/@fuse/services/confirmation/confirmation.module.ts
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
58
src/@fuse/services/confirmation/confirmation.service.ts
Normal file
58
src/@fuse/services/confirmation/confirmation.service.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
}
|
||||
22
src/@fuse/services/confirmation/confirmation.types.ts
Normal file
22
src/@fuse/services/confirmation/confirmation.types.ts
Normal 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;
|
||||
}
|
||||
85
src/@fuse/services/confirmation/dialog/dialog.component.html
Normal file
85
src/@fuse/services/confirmation/dialog/dialog.component.html
Normal 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>
|
||||
52
src/@fuse/services/confirmation/dialog/dialog.component.ts
Normal file
52
src/@fuse/services/confirmation/dialog/dialog.component.ts
Normal 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
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
1
src/@fuse/services/confirmation/index.ts
Normal file
1
src/@fuse/services/confirmation/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from '@fuse/services/confirmation/public-api';
|
||||
3
src/@fuse/services/confirmation/public-api.ts
Normal file
3
src/@fuse/services/confirmation/public-api.ts
Normal 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';
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { Version } from '@fuse/version/version';
|
||||
|
||||
export const FUSE_VERSION = new Version('13.2.0').full;
|
||||
export const FUSE_VERSION = new Version('13.6.0').full;
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -4,6 +4,7 @@ import { forkJoin, Observable } from 'rxjs';
|
||||
import { MessagesService } from 'app/layout/common/messages/messages.service';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
import { NotificationsService } from 'app/layout/common/notifications/notifications.service';
|
||||
import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service';
|
||||
import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service';
|
||||
import { UserService } from 'app/core/user/user.service';
|
||||
|
||||
@@ -19,6 +20,7 @@ export class InitialDataResolver implements Resolve<any>
|
||||
private _messagesService: MessagesService,
|
||||
private _navigationService: NavigationService,
|
||||
private _notificationsService: NotificationsService,
|
||||
private _quickChatService: QuickChatService,
|
||||
private _shortcutsService: ShortcutsService,
|
||||
private _userService: UserService
|
||||
)
|
||||
@@ -42,6 +44,7 @@ export class InitialDataResolver implements Resolve<any>
|
||||
this._navigationService.get(),
|
||||
this._messagesService.getAll(),
|
||||
this._notificationsService.getAll(),
|
||||
this._quickChatService.getChats(),
|
||||
this._shortcutsService.getAll(),
|
||||
this._userService.get()
|
||||
]);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@ import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
|
||||
}
|
||||
],
|
||||
defaultLang : 'en',
|
||||
fallbackLang : 'en',
|
||||
reRenderOnLangChange: true,
|
||||
prodMode : environment.production
|
||||
})
|
||||
|
||||
196
src/app/layout/common/quick-chat/quick-chat.component.html
Normal file
196
src/app/layout/common/quick-chat/quick-chat.component.html
Normal file
@@ -0,0 +1,196 @@
|
||||
<div class="fixed lg:sticky top-0 bottom-0 lg:left-full w-full sm:w-96 lg:w-16 lg:h-screen">
|
||||
<div
|
||||
class="flex flex-col w-full sm:w-96 h-full lg:shadow transform transition-transform duration-400 ease-drawer bg-card"
|
||||
[ngClass]="{'-translate-x-full sm:-translate-x-96 lg:-translate-x-80 shadow': opened, 'translate-x-0': !opened}">
|
||||
|
||||
<!-- Header -->
|
||||
<div
|
||||
class="quick-chat-header flex flex-0 items-center justify-start cursor-pointer"
|
||||
(click)="toggle()">
|
||||
|
||||
<!-- Toggle -->
|
||||
<ng-container *ngIf="!opened || (opened && !selectedChat)">
|
||||
<div class="flex flex-auto items-center justify-center">
|
||||
<div class="flex flex-0 items-center justify-center w-16">
|
||||
<mat-icon
|
||||
class="icon-size-6"
|
||||
[svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</div>
|
||||
<div class="text-lg font-medium text-secondary">Team Chat</div>
|
||||
<button
|
||||
class="ml-auto mr-4"
|
||||
mat-icon-button>
|
||||
<mat-icon [svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- Contact info -->
|
||||
<ng-container *ngIf="opened && selectedChat">
|
||||
<div class="flex flex-auto items-center ml-3">
|
||||
<div class="relative flex flex-0 items-center justify-center w-10 h-10">
|
||||
<ng-container *ngIf="chat.contact.avatar">
|
||||
<img
|
||||
class="w-full h-full rounded-full object-cover"
|
||||
[src]="chat.contact.avatar"
|
||||
alt="Contact avatar"/>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!chat.contact.avatar">
|
||||
<div class="flex items-center justify-center w-full h-full rounded-full text-lg uppercase bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-200">
|
||||
{{chat.contact.name.charAt(0)}}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="ml-4 text-lg font-medium leading-5 truncate">{{chat.contact.name}}</div>
|
||||
<button
|
||||
class="ml-auto mr-4"
|
||||
mat-icon-button>
|
||||
<mat-icon [svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex flex-auto border-t overflow-hidden">
|
||||
|
||||
<!-- Chat list -->
|
||||
<div
|
||||
class="flex-0 w-16 h-full overflow-y-auto overscroll-y-contain sm:overflow-hidden sm:overscroll-auto"
|
||||
fuseScrollbar
|
||||
[fuseScrollbarOptions]="{wheelPropagation: false}">
|
||||
<div class="flex-auto">
|
||||
<ng-container *ngFor="let chat of chats; trackBy: trackByFn">
|
||||
<div
|
||||
class="flex items-center py-3 px-4 cursor-pointer"
|
||||
[ngClass]="{'hover:bg-gray-100 dark:hover:bg-hover': !selectedChat || selectedChat.id !== chat.id,
|
||||
'bg-primary-50 dark:bg-hover': selectedChat && selectedChat.id === chat.id}"
|
||||
(click)="selectChat(chat.id)">
|
||||
<div class="relative flex flex-0 items-center justify-center w-8 h-8">
|
||||
<ng-container *ngIf="chat.unreadCount > 0">
|
||||
<div
|
||||
class="absolute bottom-0 right-0 flex-0 w-2 h-2 -ml-0.5 rounded-full ring-2 ring-bg-card dark:ring-gray-900 bg-primary dark:bg-primary-500 text-on-primary"
|
||||
[class.ring-primary-50]="selectedChat && selectedChat.id === chat.id"></div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="chat.contact.avatar">
|
||||
<img
|
||||
class="w-full h-full rounded-full object-cover"
|
||||
[src]="chat.contact.avatar"
|
||||
alt="Contact avatar"/>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!chat.contact.avatar">
|
||||
<div class="flex items-center justify-center w-full h-full rounded-full text-lg uppercase bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-200">
|
||||
{{chat.contact.name.charAt(0)}}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conversation -->
|
||||
<div class="flex flex-col flex-auto border-l overflow-hidden bg-gray-50 dark:bg-transparent">
|
||||
<ng-container *ngIf="chat; else selectChatOrStartNew">
|
||||
<div class="flex flex-col-reverse overflow-y-auto overscroll-y-contain">
|
||||
<div class="flex flex-col flex-auto flex-shrink p-6">
|
||||
<ng-container *ngFor="let message of chat.messages; let i = index; let first = first; let last = last; trackBy: trackByFn">
|
||||
<!-- Start of the day -->
|
||||
<ng-container *ngIf="first || (chat.messages[i - 1].createdAt | date:'d') !== (message.createdAt | date:'d')">
|
||||
<div class="flex items-center justify-center my-3 -mx-6">
|
||||
<div class="flex-auto border-b"></div>
|
||||
<div class="flex-0 mx-4 text-sm font-medium leading-5 text-secondary">
|
||||
{{message.createdAt | date: 'longDate'}}
|
||||
</div>
|
||||
<div class="flex-auto border-b"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div
|
||||
class="flex flex-col"
|
||||
[ngClass]="{'items-end': message.isMine,
|
||||
'items-start': !message.isMine,
|
||||
'mt-0.5': i > 0 && chat.messages[i - 1].isMine === message.isMine,
|
||||
'mt-3': i > 0 && chat.messages[i - 1].isMine !== message.isMine}">
|
||||
<!-- Bubble -->
|
||||
<div
|
||||
class="relative max-w-3/4 px-3 py-2 rounded-lg"
|
||||
[ngClass]="{'bg-blue-500 text-blue-50': message.isMine,
|
||||
'bg-gray-500 text-gray-50': !message.isMine}">
|
||||
<!-- Speech bubble tail -->
|
||||
<ng-container *ngIf="last || chat.messages[i + 1].isMine !== message.isMine">
|
||||
<div
|
||||
class="absolute bottom-0 w-3 transform"
|
||||
[ngClass]="{'text-blue-500 -right-1 -mr-px mb-px': message.isMine,
|
||||
'text-gray-500 -left-1 -ml-px mb-px -scale-x-1': !message.isMine}">
|
||||
<ng-container *ngTemplateOutlet="speechBubbleExtension"></ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
<!-- Message -->
|
||||
<div
|
||||
class="min-w-4 leading-5"
|
||||
[innerHTML]="message.value">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Time -->
|
||||
<ng-container
|
||||
*ngIf="first
|
||||
|| last
|
||||
|| chat.messages[i + 1].isMine !== message.isMine
|
||||
|| chat.messages[i + 1].createdAt !== message.createdAt">
|
||||
<div
|
||||
class="my-0.5 text-sm font-medium text-secondary"
|
||||
[ngClass]="{'mr-3': message.isMine,
|
||||
'ml-3': !message.isMine}">
|
||||
{{message.createdAt | date:'HH:mm'}}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message field -->
|
||||
<div class="flex items-end p-4 border-t bg-gray-50 dark:bg-transparent">
|
||||
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded fuse-mat-bold w-full">
|
||||
<textarea
|
||||
class="min-h-5 my-0 resize-none"
|
||||
style="margin: 11px 0 !important; padding: 0 !important;"
|
||||
[rows]="1"
|
||||
matInput
|
||||
#messageInput></textarea>
|
||||
</mat-form-field>
|
||||
<div class="flex items-center h-11 my-px ml-4">
|
||||
<button
|
||||
mat-icon-button>
|
||||
<mat-icon
|
||||
class="transform rotate-90"
|
||||
[svgIcon]="'heroicons_outline:paper-airplane'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Select chat or start new template -->
|
||||
<ng-template #selectChatOrStartNew>
|
||||
<div class="flex flex-col flex-auto items-center justify-center w-full h-full p-4">
|
||||
<mat-icon
|
||||
class="icon-size-20"
|
||||
[svgIcon]="'iconsmind:speach_bubble'"></mat-icon>
|
||||
<div class="mt-4 text-xl text-center font-medium tracking-tight text-secondary">Select a conversation</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<!-- Speech bubble tail SVG -->
|
||||
<!-- @formatter:off -->
|
||||
<ng-template #speechBubbleExtension>
|
||||
<svg width="100%" height="100%" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M1.01522827,0.516204834 C-8.83532715,54.3062744 61.7609863,70.5215302 64.8009949,64.3061218 C68.8074951,54.8859711 30.1663208,52.9997559 37.5036011,0.516204834 L1.01522827,0.516204834 Z" fill="currentColor" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</ng-template>
|
||||
<!-- @formatter:on -->
|
||||
26
src/app/layout/common/quick-chat/quick-chat.component.scss
Normal file
26
src/app/layout/common/quick-chat/quick-chat.component.scss
Normal file
@@ -0,0 +1,26 @@
|
||||
quick-chat {
|
||||
z-index: 399;
|
||||
}
|
||||
|
||||
/* Adjustments depending on the selected layout */
|
||||
.quick-chat-header {
|
||||
height: 64px;
|
||||
|
||||
enterprise-layout &,
|
||||
modern-layout & {
|
||||
height: 80px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Overlay */
|
||||
.quick-chat-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 299;
|
||||
opacity: 1;
|
||||
background-color: transparent;
|
||||
}
|
||||
275
src/app/layout/common/quick-chat/quick-chat.component.ts
Normal file
275
src/app/layout/common/quick-chat/quick-chat.component.ts
Normal file
@@ -0,0 +1,275 @@
|
||||
import { Component, ElementRef, HostBinding, HostListener, NgZone, OnDestroy, OnInit, Renderer2, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service';
|
||||
import { Chat } from 'app/layout/common/quick-chat/quick-chat.types';
|
||||
|
||||
@Component({
|
||||
selector : 'quick-chat',
|
||||
templateUrl : './quick-chat.component.html',
|
||||
styleUrls : ['./quick-chat.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
exportAs : 'quickChat'
|
||||
})
|
||||
export class QuickChatComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@ViewChild('messageInput') messageInput: ElementRef;
|
||||
chat: Chat;
|
||||
chats: Chat[];
|
||||
opened: boolean = false;
|
||||
selectedChat: Chat;
|
||||
private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
|
||||
private _overlay: HTMLElement;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(
|
||||
private _elementRef: ElementRef,
|
||||
private _renderer2: Renderer2,
|
||||
private _ngZone: NgZone,
|
||||
private _quickChatService: QuickChatService,
|
||||
private _scrollStrategyOptions: ScrollStrategyOptions
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Decorated methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Host binding for component classes
|
||||
*/
|
||||
@HostBinding('class') get classList(): any
|
||||
{
|
||||
return {
|
||||
'quick-chat-opened': this.opened
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize on 'input' and 'ngModelChange' events
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
@HostListener('input')
|
||||
@HostListener('ngModelChange')
|
||||
private _resizeMessageInput(): void
|
||||
{
|
||||
// This doesn't need to trigger Angular's change detection by itself
|
||||
this._ngZone.runOutsideAngular(() => {
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
// Set the height to 'auto' so we can correctly read the scrollHeight
|
||||
this.messageInput.nativeElement.style.height = 'auto';
|
||||
|
||||
// Get the scrollHeight and subtract the vertical padding
|
||||
this.messageInput.nativeElement.style.height = `${this.messageInput.nativeElement.scrollHeight}px`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Chat
|
||||
this._quickChatService.chat$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((chat: Chat) => {
|
||||
this.chat = chat;
|
||||
});
|
||||
|
||||
// Chats
|
||||
this._quickChatService.chats$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((chats: Chat[]) => {
|
||||
this.chats = chats;
|
||||
});
|
||||
|
||||
// Selected chat
|
||||
this._quickChatService.chat$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((chat: Chat) => {
|
||||
this.selectedChat = chat;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* On destroy
|
||||
*/
|
||||
ngOnDestroy(): void
|
||||
{
|
||||
// Unsubscribe from all subscriptions
|
||||
this._unsubscribeAll.next();
|
||||
this._unsubscribeAll.complete();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open the panel
|
||||
*/
|
||||
open(): void
|
||||
{
|
||||
// Return if the panel has already opened
|
||||
if ( this.opened )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the panel
|
||||
this._toggleOpened(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the panel
|
||||
*/
|
||||
close(): void
|
||||
{
|
||||
// Return if the panel has already closed
|
||||
if ( !this.opened )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Close the panel
|
||||
this._toggleOpened(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the panel
|
||||
*/
|
||||
toggle(): void
|
||||
{
|
||||
if ( this.opened )
|
||||
{
|
||||
this.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the chat
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
selectChat(id: string): void
|
||||
{
|
||||
// Open the panel
|
||||
this._toggleOpened(true);
|
||||
|
||||
// Get the chat data
|
||||
this._quickChatService.getChatById(id).subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Track by function for ngFor loops
|
||||
*
|
||||
* @param index
|
||||
* @param item
|
||||
*/
|
||||
trackByFn(index: number, item: any): any
|
||||
{
|
||||
return item.id || index;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Private methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Show the backdrop
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private _showOverlay(): void
|
||||
{
|
||||
// Try hiding the overlay in case there is one already opened
|
||||
this._hideOverlay();
|
||||
|
||||
// Create the backdrop element
|
||||
this._overlay = this._renderer2.createElement('div');
|
||||
|
||||
// Return if overlay couldn't be create for some reason
|
||||
if ( !this._overlay )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a class to the backdrop element
|
||||
this._overlay.classList.add('quick-chat-overlay');
|
||||
|
||||
// Append the backdrop to the parent of the panel
|
||||
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay);
|
||||
|
||||
// Enable block scroll strategy
|
||||
this._scrollStrategy.enable();
|
||||
|
||||
// Add an event listener to the overlay
|
||||
this._overlay.addEventListener('click', () => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the backdrop
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private _hideOverlay(): void
|
||||
{
|
||||
if ( !this._overlay )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the backdrop still exists...
|
||||
if ( this._overlay )
|
||||
{
|
||||
// Remove the backdrop
|
||||
this._overlay.parentNode.removeChild(this._overlay);
|
||||
this._overlay = null;
|
||||
}
|
||||
|
||||
// Disable block scroll strategy
|
||||
this._scrollStrategy.disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open/close the panel
|
||||
*
|
||||
* @param open
|
||||
* @private
|
||||
*/
|
||||
private _toggleOpened(open: boolean): void
|
||||
{
|
||||
// Set the opened
|
||||
this.opened = open;
|
||||
|
||||
// If the panel opens, show the overlay
|
||||
if ( open )
|
||||
{
|
||||
this._showOverlay();
|
||||
}
|
||||
// Otherwise, hide the overlay
|
||||
else
|
||||
{
|
||||
this._hideOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/app/layout/common/quick-chat/quick-chat.module.ts
Normal file
32
src/app/layout/common/quick-chat/quick-chat.module.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { FuseDrawerModule } from '@fuse/components/drawer';
|
||||
import { FuseScrollbarModule } from '@fuse/directives/scrollbar';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { QuickChatComponent } from 'app/layout/common/quick-chat/quick-chat.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
QuickChatComponent
|
||||
],
|
||||
imports: [
|
||||
RouterModule,
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
FuseDrawerModule,
|
||||
FuseScrollbarModule,
|
||||
SharedModule,
|
||||
],
|
||||
exports : [
|
||||
QuickChatComponent
|
||||
]
|
||||
})
|
||||
export class QuickChatModule
|
||||
{
|
||||
}
|
||||
85
src/app/layout/common/quick-chat/quick-chat.service.ts
Normal file
85
src/app/layout/common/quick-chat/quick-chat.service.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
|
||||
import { map, switchMap, tap } from 'rxjs/operators';
|
||||
import { Chat } from 'app/layout/common/quick-chat/quick-chat.types';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class QuickChatService
|
||||
{
|
||||
private _chat: BehaviorSubject<Chat> = new BehaviorSubject(null);
|
||||
private _chats: BehaviorSubject<Chat[]> = new BehaviorSubject<Chat[]>(null);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(private _httpClient: HttpClient)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Accessors
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Getter for chat
|
||||
*/
|
||||
get chat$(): Observable<Chat>
|
||||
{
|
||||
return this._chat.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for chat
|
||||
*/
|
||||
get chats$(): Observable<Chat[]>
|
||||
{
|
||||
return this._chats.asObservable();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get chats
|
||||
*/
|
||||
getChats(): Observable<any>
|
||||
{
|
||||
return this._httpClient.get<Chat[]>('api/apps/chat/chats').pipe(
|
||||
tap((response: Chat[]) => {
|
||||
this._chats.next(response);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
getChatById(id: string): Observable<any>
|
||||
{
|
||||
return this._httpClient.get<Chat>('api/apps/chat/chat', {params: {id}}).pipe(
|
||||
map((chat) => {
|
||||
|
||||
// Update the chat
|
||||
this._chat.next(chat);
|
||||
|
||||
// Return the chat
|
||||
return chat;
|
||||
}),
|
||||
switchMap((chat) => {
|
||||
|
||||
if ( !chat )
|
||||
{
|
||||
return throwError('Could not found chat with id of ' + id + '!');
|
||||
}
|
||||
|
||||
return of(chat);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
46
src/app/layout/common/quick-chat/quick-chat.types.ts
Normal file
46
src/app/layout/common/quick-chat/quick-chat.types.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
export interface Chat
|
||||
{
|
||||
id?: string;
|
||||
contactId?: string;
|
||||
contact?: Contact;
|
||||
unreadCount?: number;
|
||||
muted?: boolean;
|
||||
lastMessage?: string;
|
||||
lastMessageAt?: string;
|
||||
messages?: {
|
||||
id?: string;
|
||||
chatId?: string;
|
||||
contactId?: string;
|
||||
isMine?: boolean;
|
||||
value?: string;
|
||||
createdAt?: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface Contact
|
||||
{
|
||||
id?: string;
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
about?: string;
|
||||
details?: {
|
||||
emails?: {
|
||||
email?: string;
|
||||
label?: string;
|
||||
}[];
|
||||
phoneNumbers?: {
|
||||
country?: string;
|
||||
phoneNumber?: string;
|
||||
label?: string;
|
||||
}[];
|
||||
title?: string;
|
||||
company?: string;
|
||||
birthday?: string;
|
||||
address?: string;
|
||||
};
|
||||
attachments?: {
|
||||
media?: any[];
|
||||
docs?: any[];
|
||||
links?: any[];
|
||||
};
|
||||
}
|
||||
474
src/app/layout/common/settings/settings.component.html
Normal file
474
src/app/layout/common/settings/settings.component.html
Normal file
@@ -0,0 +1,474 @@
|
||||
<div
|
||||
class="fixed flex items-center justify-center right-0 w-10 h-10 shadow-lg rounded-l-lg z-90 cursor-pointer bg-red-600 bg-opacity-90 print:hidden"
|
||||
[class.lg:right-0]="config.layout === 'centered' || config.layout === 'material'"
|
||||
[class.lg:right-16]="config.layout !== 'centered' && config.layout !== 'material'"
|
||||
style="top: 275px"
|
||||
(click)="settingsDrawer.toggle()">
|
||||
<mat-icon
|
||||
class="icon-size-5 text-white animate-spin-slow"
|
||||
[svgIcon]="'heroicons_solid:cog'"></mat-icon>
|
||||
</div>
|
||||
|
||||
<fuse-drawer
|
||||
class="w-screen min-w-screen sm:w-100 sm:min-w-100 z-999"
|
||||
fixed
|
||||
[mode]="'over'"
|
||||
[name]="'settingsDrawer'"
|
||||
[position]="'right'"
|
||||
#settingsDrawer>
|
||||
|
||||
<div class="flex flex-col w-full overflow-auto bg-card">
|
||||
<div class="flex flex-row items-center px-6 h-20 min-h-20 text-white bg-primary">
|
||||
<mat-icon
|
||||
class="icon-size-7 text-current"
|
||||
[svgIcon]="'heroicons_solid:cog'"></mat-icon>
|
||||
<div class="ml-3 text-2xl font-semibold tracking-tight">Settings</div>
|
||||
<button
|
||||
class="ml-auto"
|
||||
mat-icon-button
|
||||
(click)="settingsDrawer.close()">
|
||||
<mat-icon
|
||||
class="text-current"
|
||||
[svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col p-6">
|
||||
|
||||
<!-- Theme -->
|
||||
<div class="text-md font-semibold text-secondary">THEME</div>
|
||||
<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 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="flex-0 w-3 h-3 rounded-full"
|
||||
[style.background-color]="theme[1].primary"></div>
|
||||
<div
|
||||
class="ml-2.5 font-medium leading-5 truncate"
|
||||
[class.text-secondary]="config.theme !== theme[0]">
|
||||
{{theme[0] | titlecase}}
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<hr class="my-8">
|
||||
|
||||
<!-- Scheme -->
|
||||
<div class="text-md font-semibold text-secondary">SCHEME</div>
|
||||
<div class="grid grid-cols-3 gap-3 justify-items-start mt-6">
|
||||
<!-- Auto -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'auto'"
|
||||
matTooltip="Automatically sets the scheme based on user's operating system's color scheme preference using 'prefer-color-scheme' media query."
|
||||
(click)="setScheme('auto')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:lightning-bolt'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'auto'">
|
||||
Auto
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dark -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'dark'"
|
||||
(click)="setScheme('dark')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:moon'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'dark'">
|
||||
Dark
|
||||
</div>
|
||||
</div>
|
||||
<!-- Light -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'light'"
|
||||
(click)="setScheme('light')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:sun'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'light'">
|
||||
Light
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-8">
|
||||
|
||||
<!-- Layout -->
|
||||
<div class="text-md font-semibold text-secondary">LAYOUT</div>
|
||||
<div class="grid grid-cols-3 gap-3 mt-6">
|
||||
|
||||
<!-- Empty -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('empty')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'empty'">
|
||||
<div class="flex flex-col flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'empty'">
|
||||
Empty
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Classic -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('classic')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'classic'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="mt-3 mx-1.5 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'classic'">
|
||||
Classic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Classy -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('classy')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'classy'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center mt-1 mx-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-auto rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-0.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="w-4 h-4 mt-2.5 mx-auto rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="mt-2 mx-1 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-2">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'classy'">
|
||||
Classy
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compact -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('compact')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'compact'">
|
||||
<div class="w-5 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-3 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'compact'">
|
||||
Compact
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dense -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('dense')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'dense'">
|
||||
<div class="w-4 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'dense'">
|
||||
Dense
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Futuristic -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('futuristic')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'futuristic'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex flex-col flex-auto h-full py-3 px-1.5 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex-auto"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'futuristic'">
|
||||
Futuristic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thin -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('thin')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'thin'">
|
||||
<div class="w-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-1.5 h-1.5 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'thin'">
|
||||
Thin
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2"></div>
|
||||
|
||||
<!-- Centered -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('centered')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'centered'">
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded-md overflow-hidden">
|
||||
<div class="flex items-center h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex ml-1.5">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end ml-auto mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'centered'">
|
||||
Centered
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Enterprise -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('enterprise')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'enterprise'">
|
||||
<div class="flex items-center h-3 px-2 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center h-3 px-2 border-t border-b space-x-1 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded overflow-hidden">
|
||||
<div class="flex flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'enterprise'">
|
||||
Enterprise
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Material -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('material')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'material'">
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded overflow-hidden">
|
||||
<div class="flex items-center h-4 px-2 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center h-2 px-2 space-x-1 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'material'">
|
||||
Material
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modern -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('modern')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'modern'">
|
||||
<div class="flex items-center h-4 px-2 border-b bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center h-3 ml-2 space-x-1">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto">
|
||||
<div class="flex flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'modern'">
|
||||
Modern
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</fuse-drawer>
|
||||
124
src/app/layout/common/settings/settings.component.ts
Normal file
124
src/app/layout/common/settings/settings.component.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseConfigService } from '@fuse/services/config';
|
||||
import { FuseTailwindService } from '@fuse/services/tailwind';
|
||||
import { AppConfig, Scheme, Theme } from 'app/core/config/app.config';
|
||||
import { Layout } from 'app/layout/layout.types';
|
||||
|
||||
@Component({
|
||||
selector : 'settings',
|
||||
templateUrl : './settings.component.html',
|
||||
styles : [
|
||||
`
|
||||
settings {
|
||||
position: static;
|
||||
display: block;
|
||||
flex: none;
|
||||
width: auto;
|
||||
}
|
||||
`
|
||||
],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class SettingsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
config: AppConfig;
|
||||
layout: Layout;
|
||||
scheme: 'dark' | 'light';
|
||||
theme: string;
|
||||
themes: [string, any][] = [];
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _fuseConfigService: FuseConfigService,
|
||||
private _fuseTailwindService: FuseTailwindService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Get the themes
|
||||
this._fuseTailwindService.tailwindConfig$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((config) => {
|
||||
this.themes = Object.entries(config.themes);
|
||||
});
|
||||
|
||||
// Subscribe to config changes
|
||||
this._fuseConfigService.config$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((config: AppConfig) => {
|
||||
|
||||
// Store the config
|
||||
this.config = config;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* On destroy
|
||||
*/
|
||||
ngOnDestroy(): void
|
||||
{
|
||||
// Unsubscribe from all subscriptions
|
||||
this._unsubscribeAll.next();
|
||||
this._unsubscribeAll.complete();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the layout on the config
|
||||
*
|
||||
* @param layout
|
||||
*/
|
||||
setLayout(layout: string): void
|
||||
{
|
||||
// Clear the 'layout' query param to allow layout changes
|
||||
this._router.navigate([], {
|
||||
queryParams : {
|
||||
layout: null
|
||||
},
|
||||
queryParamsHandling: 'merge'
|
||||
}).then(() => {
|
||||
|
||||
// Set the config
|
||||
this._fuseConfigService.config = {layout};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scheme on the config
|
||||
*
|
||||
* @param scheme
|
||||
*/
|
||||
setScheme(scheme: Scheme): void
|
||||
{
|
||||
this._fuseConfigService.config = {scheme};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme on the config
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
setTheme(theme: Theme): void
|
||||
{
|
||||
this._fuseConfigService.config = {theme};
|
||||
}
|
||||
}
|
||||
28
src/app/layout/common/settings/settings.module.ts
Normal file
28
src/app/layout/common/settings/settings.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { FuseDrawerModule } from '@fuse/components/drawer';
|
||||
import { SettingsComponent } from 'app/layout/common/settings/settings.component';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
SettingsComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
FuseDrawerModule,
|
||||
MatButtonModule
|
||||
],
|
||||
exports : [
|
||||
SettingsComponent
|
||||
]
|
||||
})
|
||||
export class SettingsModule
|
||||
{
|
||||
}
|
||||
@@ -44,468 +44,4 @@
|
||||
<!-- ----------------------------------------------------------------------------------------------------- -->
|
||||
<!-- Settings drawer - Remove this to remove the drawer and its button -->
|
||||
<!-- ----------------------------------------------------------------------------------------------------- -->
|
||||
<div
|
||||
class="fixed flex items-center justify-center right-0 w-10 h-10 shadow-lg rounded-l-lg z-999 cursor-pointer bg-red-600 bg-opacity-90 print:hidden"
|
||||
style="top: 275px"
|
||||
(click)="settingsDrawer.toggle()">
|
||||
<mat-icon
|
||||
class="icon-size-5 text-white animate-spin-slow"
|
||||
[svgIcon]="'heroicons_solid:cog'"></mat-icon>
|
||||
</div>
|
||||
|
||||
<fuse-drawer
|
||||
class="w-screen min-w-screen sm:w-100 sm:min-w-100"
|
||||
fixed
|
||||
transparentOverlay
|
||||
[mode]="'over'"
|
||||
[name]="'settingsDrawer'"
|
||||
[position]="'right'"
|
||||
#settingsDrawer>
|
||||
|
||||
<div class="flex flex-col w-full overflow-auto bg-card">
|
||||
<div class="flex flex-row items-center px-6 h-20 min-h-20 text-white bg-primary">
|
||||
<mat-icon
|
||||
class="icon-size-7 text-current"
|
||||
[svgIcon]="'heroicons_solid:cog'"></mat-icon>
|
||||
<div class="ml-3 text-2xl font-semibold tracking-tight">Settings</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col p-6">
|
||||
|
||||
<!-- Theme -->
|
||||
<div class="text-md font-semibold text-secondary">THEME</div>
|
||||
<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 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="flex-0 w-3 h-3 rounded-full"
|
||||
[style.background-color]="theme[1].primary"></div>
|
||||
<div
|
||||
class="ml-2.5 font-medium leading-5 truncate"
|
||||
[class.text-secondary]="config.theme !== theme[0]">
|
||||
{{theme[0] | titlecase}}
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<hr class="my-8">
|
||||
|
||||
<!-- Scheme -->
|
||||
<div class="text-md font-semibold text-secondary">SCHEME</div>
|
||||
<div class="grid grid-cols-3 gap-3 justify-items-start mt-6">
|
||||
<!-- Auto -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'auto'"
|
||||
[matTooltip]="'Automatically sets the scheme based on user\'s operating system\'s color scheme preference using \'prefer-color-scheme\' media query.'"
|
||||
(click)="setScheme('auto')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:lightning-bolt'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'auto'">
|
||||
Auto
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dark -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'dark'"
|
||||
(click)="setScheme('dark')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:moon'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'dark'">
|
||||
Dark
|
||||
</div>
|
||||
</div>
|
||||
<!-- Light -->
|
||||
<div
|
||||
class="flex items-center py-3 pl-5 pr-6 rounded-full cursor-pointer ring-inset ring-primary bg-hover"
|
||||
[class.ring-2]="config.scheme === 'light'"
|
||||
(click)="setScheme('light')">
|
||||
<div class="flex items-center rounded-full overflow-hidden">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:sun'"></mat-icon>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center ml-2 font-medium leading-5"
|
||||
[class.text-secondary]="config.scheme !== 'light'">
|
||||
Light
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-8">
|
||||
|
||||
<!-- Layout -->
|
||||
<div class="text-md font-semibold text-secondary">LAYOUT</div>
|
||||
<div class="grid grid-cols-3 gap-3 mt-6">
|
||||
|
||||
<!-- Empty -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('empty')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'empty'">
|
||||
<div class="flex flex-col flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'empty'">
|
||||
Empty
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Classic -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('classic')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'classic'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="mt-3 mx-1.5 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'classic'">
|
||||
Classic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Classy -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('classy')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'classy'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center mt-1 mx-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-auto rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-0.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="w-4 h-4 mt-2.5 mx-auto rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="mt-2 mx-1 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-2">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'classy'">
|
||||
Classy
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compact -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('compact')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'compact'">
|
||||
<div class="w-5 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-3 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-2.5 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'compact'">
|
||||
Compact
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dense -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('dense')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'dense'">
|
||||
<div class="w-4 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-2 h-2 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'dense'">
|
||||
Dense
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Futuristic -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('futuristic')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'futuristic'">
|
||||
<div class="w-8 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex flex-col flex-auto h-full py-3 px-1.5 space-y-1">
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex-auto"></div>
|
||||
<div class="h-1 rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'futuristic'">
|
||||
Futuristic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thin -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('thin')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'thin'">
|
||||
<div class="w-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-1.5 h-1.5 mt-2 mx-auto rounded-sm bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex flex-col items-center w-full mt-2 space-y-1">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto border-l">
|
||||
<div class="h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-end h-full mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'thin'">
|
||||
Thin
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2"></div>
|
||||
|
||||
<!-- Centered -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('centered')">
|
||||
<div
|
||||
class="flex h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'centered'">
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded-md overflow-hidden">
|
||||
<div class="flex items-center h-3 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex ml-1.5">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end ml-auto mr-1.5">
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 ml-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'centered'">
|
||||
Centered
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Enterprise -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('enterprise')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'enterprise'">
|
||||
<div class="flex items-center h-3 px-2 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center h-3 px-2 border-t border-b space-x-1 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded overflow-hidden">
|
||||
<div class="flex flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'enterprise'">
|
||||
Enterprise
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Material -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('material')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'material'">
|
||||
<div class="flex flex-col flex-auto my-1 mx-2 border rounded overflow-hidden">
|
||||
<div class="flex items-center h-4 px-2 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center h-2 px-2 space-x-1 bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex flex-auto border-t bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'material'">
|
||||
Material
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modern -->
|
||||
<div
|
||||
class="flex flex-col cursor-pointer"
|
||||
(click)="setLayout('modern')">
|
||||
<div
|
||||
class="flex flex-col h-20 rounded-md overflow-hidden border-2 hover:opacity-80"
|
||||
[class.border-primary]="config.layout === 'modern'">
|
||||
<div class="flex items-center h-4 px-2 border-b bg-gray-100 dark:bg-gray-800">
|
||||
<div class="w-2 h-2 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="flex items-center h-3 ml-2 space-x-1">
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-3 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end ml-auto space-x-1">
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
<div class="w-1 h-1 rounded-full bg-gray-300 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto">
|
||||
<div class="flex flex-auto bg-gray-50 dark:bg-gray-900"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-md font-medium text-center text-secondary"
|
||||
[class.text-primary]="config.layout === 'modern'">
|
||||
Modern
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</fuse-drawer>
|
||||
<settings></settings>
|
||||
|
||||
@@ -5,10 +5,9 @@ import { combineLatest, Subject } from 'rxjs';
|
||||
import { filter, map, takeUntil } from 'rxjs/operators';
|
||||
import { FuseConfigService } from '@fuse/services/config';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
|
||||
import { FUSE_VERSION } from '@fuse/version';
|
||||
import { Layout } from 'app/layout/layout.types';
|
||||
import { AppConfig, Scheme, Theme } from 'app/core/config/app.config';
|
||||
import { AppConfig } from 'app/core/config/app.config';
|
||||
|
||||
@Component({
|
||||
selector : 'layout',
|
||||
@@ -22,7 +21,6 @@ export class LayoutComponent implements OnInit, OnDestroy
|
||||
layout: Layout;
|
||||
scheme: 'dark' | 'light';
|
||||
theme: string;
|
||||
themes: [string, any][] = [];
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -34,8 +32,7 @@ export class LayoutComponent implements OnInit, OnDestroy
|
||||
private _renderer2: Renderer2,
|
||||
private _router: Router,
|
||||
private _fuseConfigService: FuseConfigService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseTailwindConfigService: FuseTailwindService
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -49,11 +46,6 @@ export class LayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Get the themes
|
||||
this._fuseTailwindConfigService.tailwindConfig$.subscribe((config) => {
|
||||
this.themes = Object.entries(config.themes);
|
||||
});
|
||||
|
||||
// Set the theme and scheme based on the configuration
|
||||
combineLatest([
|
||||
this._fuseConfigService.config$,
|
||||
@@ -123,50 +115,6 @@ export class LayoutComponent implements OnInit, OnDestroy
|
||||
this._unsubscribeAll.complete();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the layout on the config
|
||||
*
|
||||
* @param layout
|
||||
*/
|
||||
setLayout(layout: string): void
|
||||
{
|
||||
// Clear the 'layout' query param to allow layout changes
|
||||
this._router.navigate([], {
|
||||
queryParams : {
|
||||
layout: null
|
||||
},
|
||||
queryParamsHandling: 'merge'
|
||||
}).then(() => {
|
||||
|
||||
// Set the config
|
||||
this._fuseConfigService.config = {layout};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scheme on the config
|
||||
*
|
||||
* @param scheme
|
||||
*/
|
||||
setScheme(scheme: Scheme): void
|
||||
{
|
||||
this._fuseConfigService.config = {scheme};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the theme on the config
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
setTheme(theme: Theme): void
|
||||
{
|
||||
this._fuseConfigService.config = {theme};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Private methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -14,6 +14,7 @@ import { CompactLayoutModule } from 'app/layout/layouts/vertical/compact/compact
|
||||
import { DenseLayoutModule } from 'app/layout/layouts/vertical/dense/dense.module';
|
||||
import { FuturisticLayoutModule } from 'app/layout/layouts/vertical/futuristic/futuristic.module';
|
||||
import { ThinLayoutModule } from 'app/layout/layouts/vertical/thin/thin.module';
|
||||
import { SettingsModule } from 'app/layout/common/settings/settings.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
||||
const layoutModules = [
|
||||
@@ -39,12 +40,13 @@ const layoutModules = [
|
||||
declarations: [
|
||||
LayoutComponent
|
||||
],
|
||||
imports : [
|
||||
imports: [
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
FuseDrawerModule,
|
||||
SharedModule,
|
||||
...layoutModules
|
||||
SettingsModule,
|
||||
...layoutModules,
|
||||
],
|
||||
exports : [
|
||||
LayoutComponent,
|
||||
|
||||
@@ -45,13 +45,19 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,3 +92,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterpr
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -54,13 +54,19 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,3 +84,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/mode
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -35,13 +35,19 @@
|
||||
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,3 +65,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/clas
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -65,12 +65,18 @@
|
||||
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,3 +93,6 @@
|
||||
</div>-->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseFullscreenModule } from '@fuse/components/fullscreen/fullscreen.mod
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -30,13 +30,19 @@
|
||||
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,3 +60,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/comp
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -39,13 +39,19 @@
|
||||
</button>
|
||||
</div>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,3 +69,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.co
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -44,13 +44,19 @@
|
||||
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -67,3 +73,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristi
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -31,13 +31,19 @@
|
||||
<mat-icon [svgIcon]="'heroicons_outline:menu'"></mat-icon>
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-1 sm:space-x-2">
|
||||
<div class="flex items-center pl-2 ml-auto space-x-0.5 sm:space-x-2">
|
||||
<languages></languages>
|
||||
<fuse-fullscreen class="hidden md:block"></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<button
|
||||
class="lg:hidden"
|
||||
mat-icon-button
|
||||
(click)="quickChat.toggle()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
|
||||
</button>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,3 +61,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Quick chat -->
|
||||
<quick-chat #quickChat="quickChat"></quick-chat>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FuseNavigationModule } from '@fuse/components/navigation';
|
||||
import { LanguagesModule } from 'app/layout/common/languages/languages.module';
|
||||
import { MessagesModule } from 'app/layout/common/messages/messages.module';
|
||||
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
|
||||
import { QuickChatModule } from 'app/layout/common/quick-chat/quick-chat.module';
|
||||
import { SearchModule } from 'app/layout/common/search/search.module';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
@@ -32,6 +33,7 @@ import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.compo
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
QuickChatModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserModule,
|
||||
|
||||
@@ -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',
|
||||
@@ -683,10 +697,24 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
children: [
|
||||
{
|
||||
id : 'user-interface.material-components',
|
||||
title: '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.2.0',
|
||||
title : '13.6.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'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
38
src/app/mock-api/dashboards/crypto/api.ts
Normal file
38
src/app/mock-api/dashboards/crypto/api.ts
Normal 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)]);
|
||||
}
|
||||
}
|
||||
1196
src/app/mock-api/dashboards/crypto/data.ts
Normal file
1196
src/app/mock-api/dashboards/crypto/data.ts
Normal file
File diff suppressed because it is too large
Load Diff
38
src/app/mock-api/dashboards/finance/api.ts
Normal file
38
src/app/mock-api/dashboards/finance/api.ts
Normal 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)]);
|
||||
}
|
||||
}
|
||||
1045
src/app/mock-api/dashboards/finance/data.ts
Normal file
1045
src/app/mock-api/dashboards/finance/data.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>();
|
||||
|
||||
|
||||
277
src/app/modules/admin/dashboards/crypto/crypto.component.html
Normal file
277
src/app/modules/admin/dashboards/crypto/crypto.component.html
Normal 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>
|
||||
238
src/app/modules/admin/dashboards/crypto/crypto.component.ts
Normal file
238
src/app/modules/admin/dashboards/crypto/crypto.component.ts
Normal 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'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
42
src/app/modules/admin/dashboards/crypto/crypto.module.ts
Normal file
42
src/app/modules/admin/dashboards/crypto/crypto.module.ts
Normal 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
|
||||
{
|
||||
}
|
||||
32
src/app/modules/admin/dashboards/crypto/crypto.resolvers.ts
Normal file
32
src/app/modules/admin/dashboards/crypto/crypto.resolvers.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
13
src/app/modules/admin/dashboards/crypto/crypto.routing.ts
Normal file
13
src/app/modules/admin/dashboards/crypto/crypto.routing.ts
Normal 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
|
||||
}
|
||||
}
|
||||
];
|
||||
47
src/app/modules/admin/dashboards/crypto/crypto.service.ts
Normal file
47
src/app/modules/admin/dashboards/crypto/crypto.service.ts
Normal 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);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
526
src/app/modules/admin/dashboards/finance/finance.component.html
Normal file
526
src/app/modules/admin/dashboards/finance/finance.component.html
Normal 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>
|
||||
146
src/app/modules/admin/dashboards/finance/finance.component.ts
Normal file
146
src/app/modules/admin/dashboards/finance/finance.component.ts
Normal 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'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
34
src/app/modules/admin/dashboards/finance/finance.module.ts
Normal file
34
src/app/modules/admin/dashboards/finance/finance.module.ts
Normal 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
|
||||
{
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
13
src/app/modules/admin/dashboards/finance/finance.routing.ts
Normal file
13
src/app/modules/admin/dashboards/finance/finance.routing.ts
Normal 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
|
||||
}
|
||||
}
|
||||
];
|
||||
47
src/app/modules/admin/dashboards/finance/finance.service.ts
Normal file
47
src/app/modules/admin/dashboards/finance/finance.service.ts
Normal 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);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,13 +4,142 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
@Component({
|
||||
selector : 'changelog',
|
||||
templateUrl : './changelog.html',
|
||||
styles : [''],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ChangelogComponent
|
||||
{
|
||||
changelog: any[] = [
|
||||
|
||||
// v13.6.0
|
||||
{
|
||||
version : 'v13.6.0',
|
||||
releaseDate: 'Aug 31, 2021',
|
||||
changes : [
|
||||
{
|
||||
type: 'Added',
|
||||
list: [
|
||||
'(QuickChat) Added the QuickChat bar'
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Changed',
|
||||
list: [
|
||||
'(dependencies) Updated Angular & Angular Material to v12.2.3',
|
||||
'(dependencies) Updated various other packages',
|
||||
'(layout) Separated the Settings drawer from the layout component'
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Fixed',
|
||||
list: [
|
||||
'(@fuse/drawer) Final opacity of the overlay is not permanent due to player being destroyed right after the animation'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// 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',
|
||||
@@ -37,7 +166,7 @@ export class ChangelogComponent
|
||||
'(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',
|
||||
'(package.json) Added "description" and "author" fields'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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><language></language></code> and remove all instances</li>
|
||||
<li>Do a project wide search for <code><languages></languages></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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user