mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-23 13:37:05 +00:00
Compare commits
140 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de7a598c07 | ||
|
|
8ae3cdfbea | ||
|
|
533e39261b | ||
|
|
7870e312b9 | ||
|
|
1662042e35 | ||
|
|
08266c3e51 | ||
|
|
8000e53bae | ||
|
|
8fbef029c0 | ||
|
|
b7b849ee60 | ||
|
|
872dffe42b | ||
|
|
646b084a12 | ||
|
|
c88d30a4f4 | ||
|
|
f2d5bf3041 | ||
|
|
388456b937 | ||
|
|
127280c040 | ||
|
|
cad7cd43f0 | ||
|
|
41756200ca | ||
|
|
4a5f641c1c | ||
|
|
39ad558455 | ||
|
|
404c4f5c07 | ||
|
|
51ee16ed93 | ||
|
|
607f2afa90 | ||
|
|
baf35619bd | ||
|
|
6599587e31 | ||
|
|
3fa878b3f2 | ||
|
|
a24bc3fc95 | ||
|
|
9b1c0f2541 | ||
|
|
3ba64abf6e | ||
|
|
82ed80e35d | ||
|
|
72a63b30ca | ||
|
|
d2b37efed4 | ||
|
|
6d516a119a | ||
|
|
3adf9bee6e | ||
|
|
bb06bccf91 | ||
|
|
3018c0235f | ||
|
|
a6399c0cf4 | ||
|
|
22d91673ae | ||
|
|
3e303a041a | ||
|
|
714bc49c4e | ||
|
|
3cc4f31238 | ||
|
|
c5aa094230 | ||
|
|
cbd35d57f8 | ||
|
|
11d5dcdb9d | ||
|
|
66e5511402 | ||
|
|
20a03c3689 | ||
|
|
d033470851 | ||
|
|
c374c2c6cf | ||
|
|
30d75c9bd7 | ||
|
|
54cd21f496 | ||
|
|
57d87fa1c4 | ||
|
|
cd8c6ece0f | ||
|
|
1bf4c48cdc | ||
|
|
ea9efc3dc2 | ||
|
|
878a6bf191 | ||
|
|
099e745a36 | ||
|
|
150ddc64d7 | ||
|
|
a6d64b1747 | ||
|
|
6eff4a1898 | ||
|
|
e3630218b5 | ||
|
|
154095da0f | ||
|
|
a32970b7c2 | ||
|
|
2771d3b1ae | ||
|
|
9b44793b64 | ||
|
|
9521257b4d | ||
|
|
5378a6b6ef | ||
|
|
c41e48df7f | ||
|
|
b87173b056 | ||
|
|
6aaa355a48 | ||
|
|
b96dd041d9 | ||
|
|
9786c6baf5 | ||
|
|
f5cc14939c | ||
|
|
8fd434600b | ||
|
|
4c82f6749b | ||
|
|
b0830148a3 | ||
|
|
cdc54ab05e | ||
|
|
e6ad547d27 | ||
|
|
afda4b35c9 | ||
|
|
3b88638dee | ||
|
|
b96182c848 | ||
|
|
443a103d6f | ||
|
|
42241b279d | ||
|
|
e5eaea5013 | ||
|
|
6e85b9ff2a | ||
|
|
6e593b1f1e | ||
|
|
57a3f6ae99 | ||
|
|
700a117654 | ||
|
|
5337c95782 | ||
|
|
964c4b23a9 | ||
|
|
a8337ce617 | ||
|
|
3ceda2cf3f | ||
|
|
805b50707e | ||
|
|
3fd522de31 | ||
|
|
4a2c7560e8 | ||
|
|
46753d5402 | ||
|
|
9d3e971325 | ||
|
|
9d7c015fe7 | ||
|
|
4b5cac11f2 | ||
|
|
6c62d25c35 | ||
|
|
5c46b1aaa4 | ||
|
|
3a1a7d44b6 | ||
|
|
0076b1ee8a | ||
|
|
c69542679d | ||
|
|
e4ebe2fd7e | ||
|
|
f380d8ca16 | ||
|
|
6b14c1db7f | ||
|
|
20901117d1 | ||
|
|
83e3c85448 | ||
|
|
4d4b411f76 | ||
|
|
7b5217d009 | ||
|
|
e671100bc5 | ||
|
|
f910615831 | ||
|
|
778679e136 | ||
|
|
c25610ee4e | ||
|
|
3ddd7e4533 | ||
|
|
c21c362b84 | ||
|
|
9f97d74911 | ||
|
|
08aec7c3db | ||
|
|
0f249f287e | ||
|
|
c7b8a4564b | ||
|
|
b6a3023ebd | ||
|
|
693e44dbaf | ||
|
|
206ef711a4 | ||
|
|
7e0cc1249e | ||
|
|
138a43da59 | ||
|
|
fe7e2514a6 | ||
|
|
b8f0d9f0b2 | ||
|
|
2a4a392153 | ||
|
|
c2fa88f4d4 | ||
|
|
67d25012ec | ||
|
|
6de6a07778 | ||
|
|
e7ab0ea13f | ||
|
|
4b686d86cc | ||
|
|
190395f14b | ||
|
|
4a9b8ee91e | ||
|
|
488fe8a1eb | ||
|
|
db9a2a2433 | ||
|
|
3dda8479cf | ||
|
|
7c402670a1 | ||
|
|
f6bf0fb5d3 | ||
|
|
d44c004d01 |
@@ -1,17 +0,0 @@
|
|||||||
# 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
|
|
||||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,6 +31,7 @@ chrome-profiler-events*.json
|
|||||||
.history/*
|
.history/*
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
|
/.angular/cache
|
||||||
/.sass-cache
|
/.sass-cache
|
||||||
/connect.lock
|
/connect.lock
|
||||||
/coverage
|
/coverage
|
||||||
|
|||||||
@@ -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 app will automatically reload if you change any of the source files.
|
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.
|
||||||
|
|
||||||
## Code scaffolding
|
## Code scaffolding
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
|
|||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
## Running unit tests
|
## Running unit tests
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
|
|||||||
|
|
||||||
## Running end-to-end tests
|
## Running end-to-end tests
|
||||||
|
|
||||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice.
|
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||||
|
|
||||||
## Further help
|
## Further help
|
||||||
|
|
||||||
|
|||||||
42
angular.json
42
angular.json
@@ -20,7 +20,9 @@
|
|||||||
"outputPath": "dist/fuse",
|
"outputPath": "dist/fuse",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": [
|
||||||
|
"zone.js"
|
||||||
|
],
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"inlineStyleLanguage": "scss",
|
"inlineStyleLanguage": "scss",
|
||||||
"allowedCommonJsDependencies": [
|
"allowedCommonJsDependencies": [
|
||||||
@@ -28,7 +30,9 @@
|
|||||||
"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",
|
||||||
@@ -60,19 +64,13 @@
|
|||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "5mb",
|
"maximumWarning": "3mb",
|
||||||
"maximumError": "8mb"
|
"maximumError": "5mb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "100kb",
|
"maximumWarning": "75kb",
|
||||||
"maximumError": "150kb"
|
"maximumError": "90kb"
|
||||||
}
|
|
||||||
],
|
|
||||||
"fileReplacements": [
|
|
||||||
{
|
|
||||||
"replace": "src/environments/environment.ts",
|
|
||||||
"with": "src/environments/environment.prod.ts"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputHashing": "all"
|
"outputHashing": "all"
|
||||||
@@ -109,10 +107,11 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"main": "src/test.ts",
|
"polyfills": [
|
||||||
"polyfills": "src/polyfills.ts",
|
"zone.js",
|
||||||
|
"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",
|
||||||
@@ -124,21 +123,8 @@
|
|||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-eslint/builder:lint",
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.html"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"defaultProject": "fuse",
|
|
||||||
"cli": {
|
|
||||||
"defaultCollection": "@angular-eslint/schematics"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
// 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
|
|
||||||
});
|
|
||||||
};
|
|
||||||
27115
package-lock.json
generated
27115
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
115
package.json
115
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@fuse/demo",
|
"name": "fuse-angular",
|
||||||
"version": "13.4.0",
|
"version": "17.0.0",
|
||||||
"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",
|
||||||
@@ -9,82 +9,59 @@
|
|||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"test": "ng test",
|
"watch": "ng build --watch --configuration development",
|
||||||
"lint": "ng lint"
|
"test": "ng test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "12.1.4",
|
"@angular/animations": "15.0.0",
|
||||||
"@angular/cdk": "12.1.4",
|
"@angular/cdk": "15.0.0",
|
||||||
"@angular/common": "12.1.4",
|
"@angular/common": "15.0.0",
|
||||||
"@angular/compiler": "12.1.4",
|
"@angular/compiler": "15.0.0",
|
||||||
"@angular/core": "12.1.4",
|
"@angular/core": "15.0.0",
|
||||||
"@angular/forms": "12.1.4",
|
"@angular/forms": "15.0.0",
|
||||||
"@angular/material": "12.1.4",
|
"@angular/material": "15.0.0",
|
||||||
"@angular/material-moment-adapter": "12.1.4",
|
"@angular/material-luxon-adapter": "15.0.0",
|
||||||
"@angular/platform-browser": "12.1.4",
|
"@angular/platform-browser": "15.0.0",
|
||||||
"@angular/platform-browser-dynamic": "12.1.4",
|
"@angular/platform-browser-dynamic": "15.0.0",
|
||||||
"@angular/router": "12.1.4",
|
"@angular/router": "15.0.0",
|
||||||
"@fullcalendar/angular": "4.4.5-beta",
|
"@ngneat/transloco": "4.1.1",
|
||||||
"@fullcalendar/core": "4.4.2",
|
"apexcharts": "3.36.3",
|
||||||
"@fullcalendar/daygrid": "4.4.2",
|
|
||||||
"@fullcalendar/interaction": "4.4.2",
|
|
||||||
"@fullcalendar/list": "4.4.2",
|
|
||||||
"@fullcalendar/moment": "4.4.2",
|
|
||||||
"@fullcalendar/rrule": "4.4.2",
|
|
||||||
"@fullcalendar/timegrid": "4.4.2",
|
|
||||||
"@ngneat/transloco": "2.22.0",
|
|
||||||
"apexcharts": "3.27.3",
|
|
||||||
"crypto-js": "3.3.0",
|
"crypto-js": "3.3.0",
|
||||||
"highlight.js": "11.1.0",
|
"highlight.js": "11.6.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"moment": "2.29.1",
|
"luxon": "3.1.0",
|
||||||
"ng-apexcharts": "1.5.12",
|
"ng-apexcharts": "1.7.4",
|
||||||
"ngx-markdown": "12.0.1",
|
"ngx-quill": "19.0.1",
|
||||||
"ngx-quill": "14.1.2",
|
"perfect-scrollbar": "1.5.5",
|
||||||
"perfect-scrollbar": "1.5.2",
|
|
||||||
"quill": "1.3.7",
|
"quill": "1.3.7",
|
||||||
"rrule": "2.6.8",
|
"rxjs": "7.5.7",
|
||||||
"rxjs": "6.6.7",
|
"tslib": "2.4.1",
|
||||||
"tslib": "2.3.0",
|
"zone.js": "0.12.0"
|
||||||
"web-animations-js": "2.3.2",
|
|
||||||
"zone.js": "0.11.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "12.1.4",
|
"@angular-devkit/build-angular": "15.0.0",
|
||||||
"@angular-eslint/builder": "12.3.1",
|
"@angular/cli": "15.0.0",
|
||||||
"@angular-eslint/eslint-plugin": "12.3.1",
|
"@angular/compiler-cli": "15.0.0",
|
||||||
"@angular-eslint/eslint-plugin-template": "12.3.1",
|
"@tailwindcss/line-clamp": "0.4.2",
|
||||||
"@angular-eslint/schematics": "12.3.1",
|
"@tailwindcss/typography": "0.5.8",
|
||||||
"@angular-eslint/template-parser": "12.3.1",
|
"@types/chroma-js": "2.1.4",
|
||||||
"@angular/cli": "12.1.4",
|
|
||||||
"@angular/compiler-cli": "12.1.4",
|
|
||||||
"@tailwindcss/aspect-ratio": "0.2.1",
|
|
||||||
"@tailwindcss/line-clamp": "0.2.1",
|
|
||||||
"@tailwindcss/typography": "0.4.1",
|
|
||||||
"@types/chroma-js": "2.1.3",
|
|
||||||
"@types/crypto-js": "3.1.47",
|
"@types/crypto-js": "3.1.47",
|
||||||
"@types/highlight.js": "10.1.0",
|
"@types/highlight.js": "10.1.0",
|
||||||
"@types/jasmine": "3.8.2",
|
"@types/jasmine": "4.3.0",
|
||||||
"@types/lodash": "4.14.171",
|
"@types/lodash": "4.14.189",
|
||||||
"@types/lodash-es": "4.17.4",
|
"@types/lodash-es": "4.17.6",
|
||||||
"@types/node": "12.20.17",
|
"@types/luxon": "3.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "4.28.5",
|
"autoprefixer": "10.4.13",
|
||||||
"@typescript-eslint/parser": "4.28.5",
|
"chroma-js": "2.4.2",
|
||||||
"autoprefixer": "10.3.1",
|
"jasmine-core": "4.5.0",
|
||||||
"chroma-js": "2.1.2",
|
"karma": "6.4.1",
|
||||||
"eslint": "7.31.0",
|
"karma-chrome-launcher": "3.1.1",
|
||||||
"eslint-plugin-import": "2.23.4",
|
"karma-coverage": "2.2.0",
|
||||||
"eslint-plugin-jsdoc": "36.0.6",
|
"karma-jasmine": "5.1.0",
|
||||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
"karma-jasmine-html-reporter": "2.0.0",
|
||||||
"jasmine-core": "3.8.0",
|
|
||||||
"karma": "6.3.4",
|
|
||||||
"karma-chrome-launcher": "3.1.0",
|
|
||||||
"karma-coverage": "2.0.3",
|
|
||||||
"karma-jasmine": "4.0.1",
|
|
||||||
"karma-jasmine-html-reporter": "1.7.0",
|
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"postcss": "8.3.6",
|
"postcss": "8.4.19",
|
||||||
"tailwindcss": "2.2.7",
|
"tailwindcss": "3.2.4",
|
||||||
"typescript": "4.3.5"
|
"typescript": "4.8.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||||
import { Subject } from 'rxjs';
|
import { filter, Subject, takeUntil } from 'rxjs';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
|
||||||
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
import { fuseAnimations } from '@fuse/animations';
|
import { fuseAnimations } from '@fuse/animations';
|
||||||
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
|
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
|
||||||
@@ -54,6 +53,7 @@ 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,6 +71,7 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
@@ -145,7 +146,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,12 +38,14 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
<div
|
|
||||||
class="range"
|
|
||||||
(click)="openPickerPanel()"
|
|
||||||
#pickerPanelOrigin>
|
|
||||||
|
|
||||||
<div class="start">
|
|
||||||
<div class="date">{{range.startDate}}</div>
|
|
||||||
<div
|
|
||||||
class="time"
|
|
||||||
*ngIf="range.startTime">{{range.startTime}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator">-</div>
|
|
||||||
|
|
||||||
<div class="end">
|
|
||||||
<div class="date">{{range.endDate}}</div>
|
|
||||||
<div
|
|
||||||
class="time"
|
|
||||||
*ngIf="range.endTime">{{range.endTime}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #pickerPanel>
|
|
||||||
|
|
||||||
<!-- Start -->
|
|
||||||
<div class="start">
|
|
||||||
|
|
||||||
<div class="month">
|
|
||||||
<div class="month-header">
|
|
||||||
<button
|
|
||||||
class="previous-button"
|
|
||||||
mat-icon-button
|
|
||||||
(click)="prev()"
|
|
||||||
tabindex="1">
|
|
||||||
<mat-icon [svgIcon]="'heroicons_outline:chevron-left'"></mat-icon>
|
|
||||||
</button>
|
|
||||||
<div class="month-label">{{getMonthLabel(1)}}</div>
|
|
||||||
</div>
|
|
||||||
<mat-month-view
|
|
||||||
[(activeDate)]="activeDates.month1"
|
|
||||||
[dateFilter]="dateFilter()"
|
|
||||||
[dateClass]="dateClass()"
|
|
||||||
(click)="$event.stopImmediatePropagation()"
|
|
||||||
(selectedChange)="onSelectedDateChange($event)"
|
|
||||||
#matMonthView1>
|
|
||||||
</mat-month-view>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-form-field
|
|
||||||
class="fuse-mat-no-subscript time start-time"
|
|
||||||
*ngIf="timeRange">
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
[autocomplete]="'off'"
|
|
||||||
[formControl]="startTimeFormControl"
|
|
||||||
(blur)="updateStartTime($event)"
|
|
||||||
tabindex="3">
|
|
||||||
<mat-label>Start time</mat-label>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- End -->
|
|
||||||
<div class="end">
|
|
||||||
|
|
||||||
<div class="month">
|
|
||||||
<div class="month-header">
|
|
||||||
<div class="month-label">{{getMonthLabel(2)}}</div>
|
|
||||||
<button
|
|
||||||
class="next-button"
|
|
||||||
mat-icon-button
|
|
||||||
(click)="next()"
|
|
||||||
tabindex="2">
|
|
||||||
<mat-icon [svgIcon]="'heroicons_outline:chevron-right'"></mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<mat-month-view
|
|
||||||
[(activeDate)]="activeDates.month2"
|
|
||||||
[dateFilter]="dateFilter()"
|
|
||||||
[dateClass]="dateClass()"
|
|
||||||
(click)="$event.stopImmediatePropagation()"
|
|
||||||
(selectedChange)="onSelectedDateChange($event)"
|
|
||||||
#matMonthView2>
|
|
||||||
</mat-month-view>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-form-field
|
|
||||||
class="fuse-mat-no-subscript time end-time"
|
|
||||||
*ngIf="timeRange">
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
[formControl]="endTimeFormControl"
|
|
||||||
(blur)="updateEndTime($event)"
|
|
||||||
tabindex="4">
|
|
||||||
<mat-label>End time</mat-label>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</ng-template>
|
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
/* Variables */
|
|
||||||
$body-cell-padding: 2px;
|
|
||||||
|
|
||||||
fuse-date-range {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.range {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 48px;
|
|
||||||
min-height: 48px;
|
|
||||||
max-height: 48px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.start,
|
|
||||||
.end {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
border-width: 1px;
|
|
||||||
line-height: 1;
|
|
||||||
@apply shadow-sm border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500;
|
|
||||||
|
|
||||||
.date {
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
+ .time {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator {
|
|
||||||
margin: 0 2px;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
margin: 0 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fuse-date-range-panel {
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 24px;
|
|
||||||
@apply shadow-2xl bg-card;
|
|
||||||
|
|
||||||
.start,
|
|
||||||
.end {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.month {
|
|
||||||
max-width: 196px;
|
|
||||||
min-width: 196px;
|
|
||||||
width: 196px;
|
|
||||||
|
|
||||||
.month-header {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 32px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.previous-button,
|
|
||||||
.next-button {
|
|
||||||
position: absolute;
|
|
||||||
width: 24px !important;
|
|
||||||
height: 24px !important;
|
|
||||||
min-height: 24px !important;
|
|
||||||
max-height: 24px !important;
|
|
||||||
line-height: 24px !important;
|
|
||||||
|
|
||||||
.mat-icon {
|
|
||||||
@apply icon-size-5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.previous-button {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next-button {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.month-label {
|
|
||||||
font-weight: 500;
|
|
||||||
@apply text-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-month-view {
|
|
||||||
display: flex;
|
|
||||||
min-height: 188px;
|
|
||||||
|
|
||||||
.mat-calendar-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
tbody {
|
|
||||||
|
|
||||||
tr {
|
|
||||||
|
|
||||||
&[aria-hidden=true] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
|
|
||||||
td:first-child {
|
|
||||||
|
|
||||||
&[aria-hidden=true] {
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
td:hover {
|
|
||||||
|
|
||||||
&.fuse-date-range {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
@apply bg-primary-200;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-calendar-body-cell-content {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-start,
|
|
||||||
&.fuse-date-range-end {
|
|
||||||
|
|
||||||
.mat-calendar-body-cell-content {
|
|
||||||
@apply bg-primary text-on-primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-calendar-body-today {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-calendar-body-cell {
|
|
||||||
width: 28px !important;
|
|
||||||
height: 28px !important;
|
|
||||||
padding: $body-cell-padding !important;
|
|
||||||
|
|
||||||
&.fuse-date-range {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: $body-cell-padding;
|
|
||||||
right: 0;
|
|
||||||
bottom: $body-cell-padding;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-start {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
left: $body-cell-padding;
|
|
||||||
border-radius: 999px 0 0 999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-end,
|
|
||||||
&:last-child {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
right: $body-cell-padding;
|
|
||||||
border-radius: 999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-end {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
right: $body-cell-padding;
|
|
||||||
border-radius: 0 999px 999px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
left: $body-cell-padding;
|
|
||||||
border-radius: 999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-radius: 999px 0 0 999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-radius: 0 999px 999px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-calendar-body-cell-content {
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td.mat-calendar-body-label {
|
|
||||||
|
|
||||||
+ td.mat-calendar-body-cell {
|
|
||||||
|
|
||||||
&.fuse-date-range {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-radius: 999px 0 0 999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-start {
|
|
||||||
|
|
||||||
&.fuse-date-range-end {
|
|
||||||
border-radius: 999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fuse-date-range-end {
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
left: $body-cell-padding;
|
|
||||||
border-radius: 999px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 196px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.start {
|
|
||||||
align-items: flex-start;
|
|
||||||
margin-right: 20px;
|
|
||||||
|
|
||||||
.month {
|
|
||||||
|
|
||||||
.month-label {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.end {
|
|
||||||
align-items: flex-end;
|
|
||||||
margin-left: 20px;
|
|
||||||
|
|
||||||
.month {
|
|
||||||
|
|
||||||
.month-label {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,682 +0,0 @@
|
|||||||
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, HostBinding, Input, OnDestroy, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
|
||||||
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
|
||||||
import { Overlay } from '@angular/cdk/overlay';
|
|
||||||
import { TemplatePortal } from '@angular/cdk/portal';
|
|
||||||
import { MatCalendarCellCssClasses, MatMonthView } from '@angular/material/datepicker';
|
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import * as moment from 'moment';
|
|
||||||
import { Moment } from 'moment';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector : 'fuse-date-range',
|
|
||||||
templateUrl : './date-range.component.html',
|
|
||||||
styleUrls : ['./date-range.component.scss'],
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
|
||||||
exportAs : 'fuseDateRange',
|
|
||||||
providers : [
|
|
||||||
{
|
|
||||||
provide : NG_VALUE_ACCESSOR,
|
|
||||||
useExisting: forwardRef(() => FuseDateRangeComponent),
|
|
||||||
multi : true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnDestroy
|
|
||||||
{
|
|
||||||
@Output() readonly rangeChanged: EventEmitter<{ start: string; end: string }> = new EventEmitter<{ start: string; end: string }>();
|
|
||||||
@ViewChild('matMonthView1') private _matMonthView1: MatMonthView<any>;
|
|
||||||
@ViewChild('matMonthView2') private _matMonthView2: MatMonthView<any>;
|
|
||||||
@ViewChild('pickerPanelOrigin', {read: ElementRef}) private _pickerPanelOrigin: ElementRef;
|
|
||||||
@ViewChild('pickerPanel') private _pickerPanel: TemplateRef<any>;
|
|
||||||
@HostBinding('class.fuse-date-range') private _defaultClassNames = true;
|
|
||||||
|
|
||||||
activeDates: { month1: Moment | null; month2: Moment | null } = {
|
|
||||||
month1: null,
|
|
||||||
month2: null
|
|
||||||
};
|
|
||||||
setWhichDate: 'start' | 'end' = 'start';
|
|
||||||
startTimeFormControl: FormControl;
|
|
||||||
endTimeFormControl: FormControl;
|
|
||||||
private _dateFormat: string;
|
|
||||||
private _onChange: (value: any) => void;
|
|
||||||
private _onTouched: (value: any) => void;
|
|
||||||
private _programmaticChange!: boolean;
|
|
||||||
private _range: { start: Moment | null; end: Moment | null } = {
|
|
||||||
start: null,
|
|
||||||
end : null
|
|
||||||
};
|
|
||||||
private _timeFormat: string;
|
|
||||||
private _timeRange: boolean;
|
|
||||||
private readonly _timeRegExp: RegExp = new RegExp('^(0[0-9]|1[0-9]|2[0-4]|[0-9]):([0-5][0-9])(A|(?:AM)|P|(?:PM))?$', 'i');
|
|
||||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
private _changeDetectorRef: ChangeDetectorRef,
|
|
||||||
private _elementRef: ElementRef,
|
|
||||||
private _overlay: Overlay,
|
|
||||||
private _renderer2: Renderer2,
|
|
||||||
private _viewContainerRef: ViewContainerRef
|
|
||||||
)
|
|
||||||
{
|
|
||||||
this._onChange = (): void => {
|
|
||||||
};
|
|
||||||
this._onTouched = (): void => {
|
|
||||||
};
|
|
||||||
this.dateFormat = 'DD/MM/YYYY';
|
|
||||||
this.timeFormat = '12';
|
|
||||||
|
|
||||||
// Initialize the component
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Accessors
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter & getter for dateFormat input
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
@Input()
|
|
||||||
set dateFormat(value: string)
|
|
||||||
{
|
|
||||||
// Return if the values are the same
|
|
||||||
if ( this._dateFormat === value )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the value
|
|
||||||
this._dateFormat = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dateFormat(): string
|
|
||||||
{
|
|
||||||
return this._dateFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter & getter for timeFormat input
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
@Input()
|
|
||||||
set timeFormat(value: string)
|
|
||||||
{
|
|
||||||
// Return if the values are the same
|
|
||||||
if ( this._timeFormat === value )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set format based on the time format input
|
|
||||||
this._timeFormat = value === '12' ? 'hh:mmA' : 'HH:mm';
|
|
||||||
}
|
|
||||||
|
|
||||||
get timeFormat(): string
|
|
||||||
{
|
|
||||||
return this._timeFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter & getter for timeRange input
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
@Input()
|
|
||||||
set timeRange(value: boolean)
|
|
||||||
{
|
|
||||||
// Return if the values are the same
|
|
||||||
if ( this._timeRange === value )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the value
|
|
||||||
this._timeRange = value;
|
|
||||||
|
|
||||||
// If the time range turned off...
|
|
||||||
if ( !value )
|
|
||||||
{
|
|
||||||
this.range = {
|
|
||||||
start: this._range.start.clone().startOf('day'),
|
|
||||||
end : this._range.end.clone().endOf('day')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get timeRange(): boolean
|
|
||||||
{
|
|
||||||
return this._timeRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter & getter for range input
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
@Input()
|
|
||||||
set range(value)
|
|
||||||
{
|
|
||||||
if ( !value )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the value is an object and has 'start' and 'end' values
|
|
||||||
if ( !value.start || !value.end )
|
|
||||||
{
|
|
||||||
console.error('Range input must have "start" and "end" properties!');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we are setting an individual date or both of them
|
|
||||||
const whichDate = value.whichDate || null;
|
|
||||||
|
|
||||||
// Get the start and end dates as moment
|
|
||||||
const start = moment(value.start);
|
|
||||||
const end = moment(value.end);
|
|
||||||
|
|
||||||
// If we are only setting the start date...
|
|
||||||
if ( whichDate === 'start' )
|
|
||||||
{
|
|
||||||
// Set the start date
|
|
||||||
this._range.start = start.clone();
|
|
||||||
|
|
||||||
// If the selected start date is after the end date...
|
|
||||||
if ( this._range.start.isAfter(this._range.end) )
|
|
||||||
{
|
|
||||||
// Set the end date to the start date but keep the end date's time
|
|
||||||
const endDate = start.clone().hours(this._range.end.hours()).minutes(this._range.end.minutes()).seconds(this._range.end.seconds());
|
|
||||||
|
|
||||||
// Test this new end date to see if it's ahead of the start date
|
|
||||||
if ( this._range.start.isBefore(endDate) )
|
|
||||||
{
|
|
||||||
// If it's, set the new end date
|
|
||||||
this._range.end = endDate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise, set the end date same as the start date
|
|
||||||
this._range.end = start.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are only setting the end date...
|
|
||||||
if ( whichDate === 'end' )
|
|
||||||
{
|
|
||||||
// Set the end date
|
|
||||||
this._range.end = end.clone();
|
|
||||||
|
|
||||||
// If the selected end date is before the start date...
|
|
||||||
if ( this._range.start.isAfter(this._range.end) )
|
|
||||||
{
|
|
||||||
// Set the start date to the end date but keep the start date's time
|
|
||||||
const startDate = end.clone().hours(this._range.start.hours()).minutes(this._range.start.minutes()).seconds(this._range.start.seconds());
|
|
||||||
|
|
||||||
// Test this new end date to see if it's ahead of the start date
|
|
||||||
if ( this._range.end.isAfter(startDate) )
|
|
||||||
{
|
|
||||||
// If it's, set the new start date
|
|
||||||
this._range.start = startDate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise, set the start date same as the end date
|
|
||||||
this._range.start = end.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are setting both dates...
|
|
||||||
if ( !whichDate )
|
|
||||||
{
|
|
||||||
// Set the start date
|
|
||||||
this._range.start = start.clone();
|
|
||||||
|
|
||||||
// If the start date is before the end date, set the end date as normal.
|
|
||||||
// If the start date is after the end date, set the end date same as the start date.
|
|
||||||
this._range.end = start.isBefore(end) ? end.clone() : start.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare another range object that holds the ISO formatted range dates
|
|
||||||
const range = {
|
|
||||||
start: this._range.start.clone().toISOString(),
|
|
||||||
end : this._range.end.clone().toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Emit the range changed event with the range
|
|
||||||
this.rangeChanged.emit(range);
|
|
||||||
|
|
||||||
// Update the model with the range if the change was not a programmatic change
|
|
||||||
// Because programmatic changes trigger writeValue which triggers onChange and onTouched
|
|
||||||
// internally causing them to trigger twice which breaks the form's pristine and touched
|
|
||||||
// statuses.
|
|
||||||
if ( !this._programmaticChange )
|
|
||||||
{
|
|
||||||
this._onTouched(range);
|
|
||||||
this._onChange(range);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the active dates
|
|
||||||
this.activeDates = {
|
|
||||||
month1: this._range.start.clone(),
|
|
||||||
month2: this._range.start.clone().add(1, 'month')
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the time form controls
|
|
||||||
this.startTimeFormControl.setValue(this._range.start.clone().format(this._timeFormat).toString());
|
|
||||||
this.endTimeFormControl.setValue(this._range.end.clone().format(this._timeFormat).toString());
|
|
||||||
|
|
||||||
// Run ngAfterContentInit on month views to trigger
|
|
||||||
// re-render on month views if they are available
|
|
||||||
if ( this._matMonthView1 && this._matMonthView2 )
|
|
||||||
{
|
|
||||||
this._matMonthView1.ngAfterContentInit();
|
|
||||||
this._matMonthView2.ngAfterContentInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the programmatic change status
|
|
||||||
this._programmaticChange = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get range(): any
|
|
||||||
{
|
|
||||||
// Clone the range start and end
|
|
||||||
const start = this._range.start.clone();
|
|
||||||
const end = this._range.end.clone();
|
|
||||||
|
|
||||||
// Build and return the range object
|
|
||||||
return {
|
|
||||||
startDate: start.clone().format(this.dateFormat),
|
|
||||||
startTime: this.timeRange ? start.clone().format(this.timeFormat) : null,
|
|
||||||
endDate : end.clone().format(this.dateFormat),
|
|
||||||
endTime : this.timeRange ? end.clone().format(this.timeFormat) : null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Control Value Accessor
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the form model on change
|
|
||||||
*
|
|
||||||
* @param fn
|
|
||||||
*/
|
|
||||||
registerOnChange(fn: any): void
|
|
||||||
{
|
|
||||||
this._onChange = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the form model on blur
|
|
||||||
*
|
|
||||||
* @param fn
|
|
||||||
*/
|
|
||||||
registerOnTouched(fn: any): void
|
|
||||||
{
|
|
||||||
this._onTouched = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write to view from model when the form model changes programmatically
|
|
||||||
*
|
|
||||||
* @param range
|
|
||||||
*/
|
|
||||||
writeValue(range: { start: string; end: string }): void
|
|
||||||
{
|
|
||||||
// Set this change as a programmatic one
|
|
||||||
this._programmaticChange = true;
|
|
||||||
|
|
||||||
// Set the range
|
|
||||||
this.range = range;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Lifecycle hooks
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On init
|
|
||||||
*/
|
|
||||||
ngOnInit(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On destroy
|
|
||||||
*/
|
|
||||||
ngOnDestroy(): void
|
|
||||||
{
|
|
||||||
// Unsubscribe from all subscriptions
|
|
||||||
this._unsubscribeAll.next();
|
|
||||||
this._unsubscribeAll.complete();
|
|
||||||
|
|
||||||
// @ TODO: Workaround until "angular/issues/20007" resolved
|
|
||||||
this.writeValue = (): void => {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Public methods
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the picker panel
|
|
||||||
*/
|
|
||||||
openPickerPanel(): void
|
|
||||||
{
|
|
||||||
// Create the overlay
|
|
||||||
const overlayRef = this._overlay.create({
|
|
||||||
panelClass : 'fuse-date-range-panel',
|
|
||||||
backdropClass : '',
|
|
||||||
hasBackdrop : true,
|
|
||||||
scrollStrategy : this._overlay.scrollStrategies.reposition(),
|
|
||||||
positionStrategy: this._overlay.position()
|
|
||||||
.flexibleConnectedTo(this._pickerPanelOrigin)
|
|
||||||
.withPositions([
|
|
||||||
{
|
|
||||||
originX : 'start',
|
|
||||||
originY : 'bottom',
|
|
||||||
overlayX: 'start',
|
|
||||||
overlayY: 'top',
|
|
||||||
offsetY : 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
originX : 'start',
|
|
||||||
originY : 'top',
|
|
||||||
overlayX: 'start',
|
|
||||||
overlayY: 'bottom',
|
|
||||||
offsetY : -8
|
|
||||||
}
|
|
||||||
])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a portal from the template
|
|
||||||
const templatePortal = new TemplatePortal(this._pickerPanel, this._viewContainerRef);
|
|
||||||
|
|
||||||
// On backdrop click
|
|
||||||
overlayRef.backdropClick().subscribe(() => {
|
|
||||||
|
|
||||||
// If template portal exists and attached...
|
|
||||||
if ( templatePortal && templatePortal.isAttached )
|
|
||||||
{
|
|
||||||
// Detach it
|
|
||||||
templatePortal.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If overlay exists and attached...
|
|
||||||
if ( overlayRef && overlayRef.hasAttached() )
|
|
||||||
{
|
|
||||||
// Detach it
|
|
||||||
overlayRef.detach();
|
|
||||||
overlayRef.dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attach the portal to the overlay
|
|
||||||
overlayRef.attach(templatePortal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get month label
|
|
||||||
*
|
|
||||||
* @param month
|
|
||||||
*/
|
|
||||||
getMonthLabel(month: number): string
|
|
||||||
{
|
|
||||||
if ( month === 1 )
|
|
||||||
{
|
|
||||||
return this.activeDates.month1.clone().format('MMMM Y');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.activeDates.month2.clone().format('MMMM Y');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date class function to add/remove class names to calendar days
|
|
||||||
*/
|
|
||||||
dateClass(): any
|
|
||||||
{
|
|
||||||
return (date: Moment): MatCalendarCellCssClasses => {
|
|
||||||
|
|
||||||
// If the date is both start and end date...
|
|
||||||
if ( date.isSame(this._range.start, 'day') && date.isSame(this._range.end, 'day') )
|
|
||||||
{
|
|
||||||
return ['fuse-date-range', 'fuse-date-range-start', 'fuse-date-range-end'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the date is the start date...
|
|
||||||
if ( date.isSame(this._range.start, 'day') )
|
|
||||||
{
|
|
||||||
return ['fuse-date-range', 'fuse-date-range-start'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the date is the end date...
|
|
||||||
if ( date.isSame(this._range.end, 'day') )
|
|
||||||
{
|
|
||||||
return ['fuse-date-range', 'fuse-date-range-end'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the date is in between start and end dates...
|
|
||||||
if ( date.isBetween(this._range.start, this._range.end, 'day') )
|
|
||||||
{
|
|
||||||
return ['fuse-date-range', 'fuse-date-range-mid'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date filter to enable/disable calendar days
|
|
||||||
*/
|
|
||||||
dateFilter(): any
|
|
||||||
{
|
|
||||||
// If we are selecting the end date, disable all the dates that comes before the start date
|
|
||||||
return (date: Moment): boolean => !(this.setWhichDate === 'end' && date.isBefore(this._range.start, 'day'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On selected date change
|
|
||||||
*
|
|
||||||
* @param date
|
|
||||||
*/
|
|
||||||
onSelectedDateChange(date: Moment): void
|
|
||||||
{
|
|
||||||
// Create a new range object
|
|
||||||
const newRange = {
|
|
||||||
start : this._range.start.clone().toISOString(),
|
|
||||||
end : this._range.end.clone().toISOString(),
|
|
||||||
whichDate: null
|
|
||||||
};
|
|
||||||
|
|
||||||
// Replace either the start or the end date with the new one
|
|
||||||
// depending on which date we are setting
|
|
||||||
if ( this.setWhichDate === 'start' )
|
|
||||||
{
|
|
||||||
newRange.start = moment(newRange.start).year(date.year()).month(date.month()).date(date.date()).toISOString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newRange.end = moment(newRange.end).year(date.year()).month(date.month()).date(date.date()).toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the which date to the new range object
|
|
||||||
newRange.whichDate = this.setWhichDate;
|
|
||||||
|
|
||||||
// Switch which date to set on the next run
|
|
||||||
this.setWhichDate = this.setWhichDate === 'start' ? 'end' : 'start';
|
|
||||||
|
|
||||||
// Set the range
|
|
||||||
this.range = newRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Go to previous month on both views
|
|
||||||
*/
|
|
||||||
prev(): void
|
|
||||||
{
|
|
||||||
this.activeDates.month1 = moment(this.activeDates.month1).subtract(1, 'month');
|
|
||||||
this.activeDates.month2 = moment(this.activeDates.month2).subtract(1, 'month');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Go to next month on both views
|
|
||||||
*/
|
|
||||||
next(): void
|
|
||||||
{
|
|
||||||
this.activeDates.month1 = moment(this.activeDates.month1).add(1, 'month');
|
|
||||||
this.activeDates.month2 = moment(this.activeDates.month2).add(1, 'month');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the start time
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
updateStartTime(event): void
|
|
||||||
{
|
|
||||||
// Parse the time
|
|
||||||
const parsedTime = this._parseTime(event.target.value);
|
|
||||||
|
|
||||||
// Go back to the previous value if the form control is not valid
|
|
||||||
if ( this.startTimeFormControl.invalid )
|
|
||||||
{
|
|
||||||
// Override the time
|
|
||||||
const time = this._range.start.clone().format(this._timeFormat);
|
|
||||||
|
|
||||||
// Set the time
|
|
||||||
this.startTimeFormControl.setValue(time);
|
|
||||||
|
|
||||||
// Do not update the range
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the new time to the start date
|
|
||||||
const startDate = this._range.start.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
|
|
||||||
|
|
||||||
// If the new start date is after the current end date,
|
|
||||||
// use the end date's time and set the start date again
|
|
||||||
if ( startDate.isAfter(this._range.end) )
|
|
||||||
{
|
|
||||||
const endDateHours = this._range.end.hours();
|
|
||||||
const endDateMinutes = this._range.end.minutes();
|
|
||||||
|
|
||||||
// Set the start date
|
|
||||||
startDate.hours(endDateHours).minutes(endDateMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything is okay, set the new date
|
|
||||||
this.range = {
|
|
||||||
start : startDate.toISOString(),
|
|
||||||
end : this._range.end.clone().toISOString(),
|
|
||||||
whichDate: 'start'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the end time
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
updateEndTime(event): void
|
|
||||||
{
|
|
||||||
// Parse the time
|
|
||||||
const parsedTime = this._parseTime(event.target.value);
|
|
||||||
|
|
||||||
// Go back to the previous value if the form control is not valid
|
|
||||||
if ( this.endTimeFormControl.invalid )
|
|
||||||
{
|
|
||||||
// Override the time
|
|
||||||
const time = this._range.end.clone().format(this._timeFormat);
|
|
||||||
|
|
||||||
// Set the time
|
|
||||||
this.endTimeFormControl.setValue(time);
|
|
||||||
|
|
||||||
// Do not update the range
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the new time to the end date
|
|
||||||
const endDate = this._range.end.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
|
|
||||||
|
|
||||||
// If the new end date is before the current start date,
|
|
||||||
// use the start date's time and set the end date again
|
|
||||||
if ( endDate.isBefore(this._range.start) )
|
|
||||||
{
|
|
||||||
const startDateHours = this._range.start.hours();
|
|
||||||
const startDateMinutes = this._range.start.minutes();
|
|
||||||
|
|
||||||
// Set the end date
|
|
||||||
endDate.hours(startDateHours).minutes(startDateMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything is okay, set the new date
|
|
||||||
this.range = {
|
|
||||||
start : this._range.start.clone().toISOString(),
|
|
||||||
end : endDate.toISOString(),
|
|
||||||
whichDate: 'end'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Private methods
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private _init(): void
|
|
||||||
{
|
|
||||||
// Start and end time form controls
|
|
||||||
this.startTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
|
|
||||||
this.endTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
|
|
||||||
|
|
||||||
// Set the default range
|
|
||||||
this._programmaticChange = true;
|
|
||||||
this.range = {
|
|
||||||
start: moment().startOf('day').toISOString(),
|
|
||||||
end : moment().add(1, 'day').endOf('day').toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the default time range
|
|
||||||
this._programmaticChange = true;
|
|
||||||
this.timeRange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the time from the inputs
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private _parseTime(value: string): Moment
|
|
||||||
{
|
|
||||||
// Parse the time using the time regexp
|
|
||||||
const timeArr = value.split(this._timeRegExp).filter(part => part !== '');
|
|
||||||
|
|
||||||
// Get the meridiem
|
|
||||||
const meridiem = timeArr[2] || null;
|
|
||||||
|
|
||||||
// If meridiem exists...
|
|
||||||
if ( meridiem )
|
|
||||||
{
|
|
||||||
// Create a moment using 12-hours format and return it
|
|
||||||
return moment(value, 'hh:mmA').seconds(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If meridiem doesn't exist, create a moment using 24-hours format and return in
|
|
||||||
return moment(value, 'HH:mm').seconds(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatInputModule } from '@angular/material/input';
|
|
||||||
import { MatMomentDateModule } from '@angular/material-moment-adapter';
|
|
||||||
import { FuseDateRangeComponent } from '@fuse/components/date-range/date-range.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
FuseDateRangeComponent
|
|
||||||
],
|
|
||||||
imports : [
|
|
||||||
CommonModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatDatepickerModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatMomentDateModule
|
|
||||||
],
|
|
||||||
exports : [
|
|
||||||
FuseDateRangeComponent
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class FuseDateRangeModule
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from '@fuse/components/date-range/public-api';
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from '@fuse/components/date-range/date-range.component';
|
|
||||||
export * from '@fuse/components/date-range/date-range.module';
|
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
$fuse-drawer-width: 320;
|
:root {
|
||||||
|
--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: #{$fuse-drawer-width}px;
|
width: var(--fuse-drawer-width);
|
||||||
min-width: #{$fuse-drawer-width}px;
|
min-width: var(--fuse-drawer-width);
|
||||||
max-width: #{$fuse-drawer-width}px;
|
max-width: var(--fuse-drawer-width);
|
||||||
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;
|
||||||
@@ -43,7 +45,7 @@ fuse-drawer {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-drawer-mode-side {
|
&.fuse-drawer-mode-side {
|
||||||
margin-left: -#{$fuse-drawer-width}px;
|
margin-left: calc(var(--fuse-drawer-width) * -1);
|
||||||
|
|
||||||
&.fuse-drawer-opened {
|
&.fuse-drawer-opened {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
@@ -71,7 +73,7 @@ fuse-drawer {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-drawer-mode-side {
|
&.fuse-drawer-mode-side {
|
||||||
margin-right: -#{$fuse-drawer-width}px;
|
margin-right: calc(var(--fuse-drawer-width) * -1);
|
||||||
|
|
||||||
&.fuse-drawer-opened {
|
&.fuse-drawer-opened {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
@@ -116,7 +118,7 @@ fuse-drawer {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 299;
|
z-index: 299;
|
||||||
opacity: 0;
|
opacity: 1;
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
|
||||||
/* Fixed mode */
|
/* Fixed mode */
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ 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;
|
||||||
@@ -47,6 +48,9 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
|||||||
private _fuseUtilsService: FuseUtilsService
|
private _fuseUtilsService: FuseUtilsService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
this._handleOverlayClick = (): void => {
|
||||||
|
this.close();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
@@ -58,6 +62,7 @@ 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,
|
||||||
@@ -66,6 +71,7 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,6 +217,12 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
|||||||
*/
|
*/
|
||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
|
// Finish the animation
|
||||||
|
if ( this._player )
|
||||||
|
{
|
||||||
|
this._player.finish();
|
||||||
|
}
|
||||||
|
|
||||||
// Deregister the drawer from the registry
|
// Deregister the drawer from the registry
|
||||||
this._fuseDrawerService.deregisterComponent(this.name);
|
this._fuseDrawerService.deregisterComponent(this.name);
|
||||||
}
|
}
|
||||||
@@ -312,12 +324,6 @@ 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');
|
||||||
|
|
||||||
@@ -336,25 +342,17 @@ 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 the enter animation and attach it to the player
|
// Create enter animation and attach it to the player
|
||||||
this._player = this._animationBuilder.build([
|
this._player = this._animationBuilder.build([
|
||||||
|
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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._overlay.addEventListener('click', this._handleOverlayClick);
|
||||||
this.close();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -380,13 +378,13 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
|
|||||||
// Once the animation is done...
|
// Once the animation is done...
|
||||||
this._player.onDone(() => {
|
this._player.onDone(() => {
|
||||||
|
|
||||||
// Destroy the player
|
// If the overlay still exists...
|
||||||
this._player.destroy();
|
|
||||||
|
|
||||||
// If the backdrop still exists...
|
|
||||||
if ( this._overlay )
|
if ( this._overlay )
|
||||||
{
|
{
|
||||||
// Remove the backdrop
|
// Remove the event listener
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
declarations: [
|
declarations: [
|
||||||
FuseFullscreenComponent
|
FuseFullscreenComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports : [
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
|
|||||||
1
src/@fuse/components/loading-bar/index.ts
Normal file
1
src/@fuse/components/loading-bar/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '@fuse/components/loading-bar/public-api';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ng-container *ngIf="show">
|
||||||
|
<mat-progress-bar
|
||||||
|
[mode]="mode"
|
||||||
|
[value]="progress"></mat-progress-bar>
|
||||||
|
</ng-container>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fuse-loading-bar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
82
src/@fuse/components/loading-bar/loading-bar.component.ts
Normal file
82
src/@fuse/components/loading-bar/loading-bar.component.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
import { FuseLoadingService } from '@fuse/services/loading';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector : 'fuse-loading-bar',
|
||||||
|
templateUrl : './loading-bar.component.html',
|
||||||
|
styleUrls : ['./loading-bar.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
exportAs : 'fuseLoadingBar'
|
||||||
|
})
|
||||||
|
export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy
|
||||||
|
{
|
||||||
|
@Input() autoMode: boolean = true;
|
||||||
|
mode: 'determinate' | 'indeterminate';
|
||||||
|
progress: number = 0;
|
||||||
|
show: boolean = false;
|
||||||
|
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
constructor(private _fuseLoadingService: FuseLoadingService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
// @ Lifecycle hooks
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On changes
|
||||||
|
*
|
||||||
|
* @param changes
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: SimpleChanges): void
|
||||||
|
{
|
||||||
|
// Auto mode
|
||||||
|
if ( 'autoMode' in changes )
|
||||||
|
{
|
||||||
|
// Set the auto mode in the service
|
||||||
|
this._fuseLoadingService.setAutoMode(coerceBooleanProperty(changes.autoMode.currentValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On init
|
||||||
|
*/
|
||||||
|
ngOnInit(): void
|
||||||
|
{
|
||||||
|
// Subscribe to the service
|
||||||
|
this._fuseLoadingService.mode$
|
||||||
|
.pipe(takeUntil(this._unsubscribeAll))
|
||||||
|
.subscribe((value) => {
|
||||||
|
this.mode = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._fuseLoadingService.progress$
|
||||||
|
.pipe(takeUntil(this._unsubscribeAll))
|
||||||
|
.subscribe((value) => {
|
||||||
|
this.progress = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._fuseLoadingService.show$
|
||||||
|
.pipe(takeUntil(this._unsubscribeAll))
|
||||||
|
.subscribe((value) => {
|
||||||
|
this.show = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On destroy
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void
|
||||||
|
{
|
||||||
|
// Unsubscribe from all subscriptions
|
||||||
|
this._unsubscribeAll.next(null);
|
||||||
|
this._unsubscribeAll.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/@fuse/components/loading-bar/loading-bar.module.ts
Normal file
20
src/@fuse/components/loading-bar/loading-bar.module.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
|
import { FuseLoadingBarComponent } from '@fuse/components/loading-bar/loading-bar.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
FuseLoadingBarComponent
|
||||||
|
],
|
||||||
|
imports : [
|
||||||
|
CommonModule,
|
||||||
|
MatProgressBarModule
|
||||||
|
],
|
||||||
|
exports : [
|
||||||
|
FuseLoadingBarComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class FuseLoadingBarModule
|
||||||
|
{
|
||||||
|
}
|
||||||
2
src/@fuse/components/loading-bar/public-api.ts
Normal file
2
src/@fuse/components/loading-bar/public-api.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from '@fuse/components/loading-bar/loading-bar.component';
|
||||||
|
export * from '@fuse/components/loading-bar/loading-bar.module';
|
||||||
@@ -5,7 +5,6 @@ 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'
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
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 || ''">
|
||||||
@@ -45,6 +49,10 @@
|
|||||||
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 || ''"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { IsActiveMatchOptions } from '@angular/router';
|
import { IsActiveMatchOptions } from '@angular/router';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -10,7 +9,6 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-horizontal-navigation-basic-item',
|
selector : 'fuse-horizontal-navigation-basic-item',
|
||||||
templateUrl : './basic.component.html',
|
templateUrl : './basic.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
|
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
|
||||||
@@ -77,7 +75,7 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { BooleanInput } from '@angular/cdk/coercion';
|
import { BooleanInput } from '@angular/cdk/coercion';
|
||||||
import { MatMenu } from '@angular/material/menu';
|
import { MatMenu } from '@angular/material/menu';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -10,7 +9,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-horizontal-navigation-branch-item',
|
selector : 'fuse-horizontal-navigation-branch-item',
|
||||||
templateUrl : './branch.component.html',
|
templateUrl : './branch.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
|
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
|
||||||
@@ -65,7 +63,7 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -8,7 +7,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-horizontal-navigation-divider-item',
|
selector : 'fuse-horizontal-navigation-divider-item',
|
||||||
templateUrl : './divider.component.html',
|
templateUrl : './divider.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
|
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
|
||||||
@@ -57,7 +55,7 @@ export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnD
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -8,7 +7,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-horizontal-navigation-spacer-item',
|
selector : 'fuse-horizontal-navigation-spacer-item',
|
||||||
templateUrl : './spacer.component.html',
|
templateUrl : './spacer.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
|
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
|
||||||
@@ -57,7 +55,7 @@ export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDe
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnD
|
|||||||
this._fuseNavigationService.deregisterComponent(this.name);
|
this._fuseNavigationService.deregisterComponent(this.name);
|
||||||
|
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IsActiveMatchOptions } from '@angular/router';
|
import { IsActiveMatchOptions, Params, QueryParamsHandling } from '@angular/router';
|
||||||
|
|
||||||
export interface FuseNavigationItem
|
export interface FuseNavigationItem
|
||||||
{
|
{
|
||||||
@@ -17,6 +17,10 @@ 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'
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
|
||||||
import { NavigationEnd, Router } from '@angular/router';
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
import { BooleanInput } from '@angular/cdk/coercion';
|
import { BooleanInput } from '@angular/cdk/coercion';
|
||||||
import { Subject } from 'rxjs';
|
import { filter, Subject, takeUntil } from 'rxjs';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -10,7 +9,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-aside-item',
|
selector : 'fuse-vertical-navigation-aside-item',
|
||||||
templateUrl : './aside.component.html',
|
templateUrl : './aside.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy
|
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy
|
||||||
@@ -99,7 +97,7 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
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 || ''">
|
||||||
@@ -45,6 +49,10 @@
|
|||||||
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 || ''"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { IsActiveMatchOptions } from '@angular/router';
|
import { IsActiveMatchOptions } from '@angular/router';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -10,7 +9,6 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-basic-item',
|
selector : 'fuse-vertical-navigation-basic-item',
|
||||||
templateUrl : './basic.component.html',
|
templateUrl : './basic.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
|
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
|
||||||
@@ -77,7 +75,7 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { NavigationEnd, Router } from '@angular/router';
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
import { BooleanInput } from '@angular/cdk/coercion';
|
import { BooleanInput } from '@angular/cdk/coercion';
|
||||||
import { Subject } from 'rxjs';
|
import { filter, Subject, takeUntil } from 'rxjs';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
|
||||||
import { fuseAnimations } from '@fuse/animations';
|
import { fuseAnimations } from '@fuse/animations';
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
@@ -11,7 +10,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-collapsable-item',
|
selector : 'fuse-vertical-navigation-collapsable-item',
|
||||||
templateUrl : './collapsable.component.html',
|
templateUrl : './collapsable.component.html',
|
||||||
styles : [],
|
|
||||||
animations : fuseAnimations,
|
animations : fuseAnimations,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
@@ -50,10 +48,12 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
@@ -177,7 +177,7 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -8,7 +7,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-divider-item',
|
selector : 'fuse-vertical-navigation-divider-item',
|
||||||
templateUrl : './divider.component.html',
|
templateUrl : './divider.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
|
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
|
||||||
@@ -57,7 +55,7 @@ export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDes
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { BooleanInput } from '@angular/cdk/coercion';
|
import { BooleanInput } from '@angular/cdk/coercion';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -9,7 +8,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-group-item',
|
selector : 'fuse-vertical-navigation-group-item',
|
||||||
templateUrl : './group.component.html',
|
templateUrl : './group.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy
|
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy
|
||||||
@@ -63,7 +61,7 @@ export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestr
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
|
||||||
@@ -8,7 +7,6 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
|
|||||||
@Component({
|
@Component({
|
||||||
selector : 'fuse-vertical-navigation-spacer-item',
|
selector : 'fuse-vertical-navigation-spacer-item',
|
||||||
templateUrl : './spacer.component.html',
|
templateUrl : './spacer.component.html',
|
||||||
styles : [],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
|
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
|
||||||
@@ -57,7 +55,7 @@ export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDest
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
$fuse-vertical-navigation-compact-width: 112;
|
:root {
|
||||||
|
--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: #{$fuse-vertical-navigation-compact-width}px;
|
width: var(--fuse-vertical-navigation-compact-width);
|
||||||
min-width: #{$fuse-vertical-navigation-compact-width}px;
|
min-width: var(--fuse-vertical-navigation-compact-width);
|
||||||
max-width: #{$fuse-vertical-navigation-compact-width}px;
|
max-width: var(--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: -#{$fuse-vertical-navigation-compact-width}px;
|
margin-left: calc(var(--fuse-vertical-navigation-compact-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opened */
|
/* Opened */
|
||||||
@@ -28,7 +30,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-vertical-navigation-mode-side {
|
&.fuse-vertical-navigation-mode-side {
|
||||||
margin-right: -#{$fuse-vertical-navigation-compact-width}px;
|
margin-right: calc(var(--fuse-vertical-navigation-compact-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opened */
|
/* Opened */
|
||||||
@@ -39,7 +41,7 @@ fuse-vertical-navigation {
|
|||||||
/* Aside wrapper */
|
/* Aside wrapper */
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: #{$fuse-vertical-navigation-compact-width}px;
|
right: var(--fuse-vertical-navigation-compact-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Aside wrapper */
|
/* Aside wrapper */
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: #{$fuse-vertical-navigation-compact-width}px;
|
left: var(--fuse-vertical-navigation-compact-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
$fuse-vertical-navigation-width: 280;
|
:root {
|
||||||
|
--fuse-vertical-navigation-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
fuse-vertical-navigation {
|
fuse-vertical-navigation {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
@@ -7,9 +9,9 @@ fuse-vertical-navigation {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: #{$fuse-vertical-navigation-width}px;
|
width: var(--fuse-vertical-navigation-width);
|
||||||
min-width: #{$fuse-vertical-navigation-width}px;
|
min-width: var(--fuse-vertical-navigation-width);
|
||||||
max-width: #{$fuse-vertical-navigation-width}px;
|
max-width: var(--fuse-vertical-navigation-width);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
@@ -45,7 +47,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-vertical-navigation-mode-side {
|
&.fuse-vertical-navigation-mode-side {
|
||||||
margin-left: -#{$fuse-vertical-navigation-width}px;
|
margin-left: calc(#{var(--fuse-vertical-navigation-width)} * -1);
|
||||||
|
|
||||||
&.fuse-vertical-navigation-opened {
|
&.fuse-vertical-navigation-opened {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
@@ -73,7 +75,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-vertical-navigation-mode-side {
|
&.fuse-vertical-navigation-mode-side {
|
||||||
margin-right: -#{$fuse-vertical-navigation-width}px;
|
margin-right: calc(var(--fuse-vertical-navigation-width) * -1);
|
||||||
|
|
||||||
&.fuse-vertical-navigation-opened {
|
&.fuse-vertical-navigation-opened {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
@@ -170,8 +172,8 @@ fuse-vertical-navigation {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: #{$fuse-vertical-navigation-width}px;
|
left: var(--fuse-vertical-navigation-width);
|
||||||
width: #{$fuse-vertical-navigation-width}px;
|
width: var(--fuse-vertical-navigation-width);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@@ -196,7 +198,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: #{$fuse-vertical-navigation-width}px;
|
right: var(--fuse-vertical-navigation-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +337,10 @@ 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;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
$fuse-vertical-navigation-width: 280;
|
:root {
|
||||||
$fuse-vertical-navigation-dense-width: 80;
|
--fuse-vertical-navigation-width: 280px;
|
||||||
|
--fuse-vertical-navigation-dense-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
fuse-vertical-navigation {
|
fuse-vertical-navigation {
|
||||||
|
|
||||||
@@ -8,16 +10,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: #{$fuse-vertical-navigation-dense-width}px;
|
width: var(--fuse-vertical-navigation-dense-width);
|
||||||
min-width: #{$fuse-vertical-navigation-dense-width}px;
|
min-width: var(--fuse-vertical-navigation-dense-width);
|
||||||
max-width: #{$fuse-vertical-navigation-dense-width}px;
|
max-width: var(--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: -#{$fuse-vertical-navigation-dense-width}px;
|
margin-left: calc(var(--fuse-vertical-navigation-dense-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opened */
|
/* Opened */
|
||||||
@@ -31,7 +33,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Side mode */
|
/* Side mode */
|
||||||
&.fuse-vertical-navigation-mode-side {
|
&.fuse-vertical-navigation-mode-side {
|
||||||
margin-right: -#{$fuse-vertical-navigation-dense-width}px;
|
margin-right: calc(var(--fuse-vertical-navigation-dense-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opened */
|
/* Opened */
|
||||||
@@ -42,14 +44,14 @@ fuse-vertical-navigation {
|
|||||||
/* Aside wrapper */
|
/* Aside wrapper */
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: #{$fuse-vertical-navigation-dense-width}px;
|
right: var(--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: #{$fuse-vertical-navigation-width}px;
|
right: var(--fuse-vertical-navigation-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,9 +71,9 @@ fuse-vertical-navigation {
|
|||||||
.fuse-vertical-navigation-item-wrapper {
|
.fuse-vertical-navigation-item-wrapper {
|
||||||
|
|
||||||
.fuse-vertical-navigation-item {
|
.fuse-vertical-navigation-item {
|
||||||
width: #{$fuse-vertical-navigation-width}px - 24px;
|
width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
|
||||||
min-width: #{$fuse-vertical-navigation-width}px - 24px;
|
min-width: calc(var(--fuse-vertical-navigation-dense-width) - 24px);
|
||||||
max-width: #{$fuse-vertical-navigation-width}px - 24px;
|
max-width: calc(var(--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,
|
||||||
@@ -142,20 +144,23 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Aside wrapper */
|
/* Aside wrapper */
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: #{$fuse-vertical-navigation-dense-width}px;
|
left: var(--fuse-vertical-navigation-dense-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hover */
|
/* Hover */
|
||||||
&.fuse-vertical-navigation-hover {
|
&.fuse-vertical-navigation-hover {
|
||||||
|
|
||||||
.fuse-vertical-navigation-wrapper {
|
.fuse-vertical-navigation-wrapper {
|
||||||
width: #{$fuse-vertical-navigation-width}px;
|
width: var(--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);
|
||||||
|
min-width: calc(var(--fuse-vertical-navigation-width) - 24px);
|
||||||
|
max-width: calc(var(--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,
|
||||||
@@ -170,7 +175,7 @@ fuse-vertical-navigation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: #{$fuse-vertical-navigation-width}px;
|
left: var(--fuse-vertical-navigation-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
$fuse-vertical-navigation-thin-width: 80;
|
:root {
|
||||||
|
--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: #{$fuse-vertical-navigation-thin-width}px;
|
width: var(--fuse-vertical-navigation-thin-width);
|
||||||
min-width: #{$fuse-vertical-navigation-thin-width}px;
|
min-width: var(--fuse-vertical-navigation-thin-width);
|
||||||
max-width: #{$fuse-vertical-navigation-thin-width}px;
|
max-width: var(--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: -#{$fuse-vertical-navigation-thin-width}px;
|
margin-left: calc(var(--fuse-vertical-navigation-thin-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.fuse-vertical-navigation-opened {
|
&.fuse-vertical-navigation-opened {
|
||||||
@@ -25,7 +27,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: -#{$fuse-vertical-navigation-thin-width}px;
|
margin-right: calc(var(--fuse-vertical-navigation-thin-width) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.fuse-vertical-navigation-opened {
|
&.fuse-vertical-navigation-opened {
|
||||||
@@ -34,7 +36,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: #{$fuse-vertical-navigation-thin-width}px;
|
right: var(--fuse-vertical-navigation-thin-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ fuse-vertical-navigation {
|
|||||||
|
|
||||||
/* Aside wrapper */
|
/* Aside wrapper */
|
||||||
.fuse-vertical-navigation-aside-wrapper {
|
.fuse-vertical-navigation-aside-wrapper {
|
||||||
left: #{$fuse-vertical-navigation-thin-width}px;
|
left: var(--fuse-vertical-navigation-thin-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import 'styles/appearances/default';
|
@use 'styles/appearances/default';
|
||||||
@import 'styles/appearances/compact';
|
@use 'styles/appearances/compact';
|
||||||
@import 'styles/appearances/dense';
|
@use 'styles/appearances/dense';
|
||||||
@import 'styles/appearances/thin';
|
@use 'styles/appearances/thin';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, QueryList, Renderer2, SimpleChanges, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
|
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 { 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 { merge, ReplaySubject, Subject, Subscription } from 'rxjs';
|
import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs';
|
||||||
import { delay, filter, takeUntil } from 'rxjs/operators';
|
|
||||||
import { fuseAnimations } from '@fuse/animations';
|
import { fuseAnimations } from '@fuse/animations';
|
||||||
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
|
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
|
||||||
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
|
||||||
@@ -52,6 +52,7 @@ 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();
|
||||||
@@ -65,6 +66,7 @@ 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,
|
||||||
@@ -90,6 +92,7 @@ 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,
|
||||||
@@ -101,6 +104,7 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,6 +333,34 @@ 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
|
||||||
@@ -374,6 +406,9 @@ 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();
|
||||||
@@ -382,7 +417,7 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
|
|||||||
this._fuseNavigationService.deregisterComponent(this.name);
|
this._fuseNavigationService.deregisterComponent(this.name);
|
||||||
|
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
|
import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { NavigationEnd, Router } from '@angular/router';
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
import { Subject } from 'rxjs';
|
import { filter, Subject, takeUntil } from 'rxjs';
|
||||||
import { filter, takeUntil } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[fuseScrollReset]',
|
selector: '[fuseScrollReset]',
|
||||||
@@ -47,7 +46,7 @@ export class FuseScrollResetDirective implements OnInit, OnDestroy
|
|||||||
ngOnDestroy(): void
|
ngOnDestroy(): void
|
||||||
{
|
{
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChang
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
import { Platform } from '@angular/cdk/platform';
|
import { Platform } from '@angular/cdk/platform';
|
||||||
import { fromEvent, Subject } from 'rxjs';
|
import { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs';
|
||||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
||||||
import PerfectScrollbar from 'perfect-scrollbar';
|
import PerfectScrollbar from 'perfect-scrollbar';
|
||||||
import { merge } from 'lodash-es';
|
import { merge } from 'lodash-es';
|
||||||
import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types';
|
import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types';
|
||||||
@@ -138,7 +137,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
|
|||||||
this._destroy();
|
this._destroy();
|
||||||
|
|
||||||
// Unsubscribe from all subscriptions
|
// Unsubscribe from all subscriptions
|
||||||
this._unsubscribeAll.next();
|
this._unsubscribeAll.next(null);
|
||||||
this._unsubscribeAll.complete();
|
this._unsubscribeAll.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,32 @@
|
|||||||
import { NgModule, Optional, SkipSelf } from '@angular/core';
|
import { NgModule, Optional, SkipSelf } from '@angular/core';
|
||||||
|
import { MATERIAL_SANITY_CHECKS } from '@angular/material/core';
|
||||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
import { 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 { 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 { FuseTailwindConfigModule } from '@fuse/services/tailwind/tailwind.module';
|
|
||||||
import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
|
import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports : [
|
imports : [
|
||||||
FuseConfirmationModule,
|
FuseConfirmationModule,
|
||||||
|
FuseLoadingModule,
|
||||||
FuseMediaWatcherModule,
|
FuseMediaWatcherModule,
|
||||||
|
FusePlatformModule,
|
||||||
FuseSplashScreenModule,
|
FuseSplashScreenModule,
|
||||||
FuseTailwindConfigModule,
|
|
||||||
FuseUtilsModule
|
FuseUtilsModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
{
|
||||||
|
// Disable 'theme' sanity check
|
||||||
|
provide : MATERIAL_SANITY_CHECKS,
|
||||||
|
useValue: {
|
||||||
|
doctype: true,
|
||||||
|
theme : false,
|
||||||
|
version: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Use the 'fill' appearance on Angular Material form fields by default
|
// Use the 'fill' appearance on Angular Material form fields by default
|
||||||
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
||||||
import { Observable, of, throwError } from 'rxjs';
|
import { delay, Observable, of, switchMap, throwError } from 'rxjs';
|
||||||
import { delay, switchMap } from 'rxjs/operators';
|
|
||||||
import { FUSE_MOCK_API_DEFAULT_DELAY } from '@fuse/lib/mock-api/mock-api.constants';
|
import { FUSE_MOCK_API_DEFAULT_DELAY } from '@fuse/lib/mock-api/mock-api.constants';
|
||||||
import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service';
|
import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { HttpRequest } from '@angular/common/http';
|
import { HttpRequest } from '@angular/common/http';
|
||||||
import { Observable, of, throwError } from 'rxjs';
|
import { Observable, of, take, throwError } from 'rxjs';
|
||||||
import { take } from 'rxjs/operators';
|
|
||||||
import { FuseMockApiReplyCallback } from '@fuse/lib/mock-api/mock-api.types';
|
import { FuseMockApiReplyCallback } from '@fuse/lib/mock-api/mock-api.types';
|
||||||
|
|
||||||
export class FuseMockApiHandler
|
export class FuseMockApiHandler
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import { FuseMockApiMethods } from '@fuse/lib/mock-api/mock-api.types';
|
|||||||
export class FuseMockApiService
|
export class FuseMockApiService
|
||||||
{
|
{
|
||||||
private _handlers: { [key: string]: Map<string, FuseMockApiHandler> } = {
|
private _handlers: { [key: string]: Map<string, FuseMockApiHandler> } = {
|
||||||
'delete': new Map<string, FuseMockApiHandler>(),
|
'get' : new Map<string, FuseMockApiHandler>(),
|
||||||
'get' : new Map<string, FuseMockApiHandler>(),
|
'post' : new Map<string, FuseMockApiHandler>(),
|
||||||
'patch' : new Map<string, FuseMockApiHandler>(),
|
'patch' : new Map<string, FuseMockApiHandler>(),
|
||||||
'post' : new Map<string, FuseMockApiHandler>(),
|
'delete' : new Map<string, FuseMockApiHandler>(),
|
||||||
'put' : new Map<string, FuseMockApiHandler>()
|
'put' : new Map<string, FuseMockApiHandler>(),
|
||||||
|
'head' : new Map<string, FuseMockApiHandler>(),
|
||||||
|
'jsonp' : new Map<string, FuseMockApiHandler>(),
|
||||||
|
'options': new Map<string, FuseMockApiHandler>()
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,18 +89,7 @@ export class FuseMockApiService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a DELETE request handler
|
* Register GET request handler
|
||||||
*
|
|
||||||
* @param url - URL address of the mocked API endpoint
|
|
||||||
* @param delay - Delay of the response in milliseconds
|
|
||||||
*/
|
|
||||||
onDelete(url: string, delay?: number): FuseMockApiHandler
|
|
||||||
{
|
|
||||||
return this._registerHandler('delete', url, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a GET request handler
|
|
||||||
*
|
*
|
||||||
* @param url - URL address of the mocked API endpoint
|
* @param url - URL address of the mocked API endpoint
|
||||||
* @param delay - Delay of the response in milliseconds
|
* @param delay - Delay of the response in milliseconds
|
||||||
@@ -108,18 +100,7 @@ export class FuseMockApiService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a PATCH request handler
|
* Register POST request handler
|
||||||
*
|
|
||||||
* @param url - URL address of the mocked API endpoint
|
|
||||||
* @param delay - Delay of the response in milliseconds
|
|
||||||
*/
|
|
||||||
onPatch(url: string, delay?: number): FuseMockApiHandler
|
|
||||||
{
|
|
||||||
return this._registerHandler('patch', url, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a POST request handler
|
|
||||||
*
|
*
|
||||||
* @param url - URL address of the mocked API endpoint
|
* @param url - URL address of the mocked API endpoint
|
||||||
* @param delay - Delay of the response in milliseconds
|
* @param delay - Delay of the response in milliseconds
|
||||||
@@ -130,7 +111,29 @@ export class FuseMockApiService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a PUT request handler
|
* Register PATCH request handler
|
||||||
|
*
|
||||||
|
* @param url - URL address of the mocked API endpoint
|
||||||
|
* @param delay - Delay of the response in milliseconds
|
||||||
|
*/
|
||||||
|
onPatch(url: string, delay?: number): FuseMockApiHandler
|
||||||
|
{
|
||||||
|
return this._registerHandler('patch', url, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register DELETE request handler
|
||||||
|
*
|
||||||
|
* @param url - URL address of the mocked API endpoint
|
||||||
|
* @param delay - Delay of the response in milliseconds
|
||||||
|
*/
|
||||||
|
onDelete(url: string, delay?: number): FuseMockApiHandler
|
||||||
|
{
|
||||||
|
return this._registerHandler('delete', url, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register PUT request handler
|
||||||
*
|
*
|
||||||
* @param url - URL address of the mocked API endpoint
|
* @param url - URL address of the mocked API endpoint
|
||||||
* @param delay - Delay of the response in milliseconds
|
* @param delay - Delay of the response in milliseconds
|
||||||
@@ -140,6 +143,39 @@ export class FuseMockApiService
|
|||||||
return this._registerHandler('put', url, delay);
|
return this._registerHandler('put', url, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register HEAD request handler
|
||||||
|
*
|
||||||
|
* @param url - URL address of the mocked API endpoint
|
||||||
|
* @param delay - Delay of the response in milliseconds
|
||||||
|
*/
|
||||||
|
onHead(url: string, delay?: number): FuseMockApiHandler
|
||||||
|
{
|
||||||
|
return this._registerHandler('head', url, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register JSONP request handler
|
||||||
|
*
|
||||||
|
* @param url - URL address of the mocked API endpoint
|
||||||
|
* @param delay - Delay of the response in milliseconds
|
||||||
|
*/
|
||||||
|
onJsonp(url: string, delay?: number): FuseMockApiHandler
|
||||||
|
{
|
||||||
|
return this._registerHandler('jsonp', url, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register OPTIONS request handler
|
||||||
|
*
|
||||||
|
* @param url - URL address of the mocked API endpoint
|
||||||
|
* @param delay - Delay of the response in milliseconds
|
||||||
|
*/
|
||||||
|
onOptions(url: string, delay?: number): FuseMockApiHandler
|
||||||
|
{
|
||||||
|
return this._registerHandler('options', url, delay);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
// @ Private methods
|
// @ Private methods
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export type FuseMockApiReplyCallback =
|
|||||||
export type FuseMockApiMethods =
|
export type FuseMockApiMethods =
|
||||||
| 'get'
|
| 'get'
|
||||||
| 'post'
|
| 'post'
|
||||||
| 'put'
|
|
||||||
| 'patch'
|
| 'patch'
|
||||||
| 'delete';
|
| 'delete'
|
||||||
|
| 'put'
|
||||||
|
| 'head'
|
||||||
|
| 'jsonp'
|
||||||
|
| 'options';
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ 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();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
declarations: [
|
declarations: [
|
||||||
FuseConfirmationDialogComponent
|
FuseConfirmationDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports : [
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ export class FuseConfirmationService
|
|||||||
return this._matDialog.open(FuseConfirmationDialogComponent, {
|
return this._matDialog.open(FuseConfirmationDialogComponent, {
|
||||||
autoFocus : false,
|
autoFocus : false,
|
||||||
disableClose: !userConfig.dismissible,
|
disableClose: !userConfig.dismissible,
|
||||||
data : userConfig
|
data : userConfig,
|
||||||
|
panelClass : 'fuse-confirmation-dialog-panel'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="relative flex flex-col md:w-128 -m-6">
|
<div class="relative flex flex-col w-full h-full">
|
||||||
|
|
||||||
<!-- Dismiss button -->
|
<!-- Dismiss button -->
|
||||||
<ng-container *ngIf="data.dismissible">
|
<ng-container *ngIf="data.dismissible">
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div class="flex flex-col sm:flex-row items-center sm:items-start p-8 pb-6 sm:pb-8">
|
<div class="flex flex-col sm:flex-row flex-auto items-center sm:items-start p-8 pb-6 sm:pb-8">
|
||||||
|
|
||||||
<!-- Icon -->
|
<!-- Icon -->
|
||||||
<ng-container *ngIf="data.icon.show">
|
<ng-container *ngIf="data.icon.show">
|
||||||
|
|||||||
@@ -1,38 +1,32 @@
|
|||||||
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA } 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 : [
|
||||||
|
`
|
||||||
|
.fuse-confirmation-dialog-panel {
|
||||||
|
@screen md {
|
||||||
|
@apply w-128;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-dialog-container {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FuseConfirmationDialogComponent implements OnInit
|
export class FuseConfirmationDialogComponent
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig)
|
||||||
@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig,
|
|
||||||
public matDialogRef: MatDialogRef<FuseConfirmationDialogComponent>
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Lifecycle hooks
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On init
|
|
||||||
*/
|
|
||||||
ngOnInit(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Public methods
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/@fuse/services/loading/index.ts
Normal file
1
src/@fuse/services/loading/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '@fuse/services/loading/public-api';
|
||||||
48
src/@fuse/services/loading/loading.interceptor.ts
Normal file
48
src/@fuse/services/loading/loading.interceptor.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||||
|
import { finalize, Observable } from 'rxjs';
|
||||||
|
import { FuseLoadingService } from '@fuse/services/loading/loading.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FuseLoadingInterceptor implements HttpInterceptor
|
||||||
|
{
|
||||||
|
handleRequestsAutomatically: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
private _fuseLoadingService: FuseLoadingService
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Subscribe to the auto
|
||||||
|
this._fuseLoadingService.auto$
|
||||||
|
.subscribe((value) => {
|
||||||
|
this.handleRequestsAutomatically = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercept
|
||||||
|
*
|
||||||
|
* @param req
|
||||||
|
* @param next
|
||||||
|
*/
|
||||||
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
|
||||||
|
{
|
||||||
|
// If the Auto mode is turned off, do nothing
|
||||||
|
if ( !this.handleRequestsAutomatically )
|
||||||
|
{
|
||||||
|
return next.handle(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the loading status to true
|
||||||
|
this._fuseLoadingService._setLoadingStatus(true, req.url);
|
||||||
|
|
||||||
|
return next.handle(req).pipe(
|
||||||
|
finalize(() => {
|
||||||
|
// Set the status to false if there are any errors or the request is completed
|
||||||
|
this._fuseLoadingService._setLoadingStatus(false, req.url);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/@fuse/services/loading/loading.module.ts
Normal file
16
src/@fuse/services/loading/loading.module.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
import { FuseLoadingInterceptor } from '@fuse/services/loading/loading.interceptor';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide : HTTP_INTERCEPTORS,
|
||||||
|
useClass: FuseLoadingInterceptor,
|
||||||
|
multi : true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class FuseLoadingModule
|
||||||
|
{
|
||||||
|
}
|
||||||
146
src/@fuse/services/loading/loading.service.ts
Normal file
146
src/@fuse/services/loading/loading.service.ts
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class FuseLoadingService
|
||||||
|
{
|
||||||
|
private _auto$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||||
|
private _mode$: BehaviorSubject<'determinate' | 'indeterminate'> = new BehaviorSubject<'determinate' | 'indeterminate'>('indeterminate');
|
||||||
|
private _progress$: BehaviorSubject<number | null> = new BehaviorSubject<number | null>(0);
|
||||||
|
private _show$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
|
private _urlMap: Map<string, boolean> = new Map<string, boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
constructor(private _httpClient: HttpClient)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
// @ Accessors
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for auto mode
|
||||||
|
*/
|
||||||
|
get auto$(): Observable<boolean>
|
||||||
|
{
|
||||||
|
return this._auto$.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for mode
|
||||||
|
*/
|
||||||
|
get mode$(): Observable<'determinate' | 'indeterminate'>
|
||||||
|
{
|
||||||
|
return this._mode$.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for progress
|
||||||
|
*/
|
||||||
|
get progress$(): Observable<number>
|
||||||
|
{
|
||||||
|
return this._progress$.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for show
|
||||||
|
*/
|
||||||
|
get show$(): Observable<boolean>
|
||||||
|
{
|
||||||
|
return this._show$.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
// @ Public methods
|
||||||
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the loading bar
|
||||||
|
*/
|
||||||
|
show(): void
|
||||||
|
{
|
||||||
|
this._show$.next(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the loading bar
|
||||||
|
*/
|
||||||
|
hide(): void
|
||||||
|
{
|
||||||
|
this._show$.next(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the auto mode
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
setAutoMode(value: boolean): void
|
||||||
|
{
|
||||||
|
this._auto$.next(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the mode
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
setMode(value: 'determinate' | 'indeterminate'): void
|
||||||
|
{
|
||||||
|
this._mode$.next(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the progress of the bar manually
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
setProgress(value: number): void
|
||||||
|
{
|
||||||
|
if ( value < 0 || value > 100 )
|
||||||
|
{
|
||||||
|
console.error('Progress value must be between 0 and 100!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._progress$.next(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the loading status on the given url
|
||||||
|
*
|
||||||
|
* @param status
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
_setLoadingStatus(status: boolean, url: string): void
|
||||||
|
{
|
||||||
|
// Return if the url was not provided
|
||||||
|
if ( !url )
|
||||||
|
{
|
||||||
|
console.error('The request URL must be provided!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status === true )
|
||||||
|
{
|
||||||
|
this._urlMap.set(url, status);
|
||||||
|
this._show$.next(true);
|
||||||
|
}
|
||||||
|
else if ( status === false && this._urlMap.has(url) )
|
||||||
|
{
|
||||||
|
this._urlMap.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only set the status to 'false' if all outgoing requests are completed
|
||||||
|
if ( this._urlMap.size === 0 )
|
||||||
|
{
|
||||||
|
this._show$.next(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/@fuse/services/loading/public-api.ts
Normal file
2
src/@fuse/services/loading/public-api.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from '@fuse/services/loading/loading.service';
|
||||||
|
export * from '@fuse/services/loading/loading.module';
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
|
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
|
||||||
import { Observable, ReplaySubject } from 'rxjs';
|
import { map, Observable, ReplaySubject, switchMap } from 'rxjs';
|
||||||
import { map, switchMap } from 'rxjs/operators';
|
import { fromPairs } from 'lodash-es';
|
||||||
import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
|
import { FuseConfigService } from '@fuse/services/config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FuseMediaWatcherService
|
export class FuseMediaWatcherService
|
||||||
@@ -14,11 +14,12 @@ export class FuseMediaWatcherService
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private _breakpointObserver: BreakpointObserver,
|
private _breakpointObserver: BreakpointObserver,
|
||||||
private _fuseTailwindConfigService: FuseTailwindService
|
private _fuseConfigService: FuseConfigService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this._fuseTailwindConfigService.tailwindConfig$.pipe(
|
this._fuseConfigService.config$.pipe(
|
||||||
switchMap(config => this._breakpointObserver.observe(Object.values(config.breakpoints)).pipe(
|
map(config => fromPairs(Object.entries(config.screens).map(([alias, screen]) => ([alias, `(min-width: ${screen})`])))),
|
||||||
|
switchMap(screens => this._breakpointObserver.observe(Object.values(screens)).pipe(
|
||||||
map((state) => {
|
map((state) => {
|
||||||
|
|
||||||
// Prepare the observable values and set their defaults
|
// Prepare the observable values and set their defaults
|
||||||
@@ -30,7 +31,7 @@ export class FuseMediaWatcherService
|
|||||||
for ( const [query] of matchingBreakpoints )
|
for ( const [query] of matchingBreakpoints )
|
||||||
{
|
{
|
||||||
// Find the alias of the matching query
|
// Find the alias of the matching query
|
||||||
const matchingAlias = Object.entries(config.breakpoints).find(([alias, q]) => q === query)[0];
|
const matchingAlias = Object.entries(screens).find(([alias, q]) => q === query)[0];
|
||||||
|
|
||||||
// Add the matching query to the observable values
|
// Add the matching query to the observable values
|
||||||
if ( matchingAlias )
|
if ( matchingAlias )
|
||||||
|
|||||||
1
src/@fuse/services/platform/index.ts
Normal file
1
src/@fuse/services/platform/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '@fuse/services/platform/public-api';
|
||||||
17
src/@fuse/services/platform/platform.module.ts
Normal file
17
src/@fuse/services/platform/platform.module.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FusePlatformService } from '@fuse/services/platform/platform.service';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [
|
||||||
|
FusePlatformService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class FusePlatformModule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
constructor(private _fusePlatformService: FusePlatformService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/@fuse/services/platform/platform.service.ts
Normal file
59
src/@fuse/services/platform/platform.service.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1
src/@fuse/services/platform/public-api.ts
Normal file
1
src/@fuse/services/platform/public-api.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '@fuse/services/platform/platform.service';
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { NavigationEnd, Router } from '@angular/router';
|
import { NavigationEnd, Router } from '@angular/router';
|
||||||
import { filter, take } from 'rxjs/operators';
|
import { filter, take } from 'rxjs';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FuseSplashScreenService
|
export class FuseSplashScreenService
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from '@fuse/services/tailwind/public-api';
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from '@fuse/services/tailwind/tailwind.module';
|
|
||||||
export * from '@fuse/services/tailwind/tailwind.service';
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
providers: [
|
|
||||||
FuseTailwindService
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class FuseTailwindConfigModule
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
constructor(private _fuseTailwindConfigService: FuseTailwindService)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Observable, ReplaySubject } from 'rxjs';
|
|
||||||
import { fromPairs, map } from 'lodash-es';
|
|
||||||
import * as extractedTailwindConfigStyle from '@fuse/styles/core/tailwind-config.scss';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FuseTailwindService
|
|
||||||
{
|
|
||||||
private _tailwindConfig: ReplaySubject<any> = new ReplaySubject<any>(1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
constructor()
|
|
||||||
{
|
|
||||||
// Prepare the config object
|
|
||||||
const config: any = {};
|
|
||||||
|
|
||||||
// Extract the style from the class
|
|
||||||
const regexpForClass = /\.fuse-tailwind-extracted-config\s\{([\s\S]*)\}/g;
|
|
||||||
const style = regexpForClass.exec(extractedTailwindConfigStyle.default)[1].trim();
|
|
||||||
|
|
||||||
// Extract the rules
|
|
||||||
const regexp = /(--[\s\S]*?):'([\s\S]*?)';/g;
|
|
||||||
let rules = regexp.exec(style);
|
|
||||||
|
|
||||||
// Add to the config
|
|
||||||
while ( rules !== null )
|
|
||||||
{
|
|
||||||
const configGroup = /--([\s\S]*?)-/g.exec(rules[1])[1];
|
|
||||||
if ( !config[configGroup] )
|
|
||||||
{
|
|
||||||
config[configGroup] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
config[configGroup][rules[1].replace(/(--[\s\S]*?-)/g, '')] = rules[2];
|
|
||||||
rules = regexp.exec(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the themes objects
|
|
||||||
config.themes = fromPairs(map(config.themes, (value, key) => [key, JSON.parse(value)]));
|
|
||||||
|
|
||||||
// Execute the observable with the config
|
|
||||||
this._tailwindConfig.next(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
// @ Accessors
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for _tailwindConfig
|
|
||||||
*/
|
|
||||||
get tailwindConfig$(): Observable<any>
|
|
||||||
{
|
|
||||||
return this._tailwindConfig.asObservable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* ----------------------------------------------------------------------------------------------------- */
|
|
||||||
/* @ Any configuration we need from Tailwind's config file will be extracted here so we can import this
|
|
||||||
/* @ file from "config.ts" to access the extracted configuration from TypeScript
|
|
||||||
/* ----------------------------------------------------------------------------------------------------- */
|
|
||||||
@variants fuse-tailwind-extracted-config {
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
/* 1. Core */
|
/* 1. Components */
|
||||||
@import 'core/tailwind-config';
|
@use 'components/example-viewer';
|
||||||
|
@use 'components/input';
|
||||||
|
|
||||||
/* 2. Components */
|
/* 2. Overrides */
|
||||||
@import 'components/example-viewer';
|
@use 'overrides/angular-material';
|
||||||
@import 'components/input';
|
@use 'overrides/highlightjs';
|
||||||
|
@use 'overrides/perfect-scrollbar';
|
||||||
/* 3. Overrides */
|
@use 'overrides/quill';
|
||||||
@import 'overrides/angular-material';
|
|
||||||
@import 'overrides/fullcalendar';
|
|
||||||
@import 'overrides/highlightjs';
|
|
||||||
@import 'overrides/perfect-scrollbar';
|
|
||||||
@import 'overrides/quill';
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,680 +0,0 @@
|
|||||||
/* ----------------------------------------------------------------------------------------------------- */
|
|
||||||
/* @ FullCalendar overrides
|
|
||||||
/* ----------------------------------------------------------------------------------------------------- */
|
|
||||||
.fc {
|
|
||||||
|
|
||||||
.fc-view-container {
|
|
||||||
|
|
||||||
/* Day Grid - Month view */
|
|
||||||
.fc-view.fc-dayGridMonth-view {
|
|
||||||
|
|
||||||
.fc-head {
|
|
||||||
|
|
||||||
> tr > .fc-head-container {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-row {
|
|
||||||
|
|
||||||
.fc-day-header {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding-top: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
@apply text-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-body {
|
|
||||||
|
|
||||||
> tr > .fc-widget-content {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-day-grid {
|
|
||||||
|
|
||||||
.fc-week {
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-day {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content-skeleton {
|
|
||||||
|
|
||||||
.fc-day-top {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.fc-other-month {
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
.fc-day-number {
|
|
||||||
@apply text-hint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
|
|
||||||
.fc-day-number {
|
|
||||||
@apply bg-primary text-on-primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day-number {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 22px;
|
|
||||||
height: 21px;
|
|
||||||
margin: 4px 0;
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
|
|
||||||
.fc-day-grid-event {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 22px;
|
|
||||||
min-height: 22px;
|
|
||||||
max-height: 22px;
|
|
||||||
margin: 0 6px 4px 6px;
|
|
||||||
padding: 0 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-more {
|
|
||||||
padding: 0 3px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
white-space: nowrap;
|
|
||||||
@apply text-secondary;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-highlight-skeleton {
|
|
||||||
|
|
||||||
.fc-highlight {
|
|
||||||
position: relative;
|
|
||||||
opacity: 1;
|
|
||||||
@apply bg-gray-100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-popover {
|
|
||||||
@apply bg-card;
|
|
||||||
|
|
||||||
&.fc-more-popover {
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
@apply shadow-2xl;
|
|
||||||
|
|
||||||
.fc-header {
|
|
||||||
height: 32px;
|
|
||||||
min-height: 32px;
|
|
||||||
max-height: 32px;
|
|
||||||
padding: 0 8px;
|
|
||||||
@apply bg-hover;
|
|
||||||
|
|
||||||
.fc-title {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-body {
|
|
||||||
max-height: 160px;
|
|
||||||
overflow: hidden auto;
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
.fc-day-grid-event {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 22px;
|
|
||||||
min-height: 22px;
|
|
||||||
max-height: 22px;
|
|
||||||
margin: 0 0 6px 0;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Time Grid - Week view */
|
|
||||||
.fc-view.fc-timeGridWeek-view {
|
|
||||||
|
|
||||||
.fc-head {
|
|
||||||
|
|
||||||
> tr > .fc-head-container {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-row {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day-header {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
@apply text-secondary;
|
|
||||||
|
|
||||||
&.fc-weekday {
|
|
||||||
padding-top: 16px;
|
|
||||||
font-size: 12px;
|
|
||||||
letter-spacing: 0.055em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-date {
|
|
||||||
padding-bottom: 12px;
|
|
||||||
font-size: 26px;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-body {
|
|
||||||
|
|
||||||
> tr > .fc-widget-content {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-day-grid {
|
|
||||||
|
|
||||||
.fc-row {
|
|
||||||
min-height: 0;
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content-skeleton {
|
|
||||||
padding-bottom: 0;
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
|
|
||||||
.fc-day-grid-event {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 22px;
|
|
||||||
min-height: 22px;
|
|
||||||
max-height: 22px;
|
|
||||||
margin: 0 6px 6px 6px;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-divider {
|
|
||||||
border: none;
|
|
||||||
background: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-time-grid {
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
border: none;
|
|
||||||
width: 48px !important;
|
|
||||||
|
|
||||||
+ .fc-day {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-slats {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
height: 48px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 12px;
|
|
||||||
width: 48px;
|
|
||||||
min-width: 48px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-time {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-widget-content {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content-skeleton {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
margin: 0 12px 0 0;
|
|
||||||
|
|
||||||
.fc-time-grid-event {
|
|
||||||
display: flex;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.fc-time,
|
|
||||||
.fc-title {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Time Grid - Day view */
|
|
||||||
.fc-view.fc-timeGridDay-view {
|
|
||||||
|
|
||||||
.fc-head {
|
|
||||||
|
|
||||||
> tr > .fc-head-container {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-row {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day-header {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
@apply text-secondary;
|
|
||||||
|
|
||||||
&.fc-weekday {
|
|
||||||
padding-top: 16px;
|
|
||||||
font-size: 12px;
|
|
||||||
letter-spacing: 0.055em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-date {
|
|
||||||
padding-bottom: 12px;
|
|
||||||
font-size: 26px;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-body {
|
|
||||||
|
|
||||||
> tr > .fc-widget-content {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-day-grid {
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-day {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-row {
|
|
||||||
min-height: 0;
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content-skeleton {
|
|
||||||
padding-bottom: 0;
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
|
|
||||||
.fc-day-grid-event {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 22px;
|
|
||||||
min-height: 22px;
|
|
||||||
max-height: 22px;
|
|
||||||
margin: 0 6px 6px 6px;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-divider {
|
|
||||||
border: none;
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-time-grid {
|
|
||||||
|
|
||||||
.fc-bg {
|
|
||||||
|
|
||||||
.fc-day {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-today {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
border: none;
|
|
||||||
width: 48px !important;
|
|
||||||
|
|
||||||
+ .fc-day {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-slats {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
height: 48px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 12px;
|
|
||||||
width: 48px;
|
|
||||||
min-width: 48px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-time {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-widget-content {
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-content-skeleton {
|
|
||||||
|
|
||||||
.fc-axis {
|
|
||||||
width: 48px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-event-container {
|
|
||||||
margin: 0 12px 0 0;
|
|
||||||
|
|
||||||
.fc-time-grid-event {
|
|
||||||
display: flex;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.fc-time,
|
|
||||||
.fc-title {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List - Year view */
|
|
||||||
.fc-view.fc-listYear-view {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
.fc-list-table {
|
|
||||||
|
|
||||||
.fc-list-heading {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-list-item {
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
|
|
||||||
td {
|
|
||||||
@apply bg-hover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: auto;
|
|
||||||
height: 48px;
|
|
||||||
min-height: 48px;
|
|
||||||
padding: 0 8px;
|
|
||||||
border-width: 0 0 1px 0;
|
|
||||||
border-color: var(--fuse-divider);
|
|
||||||
|
|
||||||
&.fc-list-item-date {
|
|
||||||
order: 1;
|
|
||||||
padding-left: 16px;
|
|
||||||
width: 100px;
|
|
||||||
min-width: 100px;
|
|
||||||
max-width: 100px;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
width: 120px;
|
|
||||||
min-width: 120px;
|
|
||||||
max-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
|
|
||||||
span {
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding-right: 2px;
|
|
||||||
width: 32px;
|
|
||||||
min-width: 32px;
|
|
||||||
max-width: 32px;
|
|
||||||
font-size: 18px;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ span {
|
|
||||||
display: flex;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 0.055em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
@apply text-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-list-item-time {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
order: 3;
|
|
||||||
width: 120px;
|
|
||||||
min-width: 120px;
|
|
||||||
max-width: 120px;
|
|
||||||
|
|
||||||
@screen sm {
|
|
||||||
width: 160px;
|
|
||||||
min-width: 160px;
|
|
||||||
max-width: 160px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-list-item-marker {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
order: 2;
|
|
||||||
|
|
||||||
.fc-event-dot {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fc-list-item-title {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
order: 4;
|
|
||||||
padding-right: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Day grid event - Dragging */
|
|
||||||
.fc-day-grid-event {
|
|
||||||
|
|
||||||
&.fc-dragging,
|
|
||||||
&.fc-resizing {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 22px;
|
|
||||||
min-height: 22px;
|
|
||||||
max-height: 22px;
|
|
||||||
margin: 0 6px 4px 6px;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,11 +4,12 @@
|
|||||||
.ql-toolbar {
|
.ql-toolbar {
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: 6px 6px 0 0;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
@apply bg-gray-100 border-gray-300;
|
@apply bg-gray-100;
|
||||||
|
@apply border-gray-300 border-opacity-100 #{'!important'};
|
||||||
|
|
||||||
.dark & {
|
.dark & {
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
@apply border-gray-500;
|
@apply border-gray-500 #{'!important'};
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-formats {
|
.ql-formats {
|
||||||
@@ -79,30 +80,63 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ql-container {
|
.ql-container {
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
|
min-height: 160px;
|
||||||
|
max-height: 400px;
|
||||||
border-radius: 0 0 6px 6px;
|
border-radius: 0 0 6px 6px;
|
||||||
@apply border-gray-300 shadow-sm;
|
@apply border-gray-300 border-opacity-100 shadow-sm #{'!important'};
|
||||||
|
|
||||||
.dark & {
|
.dark & {
|
||||||
@apply border-gray-500;
|
@apply border-gray-500 #{'!important'};
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-editor {
|
.ql-editor {
|
||||||
min-height: 160px;
|
@apply bg-card;
|
||||||
max-height: 160px;
|
|
||||||
height: 160px;
|
|
||||||
@apply bg-gray-50;
|
|
||||||
|
|
||||||
.dark & {
|
.dark & {
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
//background-color: rgba(0, 0, 0, 0.05);
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
@apply bg-card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.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'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,11 +63,15 @@
|
|||||||
-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'};
|
||||||
}
|
}
|
||||||
|
|
||||||
*, *::before, *::after {
|
/* Set the border color */
|
||||||
|
*,
|
||||||
|
::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));
|
||||||
|
|
||||||
@@ -76,6 +80,47 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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'};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,176 +1,164 @@
|
|||||||
@use '~@angular/material' as mat;
|
|
||||||
@use "sass:map";
|
@use "sass:map";
|
||||||
|
@use '@angular/material' as mat;
|
||||||
|
@use "user-themes" as userThemes;
|
||||||
|
|
||||||
|
/* 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 color.
|
/* Create a base theme without any color to set the density and typography */
|
||||||
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: -2,
|
density: 0,
|
||||||
typography: mat.define-typography-config(
|
typography: mat.define-typography-config(
|
||||||
$font-family: theme('fontFamily.sans'),
|
$font-family: theme('fontFamily.sans'),
|
||||||
$title: mat.define-typography-level(1.25rem, 2rem, 600),
|
$headline-1: mat.define-typography-level(1.875rem, 2.25rem, 800, theme('fontFamily.sans')),
|
||||||
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
|
$headline-2: mat.define-typography-level(1.25rem, 1.75rem, 700, theme('fontFamily.sans')),
|
||||||
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
|
$headline-3: mat.define-typography-level(1.125rem, 1.75rem, 600, theme('fontFamily.sans')),
|
||||||
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
|
$headline-4: mat.define-typography-level(0.875rem, 1.25rem, 600, theme('fontFamily.sans')),
|
||||||
|
$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'))
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
/* Prepare the Background and Foreground maps */
|
/* Loop through user themes and generate Angular Material themes */
|
||||||
$background-light: (
|
@each $name, $theme in userThemes.$user-themes {
|
||||||
status-bar: #CBD5E1, /* blueGray.300 */
|
|
||||||
app-bar: #FFFFFF,
|
|
||||||
background: #F1F5F9, /* blueGray.100 */
|
|
||||||
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
|
|
||||||
card: #FFFFFF,
|
|
||||||
dialog: #FFFFFF,
|
|
||||||
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
|
|
||||||
raised-button: #FFFFFF,
|
|
||||||
focused-button: #64748B, /* blueGray.500 */
|
|
||||||
selected-button: #E2E8F0, /* blueGray.200 */
|
|
||||||
selected-disabled-button: #E2E8F0, /* blueGray.200 */
|
|
||||||
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
|
|
||||||
unselected-chip: #E2E8F0, /* blueGray.200 */
|
|
||||||
disabled-list-option: #CBD5E1, /* blueGray.300 */
|
|
||||||
tooltip: #1E293B /* blueGray.800 */
|
|
||||||
);
|
|
||||||
|
|
||||||
$background-dark: (
|
/* Generate the palettes */
|
||||||
status-bar: #0F172A, /* blueGray.900 */
|
$palettes: ();
|
||||||
app-bar: #0F172A, /* blueGray.900 */
|
@each $name in (primary, accent, warn) {
|
||||||
background: #0F172A, /* blueGray.900 */
|
|
||||||
hover: rgba(255, 255, 255, 0.05),
|
|
||||||
card: #1E293B, /* blueGray.800 */
|
|
||||||
dialog: #1E293B, /* blueGray.800 */
|
|
||||||
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
|
|
||||||
raised-button: #0F172A, /* blueGray.900 */
|
|
||||||
focused-button: #E2E8F0, /* blueGray.200 */
|
|
||||||
selected-button: rgba(255, 255, 255, 0.05),
|
|
||||||
selected-disabled-button: #1E293B, /* blueGray.800 */
|
|
||||||
disabled-button-toggle: #0F172A, /* blueGray.900 */
|
|
||||||
unselected-chip: #475569, /* blueGray.600 */
|
|
||||||
disabled-list-option: #E2E8F0, /* blueGray.200 */
|
|
||||||
tooltip: #64748B /* blueGray.500 */
|
|
||||||
);
|
|
||||||
|
|
||||||
$foreground-light: (
|
/* Define the Angular Material theme */
|
||||||
base: #000000,
|
$palette: mat.define-palette(map.get($theme, $name));
|
||||||
divider: #E2E8F0, /* blueGray.200 */
|
|
||||||
dividers: #E2E8F0, /* blueGray.200 */
|
|
||||||
disabled: #94A3B8, /* blueGray.400 */
|
|
||||||
disabled-button: #94A3B8, /* blueGray.400 */
|
|
||||||
disabled-text: #94A3B8, /* blueGray.400 */
|
|
||||||
elevation: #000000,
|
|
||||||
hint-text: #94A3B8, /* blueGray.400 */
|
|
||||||
secondary-text: #64748B, /* blueGray.500 */
|
|
||||||
icon: #64748B, /* blueGray.500 */
|
|
||||||
icons: #64748B, /* blueGray.500 */
|
|
||||||
mat-icon: #64748B, /* blueGray.500 */
|
|
||||||
text: #1E293B, /* blueGray.800 */
|
|
||||||
slider-min: #1E293B, /* blueGray.800 */
|
|
||||||
slider-off: #CBD5E1, /* blueGray.300 */
|
|
||||||
slider-off-active: #94A3B8 /* blueGray.400 */
|
|
||||||
);
|
|
||||||
|
|
||||||
$foreground-dark: (
|
/* Replace the default colors on the defined Material palette */
|
||||||
base: #FFFFFF,
|
$palette: map.merge($palette, (
|
||||||
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
|
default: map.get(map.get($theme, $name), DEFAULT),
|
||||||
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
|
lighter: map.get(map.get($theme, $name), 100),
|
||||||
disabled: #475569, /* blueGray.600 */
|
darker: map.get(map.get($theme, $name), 700),
|
||||||
disabled-button: #1E293B, /* blueGray.800 */
|
text: map.get(map.get($theme, $name), DEFAULT),
|
||||||
disabled-text: #475569, /* blueGray.600 */
|
default-contrast: map.get(map.get(map.get($theme, $name), contrast), DEFAULT),
|
||||||
elevation: #000000,
|
lighter-contrast: map.get(map.get(map.get($theme, $name), contrast), 100),
|
||||||
hint-text: #64748B, /* blueGray.500 */
|
darker-contrast: map.get(map.get(map.get($theme, $name), contrast), 700)
|
||||||
secondary-text: #94A3B8, /* blueGray.400 */
|
));
|
||||||
icon: #F1F5F9, /* blueGray.100 */
|
|
||||||
icons: #F1F5F9, /* blueGray.100 */
|
|
||||||
mat-icon: #94A3B8, /* blueGray.400 */
|
|
||||||
text: #FFFFFF,
|
|
||||||
slider-min: #FFFFFF,
|
|
||||||
slider-off: #64748B, /* blueGray.500 */
|
|
||||||
slider-off-active: #94A3B8 /* blueGray.400 */
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Generate Primary, Accent and Warn palettes */
|
$palettes: map.merge($palettes, (#{$name}: $palette));
|
||||||
$palettes: ();
|
}
|
||||||
@each $name in (primary, accent, warn) {
|
|
||||||
$palettes: map.merge($palettes, (#{$name}: (
|
|
||||||
50: var(--fuse-#{$name}-50),
|
|
||||||
100: var(--fuse-#{$name}-100),
|
|
||||||
200: var(--fuse-#{$name}-200),
|
|
||||||
300: var(--fuse-#{$name}-300),
|
|
||||||
400: var(--fuse-#{$name}-400),
|
|
||||||
500: var(--fuse-#{$name}-500),
|
|
||||||
600: var(--fuse-#{$name}-600),
|
|
||||||
700: var(--fuse-#{$name}-700),
|
|
||||||
800: var(--fuse-#{$name}-800),
|
|
||||||
900: var(--fuse-#{$name}-900),
|
|
||||||
contrast: (
|
|
||||||
50: var(--fuse-on-#{$name}-50),
|
|
||||||
100: var(--fuse-on-#{$name}-100),
|
|
||||||
200: var(--fuse-on-#{$name}-200),
|
|
||||||
300: var(--fuse-on-#{$name}-300),
|
|
||||||
400: var(--fuse-on-#{$name}-400),
|
|
||||||
500: var(--fuse-on-#{$name}-500),
|
|
||||||
600: var(--fuse-on-#{$name}-600),
|
|
||||||
700: var(--fuse-on-#{$name}-700),
|
|
||||||
800: var(--fuse-on-#{$name}-800),
|
|
||||||
900: var(--fuse-on-#{$name}-900)
|
|
||||||
),
|
|
||||||
default: var(--fuse-#{$name}),
|
|
||||||
lighter: var(--fuse-#{$name}-100),
|
|
||||||
darker: var(--fuse-#{$name}-700),
|
|
||||||
text: var(--fuse-#{$name}),
|
|
||||||
default-contrast: var(--fuse-on-#{$name}),
|
|
||||||
lighter-contrast: var(--fuse-on-#{$name}-100),
|
|
||||||
darker-contrast: var(--fuse-on-#{$name}-700)
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate Angular Material themes. Since we are using CSS Custom Properties,
|
/* Define a light & dark Angular Material theme with the generated palettes */
|
||||||
we don't have to generate a separate Angular Material theme for each color
|
$light-theme: mat.define-light-theme((
|
||||||
set. We can just create one light and one dark theme and then switch the
|
|
||||||
CSS Custom Properties to dynamically switch the colors. */
|
|
||||||
body.light,
|
|
||||||
body .light {
|
|
||||||
$base-light-theme: mat.define-light-theme((
|
|
||||||
color: ($palettes)
|
color: ($palettes)
|
||||||
));
|
));
|
||||||
|
|
||||||
$light-theme: (
|
$dark-theme: mat.define-dark-theme((
|
||||||
color: (
|
|
||||||
primary: map.get(map.get($base-light-theme, color), primary),
|
|
||||||
accent: map.get(map.get($base-light-theme, color), accent),
|
|
||||||
warn: map.get(map.get($base-light-theme, color), warn),
|
|
||||||
is-dark: map.get(map.get($base-light-theme, color), is-dark),
|
|
||||||
foreground: $foreground-light,
|
|
||||||
background: $background-light
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* 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)
|
color: ($palettes)
|
||||||
));
|
));
|
||||||
|
|
||||||
$dark-theme: (
|
/* Merge the custom base colors with the generated themes */
|
||||||
color: (
|
$light-theme-colors: map.merge(map.get($light-theme, color), $light-base);
|
||||||
primary: map.get(map.get($base-dark-theme, color), primary),
|
$light-theme: map.merge(
|
||||||
accent: map.get(map.get($base-dark-theme, color), accent),
|
(color: $light-theme-colors),
|
||||||
warn: map.get(map.get($base-dark-theme, color), warn),
|
$light-theme-colors
|
||||||
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
|
|
||||||
foreground: $foreground-dark,
|
|
||||||
background: $background-dark
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Use all-component-colors to only generate the colors */
|
$dark-theme-colors: map.merge(map.get($dark-theme, color), $dark-base);
|
||||||
@include mat.all-component-colors($dark-theme);
|
$dark-theme: map.merge(
|
||||||
|
(color: $dark-theme-colors),
|
||||||
|
$dark-theme-colors
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Generate and encapsulate Angular Material themes */
|
||||||
|
#{map.get($theme, selector)} .light,
|
||||||
|
#{map.get($theme, selector)}.light {
|
||||||
|
@include mat.all-component-colors($light-theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
#{map.get($theme, selector)} .dark,
|
||||||
|
#{map.get($theme, selector)}.dark {
|
||||||
|
@include mat.all-component-colors($dark-theme);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/@fuse/styles/user-themes.scss
Normal file
1
src/@fuse/styles/user-themes.scss
Normal file
File diff suppressed because one or more lines are too long
@@ -1,38 +0,0 @@
|
|||||||
const plugin = require('tailwindcss/plugin');
|
|
||||||
const buildMediaQuery = require('tailwindcss/lib/util/buildMediaQuery').default;
|
|
||||||
|
|
||||||
const extractConfig = plugin(({
|
|
||||||
addVariant,
|
|
||||||
theme
|
|
||||||
}) =>
|
|
||||||
{
|
|
||||||
addVariant('fuse-tailwind-extracted-config', ({container}) =>
|
|
||||||
{
|
|
||||||
// Prepare the extracted config variable
|
|
||||||
let extractedConfig = '';
|
|
||||||
|
|
||||||
// Breakpoints
|
|
||||||
Object.entries(theme('screens')).forEach(([key, value]) =>
|
|
||||||
{
|
|
||||||
extractedConfig = `${extractedConfig} --breakpoints-${key}:'${buildMediaQuery(value)}';`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Themes
|
|
||||||
(theme('fuse.themes')).forEach((value) =>
|
|
||||||
{
|
|
||||||
Object.entries(value).forEach(([key, value]) =>
|
|
||||||
{
|
|
||||||
extractedConfig = `${extractedConfig} --themes-${key}:'${JSON.stringify(value)}';`;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Append the extracted config
|
|
||||||
container.append(`
|
|
||||||
.fuse-tailwind-extracted-config {
|
|
||||||
${extractedConfig}
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = extractConfig;
|
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
const plugin = require('tailwindcss/plugin');
|
const plugin = require('tailwindcss/plugin');
|
||||||
|
|
||||||
const iconSize = plugin(({
|
module.exports = plugin(
|
||||||
addUtilities,
|
({
|
||||||
theme,
|
matchUtilities,
|
||||||
e,
|
theme
|
||||||
variants
|
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
const values = theme('iconSize');
|
matchUtilities(
|
||||||
|
{
|
||||||
addUtilities(
|
'icon-size': (value) => ({
|
||||||
Object.entries(values).map(([key, value]) => ({
|
|
||||||
[`.${e(`icon-size-${key}`)}`]: {
|
|
||||||
width : value,
|
width : value,
|
||||||
height : value,
|
height : value,
|
||||||
minWidth : value,
|
minWidth : value,
|
||||||
@@ -22,13 +19,14 @@ const iconSize = plugin(({
|
|||||||
width : value,
|
width : value,
|
||||||
height: value
|
height: value
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})),
|
},
|
||||||
variants('iconSize')
|
{
|
||||||
);
|
values: theme('iconSize')
|
||||||
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
theme : {
|
theme: {
|
||||||
iconSize: {
|
iconSize: {
|
||||||
3 : '0.75rem',
|
3 : '0.75rem',
|
||||||
3.5: '0.875rem',
|
3.5: '0.875rem',
|
||||||
@@ -47,10 +45,6 @@ const iconSize = plugin(({
|
|||||||
22 : '5.5rem',
|
22 : '5.5rem',
|
||||||
24 : '6rem'
|
24 : '6rem'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
variants: {
|
|
||||||
iconSize: ['responsive']
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
module.exports = iconSize;
|
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
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
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the provided theme
|
* Normalizes the provided theme by omitting empty values and values that
|
||||||
|
* start with "on" from each palette. Also sets the correct DEFAULT value
|
||||||
|
* of each palette.
|
||||||
*
|
*
|
||||||
* @param theme
|
* @param theme
|
||||||
*/
|
*/
|
||||||
@@ -28,67 +32,6 @@ 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
|
||||||
// -----------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------
|
||||||
@@ -98,29 +41,113 @@ const theming = plugin.withOptions((options) => ({
|
|||||||
theme
|
theme
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
// -----------------------------------------------------------------------------------------------------
|
/**
|
||||||
// @ Map variable colors
|
* Create user themes object by going through the provided themes and
|
||||||
// -----------------------------------------------------------------------------------------------------
|
* merging them with the provided "default" so, we can have a complete
|
||||||
const mapVariableColors = _.fromPairs(_.map(options.themes, (theme, themeName) => [
|
* set of color palettes for each user theme.
|
||||||
themeName === 'default' ? 'body' : `body.theme-${e(themeName)}`,
|
*/
|
||||||
_.fromPairs(_.flatten(_.map(flattenColorPalette(_.fromPairs(_.flatten(_.map(normalizeTheme(theme), (palette, paletteName) => [
|
const userThemes = _.fromPairs(_.map(options.themes, (theme, themeName) => [
|
||||||
[
|
themeName,
|
||||||
e(paletteName),
|
_.defaults({}, theme, options.themes['default'])
|
||||||
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)
|
||||||
|
]));
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------
|
/**
|
||||||
// @ Generate scheme based css custom properties and utility classes
|
* Go through the themes to generate the contrasts and filter the
|
||||||
// -----------------------------------------------------------------------------------------------------
|
* 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';
|
||||||
@@ -135,13 +162,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
|
||||||
* all on dark themes so that the fallback value can be used on
|
* at 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
|
||||||
@@ -156,7 +183,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(',')]])))
|
||||||
}
|
}
|
||||||
@@ -165,7 +192,7 @@ const theming = plugin.withOptions((options) => ({
|
|||||||
|
|
||||||
const schemeUtilities = (() =>
|
const schemeUtilities = (() =>
|
||||||
{
|
{
|
||||||
// Generate general styles & utilities
|
/* Generate general styles & utilities */
|
||||||
return {};
|
return {};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -175,9 +202,17 @@ 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: {
|
||||||
@@ -185,47 +220,45 @@ const theming = plugin.withOptions((options) => ({
|
|||||||
light: {
|
light: {
|
||||||
'bg-app-bar' : '#FFFFFF',
|
'bg-app-bar' : '#FFFFFF',
|
||||||
'bg-card' : '#FFFFFF',
|
'bg-card' : '#FFFFFF',
|
||||||
'bg-default' : colors.blueGray[100],
|
'bg-default' : colors.slate[100],
|
||||||
'bg-dialog' : '#FFFFFF',
|
'bg-dialog' : '#FFFFFF',
|
||||||
'bg-hover' : chroma(colors.blueGray[400]).alpha(0.12).css(),
|
'bg-hover' : chroma(colors.slate[400]).alpha(0.12).css(),
|
||||||
'bg-status-bar': colors.blueGray[300]
|
'bg-status-bar': colors.slate[300]
|
||||||
},
|
},
|
||||||
dark : {
|
dark : {
|
||||||
'bg-app-bar' : colors.blueGray[900],
|
'bg-app-bar' : colors.slate[900],
|
||||||
'bg-card' : colors.blueGray[800],
|
'bg-card' : colors.slate[800],
|
||||||
'bg-default' : colors.blueGray[900],
|
'bg-default' : colors.slate[900],
|
||||||
'bg-dialog' : colors.blueGray[800],
|
'bg-dialog' : colors.slate[800],
|
||||||
'bg-hover' : 'rgba(255, 255, 255, 0.05)',
|
'bg-hover' : 'rgba(255, 255, 255, 0.05)',
|
||||||
'bg-status-bar': colors.blueGray[900]
|
'bg-status-bar': colors.slate[900]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
foreground: {
|
foreground: {
|
||||||
light: {
|
light: {
|
||||||
'text-default' : colors.blueGray[800],
|
'text-default' : colors.slate[800],
|
||||||
'text-secondary': colors.blueGray[500],
|
'text-secondary': colors.slate[500],
|
||||||
'text-hint' : colors.blueGray[400],
|
'text-hint' : colors.slate[400],
|
||||||
'text-disabled' : colors.blueGray[400],
|
'text-disabled' : colors.slate[400],
|
||||||
'border' : colors.blueGray[200],
|
'border' : colors.slate[200],
|
||||||
'divider' : colors.blueGray[200],
|
'divider' : colors.slate[200],
|
||||||
'icon' : colors.blueGray[500],
|
'icon' : colors.slate[500],
|
||||||
'mat-icon' : colors.blueGray[500]
|
'mat-icon' : colors.slate[500]
|
||||||
},
|
},
|
||||||
dark : {
|
dark : {
|
||||||
'text-default' : '#FFFFFF',
|
'text-default' : '#FFFFFF',
|
||||||
'text-secondary': colors.blueGray[400],
|
'text-secondary': colors.slate[400],
|
||||||
'text-hint' : colors.blueGray[500],
|
'text-hint' : colors.slate[500],
|
||||||
'text-disabled' : colors.blueGray[600],
|
'text-disabled' : colors.slate[600],
|
||||||
'border' : chroma(colors.blueGray[100]).alpha(0.12).css(),
|
'border' : chroma(colors.slate[100]).alpha(0.12).css(),
|
||||||
'divider' : chroma(colors.blueGray[100]).alpha(0.12).css(),
|
'divider' : chroma(colors.slate[100]).alpha(0.12).css(),
|
||||||
'icon' : colors.blueGray[400],
|
'icon' : colors.slate[400],
|
||||||
'mat-icon' : colors.blueGray[400]
|
'mat-icon' : colors.slate[400]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
themes : generateThemesObject(options.themes)
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
variants: {}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const plugin = require('tailwindcss/plugin');
|
const plugin = require('tailwindcss/plugin');
|
||||||
|
|
||||||
const utilities = plugin(({
|
module.exports = plugin(({
|
||||||
addComponents
|
addComponents
|
||||||
}) =>
|
}) =>
|
||||||
{
|
{
|
||||||
@@ -54,9 +54,6 @@ const utilities = plugin(({
|
|||||||
'--tw-ring-opacity': '1 !important',
|
'--tw-ring-opacity': '1 !important',
|
||||||
'--tw-ring-color' : 'rgba(var(--fuse-bg-card-rgb), var(--tw-ring-opacity)) !important'
|
'--tw-ring-color' : 'rgba(var(--fuse-bg-card-rgb), var(--tw-ring-opacity)) !important'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
variants: ['dark', 'responsive', 'group-hover', 'hover']
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -65,11 +62,6 @@ const utilities = plugin(({
|
|||||||
'.bg-hover': {
|
'.bg-hover': {
|
||||||
backgroundColor: 'var(--fuse-bg-hover) !important'
|
backgroundColor: 'var(--fuse-bg-hover) !important'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
variants: ['dark', 'group-hover', 'hover']
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = utilities;
|
|
||||||
|
|||||||
67
src/@fuse/tailwind/utils/json-to-sass-map.js
Normal file
67
src/@fuse/tailwind/utils/json-to-sass-map.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
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) + ';';
|
||||||
|
};
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
import { Version } from '@fuse/version/version';
|
import { Version } from '@fuse/version/version';
|
||||||
|
|
||||||
export const FUSE_VERSION = new Version('13.4.0').full;
|
export const FUSE_VERSION = new Version('17.0.0').full;
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ 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';
|
||||||
@@ -36,10 +35,7 @@ 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
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { forkJoin, Observable } from 'rxjs';
|
|||||||
import { MessagesService } from 'app/layout/common/messages/messages.service';
|
import { MessagesService } from 'app/layout/common/messages/messages.service';
|
||||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
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 { 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'
|
||||||
@@ -19,8 +19,8 @@ export class InitialDataResolver implements Resolve<any>
|
|||||||
private _messagesService: MessagesService,
|
private _messagesService: MessagesService,
|
||||||
private _navigationService: NavigationService,
|
private _navigationService: NavigationService,
|
||||||
private _notificationsService: NotificationsService,
|
private _notificationsService: NotificationsService,
|
||||||
private _shortcutsService: ShortcutsService,
|
private _quickChatService: QuickChatService,
|
||||||
private _userService: UserService
|
private _shortcutsService: ShortcutsService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -42,8 +42,8 @@ export class InitialDataResolver implements Resolve<any>
|
|||||||
this._navigationService.get(),
|
this._navigationService.get(),
|
||||||
this._messagesService.getAll(),
|
this._messagesService.getAll(),
|
||||||
this._notificationsService.getAll(),
|
this._notificationsService.getAll(),
|
||||||
this._shortcutsService.getAll(),
|
this._quickChatService.getChats(),
|
||||||
this._userService.get()
|
this._shortcutsService.getAll()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ export const appRoutes: Route[] = [
|
|||||||
// Apps
|
// Apps
|
||||||
{path: 'apps', children: [
|
{path: 'apps', children: [
|
||||||
{path: 'academy', loadChildren: () => import('app/modules/admin/apps/academy/academy.module').then(m => m.AcademyModule)},
|
{path: 'academy', loadChildren: () => import('app/modules/admin/apps/academy/academy.module').then(m => m.AcademyModule)},
|
||||||
{path: 'calendar', loadChildren: () => import('app/modules/admin/apps/calendar/calendar.module').then(m => m.CalendarModule)},
|
|
||||||
{path: 'chat', loadChildren: () => import('app/modules/admin/apps/chat/chat.module').then(m => m.ChatModule)},
|
{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: '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: 'ecommerce', loadChildren: () => import('app/modules/admin/apps/ecommerce/ecommerce.module').then(m => m.ECommerceModule)},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { catchError, Observable, throwError } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
|
||||||
import { AuthService } from 'app/core/auth/auth.service';
|
import { AuthService } from 'app/core/auth/auth.service';
|
||||||
import { AuthUtils } from 'app/core/auth/auth.utils';
|
import { AuthUtils } from 'app/core/auth/auth.utils';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable, of, throwError } from 'rxjs';
|
import { catchError, Observable, of, switchMap, throwError } from 'rxjs';
|
||||||
import { catchError, switchMap } from 'rxjs/operators';
|
|
||||||
import { AuthUtils } from 'app/core/auth/auth.utils';
|
import { AuthUtils } from 'app/core/auth/auth.utils';
|
||||||
import { UserService } from 'app/core/user/user.service';
|
import { UserService } from 'app/core/user/user.service';
|
||||||
|
|
||||||
@@ -97,8 +96,8 @@ export class AuthService
|
|||||||
*/
|
*/
|
||||||
signInUsingToken(): Observable<any>
|
signInUsingToken(): Observable<any>
|
||||||
{
|
{
|
||||||
// Renew token
|
// Sign in using the token
|
||||||
return this._httpClient.post('api/auth/refresh-access-token', {
|
return this._httpClient.post('api/auth/sign-in-with-token', {
|
||||||
accessToken: this.accessToken
|
accessToken: this.accessToken
|
||||||
}).pipe(
|
}).pipe(
|
||||||
catchError(() =>
|
catchError(() =>
|
||||||
@@ -108,8 +107,17 @@ export class AuthService
|
|||||||
),
|
),
|
||||||
switchMap((response: any) => {
|
switchMap((response: any) => {
|
||||||
|
|
||||||
// Store the access token in the local storage
|
// Replace the access token with the new one if it's available on
|
||||||
this.accessToken = response.accessToken;
|
// the response object.
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
|
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of, switchMap } from 'rxjs';
|
||||||
import { AuthService } from 'app/core/auth/auth.service';
|
import { AuthService } from 'app/core/auth/auth.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
|
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of, switchMap } from 'rxjs';
|
||||||
import { AuthService } from 'app/core/auth/auth.service';
|
import { AuthService } from 'app/core/auth/auth.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { Layout } from 'app/layout/layout.types';
|
|||||||
|
|
||||||
// Types
|
// Types
|
||||||
export type Scheme = 'auto' | 'dark' | 'light';
|
export type Scheme = 'auto' | 'dark' | 'light';
|
||||||
export type Theme = 'default' | string;
|
export type Screens = { [key: string]: string };
|
||||||
|
export type Theme = 'theme-default' | string;
|
||||||
|
export type Themes = { id: string; name: string }[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppConfig interface. Update this interface to strictly type your config
|
* AppConfig interface. Update this interface to strictly type your config
|
||||||
@@ -12,7 +14,9 @@ export interface AppConfig
|
|||||||
{
|
{
|
||||||
layout: Layout;
|
layout: Layout;
|
||||||
scheme: Scheme;
|
scheme: Scheme;
|
||||||
|
screens: Screens;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
|
themes: Themes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,9 +26,46 @@ export interface AppConfig
|
|||||||
* If you need to store global configuration for your app, you can use this
|
* If you need to store global configuration for your app, you can use this
|
||||||
* object to set the defaults. To access, update and reset the config, use
|
* object to set the defaults. To access, update and reset the config, use
|
||||||
* FuseConfigService and its methods.
|
* FuseConfigService and its methods.
|
||||||
|
*
|
||||||
|
* "Screens" are carried over to the BreakpointObserver for accessing them within
|
||||||
|
* components, and they are required.
|
||||||
|
*
|
||||||
|
* "Themes" are required for Tailwind to generate themes.
|
||||||
*/
|
*/
|
||||||
export const appConfig: AppConfig = {
|
export const appConfig: AppConfig = {
|
||||||
layout: 'classy',
|
layout : 'classy',
|
||||||
scheme: 'light',
|
scheme : 'light',
|
||||||
theme : 'default'
|
screens: {
|
||||||
|
sm: '600px',
|
||||||
|
md: '960px',
|
||||||
|
lg: '1280px',
|
||||||
|
xl: '1440px'
|
||||||
|
},
|
||||||
|
theme : 'theme-default',
|
||||||
|
themes : [
|
||||||
|
{
|
||||||
|
id : 'theme-default',
|
||||||
|
name: 'Default'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id : 'theme-brand',
|
||||||
|
name: 'Brand'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id : 'theme-teal',
|
||||||
|
name: 'Teal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id : 'theme-rose',
|
||||||
|
name: 'Rose'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id : 'theme-purple',
|
||||||
|
name: 'Purple'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id : 'theme-amber',
|
||||||
|
name: 'Amber'
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ 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'));
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable, ReplaySubject } from 'rxjs';
|
import { Observable, ReplaySubject, tap } from 'rxjs';
|
||||||
import { tap } from 'rxjs/operators';
|
|
||||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user