Compare commits

..

45 Commits

Author SHA1 Message Date
Sercan Yemen
38a4c392fe Merge remote-tracking branch 'origin/demo' into starter 2022-01-01 22:52:20 +03:00
Sercan Yemen
d9dee128de Merge remote-tracking branch 'origin/demo' into starter 2021-12-22 14:58:21 +03:00
sercan
b84fb68a47 Merge remote-tracking branch 'origin/demo' into starter 2021-11-11 11:01:19 +03:00
sercan
3d6714008a Merge remote-tracking branch 'origin/demo' into starter 2021-09-10 12:27:59 +03:00
sercan
ea954a75de (app.routing) Fixed: Wrong and missing eslint exceptions 2021-09-10 12:26:21 +03:00
sercan
4b37f2304a Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 16:44:22 +03:00
sercan
82244fd40e Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 15:50:30 +03:00
sercan
c5433cb917 Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 15:49:55 +03:00
sercan
cf5f13d78e Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:18:08 +03:00
sercan
ef85907d1b Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:17:19 +03:00
sercan
cafc3188cf Merge remote-tracking branch 'origin/demo' into starter 2021-08-31 10:07:33 +03:00
sercan
6381362326 Merge remote-tracking branch 'origin/demo' into starter 2021-08-12 17:05:40 +03:00
sercan
e1942f46fd Merge remote-tracking branch 'origin/demo' into starter 2021-08-12 16:57:58 +03:00
sercan
ce656430c8 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:40:12 +03:00
sercan
c93b1ce232 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:23:27 +03:00
sercan
b874b37db2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-29 10:21:30 +03:00
sercan
4287361a09 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:49:22 +03:00
sercan
4f19eb6171 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 20:48:48 +03:00
sercan
cd13f9d9a4 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:38:44 +03:00
sercan
db8c52f093 Merge remote-tracking branch 'origin/demo' into starter 2021-07-16 12:36:58 +03:00
sercan
2189232273 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:11:01 +03:00
sercan
36b89e75db Update package name 2021-07-02 23:05:27 +03:00
sercan
8c2ff122b2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-02 23:01:10 +03:00
sercan
b2cb512b0e Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:29:26 +03:00
sercan
21652570c2 Merge remote-tracking branch 'origin/demo' into starter 2021-07-01 14:28:05 +03:00
sercan
90891eb201 Merge remote-tracking branch 'origin/demo' into starter 2021-06-15 08:36:32 +03:00
sercan
6c7201b77a Merge remote-tracking branch 'origin/demo' into starter 2021-06-03 13:28:30 +03:00
sercan
90f869e7b9 Merge remote-tracking branch 'origin/demo' into starter 2021-05-31 10:46:26 +03:00
sercan
2d2db97416 Merge remote-tracking branch 'origin/demo' into starter 2021-05-24 14:33:12 +03:00
sercan
5daa2260e6 Merge remote-tracking branch 'origin/demo' into starter 2021-05-24 14:29:35 +03:00
sercan
af984fcba1 Merge remote-tracking branch 'origin/demo' into starter 2021-05-23 07:13:28 +03:00
sercan
97d3662417 Merge remote-tracking branch 'origin/demo' into starter 2021-05-21 12:17:06 +03:00
sercan
d897a244c8 Merge remote-tracking branch 'origin/demo' into starter 2021-05-18 16:25:53 +03:00
sercan
d146a92c79 Merge remote-tracking branch 'origin/demo' into starter 2021-05-15 13:18:13 +03:00
sercan
27b6858b76 Merge remote-tracking branch 'origin/demo' into starter 2021-05-06 17:12:50 +03:00
sercan
fcfba4c9e4 Merge remote-tracking branch 'origin/demo' into starter 2021-04-30 19:40:30 +03:00
sercan
40894e0aa3 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/academy/academy.service.ts
#	src/app/modules/admin/apps/academy/details/details.component.html
#	src/app/modules/admin/apps/academy/list/list.component.html
#	src/app/modules/admin/apps/mailbox/list/list.component.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
#	src/app/modules/admin/pages/pricing/modern/modern.component.html
#	src/app/modules/admin/pages/pricing/simple/simple.component.html
#	src/app/modules/admin/pages/pricing/single/single.component.html
#	src/app/modules/admin/pages/pricing/table/table.component.html
2021-04-30 19:40:07 +03:00
sercan
8dcf21cb1a Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:23:15 +03:00
sercan
d917f03883 Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:20:06 +03:00
sercan
0f2ddbda83 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
2021-04-26 09:56:44 +03:00
sercan
fa0d74504b Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 09:56:29 +03:00
sercan
ad2b19a07a Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/contacts/details/details.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.ts
#	src/app/modules/landing/home/home.component.html
2021-04-26 09:31:42 +03:00
sercan
4bf11591a2 (Assets) Added avatar images back 2021-04-19 13:08:24 +03:00
sercan
f45a605b4e Preparing the starter 2021-04-15 17:43:28 +03:00
sercan
c150a8902c Starter 2021-04-15 17:23:49 +03:00
837 changed files with 45711 additions and 81364 deletions

16
.browserslistrc Normal file
View File

@@ -0,0 +1,16 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

View File

@@ -4,7 +4,7 @@ This project was generated with [Angular CLI](https://github.com/angular/angular
## Development server ## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding ## Code scaffolding

View File

@@ -1,6 +1,12 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"cli": {
"defaultCollection": "@angular-eslint/schematics",
"cache": {
"enabled": false
}
},
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"fuse": { "fuse": {
@@ -20,9 +26,7 @@
"outputPath": "dist/fuse", "outputPath": "dist/fuse",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": [ "polyfills": "src/polyfills.ts",
"zone.js"
],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": [ "allowedCommonJsDependencies": [
@@ -30,9 +34,7 @@
"highlight.js", "highlight.js",
"crypto-js/enc-utf8", "crypto-js/enc-utf8",
"crypto-js/hmac-sha256", "crypto-js/hmac-sha256",
"crypto-js/enc-base64", "crypto-js/enc-base64"
"flat",
"quill"
], ],
"assets": [ "assets": [
"src/favicon-16x16.png", "src/favicon-16x16.png",
@@ -73,6 +75,12 @@
"maximumError": "90kb" "maximumError": "90kb"
} }
], ],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all" "outputHashing": "all"
}, },
"development": { "development": {
@@ -107,11 +115,10 @@
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"polyfills": [ "main": "src/test.ts",
"zone.js", "polyfills": "src/polyfills.ts",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": [ "assets": [
"src/favicon-16x16.png", "src/favicon-16x16.png",
@@ -123,8 +130,18 @@
], ],
"scripts": [] "scripts": []
} }
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
} }
} }
} }
} },
"defaultProject": "fuse"
} }

45
karma.conf.js Normal file
View File

@@ -0,0 +1,45 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config)
{
config.set({
basePath : '',
frameworks : ['jasmine', '@angular-devkit/build-angular'],
plugins : [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client : {
jasmine : {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter : {
dir : require('path').join(__dirname, './coverage/fuse'),
subdir : '.',
reporters: [
{type: 'html'},
{type: 'text-summary'}
]
},
reporters : ['progress', 'kjhtml'],
port : 9876,
colors : true,
logLevel : config.LOG_INFO,
autoWatch : true,
browsers : ['Chrome'],
singleRun : false,
restartOnFileChange: true
});
};

19558
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "fuse-angular", "name": "@fuse/starter",
"version": "17.0.1", "version": "14.1.1",
"description": "Fuse - Angular Admin Template and Starter Project", "description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn", "author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard", "license": "https://themeforest.net/licenses/standard",
@@ -10,58 +10,72 @@
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test",
"lint": "ng lint"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "15.0.0", "@angular/animations": "13.1.1",
"@angular/cdk": "15.0.0", "@angular/cdk": "13.1.1",
"@angular/common": "15.0.0", "@angular/common": "13.1.1",
"@angular/compiler": "15.0.0", "@angular/compiler": "13.1.1",
"@angular/core": "15.0.0", "@angular/core": "13.1.1",
"@angular/forms": "15.0.0", "@angular/forms": "13.1.1",
"@angular/material": "15.0.0", "@angular/material": "13.1.1",
"@angular/material-luxon-adapter": "15.0.0", "@angular/material-moment-adapter": "13.1.1",
"@angular/platform-browser": "15.0.0", "@angular/platform-browser": "13.1.1",
"@angular/platform-browser-dynamic": "15.0.0", "@angular/platform-browser-dynamic": "13.1.1",
"@angular/router": "15.0.0", "@angular/router": "13.1.1",
"@ngneat/transloco": "4.1.1", "@ngneat/transloco": "3.1.1",
"apexcharts": "3.36.3", "apexcharts": "3.32.1",
"crypto-js": "3.3.0", "crypto-js": "3.3.0",
"highlight.js": "11.6.0", "highlight.js": "11.3.1",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"luxon": "3.1.0", "moment": "2.29.1",
"ng-apexcharts": "1.7.4", "ng-apexcharts": "1.6.0",
"ngx-quill": "19.0.1", "ngx-markdown": "13.0.0",
"perfect-scrollbar": "1.5.5", "ngx-quill": "16.1.1",
"perfect-scrollbar": "1.5.3",
"quill": "1.3.7", "quill": "1.3.7",
"rxjs": "7.5.7", "rxjs": "7.5.1",
"tslib": "2.4.1", "tslib": "2.3.1",
"zone.js": "0.12.0" "zone.js": "0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "15.0.0", "@angular-devkit/build-angular": "13.1.2",
"@angular/cli": "15.0.0", "@angular-eslint/builder": "13.0.1",
"@angular/compiler-cli": "15.0.0", "@angular-eslint/eslint-plugin": "13.0.1",
"@tailwindcss/line-clamp": "0.4.2", "@angular-eslint/eslint-plugin-template": "13.0.1",
"@tailwindcss/typography": "0.5.8", "@angular-eslint/schematics": "13.0.1",
"@types/chroma-js": "2.1.4", "@angular-eslint/template-parser": "13.0.1",
"@angular/cli": "13.1.2",
"@angular/compiler-cli": "13.1.1",
"@tailwindcss/aspect-ratio": "0.4.0",
"@tailwindcss/line-clamp": "0.3.0",
"@tailwindcss/typography": "0.5.0",
"@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47", "@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0", "@types/highlight.js": "10.1.0",
"@types/jasmine": "4.3.0", "@types/jasmine": "3.10.2",
"@types/lodash": "4.14.189", "@types/lodash": "4.14.178",
"@types/lodash-es": "4.17.6", "@types/lodash-es": "4.17.5",
"@types/luxon": "3.1.0", "@types/node": "12.20.38",
"autoprefixer": "10.4.13", "@typescript-eslint/eslint-plugin": "5.8.1",
"chroma-js": "2.4.2", "@typescript-eslint/parser": "5.8.1",
"jasmine-core": "4.5.0", "autoprefixer": "10.4.1",
"karma": "6.4.1", "chroma-js": "2.1.2",
"karma-chrome-launcher": "3.1.1", "eslint": "8.6.0",
"karma-coverage": "2.2.0", "eslint-plugin-import": "2.25.3",
"karma-jasmine": "5.1.0", "eslint-plugin-jsdoc": "37.5.0",
"karma-jasmine-html-reporter": "2.0.0", "eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.10.1",
"karma": "6.3.9",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "2.1.0",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.7.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"postcss": "8.4.19", "postcss": "8.4.5",
"tailwindcss": "3.2.4", "tailwindcss": "3.0.8",
"typescript": "4.8.4" "typescript": "4.5.4"
} }
} }

View File

@@ -53,7 +53,6 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-alert-appearance-border' : this.appearance === 'border', 'fuse-alert-appearance-border' : this.appearance === 'border',
'fuse-alert-appearance-fill' : this.appearance === 'fill', 'fuse-alert-appearance-fill' : this.appearance === 'fill',
@@ -71,7 +70,6 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
'fuse-alert-type-warning' : this.type === 'warning', 'fuse-alert-type-warning' : this.type === 'warning',
'fuse-alert-type-error' : this.type === 'error' 'fuse-alert-type-error' : this.type === 'error'
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

View File

@@ -38,14 +38,12 @@ export class FuseCardComponent implements OnChanges
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-card-expanded' : this.expanded, 'fuse-card-expanded' : this.expanded,
'fuse-card-face-back' : this.flippable && this.face === 'back', 'fuse-card-face-back' : this.flippable && this.face === 'back',
'fuse-card-face-front': this.flippable && this.face === 'front', 'fuse-card-face-front': this.flippable && this.face === 'front',
'fuse-card-flippable' : this.flippable 'fuse-card-flippable' : this.flippable
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

View File

@@ -1,16 +1,14 @@
/* Variables */ /* Variables */
:root { $fuse-drawer-width: 320;
--fuse-drawer-width: 320px;
}
fuse-drawer { fuse-drawer {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1 1 auto;
width: var(--fuse-drawer-width); width: #{$fuse-drawer-width}px;
min-width: var(--fuse-drawer-width); min-width: #{$fuse-drawer-width}px;
max-width: var(--fuse-drawer-width); max-width: #{$fuse-drawer-width}px;
z-index: 300; z-index: 300;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .35); box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .35);
@apply bg-card; @apply bg-card;
@@ -45,7 +43,7 @@ fuse-drawer {
/* Side mode */ /* Side mode */
&.fuse-drawer-mode-side { &.fuse-drawer-mode-side {
margin-left: calc(var(--fuse-drawer-width) * -1); margin-left: -#{$fuse-drawer-width}px;
&.fuse-drawer-opened { &.fuse-drawer-opened {
margin-left: 0; margin-left: 0;
@@ -73,7 +71,7 @@ fuse-drawer {
/* Side mode */ /* Side mode */
&.fuse-drawer-mode-side { &.fuse-drawer-mode-side {
margin-right: calc(var(--fuse-drawer-width) * -1); margin-right: -#{$fuse-drawer-width}px;
&.fuse-drawer-opened { &.fuse-drawer-opened {
margin-right: 0; margin-right: 0;

View File

@@ -32,7 +32,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
@Output() readonly positionChanged: EventEmitter<FuseDrawerPosition> = new EventEmitter<FuseDrawerPosition>(); @Output() readonly positionChanged: EventEmitter<FuseDrawerPosition> = new EventEmitter<FuseDrawerPosition>();
private _animationsEnabled: boolean = false; private _animationsEnabled: boolean = false;
private readonly _handleOverlayClick: any;
private _hovered: boolean = false; private _hovered: boolean = false;
private _overlay: HTMLElement; private _overlay: HTMLElement;
private _player: AnimationPlayer; private _player: AnimationPlayer;
@@ -48,9 +47,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService
) )
{ {
this._handleOverlayClick = (): void => {
this.close();
};
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -62,7 +58,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-drawer-animations-enabled' : this._animationsEnabled, 'fuse-drawer-animations-enabled' : this._animationsEnabled,
'fuse-drawer-fixed' : this.fixed, 'fuse-drawer-fixed' : this.fixed,
@@ -71,7 +66,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
'fuse-drawer-opened' : this.opened, 'fuse-drawer-opened' : this.opened,
[`fuse-drawer-position-${this.position}`]: true [`fuse-drawer-position-${this.position}`]: true
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
/** /**
@@ -324,6 +318,12 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Create the backdrop element // Create the backdrop element
this._overlay = this._renderer2.createElement('div'); 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 // Add a class to the backdrop element
this._overlay.classList.add('fuse-drawer-overlay'); this._overlay.classList.add('fuse-drawer-overlay');
@@ -342,17 +342,27 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Append the backdrop to the parent of the drawer // Append the backdrop to the parent of the drawer
this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay); this._renderer2.appendChild(this._elementRef.nativeElement.parentElement, this._overlay);
// Create enter animation and attach it to the player // Create the enter animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
style({opacity: 0}), style({opacity: 0}),
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1}))
]).create(this._overlay); ]).create(this._overlay);
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
this._player = null;
});
// Play the animation // Play the animation
this._player.play(); this._player.play();
// Add an event listener to the overlay // Add an event listener to the overlay
this._overlay.addEventListener('click', this._handleOverlayClick); this._overlay.addEventListener('click', () => {
this.close();
});
} }
/** /**
@@ -378,13 +388,14 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Once the animation is done... // Once the animation is done...
this._player.onDone(() => { this._player.onDone(() => {
// If the overlay still exists... // Destroy the player
this._player.destroy();
this._player = null;
// If the backdrop still exists...
if ( this._overlay ) if ( this._overlay )
{ {
// Remove the event listener // Remove the backdrop
this._overlay.removeEventListener('click', this._handleOverlayClick);
// Remove the overlay
this._overlay.parentNode.removeChild(this._overlay); this._overlay.parentNode.removeChild(this._overlay);
this._overlay = null; this._overlay = null;
} }

View File

@@ -5,6 +5,7 @@ import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
@Component({ @Component({
selector : 'fuse-masonry', selector : 'fuse-masonry',
templateUrl : './masonry.component.html', templateUrl : './masonry.component.html',
styleUrls : ['./masonry.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
animations : fuseAnimations, animations : fuseAnimations,
exportAs : 'fuseMasonry' exportAs : 'fuseMasonry'

View File

@@ -10,10 +10,6 @@
class="fuse-horizontal-navigation-item" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"> [matTooltip]="item.tooltip || ''">
@@ -49,10 +45,6 @@
class="fuse-horizontal-navigation-item" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''" [matTooltip]="item.tooltip || ''"

View File

@@ -1,4 +1,4 @@
import { IsActiveMatchOptions, Params, QueryParamsHandling } from '@angular/router'; import { IsActiveMatchOptions } from '@angular/router';
export interface FuseNavigationItem export interface FuseNavigationItem
{ {
@@ -17,10 +17,6 @@ export interface FuseNavigationItem
disabled?: boolean; disabled?: boolean;
tooltip?: string; tooltip?: string;
link?: string; link?: string;
fragment?: string;
preserveFragment?: boolean;
queryParams?: Params | null;
queryParamsHandling?: QueryParamsHandling | null;
externalLink?: boolean; externalLink?: boolean;
target?: target?:
| '_blank' | '_blank'

View File

@@ -10,10 +10,6 @@
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''"> [matTooltip]="item.tooltip || ''">
@@ -49,10 +45,6 @@
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[fragment]="item.fragment ?? null"
[preserveFragment]="item.preserveFragment ?? false"
[queryParams]="item.queryParams ?? null"
[queryParamsHandling]="item.queryParamsHandling ?? null"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="isActiveMatchOptions"
[matTooltip]="item.tooltip || ''" [matTooltip]="item.tooltip || ''"

View File

@@ -48,12 +48,10 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-vertical-navigation-item-collapsed': this.isCollapsed, 'fuse-vertical-navigation-item-collapsed': this.isCollapsed,
'fuse-vertical-navigation-item-expanded' : this.isExpanded 'fuse-vertical-navigation-item-expanded' : this.isExpanded
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

View File

@@ -1,22 +1,20 @@
/* Variables */ /* Variables */
:root { $fuse-vertical-navigation-compact-width: 112px;
--fuse-vertical-navigation-compact-width: 112px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
/* Compact appearance overrides */ /* Compact appearance overrides */
&.fuse-vertical-navigation-appearance-compact { &.fuse-vertical-navigation-appearance-compact {
width: var(--fuse-vertical-navigation-compact-width); width: $fuse-vertical-navigation-compact-width;
min-width: var(--fuse-vertical-navigation-compact-width); min-width: $fuse-vertical-navigation-compact-width;
max-width: var(--fuse-vertical-navigation-compact-width); max-width: $fuse-vertical-navigation-compact-width;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-compact-width) * -1); margin-left: -$fuse-vertical-navigation-compact-width;
} }
/* Opened */ /* Opened */
@@ -30,7 +28,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-compact-width) * -1); margin-right: -$fuse-vertical-navigation-compact-width;
} }
/* Opened */ /* Opened */
@@ -41,7 +39,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: var(--fuse-vertical-navigation-compact-width); right: $fuse-vertical-navigation-compact-width;
} }
} }
@@ -106,7 +104,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-compact-width); left: $fuse-vertical-navigation-compact-width;
} }
} }
} }

View File

@@ -1,7 +1,5 @@
/* Variables */ /* Variables */
:root { $fuse-vertical-navigation-width: 280px;
--fuse-vertical-navigation-width: 280px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
position: sticky; position: sticky;
@@ -9,9 +7,9 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
flex: 1 0 auto; flex: 1 0 auto;
top: 0; top: 0;
width: var(--fuse-vertical-navigation-width); width: $fuse-vertical-navigation-width;
min-width: var(--fuse-vertical-navigation-width); min-width: $fuse-vertical-navigation-width;
max-width: var(--fuse-vertical-navigation-width); max-width: $fuse-vertical-navigation-width;
height: 100vh; height: 100vh;
min-height: 100vh; min-height: 100vh;
max-height: 100vh; max-height: 100vh;
@@ -47,7 +45,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: calc(#{var(--fuse-vertical-navigation-width)} * -1); margin-left: -$fuse-vertical-navigation-width;
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-left: 0; margin-left: 0;
@@ -75,7 +73,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-width) * -1); margin-right: -$fuse-vertical-navigation-width;
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-right: 0; margin-right: 0;
@@ -172,8 +170,8 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: var(--fuse-vertical-navigation-width); left: $fuse-vertical-navigation-width;
width: var(--fuse-vertical-navigation-width); width: $fuse-vertical-navigation-width;
height: 100%; height: 100%;
z-index: 5; z-index: 5;
overflow-x: hidden; overflow-x: hidden;
@@ -198,7 +196,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: var(--fuse-vertical-navigation-width); right: $fuse-vertical-navigation-width;
} }
} }
@@ -337,10 +335,7 @@ fuse-vertical-navigation {
} }
> .fuse-vertical-navigation-item-children { > .fuse-vertical-navigation-item-children {
margin-top: 6px;
> *:first-child {
margin-top: 6px;
}
> *:last-child { > *:last-child {
padding-bottom: 6px; padding-bottom: 6px;

View File

@@ -1,8 +1,6 @@
/* Variables */ /* Variables */
:root { $fuse-vertical-navigation-width: 280px;
--fuse-vertical-navigation-width: 280px; $fuse-vertical-navigation-dense-width: 80px;
--fuse-vertical-navigation-dense-width: 80px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
@@ -10,16 +8,16 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-appearance-dense { &.fuse-vertical-navigation-appearance-dense {
&:not(.fuse-vertical-navigation-mode-over) { &:not(.fuse-vertical-navigation-mode-over) {
width: var(--fuse-vertical-navigation-dense-width); width: $fuse-vertical-navigation-dense-width;
min-width: var(--fuse-vertical-navigation-dense-width); min-width: $fuse-vertical-navigation-dense-width;
max-width: var(--fuse-vertical-navigation-dense-width); max-width: $fuse-vertical-navigation-dense-width;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-dense-width) * -1); margin-left: -$fuse-vertical-navigation-dense-width;
} }
/* Opened */ /* Opened */
@@ -33,7 +31,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-dense-width) * -1); margin-right: -$fuse-vertical-navigation-dense-width;
} }
/* Opened */ /* Opened */
@@ -44,14 +42,14 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: var(--fuse-vertical-navigation-dense-width); right: $fuse-vertical-navigation-dense-width;
} }
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: var(--fuse-vertical-navigation-width); right: $fuse-vertical-navigation-width;
} }
} }
} }
@@ -71,9 +69,9 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: calc(var(--fuse-vertical-navigation-dense-width) - 24px); width: $fuse-vertical-navigation-dense-width - 24px;
min-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px); min-width: $fuse-vertical-navigation-dense-width - 24px;
max-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px); max-width: $fuse-vertical-navigation-dense-width - 24px;
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -144,23 +142,23 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-dense-width); left: $fuse-vertical-navigation-dense-width;
} }
/* Hover */ /* Hover */
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-wrapper { .fuse-vertical-navigation-wrapper {
width: var(--fuse-vertical-navigation-width); width: $fuse-vertical-navigation-width;
.fuse-vertical-navigation-content { .fuse-vertical-navigation-content {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: calc(var(--fuse-vertical-navigation-width) - 24px); width: $fuse-vertical-navigation-width - 24px;
min-width: calc(var(--fuse-vertical-navigation-width) - 24px); min-width: $fuse-vertical-navigation-width - 24px;
max-width: calc(var(--fuse-vertical-navigation-width) - 24px); max-width: $fuse-vertical-navigation-width - 24px;
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -175,7 +173,7 @@ fuse-vertical-navigation {
} }
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-width); left: $fuse-vertical-navigation-width;
} }
} }
} }

View File

@@ -1,21 +1,19 @@
/* Variables */ /* Variables */
:root { $fuse-vertical-navigation-thin-width: 80px;
--fuse-vertical-navigation-thin-width: 80px;
}
fuse-vertical-navigation { fuse-vertical-navigation {
/* Thin appearance overrides */ /* Thin appearance overrides */
&.fuse-vertical-navigation-appearance-thin { &.fuse-vertical-navigation-appearance-thin {
width: var(--fuse-vertical-navigation-thin-width); width: $fuse-vertical-navigation-thin-width;
min-width: var(--fuse-vertical-navigation-thin-width); min-width: $fuse-vertical-navigation-thin-width;
max-width: var(--fuse-vertical-navigation-thin-width); max-width: $fuse-vertical-navigation-thin-width;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: calc(var(--fuse-vertical-navigation-thin-width) * -1); margin-left: -$fuse-vertical-navigation-thin-width;
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -27,7 +25,7 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-position-right { &.fuse-vertical-navigation-position-right {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: calc(var(--fuse-vertical-navigation-thin-width) * -1); margin-right: -$fuse-vertical-navigation-thin-width;
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -36,7 +34,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: var(--fuse-vertical-navigation-thin-width); right: $fuse-vertical-navigation-thin-width;
} }
} }
@@ -93,7 +91,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: var(--fuse-vertical-navigation-thin-width); left: $fuse-vertical-navigation-thin-width;
} }
} }
} }

View File

@@ -1,4 +1,4 @@
@use 'styles/appearances/default'; @import 'styles/appearances/default';
@use 'styles/appearances/compact'; @import 'styles/appearances/compact';
@use 'styles/appearances/dense'; @import 'styles/appearances/dense';
@use 'styles/appearances/thin'; @import 'styles/appearances/thin';

View File

