mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-22 04:27:08 +00:00
Compare commits
33 Commits
v13.3.0-st
...
v13.6.0
| 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 |
@@ -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": [
|
||||
|
||||
2186
package-lock.json
generated
2186
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
63
package.json
63
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fuse/demo",
|
||||
"version": "13.3.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,21 +9,22 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "12.1.2",
|
||||
"@angular/cdk": "12.1.2",
|
||||
"@angular/common": "12.1.2",
|
||||
"@angular/compiler": "12.1.2",
|
||||
"@angular/core": "12.1.2",
|
||||
"@angular/forms": "12.1.2",
|
||||
"@angular/material": "12.1.2",
|
||||
"@angular/material-moment-adapter": "12.1.2",
|
||||
"@angular/platform-browser": "12.1.2",
|
||||
"@angular/platform-browser-dynamic": "12.1.2",
|
||||
"@angular/router": "12.1.2",
|
||||
"@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,48 +34,48 @@
|
||||
"@fullcalendar/rrule": "4.4.2",
|
||||
"@fullcalendar/timegrid": "4.4.2",
|
||||
"@ngneat/transloco": "2.22.0",
|
||||
"apexcharts": "3.27.2",
|
||||
"apexcharts": "3.28.1",
|
||||
"crypto-js": "3.3.0",
|
||||
"highlight.js": "11.1.0",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"@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.1.2",
|
||||
"@angular/compiler-cli": "12.1.2",
|
||||
"@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.8.1",
|
||||
"@types/lodash": "4.14.171",
|
||||
"@types/jasmine": "3.8.2",
|
||||
"@types/lodash": "4.14.172",
|
||||
"@types/lodash-es": "4.17.4",
|
||||
"@types/node": "12.20.16",
|
||||
"@typescript-eslint/eslint-plugin": "4.28.3",
|
||||
"@typescript-eslint/parser": "4.28.3",
|
||||
"autoprefixer": "10.3.1",
|
||||
"@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.30.0",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-jsdoc": "35.4.3",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-plugin-import": "2.24.2",
|
||||
"eslint-plugin-jsdoc": "36.0.8",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"jasmine-core": "3.8.0",
|
||||
"karma": "6.3.4",
|
||||
@@ -83,8 +84,8 @@
|
||||
"karma-jasmine": "4.0.1",
|
||||
"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,4 +1,5 @@
|
||||
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';
|
||||
@@ -15,6 +16,15 @@ import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
|
||||
FuseUtilsModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
// Disable 'theme' sanity check
|
||||
provide : MATERIAL_SANITY_CHECKS,
|
||||
useValue: {
|
||||
doctype: true,
|
||||
theme : false,
|
||||
version: true
|
||||
}
|
||||
},
|
||||
{
|
||||
// Use the 'fill' appearance on Angular Material form fields by default
|
||||
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
|
||||
@@ -51,7 +51,8 @@ export class FuseConfirmationService
|
||||
return this._matDialog.open(FuseConfirmationDialogComponent, {
|
||||
autoFocus : false,
|
||||
disableClose: !userConfig.dismissible,
|
||||
data : userConfig
|
||||
data : userConfig,
|
||||
panelClass : 'fuse-confirmation-dialog-panel'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="relative flex flex-col md:w-128 -m-6">
|
||||
<div class="relative flex flex-col w-full h-full">
|
||||
|
||||
<!-- Dismiss button -->
|
||||
<ng-container *ngIf="data.dismissible">
|
||||
@@ -14,20 +14,20 @@
|
||||
</ng-container>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex flex-col sm:flex-row items-center sm:items-start p-8 pb-6 sm:pb-8">
|
||||
<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': data.icon.color === 'primary',
|
||||
'text-accent-600 bg-accent-100': data.icon.color === 'accent',
|
||||
'text-warn-600 bg-warn-100': data.icon.color === 'warn',
|
||||
'text-gray-600 bg-gray-100': data.icon.color === 'basic',
|
||||
'text-blue-600 bg-blue-100': data.icon.color === 'info',
|
||||
'text-green-500 bg-green-100': data.icon.color === 'success',
|
||||
'text-amber-500 bg-amber-100': data.icon.color === 'warning',
|
||||
'text-red-600 bg-red-100': data.icon.color === 'error'
|
||||
[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"
|
||||
@@ -56,9 +56,9 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Buttons -->
|
||||
<!-- 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">
|
||||
<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">
|
||||
|
||||
@@ -5,6 +5,20 @@ import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation
|
||||
@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
|
||||
|
||||
@@ -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.3.0').full;
|
||||
export const FUSE_VERSION = new Version('13.6.0').full;
|
||||
|
||||
@@ -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
|
||||
|
||||
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'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -967,7 +981,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
icon : 'heroicons_outline:speakerphone',
|
||||
link : '/docs/changelog',
|
||||
badge: {
|
||||
title : '13.3.0',
|
||||
title : '13.6.0',
|
||||
classes: 'px-2 bg-yellow-300 text-black rounded-full'
|
||||
}
|
||||
},
|
||||
|
||||
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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
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'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'theming',
|
||||
templateUrl: './theming.html',
|
||||
styles : ['']
|
||||
templateUrl: './theming.html'
|
||||
})
|
||||
export class ThemingComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'component-structure',
|
||||
templateUrl: './component-structure.html',
|
||||
styles : ['']
|
||||
templateUrl: './component-structure.html'
|
||||
})
|
||||
export class ComponentStructureComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'deployment',
|
||||
templateUrl: './deployment.html',
|
||||
styles : ['']
|
||||
templateUrl: './deployment.html'
|
||||
})
|
||||
export class DeploymentComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'starter-kit',
|
||||
templateUrl: './starter-kit.html',
|
||||
styles : ['']
|
||||
templateUrl: './starter-kit.html'
|
||||
})
|
||||
export class StarterKitComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'updating',
|
||||
templateUrl: './updating.html',
|
||||
styles : ['']
|
||||
templateUrl: './updating.html'
|
||||
})
|
||||
export class UpdatingComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'installation',
|
||||
templateUrl: './installation.html',
|
||||
styles : ['']
|
||||
templateUrl: './installation.html'
|
||||
})
|
||||
export class InstallationComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'introduction',
|
||||
templateUrl: './introduction.html',
|
||||
styles : ['']
|
||||
templateUrl: './introduction.html'
|
||||
})
|
||||
export class IntroductionComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'prerequisites',
|
||||
templateUrl: './prerequisites.html',
|
||||
styles : ['']
|
||||
templateUrl: './prerequisites.html'
|
||||
})
|
||||
export class PrerequisitesComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { GuidesComponent } from 'app/modules/admin/docs/guides/guides.component'
|
||||
|
||||
@Component({
|
||||
selector : 'serving',
|
||||
templateUrl: './serving.html',
|
||||
styles : ['']
|
||||
templateUrl: './serving.html'
|
||||
})
|
||||
export class ServingComponent
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="max-w-3xl">
|
||||
<div class="max-w-3xl prose prose-sm">
|
||||
<p>
|
||||
One of the repetitive and tedious jobs in Angular is to create confirmation dialogs. Since dialogs require their own component
|
||||
One of the repetitive and tedious jobs in Angular is to create confirmation dialogs. Since dialogs require their own components
|
||||
you have to either create a separate component every time you need a confirmation dialog or you have to create your own
|
||||
confirmation dialog system that can be configured.
|
||||
</p>
|
||||
|
||||
@@ -3,8 +3,7 @@ import { FuseComponentsComponent } from 'app/modules/admin/ui/fuse-components/fu
|
||||
|
||||
@Component({
|
||||
selector : 'card',
|
||||
templateUrl: './card.component.html',
|
||||
styles : ['']
|
||||
templateUrl: './card.component.html'
|
||||
})
|
||||
export class CardComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { FuseComponentsComponent } from 'app/modules/admin/ui/fuse-components/fu
|
||||
|
||||
@Component({
|
||||
selector : 'date-range',
|
||||
templateUrl: './date-range.component.html',
|
||||
styles : ['']
|
||||
templateUrl: './date-range.component.html'
|
||||
})
|
||||
export class DateRangeComponent
|
||||
{
|
||||
|
||||
@@ -4,8 +4,7 @@ import { FuseComponentsComponent } from 'app/modules/admin/ui/fuse-components/fu
|
||||
|
||||
@Component({
|
||||
selector : 'drawer',
|
||||
templateUrl: './drawer.component.html',
|
||||
styles : ['']
|
||||
templateUrl: './drawer.component.html'
|
||||
})
|
||||
export class DrawerComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { FuseComponentsComponent } from 'app/modules/admin/ui/fuse-components/fu
|
||||
|
||||
@Component({
|
||||
selector : 'fullscreen',
|
||||
templateUrl: './fullscreen.component.html',
|
||||
styles : ['']
|
||||
templateUrl: './fullscreen.component.html'
|
||||
})
|
||||
export class FullscreenComponent
|
||||
{
|
||||
|
||||
@@ -3,8 +3,7 @@ import { FuseComponentsComponent } from 'app/modules/admin/ui/fuse-components/fu
|
||||
|
||||
@Component({
|
||||
selector : 'highlight',
|
||||
templateUrl: './highlight.component.html',
|
||||
styles : ['']
|
||||
templateUrl: './highlight.component.html'
|
||||
})
|
||||
export class HighlightComponent
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user