@@ -1,6 +1,5 @@
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Inject, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { DOCUMENT } from '@angular/common';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay'; import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs'; import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs';
@@ -52,7 +51,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
private readonly _handleAsideOverlayClick: any; private readonly _handleAsideOverlayClick: any;
private readonly _handleOverlayClick: any; private readonly _handleOverlayClick: any;
private _hovered: boolean = false; private _hovered: boolean = false;
private _mutationObserver: MutationObserver;
private _overlay: HTMLElement; private _overlay: HTMLElement;
private _player: AnimationPlayer; private _player: AnimationPlayer;
private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block(); private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
@@ -66,7 +64,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
constructor( constructor(
private _animationBuilder: AnimationBuilder, private _animationBuilder: AnimationBuilder,
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
@Inject(DOCUMENT) private _document: Document,
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _router: Router, private _router: Router,
@@ -92,7 +89,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
@HostBinding('class') get classList(): any @HostBinding('class') get classList(): any
{ {
/* eslint-disable @typescript-eslint/naming-convention */
return { return {
'fuse-vertical-navigation-animations-enabled' : this._animationsEnabled, 'fuse-vertical-navigation-animations-enabled' : this._animationsEnabled,
[`fuse-vertical-navigation-appearance-${this.appearance}`]: true, [`fuse-vertical-navigation-appearance-${this.appearance}`]: true,
@@ -104,7 +100,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
'fuse-vertical-navigation-position-left' : this.position === 'left', 'fuse-vertical-navigation-position-left' : this.position === 'left',
'fuse-vertical-navigation-position-right' : this.position === 'right' 'fuse-vertical-navigation-position-right' : this.position === 'right'
}; };
/* eslint-enable @typescript-eslint/naming-convention */
} }
/** /**
@@ -333,34 +328,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
ngAfterViewInit(): void ngAfterViewInit(): void
{ {
// Fix for Firefox.
//
// Because 'position: sticky' doesn't work correctly inside a 'position: fixed' parent,
// adding the '.cdk-global-scrollblock' to the html element breaks the navigation's position.
// This fixes the problem by reading the 'top' value from the html element and adding it as a
// 'marginTop' to the navigation itself.
this._mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const mutationTarget = mutation.target as HTMLElement;
if ( mutation.attributeName === 'class' )
{
if ( mutationTarget.classList.contains('cdk-global-scrollblock') )
{
const top = parseInt(mutationTarget.style.top, 10);
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', `${Math.abs(top)}px`);
}
else
{
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', null);
}
}
});
});
this._mutationObserver.observe(this._document.documentElement, {
attributes : true,
attributeFilter: ['class']
});
setTimeout(() => { setTimeout(() => {
// Return if 'navigation content' element does not exist // Return if 'navigation content' element does not exist
@@ -406,9 +373,6 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Disconnect the mutation observer
this._mutationObserver.disconnect();
// Forcefully close the navigation and aside in case they are opened // Forcefully close the navigation and aside in case they are opened
this.close(); this.close();
this.closeAside(); this.closeAside();

View File

@@ -4,7 +4,6 @@ import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseConfirmationModule } from '@fuse/services/confirmation'; import { FuseConfirmationModule } from '@fuse/services/confirmation';
import { FuseLoadingModule } from '@fuse/services/loading'; import { FuseLoadingModule } from '@fuse/services/loading';
import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module'; import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module';
import { FusePlatformModule } from '@fuse/services/platform/platform.module';
import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module'; import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module';
import { FuseUtilsModule } from '@fuse/services/utils/utils.module'; import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@@ -13,7 +12,6 @@ import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
FuseConfirmationModule, FuseConfirmationModule,
FuseLoadingModule, FuseLoadingModule,
FuseMediaWatcherModule, FuseMediaWatcherModule,
FusePlatformModule,
FuseSplashScreenModule, FuseSplashScreenModule,
FuseUtilsModule FuseUtilsModule
], ],

View File

@@ -35,7 +35,6 @@ export class FuseConfigService
this._config.next(config); this._config.next(config);
} }
// eslint-disable-next-line @typescript-eslint/member-ordering
get config$(): Observable<any> get config$(): Observable<any>
{ {
return this._config.asObservable(); return this._config.asObservable();

View File

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

View File

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

View File

@@ -1,17 +0,0 @@
import { NgModule } from '@angular/core';
import { FusePlatformService } from '@fuse/services/platform/platform.service';
@NgModule({
providers: [
FusePlatformService
]
})
export class FusePlatformModule
{
/**
* Constructor
*/
constructor(private _fusePlatformService: FusePlatformService)
{
}
}

View File

@@ -1,59 +0,0 @@
import { Injectable } from '@angular/core';
import { Platform } from '@angular/cdk/platform';
@Injectable({
providedIn: 'root'
})
export class FusePlatformService
{
osName = 'os-unknown';
/**
* Constructor
*/
constructor(private _platform: Platform)
{
// If the platform is not a browser, return immediately
if ( !this._platform.isBrowser )
{
return;
}
// Windows
if ( navigator.userAgent.includes('Win') )
{
this.osName = 'os-windows';
}
// Mac OS
if ( navigator.userAgent.includes('Mac') )
{
this.osName = 'os-mac';
}
// Unix
if ( navigator.userAgent.includes('X11') )
{
this.osName = 'os-unix';
}
// Linux
if ( navigator.userAgent.includes('Linux') )
{
this.osName = 'os-linux';
}
// iOS
if ( this._platform.IOS )
{
this.osName = 'os-ios';
}
// Android
if ( this._platform.ANDROID )
{
this.osName = 'os-android';
}
}
}

View File

@@ -1 +0,0 @@
export * from '@fuse/services/platform/platform.service';

View File

@@ -1,9 +1,9 @@
/* 1. Components */ /* 1. Components */
@use 'components/example-viewer'; @import 'components/example-viewer';
@use 'components/input'; @import 'components/input';
/* 2. Overrides */ /* 2. Overrides */
@use 'overrides/angular-material'; @import 'overrides/angular-material';
@use 'overrides/highlightjs'; @import 'overrides/highlightjs';
@use 'overrides/perfect-scrollbar'; @import 'overrides/perfect-scrollbar';
@use 'overrides/quill'; @import 'overrides/quill';

File diff suppressed because it is too large Load Diff

View File

@@ -80,9 +80,7 @@
} }
.ql-container { .ql-container {
overflow: auto; overflow: hidden;
min-height: 160px;
max-height: 400px;
border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px;
@apply border-gray-300 border-opacity-100 shadow-sm #{'!important'}; @apply border-gray-300 border-opacity-100 shadow-sm #{'!important'};
@@ -91,52 +89,17 @@
} }
.ql-editor { .ql-editor {
min-height: 160px;
max-height: 160px;
height: 160px;
@apply bg-card; @apply bg-card;
.dark & { .dark & {
//background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
} }
&.ql-blank::before { &.ql-blank::before {
@apply text-hint; @apply text-hint;
} }
} }
.ql-tooltip {
@apply px-3 py-1 shadow-sm rounded-md bg-gray-100 border-gray-300;
.dark & {
@apply shadow-lg bg-gray-700 border-gray-700 #{'!important'};
}
// Label
&:before {
@apply text-secondary;
}
.ql-action,
.ql-remove {
@apply text-primary border-gray-300;
.dark & {
@apply text-primary-400 border-gray-300;
}
}
.ql-action:after {
@apply border-r border-r-gray-300 #{'!important'};
.dark & {
@apply border-r-gray-500 #{'!important'};
}
}
input {
@apply rounded-sm text-default bg-white border-gray-300 #{'!important'};
.dark & {
@apply bg-gray-700 border-gray-500 #{'!important'};
}
}
}
} }

View File

@@ -63,15 +63,11 @@
-webkit-text-fill-color: currentColor; -webkit-text-fill-color: currentColor;
} }
/* Set the background and foreground colors */
body, .dark, .light { body, .dark, .light {
@apply text-default bg-default #{'!important'}; @apply text-default bg-default #{'!important'};
} }
/* Set the border color */ *, *::before, *::after {
*,
::before,
::after {
--tw-border-opacity: 1 !important; --tw-border-opacity: 1 !important;
border-color: rgba(var(--fuse-border-rgb), var(--tw-border-opacity)); border-color: rgba(var(--fuse-border-rgb), var(--tw-border-opacity));
@@ -80,47 +76,6 @@
} }
} }
/* Style scrollbars on platforms other than MacOS and iOS */
@media only screen and (min-width: 960px) {
body:not(.os-mac) {
::-webkit-scrollbar {
width: 8px;
height: 8px;
background-color: rgba(0, 0, 0, 0);
}
::-webkit-scrollbar:hover {
width: 8px;
height: 8px;
background-color: rgba(0, 0, 0, 0.06);
}
::-webkit-scrollbar-thumb {
border: 2px solid transparent;
border-radius: 20px;
box-shadow: inset 0 0 0 20px rgba(0, 0, 0, 0.24);
}
::-webkit-scrollbar-thumb:active {
border-radius: 20px;
box-shadow: inset 0 0 0 20px rgba(0, 0, 0, 0.37);
}
&.dark {
::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 0 20px rgba(255, 255, 255, 0.24);
}
::-webkit-scrollbar-thumb:active {
box-shadow: inset 0 0 0 20px rgba(255, 255, 255, 0.37);
}
}
}
}
/* Set the foreground color for disabled elements */
[disabled] * { [disabled] * {
@apply text-disabled #{'!important'}; @apply text-disabled #{'!important'};
} }

View File

@@ -1,164 +1,167 @@
@use "sass:map";
@use '@angular/material' as mat; @use '@angular/material' as mat;
@use "user-themes" as userThemes; @use "sass:map";
/* Set the base colors for light themes */
$light-base: (
foreground: (
base: #000000,
divider: #E2E8F0, /* slate.200 */
dividers: #E2E8F0, /* slate.200 */
disabled: #94A3B8, /* slate.400 */
disabled-button: #94A3B8, /* slate.400 */
disabled-text: #94A3B8, /* slate.400 */
elevation: #000000,
hint-text: #94A3B8, /* slate.400 */
secondary-text: #64748B, /* slate.500 */
icon: #64748B, /* slate.500 */
icons: #64748B, /* slate.500 */
mat-icon: #64748B, /* slate.500 */
text: #1E293B, /* slate.800 */
slider-min: #1E293B, /* slate.800 */
slider-off: #CBD5E1, /* slate.300 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #CBD5E1, /* slate.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* slate.100 */
hover: rgba(148, 163, 184, 0.12), /* slate.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* slate.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* slate.500 */
selected-button: #E2E8F0, /* slate.200 */
selected-disabled-button: #E2E8F0, /* slate.200 */
disabled-button-toggle: #CBD5E1, /* slate.300 */
unselected-chip: #E2E8F0, /* slate.200 */
disabled-list-option: #CBD5E1, /* slate.300 */
tooltip: #1E293B /* slate.800 */
)
);
/* Set the base colors for dark themes */
$dark-base: (
foreground: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */
disabled: #475569, /* slate.600 */
disabled-button: #1E293B, /* slate.800 */
disabled-text: #475569, /* slate.600 */
elevation: #000000,
hint-text: #64748B, /* slate.500 */
secondary-text: #94A3B8, /* slate.400 */
icon: #F1F5F9, /* slate.100 */
icons: #F1F5F9, /* slate.100 */
mat-icon: #94A3B8, /* slate.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* slate.500 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #0F172A, /* slate.900 */
app-bar: #0F172A, /* slate.900 */
background: #0F172A, /* slate.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* slate.800 */
dialog: #1E293B, /* slate.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* slate.900 + opacity */
raised-button: #0F172A, /* slate.900 */
focused-button: #E2E8F0, /* slate.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* slate.800 */
disabled-button-toggle: #0F172A, /* slate.900 */
unselected-chip: #475569, /* slate.600 */
disabled-list-option: #E2E8F0, /* slate.200 */
tooltip: #64748B /* slate.500 */
)
);
/* Include the core Angular Material styles */ /* Include the core Angular Material styles */
@include mat.core(); @include mat.core();
/* Create a base theme without any color to set the density and typography */ /* Create a base theme without color.
This will globally set the density and typography for all future color themes. */
@include mat.all-component-themes(( @include mat.all-component-themes((
color: null, color: null,
density: 0, density: -2,
typography: mat.define-typography-config( typography: mat.define-typography-config(
$font-family: theme('fontFamily.sans'), $font-family: theme('fontFamily.sans'),
$headline-1: mat.define-typography-level(1.875rem, 2.25rem, 800, theme('fontFamily.sans')), $title: mat.define-typography-level(1.25rem, 2rem, 600),
$headline-2: mat.define-typography-level(1.25rem, 1.75rem, 700, theme('fontFamily.sans')), $body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$headline-3: mat.define-typography-level(1.125rem, 1.75rem, 600, theme('fontFamily.sans')), $button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$headline-4: mat.define-typography-level(0.875rem, 1.25rem, 600, theme('fontFamily.sans')), $input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
$headline-5: mat.define-typography-level(0.875rem, 1.5rem, 400, theme('fontFamily.sans')),
$headline-6: mat.define-typography-level(0.875rem, 1.5rem, 400, theme('fontFamily.sans')),
$subtitle-1: mat.define-typography-level(1rem, 1.75rem, 400, theme('fontFamily.sans')),
$subtitle-2: mat.define-typography-level(0.875rem, 1.25rem, 600, theme('fontFamily.sans')),
$body-1: mat.define-typography-level(0.875rem, 1.5rem, 400, theme('fontFamily.sans')),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 400, theme('fontFamily.sans')),
$caption: mat.define-typography-level(0.75rem, 1rem, 400, theme('fontFamily.sans')),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500, theme('fontFamily.sans')),
$overline: mat.define-typography-level(0.75rem, 2rem, 500, theme('fontFamily.sans'))
) )
)); ));
/* Loop through user themes and generate Angular Material themes */ /* Generate Primary, Accent and Warn palettes */
@each $name, $theme in userThemes.$user-themes { $palettes: ();
@each $name in (primary, accent, warn) {
/* Generate the palettes */ $palettes: map.merge($palettes, (#{$name}: (
$palettes: (); 50: var(--fuse-#{$name}-50),
@each $name in (primary, accent, warn) { 100: var(--fuse-#{$name}-100),
200: var(--fuse-#{$name}-200),
/* Define the Angular Material theme */ 300: var(--fuse-#{$name}-300),
$palette: mat.define-palette(map.get($theme, $name)); 400: var(--fuse-#{$name}-400),
500: var(--fuse-#{$name}-500),
/* Replace the default colors on the defined Material palette */ 600: var(--fuse-#{$name}-600),
$palette: map.merge($palette, ( 700: var(--fuse-#{$name}-700),
default: map.get(map.get($theme, $name), DEFAULT), 800: var(--fuse-#{$name}-800),
lighter: map.get(map.get($theme, $name), 100), 900: var(--fuse-#{$name}-900),
darker: map.get(map.get($theme, $name), 700), contrast: (
text: map.get(map.get($theme, $name), DEFAULT), 50: var(--fuse-on-#{$name}-50),
default-contrast: map.get(map.get(map.get($theme, $name), contrast), DEFAULT), 100: var(--fuse-on-#{$name}-100),
lighter-contrast: map.get(map.get(map.get($theme, $name), contrast), 100), 200: var(--fuse-on-#{$name}-200),
darker-contrast: map.get(map.get(map.get($theme, $name), contrast), 700) 300: var(--fuse-on-#{$name}-300),
)); 400: var(--fuse-on-#{$name}-400),
500: var(--fuse-on-#{$name}-500),
$palettes: map.merge($palettes, (#{$name}: $palette)); 600: var(--fuse-on-#{$name}-600),
} 700: var(--fuse-on-#{$name}-700),
800: var(--fuse-on-#{$name}-800),
/* Define a light & dark Angular Material theme with the generated palettes */ 900: var(--fuse-on-#{$name}-900)
$light-theme: mat.define-light-theme(( ),
color: ($palettes) default: var(--fuse-#{$name}),
)); lighter: var(--fuse-#{$name}-100),
darker: var(--fuse-#{$name}-700),
$dark-theme: mat.define-dark-theme(( text: var(--fuse-#{$name}),
color: ($palettes) default-contrast: var(--fuse-on-#{$name}),
)); lighter-contrast: var(--fuse-on-#{$name}-100),
darker-contrast: var(--fuse-on-#{$name}-700)
/* Merge the custom base colors with the generated themes */ )));
$light-theme-colors: map.merge(map.get($light-theme, color), $light-base); }
$light-theme: map.merge(
(color: $light-theme-colors), /* Generate Angular Material themes. Since we are using CSS Custom Properties,
$light-theme-colors we don't have to generate a separate Angular Material theme for each color
); set. We can just create one light and one dark theme and then switch the
CSS Custom Properties to dynamically switch the colors. */
$dark-theme-colors: map.merge(map.get($dark-theme, color), $dark-base); body.light,
$dark-theme: map.merge( body .light {
(color: $dark-theme-colors), $base-light-theme: mat.define-light-theme((
$dark-theme-colors color: ($palettes)
); ));
/* Generate and encapsulate Angular Material themes */ $light-theme: (
#{map.get($theme, selector)} .light, color: (
#{map.get($theme, selector)}.light { primary: map.get(map.get($base-light-theme, color), primary),
@include mat.all-component-colors($light-theme); 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),
#{map.get($theme, selector)} .dark, foreground: (
#{map.get($theme, selector)}.dark { base: #000000,
@include mat.all-component-colors($dark-theme); divider: #E2E8F0, /* slate.200 */
} dividers: #E2E8F0, /* slate.200 */
disabled: #94A3B8, /* slate.400 */
disabled-button: #94A3B8, /* slate.400 */
disabled-text: #94A3B8, /* slate.400 */
elevation: #000000,
hint-text: #94A3B8, /* slate.400 */
secondary-text: #64748B, /* slate.500 */
icon: #64748B, /* slate.500 */
icons: #64748B, /* slate.500 */
mat-icon: #64748B, /* slate.500 */
text: #1E293B, /* slate.800 */
slider-min: #1E293B, /* slate.800 */
slider-off: #CBD5E1, /* slate.300 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #CBD5E1, /* slate.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* slate.100 */
hover: rgba(148, 163, 184, 0.12), /* slate.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* slate.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* slate.500 */
selected-button: #E2E8F0, /* slate.200 */
selected-disabled-button: #E2E8F0, /* slate.200 */
disabled-button-toggle: #CBD5E1, /* slate.300 */
unselected-chip: #E2E8F0, /* slate.200 */
disabled-list-option: #CBD5E1, /* slate.300 */
tooltip: #1E293B /* slate.800 */
)
)
);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($light-theme);
}
body.dark,
body .dark {
$base-dark-theme: mat.define-dark-theme((
color: ($palettes)
));
$dark-theme: (
color: (
primary: map.get(map.get($base-dark-theme, color), primary),
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: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */
disabled: #475569, /* slate.600 */
disabled-button: #1E293B, /* slate.800 */
disabled-text: #475569, /* slate.600 */
elevation: #000000,
hint-text: #64748B, /* slate.500 */
secondary-text: #94A3B8, /* slate.400 */
icon: #F1F5F9, /* slate.100 */
icons: #F1F5F9, /* slate.100 */
mat-icon: #94A3B8, /* slate.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* slate.500 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #0F172A, /* slate.900 */
app-bar: #0F172A, /* slate.900 */
background: #0F172A, /* slate.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* slate.800 */
dialog: #1E293B, /* slate.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* slate.900 + opacity */
raised-button: #0F172A, /* slate.900 */
focused-button: #E2E8F0, /* slate.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* slate.800 */
disabled-button-toggle: #0F172A, /* slate.900 */
unselected-chip: #475569, /* slate.600 */
disabled-list-option: #E2E8F0, /* slate.200 */
tooltip: #64748B /* slate.500 */
)
)
);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($dark-theme);
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,21 +1,17 @@
const chroma = require('chroma-js'); const chroma = require('chroma-js');
const _ = require('lodash'); const _ = require('lodash');
const fs = require('fs');
const path = require('path'); const path = require('path');
const colors = require('tailwindcss/colors'); const colors = require('tailwindcss/colors');
const plugin = require('tailwindcss/plugin'); const plugin = require('tailwindcss/plugin');
const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default; const flattenColorPalette = require('tailwindcss/lib/util/flattenColorPalette').default;
const generateContrasts = require(path.resolve(__dirname, ('../utils/generate-contrasts'))); const generateContrasts = require(path.resolve(__dirname, ('../utils/generate-contrasts')));
const jsonToSassMap = require(path.resolve(__dirname, ('../utils/json-to-sass-map')));
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Utilities // @ Utilities
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
/** /**
* Normalizes the provided theme by omitting empty values and values that * Normalize the provided theme
* start with "on" from each palette. Also sets the correct DEFAULT value
* of each palette.
* *
* @param theme * @param theme
*/ */
@@ -32,6 +28,67 @@ const normalizeTheme = (theme) =>
)); ));
}; };
/**
* Generates variable colors for the 'colors'
* configuration from the provided theme
*
* @param theme
*/
const generateVariableColors = (theme) =>
{
// https://github.com/adamwathan/tailwind-css-variable-text-opacity-demo
const customPropertiesWithOpacity = (name) => ({
opacityVariable,
opacityValue
}) =>
{
if ( opacityValue )
{
return `rgba(var(--fuse-${name}-rgb), ${opacityValue})`;
}
if ( opacityVariable )
{
return `rgba(var(--fuse-${name}-rgb), var(${opacityVariable}, 1))`;
}
return `rgb(var(--fuse-${name}-rgb))`;
};
return _.fromPairs(_.flatten(_.map(_.keys(flattenColorPalette(normalizeTheme(theme))), (name) => [
[name, customPropertiesWithOpacity(name)],
[`on-${name}`, customPropertiesWithOpacity(`on-${name}`)]
])));
};
/**
* Generate and return themes object with theme name and colors/
* This is useful for accessing themes from Angular (Typescript).
*
* @param themes
* @returns {unknown[]}
*/
function generateThemesObject(themes)
{
const normalizedDefaultTheme = normalizeTheme(themes.default);
return _.map(_.cloneDeep(themes), (value, key) =>
{
const theme = normalizeTheme(value);
const primary = (theme && theme.primary && theme.primary.DEFAULT) ? theme.primary.DEFAULT : normalizedDefaultTheme.primary.DEFAULT;
const accent = (theme && theme.accent && theme.accent.DEFAULT) ? theme.accent.DEFAULT : normalizedDefaultTheme.accent.DEFAULT;
const warn = (theme && theme.warn && theme.warn.DEFAULT) ? theme.warn.DEFAULT : normalizedDefaultTheme.warn.DEFAULT;
return _.fromPairs([
[
key,
{
primary,
accent,
warn
}
]
]);
});
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ FUSE TailwindCSS Main Plugin // @ FUSE TailwindCSS Main Plugin
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -41,113 +98,29 @@ const theming = plugin.withOptions((options) => ({
theme theme
}) => }) =>
{ {
/** // -----------------------------------------------------------------------------------------------------
* Create user themes object by going through the provided themes and // @ Map variable colors
* merging them with the provided "default" so, we can have a complete // -----------------------------------------------------------------------------------------------------
* set of color palettes for each user theme. const mapVariableColors = _.fromPairs(_.map(options.themes, (theme, themeName) => [
*/ themeName === 'default' ? 'body, .theme-default' : `.theme-${e(themeName)}`,
const userThemes = _.fromPairs(_.map(options.themes, (theme, themeName) => [ _.fromPairs(_.flatten(_.map(flattenColorPalette(_.fromPairs(_.flatten(_.map(normalizeTheme(theme), (palette, paletteName) => [
themeName, [
_.defaults({}, theme, options.themes['default']) e(paletteName),
palette
],
[
`on-${e(paletteName)}`,
_.fromPairs(_.map(generateContrasts(palette), (color, hue) => [hue, _.get(theme, [`on-${paletteName}`, hue]) || color]))
]
])
))), (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]])))
])); ]));
/** addComponents(mapVariableColors);
* Normalize the themes and assign it to the themes object. This will
* be the final object that we create a SASS map from
*/
let themes = _.fromPairs(_.map(userThemes, (theme, themeName) => [
themeName,
normalizeTheme(theme)
]));
/** // -----------------------------------------------------------------------------------------------------
* Go through the themes to generate the contrasts and filter the // @ Generate scheme based css custom properties and utility classes
* palettes to only have "primary", "accent" and "warn" objects. // -----------------------------------------------------------------------------------------------------
*/
themes = _.fromPairs(_.map(themes, (theme, themeName) => [
themeName,
_.pick(
_.fromPairs(_.map(theme, (palette, paletteName) => [
paletteName,
{
...palette,
contrast: _.fromPairs(_.map(generateContrasts(palette), (color, hue) => [
hue,
_.get(userThemes[themeName], [`on-${paletteName}`, hue]) || color
]))
}
])),
['primary', 'accent', 'warn']
)
]));
/**
* Go through the themes and attach appropriate class selectors so,
* we can use them to encapsulate each theme.
*/
themes = _.fromPairs(_.map(themes, (theme, themeName) => [
themeName,
{
selector: `".theme-${themeName}"`,
...theme
}
]));
/* Generate the SASS map using the themes object */
const sassMap = jsonToSassMap(JSON.stringify({'user-themes': themes}));
/* Get the file path */
const filename = path.resolve(__dirname, ('../../styles/user-themes.scss'));
/* Read the file and get its data */
let data;
try
{
data = fs.readFileSync(filename, {encoding: 'utf8'});
}
catch ( err )
{
console.error(err);
}
/* Write the file if the map has been changed */
if ( data !== sassMap )
{
try
{
fs.writeFileSync(filename, sassMap, {encoding: 'utf8'});
}
catch ( err )
{
console.error(err);
}
}
/**
* Iterate through the user's themes and build Tailwind components containing
* CSS Custom Properties using the colors from them. This allows switching
* themes by simply replacing a class name as well as nesting them.
*/
addComponents(
_.fromPairs(_.map(options.themes, (theme, themeName) => [
themeName === 'default' ? 'body, .theme-default' : `.theme-${e(themeName)}`,
_.fromPairs(_.flatten(_.map(flattenColorPalette(_.fromPairs(_.flatten(_.map(normalizeTheme(theme), (palette, paletteName) => [
[
e(paletteName),
palette
],
[
`on-${e(paletteName)}`,
_.fromPairs(_.map(generateContrasts(palette), (color, hue) => [hue, _.get(theme, [`on-${paletteName}`, hue]) || color]))
]
])
))), (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]])))
]))
);
/**
* Generate scheme based css custom properties and utility classes
*/
const schemeCustomProps = _.map(['light', 'dark'], (colorScheme) => const schemeCustomProps = _.map(['light', 'dark'], (colorScheme) =>
{ {
const isDark = colorScheme === 'dark'; const isDark = colorScheme === 'dark';
@@ -162,13 +135,13 @@ const theming = plugin.withOptions((options) => ({
/** /**
* If a custom property is not available, browsers will use * If a custom property is not available, browsers will use
* the fallback value. In this case, we want to use '--is-dark' * the fallback value. In this case, we want to use '--is-dark'
* as the indicator of a dark theme so, we can use it like this: * as the indicator of a dark theme so we can use it like this:
* background-color: var(--is-dark, red); * background-color: var(--is-dark, red);
* *
* If we set '--is-dark' as "true" on dark themes, the above rule * If we set '--is-dark' as "true" on dark themes, the above rule
* won't work because of the said "fallback value" logic. Therefore, * won't work because of the said "fallback value" logic. Therefore,
* we set the '--is-dark' to "false" on light themes and not set it * we set the '--is-dark' to "false" on light themes and not set it
* at all on dark themes so that the fallback value can be used on * all on dark themes so that the fallback value can be used on
* dark themes. * dark themes.
* *
* On light themes, since '--is-dark' exists, the above rule will be * On light themes, since '--is-dark' exists, the above rule will be
@@ -183,7 +156,7 @@ const theming = plugin.withOptions((options) => ({
*/ */
...(!isDark ? {'--is-dark': 'false'} : {}), ...(!isDark ? {'--is-dark': 'false'} : {}),
/* Generate custom properties from customProps */ // Generate custom properties from customProps
..._.fromPairs(_.flatten(_.map(background, (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]]))), ..._.fromPairs(_.flatten(_.map(background, (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]]))),
..._.fromPairs(_.flatten(_.map(foreground, (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]]))) ..._.fromPairs(_.flatten(_.map(foreground, (value, key) => [[`--fuse-${e(key)}`, value], [`--fuse-${e(key)}-rgb`, chroma(value).rgb().join(',')]])))
} }
@@ -192,7 +165,7 @@ const theming = plugin.withOptions((options) => ({
const schemeUtilities = (() => const schemeUtilities = (() =>
{ {
/* Generate general styles & utilities */ // Generate general styles & utilities
return {}; return {};
})(); })();
@@ -202,17 +175,9 @@ const theming = plugin.withOptions((options) => ({
(options) => (options) =>
{ {
return { return {
theme: { theme : {
extend: { extend: {
/** colors: generateVariableColors(options.themes.default)
* Add 'Primary', 'Accent' and 'Warn' palettes as colors so all color utilities
* are generated for them; "bg-primary", "text-on-primary", "bg-accent-600" etc.
* This will also allow using arbitrary values with them such as opacity and such.
*/
colors: _.fromPairs(_.flatten(_.map(_.keys(flattenColorPalette(normalizeTheme(options.themes.default))), (name) => [
[name, `rgba(var(--fuse-${name}-rgb), <alpha-value>)`],
[`on-${name}`, `rgba(var(--fuse-on-${name}-rgb), <alpha-value>)`]
])))
}, },
fuse : { fuse : {
customProps: { customProps: {
@@ -256,7 +221,8 @@ const theming = plugin.withOptions((options) => ({
'mat-icon' : colors.slate[400] 'mat-icon' : colors.slate[400]
} }
} }
} },
themes : generateThemesObject(options.themes)
} }
} }
}; };

View File

@@ -1,67 +0,0 @@
const _ = require('lodash');
module.exports = (data) =>
{
if ( !data )
{
return;
}
data = JSON.parse(data);
const getSCSS = (chunk) =>
{
let scss = '';
if ( typeof chunk === "object" && !Array.isArray(chunk) )
{
_.mapKeys(chunk, (value, key) =>
{
scss += key + ': ';
if ( typeof value === "object" )
{
if ( Array.isArray(value) )
{
scss += '(';
_.each(value, (val1) =>
{
if ( Array.isArray(val1) )
{
_.each(val1, (val2) =>
{
scss += val2 + ' ';
});
scss = scss.slice(0, -1) + ', ';
}
else
{
scss += val1 + ', ';
}
});
scss = scss.slice(0, -2);
scss += ')';
}
else
{
scss += '(' + getSCSS(value) + ')';
}
}
else
{
scss += getSCSS(value);
}
scss += ', ';
});
scss = scss.slice(0, -2);
}
else
{
scss += chunk;
}
return scss;
};
return '$' + getSCSS(data) + ';';
};

View File

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

View File

@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ExtraOptions, PreloadAllModules, RouterModule } from '@angular/router'; import { ExtraOptions, PreloadAllModules, RouterModule } from '@angular/router';
import { MarkdownModule } from 'ngx-markdown';
import { FuseModule } from '@fuse'; import { FuseModule } from '@fuse';
import { FuseConfigModule } from '@fuse/services/config'; import { FuseConfigModule } from '@fuse/services/config';
import { FuseMockApiModule } from '@fuse/lib/mock-api'; import { FuseMockApiModule } from '@fuse/lib/mock-api';
@@ -35,7 +36,10 @@ const routerConfig: ExtraOptions = {
CoreModule, CoreModule,
// Layout module of your application // Layout module of your application
LayoutModule LayoutModule,
// 3rd party modules that require global configuration via forRoot
MarkdownModule.forRoot({})
], ],
bootstrap : [ bootstrap : [
AppComponent AppComponent

View File

@@ -6,6 +6,7 @@ import { NavigationService } from 'app/core/navigation/navigation.service';
import { NotificationsService } from 'app/layout/common/notifications/notifications.service'; import { NotificationsService } from 'app/layout/common/notifications/notifications.service';
import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service'; import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service';
import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service'; import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service';
import { UserService } from 'app/core/user/user.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -20,7 +21,8 @@ export class InitialDataResolver implements Resolve<any>
private _navigationService: NavigationService, private _navigationService: NavigationService,
private _notificationsService: NotificationsService, private _notificationsService: NotificationsService,
private _quickChatService: QuickChatService, private _quickChatService: QuickChatService,
private _shortcutsService: ShortcutsService private _shortcutsService: ShortcutsService,
private _userService: UserService
) )
{ {
} }
@@ -43,7 +45,8 @@ export class InitialDataResolver implements Resolve<any>
this._messagesService.getAll(), this._messagesService.getAll(),
this._notificationsService.getAll(), this._notificationsService.getAll(),
this._quickChatService.getChats(), this._quickChatService.getChats(),
this._shortcutsService.getAll() this._shortcutsService.getAll(),
this._userService.get()
]); ]);
} }
} }

View File

@@ -9,15 +9,15 @@ import { InitialDataResolver } from 'app/app.resolvers';
/* eslint-disable @typescript-eslint/explicit-function-return-type */ /* eslint-disable @typescript-eslint/explicit-function-return-type */
export const appRoutes: Route[] = [ export const appRoutes: Route[] = [
// Redirect empty path to '/dashboards/project' // Redirect empty path to '/example'
{path: '', pathMatch : 'full', redirectTo: 'dashboards/project'}, {path: '', pathMatch : 'full', redirectTo: 'example'},
// Redirect signed in user to the '/dashboards/project' // Redirect signed in user to the '/example'
// //
// After the user signs in, the sign in page will redirect the user to the 'signed-in-redirect' // After the user signs in, the sign in page will redirect the user to the 'signed-in-redirect'
// path. Below is another redirection for that path to redirect the user to the desired // path. Below is another redirection for that path to redirect the user to the desired
// location. This is a small convenience to keep all main routes together here on this file. // location. This is a small convenience to keep all main routes together here on this file.
{path: 'signed-in-redirect', pathMatch : 'full', redirectTo: 'dashboards/project'}, {path: 'signed-in-redirect', pathMatch : 'full', redirectTo: 'example'},
// Auth routes for guests // Auth routes for guests
{ {
@@ -74,136 +74,7 @@ export const appRoutes: Route[] = [
initialData: InitialDataResolver, initialData: InitialDataResolver,
}, },
children : [ children : [
{path: 'example', loadChildren: () => import('app/modules/admin/example/example.module').then(m => m.ExampleModule)},
// Dashboards
{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
{path: 'apps', children: [
{path: 'academy', loadChildren: () => import('app/modules/admin/apps/academy/academy.module').then(m => m.AcademyModule)},
{path: 'chat', loadChildren: () => import('app/modules/admin/apps/chat/chat.module').then(m => m.ChatModule)},
{path: 'contacts', loadChildren: () => import('app/modules/admin/apps/contacts/contacts.module').then(m => m.ContactsModule)},
{path: 'ecommerce', loadChildren: () => import('app/modules/admin/apps/ecommerce/ecommerce.module').then(m => m.ECommerceModule)},
{path: 'file-manager', loadChildren: () => import('app/modules/admin/apps/file-manager/file-manager.module').then(m => m.FileManagerModule)},
{path: 'help-center', loadChildren: () => import('app/modules/admin/apps/help-center/help-center.module').then(m => m.HelpCenterModule)},
{path: 'mailbox', loadChildren: () => import('app/modules/admin/apps/mailbox/mailbox.module').then(m => m.MailboxModule)},
{path: 'notes', loadChildren: () => import('app/modules/admin/apps/notes/notes.module').then(m => m.NotesModule)},
{path: 'scrumboard', loadChildren: () => import('app/modules/admin/apps/scrumboard/scrumboard.module').then(m => m.ScrumboardModule)},
{path: 'tasks', loadChildren: () => import('app/modules/admin/apps/tasks/tasks.module').then(m => m.TasksModule)},
]},
// Pages
{path: 'pages', children: [
// Activities
{path: 'activities', loadChildren: () => import('app/modules/admin/pages/activities/activities.module').then(m => m.ActivitiesModule)},
// Authentication
{path: 'authentication', loadChildren: () => import('app/modules/admin/pages/authentication/authentication.module').then(m => m.AuthenticationModule)},
// Coming Soon
{path: 'coming-soon', loadChildren: () => import('app/modules/admin/pages/coming-soon/coming-soon.module').then(m => m.ComingSoonModule)},
// Error
{path: 'error', children: [
{path: '404', loadChildren: () => import('app/modules/admin/pages/error/error-404/error-404.module').then(m => m.Error404Module)},
{path: '500', loadChildren: () => import('app/modules/admin/pages/error/error-500/error-500.module').then(m => m.Error500Module)}
]},
// Invoice
{path: 'invoice', children: [
{path: 'printable', children: [
{path: 'compact', loadChildren: () => import('app/modules/admin/pages/invoice/printable/compact/compact.module').then(m => m.CompactModule)},
{path: 'modern', loadChildren: () => import('app/modules/admin/pages/invoice/printable/modern/modern.module').then(m => m.ModernModule)}
]}
]},
// Maintenance
{path: 'maintenance', loadChildren: () => import('app/modules/admin/pages/maintenance/maintenance.module').then(m => m.MaintenanceModule)},
// Pricing
{path: 'pricing', children: [
{path: 'modern', loadChildren: () => import('app/modules/admin/pages/pricing/modern/modern.module').then(m => m.PricingModernModule)},
{path: 'simple', loadChildren: () => import('app/modules/admin/pages/pricing/simple/simple.module').then(m => m.PricingSimpleModule)},
{path: 'single', loadChildren: () => import('app/modules/admin/pages/pricing/single/single.module').then(m => m.PricingSingleModule)},
{path: 'table', loadChildren: () => import('app/modules/admin/pages/pricing/table/table.module').then(m => m.PricingTableModule)}
]},
// Profile
{path: 'profile', loadChildren: () => import('app/modules/admin/pages/profile/profile.module').then(m => m.ProfileModule)},
// Settings
{path: 'settings', loadChildren: () => import('app/modules/admin/pages/settings/settings.module').then(m => m.SettingsModule)},
]},
// User Interface
{path: 'ui', children: [
// Material Components
{path: 'material-components', loadChildren: () => import('app/modules/admin/ui/material-components/material-components.module').then(m => m.MaterialComponentsModule)},
// Fuse Components
{path: 'fuse-components', loadChildren: () => import('app/modules/admin/ui/fuse-components/fuse-components.module').then(m => m.FuseComponentsModule)},
// Other Components
{path: 'other-components', loadChildren: () => import('app/modules/admin/ui/other-components/other-components.module').then(m => m.OtherComponentsModule)},
// TailwindCSS
{path: 'tailwindcss', loadChildren: () => import('app/modules/admin/ui/tailwindcss/tailwindcss.module').then(m => m.TailwindCSSModule)},
// Advanced Search
{path: 'advanced-search', loadChildren: () => import('app/modules/admin/ui/advanced-search/advanced-search.module').then(m => m.AdvancedSearchModule)},
// Animations
{path: 'animations', loadChildren: () => import('app/modules/admin/ui/animations/animations.module').then(m => m.AnimationsModule)},
// Cards
{path: 'cards', loadChildren: () => import('app/modules/admin/ui/cards/cards.module').then(m => m.CardsModule)},
// Colors
{path: 'colors', loadChildren: () => import('app/modules/admin/ui/colors/colors.module').then(m => m.ColorsModule)},
// Confirmation Dialog
{path: 'confirmation-dialog', loadChildren: () => import('app/modules/admin/ui/confirmation-dialog/confirmation-dialog.module').then(m => m.ConfirmationDialogModule)},
// Datatable
{path: 'datatable', loadChildren: () => import('app/modules/admin/ui/datatable/datatable.module').then(m => m.DatatableModule)},
// Forms
{path: 'forms', children: [
{path: 'fields', loadChildren: () => import('app/modules/admin/ui/forms/fields/fields.module').then(m => m.FormsFieldsModule)},
{path: 'layouts', loadChildren: () => import('app/modules/admin/ui/forms/layouts/layouts.module').then(m => m.FormsLayoutsModule)},
{path: 'wizards', loadChildren: () => import('app/modules/admin/ui/forms/wizards/wizards.module').then(m => m.FormsWizardsModule)}
]},
// Icons
{path: 'icons', loadChildren: () => import('app/modules/admin/ui/icons/icons.module').then(m => m.IconsModule)},
// Page Layouts
{path: 'page-layouts', loadChildren: () => import('app/modules/admin/ui/page-layouts/page-layouts.module').then(m => m.PageLayoutsModule)},
// Typography
{path: 'typography', loadChildren: () => import('app/modules/admin/ui/typography/typography.module').then(m => m.TypographyModule)}
]},
// Documentation
{path: 'docs', children: [
// Changelog
{path: 'changelog', loadChildren: () => import('app/modules/admin/docs/changelog/changelog.module').then(m => m.ChangelogModule)},
// Guides
{path: 'guides', loadChildren: () => import('app/modules/admin/docs/guides/guides.module').then(m => m.GuidesModule)}
]},
// 404 & Catch all
{path: '404-not-found', pathMatch: 'full', loadChildren: () => import('app/modules/admin/pages/error/error-404/error-404.module').then(m => m.Error404Module)},
{path: '**', redirectTo: '404-not-found'}
] ]
} }
]; ];

View File

@@ -96,8 +96,8 @@ export class AuthService
*/ */
signInUsingToken(): Observable<any> signInUsingToken(): Observable<any>
{ {
// Sign in using the token // Renew token
return this._httpClient.post('api/auth/sign-in-with-token', { return this._httpClient.post('api/auth/refresh-access-token', {
accessToken: this.accessToken accessToken: this.accessToken
}).pipe( }).pipe(
catchError(() => catchError(() =>
@@ -107,17 +107,8 @@ export class AuthService
), ),
switchMap((response: any) => { switchMap((response: any) => {
// Replace the access token with the new one if it's available on // Store the access token in the local storage
// the response object. this.accessToken = response.accessToken;
//
// This is an added optional step for better security. Once you sign
// in using the token, you should generate a new one on the server
// side and attach it to the response object. Then the following
// piece of code can replace the token with the refreshed one.
if ( response.accessToken )
{
this.accessToken = response.accessToken;
}
// Set the authenticated flag to true // Set the authenticated flag to true
this._authenticated = true; this._authenticated = true;

View File

@@ -17,6 +17,7 @@ export class IconsModule
this._matIconRegistry.addSvgIconSet(this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-twotone.svg')); this._matIconRegistry.addSvgIconSet(this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-twotone.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-outline.svg')); this._matIconRegistry.addSvgIconSetInNamespace('mat_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-solid.svg')); this._matIconRegistry.addSvgIconSetInNamespace('mat_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-solid.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('iconsmind', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/iconsmind.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('feather', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/feather.svg')); this._matIconRegistry.addSvgIconSetInNamespace('feather', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/feather.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-outline.svg')); this._matIconRegistry.addSvgIconSetInNamespace('heroicons_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-solid.svg')); this._matIconRegistry.addSvgIconSetInNamespace('heroicons_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-solid.svg'));

View File

@@ -1,5 +1,6 @@
import { Translation, TRANSLOCO_CONFIG, TRANSLOCO_LOADER, translocoConfig, TranslocoModule, TranslocoService } from '@ngneat/transloco'; import { Translation, TRANSLOCO_CONFIG, TRANSLOCO_LOADER, translocoConfig, TranslocoModule, TranslocoService } from '@ngneat/transloco';
import { APP_INITIALIZER, NgModule } from '@angular/core'; import { APP_INITIALIZER, NgModule } from '@angular/core';
import { environment } from 'environments/environment';
import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader'; import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
@NgModule({ @NgModule({
@@ -24,7 +25,7 @@ import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
defaultLang : 'en', defaultLang : 'en',
fallbackLang : 'en', fallbackLang : 'en',
reRenderOnLangChange: true, reRenderOnLangChange: true,
prodMode : true prodMode : environment.production
}) })
}, },
{ {

View File

@@ -144,9 +144,9 @@
<!-- No messages --> <!-- No messages -->
<ng-container *ngIf="!messages || !messages.length"> <ng-container *ngIf="!messages || !messages.length">
<div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8"> <div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8">
<div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100 dark:bg-primary-600"> <div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100">
<mat-icon <mat-icon
class="text-primary-700 dark:text-primary-50" class="text-primary-500-700"
[svgIcon]="'heroicons_outline:inbox'"></mat-icon> [svgIcon]="'heroicons_outline:inbox'"></mat-icon>
</div> </div>
<div class="mt-5 text-2xl font-semibold tracking-tight">No messages</div> <div class="mt-5 text-2xl font-semibold tracking-tight">No messages</div>

View File

@@ -145,9 +145,9 @@
<!-- No notifications --> <!-- No notifications -->
<ng-container *ngIf="!notifications || !notifications.length"> <ng-container *ngIf="!notifications || !notifications.length">
<div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8"> <div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8">
<div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100 dark:bg-primary-600"> <div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100">
<mat-icon <mat-icon
class="text-primary-700 dark:text-primary-50" class="text-primary-500-700"
[svgIcon]="'heroicons_outline:bell'"></mat-icon> [svgIcon]="'heroicons_outline:bell'"></mat-icon>
</div> </div>
<div class="mt-5 text-2xl font-semibold tracking-tight">No notifications</div> <div class="mt-5 text-2xl font-semibold tracking-tight">No notifications</div>

View File

@@ -151,12 +151,12 @@
<!-- Message field --> <!-- Message field -->
<div class="flex items-end p-4 border-t bg-gray-50 dark:bg-transparent"> <div class="flex items-end p-4 border-t bg-gray-50 dark:bg-transparent">
<mat-form-field <mat-form-field class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded fuse-mat-bold w-full">
class="fuse-mat-dense fuse-mat-rounded fuse-mat-bold w-full"
[subscriptSizing]="'dynamic'">
<textarea <textarea
class="min-h-5 my-0 resize-none"
style="margin: 11px 0 !important; padding: 0 !important;"
[rows]="1"
matInput matInput
cdkTextareaAutosize
#messageInput></textarea> #messageInput></textarea>
</mat-form-field> </mat-form-field>
<div class="flex items-center h-11 my-px ml-4"> <div class="flex items-center h-11 my-px ml-4">
@@ -178,8 +178,8 @@
<ng-template #selectChatOrStartNew> <ng-template #selectChatOrStartNew>
<div class="flex flex-col flex-auto items-center justify-center w-full h-full p-4"> <div class="flex flex-col flex-auto items-center justify-center w-full h-full p-4">
<mat-icon <mat-icon
class="icon-size-24" class="icon-size-20"
[svgIcon]="'heroicons_outline:chat'"></mat-icon> [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 class="mt-4 text-xl text-center font-medium tracking-tight text-secondary">Select a conversation</div>
</div> </div>
</ng-template> </ng-template>

View File

@@ -1,5 +1,4 @@
import { AfterViewInit, Component, ElementRef, HostBinding, HostListener, Inject, NgZone, OnDestroy, OnInit, Renderer2, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, HostBinding, HostListener, NgZone, OnDestroy, OnInit, Renderer2, ViewChild, ViewEncapsulation } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay'; import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { Subject, takeUntil } from 'rxjs'; import { Subject, takeUntil } from 'rxjs';
import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service'; import { QuickChatService } from 'app/layout/common/quick-chat/quick-chat.service';
@@ -12,14 +11,13 @@ import { Chat } from 'app/layout/common/quick-chat/quick-chat.types';
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
exportAs : 'quickChat' exportAs : 'quickChat'
}) })
export class QuickChatComponent implements OnInit, AfterViewInit, OnDestroy export class QuickChatComponent implements OnInit, OnDestroy
{ {
@ViewChild('messageInput') messageInput: ElementRef; @ViewChild('messageInput') messageInput: ElementRef;
chat: Chat; chat: Chat;
chats: Chat[]; chats: Chat[];
opened: boolean = false; opened: boolean = false;
selectedChat: Chat; selectedChat: Chat;
private _mutationObserver: MutationObserver;
private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block(); private _scrollStrategy: ScrollStrategy = this._scrollStrategyOptions.block();
private _overlay: HTMLElement; private _overlay: HTMLElement;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -28,7 +26,6 @@ export class QuickChatComponent implements OnInit, AfterViewInit, OnDestroy
* Constructor * Constructor
*/ */
constructor( constructor(
@Inject(DOCUMENT) private _document: Document,
private _elementRef: ElementRef, private _elementRef: ElementRef,
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _ngZone: NgZone, private _ngZone: NgZone,
@@ -106,48 +103,11 @@ export class QuickChatComponent implements OnInit, AfterViewInit, OnDestroy
}); });
} }
/**
* After view init
*/
ngAfterViewInit(): void
{
// Fix for Firefox.
//
// Because 'position: sticky' doesn't work correctly inside a 'position: fixed' parent,
// adding the '.cdk-global-scrollblock' to the html element breaks the navigation's position.
// This fixes the problem by reading the 'top' value from the html element and adding it as a
// 'marginTop' to the navigation itself.
this._mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const mutationTarget = mutation.target as HTMLElement;
if ( mutation.attributeName === 'class' )
{
if ( mutationTarget.classList.contains('cdk-global-scrollblock') )
{
const top = parseInt(mutationTarget.style.top, 10);
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', `${Math.abs(top)}px`);
}
else
{
this._renderer2.setStyle(this._elementRef.nativeElement, 'margin-top', null);
}
}
});
});
this._mutationObserver.observe(this._document.documentElement, {
attributes : true,
attributeFilter: ['class']
});
}
/** /**
* On destroy * On destroy
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Disconnect the mutation observer
this._mutationObserver.disconnect();
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next(null);
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();

View File

@@ -18,12 +18,11 @@
class="w-full h-full px-16 sm:px-18" class="w-full h-full px-16 sm:px-18"
[formControl]="searchControl" [formControl]="searchControl"
[matAutocomplete]="matAutocomplete" [matAutocomplete]="matAutocomplete"
[placeholder]="'Search...'" [placeholder]="'Search for a page or a contact'"
(keydown)="onKeydown($event)" (keydown)="onKeydown($event)"
#barSearchInput> #barSearchInput>
<mat-autocomplete <mat-autocomplete
class="max-h-128 sm:px-2 border-t rounded-b shadow-md" class="max-h-128 sm:px-2 border-t rounded-b shadow-md"
[autoSelectActiveOption]="true"
[disableRipple]="true" [disableRipple]="true"
#matAutocomplete="matAutocomplete"> #matAutocomplete="matAutocomplete">
<mat-option <mat-option
@@ -38,8 +37,7 @@
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn"> <ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
<mat-option <mat-option
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover" class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
[routerLink]="result.link" [routerLink]="result.link">
[value]="result.value">
<!-- Contacts --> <!-- Contacts -->
<ng-container *ngIf="resultSet.id === 'contacts'"> <ng-container *ngIf="resultSet.id === 'contacts'">
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container> <ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>
@@ -68,9 +66,7 @@
<!-- Basic search --> <!-- Basic search -->
<ng-container *ngIf="appearance === 'basic'"> <ng-container *ngIf="appearance === 'basic'">
<div class="w-full sm:min-w-80"> <div class="w-full sm:min-w-80">
<mat-form-field <mat-form-field class="fuse-mat-no-subscript w-full">
class="w-full"
[subscriptSizing]="'dynamic'">
<mat-icon <mat-icon
matPrefix matPrefix
[svgIcon]="'heroicons_outline:search'"></mat-icon> [svgIcon]="'heroicons_outline:search'"></mat-icon>
@@ -78,12 +74,11 @@
matInput matInput
[formControl]="searchControl" [formControl]="searchControl"
[matAutocomplete]="matAutocomplete" [matAutocomplete]="matAutocomplete"
[placeholder]="'Search...'" [placeholder]="'Search for a page or a contact'"
(keydown)="onKeydown($event)"> (keydown)="onKeydown($event)">
</mat-form-field> </mat-form-field>
<mat-autocomplete <mat-autocomplete
class="max-h-128 mt-1 rounded" class="max-h-128 mt-1 rounded"
[autoSelectActiveOption]="true"
[disableRipple]="true" [disableRipple]="true"
#matAutocomplete="matAutocomplete"> #matAutocomplete="matAutocomplete">
<mat-option <mat-option
@@ -98,8 +93,7 @@
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn"> <ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
<mat-option <mat-option
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover" class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
[routerLink]="result.link" [routerLink]="result.link">
[value]="result.value">
<!-- Contacts --> <!-- Contacts -->
<ng-container *ngIf="resultSet.id === 'contacts'"> <ng-container *ngIf="resultSet.id === 'contacts'">
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container> <ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>

View File

@@ -1,7 +1,6 @@
import { Component, ElementRef, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { UntypedFormControl } from '@angular/forms'; import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { MatAutocomplete } from '@angular/material/autocomplete';
import { debounceTime, filter, map, Subject, takeUntil } from 'rxjs'; import { debounceTime, filter, map, Subject, takeUntil } from 'rxjs';
import { fuseAnimations } from '@fuse/animations/public-api'; import { fuseAnimations } from '@fuse/animations/public-api';
@@ -21,8 +20,7 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
opened: boolean = false; opened: boolean = false;
resultSets: any[]; resultSets: any[];
searchControl: UntypedFormControl = new UntypedFormControl(); searchControl: FormControl = new FormControl();
private _matAutocomplete: MatAutocomplete;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
/** /**
@@ -61,7 +59,7 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
set barSearchInput(value: ElementRef) set barSearchInput(value: ElementRef)
{ {
// If the value exists, it means that the search input // If the value exists, it means that the search input
// is now in the DOM, and we can focus on the input.. // is now in the DOM and we can focus on the input..
if ( value ) if ( value )
{ {
// Give Angular time to complete the change detection cycle // Give Angular time to complete the change detection cycle
@@ -73,17 +71,6 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
} }
} }
/**
* Setter for mat-autocomplete element reference
*
* @param value
*/
@ViewChild('matAutocomplete')
set matAutocomplete(value: MatAutocomplete)
{
this._matAutocomplete = value;
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks // @ Lifecycle hooks
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -165,12 +152,14 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
*/ */
onKeydown(event: KeyboardEvent): void onKeydown(event: KeyboardEvent): void
{ {
// Escape // Listen for escape to close the search
if ( event.code === 'Escape' ) // if the appearance is 'bar'
if ( this.appearance === 'bar' )
{ {
// If the appearance is 'bar' and the mat-autocomplete is not open, close the search // Escape
if ( this.appearance === 'bar' && !this._matAutocomplete.isOpen ) if ( event.code === 'Escape' )
{ {
// Close the search
this.close(); this.close();
} }
} }

View File

@@ -1,5 +1,5 @@
<div <div
class="settings-cog 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="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-0]="config.layout === 'centered' || config.layout === 'material'"
[class.lg:right-16]="config.layout !== 'centered' && config.layout !== 'material'" [class.lg:right-16]="config.layout !== 'centered' && config.layout !== 'material'"
style="top: 275px" style="top: 275px"

View File

@@ -16,13 +16,6 @@ import { Layout } from 'app/layout/layout.types';
flex: none; flex: none;
width: auto; width: auto;
} }
@media (screen and min-width: 1280px) {
empty-layout + settings .settings-cog {
right: 0 !important;
}
}
` `
], ],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@@ -148,9 +148,9 @@
<!-- No shortcuts --> <!-- No shortcuts -->
<ng-container *ngIf="!shortcuts || !shortcuts.length"> <ng-container *ngIf="!shortcuts || !shortcuts.length">
<div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8"> <div class="flex flex-col flex-auto items-center justify-center sm:justify-start py-12 px-8">
<div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100 dark:bg-primary-600"> <div class="flex flex-0 items-center justify-center w-14 h-14 rounded-full bg-primary-100">
<mat-icon <mat-icon
class="text-primary-700 dark:text-primary-50" class="text-primary-500-700"
[svgIcon]="'heroicons_outline:bookmark'"></mat-icon> [svgIcon]="'heroicons_outline:bookmark'"></mat-icon>
</div> </div>
<div class="mt-5 text-2xl font-semibold tracking-tight">No shortcuts</div> <div class="mt-5 text-2xl font-semibold tracking-tight">No shortcuts</div>

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Overlay, OverlayRef } from '@angular/cdk/overlay'; import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal'; import { TemplatePortal } from '@angular/cdk/portal';
import { MatButton } from '@angular/material/button'; import { MatButton } from '@angular/material/button';
@@ -20,7 +20,7 @@ export class ShortcutsComponent implements OnInit, OnDestroy
@ViewChild('shortcutsPanel') private _shortcutsPanel: TemplateRef<any>; @ViewChild('shortcutsPanel') private _shortcutsPanel: TemplateRef<any>;
mode: 'view' | 'modify' | 'add' | 'edit' = 'view'; mode: 'view' | 'modify' | 'add' | 'edit' = 'view';
shortcutForm: UntypedFormGroup; shortcutForm: FormGroup;
shortcuts: Shortcut[]; shortcuts: Shortcut[];
private _overlayRef: OverlayRef; private _overlayRef: OverlayRef;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -30,7 +30,7 @@ export class ShortcutsComponent implements OnInit, OnDestroy
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _formBuilder: UntypedFormBuilder, private _formBuilder: FormBuilder,
private _shortcutsService: ShortcutsService, private _shortcutsService: ShortcutsService,
private _overlay: Overlay, private _overlay: Overlay,
private _viewContainerRef: ViewContainerRef private _viewContainerRef: ViewContainerRef

View File

@@ -4,7 +4,6 @@ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { combineLatest, filter, map, Subject, takeUntil } from 'rxjs'; import { combineLatest, filter, map, Subject, takeUntil } from 'rxjs';
import { FuseConfigService } from '@fuse/services/config'; import { FuseConfigService } from '@fuse/services/config';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FusePlatformService } from '@fuse/services/platform';
import { FUSE_VERSION } from '@fuse/version'; import { FUSE_VERSION } from '@fuse/version';
import { Layout } from 'app/layout/layout.types'; import { Layout } from 'app/layout/layout.types';
import { AppConfig } from 'app/core/config/app.config'; import { AppConfig } from 'app/core/config/app.config';
@@ -32,8 +31,7 @@ export class LayoutComponent implements OnInit, OnDestroy
private _renderer2: Renderer2, private _renderer2: Renderer2,
private _router: Router, private _router: Router,
private _fuseConfigService: FuseConfigService, private _fuseConfigService: FuseConfigService,
private _fuseMediaWatcherService: FuseMediaWatcherService, private _fuseMediaWatcherService: FuseMediaWatcherService
private _fusePlatformService: FusePlatformService
) )
{ {
} }
@@ -104,9 +102,6 @@ export class LayoutComponent implements OnInit, OnDestroy
// Set the app version // Set the app version
this._renderer2.setAttribute(this._document.querySelector('[ng-version]'), 'fuse-version', FUSE_VERSION); this._renderer2.setAttribute(this._document.querySelector('[ng-version]'), 'fuse-version', FUSE_VERSION);
// Set the OS name
this._renderer2.addClass(this._document.body, this._fusePlatformService.osName);
} }
/** /**

View File

@@ -66,9 +66,6 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
// Check if the screen is small // Check if the screen is small
this.isScreenSmall = !matchingAliases.includes('md'); this.isScreenSmall = !matchingAliases.includes('md');
// Change the navigation appearance
this.navigationAppearance = this.isScreenSmall ? 'default' : 'dense';
}); });
} }

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
/** /**
* Attachments are common and will be filled from here * Attachments are common and will be filled from here
@@ -35,175 +32,175 @@ export const messages = [
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Hi!', value : 'Hi!',
createdAt: now.minus({week: 1}).set({hour: 18, minute: 56}).toISO() createdAt: moment().subtract(1, 'week').hour(18).minute(56).toISOString()
}, },
{ {
id : 'eb82cf4b-fa93-4bf4-a88a-99e987ddb7ea', id : 'eb82cf4b-fa93-4bf4-a88a-99e987ddb7ea',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Hey, dude!', value : 'Hey, dude!',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 4}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(4).toISOString()
}, },
{ {
id : '3cf9b2a6-ae54-47db-97b2-ee139a8f84e5', id : '3cf9b2a6-ae54-47db-97b2-ee139a8f84e5',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Long time no see.', value : 'Long time no see.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 4}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(4).toISOString()
}, },
{ {
id : '2ab91b0f-fafb-45f3-88df-7efaff29134b', id : '2ab91b0f-fafb-45f3-88df-7efaff29134b',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Yeah, man... Things were quite busy for me and my family.', value : 'Yeah, man... Things were quite busy for me and my family.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 6}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(6).toISOString()
}, },
{ {
id : '10e81481-378f-49ac-b06b-7c59dcc639ae', id : '10e81481-378f-49ac-b06b-7c59dcc639ae',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'What\'s up? Anything I can help with?', value : 'What\'s up? Anything I can help with?',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 6}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(6).toISOString()
}, },
{ {
id : '3b334e72-6605-4ebd-a4f6-3850067048de', id : '3b334e72-6605-4ebd-a4f6-3850067048de',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'We\'ve been on the move, changed 3 places over 4 months', value : 'We\'ve been on the move, changed 3 places over 4 months',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 7}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(7).toISOString()
}, },
{ {
id : '25998113-3a96-4dd0-a7b9-4d2bb58db3f3', id : '25998113-3a96-4dd0-a7b9-4d2bb58db3f3',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Wow! That\'s crazy! 🤯 What happened?', value : 'Wow! That\'s crazy! 🤯 What happened?',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 7}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(7).toISOString()
}, },
{ {
id : '30adb3da-0e4f-487e-aec2-6d9f31e097f6', id : '30adb3da-0e4f-487e-aec2-6d9f31e097f6',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'You know I got a job in that big software company. First move was because of that.', value : 'You know I got a job in that big software company. First move was because of that.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 8}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(8).toISOString()
}, },
{ {
id : 'c0d6fd6e-d294-4845-8751-e84b8f2c4d3b', id : 'c0d6fd6e-d294-4845-8751-e84b8f2c4d3b',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Then they decided to re-locate me after a month', value : 'Then they decided to re-locate me after a month',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 8}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(8).toISOString()
}, },
{ {
id : '8d3c442b-62fa-496f-bffa-210ff5c1866b', id : '8d3c442b-62fa-496f-bffa-210ff5c1866b',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Which was an absolute pain because we just set up everything, house, kids school and all that.', value : 'Which was an absolute pain because we just set up everything, house, kids school and all that.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 8}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(8).toISOString()
}, },
{ {
id : '3cf26ef0-e81f-4698-ac39-487454413332', id : '3cf26ef0-e81f-4698-ac39-487454413332',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'So we moved the second time.', value : 'So we moved the second time.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 9}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(9).toISOString()
}, },
{ {
id : '415151b9-9ee9-40a4-a4ad-2d88146bc71b', id : '415151b9-9ee9-40a4-a4ad-2d88146bc71b',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'It\'s crazy!', value : 'It\'s crazy!',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 9}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(9).toISOString()
}, },
{ {
id : '3a2d3a0e-839b-46e7-86ae-ca0826ecda7c', id : '3a2d3a0e-839b-46e7-86ae-ca0826ecda7c',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Then this virus thing happened and just after a week we moved in, they decided the whole department will be working remotely.', value : 'Then this virus thing happened and just after a week we moved in, they decided the whole department will be working remotely.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 10}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(10).toISOString()
}, },
{ {
id : '5329c20d-6754-47ec-af8c-660c72be3528', id : '5329c20d-6754-47ec-af8c-660c72be3528',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'And then we decided to move back our first location because, you know, everything was already setup so that\'s the third time.', value : 'And then we decided to move back our first location because, you know, everything was already setup so that\'s the third time.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 10}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(10).toISOString()
}, },
{ {
id : '415151b9-9ee9-40a4-a4ad-2d88146bc71b', id : '415151b9-9ee9-40a4-a4ad-2d88146bc71b',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Ohh dude, I\'m really sorry you had to go through all that in such a short period of time', value : 'Ohh dude, I\'m really sorry you had to go through all that in such a short period of time',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 11}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(11).toISOString()
}, },
{ {
id : 'ea7662d5-7b72-4c19-ad6c-f80320541001', id : 'ea7662d5-7b72-4c19-ad6c-f80320541001',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : '😕', value : '😕',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 11}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(11).toISOString()
}, },
{ {
id : '3a2d3a0e-839b-46e7-86ae-ca0826ecda7c', id : '3a2d3a0e-839b-46e7-86ae-ca0826ecda7c',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Thanks, man! It was good catching up with you.', value : 'Thanks, man! It was good catching up with you.',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 11}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(11).toISOString()
}, },
{ {
id : '5329c20d-6754-47ec-af8c-660c72be3528', id : '5329c20d-6754-47ec-af8c-660c72be3528',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Yeah dude. Hit me again next week so we can grab a coffee, remotely!', value : 'Yeah dude. Hit me again next week so we can grab a coffee, remotely!',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 12}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(12).toISOString()
}, },
{ {
id : '5329c20d-6754-47ec-af8c-660c72be3528', id : '5329c20d-6754-47ec-af8c-660c72be3528',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : ':) Sure, man! See you next week!', value : ':) Sure, man! See you next week!',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 12}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(12).toISOString()
}, },
{ {
id : '5329c20d-6754-47ec-af8c-660c72be3528', id : '5329c20d-6754-47ec-af8c-660c72be3528',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'See you later!', value : 'See you later!',
createdAt: now.minus({week: 1}).set({hour: 19, minute: 12}).toISO() createdAt: moment().subtract(1, 'week').hour(19).minute(12).toISOString()
}, },
{ {
id : 'bab8ca0e-b8e5-4375-807b-1c91fca25a5d', id : 'bab8ca0e-b8e5-4375-807b-1c91fca25a5d',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Hey! Are you available right now? How about if we grab that coffee today? Remotely, of course :)', value : 'Hey! Are you available right now? How about if we grab that coffee today? Remotely, of course :)',
createdAt: now.set({hour: 12, minute: 45}).toISO() createdAt: moment().hour(12).minute(45).toISOString()
}, },
{ {
id : '8445a84d-599d-4e2d-a31c-5f4f29ad2b4c', id : '8445a84d-599d-4e2d-a31c-5f4f29ad2b4c',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Hi!', value : 'Hi!',
createdAt: now.set({hour: 12, minute: 56}).toISO() createdAt: moment().hour(12).minute(56).toISOString()
}, },
{ {
id : '9f506742-50da-4350-af9d-61e53392fa08', id : '9f506742-50da-4350-af9d-61e53392fa08',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : 'Sure thing! I\'m gonna call you in 5, is it okay?', value : 'Sure thing! I\'m gonna call you in 5, is it okay?',
createdAt: now.set({hour: 12, minute: 56}).toISO() createdAt: moment().hour(12).minute(56).toISOString()
}, },
{ {
id : 'ca8523d8-faed-45f7-af09-f6bd5c3f3875', id : 'ca8523d8-faed-45f7-af09-f6bd5c3f3875',
chatId : '', chatId : '',
contactId: 'me', contactId: 'me',
value : 'Awesome! Call me in 5 minutes..', value : 'Awesome! Call me in 5 minutes..',
createdAt: now.set({hour: 12, minute: 58}).toISO() createdAt: moment().hour(12).minute(58).toISOString()
}, },
{ {
id : '39944b00-1ffe-4ffb-8ca6-13c292812e06', id : '39944b00-1ffe-4ffb-8ca6-13c292812e06',
chatId : '', chatId : '',
contactId: '', contactId: '',
value : '👍🏻', value : '👍🏻',
createdAt: now.set({hour: 13, minute: 0}).toISO() createdAt: moment().hour(13).minute(0).toISOString()
} }
]; ];
export const chats = [ export const chats = [

View File

@@ -38,8 +38,8 @@ export class FileManagerMockApi
// Clone the items // Clone the items
let items = cloneDeep(this._items); let items = cloneDeep(this._items);
// See if the folder id exist // See if a folder id exist
const folderId = request.params.get('folderId') === 'null' ? null : request.params.get('folderId'); const folderId = request.params.get('folderId') ?? null;
// Filter the items by folder id. If folder id is null, // Filter the items by folder id. If folder id is null,
// that means we want to root items which have folder id // that means we want to root items which have folder id

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const folders = [ export const folders = [
{ {
@@ -106,7 +103,7 @@ export const mails = [
bcc : [ bcc : [
'Julie T. <julie.t@company.com>' 'Julie T. <julie.t@company.com>'
], ],
date : now.set({hour: 20, minute: 13}).toISO(), // Today - 20:13 date : moment().hour(20).minute(13).toISOString(), // Today - 20:13
subject : 'Please review and sign the attached agreement', subject : 'Please review and sign the attached agreement',
content : 'Hi Brian,\n\nUllamco deserunt commodo esse deserunt deserunt quis eiusmod. Laborum sint excepteur non sit eiusmod sunt voluptate ipsum nisi ullamco magna. Lorem consectetur est dolor minim exercitation deserunt quis duis fugiat ipsum incididunt non. Anim aute ipsum cupidatat nisi occaecat quis sit nisi labore labore dolore do. Pariatur veniam culpa quis veniam nisi exercitation veniam ut. Quis do sint proident fugiat ad.\n\nNon id nisi commodo veniam. Veniam veniam minim ea laborum voluptate id duis deserunt. Anim ut ut amet et ullamco nulla fugiat id incididunt adipisicing excepteur amet. Ex amet eu cillum non fugiat velit dolore. Incididunt duis est eu et ex sunt consectetur cillum nisi aute proident.\n\nIncididunt excepteur laborum quis sit. Ex quis officia incididunt proident aliqua adipisicing. Irure ad in Lorem laborum deserunt nulla consequat. Pariatur excepteur exercitation cupidatat aute.\n\nCheers!\nMyra Dudley', content : 'Hi Brian,\n\nUllamco deserunt commodo esse deserunt deserunt quis eiusmod. Laborum sint excepteur non sit eiusmod sunt voluptate ipsum nisi ullamco magna. Lorem consectetur est dolor minim exercitation deserunt quis duis fugiat ipsum incididunt non. Anim aute ipsum cupidatat nisi occaecat quis sit nisi labore labore dolore do. Pariatur veniam culpa quis veniam nisi exercitation veniam ut. Quis do sint proident fugiat ad.\n\nNon id nisi commodo veniam. Veniam veniam minim ea laborum voluptate id duis deserunt. Anim ut ut amet et ullamco nulla fugiat id incididunt adipisicing excepteur amet. Ex amet eu cillum non fugiat velit dolore. Incididunt duis est eu et ex sunt consectetur cillum nisi aute proident.\n\nIncididunt excepteur laborum quis sit. Ex quis officia incididunt proident aliqua adipisicing. Irure ad in Lorem laborum deserunt nulla consequat. Pariatur excepteur exercitation cupidatat aute.\n\nCheers!\nMyra Dudley',
attachments: [ attachments: [
@@ -150,7 +147,7 @@ export const mails = [
contact: 'Shaw Murray <shaw.murray@company.com>' contact: 'Shaw Murray <shaw.murray@company.com>'
}, },
to : 'me <hughes.brian@company.com>', to : 'me <hughes.brian@company.com>',
date : now.set({hour: 18, minute: 56}).toISO(), // Today - 18:56 date : moment().hour(18).minute(56).toISOString(), // Today - 18:56
subject : 'Delivery address confirmation', subject : 'Delivery address confirmation',
content : 'Dear Brian,\n\nDolore consectetur est cupidatat ipsum reprehenderit anim quis veniam anim ipsum incididunt exercitation. Velit exercitation culpa eiusmod dolore labore irure. Duis esse quis elit pariatur labore occaecat esse voluptate dolore deserunt cillum irure. Aute qui nulla est exercitation qui sunt anim aliquip. Ex ad est velit laboris exercitation ea ut pariatur. Amet reprehenderit ut est id sunt commodo anim et est voluptate et.\n\nMagna aliqua incididunt non ut voluptate nulla aliqua exercitation elit consectetur cupidatat. Proident in reprehenderit occaecat laborum non eu amet id aliqua nulla dolore. Eiusmod quis adipisicing quis cupidatat labore.\n\nReprehenderit nulla ullamco est dolore ex irure sunt nostrud reprehenderit quis dolor. Tempor nostrud elit elit aute ut ut eiusmod laboris excepteur consequat ex. Velit id ex ullamco in. Ea elit Lorem Lorem aliquip amet consequat irure nisi qui cillum incididunt. Commodo aute Lorem eiusmod veniam consectetur aute eu dolore. Ea magna incididunt laboris quis quis et tempor dolore dolore ut nisi.\n\nBest Regards,\nShaw Murray', content : 'Dear Brian,\n\nDolore consectetur est cupidatat ipsum reprehenderit anim quis veniam anim ipsum incididunt exercitation. Velit exercitation culpa eiusmod dolore labore irure. Duis esse quis elit pariatur labore occaecat esse voluptate dolore deserunt cillum irure. Aute qui nulla est exercitation qui sunt anim aliquip. Ex ad est velit laboris exercitation ea ut pariatur. Amet reprehenderit ut est id sunt commodo anim et est voluptate et.\n\nMagna aliqua incididunt non ut voluptate nulla aliqua exercitation elit consectetur cupidatat. Proident in reprehenderit occaecat laborum non eu amet id aliqua nulla dolore. Eiusmod quis adipisicing quis cupidatat labore.\n\nReprehenderit nulla ullamco est dolore ex irure sunt nostrud reprehenderit quis dolor. Tempor nostrud elit elit aute ut ut eiusmod laboris excepteur consequat ex. Velit id ex ullamco in. Ea elit Lorem Lorem aliquip amet consequat irure nisi qui cillum incididunt. Commodo aute Lorem eiusmod veniam consectetur aute eu dolore. Ea magna incididunt laboris quis quis et tempor dolore dolore ut nisi.\n\nBest Regards,\nShaw Murray',
attachments: [], attachments: [],
@@ -173,7 +170,7 @@ export const mails = [
cc : [ cc : [
'Graham Belltower <graham.belltower@company.com>' 'Graham Belltower <graham.belltower@company.com>'
], ],
date : now.set({hour: 14, minute: 35}).toISO(), // Today - 14:35 date : moment().hour(14).minute(35).toISOString(), // Today - 14:35
subject : 'Insurance documents', subject : 'Insurance documents',
content : 'Hi Brian,\n\nAliquip ipsum sunt sit sunt velit velit pariatur. Nisi incididunt eiusmod consequat ut cillum eu exercitation. Enim proident nostrud aute in. Non irure nisi duis aliquip commodo proident veniam adipisicing id velit. Enim magna Lorem fugiat tempor.\n\nCommodo non nulla incididunt irure voluptate. Fugiat culpa cillum aute quis. Voluptate veniam adipisicing dolor sint. Proident eiusmod quis duis ipsum sit eu.\n\nDeserunt reprehenderit adipisicing reprehenderit ipsum. Laborum in veniam amet occaecat tempor esse enim dolore elit sit quis adipisicing. Aute occaecat eiusmod enim cupidatat sunt.\n\nBest Regards,\nSanders Beck', content : 'Hi Brian,\n\nAliquip ipsum sunt sit sunt velit velit pariatur. Nisi incididunt eiusmod consequat ut cillum eu exercitation. Enim proident nostrud aute in. Non irure nisi duis aliquip commodo proident veniam adipisicing id velit. Enim magna Lorem fugiat tempor.\n\nCommodo non nulla incididunt irure voluptate. Fugiat culpa cillum aute quis. Voluptate veniam adipisicing dolor sint. Proident eiusmod quis duis ipsum sit eu.\n\nDeserunt reprehenderit adipisicing reprehenderit ipsum. Laborum in veniam amet occaecat tempor esse enim dolore elit sit quis adipisicing. Aute occaecat eiusmod enim cupidatat sunt.\n\nBest Regards,\nSanders Beck',
attachments: [], attachments: [],
@@ -191,7 +188,7 @@ export const mails = [
contact: 'Zimmerman Gould <zimmerman.gould@company.com>' contact: 'Zimmerman Gould <zimmerman.gould@company.com>'
}, },
to : 'me <hughes.brian@company.com>', to : 'me <hughes.brian@company.com>',
date : now.minus({day: 1}).set({hour: 22, minute: 26}).toISO(), // Yesterday - 22:26 date : moment().hour(22).minute(26).subtract(1, 'day').toISOString(), // Yesterday - 08:22
subject : 'Previous clients and their invoices', subject : 'Previous clients and their invoices',
content : 'Dear Brian,\n\nDo aute eu dolore officia laborum id anim fugiat incididunt nulla esse proident. Veniam veniam nostrud ut nisi magna ipsum ea eiusmod esse velit id aliqua nisi irure. Amet laborum fugiat deserunt est. Quis amet veniam anim nostrud irure cillum voluptate consequat qui cupidatat minim occaecat elit enim. Ut ut incididunt cillum sit sit irure culpa. Culpa exercitation minim velit eu. Ipsum exercitation excepteur et ad do sit.\n\nVeniam cupidatat officia aliqua ad excepteur cillum laboris deserunt esse laboris adipisicing reprehenderit. Reprehenderit anim consectetur pariatur labore do in irure. Ad consequat commodo non pariatur occaecat. Eiusmod cillum non anim consequat culpa nisi. Est nulla ut sint qui deserunt anim. Excepteur qui occaecat dolore nulla occaecat cupidatat aute sit laborum magna.\n\nConsequat aliqua commodo officia excepteur. Ex consectetur elit dolor exercitation ullamco amet laboris. Deserunt nulla non proident est pariatur reprehenderit reprehenderit. Ea nisi id aliqua cillum velit tempor ipsum dolor proident cillum eiusmod et ipsum anim. Elit non quis mollit enim Lorem cupidatat et labore. Laboris cillum reprehenderit aute veniam aliqua esse officia proident deserunt. Eiusmod laboris ullamco amet consectetur amet.\n\nKind Regards,\nZimmerman Gould', content : 'Dear Brian,\n\nDo aute eu dolore officia laborum id anim fugiat incididunt nulla esse proident. Veniam veniam nostrud ut nisi magna ipsum ea eiusmod esse velit id aliqua nisi irure. Amet laborum fugiat deserunt est. Quis amet veniam anim nostrud irure cillum voluptate consequat qui cupidatat minim occaecat elit enim. Ut ut incididunt cillum sit sit irure culpa. Culpa exercitation minim velit eu. Ipsum exercitation excepteur et ad do sit.\n\nVeniam cupidatat officia aliqua ad excepteur cillum laboris deserunt esse laboris adipisicing reprehenderit. Reprehenderit anim consectetur pariatur labore do in irure. Ad consequat commodo non pariatur occaecat. Eiusmod cillum non anim consequat culpa nisi. Est nulla ut sint qui deserunt anim. Excepteur qui occaecat dolore nulla occaecat cupidatat aute sit laborum magna.\n\nConsequat aliqua commodo officia excepteur. Ex consectetur elit dolor exercitation ullamco amet laboris. Deserunt nulla non proident est pariatur reprehenderit reprehenderit. Ea nisi id aliqua cillum velit tempor ipsum dolor proident cillum eiusmod et ipsum anim. Elit non quis mollit enim Lorem cupidatat et labore. Laboris cillum reprehenderit aute veniam aliqua esse officia proident deserunt. Eiusmod laboris ullamco amet consectetur amet.\n\nKind Regards,\nZimmerman Gould',
attachments: [], attachments: [],
@@ -212,7 +209,7 @@ export const mails = [
cc : [ cc : [
'Graham Belltower <graham.belltower@company.com>' 'Graham Belltower <graham.belltower@company.com>'
], ],
date : now.minus({day: 1}).set({hour: 20, minute: 5}).toISO(), // Yesterday - 20:05 date : moment().hour(20).minute(5).subtract(1, 'day').toISOString(), // Yesterday - 22:05
subject : 'Quote for a new web design project', subject : 'Quote for a new web design project',
content : 'Hey Brian,\n\nNisi officia aliqua ex non cupidatat sint ullamco. Irure pariatur ullamco consequat ut eu anim. Ut ad elit pariatur est non sunt. Tempor dolore quis commodo dolore duis officia laboris nostrud sint. Exercitation ullamco laboris eiusmod culpa ut.\n\nAute Lorem aute occaecat dolore tempor ipsum proident fugiat deserunt non incididunt velit nulla. Dolor pariatur tempor amet qui eu exercitation. Tempor minim culpa proident nisi esse ea. Enim est fugiat aliqua aliqua aute velit laborum cupidatat irure nisi dolor deserunt aliqua.\n\nFugiat ut dolor tempor sunt aliquip dolor nostrud. Consequat incididunt ullamco cillum dolore excepteur deserunt est dolor aliquip irure do mollit officia. Consectetur cillum et non minim nisi. Esse quis sunt deserunt elit sint velit tempor et ullamco laboris officia excepteur. Veniam ad ut aliqua sunt consequat reprehenderit nostrud non in duis aute quis pariatur. Occaecat mollit anim non pariatur. Ad do ad id fugiat et culpa laborum esse cupidatat voluptate elit ut magna voluptate.\n\nBest Regards,\nKarina Alford', content : 'Hey Brian,\n\nNisi officia aliqua ex non cupidatat sint ullamco. Irure pariatur ullamco consequat ut eu anim. Ut ad elit pariatur est non sunt. Tempor dolore quis commodo dolore duis officia laboris nostrud sint. Exercitation ullamco laboris eiusmod culpa ut.\n\nAute Lorem aute occaecat dolore tempor ipsum proident fugiat deserunt non incididunt velit nulla. Dolor pariatur tempor amet qui eu exercitation. Tempor minim culpa proident nisi esse ea. Enim est fugiat aliqua aliqua aute velit laborum cupidatat irure nisi dolor deserunt aliqua.\n\nFugiat ut dolor tempor sunt aliquip dolor nostrud. Consequat incididunt ullamco cillum dolore excepteur deserunt est dolor aliquip irure do mollit officia. Consectetur cillum et non minim nisi. Esse quis sunt deserunt elit sint velit tempor et ullamco laboris officia excepteur. Veniam ad ut aliqua sunt consequat reprehenderit nostrud non in duis aute quis pariatur. Occaecat mollit anim non pariatur. Ad do ad id fugiat et culpa laborum esse cupidatat voluptate elit ut magna voluptate.\n\nBest Regards,\nKarina Alford',
attachments: [], attachments: [],
@@ -233,7 +230,7 @@ export const mails = [
cc : [ cc : [
'Graham Belltower <graham.belltower@company.com>' 'Graham Belltower <graham.belltower@company.com>'
], ],
date : now.minus({day: 1}).set({hour: 16, minute: 43}).toISO(), // Yesterday - 16:43 date : moment().hour(16).minute(43).subtract(1, 'day').toISOString(), // Yesterday - 16:43
subject : 'Nulla culpa consectetur aute ex eu irure incididunt aliqua cupidatat sit cillum fugiat anim ea', subject : 'Nulla culpa consectetur aute ex eu irure incididunt aliqua cupidatat sit cillum fugiat anim ea',
content : 'Hey Brian,\n\nDo pariatur occaecat tempor duis. Aute occaecat non consequat ut occaecat sint. Cillum reprehenderit elit nisi incididunt in labore pariatur. Labore mollit pariatur nulla officia esse anim exercitation nisi commodo culpa laborum amet nisi.\n\nSunt culpa mollit nostrud excepteur adipisicing sit do. Cillum voluptate amet do sit quis aliquip ea est qui elit. Veniam exercitation sit reprehenderit labore officia in labore excepteur eiusmod exercitation.\n\nEnim nostrud est non esse reprehenderit in ea eiusmod. Duis incididunt amet aliquip dolor esse. Nostrud qui commodo in non nostrud proident enim cupidatat. Aute sunt aliqua excepteur qui occaecat nulla incididunt commodo adipisicing ipsum.\n\nKind Regards,\nCarla Gray', content : 'Hey Brian,\n\nDo pariatur occaecat tempor duis. Aute occaecat non consequat ut occaecat sint. Cillum reprehenderit elit nisi incididunt in labore pariatur. Labore mollit pariatur nulla officia esse anim exercitation nisi commodo culpa laborum amet nisi.\n\nSunt culpa mollit nostrud excepteur adipisicing sit do. Cillum voluptate amet do sit quis aliquip ea est qui elit. Veniam exercitation sit reprehenderit labore officia in labore excepteur eiusmod exercitation.\n\nEnim nostrud est non esse reprehenderit in ea eiusmod. Duis incididunt amet aliquip dolor esse. Nostrud qui commodo in non nostrud proident enim cupidatat. Aute sunt aliqua excepteur qui occaecat nulla incididunt commodo adipisicing ipsum.\n\nKind Regards,\nCarla Gray',
attachments: [], attachments: [],
@@ -255,7 +252,7 @@ export const mails = [
'Graham Belltower <graham.belltower@company.com>', 'Graham Belltower <graham.belltower@company.com>',
'Julie T. <julie.t@company.com>' 'Julie T. <julie.t@company.com>'
], ],
date : now.minus({day: 2}).set({hour: 11, minute: 28}).toISO(), // 2 days ago - 11:28 date : moment().hour(11).minute(28).subtract(2, 'day').toISOString(), // 2 days ago - 11:28
subject : 'Ipsum laborum minim aute labore in', subject : 'Ipsum laborum minim aute labore in',
content : 'Dear Brian,\n\nLaboris non ad et aute sint aliquip mollit voluptate velit dolore magna fugiat ex. Voluptate amet aute deserunt tempor non laboris cillum. Voluptate veniam magna sint magna proident exercitation adipisicing aute id ad tempor reprehenderit magna ullamco. Laborum Lorem anim elit aliquip ut aute minim fugiat aliquip. Eiusmod est et occaecat dolore anim laborum ullamco ipsum commodo.\n\nCommodo amet veniam nostrud mollit quis sint qui nulla elit esse excepteur ullamco esse magna. Nisi duis aute est in mollit irure enim tempor in. Mollit ipsum laboris et velit ex excepteur pariatur. Cillum veniam id ipsum magna. Laborum duis aliquip ut ipsum ad aliqua id sit pariatur consequat sit. Sit nulla nulla ullamco nulla eiusmod et in dolore sint reprehenderit cupidatat.\n\nIpsum mollit cupidatat magna occaecat labore est fugiat est fugiat fugiat nulla labore laboris. Eiusmod aute adipisicing pariatur aliquip sint enim anim in dolore enim aute culpa nulla. Minim magna enim officia ipsum elit quis do velit deserunt Lorem veniam excepteur.\n\nKind Regards,\nRice Cash', content : 'Dear Brian,\n\nLaboris non ad et aute sint aliquip mollit voluptate velit dolore magna fugiat ex. Voluptate amet aute deserunt tempor non laboris cillum. Voluptate veniam magna sint magna proident exercitation adipisicing aute id ad tempor reprehenderit magna ullamco. Laborum Lorem anim elit aliquip ut aute minim fugiat aliquip. Eiusmod est et occaecat dolore anim laborum ullamco ipsum commodo.\n\nCommodo amet veniam nostrud mollit quis sint qui nulla elit esse excepteur ullamco esse magna. Nisi duis aute est in mollit irure enim tempor in. Mollit ipsum laboris et velit ex excepteur pariatur. Cillum veniam id ipsum magna. Laborum duis aliquip ut ipsum ad aliqua id sit pariatur consequat sit. Sit nulla nulla ullamco nulla eiusmod et in dolore sint reprehenderit cupidatat.\n\nIpsum mollit cupidatat magna occaecat labore est fugiat est fugiat fugiat nulla labore laboris. Eiusmod aute adipisicing pariatur aliquip sint enim anim in dolore enim aute culpa nulla. Minim magna enim officia ipsum elit quis do velit deserunt Lorem veniam excepteur.\n\nKind Regards,\nRice Cash',
attachments: [ attachments: [
@@ -298,7 +295,7 @@ export const mails = [
cc : [ cc : [
'Graham Belltower <graham.belltower@company.com>' 'Graham Belltower <graham.belltower@company.com>'
], ],
date : now.minus({day: 2}).set({hour: 7, minute: 12}).toISO(), // 2 days ago - 07:12 date : moment().hour(7).minute(12).subtract(2, 'day').toISOString(), // 2 days ago - 07:12
subject : 'Ipsum fugiat ad deserunt cillum sunt fugiat', subject : 'Ipsum fugiat ad deserunt cillum sunt fugiat',
content : 'Hello Brian,\n\nId Lorem laborum eiusmod eiusmod mollit magna dolore. Et commodo officia fugiat dolor aliqua proident mollit ut commodo ullamco. Sunt nulla eu dolor velit velit reprehenderit. Culpa esse veniam fugiat eiusmod id veniam sunt reprehenderit minim mollit. Esse qui ea irure pariatur eu ullamco pariatur ipsum reprehenderit proident mollit proident. Nisi fugiat ut est aliquip nulla in non dolore.\n\nCulpa irure cillum ex fugiat cupidatat eiusmod non. Qui irure velit consectetur minim eu excepteur eiusmod veniam irure ad culpa nisi. Nisi sit nostrud quis ullamco aliquip non consequat sunt reprehenderit velit dolor dolor laboris. Dolore in Lorem consectetur nostrud. Laborum cupidatat exercitation voluptate duis amet. Sunt sint minim do in commodo ipsum commodo ea qui velit deserunt qui anim fugiat.\n\nExercitation et qui consequat incididunt nisi incididunt cupidatat officia in. Sit eiusmod anim aliqua elit. Nisi mollit ut non pariatur enim fugiat sint labore velit nostrud eu. Eiusmod id laboris laboris duis enim aute ipsum in magna. Sit eiusmod amet duis commodo sint et anim ex sunt deserunt dolor incididunt. Eiusmod duis dolore dolor elit occaecat do adipisicing ullamco ex laboris aliqua adipisicing. Labore pariatur aute proident mollit elit commodo labore minim dolore non in cillum.\n\nCheers!\nElaine Ortiz', content : 'Hello Brian,\n\nId Lorem laborum eiusmod eiusmod mollit magna dolore. Et commodo officia fugiat dolor aliqua proident mollit ut commodo ullamco. Sunt nulla eu dolor velit velit reprehenderit. Culpa esse veniam fugiat eiusmod id veniam sunt reprehenderit minim mollit. Esse qui ea irure pariatur eu ullamco pariatur ipsum reprehenderit proident mollit proident. Nisi fugiat ut est aliquip nulla in non dolore.\n\nCulpa irure cillum ex fugiat cupidatat eiusmod non. Qui irure velit consectetur minim eu excepteur eiusmod veniam irure ad culpa nisi. Nisi sit nostrud quis ullamco aliquip non consequat sunt reprehenderit velit dolor dolor laboris. Dolore in Lorem consectetur nostrud. Laborum cupidatat exercitation voluptate duis amet. Sunt sint minim do in commodo ipsum commodo ea qui velit deserunt qui anim fugiat.\n\nExercitation et qui consequat incididunt nisi incididunt cupidatat officia in. Sit eiusmod anim aliqua elit. Nisi mollit ut non pariatur enim fugiat sint labore velit nostrud eu. Eiusmod id laboris laboris duis enim aute ipsum in magna. Sit eiusmod amet duis commodo sint et anim ex sunt deserunt dolor incididunt. Eiusmod duis dolore dolor elit occaecat do adipisicing ullamco ex laboris aliqua adipisicing. Labore pariatur aute proident mollit elit commodo labore minim dolore non in cillum.\n\nCheers!\nElaine Ortiz',
attachments: [], attachments: [],
@@ -324,7 +321,7 @@ export const mails = [
cc : [ cc : [
'Graham Belltower <graham.belltower@company.com>' 'Graham Belltower <graham.belltower@company.com>'
], ],
date : now.minus({day: 2}).set({hour: 6, minute: 1}).toISO(), // 2 days ago - 06:01 date : moment().hour(6).minute(1).subtract(2, 'day').toISOString(), // 2 days ago - 06:01
subject : 'Deserunt exercitation ut nulla elit Lorem', subject : 'Deserunt exercitation ut nulla elit Lorem',
content : 'Hi Brian,\n\nEst labore sunt sunt Lorem dolore. In excepteur esse proident ut consectetur dolor voluptate laborum veniam pariatur. Excepteur ut veniam sit culpa exercitation qui nulla nulla magna ea in dolore et consequat. Irure minim ad cupidatat amet reprehenderit excepteur incididunt nulla eu et excepteur anim et aliqua.\n\nSint sint Lorem magna est irure sint ea cupidatat fugiat. Occaecat non adipisicing magna magna culpa sit commodo aute ex consequat amet minim esse ut. In nulla eiusmod veniam deserunt in.\n\nIn aute excepteur qui pariatur fugiat. Occaecat velit voluptate proident occaecat ut laboris occaecat pariatur aute dolore do. Ut commodo ipsum est non commodo ut ea qui labore veniam. Occaecat nostrud eu dolor tempor velit excepteur sint occaecat excepteur aliqua aliquip. Magna mollit ea aliquip exercitation do elit ex reprehenderit esse aliqua elit.\n\nKind Regards,\nFleming Stone', content : 'Hi Brian,\n\nEst labore sunt sunt Lorem dolore. In excepteur esse proident ut consectetur dolor voluptate laborum veniam pariatur. Excepteur ut veniam sit culpa exercitation qui nulla nulla magna ea in dolore et consequat. Irure minim ad cupidatat amet reprehenderit excepteur incididunt nulla eu et excepteur anim et aliqua.\n\nSint sint Lorem magna est irure sint ea cupidatat fugiat. Occaecat non adipisicing magna magna culpa sit commodo aute ex consequat amet minim esse ut. In nulla eiusmod veniam deserunt in.\n\nIn aute excepteur qui pariatur fugiat. Occaecat velit voluptate proident occaecat ut laboris occaecat pariatur aute dolore do. Ut commodo ipsum est non commodo ut ea qui labore veniam. Occaecat nostrud eu dolor tempor velit excepteur sint occaecat excepteur aliqua aliquip. Magna mollit ea aliquip exercitation do elit ex reprehenderit esse aliqua elit.\n\nKind Regards,\nFleming Stone',
attachments: [], attachments: [],
@@ -346,7 +343,7 @@ export const mails = [
contact: 'England Wiley <england.wiley@company.com>' contact: 'England Wiley <england.wiley@company.com>'
}, },
to : 'me <hughes.brian@company.com>', to : 'me <hughes.brian@company.com>',
date : now.minus({day: 5}).set({hour: 15, minute: 36}).toISO(), // 5 days ago - 15:36 date : moment().hour(15).minute(36).subtract(5, 'day').toISOString(), // 2 days ago - 15:36
subject : 'Minim do reprehenderit dolor ipsum officia magna laborum est anim in fugiat', subject : 'Minim do reprehenderit dolor ipsum officia magna laborum est anim in fugiat',
content : 'Dear Brian,\n\nAd do minim id ad ex sit reprehenderit labore do occaecat fugiat ut enim. Et sunt dolore sint non consequat ut. Esse deserunt nostrud pariatur nulla ullamco nulla sit aliquip culpa sunt ipsum. Ut ad minim qui anim amet aute cupidatat. Est ullamco duis laboris nulla labore incididunt consectetur. Cillum sunt mollit nulla laborum non tempor veniam consequat.\n\nAmet fugiat velit id deserunt pariatur velit laboris consectetur quis officia. Culpa nostrud deserunt nostrud esse labore esse consequat labore fugiat. Nostrud duis ex nulla et do.\n\nPariatur mollit ex adipisicing nostrud nostrud occaecat. Id tempor irure cupidatat duis cillum cupidatat nostrud enim anim. Esse nisi pariatur nisi elit elit sit quis ullamco dolor dolore pariatur est sint. Sint ex aliqua id sunt sunt magna amet ex sit anim. Irure aliquip fugiat ipsum tempor irure nisi Lorem anim sit ullamco. Exercitation nostrud mollit est non enim.\n\nBest Regards,\nEngland Wiley', content : 'Dear Brian,\n\nAd do minim id ad ex sit reprehenderit labore do occaecat fugiat ut enim. Et sunt dolore sint non consequat ut. Esse deserunt nostrud pariatur nulla ullamco nulla sit aliquip culpa sunt ipsum. Ut ad minim qui anim amet aute cupidatat. Est ullamco duis laboris nulla labore incididunt consectetur. Cillum sunt mollit nulla laborum non tempor veniam consequat.\n\nAmet fugiat velit id deserunt pariatur velit laboris consectetur quis officia. Culpa nostrud deserunt nostrud esse labore esse consequat labore fugiat. Nostrud duis ex nulla et do.\n\nPariatur mollit ex adipisicing nostrud nostrud occaecat. Id tempor irure cupidatat duis cillum cupidatat nostrud enim anim. Esse nisi pariatur nisi elit elit sit quis ullamco dolor dolore pariatur est sint. Sint ex aliqua id sunt sunt magna amet ex sit anim. Irure aliquip fugiat ipsum tempor irure nisi Lorem anim sit ullamco. Exercitation nostrud mollit est non enim.\n\nBest Regards,\nEngland Wiley',
attachments: [], attachments: [],

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const labels = [ export const labels = [
{ {
@@ -41,7 +38,7 @@ export const notes = [
reminder : null, reminder : null,
labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'], labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'],
archived : false, archived : false,
createdAt: now.set({hour: 10, minute: 19}).minus({day: 98}).toISO(), createdAt: moment().hour(10).minute(19).subtract(98, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -56,7 +53,7 @@ export const notes = [
'b1cde9ee-e54d-4142-ad8b-cf55dafc9528' 'b1cde9ee-e54d-4142-ad8b-cf55dafc9528'
], ],
archived : false, archived : false,
createdAt: now.set({hour: 15, minute: 37}).minus({day: 80}).toISO(), createdAt: moment().hour(15).minute(37).subtract(80, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -68,8 +65,8 @@ export const notes = [
reminder : null, reminder : null,
labels : ['6c288794-47eb-4605-8bdf-785b61a449d3'], labels : ['6c288794-47eb-4605-8bdf-785b61a449d3'],
archived : false, archived : false,
createdAt: now.set({hour: 19, minute: 27}).minus({day: 74}).toISO(), createdAt: moment().hour(19).minute(27).subtract(74, 'day').toISOString(),
updatedAt: now.set({hour: 15, minute: 36}).minus({day: 50}).toISO(), updatedAt: moment().hour(15).minute(36).subtract(50, 'day').toISOString()
}, },
{ {
id : '89861bd4-0144-4bb4-8b39-332ca10371d5', id : '89861bd4-0144-4bb4-8b39-332ca10371d5',
@@ -77,10 +74,10 @@ export const notes = [
content : 'Theming support for all apps', content : 'Theming support for all apps',
tasks : null, tasks : null,
image : null, image : null,
reminder: now.set({hour: 12, minute: 34}).plus({day: 50}).toISO(), reminder : moment().hour(12).minute(34).add(50, 'day').toISOString(),
labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'], labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'],
archived : false, archived : false,
createdAt: now.set({hour: 12, minute: 34}).minus({day: 59}).toISO(), createdAt: moment().hour(12).minute(34).subtract(59, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -113,7 +110,7 @@ export const notes = [
reminder : null, reminder : null,
labels : ['f47c92e5-20b9-44d9-917f-9ff4ad25dfd0'], labels : ['f47c92e5-20b9-44d9-917f-9ff4ad25dfd0'],
archived : false, archived : false,
createdAt: now.set({hour: 16, minute: 4}).minus({day: 47}).toISO(), createdAt: moment().hour(16).minute(4).subtract(47, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -148,10 +145,10 @@ export const notes = [
} }
], ],
image : null, image : null,
reminder : now.set({hour: 10, minute: 44}).minus({day: 35}).toISO(), reminder : moment().hour(10).minute(44).subtract(35, 'day').toISOString(),
labels : ['b1cde9ee-e54d-4142-ad8b-cf55dafc9528'], labels : ['b1cde9ee-e54d-4142-ad8b-cf55dafc9528'],
archived : false, archived : false,
createdAt: now.set({hour: 10, minute: 44}).minus({day: 35}).toISO(), createdAt: moment().hour(10).minute(44).subtract(35, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -186,13 +183,13 @@ export const notes = [
} }
], ],
image : null, image : null,
reminder : now.set({hour: 11, minute: 27}).minus({day: 14}).toISO(), reminder : moment().hour(11).minute(27).subtract(14, 'day').toISOString(),
labels : [ labels : [
'b1cde9ee-e54d-4142-ad8b-cf55dafc9528', 'b1cde9ee-e54d-4142-ad8b-cf55dafc9528',
'e2f749f5-41ed-49d0-a92a-1c83d879e371' 'e2f749f5-41ed-49d0-a92a-1c83d879e371'
], ],
archived : false, archived : false,
createdAt: now.set({hour: 11, minute: 27}).minus({day: 24}).toISO(), createdAt: moment().hour(11).minute(27).subtract(24, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -201,10 +198,10 @@ export const notes = [
content : 'Organize the dad\'s surprise retirement party', content : 'Organize the dad\'s surprise retirement party',
tasks : null, tasks : null,
image : null, image : null,
reminder : now.set({hour: 14, minute: 56}).minus({day: 25}).toISO(), reminder : moment().hour(14).minute(56).subtract(25, 'day').toISOString(),
labels : ['f47c92e5-20b9-44d9-917f-9ff4ad25dfd0'], labels : ['f47c92e5-20b9-44d9-917f-9ff4ad25dfd0'],
archived : false, archived : false,
createdAt: now.set({hour: 14, minute: 56}).minus({day: 20}).toISO(), createdAt: moment().hour(14).minute(56).subtract(20, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -219,8 +216,8 @@ export const notes = [
'b1cde9ee-e54d-4142-ad8b-cf55dafc9528' 'b1cde9ee-e54d-4142-ad8b-cf55dafc9528'
], ],
archived : false, archived : false,
createdAt: now.set({hour: 9, minute: 32}).minus({day: 15}).toISO(), createdAt: moment().hour(9).minute(32).subtract(15, 'day').toISOString(),
updatedAt: now.set({hour: 17, minute: 6}).minus({day: 12}).toISO(), updatedAt: moment().hour(17).minute(6).subtract(12, 'day').toISOString()
}, },
{ {
id : '15188348-78aa-4ed6-b5c2-028a214ba987', id : '15188348-78aa-4ed6-b5c2-028a214ba987',
@@ -231,7 +228,7 @@ export const notes = [
reminder : null, reminder : null,
labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'], labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'],
archived : false, archived : false,
createdAt: now.set({hour: 20, minute: 5}).minus({day: 12}).toISO(), createdAt: moment().hour(20).minute(5).subtract(12, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -251,10 +248,10 @@ export const notes = [
} }
], ],
image : null, image : null,
reminder : now.set({hour: 13, minute: 43}).minus({day: 2}).toISO(), reminder : moment().hour(13).minute(43).subtract(2, 'day').toISOString(),
labels : ['bbc73458-940b-421c-8d5f-8dcd23a9b0d6'], labels : ['bbc73458-940b-421c-8d5f-8dcd23a9b0d6'],
archived : false, archived : false,
createdAt: now.set({hour: 13, minute: 43}).minus({day: 7}).toISO(), createdAt: moment().hour(13).minute(43).subtract(7, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -269,7 +266,7 @@ export const notes = [
'6c288794-47eb-4605-8bdf-785b61a449d3' '6c288794-47eb-4605-8bdf-785b61a449d3'
], ],
archived : false, archived : false,
createdAt: now.set({hour: 7, minute: 12}).minus({day: 2}).toISO(), createdAt: moment().hour(7).minute(12).subtract(2, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -284,7 +281,7 @@ export const notes = [
'6c288794-47eb-4605-8bdf-785b61a449d3' '6c288794-47eb-4605-8bdf-785b61a449d3'
], ],
archived : true, archived : true,
createdAt: now.set({hour: 17, minute: 14}).minus({day: 100}).toISO(), createdAt: moment().hour(17).minute(14).subtract(100, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -296,7 +293,7 @@ export const notes = [
reminder : null, reminder : null,
labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'], labels : ['e2f749f5-41ed-49d0-a92a-1c83d879e371'],
archived : true, archived : true,
createdAt: now.set({hour: 10, minute: 29}).minus({day: 85}).toISO(), createdAt: moment().hour(10).minute(29).subtract(85, 'day').toISOString(),
updatedAt: null updatedAt: null
}, },
{ {
@@ -311,7 +308,7 @@ export const notes = [
'b1cde9ee-e54d-4142-ad8b-cf55dafc9528' 'b1cde9ee-e54d-4142-ad8b-cf55dafc9528'
], ],
archived : true, archived : true,
createdAt: now.set({hour: 15, minute: 30}).minus({day: 69}).toISO(), createdAt: moment().hour(15).minute(30).subtract(69, 'day').toISOString(),
updatedAt: null updatedAt: null
} }
]; ];

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const boards = [ export const boards = [
{ {
@@ -10,7 +7,7 @@ export const boards = [
title : 'Admin Dashboard', title : 'Admin Dashboard',
description : 'Roadmap for the new project', description : 'Roadmap for the new project',
icon : 'heroicons_outline:template', icon : 'heroicons_outline:template',
lastActivity: now.startOf('day').minus({day: 1}).toISO(), lastActivity: moment().startOf('day').subtract(1, 'day').toISOString(),
members : [ members : [
'9c510cf3-460d-4a8c-b3be-bcc3db578c08', '9c510cf3-460d-4a8c-b3be-bcc3db578c08',
'baa88231-0ee6-4028-96d5-7f187e0f4cd5', 'baa88231-0ee6-4028-96d5-7f187e0f4cd5',
@@ -22,7 +19,7 @@ export const boards = [
title : 'Weekly Planning', title : 'Weekly Planning',
description : 'Job related tasks for the week', description : 'Job related tasks for the week',
icon : 'heroicons_outline:calendar', icon : 'heroicons_outline:calendar',
lastActivity: now.startOf('day').minus({day: 2}).toISO(), lastActivity: moment().startOf('day').subtract(2, 'days').toISOString(),
members : [ members : [
'79ebb9ee-1e57-4706-810c-03edaec8f56d', '79ebb9ee-1e57-4706-810c-03edaec8f56d',
'319ecb5b-f99c-4ee4-81b2-3aeffd1d4735', '319ecb5b-f99c-4ee4-81b2-3aeffd1d4735',
@@ -39,7 +36,7 @@ export const boards = [
title : 'Personal Tasks', title : 'Personal Tasks',
description : 'Personal tasks around the house', description : 'Personal tasks around the house',
icon : 'heroicons_outline:home', icon : 'heroicons_outline:home',
lastActivity: now.startOf('day').minus({week: 1}).toISO(), lastActivity: moment().startOf('day').subtract(1, 'week').toISOString(),
members : [ members : [
'6f6a1c34-390b-4b2e-97c8-ff0e0d787839' '6f6a1c34-390b-4b2e-97c8-ff0e0d787839'
] ]
@@ -86,7 +83,7 @@ export const cards = [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb', 'caff9c9b-a198-4564-b1f4-8b3df1d345bb',
'f9eeb436-13a3-4208-a239-0d555960a567' 'f9eeb436-13a3-4208-a239-0d555960a567'
], ],
dueDate : now.startOf('day').minus({day: 10}).toISO() dueDate : moment().subtract(10, 'days').startOf('day').toISOString()
}, },
{ {
id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719', id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
@@ -108,7 +105,7 @@ export const cards = [
labels : [ labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb' 'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
], ],
dueDate : now.startOf('day').toISO() dueDate : moment().startOf('day').toISOString()
}, },
{ {
id : '6da8747f-b474-4c9a-9eba-5ef212285500', id : '6da8747f-b474-4c9a-9eba-5ef212285500',
@@ -119,7 +116,7 @@ export const cards = [
labels : [ labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb' 'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
], ],
dueDate : now.startOf('day').minus({day: 1}).toISO() dueDate : moment().subtract(1, 'day').startOf('day').toISOString()
}, },
{ {
id : '94fb1dee-dd83-4cca-acdd-02e96d3cc4f1', id : '94fb1dee-dd83-4cca-acdd-02e96d3cc4f1',
@@ -170,7 +167,7 @@ export const cards = [
position: 131072, position: 131072,
title : 'Create high fidelity wireframes', title : 'Create high fidelity wireframes',
labels : [], labels : [],
dueDate : now.startOf('day').minus({day: 10}).toISO() dueDate : moment().subtract(10, 'day').startOf('day').toISOString()
}, },
{ {
id : 'b1da11ed-7896-4826-962d-4b7b718896d4', id : 'b1da11ed-7896-4826-962d-4b7b718896d4',

View File

@@ -87,10 +87,10 @@ export class AuthMockApi
}); });
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Sign in using the access token - POST // @ Verify and refresh the access token - POST
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
this._fuseMockApiService this._fuseMockApiService
.onPost('api/auth/sign-in-with-token') .onPost('api/auth/refresh-access-token')
.reply(({request}) => { .reply(({request}) => {
// Get the access token // Get the access token

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const messages = [ export const messages = [
{ {
@@ -10,7 +7,7 @@ export const messages = [
image : 'assets/images/avatars/male-01.jpg', image : 'assets/images/avatars/male-01.jpg',
title : 'Gary Peters', title : 'Gary Peters',
description: 'We should talk about that at lunch!', description: 'We should talk about that at lunch!',
time : now.minus({minutes: 25}).toISO(), // 25 minutes ago time : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
read : false read : false
}, },
{ {
@@ -18,7 +15,7 @@ export const messages = [
image : 'assets/images/avatars/male-04.jpg', image : 'assets/images/avatars/male-04.jpg',
title : 'Leo Gill (Client #8817)', title : 'Leo Gill (Client #8817)',
description: 'You can download the latest invoices now. Please check and let me know.', description: 'You can download the latest invoices now. Please check and let me know.',
time : now.minus({minutes: 50}).toISO(), // 50 minutes ago time : moment().subtract(50, 'minutes').toISOString(), // 50 minutes ago
read : false read : false
}, },
{ {
@@ -26,7 +23,7 @@ export const messages = [
image : 'assets/images/avatars/female-01.jpg', image : 'assets/images/avatars/female-01.jpg',
title : 'Sarah', title : 'Sarah',
description: 'Don\'t forget to pickup Jeremy after school!', description: 'Don\'t forget to pickup Jeremy after school!',
time : now.minus({hours: 3}).toISO(), // 3 hours ago time : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -36,7 +33,7 @@ export const messages = [
image : 'assets/images/avatars/female-12.jpg', image : 'assets/images/avatars/female-12.jpg',
title : 'Nancy Salazar &bull; Joy Publishing', title : 'Nancy Salazar &bull; Joy Publishing',
description: 'I\'ll proof read your bio on next Monday.', description: 'I\'ll proof read your bio on next Monday.',
time : now.minus({hours: 5}).toISO(), // 5 hours ago time : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -46,7 +43,7 @@ export const messages = [
image : 'assets/images/avatars/male-06.jpg', image : 'assets/images/avatars/male-06.jpg',
title : 'Matthew Wood', title : 'Matthew Wood',
description: 'Dude, I heard that they are going to promote you! Congrats man, tonight the drinks are on me!', description: 'Dude, I heard that they are going to promote you! Congrats man, tonight the drinks are on me!',
time : now.minus({hours: 7}).toISO(), // 7 hours ago time : moment().subtract(7, 'hours').toISOString(), // 7 hours ago
read : false, read : false,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -56,7 +53,7 @@ export const messages = [
image : 'assets/images/avatars/female-04.jpg', image : 'assets/images/avatars/female-04.jpg',
title : 'Elizabeth (New assistant)', title : 'Elizabeth (New assistant)',
description: 'Boss, I\'ve sent all client invoices but Geoffrey refusing to pay.', description: 'Boss, I\'ve sent all client invoices but Geoffrey refusing to pay.',
time : now.minus({hours: 9}).toISO(), // 9 hours ago time : moment().subtract(9, 'hours').toISOString(), // 9 hours ago
read : false, read : false,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -66,7 +63,7 @@ export const messages = [
image : 'assets/images/avatars/male-06.jpg', image : 'assets/images/avatars/male-06.jpg',
title : 'William Bell', title : 'William Bell',
description: 'Did you see this game? We should hang out and give it a shot sometime.', description: 'Did you see this game? We should hang out and give it a shot sometime.',
time : now.minus({day: 1}).toISO(), // 1 day ago time : moment().subtract(1, 'day').toISOString(), // 1 day ago
read : true, read : true,
link : 'https://www.google.com', link : 'https://www.google.com',
useRouter : false useRouter : false
@@ -76,7 +73,7 @@ export const messages = [
image : 'assets/images/avatars/female-09.jpg', image : 'assets/images/avatars/female-09.jpg',
title : 'Cheryl Obrien - HR', title : 'Cheryl Obrien - HR',
description: 'Why did\'t you still look at the kitten pictures I\'ve sent to you!', description: 'Why did\'t you still look at the kitten pictures I\'ve sent to you!',
time : now.minus({day: 3}).toISO(), // 3 days ago time : moment().subtract(3, 'days').toISOString(), // 3 days ago
read : false, read : false,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -86,7 +83,7 @@ export const messages = [
image : 'assets/images/avatars/female-15.jpg', image : 'assets/images/avatars/female-15.jpg',
title : 'Joan Jones - Tech', title : 'Joan Jones - Tech',
description: 'Dude, Cheryl keeps bugging me with kitten pictures all the time :( What are we gonna do about it?', description: 'Dude, Cheryl keeps bugging me with kitten pictures all the time :( What are we gonna do about it?',
time : now.minus({day: 4}).toISO(), // 4 days ago time : moment().subtract(4, 'day').toISOString(), // 4 days ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const notifications = [ export const notifications = [
{ {
@@ -10,14 +7,14 @@ export const notifications = [
icon : 'heroicons_solid:star', icon : 'heroicons_solid:star',
title : 'Daily challenges', title : 'Daily challenges',
description: 'Your submission has been accepted', description: 'Your submission has been accepted',
time : now.minus({minute: 25}).toISO(), // 25 minutes ago time : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
read : false read : false
}, },
{ {
id : '6e3e97e5-effc-4fb7-b730-52a151f0b641', id : '6e3e97e5-effc-4fb7-b730-52a151f0b641',
image : 'assets/images/avatars/male-04.jpg', image : 'assets/images/avatars/male-04.jpg',
description: '<strong>Leo Gill</strong> added you to <em>Top Secret Project</em> group and assigned you as a <em>Project Manager</em>', description: '<strong>Leo Gill</strong> added you to <em>Top Secret Project</em> group and assigned you as a <em>Project Manager</em>',
time : now.minus({minute: 50}).toISO(), // 50 minutes ago time : moment().subtract(50, 'minutes').toISOString(), // 50 minutes ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -27,7 +24,7 @@ export const notifications = [
icon : 'heroicons_solid:mail', icon : 'heroicons_solid:mail',
title : 'Mailbox', title : 'Mailbox',
description: 'You have 15 unread mails across 3 mailboxes', description: 'You have 15 unread mails across 3 mailboxes',
time : now.minus({hour: 3}).toISO(), // 3 hours ago time : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
read : false, read : false,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -37,7 +34,7 @@ export const notifications = [
icon : 'heroicons_solid:refresh', icon : 'heroicons_solid:refresh',
title : 'Cron jobs', title : 'Cron jobs',
description: 'Your <em>Docker container</em> is ready to publish', description: 'Your <em>Docker container</em> is ready to publish',
time : now.minus({hour: 5}).toISO(), // 5 hours ago time : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
read : false, read : false,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -46,7 +43,7 @@ export const notifications = [
id : 'ef7b95a7-8e8b-4616-9619-130d9533add9', id : 'ef7b95a7-8e8b-4616-9619-130d9533add9',
image : 'assets/images/avatars/male-06.jpg', image : 'assets/images/avatars/male-06.jpg',
description: '<strong>Roger Murray</strong> accepted your friend request', description: '<strong>Roger Murray</strong> accepted your friend request',
time : now.minus({hour: 7}).toISO(), // 7 hours ago time : moment().subtract(7, 'hours').toISOString(), // 7 hours ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -55,7 +52,7 @@ export const notifications = [
id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665', id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665',
image : 'assets/images/avatars/female-04.jpg', image : 'assets/images/avatars/female-04.jpg',
description: '<strong>Sophie Stone</strong> sent you a direct message', description: '<strong>Sophie Stone</strong> sent you a direct message',
time : now.minus({hour: 9}).toISO(), // 9 hours ago time : moment().subtract(9, 'hours').toISOString(), // 9 hours ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -65,7 +62,7 @@ export const notifications = [
icon : 'heroicons_solid:mail', icon : 'heroicons_solid:mail',
title : 'Mailbox', title : 'Mailbox',
description: 'You have 3 new mails', description: 'You have 3 new mails',
time : now.minus({day: 1}).toISO(), // 1 day ago time : moment().subtract(1, 'day').toISOString(), // 1 day ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -75,7 +72,7 @@ export const notifications = [
icon : 'heroicons_solid:star', icon : 'heroicons_solid:star',
title : 'Daily challenges', title : 'Daily challenges',
description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days', description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
time : now.minus({day: 3}).toISO(), // 3 days ago time : moment().subtract(3, 'days').toISOString(), // 3 days ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -85,7 +82,7 @@ export const notifications = [
icon : 'heroicons_solid:refresh', icon : 'heroicons_solid:refresh',
title : 'Cron jobs', title : 'Cron jobs',
description: 'Your Vagrant container is ready to download', description: 'Your Vagrant container is ready to download',
time : now.minus({day: 4}).toISO(), // 4 days ago time : moment().subtract(4, 'day').toISOString(), // 4 days ago
read : true, read : true,
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true

View File

@@ -79,9 +79,6 @@ export class SearchMockApi
// Add a link // Add a link
result.link = '/apps/contacts/' + result.id; result.link = '/apps/contacts/' + result.id;
// Add the name as the value
result.value = result.name;
}); });
// Add to the results // Add to the results
@@ -98,8 +95,6 @@ export class SearchMockApi
// Normalize the results // Normalize the results
pagesResults.forEach((result: any) => { pagesResults.forEach((result: any) => {
// Add the page title as the value
result.value = result.title;
}); });
// Add to the results // Add to the results
@@ -118,9 +113,6 @@ export class SearchMockApi
// Add a link // Add a link
result.link = '/apps/tasks/' + result.id; result.link = '/apps/tasks/' + result.id;
// Add the title as the value
result.value = result.title;
}); });
// Add to the results // Add to the results

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,4 @@
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
/* tslint:disable:max-line-length */ /* tslint:disable:max-line-length */
export const crypto = { export const crypto = {
@@ -631,83 +628,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 154.36 y: 154.36
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 154.36 y: 154.36
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 146.94 y: 146.94
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 146.96 y: 146.96
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 146.11 y: 146.11
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 150.26 y: 150.26
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 146.11 y: 146.11
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 150.79 y: 150.79
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 145.36 y: 145.36
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 141.06 y: 141.06
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 140.10 y: 140.10
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 138.31 y: 138.31
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 138.42 y: 138.42
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 138.48 y: 138.48
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 138.71 y: 138.71
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 148.42 y: 148.42
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 146.87 y: 146.87
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 147.07 y: 147.07
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 135.07 y: 135.07
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 135.01 y: 135.01
} }
] ]
@@ -727,83 +724,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 374.77 y: 374.77
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 374.41 y: 374.41
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 375.08 y: 375.08
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 375.08 y: 375.08
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 374.09 y: 374.09
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 368.84 y: 368.84
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 367.49 y: 367.49
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 359.75 y: 359.75
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 366.65 y: 366.65
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 367.52 y: 367.52
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 367.59 y: 367.59
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 364.18 y: 364.18
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 370.11 y: 370.11
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 362.70 y: 362.70
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 362.70 y: 362.70
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 362.77 y: 362.77
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 369.46 y: 369.46
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 371.04 y: 371.04
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 371.48 y: 371.48
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 371.30 y: 371.30
} }
] ]
@@ -823,83 +820,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 0.258 y: 0.258
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 0.256 y: 0.256
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 0.255 y: 0.255
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 0.255 y: 0.255
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 0.254 y: 0.254
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 0.248 y: 0.248
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 0.247 y: 0.247
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 0.249 y: 0.249
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 0.246 y: 0.246
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 0.247 y: 0.247
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 0.247 y: 0.247
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 0.244 y: 0.244
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 0.250 y: 0.250
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 0.242 y: 0.242
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 0.251 y: 0.251
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 0.251 y: 0.251
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 0.251 y: 0.251
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 0.249 y: 0.249
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 0.242 y: 0.242
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 0.240 y: 0.240
} }
] ]
@@ -919,83 +916,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 62.54 y: 62.54
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 61.54 y: 61.54
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 62.55 y: 62.55
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 60.55 y: 60.55
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 59.54 y: 59.54
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 58.48 y: 58.48
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 54.47 y: 54.47
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 51.49 y: 51.49
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 51.46 y: 51.46
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 53.47 y: 53.47
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 52.47 y: 52.47
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 54.44 y: 54.44
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 59.50 y: 59.50
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 62.42 y: 62.42
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 61.42 y: 61.42
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 60.42 y: 60.42
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 58.49 y: 58.49
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 57.51 y: 57.51
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 54.51 y: 54.51
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 51.25 y: 51.25
} }
] ]
@@ -1015,83 +1012,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 53.54 y: 53.54
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 52.54 y: 52.54
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 52.55 y: 52.55
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 46.44 y: 46.44
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 49.50 y: 49.50
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 55.42 y: 55.42
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 54.42 y: 54.42
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 43.49 y: 43.49
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 43.46 y: 43.46
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 41.47 y: 41.47
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 41.47 y: 41.47
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 51.55 y: 51.55
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 48.54 y: 48.54
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 49.48 y: 49.48
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 45.47 y: 45.47
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 51.42 y: 51.42
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 49.49 y: 49.49
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 46.51 y: 46.51
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 41.51 y: 41.51
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 44.25 y: 44.25
} }
] ]
@@ -1111,83 +1108,83 @@ export const crypto = {
name: 'Price', name: 'Price',
data: [ data: [
{ {
x: now.minus({minutes: 20}).toFormat('HH:mm'), x: moment().subtract(20, 'minutes').format('HH:mm'),
y: 14.77 y: 14.77
}, },
{ {
x: now.minus({minutes: 19}).toFormat('HH:mm'), x: moment().subtract(19, 'minutes').format('HH:mm'),
y: 14.41 y: 14.41
}, },
{ {
x: now.minus({minutes: 18}).toFormat('HH:mm'), x: moment().subtract(18, 'minutes').format('HH:mm'),
y: 15.08 y: 15.08
}, },
{ {
x: now.minus({minutes: 17}).toFormat('HH:mm'), x: moment().subtract(17, 'minutes').format('HH:mm'),
y: 15.08 y: 15.08
}, },
{ {
x: now.minus({minutes: 16}).toFormat('HH:mm'), x: moment().subtract(16, 'minutes').format('HH:mm'),
y: 14.09 y: 14.09
}, },
{ {
x: now.minus({minutes: 15}).toFormat('HH:mm'), x: moment().subtract(15, 'minutes').format('HH:mm'),
y: 18.84 y: 18.84
}, },
{ {
x: now.minus({minutes: 14}).toFormat('HH:mm'), x: moment().subtract(14, 'minutes').format('HH:mm'),
y: 17.49 y: 17.49
}, },
{ {
x: now.minus({minutes: 13}).toFormat('HH:mm'), x: moment().subtract(13, 'minutes').format('HH:mm'),
y: 19.75 y: 19.75
}, },
{ {
x: now.minus({minutes: 12}).toFormat('HH:mm'), x: moment().subtract(12, 'minutes').format('HH:mm'),
y: 16.65 y: 16.65
}, },
{ {
x: now.minus({minutes: 11}).toFormat('HH:mm'), x: moment().subtract(11, 'minutes').format('HH:mm'),
y: 17.52 y: 17.52
}, },
{ {
x: now.minus({minutes: 10}).toFormat('HH:mm'), x: moment().subtract(10, 'minutes').format('HH:mm'),
y: 17.59 y: 17.59
}, },
{ {
x: now.minus({minutes: 9}).toFormat('HH:mm'), x: moment().subtract(9, 'minutes').format('HH:mm'),
y: 14.18 y: 14.18
}, },
{ {
x: now.minus({minutes: 8}).toFormat('HH:mm'), x: moment().subtract(8, 'minutes').format('HH:mm'),
y: 10.11 y: 10.11
}, },
{ {
x: now.minus({minutes: 7}).toFormat('HH:mm'), x: moment().subtract(7, 'minutes').format('HH:mm'),
y: 12.70 y: 12.70
}, },
{ {
x: now.minus({minutes: 6}).toFormat('HH:mm'), x: moment().subtract(6, 'minutes').format('HH:mm'),
y: 12.70 y: 12.70
}, },
{ {
x: now.minus({minutes: 5}).toFormat('HH:mm'), x: moment().subtract(5, 'minutes').format('HH:mm'),
y: 12.77 y: 12.77
}, },
{ {
x: now.minus({minutes: 4}).toFormat('HH:mm'), x: moment().subtract(4, 'minutes').format('HH:mm'),
y: 19.46 y: 19.46
}, },
{ {
x: now.minus({minutes: 3}).toFormat('HH:mm'), x: moment().subtract(3, 'minutes').format('HH:mm'),
y: 11.04 y: 11.04
}, },
{ {
x: now.minus({minutes: 2}).toFormat('HH:mm'), x: moment().subtract(2, 'minutes').format('HH:mm'),
y: 11.48 y: 11.48
}, },
{ {
x: now.minus({minutes: 1}).toFormat('HH:mm'), x: moment().subtract(1, 'minutes').format('HH:mm'),
y: 11.30 y: 11.30
} }
] ]

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,5 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const project = { export const project = {
githubIssues : { githubIssues : {
@@ -151,12 +148,12 @@ export const project = {
weeklyExpenses : { weeklyExpenses : {
amount: 17663, amount: 17663,
labels: [ labels: [
now.minus({days: 47}).toFormat('dd MMM') + ' - ' + now.minus({days: 40}).toFormat('dd MMM'), moment().subtract(47, 'days').format('DD MMM') + ' - ' + moment().subtract(40, 'days').format('DD MMM'),
now.minus({days: 39}).toFormat('dd MMM') + ' - ' + now.minus({days: 32}).toFormat('dd MMM'), moment().subtract(39, 'days').format('DD MMM') + ' - ' + moment().subtract(32, 'days').format('DD MMM'),
now.minus({days: 31}).toFormat('dd MMM') + ' - ' + now.minus({days: 24}).toFormat('dd MMM'), moment().subtract(31, 'days').format('DD MMM') + ' - ' + moment().subtract(24, 'days').format('DD MMM'),
now.minus({days: 23}).toFormat('dd MMM') + ' - ' + now.minus({days: 16}).toFormat('dd MMM'), moment().subtract(23, 'days').format('DD MMM') + ' - ' + moment().subtract(16, 'days').format('DD MMM'),
now.minus({days: 15}).toFormat('dd MMM') + ' - ' + now.minus({days: 8}).toFormat('dd MMM'), moment().subtract(15, 'days').format('DD MMM') + ' - ' + moment().subtract(8, 'days').format('DD MMM'),
now.minus({days: 7}).toFormat('dd MMM') + ' - ' + now.toFormat('dd MMM') moment().subtract(7, 'days').format('DD MMM') + ' - ' + moment().format('DD MMM')
], ],
series: [ series: [
{ {
@@ -168,10 +165,10 @@ export const project = {
monthlyExpenses : { monthlyExpenses : {
amount: 54663, amount: 54663,
labels: [ labels: [
now.minus({days: 31}).toFormat('dd MMM') + ' - ' + now.minus({days: 24}).toFormat('dd MMM'), moment().subtract(31, 'days').format('DD MMM') + ' - ' + moment().subtract(24, 'days').format('DD MMM'),
now.minus({days: 23}).toFormat('dd MMM') + ' - ' + now.minus({days: 16}).toFormat('dd MMM'), moment().subtract(23, 'days').format('DD MMM') + ' - ' + moment().subtract(16, 'days').format('DD MMM'),
now.minus({days: 15}).toFormat('dd MMM') + ' - ' + now.minus({days: 8}).toFormat('dd MMM'), moment().subtract(15, 'days').format('DD MMM') + ' - ' + moment().subtract(8, 'days').format('DD MMM'),
now.minus({days: 7}).toFormat('dd MMM') + ' - ' + now.toFormat('dd MMM') moment().subtract(7, 'days').format('DD MMM') + ' - ' + moment().format('DD MMM')
], ],
series: [ series: [
{ {
@@ -183,16 +180,16 @@ export const project = {
yearlyExpenses : { yearlyExpenses : {
amount: 648813, amount: 648813,
labels: [ labels: [
now.minus({days: 79}).toFormat('dd MMM') + ' - ' + now.minus({days: 72}).toFormat('dd MMM'), moment().subtract(79, 'days').format('DD MMM') + ' - ' + moment().subtract(72, 'days').format('DD MMM'),
now.minus({days: 71}).toFormat('dd MMM') + ' - ' + now.minus({days: 64}).toFormat('dd MMM'), moment().subtract(71, 'days').format('DD MMM') + ' - ' + moment().subtract(64, 'days').format('DD MMM'),
now.minus({days: 63}).toFormat('dd MMM') + ' - ' + now.minus({days: 56}).toFormat('dd MMM'), moment().subtract(63, 'days').format('DD MMM') + ' - ' + moment().subtract(56, 'days').format('DD MMM'),
now.minus({days: 55}).toFormat('dd MMM') + ' - ' + now.minus({days: 48}).toFormat('dd MMM'), moment().subtract(55, 'days').format('DD MMM') + ' - ' + moment().subtract(48, 'days').format('DD MMM'),
now.minus({days: 47}).toFormat('dd MMM') + ' - ' + now.minus({days: 40}).toFormat('dd MMM'), moment().subtract(47, 'days').format('DD MMM') + ' - ' + moment().subtract(40, 'days').format('DD MMM'),
now.minus({days: 39}).toFormat('dd MMM') + ' - ' + now.minus({days: 32}).toFormat('dd MMM'), moment().subtract(39, 'days').format('DD MMM') + ' - ' + moment().subtract(32, 'days').format('DD MMM'),
now.minus({days: 31}).toFormat('dd MMM') + ' - ' + now.minus({days: 24}).toFormat('dd MMM'), moment().subtract(31, 'days').format('DD MMM') + ' - ' + moment().subtract(24, 'days').format('DD MMM'),
now.minus({days: 23}).toFormat('dd MMM') + ' - ' + now.minus({days: 16}).toFormat('dd MMM'), moment().subtract(23, 'days').format('DD MMM') + ' - ' + moment().subtract(16, 'days').format('DD MMM'),
now.minus({days: 15}).toFormat('dd MMM') + ' - ' + now.minus({days: 8}).toFormat('dd MMM'), moment().subtract(15, 'days').format('DD MMM') + ' - ' + moment().subtract(8, 'days').format('DD MMM'),
now.minus({days: 7}).toFormat('dd MMM') + ' - ' + now.toFormat('dd MMM') moment().subtract(7, 'days').format('DD MMM') + ' - ' + moment().format('DD MMM')
], ],
series: [ series: [
{ {

View File

@@ -1,15 +1,12 @@
/* eslint-disable */ /* eslint-disable */
import { DateTime } from 'luxon'; import * as moment from 'moment';
/* Get the current instant */
const now = DateTime.now();
export const activities = [ export const activities = [
{ {
id : '493190c9-5b61-4912-afe5-78c21f1044d7', id : '493190c9-5b61-4912-afe5-78c21f1044d7',
icon : 'heroicons_solid:star', icon : 'heroicons_solid:star',
description : 'Your submission has been accepted', description : 'Your submission has been accepted',
date : now.minus({minutes: 25}).toISO(), // 25 minutes ago date : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
extraContent: `<div class="font-bold">Congratulations for your acceptance!</div><br> extraContent: `<div class="font-bold">Congratulations for your acceptance!</div><br>
<div>Hi Brian,<br>Your submission has been accepted and you are ready to move into the next phase. Once you are ready, reach out to me and we will ...</div>` <div>Hi Brian,<br>Your submission has been accepted and you are ready to move into the next phase. Once you are ready, reach out to me and we will ...</div>`
}, },
@@ -17,7 +14,7 @@ export const activities = [
id : '6e3e97e5-effc-4fb7-b730-52a151f0b641', id : '6e3e97e5-effc-4fb7-b730-52a151f0b641',
image : 'assets/images/avatars/male-04.jpg', image : 'assets/images/avatars/male-04.jpg',
description : '<strong>Leo Gill</strong> added you to <strong>Top Secret Project</strong> group and assigned you as a <strong>Project Manager</strong>', description : '<strong>Leo Gill</strong> added you to <strong>Top Secret Project</strong> group and assigned you as a <strong>Project Manager</strong>',
date : now.minus({minutes: 50}).toISO(), // 50 minutes ago date : moment().subtract(50, 'minutes').toISOString(), // 50 minutes ago
linkedContent: 'Top Secret Project', linkedContent: 'Top Secret Project',
link : '/dashboards/project', link : '/dashboards/project',
useRouter : true useRouter : true
@@ -26,7 +23,7 @@ export const activities = [
id : 'b91ccb58-b06c-413b-b389-87010e03a120', id : 'b91ccb58-b06c-413b-b389-87010e03a120',
icon : 'heroicons_solid:mail', icon : 'heroicons_solid:mail',
description : 'You have 15 unread mails across 3 mailboxes', description : 'You have 15 unread mails across 3 mailboxes',
date : now.minus({hours: 3}).toISO(), // 3 hours ago date : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
linkedContent: 'Mailbox', linkedContent: 'Mailbox',
link : '/apps/mailbox', link : '/apps/mailbox',
useRouter : true useRouter : true
@@ -35,7 +32,7 @@ export const activities = [
id : '541416c9-84a7-408a-8d74-27a43c38d797', id : '541416c9-84a7-408a-8d74-27a43c38d797',
icon : 'heroicons_solid:refresh', icon : 'heroicons_solid:refresh',
description : 'Your <strong>Docker container</strong> is ready to publish', description : 'Your <strong>Docker container</strong> is ready to publish',
date : now.minus({hours: 5}).toISO(), // 5 hours ago date : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
linkedContent: 'Download the container', linkedContent: 'Download the container',
link : '.', link : '.',
useRouter : true useRouter : true
@@ -44,20 +41,20 @@ export const activities = [
id : 'ef7b95a7-8e8b-4616-9619-130d9533add9', id : 'ef7b95a7-8e8b-4616-9619-130d9533add9',
image : 'assets/images/avatars/male-06.jpg', image : 'assets/images/avatars/male-06.jpg',
description : '<strong>Roger Murray</strong> accepted your friend request', description : '<strong>Roger Murray</strong> accepted your friend request',
date : now.minus({hours: 7}).toISO(), // 7 hours ago date : moment().subtract(7, 'hours').toISOString(), // 7 hours ago
extraContent: `You have <span class="font-semibold">8</span> mutual friends.` extraContent: `You have <span class="font-semibold">8</span> mutual friends.`
}, },
{ {
id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665', id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665',
image : 'assets/images/avatars/female-04.jpg', image : 'assets/images/avatars/female-04.jpg',
description: '<strong>Sophie Stone</strong> sent you a direct message', description: '<strong>Sophie Stone</strong> sent you a direct message',
date : now.minus({hours: 9}).toISO() // 9 hours ago date : moment().subtract(9, 'hours').toISOString() // 9 hours ago
}, },
{ {
id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e', id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e',
icon : 'heroicons_solid:mail', icon : 'heroicons_solid:mail',
description : 'You have 3 new mails', description : 'You have 3 new mails',
date : now.minus({day: 1}).toISO(), // 1 day ago date : moment().subtract(1, 'day').toISOString(), // 1 day ago
extraContent : `<ol class="list-decimal list-inside space-y-2"> extraContent : `<ol class="list-decimal list-inside space-y-2">
<li class="font-medium">Please review and sign the attached agreement</li> <li class="font-medium">Please review and sign the attached agreement</li>
<li class="font-medium">Delivery address confirmation</li> <li class="font-medium">Delivery address confirmation</li>
@@ -71,7 +68,7 @@ export const activities = [
id : 'fd0f01b4-f3de-4333-add5-cd86850279f8', id : 'fd0f01b4-f3de-4333-add5-cd86850279f8',
image : 'assets/images/avatars/female-02.jpg', image : 'assets/images/avatars/female-02.jpg',
description : '<strong>Tina Harris</strong> started a chat with you', description : '<strong>Tina Harris</strong> started a chat with you',
date : now.minus({day: 1}).toISO(), // 1 day ago, date : moment().subtract(1, 'day').toISOString(), // 1 day ago,
linkedContent: 'Go to Chat (Tina Harris)', linkedContent: 'Go to Chat (Tina Harris)',
link : '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e', link : '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e',
useRouter : true useRouter : true
@@ -80,12 +77,12 @@ export const activities = [
id : '8f8e1bf9-4661-4939-9e43-390957b60f42', id : '8f8e1bf9-4661-4939-9e43-390957b60f42',
icon : 'heroicons_solid:star', icon : 'heroicons_solid:star',
description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days', description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
date : now.minus({days: 3}).toISO() // 3 days ago date : moment().subtract(3, 'days').toISOString() // 3 days ago
}, },
{ {
id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69', id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69',
icon : 'heroicons_solid:refresh', icon : 'heroicons_solid:refresh',
description: 'Your Vagrant container is ready to download', description: 'Your Vagrant container is ready to download',
date : now.minus({day: 4}).toISO() // 4 days ago date : moment().subtract(4, 'day').toISOString() // 4 days ago
} }
]; ];

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { FuseMockApiService } from '@fuse/lib/mock-api'; import { FuseMockApiService } from '@fuse/lib/mock-api';
import { feather, heroicons, material } from 'app/mock-api/ui/icons/data'; import { feather, heroicons, iconsmind, material } from 'app/mock-api/ui/icons/data';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -10,6 +10,7 @@ export class IconsMockApi
{ {
private readonly _feather: any = feather; private readonly _feather: any = feather;
private readonly _heroicons: any = heroicons; private readonly _heroicons: any = heroicons;
private readonly _iconsmind: any = iconsmind;
private readonly _material: any = material; private readonly _material: any = material;
/** /**
@@ -75,6 +76,21 @@ export class IconsMockApi
} }
]); ]);
// -----------------------------------------------------------------------------------------------------
// @ Iconsmind icons - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/ui/icons/iconsmind')
.reply(() => [
200,
{
namespace: 'iconsmind',
name : 'Iconsmind',
grid : 'icon-size-10',
list : cloneDeep(this._iconsmind)
}
]);
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Material solid icons - GET // @ Material solid icons - GET
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
<router-outlet></router-outlet>

View File

@@ -1,17 +0,0 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
@Component({
selector : 'academy',
templateUrl : './academy.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AcademyComponent
{
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,44 +0,0 @@
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 { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseFindByKeyPipeModule } from '@fuse/pipes/find-by-key';
import { SharedModule } from 'app/shared/shared.module';
import { academyRoutes } from 'app/modules/admin/apps/academy/academy.routing';
import { AcademyComponent } from 'app/modules/admin/apps/academy/academy.component';
import { AcademyDetailsComponent } from 'app/modules/admin/apps/academy/details/details.component';
import { AcademyListComponent } from 'app/modules/admin/apps/academy/list/list.component';
import { MatTabsModule } from '@angular/material/tabs';
@NgModule({
declarations: [
AcademyComponent,
AcademyDetailsComponent,
AcademyListComponent
],
imports : [
RouterModule.forChild(academyRoutes),
MatButtonModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatProgressBarModule,
MatSelectModule,
MatSidenavModule,
MatSlideToggleModule,
MatTooltipModule,
FuseFindByKeyPipeModule,
SharedModule,
MatTabsModule
]
})
export class AcademyModule
{
}

View File

@@ -1,109 +0,0 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
import { catchError, Observable, throwError } from 'rxjs';
import { Category, Course } from 'app/modules/admin/apps/academy/academy.types';
import { AcademyService } from 'app/modules/admin/apps/academy/academy.service';
@Injectable({
providedIn: 'root'
})
export class AcademyCategoriesResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(private _academyService: AcademyService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Category[]>
{
return this._academyService.getCategories();
}
}
@Injectable({
providedIn: 'root'
})
export class AcademyCoursesResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(private _academyService: AcademyService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Course[]>
{
return this._academyService.getCourses();
}
}
@Injectable({
providedIn: 'root'
})
export class AcademyCourseResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(
private _router: Router,
private _academyService: AcademyService
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Course>
{
return this._academyService.getCourseById(route.paramMap.get('id'))
.pipe(
// Error here means the requested task is not available
catchError((error) => {
// Log the error
console.error(error);
// Get the parent url
const parentUrl = state.url.split('/').slice(0, -1).join('/');
// Navigate to there
this._router.navigateByUrl(parentUrl);
// Throw an error
return throwError(error);
})
);
}
}

View File

@@ -1,32 +0,0 @@
import { Route } from '@angular/router';
import { AcademyComponent } from 'app/modules/admin/apps/academy/academy.component';
import { AcademyListComponent } from 'app/modules/admin/apps/academy/list/list.component';
import { AcademyDetailsComponent } from 'app/modules/admin/apps/academy/details/details.component';
import { AcademyCategoriesResolver, AcademyCourseResolver, AcademyCoursesResolver } from 'app/modules/admin/apps/academy/academy.resolvers';
export const academyRoutes: Route[] = [
{
path : '',
component: AcademyComponent,
resolve : {
categories: AcademyCategoriesResolver
},
children : [
{
path : '',
pathMatch: 'full',
component: AcademyListComponent,
resolve : {
courses: AcademyCoursesResolver
}
},
{
path : ':id',
component: AcademyDetailsComponent,
resolve : {
course: AcademyCourseResolver
}
}
]
}
];

View File

@@ -1,104 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, map, Observable, of, switchMap, tap, throwError } from 'rxjs';
import { Category, Course } from 'app/modules/admin/apps/academy/academy.types';
@Injectable({
providedIn: 'root'
})
export class AcademyService
{
// Private
private _categories: BehaviorSubject<Category[] | null> = new BehaviorSubject(null);
private _course: BehaviorSubject<Course | null> = new BehaviorSubject(null);
private _courses: BehaviorSubject<Course[] | null> = new BehaviorSubject(null);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for categories
*/
get categories$(): Observable<Category[]>
{
return this._categories.asObservable();
}
/**
* Getter for courses
*/
get courses$(): Observable<Course[]>
{
return this._courses.asObservable();
}
/**
* Getter for course
*/
get course$(): Observable<Course>
{
return this._course.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get categories
*/
getCategories(): Observable<Category[]>
{
return this._httpClient.get<Category[]>('api/apps/academy/categories').pipe(
tap((response: any) => {
this._categories.next(response);
})
);
}
/**
* Get courses
*/
getCourses(): Observable<Course[]>
{
return this._httpClient.get<Course[]>('api/apps/academy/courses').pipe(
tap((response: any) => {
this._courses.next(response);
})
);
}
/**
* Get course by id
*/
getCourseById(id: string): Observable<Course>
{
return this._httpClient.get<Course>('api/apps/academy/courses/course', {params: {id}}).pipe(
map((course) => {
// Update the course
this._course.next(course);
// Return the course
return course;
}),
switchMap((course) => {
if ( !course )
{
return throwError('Could not found course with id of ' + id + '!');
}
return of(course);
})
);
}
}

View File

@@ -1,29 +0,0 @@
export interface Category
{
id?: string;
title?: string;
slug?: string;
}
export interface Course
{
id?: string;
title?: string;
slug?: string;
description?: string;
category?: string;
duration?: number;
steps?: {
order?: number;
title?: string;
subtitle?: string;
content?: string;
}[];
totalSteps?: number;
updatedAt?: number;
featured?: boolean;
progress?: {
currentStep?: number;
completed?: number;
};
}

View File

@@ -1,205 +0,0 @@
<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-90 dark:bg-gray-900"
[autoFocus]="false"
[mode]="drawerMode"
[opened]="drawerOpened"
#matDrawer>
<div class="flex flex-col items-start p-8 border-b">
<!-- Back to courses -->
<a
class="inline-flex items-center leading-6 text-primary hover:underline"
[routerLink]="['..']">
<span class="inline-flex items-center">
<mat-icon
class="icon-size-5 text-current"
[svgIcon]="'heroicons_solid:arrow-sm-left'"></mat-icon>
<span class="ml-1.5 font-medium leading-5">Back to courses</span>
</span>
</a>
<!-- Course category -->
<ng-container *ngIf="(course.category | fuseFindByKey:'slug':categories) as category">
<div
class="mt-7 py-0.5 px-3 rounded-full text-sm font-semibold"
[ngClass]="{'text-blue-800 bg-blue-100 dark:text-blue-50 dark:bg-blue-500': category.slug === 'web',
'text-green-800 bg-green-100 dark:text-green-50 dark:bg-green-500': category.slug === 'android',
'text-pink-800 bg-pink-100 dark:text-pink-50 dark:bg-pink-500': category.slug === 'cloud',
'text-amber-800 bg-amber-100 dark:text-amber-50 dark:bg-amber-500': category.slug === 'firebase'}">
{{category.title}}
</div>
</ng-container>
<!-- Course title & description -->
<div class="mt-3 text-2xl font-semibold">{{course.title}}</div>
<div class="text-secondary">{{course.description}}</div>
<!-- Course time -->
<div class="mt-6 flex items-center leading-5 text-md text-secondary">
<mat-icon
class="icon-size-5 text-hint"
[svgIcon]="'heroicons_solid:clock'"></mat-icon>
<div class="ml-1.5">{{course.duration}} minutes</div>
</div>
</div>
<!-- Steps -->
<div class="py-2 px-8">
<ol>
<ng-container *ngFor="let step of course.steps; let last = last; trackBy: trackByFn">
<li
class="relative group py-6"
[class.current-step]="step.order === currentStep">
<ng-container *ngIf="!last">
<div
class="absolute top-6 left-4 w-0.5 h-full -ml-px"
[ngClass]="{'bg-primary': step.order < currentStep,
'bg-gray-300 dark:bg-gray-600': step.order >= currentStep}"></div>
</ng-container>
<div
class="relative flex items-start cursor-pointer"
(click)="goToStep(step.order)">
<div
class="flex flex-0 items-center justify-center w-8 h-8 rounded-full ring-2 ring-inset bg-card dark:bg-default"
[ngClass]="{'bg-primary dark:bg-primary text-on-primary group-hover:bg-primary-800 ring-transparent': step.order < currentStep,
'ring-primary': step.order === currentStep,
'ring-gray-300 dark:ring-gray-600 group-hover:ring-gray-400': step.order > currentStep}">
<!-- Check icon, show if the step is completed -->
<ng-container *ngIf="step.order < currentStep">
<mat-icon
class="icon-size-5 text-current"
[svgIcon]="'heroicons_solid:check'"></mat-icon>
</ng-container>
<!-- Step order, show if the step is the current step -->
<ng-container *ngIf="step.order === currentStep">
<div class="text-md font-semibold text-primary dark:text-primary-500">{{step.order + 1}}</div>
</ng-container>
<!-- Step order, show if the step is not completed -->
<ng-container *ngIf="step.order > currentStep">
<div class="text-md font-semibold text-hint group-hover:text-secondary">{{step.order + 1}}</div>
</ng-container>
</div>
<div class="ml-4">
<div class="font-medium leading-4">{{step.title}}</div>
<div class="mt-1.5 text-md leading-4 text-secondary">{{step.subtitle}}</div>
</div>
</div>
</li>
</ng-container>
</ol>
</div>
</mat-drawer>
<!-- Drawer content -->
<mat-drawer-content class="flex flex-col overflow-hidden">
<!-- Header -->
<div class="lg:hidden flex flex-0 items-center py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 border-b lg:border-b-0 bg-card dark:bg-transparent">
<!-- Title & Actions -->
<a
mat-icon-button
[routerLink]="['..']">
<mat-icon [svgIcon]="'heroicons_outline:arrow-sm-left'"></mat-icon>
</a>
<h2 class="ml-2.5 text-md sm:text-xl font-medium tracking-tight truncate">
{{course.title}}
</h2>
</div>
<mat-progress-bar
class="hidden lg:block flex-0 h-0.5 w-full"
[value]="100 * (currentStep + 1) / course.totalSteps"></mat-progress-bar>
<!-- Main -->
<div
class="flex-auto overflow-y-auto"
cdkScrollable>
<!-- Steps -->
<mat-tab-group
class="fuse-mat-no-header"
[animationDuration]="'200'"
#courseSteps>
<ng-container *ngFor="let step of course.steps; trackBy: trackByFn">
<mat-tab>
<ng-template matTabContent>
<div
class="prose prose-sm max-w-3xl mx-auto sm:my-2 lg:mt-4 p-6 sm:p-10 sm:py-12 rounded-2xl shadow overflow-hidden bg-card"
[innerHTML]="step.content"></div>
</ng-template>
</mat-tab>
</ng-container>
</mat-tab-group>
<!-- Navigation - Desktop -->
<div class="z-10 sticky hidden lg:flex bottom-4 p-4">
<div class="flex items-center justify-center mx-auto p-2 rounded-full shadow-lg bg-primary">
<button
class="flex-0"
mat-flat-button
[color]="'primary'"
(click)="goToPreviousStep()">
<span class="inline-flex items-center">
<mat-icon
class="mr-2"
[svgIcon]="'heroicons_outline:arrow-narrow-left'"></mat-icon>
<span class="mr-1">Prev</span>
</span>
</button>
<div class="flex items-center justify-center mx-2.5 font-medium leading-5 text-on-primary">
<span>{{currentStep + 1}}</span>
<span class="mx-0.5 text-hint">/</span>
<span>{{course.totalSteps}}</span>
</div>
<button
class="flex-0"
mat-flat-button
[color]="'primary'"
(click)="goToNextStep()">
<span class="inline-flex items-center">
<span class="ml-1">Next</span>
<mat-icon
class="ml-2"
[svgIcon]="'heroicons_outline:arrow-narrow-right'"></mat-icon>
</span>
</button>
</div>
</div>
</div>
<!-- Progress & Navigation - Mobile -->
<div class="lg:hidden flex items-center p-4 border-t bg-card">
<button
mat-icon-button
(click)="matDrawer.toggle()">
<mat-icon [svgIcon]="'heroicons_outline:view-list'"></mat-icon>
</button>
<div class="flex items-center justify-center ml-1 lg:ml-2 font-medium leading-5">
<span>{{currentStep + 1}}</span>
<span class="mx-0.5 text-hint">/</span>
<span>{{course.totalSteps}}</span>
</div>
<mat-progress-bar
class="flex-auto ml-6 rounded-full"
[value]="100 * (currentStep + 1) / course.totalSteps"></mat-progress-bar>
<button
class="ml-4"
mat-icon-button
(click)="goToPreviousStep()">
<mat-icon [svgIcon]="'heroicons_outline:arrow-narrow-left'"></mat-icon>
</button>
<button
class="ml-0.5"
mat-icon-button
(click)="goToNextStep()">
<mat-icon [svgIcon]="'heroicons_outline:arrow-narrow-right'"></mat-icon>
</button>
</div>
</mat-drawer-content>
</mat-drawer-container>
</div>

View File

@@ -1,203 +0,0 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { MatTabGroup } from '@angular/material/tabs';
import { Subject, takeUntil } from 'rxjs';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { Category, Course } from 'app/modules/admin/apps/academy/academy.types';
import { AcademyService } from 'app/modules/admin/apps/academy/academy.service';
@Component({
selector : 'academy-details',
templateUrl : './details.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AcademyDetailsComponent implements OnInit, OnDestroy
{
@ViewChild('courseSteps', {static: true}) courseSteps: MatTabGroup;
categories: Category[];
course: Course;
currentStep: number = 0;
drawerMode: 'over' | 'side' = 'side';
drawerOpened: boolean = true;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
@Inject(DOCUMENT) private _document: Document,
private _academyService: AcademyService,
private _changeDetectorRef: ChangeDetectorRef,
private _elementRef: ElementRef,
private _fuseMediaWatcherService: FuseMediaWatcherService
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the categories
this._academyService.categories$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((categories: Category[]) => {
// Get the categories
this.categories = categories;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Get the course
this._academyService.course$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((course: Course) => {
// Get the course
this.course = course;
// Go to step
this.goToStep(course.progress.currentStep);
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(({matchingAliases}) => {
// Set the drawerMode and drawerOpened
if ( matchingAliases.includes('lg') )
{
this.drawerMode = 'side';
this.drawerOpened = true;
}
else
{
this.drawerMode = 'over';
this.drawerOpened = false;
}
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Go to given step
*
* @param step
*/
goToStep(step: number): void
{
// Set the current step
this.currentStep = step;
// Go to the step
this.courseSteps.selectedIndex = this.currentStep;
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Go to previous step
*/
goToPreviousStep(): void
{
// Return if we already on the first step
if ( this.currentStep === 0 )
{
return;
}
// Go to step
this.goToStep(this.currentStep - 1);
// Scroll the current step selector from sidenav into view
this._scrollCurrentStepElementIntoView();
}
/**
* Go to next step
*/
goToNextStep(): void
{
// Return if we already on the last step
if ( this.currentStep === this.course.totalSteps - 1 )
{
return;
}
// Go to step
this.goToStep(this.currentStep + 1);
// Scroll the current step selector from sidenav into view
this._scrollCurrentStepElementIntoView();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Scrolls the current step element from
* sidenav into the view. This only happens when
* previous/next buttons pressed as we don't want
* to change the scroll position of the sidebar
* when the user actually clicks around the sidebar.
*
* @private
*/
private _scrollCurrentStepElementIntoView(): void
{
// Wrap everything into setTimeout so we can make sure that the 'current-step' class points to correct element
setTimeout(() => {
// Get the current step element and scroll it into view
const currentStepElement = this._document.getElementsByClassName('current-step')[0];
if ( currentStepElement )
{
currentStepElement.scrollIntoView({
behavior: 'smooth',
block : 'start'
});
}
});
}
}

View File

@@ -1,198 +0,0 @@
<div
class="absolute inset-0 flex flex-col min-w-0 overflow-y-auto"
cdkScrollable>
<!-- Header -->
<div class="relative flex-0 py-8 px-4 sm:p-16 overflow-hidden bg-gray-800 dark">
<!-- Background - @formatter:off -->
<!-- Rings -->
<svg class="absolute inset-0 pointer-events-none"
viewBox="0 0 960 540" width="100%" height="100%" preserveAspectRatio="xMidYMax slice" xmlns="http://www.w3.org/2000/svg">
<g class="text-gray-700 opacity-25" fill="none" stroke="currentColor" stroke-width="100">
<circle r="234" cx="196" cy="23"></circle>
<circle r="234" cx="790" cy="491"></circle>
</g>
</svg>
<!-- @formatter:on -->
<div class="z-10 relative flex flex-col items-center">
<h2 class="text-xl font-semibold">FUSE ACADEMY</h2>
<div class="mt-1 text-4xl sm:text-7xl font-extrabold tracking-tight leading-tight text-center">
What do you want to learn today?
</div>
<div class="max-w-2xl mt-6 sm:text-2xl text-center tracking-tight text-secondary">
Our courses will step you through the process of a building small applications, or adding new features to existing applications.
</div>
</div>
</div>
<!-- Main -->
<div class="flex flex-auto p-6 sm:p-10">
<div class="flex flex-col flex-auto w-full max-w-xs sm:max-w-5xl mx-auto">
<!-- Filters -->
<div class="flex flex-col sm:flex-row items-center justify-between w-full max-w-xs sm:max-w-none">
<mat-form-field
class="w-full sm:w-36"
[subscriptSizing]="'dynamic'">
<mat-select
[value]="'all'"
(selectionChange)="filterByCategory($event)">
<mat-option [value]="'all'">All</mat-option>
<ng-container *ngFor="let category of categories; trackBy: trackByFn">
<mat-option [value]="category.slug">{{category.title}}</mat-option>
</ng-container>
</mat-select>
</mat-form-field>
<mat-form-field
class="w-full sm:w-72 mt-4 sm:mt-0 sm:ml-4"
[subscriptSizing]="'dynamic'">
<mat-icon
matPrefix
class="icon-size-5"
[svgIcon]="'heroicons_solid:search'"></mat-icon>
<input
(input)="filterByQuery(query.value)"
placeholder="Search by title or description"
matInput
#query>
</mat-form-field>
<mat-slide-toggle
class="mt-8 sm:mt-0 sm:ml-auto"
[color]="'primary'"
(change)="toggleCompleted($event)">
Hide completed
</mat-slide-toggle>
</div>
<!-- Courses -->
<ng-container *ngIf="this.filteredCourses.length; else noCourses">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 mt-8 sm:mt-10">
<ng-container *ngFor="let course of filteredCourses; trackBy: trackByFn">
<!-- Course -->
<div class="flex flex-col h-96 shadow rounded-2xl overflow-hidden bg-card">
<div class="flex flex-col p-6">
<div class="flex items-center justify-between">
<!-- Course category -->
<ng-container *ngIf="(course.category | fuseFindByKey:'slug':categories) as category">
<div
class="py-0.5 px-3 rounded-full text-sm font-semibold"
[ngClass]="{'text-blue-800 bg-blue-100 dark:text-blue-50 dark:bg-blue-500': category.slug === 'web',
'text-green-800 bg-green-100 dark:text-green-50 dark:bg-green-500': category.slug === 'android',
'text-pink-800 bg-pink-100 dark:text-pink-50 dark:bg-pink-500': category.slug === 'cloud',
'text-amber-800 bg-amber-100 dark:text-amber-50 dark:bg-amber-500': category.slug === 'firebase'}">
{{category.title}}
</div>
</ng-container>
<!-- Completed at least once -->
<div class="flex items-center">
<ng-container *ngIf="course.progress.completed > 0">
<mat-icon
class="icon-size-5 text-green-600"
[svgIcon]="'heroicons_solid:badge-check'"
[matTooltip]="'You completed this course at least once'"></mat-icon>
</ng-container>
</div>
</div>
<!-- Course title & description -->
<div class="mt-4 text-lg font-medium">{{course.title}}</div>
<div class="mt-0.5 line-clamp-2 text-secondary">{{course.description}}</div>
<div class="w-12 h-1 my-6 border-t-2"></div>
<!-- Course time -->
<div class="flex items-center leading-5 text-md text-secondary">
<mat-icon
class="icon-size-5 text-hint"
[svgIcon]="'heroicons_solid:clock'"></mat-icon>
<div class="ml-1.5">{{course.duration}} minutes</div>
</div>
<!-- Course completion -->
<div class="flex items-center mt-2 leading-5 text-md text-secondary">
<mat-icon
class="icon-size-5 text-hint"
[svgIcon]="'heroicons_solid:academic-cap'"></mat-icon>
<ng-container *ngIf="course.progress.completed === 0">
<div class="ml-1.5">Never completed</div>
</ng-container>
<ng-container *ngIf="course.progress.completed > 0">
<div class="ml-1.5">
<span>Completed</span>
<span class="ml-1">
<!-- Once -->
<ng-container *ngIf="course.progress.completed === 1">once</ng-container>
<!-- Twice -->
<ng-container *ngIf="course.progress.completed === 2">twice</ng-container>
<!-- Others -->
<ng-container *ngIf="course.progress.completed > 2">{{course.progress.completed}}
{{course.progress.completed | i18nPlural: {
'=0' : 'time',
'=1' : 'time',
'other': 'times'
} }}
</ng-container>
</span>
</div>
</ng-container>
</div>
</div>
<!-- Footer -->
<div class="flex flex-col w-full mt-auto">
<!-- Course progress -->
<div class="relative h-0.5">
<div
class="z-10 absolute inset-x-0 h-6 -mt-3"
[matTooltip]="course.progress.currentStep / course.totalSteps | percent"
[matTooltipPosition]="'above'"
[matTooltipClass]="'-mb-0.5'"></div>
<mat-progress-bar
class="h-0.5"
[value]="(100 * course.progress.currentStep) / course.totalSteps"></mat-progress-bar>
</div>
<!-- Course launch button -->
<div class="px-6 py-4 text-right bg-gray-50 dark:bg-transparent">
<a
mat-stroked-button
[routerLink]="[course.id]">
<span class="inline-flex items-center">
<!-- Not started -->
<ng-container *ngIf="course.progress.currentStep === 0">
<!-- Never completed -->
<ng-container *ngIf="course.progress.completed === 0">
<span>Start</span>
</ng-container>
<!-- Completed before -->
<ng-container *ngIf="course.progress.completed > 0">
<span>Start again</span>
</ng-container>
</ng-container>
<!-- Started -->
<ng-container *ngIf="course.progress.currentStep > 0">
<span>Continue</span>
</ng-container>
<mat-icon
class="ml-1.5 icon-size-5"
[svgIcon]="'heroicons_solid:arrow-sm-right'"></mat-icon>
</span>
</a>
</div>
</div>
</div>
</ng-container>
</div>
</ng-container>
<!-- No courses -->
<ng-template #noCourses>
<div class="flex flex-auto flex-col items-center justify-center bg-gray-100 dark:bg-transparent">
<mat-icon
class="icon-size-24"
[svgIcon]="'heroicons_outline:document-search'"></mat-icon>
<div class="mt-6 text-2xl font-semibold tracking-tight text-secondary">No courses found!</div>
</div>
</ng-template>
</div>
</div>
</div>

View File

@@ -1,156 +0,0 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MatSelectChange } from '@angular/material/select';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { BehaviorSubject, combineLatest, Subject, takeUntil } from 'rxjs';
import { AcademyService } from 'app/modules/admin/apps/academy/academy.service';
import { Category, Course } from 'app/modules/admin/apps/academy/academy.types';
@Component({
selector : 'academy-list',
templateUrl : './list.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AcademyListComponent implements OnInit, OnDestroy
{
categories: Category[];
courses: Course[];
filteredCourses: Course[];
filters: {
categorySlug$: BehaviorSubject<string>;
query$: BehaviorSubject<string>;
hideCompleted$: BehaviorSubject<boolean>;
} = {
categorySlug$ : new BehaviorSubject('all'),
query$ : new BehaviorSubject(''),
hideCompleted$: new BehaviorSubject(false)
};
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _activatedRoute: ActivatedRoute,
private _changeDetectorRef: ChangeDetectorRef,
private _router: Router,
private _academyService: AcademyService
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the categories
this._academyService.categories$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((categories: Category[]) => {
this.categories = categories;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Get the courses
this._academyService.courses$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((courses: Course[]) => {
this.courses = this.filteredCourses = courses;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Filter the courses
combineLatest([this.filters.categorySlug$, this.filters.query$, this.filters.hideCompleted$])
.subscribe(([categorySlug, query, hideCompleted]) => {
// Reset the filtered courses
this.filteredCourses = this.courses;
// Filter by category
if ( categorySlug !== 'all' )
{
this.filteredCourses = this.filteredCourses.filter(course => course.category === categorySlug);
}
// Filter by search query
if ( query !== '' )
{
this.filteredCourses = this.filteredCourses.filter(course => course.title.toLowerCase().includes(query.toLowerCase())
|| course.description.toLowerCase().includes(query.toLowerCase())
|| course.category.toLowerCase().includes(query.toLowerCase()));
}
// Filter by completed
if ( hideCompleted )
{
this.filteredCourses = this.filteredCourses.filter(course => course.progress.completed === 0);
}
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Filter by search query
*
* @param query
*/
filterByQuery(query: string): void
{
this.filters.query$.next(query);
}
/**
* Filter by category
*
* @param change
*/
filterByCategory(change: MatSelectChange): void
{
this.filters.categorySlug$.next(change.value);
}
/**
* Show/hide completed courses
*
* @param change
*/
toggleCompleted(change: MatSlideToggleChange): void
{
this.filters.hideCompleted$.next(change.checked);
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -1,8 +0,0 @@
<div class="absolute inset-0 flex flex-col min-w-0 overflow-hidden">
<!-- Main -->
<div class="flex flex-auto overflow-hidden">
<router-outlet></router-outlet>
</div>
</div>

View File

@@ -1,17 +0,0 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
@Component({
selector : 'chat',
templateUrl : './chat.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChatComponent
{
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,44 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
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 { MatSidenavModule } from '@angular/material/sidenav';
import { SharedModule } from 'app/shared/shared.module';
import { chatRoutes } from 'app/modules/admin/apps/chat/chat.routing';
import { ChatComponent } from 'app/modules/admin/apps/chat/chat.component';
import { ChatsComponent } from 'app/modules/admin/apps/chat/chats/chats.component';
import { ContactInfoComponent } from 'app/modules/admin/apps/chat/contact-info/contact-info.component';
import { EmptyConversationComponent } from 'app/modules/admin/apps/chat/empty-conversation/empty-conversation.component';
import { ConversationComponent } from 'app/modules/admin/apps/chat/conversation/conversation.component';
import { NewChatComponent } from 'app/modules/admin/apps/chat/new-chat/new-chat.component';
import { ProfileComponent } from 'app/modules/admin/apps/chat/profile/profile.component';
@NgModule({
declarations: [
ChatComponent,
ChatsComponent,
ContactInfoComponent,
ConversationComponent,
EmptyConversationComponent,
NewChatComponent,
ProfileComponent
],
imports : [
RouterModule.forChild(chatRoutes),
MatButtonModule,
MatCheckboxModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatMenuModule,
MatSidenavModule,
SharedModule
]
})
export class ChatModule
{
}

View File

@@ -1,146 +0,0 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
import { catchError, Observable, throwError } from 'rxjs';
import { ChatService } from 'app/modules/admin/apps/chat/chat.service';
import { Chat, Contact, Profile } from 'app/modules/admin/apps/chat/chat.types';
@Injectable({
providedIn: 'root'
})
export class ChatChatsResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(
private _chatService: ChatService,
private _router: Router
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Chat[]> | any
{
return this._chatService.getChats();
}
}
@Injectable({
providedIn: 'root'
})
export class ChatChatResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(
private _chatService: ChatService,
private _router: Router
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Chat>
{
return this._chatService.getChatById(route.paramMap.get('id'))
.pipe(
// Error here means the requested chat is not available
catchError((error) => {
// Log the error
console.error(error);
// Get the parent url
const parentUrl = state.url.split('/').slice(0, -1).join('/');
// Navigate to there
this._router.navigateByUrl(parentUrl);
// Throw an error
return throwError(error);
})
);
}
}
@Injectable({
providedIn: 'root'
})
export class ChatContactsResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(
private _chatService: ChatService,
private _router: Router
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Contact[]> | any
{
return this._chatService.getContacts();
}
}
@Injectable({
providedIn: 'root'
})
export class ChatProfileResolver implements Resolve<any>
{
/**
* Constructor
*/
constructor(
private _chatService: ChatService,
private _router: Router
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Resolver
*
* @param route
* @param state
*/
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Profile> | any
{
return this._chatService.getProfile();
}
}

View File

@@ -1,38 +0,0 @@
import { Route } from '@angular/router';
import { ChatChatResolver, ChatChatsResolver, ChatContactsResolver, ChatProfileResolver } from 'app/modules/admin/apps/chat/chat.resolvers';
import { ChatComponent } from 'app/modules/admin/apps/chat/chat.component';
import { ChatsComponent } from 'app/modules/admin/apps/chat/chats/chats.component';
import { ConversationComponent } from 'app/modules/admin/apps/chat/conversation/conversation.component';
import { EmptyConversationComponent } from 'app/modules/admin/apps/chat/empty-conversation/empty-conversation.component';
export const chatRoutes: Route[] = [
{
path : '',
component: ChatComponent,
resolve : {
chats : ChatChatsResolver,
contacts: ChatContactsResolver,
profile : ChatProfileResolver
},
children : [
{
path : '',
component: ChatsComponent,
children : [
{
path : '',
pathMatch: 'full',
component: EmptyConversationComponent
},
{
path : ':id',
component: ConversationComponent,
resolve : {
conversation: ChatChatResolver
}
}
]
}
]
}
];

View File

@@ -1,201 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, filter, map, Observable, of, switchMap, take, tap, throwError } from 'rxjs';
import { Chat, Contact, Profile } from 'app/modules/admin/apps/chat/chat.types';
@Injectable({
providedIn: 'root'
})
export class ChatService
{
private _chat: BehaviorSubject<Chat> = new BehaviorSubject(null);
private _chats: BehaviorSubject<Chat[]> = new BehaviorSubject(null);
private _contact: BehaviorSubject<Contact> = new BehaviorSubject(null);
private _contacts: BehaviorSubject<Contact[]> = new BehaviorSubject(null);
private _profile: BehaviorSubject<Profile> = new BehaviorSubject(null);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for chat
*/
get chat$(): Observable<Chat>
{
return this._chat.asObservable();
}
/**
* Getter for chats
*/
get chats$(): Observable<Chat[]>
{
return this._chats.asObservable();
}
/**
* Getter for contact
*/
get contact$(): Observable<Contact>
{
return this._contact.asObservable();
}
/**
* Getter for contacts
*/
get contacts$(): Observable<Contact[]>
{
return this._contacts.asObservable();
}
/**
* Getter for profile
*/
get profile$(): Observable<Profile>
{
return this._profile.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 contact
*
* @param id
*/
getContact(id: string): Observable<any>
{
return this._httpClient.get<Contact>('api/apps/chat/contacts', {params: {id}}).pipe(
tap((response: Contact) => {
this._contact.next(response);
})
);
}
/**
* Get contacts
*/
getContacts(): Observable<any>
{
return this._httpClient.get<Contact[]>('api/apps/chat/contacts').pipe(
tap((response: Contact[]) => {
this._contacts.next(response);
})
);
}
/**
* Get profile
*/
getProfile(): Observable<any>
{
return this._httpClient.get<Profile>('api/apps/chat/profile').pipe(
tap((response: Profile) => {
this._profile.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);
})
);
}
/**
* Update chat
*
* @param id
* @param chat
*/
updateChat(id: string, chat: Chat): Observable<Chat>
{
return this.chats$.pipe(
take(1),
switchMap(chats => this._httpClient.patch<Chat>('api/apps/chat/chat', {
id,
chat
}).pipe(
map((updatedChat) => {
// Find the index of the updated chat
const index = chats.findIndex(item => item.id === id);
// Update the chat
chats[index] = updatedChat;
// Update the chats
this._chats.next(chats);
// Return the updated contact
return updatedChat;
}),
switchMap(updatedChat => this.chat$.pipe(
take(1),
filter(item => item && item.id === id),
tap(() => {
// Update the chat if it's selected
this._chat.next(updatedChat);
// Return the updated chat
return updatedChat;
})
))
))
);
}
/**
* Reset the selected chat
*/
resetChat(): void
{
this._chat.next(null);
}
}

View File

@@ -1,55 +0,0 @@
export interface Profile
{
id?: string;
name?: string;
email?: string;
avatar?: string;
about?: 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[];
};
}
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;
}[];
}

View File

@@ -1,191 +0,0 @@
<div class="relative flex flex-auto w-full bg-card dark:bg-transparent">
<mat-drawer-container
class="flex-auto h-full"
[hasBackdrop]="false">
<!-- Drawer -->
<mat-drawer
class="w-full sm:w-100 lg:border-r lg:shadow-none dark:bg-gray-900"
[autoFocus]="false"
[(opened)]="drawerOpened"
#drawer>
<!-- New chat -->
<ng-container *ngIf="drawerComponent === 'new-chat'">
<chat-new-chat [drawer]="drawer"></chat-new-chat>
</ng-container>
<!-- Profile -->
<ng-container *ngIf="drawerComponent === 'profile'">
<chat-profile [drawer]="drawer"></chat-profile>
</ng-container>
</mat-drawer>
<!-- Drawer content -->
<mat-drawer-content class="flex overflow-hidden">
<!-- Chats list -->
<ng-container *ngIf="chats && chats.length > 0; else noChats">
<div class="relative flex flex-auto flex-col w-full min-w-0 lg:min-w-100 lg:max-w-100 bg-card dark:bg-transparent">
<!-- Header -->
<div class="flex flex-col flex-0 py-4 px-8 border-b bg-gray-50 dark:bg-transparent">
<div class="flex items-center">
<div
class="flex items-center mr-1 cursor-pointer"
(click)="openProfile()">
<div class="w-10 h-10">
<ng-container *ngIf="profile.avatar">
<img
class="object-cover w-full h-full rounded-full object-cover"
[src]="profile.avatar"
alt="Profile avatar"/>
</ng-container>
<ng-container *ngIf="!profile.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">
{{profile.name.charAt(0)}}
</div>
</ng-container>
</div>
<div class="ml-4 font-medium truncate">{{profile.name}}</div>
</div>
<button
class="ml-auto"
mat-icon-button
(click)="openNewChat()">
<mat-icon [svgIcon]="'heroicons_outline:plus-circle'"></mat-icon>
</button>
<button
class="ml-1 -mr-4"
mat-icon-button
[matMenuTriggerFor]="chatsHeaderMenu">
<mat-icon [svgIcon]="'heroicons_outline:dots-vertical'"></mat-icon>
<mat-menu #chatsHeaderMenu>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:user-group'"></mat-icon>
New group
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:chat-alt-2'"></mat-icon>
Create a room
</button>
<button
mat-menu-item
(click)="openProfile()">
<mat-icon [svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
Profile
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:archive'"></mat-icon>
Archived
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:star'"></mat-icon>
Starred
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:cog'"></mat-icon>
Settings
</button>
</mat-menu>
</button>
</div>
<!-- Search -->
<div class="mt-4">
<mat-form-field
class="fuse-mat-rounded fuse-mat-dense w-full"
[subscriptSizing]="'dynamic'">
<mat-icon
matPrefix
class="icon-size-5"
[svgIcon]="'heroicons_solid:search'"></mat-icon>
<input
matInput
[autocomplete]="'off'"
[placeholder]="'Search or start new chat'"
(input)="filterChats(searchField.value)"
#searchField>
</mat-form-field>
</div>
</div>
<!-- Chats -->
<div class="flex-auto overflow-y-auto">
<ng-container *ngIf="filteredChats.length > 0; else noChats">
<ng-container *ngFor="let chat of filteredChats; trackBy: trackByFn">
<a
class="z-20 flex items-center py-5 px-8 cursor-pointer border-b"
[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}"
[routerLink]="[chat.id]">
<div class="relative flex flex-0 items-center justify-center w-10 h-10">
<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 class="min-w-0 ml-4">
<div class="font-medium leading-5 truncate">{{chat.contact.name}}</div>
<div
class="leading-5 truncate text-secondary"
[class.text-primary]="chat.unreadCount > 0"
[class.dark:text-primary-500]="chat.unreadCount > 0">
{{chat.lastMessage}}
</div>
</div>
<div class="flex flex-col items-end self-start ml-auto pl-2">
<div class="text-sm leading-5 text-secondary">{{chat.lastMessageAt}}</div>
<ng-container *ngIf="chat.muted">
<mat-icon
class="icon-size-5 text-hint"
[svgIcon]="'heroicons_solid:volume-off'"></mat-icon>
</ng-container>
</div>
</a>
</ng-container>
</ng-container>
</div>
</div>
</ng-container>
<!-- No chats template -->
<ng-template #noChats>
<div class="flex flex-auto flex-col items-center justify-center h-full">
<mat-icon
class="icon-size-24"
[svgIcon]="'heroicons_outline:chat'"></mat-icon>
<div class="mt-4 text-2xl font-semibold tracking-tight text-secondary">No chats</div>
</div>
</ng-template>
<!-- Conversation -->
<ng-container *ngIf="chats && chats.length > 0">
<div
class="flex-auto border-l"
[ngClass]="{'z-20 absolute inset-0 lg:static lg:inset-auto flex': selectedChat && selectedChat.id,
'hidden lg:flex': !selectedChat || !selectedChat.id}">
<router-outlet></router-outlet>
</div>
</ng-container>
</mat-drawer-content>
</mat-drawer-container>
</div>

View File

@@ -1,137 +0,0 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
import { Chat, Profile } from 'app/modules/admin/apps/chat/chat.types';
import { ChatService } from 'app/modules/admin/apps/chat/chat.service';
@Component({
selector : 'chat-chats',
templateUrl : './chats.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChatsComponent implements OnInit, OnDestroy
{
chats: Chat[];
drawerComponent: 'profile' | 'new-chat';
drawerOpened: boolean = false;
filteredChats: Chat[];
profile: Profile;
selectedChat: Chat;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _chatService: ChatService,
private _changeDetectorRef: ChangeDetectorRef
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Chats
this._chatService.chats$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((chats: Chat[]) => {
this.chats = this.filteredChats = chats;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Profile
this._chatService.profile$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((profile: Profile) => {
this.profile = profile;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Selected chat
this._chatService.chat$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((chat: Chat) => {
this.selectedChat = chat;
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Filter the chats
*
* @param query
*/
filterChats(query: string): void
{
// Reset the filter
if ( !query )
{
this.filteredChats = this.chats;
return;
}
this.filteredChats = this.chats.filter(chat => chat.contact.name.toLowerCase().includes(query.toLowerCase()));
}
/**
* Open the new chat sidebar
*/
openNewChat(): void
{
this.drawerComponent = 'new-chat';
this.drawerOpened = true;
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Open the profile sidebar
*/
openProfile(): void
{
this.drawerComponent = 'profile';
this.drawerOpened = true;
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -1,86 +0,0 @@
<div class="flex flex-col flex-auto h-full bg-card dark:bg-default">
<!-- Header -->
<div class="flex flex-0 items-center h-18 px-4 border-b bg-gray-50 dark:bg-transparent">
<button
mat-icon-button
(click)="drawer.close()">
<mat-icon [svgIcon]="'heroicons_outline:x'"></mat-icon>
</button>
<div class="ml-2 text-lg font-medium">Contact info</div>
</div>
<div class="overflow-y-auto">
<!-- Contact avatar & info -->
<div class="flex flex-col items-center mt-8">
<div class="w-40 h-40 rounded-full">
<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-8xl font-semibold 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="mt-4 text-lg font-medium">{{chat.contact.name}}</div>
<div class="mt-0.5 text-md text-secondary">{{chat.contact.about}}</div>
</div>
<div class="py-10 px-7">
<!-- Media -->
<div class="text-lg font-medium">Media</div>
<div class="grid grid-cols-4 gap-1 mt-4">
<ng-container *ngFor="let media of chat.contact.attachments.media">
<img
class="h-20 rounded object-cover"
[src]="media"/>
</ng-container>
</div>
<!-- Details -->
<div class="mt-10 space-y-4">
<div class="text-lg font-medium mb-3">Details</div>
<ng-container *ngIf="chat.contact.details.emails.length">
<div>
<div class="font-medium text-secondary">Email</div>
<div class="">{{chat.contact.details.emails[0].email}}</div>
</div>
</ng-container>
<ng-container *ngIf="chat.contact.details.phoneNumbers.length">
<div>
<div class="font-medium text-secondary">Phone number</div>
<div class="">{{chat.contact.details.phoneNumbers[0].phoneNumber}}</div>
</div>
</ng-container>
<ng-container *ngIf="chat.contact.details.title">
<div>
<div class="font-medium text-secondary">Title</div>
<div class="">{{chat.contact.details.title}}</div>
</div>
</ng-container>
<ng-container *ngIf="chat.contact.details.company">
<div>
<div class="font-medium text-secondary">Company</div>
<div class="">{{chat.contact.details.company}}</div>
</div>
</ng-container>
<ng-container *ngIf="chat.contact.details.birthday">
<div>
<div class="font-medium text-secondary">Birthday</div>
<div class="">{{chat.contact.details.birthday}}</div>
</div>
</ng-container>
<ng-container *ngIf="chat.contact.details.address">
<div>
<div class="font-medium text-secondary">Address</div>
<div class="">{{chat.contact.details.address}}</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>

View File

@@ -1,22 +0,0 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { MatDrawer } from '@angular/material/sidenav';
import { Chat } from 'app/modules/admin/apps/chat/chat.types';
@Component({
selector : 'chat-contact-info',
templateUrl : './contact-info.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ContactInfoComponent
{
@Input() chat: Chat;
@Input() drawer: MatDrawer;
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,215 +0,0 @@
<div class="flex flex-col flex-auto overflow-y-auto lg:overflow-hidden bg-card dark:bg-default">
<ng-container *ngIf="chat; else selectChatOrStartNew">
<mat-drawer-container
class="flex-auto h-full"
[hasBackdrop]="false">
<!-- Drawer -->
<mat-drawer
class="w-full sm:w-100 lg:border-l lg:shadow-none dark:bg-gray-900"
[autoFocus]="false"
[mode]="drawerMode"
[position]="'end'"
[(opened)]="drawerOpened"
#drawer>
<!-- Contact info -->
<chat-contact-info
[drawer]="drawer"
[chat]="chat"></chat-contact-info>
</mat-drawer>
<!-- Drawer content -->
<mat-drawer-content class="flex flex-col overflow-hidden">
<!-- Header -->
<div class="flex flex-0 items-center h-18 px-4 md:px-6 border-b bg-gray-50 dark:bg-transparent">
<!-- Back button -->
<a
class="lg:hidden md:-ml-2"
mat-icon-button
[routerLink]="['./']"
(click)="resetChat()">
<mat-icon [svgIcon]="'heroicons_outline:arrow-narrow-left'"></mat-icon>
</a>
<!-- Contact info -->
<div
class="flex items-center ml-2 lg:ml-0 mr-2 cursor-pointer"
(click)="openContactInfo()">
<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>
</div>
<button
class="ml-auto"
mat-icon-button
[matMenuTriggerFor]="conversationHeaderMenu">
<mat-icon [svgIcon]="'heroicons_outline:dots-vertical'"></mat-icon>
<mat-menu #conversationHeaderMenu>
<button
mat-menu-item
(click)="openContactInfo()">
<mat-icon [svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
Contact info
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
Select messages
</button>
<button
mat-menu-item
(click)="toggleMuteNotifications()">
<ng-container *ngIf="!chat.muted">
<mat-icon [svgIcon]="'heroicons_outline:volume-off'"></mat-icon>
Mute notifications
</ng-container>
<ng-container *ngIf="chat.muted">
<mat-icon [svgIcon]="'heroicons_outline:volume-up'"></mat-icon>
Unmute notifications
</ng-container>
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:backspace'"></mat-icon>
Clear messages
</button>
<button mat-menu-item>
<mat-icon [svgIcon]="'heroicons_outline:trash'"></mat-icon>
Delete chat
</button>
</mat-menu>
</button>
</div>
<!-- Conversation -->
<div class="flex overflow-y-auto flex-col-reverse">
<div class="flex flex-col flex-auto shrink p-6 bg-card dark:bg-transparent">
<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"
[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">
<div class="flex items-center h-11 my-px">
<button mat-icon-button>
<mat-icon [svgIcon]="'heroicons_outline:emoji-happy'"></mat-icon>
</button>
<button
class="ml-0.5"
mat-icon-button>
<mat-icon [svgIcon]="'heroicons_outline:paper-clip'"></mat-icon>
</button>
</div>
<mat-form-field
class="fuse-mat-dense fuse-mat-rounded fuse-mat-bold w-full ml-4"
subscriptSizing="dynamic">
<textarea
matInput
cdkTextareaAutosize
#messageInput></textarea>
</mat-form-field>
<div class="flex items-center h-11 my-px ml-4">
<button
mat-icon-button>
<mat-icon
class="rotate-90"
[svgIcon]="'heroicons_outline:paper-airplane'"></mat-icon>
</button>
</div>
</div>
</mat-drawer-content>
</mat-drawer-container>
</ng-container>
<!-- Select chat or start new template -->
<ng-template #selectChatOrStartNew>
<div class="flex flex-col flex-auto items-center justify-center bg-gray-100 dark:bg-transparent">
<mat-icon
class="icon-size-24"
[svgIcon]="'heroicons_outline:chat'"></mat-icon>
<div class="mt-4 text-2xl font-semibold tracking-tight text-secondary">Select a conversation or start a new chat</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 -->
</div>

View File

@@ -1,167 +0,0 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostListener, NgZone, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { Chat } from 'app/modules/admin/apps/chat/chat.types';
import { ChatService } from 'app/modules/admin/apps/chat/chat.service';
@Component({
selector : 'chat-conversation',
templateUrl : './conversation.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ConversationComponent implements OnInit, OnDestroy
{
@ViewChild('messageInput') messageInput: ElementRef;
chat: Chat;
drawerMode: 'over' | 'side' = 'side';
drawerOpened: boolean = false;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _chatService: ChatService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _ngZone: NgZone
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* 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';
// Detect the changes so the height is applied
this._changeDetectorRef.detectChanges();
// Get the scrollHeight and subtract the vertical padding
this.messageInput.nativeElement.style.height = `${this.messageInput.nativeElement.scrollHeight}px`;
// Detect the changes one more time to apply the final height
this._changeDetectorRef.detectChanges();
});
});
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Chat
this._chatService.chat$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((chat: Chat) => {
this.chat = chat;
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Subscribe to media changes
this._fuseMediaWatcherService.onMediaChange$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(({matchingAliases}) => {
// Set the drawerMode if the given breakpoint is active
if ( matchingAliases.includes('lg') )
{
this.drawerMode = 'side';
}
else
{
this.drawerMode = 'over';
}
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the contact info
*/
openContactInfo(): void
{
// Open the drawer
this.drawerOpened = true;
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Reset the chat
*/
resetChat(): void
{
this._chatService.resetChat();
// Close the contact info in case it's opened
this.drawerOpened = false;
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Toggle mute notifications
*/
toggleMuteNotifications(): void
{
// Toggle the muted
this.chat.muted = !this.chat.muted;
// Update the chat on the server
this._chatService.updateChat(this.chat.id, this.chat).subscribe();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -1,11 +0,0 @@
<div class="flex flex-col flex-auto overflow-y-auto lg:overflow-hidden bg-card dark:bg-default">
<!-- Select chat or start new -->
<div class="flex flex-col flex-auto items-center justify-center bg-gray-100 dark:bg-transparent">
<mat-icon
class="icon-size-24"
[svgIcon]="'heroicons_outline:chat'"></mat-icon>
<div class="mt-4 text-2xl font-semibold tracking-tight text-secondary">Select a conversation or start a new chat</div>
</div>
</div>

View File

@@ -1,17 +0,0 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
@Component({
selector : 'chat-empty-conversation',
templateUrl : './empty-conversation.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EmptyConversationComponent
{
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,51 +0,0 @@
<div class="flex flex-col flex-auto h-full overflow-hidden bg-card dark:bg-default">
<!-- Header -->
<div class="flex flex-0 items-center h-18 -mb-px px-6 bg-gray-50 dark:bg-transparent">
<button
mat-icon-button
(click)="drawer.close()">
<mat-icon [svgIcon]="'heroicons_outline:arrow-narrow-left'"></mat-icon>
</button>
<div class="ml-2 text-2xl font-semibold">New chat</div>
</div>
<div class="relative overflow-y-auto">
<ng-container *ngIf="contacts.length; else noContacts">
<ng-container *ngFor="let contact of contacts; let i = index; trackBy: trackByFn">
<!-- Group -->
<ng-container *ngIf="i === 0 || contact.name.charAt(0) !== contacts[i - 1].name.charAt(0)">
<div class="z-10 sticky top-0 -mt-px px-6 py-1 md:px-8 border-t border-b font-medium uppercase text-secondary bg-gray-100 dark:bg-gray-900">
{{contact.name.charAt(0)}}
</div>
</ng-container>
<!-- Contact -->
<div class="z-20 flex items-center px-6 py-4 md:px-8 cursor-pointer border-b hover:bg-gray-100 dark:hover:bg-hover">
<div class="flex flex-0 items-center justify-center w-10 h-10 rounded-full overflow-hidden">
<ng-container *ngIf="contact.avatar">
<img
class="object-cover w-full h-full"
[src]="contact.avatar"
alt="Contact avatar"/>
</ng-container>
<ng-container *ngIf="!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">
{{contact.name.charAt(0)}}
</div>
</ng-container>
</div>
<div class="min-w-0 ml-4">
<div class="font-medium leading-5 truncate">{{contact.name}}</div>
<div class="leading-5 truncate text-secondary">{{contact.about}}</div>
</div>
</div>
</ng-container>
</ng-container>
</div>
<!-- No contacts -->
<ng-template #noContacts>
<div class="p-8 sm:p-16 border-t text-4xl font-semibold tracking-tight text-center">There are no contacts!</div>
</ng-template>
</div>

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