Compare commits

..

76 Commits

Author SHA1 Message Date
Sercan Yemen
4be77a19ed Removed unnecessary lines from angular-cli.json file 2018-03-09 20:17:38 +03:00
Sercan Yemen
8374c7d059 Merge branch 'master' into skeleton 2018-03-09 20:14:36 +03:00
Sercan Yemen
da615585d0 Merge branch 'master' into skeleton 2018-03-09 20:03:43 +03:00
Sercan Yemen
7c50487164 Removed unnecessary Angular Material example files, fixes AoT builds 2018-03-09 06:30:59 +03:00
Sercan Yemen
97c7f136bf Merge branch 'master' into skeleton 2018-03-08 12:44:21 +03:00
Sercan Yemen
1cddda02b1 Merge branch 'master' into skeleton 2018-03-08 12:42:14 +03:00
Sercan Yemen
c178eeedaa Merge branch 'master' into skeleton 2018-03-08 12:38:51 +03:00
Sercan Yemen
43b22e609e Merge branch 'master' into skeleton 2018-02-08 11:06:42 +03:00
Sercan Yemen
a914ad6dc1 Merge branch 'master' into skeleton 2018-02-05 17:17:24 +03:00
Sercan Yemen
b2e840cb60 Merge branch 'master' into skeleton 2018-01-23 17:03:44 +03:00
Sercan Yemen
d7c67ca5a8 Updated package-lock.json file 2018-01-18 13:34:27 +03:00
Sercan Yemen
cf7ab3861d Merge branch 'master' into skeleton 2018-01-18 13:21:58 +03:00
Sercan Yemen
ab4ed81cfc Merge branch 'master' into skeleton 2018-01-18 13:19:38 +03:00
Sercan Yemen
2022b7307e Merge branch 'master' into skeleton 2018-01-11 13:37:32 +03:00
Sercan Yemen
46de82a7fa Merge branch 'master' into skeleton 2018-01-11 13:37:03 +03:00
Sercan Yemen
bc2b2c75fa Merge branch 'master' into skeleton 2018-01-08 16:41:04 +03:00
Sercan Yemen
02653cd0f4 Merge branch 'master' into skeleton 2018-01-08 16:40:33 +03:00
Sercan Yemen
ff14879a94 Merge branch 'master' into skeleton 2018-01-08 16:11:29 +03:00
Sercan Yemen
49c49c46d1 Merge branch 'master' into skeleton 2018-01-08 16:09:12 +03:00
Sercan Yemen
915e9203ef Merge branch 'master' into skeleton 2018-01-08 16:08:56 +03:00
Sercan Yemen
33d295f42c Merge branch 'master' into skeleton 2018-01-02 12:37:12 +03:00
Sercan Yemen
91e277ce3f Merge branch 'master' into skeleton 2018-01-02 12:32:01 +03:00
Sercan Yemen
b7a3d35eb8 Updated package-lock.json 2017-12-28 10:52:40 +03:00
Sercan Yemen
f29f11232f Merge branch 'master' into skeleton 2017-12-28 10:51:09 +03:00
Sercan Yemen
16ffb09350 Merge branch 'master' into skeleton 2017-12-26 10:49:15 +03:00
Sercan Yemen
643a129a46 Merge branch 'master' into skeleton 2017-12-21 10:06:16 +03:00
Sercan Yemen
de16f4f866 Merge branch 'master' into skeleton 2017-12-18 12:25:56 +03:00
Sercan Yemen
415d7cebfa Skeleton updates 2017-12-14 16:20:52 +03:00
Sercan Yemen
f7d1995f63 Merge branch 'master' into skeleton 2017-12-14 16:06:32 +03:00
Sercan Yemen
3741abc063 Skeleton package updates 2017-12-14 16:03:34 +03:00
Sercan Yemen
54ccdd7de2 Merge branch 'master' into skeleton 2017-12-14 16:01:09 +03:00
Sercan Yemen
8b2e6b95b1 Merge branch 'master' into skeleton 2017-11-30 15:56:00 +03:00
Sercan Yemen
e86cea1e73 Merge branch 'master' into skeleton 2017-11-30 10:38:03 +03:00
Sercan Yemen
b81638690e Merge branch 'master' into skeleton 2017-11-30 10:23:19 +03:00
Sercan Yemen
20ac3abb25 Merge branch 'master' into skeleton 2017-11-27 17:21:38 +03:00
Sercan Yemen
f634cb06a7 Merge branch 'master' into skeleton 2017-11-27 14:42:23 +03:00
Sercan Yemen
7d67a481ff Merge branch 'master' into skeleton 2017-11-27 14:35:37 +03:00
Sercan Yemen
4659da7390 Added missing variables that prevents skeleton from building as it is 2017-11-13 12:30:11 +03:00
Sercan Yemen
2a5d15694c Merge branch 'master' into skeleton 2017-11-13 11:09:27 +03:00
Sercan Yemen
8e6024c3ee Fixes #44 : Removed angular material elements assets 2017-11-08 15:11:20 +03:00
Sercan Yemen
f4c47daadc Merge branch 'master' into skeleton 2017-11-08 15:10:51 +03:00
Sercan Yemen
381bc6c0fe Merge branch 'master' into skeleton 2017-11-04 16:50:03 +03:00
Sercan Yemen
b5a139f81d Merge branch 'master' into skeleton 2017-11-04 16:32:29 +03:00
Sercan Yemen
914477da41 Merge branch 'master' into skeleton 2017-11-04 16:25:09 +03:00
Sercan Yemen
410802808e Merge branch 'master' into skeleton 2017-11-04 16:20:46 +03:00
Sercan Yemen
56dbc58d5e Merge branch 'master' into skeleton
+ Added translation example to the sample page
2017-10-27 12:01:09 +03:00
Sercan Yemen
d7c6b2d617 Merge branch 'master' into skeleton 2017-10-27 11:49:31 +03:00
Sercan Yemen
80627bdde9 removed fake-db thingy 2017-10-16 10:50:57 +03:00
Sercan Yemen
6595975f2b Merge branch 'master' into skeleton 2017-10-16 10:45:27 +03:00
Sercan Yemen
dcb8032758 Merge branch 'master' into skeleton 2017-10-16 10:10:06 +03:00
Sercan Yemen
fb214da5fe Merge branch 'master' into skeleton 2017-10-14 18:53:08 +03:00
Sercan Yemen
e20687034f Merge branch 'master' into skeleton 2017-10-14 18:53:00 +03:00
Sercan Yemen
f9bda99deb Merge branch 'master' into skeleton 2017-10-02 10:15:00 +03:00
Sercan Yemen
1d81e37a0f removed markdown module imports 2017-09-28 13:00:44 +03:00
Sercan Yemen
83f0ed5ec1 Merge branch 'master' into skeleton 2017-09-28 12:52:59 +03:00
Sercan Yemen
e486413872 remove unnecessary stuff from skeleton 2017-09-28 12:51:15 +03:00
Sercan Yemen
576e167ef1 Merge branch 'master' into skeleton 2017-09-28 12:49:18 +03:00
Sercan Yemen
cf9e9fc209 Merge branch 'master' into skeleton 2017-09-22 16:45:47 +03:00
Sercan Yemen
ff0f2933d9 Merge branch 'master' into skeleton 2017-09-22 16:45:23 +03:00
Sercan Yemen
62467c8ddf Merge branch 'master' into skeleton 2017-09-12 16:06:21 +03:00
Sercan Yemen
024ab15b25 Merge branch 'master' into skeleton 2017-09-11 16:34:07 +03:00
Sercan Yemen
915ad52863 Merge branch 'master' into skeleton 2017-09-11 16:21:05 +03:00
Sercan Yemen
97bfaa9979 Merge branch 'master' into skeleton 2017-09-11 13:06:42 +03:00
Sercan Yemen
6ae3e154c3 Merge branch 'master' into skeleton 2017-09-11 12:59:36 +03:00
Sercan Yemen
49b6ff7292 navigation model for horizontal nav 2017-09-11 12:58:24 +03:00
Sercan Yemen
903688ab43 Merge branch 'master' into skeleton 2017-09-11 12:57:59 +03:00
Sercan Yemen
19f822cbab removed unnecessary md2 from skeleton 2017-09-01 09:05:56 +03:00
Sercan Yemen
1d21a14d0e Merge branch 'master' into skeleton 2017-08-30 20:52:23 +03:00
Sercan Yemen
4bf2ba73ad merge 'master' into skeleton 2017-08-30 20:08:12 +03:00
Sercan Yemen
6a3972fff8 Merge branch 'master' into skeleton 2017-08-30 14:43:10 +03:00
Sercan Yemen
dca16238eb Merge branch 'master' into skeleton 2017-08-30 14:41:30 +03:00
Sercan Yemen
2b91119d00 Merge branch 'master' into skeleton 2017-08-30 11:50:56 +03:00
Sercan Yemen
ff4899e8d2 Merge branch 'master' into skeleton
# Conflicts:
#	src/app/app.module.ts
#	src/app/main/content/apps/calendar/calendar.component.html
#	src/app/main/content/apps/contacts/contact-list/contact-list.component.html
#	src/app/main/content/apps/contacts/contacts.component.html
#	src/app/main/content/apps/contacts/contacts.component.scss
#	src/app/main/content/apps/contacts/contacts.module.ts
#	src/app/main/content/apps/contacts/contacts.service.ts
#	src/app/main/content/apps/contacts/selected-bar/selected-bar.component.html
#	src/app/main/content/apps/mail/sidenavs/main/main-sidenav.component.html
#	src/app/navigation.model.ts
2017-08-24 11:18:24 +03:00
Sercan Yemen
e818c53f1d navbar fixes 2017-08-22 16:05:32 +03:00
Sercan Yemen
ca96fffadf removed fuse fake db 2017-08-22 15:58:35 +03:00
Sercan Yemen
d7003711ee skeleton branch 2017-08-22 15:55:48 +03:00
1312 changed files with 9629 additions and 87404 deletions

67
.angular-cli.json Normal file
View File

@@ -0,0 +1,67 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "fuse"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.scss"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"hmr": "environments/environment.hmr.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": [
"**/node_modules/**"
]
},
{
"project": "src/tsconfig.spec.json",
"exclude": [
"**/node_modules/**"
]
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"component": {}
}
}

View File

@@ -1,6 +1,12 @@
root = true
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
indent_style=space
indent_size=4
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

5
.gitignore vendored
View File

@@ -30,10 +30,13 @@
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db

View File

@@ -1,6 +1,6 @@
# Fuse - Angular
# Fuse2
Material Design Admin Template with Angular 6+ and Angular Material
Material Design Admin Template with Angular 5+ and Angular Material 2
## The Community
@@ -14,11 +14,11 @@ Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app w
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|module`.
## 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. Use the `-prod` flag for a production build.
## Running unit tests
@@ -27,8 +27,4 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
Before running the tests make sure you are serving the app via `ng serve`.

View File

@@ -1,150 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"fuse": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets",
"src/app/main/angular-material-elements"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"ec": {
"sourceMap": true,
"extractCss": true
},
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "fuse:build"
},
"configurations": {
"production": {
"browserTarget": "fuse:build:production"
},
"hmr": {
"hmr": true,
"browserTarget": "fuse:build:hmr"
},
"ec": {
"browserTarget": "fuse:build:ec"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "fuse:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"styles.scss"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**",
"**/src/app/fake-db/**/*",
"**/src/assets/angular-material-examples/**/*"
]
}
}
}
},
"fuse-e2e": {
"root": "e2e/",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**",
"**/src/app/fake-db/**/*",
"**/src/assets/angular-material-examples/**/*"
]
}
}
}
}
},
"defaultProject": "fuse"
}

View File

@@ -9,6 +9,6 @@ describe('Fuse2 App', () => {
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to Fuse2!');
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});

View File

@@ -1,31 +0,0 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const {SpecReporter} = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs : [
'./src/**/*.e2e-spec.ts'
],
capabilities : {
'browserName': 'chrome'
},
directConnect : true,
baseUrl : 'http://localhost:4200/',
framework : 'jasmine',
jasmineNodeOpts : {
showColors : true,
defaultTimeoutInterval: 30000,
print : function ()
{
}
},
onPrepare()
{
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
});
jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}}));
}
};

View File

@@ -1,7 +1,8 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
@@ -10,4 +11,4 @@
"node"
]
}
}
}

33
karma.conf.js Normal file
View File

@@ -0,0 +1,33 @@
// 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/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

15883
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
{
"name": "fuse",
"version": "6.2.2",
"version": "5.2.9",
"license": "https://themeforest.net/licenses/terms/regular",
"scripts": {
"ng": "ng",
"start": "ng serve --open",
"start-hmr": "ng serve --configuration hmr --source-map=false --hmr-warning=false",
"start-hmr-sourcemaps": "ng serve --configuration hmr --source-map=true --hmr-warning=false",
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev",
"build-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev --stats-json",
"build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
@@ -18,71 +18,68 @@
},
"private": true,
"dependencies": {
"@agm/core": "1.0.0-beta.3",
"@angular/animations": "6.0.7",
"@angular/cdk": "6.3.3",
"@angular/common": "6.0.7",
"@angular/compiler": "6.0.7",
"@angular/core": "6.0.7",
"@angular/flex-layout": "6.0.0-beta.16",
"@angular/forms": "6.0.7",
"@angular/http": "6.0.7",
"@angular/material": "6.3.3",
"@angular/material-moment-adapter": "6.3.3",
"@angular/platform-browser": "6.0.7",
"@angular/platform-browser-dynamic": "6.0.7",
"@angular/router": "6.0.7",
"@ngrx/effects": "6.0.1",
"@ngrx/router-store": "6.0.1",
"@ngrx/store": "6.0.1",
"@ngrx/store-devtools": "6.0.1",
"@ngx-translate/core": "10.0.2",
"@swimlane/ngx-charts": "8.1.0",
"@swimlane/ngx-datatable": "13.0.1",
"@swimlane/ngx-dnd": "4.0.0",
"@agm/core": "1.0.0-beta.2",
"@angular/animations": "5.2.8",
"@angular/cdk": "5.2.4",
"@angular/common": "5.2.8",
"@angular/compiler": "5.2.8",
"@angular/core": "5.2.8",
"@angular/flex-layout": "5.0.0-beta.13",
"@angular/forms": "5.2.8",
"@angular/http": "5.2.8",
"@angular/material": "5.2.4",
"@angular/material-moment-adapter": "5.2.4",
"@angular/platform-browser": "5.2.8",
"@angular/platform-browser-dynamic": "5.2.8",
"@angular/router": "5.2.8",
"@ngrx/effects": "5.2.0",
"@ngrx/router-store": "5.2.0",
"@ngrx/store": "5.2.0",
"@ngrx/store-devtools": "5.2.0",
"@ngx-translate/core": "9.1.1",
"@swimlane/ngx-charts": "7.1.1",
"@swimlane/ngx-datatable": "11.2.0",
"@swimlane/ngx-dnd": "3.1.0",
"@types/prismjs": "1.9.0",
"angular-calendar": "0.25.2",
"angular-in-memory-web-api": "0.6.0",
"angular-calendar": "0.23.6",
"angular-in-memory-web-api": "0.5.3",
"chart.js": "2.7.2",
"classlist.js": "1.1.20150312",
"core-js": "2.5.7",
"d3": "5.5.0",
"core-js": "2.5.3",
"d3": "4.13.0",
"hammerjs": "2.0.8",
"lodash": "4.17.10",
"moment": "2.22.2",
"intl": "1.2.5",
"moment": "2.21.0",
"ng2-charts": "1.6.0",
"ngrx-store-freeze": "0.2.4",
"ngx-color-picker": "6.4.0",
"ngrx-store-freeze": "0.2.1",
"ngx-color-picker": "5.3.4",
"ngx-cookie-service": "1.0.10",
"perfect-scrollbar": "1.4.0",
"prismjs": "1.15.0",
"rxjs": "6.2.1",
"rxjs-compat": "6.2.1",
"perfect-scrollbar": "1.3.0",
"prismjs": "1.11.0",
"rxjs": "5.5.6",
"web-animations-js": "2.3.1",
"zone.js": "0.8.26"
"zone.js": "0.8.20"
},
"devDependencies": {
"@angular/cli": "6.0.8",
"@angular/compiler-cli": "6.0.7",
"@angular/language-service": "6.0.7",
"@angular-devkit/build-angular": "0.6.8",
"@angular/cli": "1.7.3",
"@angular/compiler-cli": "5.2.8",
"@angular/language-service": "5.2.8",
"@angularclass/hmr": "2.1.3",
"@types/jasmine": "2.8.8",
"@types/jasmine": "2.8.6",
"@types/jasminewd2": "2.0.3",
"@types/lodash": "4.14.110",
"@types/node": "8.9.5",
"@types/node": "6.0.101",
"codelyzer": "4.2.1",
"jasmine-core": "2.99.1",
"jasmine-core": "2.8.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "1.7.1",
"karma": "2.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-coverage-istanbul-reporter": "2.0.1",
"karma-jasmine": "1.1.2",
"karma-coverage-istanbul-reporter": "1.4.2",
"karma-jasmine": "1.1.1",
"karma-jasmine-html-reporter": "0.2.2",
"protractor": "5.3.2",
"ts-node": "5.0.1",
"protractor": "5.1.2",
"ts-node": "4.1.0",
"tslint": "5.9.1",
"typescript": "2.7.2",
"webpack-bundle-analyzer": "2.13.1"
"typescript": "2.6.2",
"webpack-bundle-analyzer": "2.11.1"
}
}

28
protractor.conf.js Normal file
View File

@@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@@ -187,14 +187,10 @@ export const fuseAnimations = [
transition('* => void', animate('300ms ease-in'))
]),
// -----------------------------------------------------------------------------------------------------
// @ Router animations
// -----------------------------------------------------------------------------------------------------
trigger('routerTransitionLeft', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -203,7 +199,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateX(100%)',
opacity : 0
@@ -211,7 +207,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateX(0)',
opacity : 1
@@ -222,7 +218,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateX(100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -231,8 +227,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -240,7 +236,7 @@ export const fuseAnimations = [
trigger('routerTransitionRight', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -249,7 +245,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateX(-100%)',
opacity : 0
@@ -257,7 +253,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateX(0)',
opacity : 1
@@ -268,7 +264,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateX(-100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -277,8 +273,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -286,7 +282,7 @@ export const fuseAnimations = [
trigger('routerTransitionUp', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -295,14 +291,14 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateY(100%)',
opacity : 0
})
], {optional: true}),
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateY(0)',
opacity : 1
@@ -313,7 +309,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateY(100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -322,15 +318,15 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
]),
trigger('routerTransitionDown', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -339,7 +335,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateY(-100%)',
opacity : 0
@@ -347,7 +343,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateY(0)',
opacity : 1
@@ -358,7 +354,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateY(-100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -367,8 +363,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -377,7 +373,7 @@ export const fuseAnimations = [
transition('* => *', group([
query('content > :enter, content > :leave ', [
query('fuse-content > :enter, fuse-content > :leave ', [
style({
position: 'absolute',
top : 0,
@@ -387,12 +383,12 @@ export const fuseAnimations = [
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
opacity: 0
})
], {optional: true}),
query('content > :leave', [
query('fuse-content > :leave', [
style({
opacity: 1
}),
@@ -401,7 +397,7 @@ export const fuseAnimations = [
opacity: 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
opacity: 0
}),
@@ -410,8 +406,8 @@ export const fuseAnimations = [
opacity: 1
}))
], {optional: true}),
query('content > :enter', animateChild(), {optional: true}),
query('content > :leave', animateChild(), {optional: true})
query('fuse-content > :enter', animateChild(), {optional: true}),
query('fuse-content > :leave', animateChild(), {optional: true})
]))
])
];

View File

@@ -10,14 +10,7 @@ export class FuseConfirmDialogComponent
{
public confirmMessage: string;
/**
* Constructor
*
* @param {MatDialogRef<FuseConfirmDialogComponent>} dialogRef
*/
constructor(
public dialogRef: MatDialogRef<FuseConfirmDialogComponent>
)
constructor(public dialogRef: MatDialogRef<FuseConfirmDialogComponent>)
{
}

View File

@@ -1,6 +1,7 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { interval, Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import * as moment from 'moment';
@Component({
@@ -8,82 +9,47 @@ import * as moment from 'moment';
templateUrl: './countdown.component.html',
styleUrls : ['./countdown.component.scss']
})
export class FuseCountdownComponent implements OnInit, OnDestroy
export class FuseCountdownComponent implements OnInit
{
// Event date
@Input('eventDate')
eventDate;
@Input('eventDate') eventDate;
countdown: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.countdown = {
days : '',
hours : '',
minutes: '',
seconds: ''
};
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
ngOnInit()
{
const currDate = moment();
const eventDate = moment(this.eventDate);
// Get the difference in between the current date and event date
let diff = eventDate.diff(currDate, 'seconds');
// Create a subscribable interval
const countDown = interval(1000)
.pipe(
map(value => {
return diff = diff - 1;
}),
map(value => {
const timeLeft = moment.duration(value, 'seconds');
const countDown =
Observable
.interval(1000)
.map(value => {
return diff = diff - 1;
})
.map(value => {
const timeLeft = moment.duration(value, 'seconds');
return {
days : timeLeft.asDays().toFixed(0),
hours : timeLeft.hours(),
minutes: timeLeft.minutes(),
seconds: timeLeft.seconds()
};
})
);
return {
days : timeLeft.asDays().toFixed(0),
hours : timeLeft.hours(),
minutes: timeLeft.minutes(),
seconds: timeLeft.seconds()
};
});
// Subscribe to the countdown interval
countDown
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(value => {
this.countdown = value;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
countDown.subscribe(value => {
this.countdown = value;
});
}
}

View File

@@ -7,9 +7,6 @@ import { Component } from '@angular/core';
})
export class FuseDemoContentComponent
{
/**
* Constructor
*/
constructor()
{
}

View File

@@ -1,16 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-demo-sidebar',
templateUrl: './demo-sidebar.component.html',
styleUrls : ['./demo-sidebar.component.scss']
})
export class FuseDemoSidebarComponent
{
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,99 +1,99 @@
<div class="demo-sidebar">
<div class="demo-sidenav">
<mat-list>
<h3 matSubheader>Sidebar Demo</h3>
<h3 matSubheader>Sidenav Demo</h3>
<mat-list-item>
<span>Sidebar Item 1</span>
<span>Sidenav Item 1</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 2</span>
<span>Sidenav Item 2</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 3</span>
<span>Sidenav Item 3</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 4</span>
<span>Sidenav Item 4</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 5</span>
<span>Sidenav Item 5</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 6</span>
<span>Sidenav Item 6</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 7</span>
<span>Sidenav Item 7</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 8</span>
<span>Sidenav Item 8</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 9</span>
<span>Sidenav Item 9</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 10</span>
<span>Sidenav Item 10</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 11</span>
<span>Sidenav Item 11</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 12</span>
<span>Sidenav Item 12</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 13</span>
<span>Sidenav Item 13</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 14</span>
<span>Sidenav Item 14</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 15</span>
<span>Sidenav Item 15</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item>
<span>Sidebar Item 16</span>
<span>Sidenav Item 16</span>
</mat-list-item>
</mat-list>

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
@Component({
selector : 'fuse-demo-sidenav',
templateUrl: './demo-sidenav.component.html',
styleUrls : ['./demo-sidenav.component.scss']
})
export class FuseDemoSidenavComponent
{
constructor()
{
}
}

View File

@@ -4,12 +4,12 @@ import { RouterModule } from '@angular/router';
import { MatDividerModule, MatListModule } from '@angular/material';
import { FuseDemoContentComponent } from './demo-content/demo-content.component';
import { FuseDemoSidebarComponent } from './demo-sidebar/demo-sidebar.component';
import { FuseDemoSidenavComponent } from './demo-sidenav/demo-sidenav.component';
@NgModule({
declarations: [
FuseDemoContentComponent,
FuseDemoSidebarComponent
FuseDemoSidenavComponent
],
imports : [
RouterModule,
@@ -19,7 +19,7 @@ import { FuseDemoSidebarComponent } from './demo-sidebar/demo-sidebar.component'
],
exports : [
FuseDemoContentComponent,
FuseDemoSidebarComponent
FuseDemoSidenavComponent
]
})
export class FuseDemoModule

View File

@@ -3,5 +3,4 @@
padding: 8px;
background: #263238;
cursor: text;
overflow: auto;
}

View File

@@ -1,55 +1,28 @@
import { Component, ContentChild, ElementRef, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, ContentChild, ElementRef, Input, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import * as Prism from 'prismjs/prism';
import '@fuse/components/highlight/prism-languages';
import './prism-languages';
@Component({
selector : 'fuse-highlight',
template : '',
template : ' ',
styleUrls: ['./highlight.component.scss']
})
export class FuseHighlightComponent implements OnInit, OnDestroy
export class FuseHighlightComponent implements OnInit
{
// Source
@ContentChild('source')
source: ElementRef;
@ContentChild('source') source: ElementRef;
@Input('lang') lang: string;
@Input('path') path: string;
// Lang
@Input('lang')
lang: string;
// Path
@Input('path')
path: string;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ElementRef} _elementRef
* @param {HttpClient} _httpClient
*/
constructor(
private _elementRef: ElementRef,
private _httpClient: HttpClient
private elementRef: ElementRef,
private http: HttpClient
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
ngOnInit()
{
// If there is no language defined, return...
if ( !this.lang )
@@ -61,13 +34,11 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
if ( this.path )
{
// Get the source
this._httpClient.get(this.path, {responseType: 'text'})
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((response) => {
this.http.get(this.path, {responseType: 'text'}).subscribe((response) => {
// Highlight it
this.highlight(response);
});
// Highlight it
this.highlight(response);
});
}
// If the path is not defined and the source element exists...
@@ -78,26 +49,7 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
}
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Highlight the given source code
*
* @param sourceCode
*/
highlight(sourceCode): void
highlight(sourceCode)
{
// Split the source into lines
const sourceLines = sourceCode.split('\n');
@@ -142,8 +94,9 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
const highlightedCode = Prism.highlight(source, Prism.languages[this.lang]);
// Replace the innerHTML of the component with the highlighted code
this._elementRef.nativeElement.innerHTML =
this.elementRef.nativeElement.innerHTML =
'<pre><code class="highlight language-' + this.lang + '">' + highlightedCode + '</code></pre>';
}
}

View File

@@ -1,12 +1,10 @@
import 'prismjs/prism';
import 'prismjs/components/prism-bash';
import 'prismjs/components/prism-c';
import 'prismjs/components/prism-cpp';
import 'prismjs/components/prism-csharp';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-diff';
import 'prismjs/components/prism-markup';
import 'prismjs/components/prism-markup-templating';
import 'prismjs/components/prism-java';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-json';

View File

@@ -13,78 +13,22 @@ import { MatColors } from '@fuse/mat-colors';
export class FuseMaterialColorPickerComponent implements OnChanges
{
colors: any;
hues: string[];
selectedColor: any;
view: string;
hues: string[];
view = 'palettes';
@Input()
selectedPalette: string;
@Input() selectedPalette = '';
@Input() selectedHue = '';
@Input() selectedFg = '';
@Input() value: any;
@Output() onValueChange = new EventEmitter();
@Output() selectedPaletteChange = new EventEmitter();
@Output() selectedHueChange = new EventEmitter();
@Output() selectedClassChange = new EventEmitter();
@Output() selectedBgChange = new EventEmitter();
@Output() selectedFgChange = new EventEmitter();
@Input()
selectedHue: string;
@Input()
selectedFg: string;
@Input()
value: any;
@Output()
onValueChange: EventEmitter<any>;
@Output()
selectedPaletteChange: EventEmitter<any>;
@Output()
selectedHueChange: EventEmitter<any>;
@Output()
selectedClassChange: EventEmitter<any>;
@Output()
selectedBgChange: EventEmitter<any>;
@Output()
selectedFgChange: EventEmitter<any>;
// Private
_selectedClass: string;
_selectedBg: string;
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.colors = MatColors.all;
this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700'];
this.selectedFg = '';
this.selectedHue = '';
this.selectedPalette = '';
this.view = 'palettes';
this.onValueChange = new EventEmitter();
this.selectedPaletteChange = new EventEmitter();
this.selectedHueChange = new EventEmitter();
this.selectedClassChange = new EventEmitter();
this.selectedBgChange = new EventEmitter();
this.selectedFgChange = new EventEmitter();
// Set the private defaults
this._selectedClass = '';
this._selectedBg = '';
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Selected class
*
* @param value
*/
_selectedClass = '';
@Input()
set selectedClass(value)
{
@@ -110,11 +54,7 @@ export class FuseMaterialColorPickerComponent implements OnChanges
return this._selectedClass;
}
/**
* Selected bg
*
* @param value
*/
_selectedBg = '';
@Input()
set selectedBg(value)
{
@@ -146,16 +86,13 @@ export class FuseMaterialColorPickerComponent implements OnChanges
return this._selectedBg;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
constructor()
{
this.colors = MatColors.all;
this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700'];
}
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: any): void
ngOnChanges(changes: any)
{
if ( changes.selectedBg && changes.selectedBg.currentValue === '' ||
changes.selectedClass && changes.selectedClass.currentValue === '' ||
@@ -169,38 +106,21 @@ export class FuseMaterialColorPickerComponent implements OnChanges
this.updateSelectedColor();
}
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Select palette
*
* @param palette
*/
selectPalette(palette): void
selectPalette(palette)
{
this.selectedPalette = palette;
this.updateSelectedColor();
this.view = 'hues';
}
/**
* Select hue
*
* @param hue
*/
selectHue(hue): void
selectHue(hue)
{
this.selectedHue = hue;
this.updateSelectedColor();
}
/**
* Remove color
*/
removeColor(): void
removeColor()
{
this.selectedPalette = '';
this.selectedHue = '';
@@ -208,10 +128,7 @@ export class FuseMaterialColorPickerComponent implements OnChanges
this.view = 'palettes';
}
/**
* Update selected color
*/
updateSelectedColor(): void
updateSelectedColor()
{
setTimeout(() => {
@@ -251,18 +168,12 @@ export class FuseMaterialColorPickerComponent implements OnChanges
});
}
/**
* Go back to palette selection
*/
backToPaletteSelection(): void
backToPaletteSelection()
{
this.view = 'palettes';
}
/**
* On menu open
*/
onMenuOpen(): void
onMenuOpen()
{
if ( this.selectedPalette === '' )
{

View File

@@ -1,6 +1,7 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material';
import { FusePipesModule } from '@fuse/pipes/pipes.module';

View File

@@ -1,69 +0,0 @@
<ng-container *ngIf="!item.hidden">
<!-- normal collapse -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && !item.function" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.url -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && !item.function"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && !item.function"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && item.function"
(click)="item.function()"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && item.function"
(click)="item.function()"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
<mat-icon class="collapsable-arrow">keyboard_arrow_right</mat-icon>
</ng-template>
<div class="children" [ngClass]="{'open': isOpen}">
<div class="{{fuseConfig.layout.navbar.background}}">
<ng-container *ngFor="let item of item.children">
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapsable *ngIf="item.type=='collapsable'"
[item]="item"></fuse-nav-horizontal-collapsable>
<fuse-nav-horizontal-collapsable *ngIf="item.type=='group'"
[item]="item"></fuse-nav-horizontal-collapsable>
</ng-container>
</div>
</div>
</ng-container>

View File

@@ -1,86 +0,0 @@
import { Component, HostBinding, HostListener, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations';
import { FuseConfigService } from '@fuse/services/config.service';
@Component({
selector : 'fuse-nav-horizontal-collapsable',
templateUrl: './collapsable.component.html',
styleUrls : ['./collapsable.component.scss'],
animations : fuseAnimations
})
export class FuseNavHorizontalCollapsableComponent implements OnInit, OnDestroy
{
fuseConfig: any;
isOpen = false;
@HostBinding('class')
classes = 'nav-collapsable nav-item';
@Input()
item: any;
// Private
private _unsubscribeAll: Subject<any>;
constructor(
private _fuseConfigService: FuseConfigService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to config changes
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(
(config) => {
this.fuseConfig = config;
}
);
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open
*/
@HostListener('mouseenter')
open(): void
{
this.isOpen = true;
}
/**
* Close
*/
@HostListener('mouseleave')
close(): void
{
this.isOpen = false;
}
}

View File

@@ -1,48 +0,0 @@
<ng-container *ngIf="!item.hidden">
<!-- item.url -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && !item.function"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && !item.function"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && item.function"
(click)="item.function()"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && item.function"
(click)="item.function()"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</ng-template>
</ng-container>

View File

@@ -1,23 +0,0 @@
import { Component, HostBinding, Input } from '@angular/core';
@Component({
selector : 'fuse-nav-horizontal-item',
templateUrl: './item.component.html',
styleUrls : ['./item.component.scss']
})
export class FuseNavHorizontalItemComponent
{
@HostBinding('class')
classes = 'nav-item';
@Input()
item: any;
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -0,0 +1,23 @@
<a class="nav-link" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
<mat-icon class="collapse-arrow">keyboard_arrow_right</mat-icon>
</a>
<div class="children" [ngClass]="{'open': isOpen}">
<div class="{{fuseSettings.colorClasses.navbar}}">
<ng-container *ngFor="let item of item.children">
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
</ng-container>
</div>
</div>

View File

@@ -0,0 +1,50 @@
import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core';
import { fuseAnimations } from '../../../../animations/index';
import { FuseConfigService } from '../../../../services/config.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector : 'fuse-nav-horizontal-collapse',
templateUrl: './nav-horizontal-collapse.component.html',
styleUrls : ['./nav-horizontal-collapse.component.scss'],
animations : fuseAnimations
})
export class FuseNavHorizontalCollapseComponent implements OnDestroy
{
onConfigChanged: Subscription;
fuseSettings: any;
isOpen = false;
@HostBinding('class') classes = 'nav-item nav-collapse';
@Input() item: any;
@HostListener('mouseenter')
open()
{
this.isOpen = true;
}
@HostListener('mouseleave')
close()
{
this.isOpen = false;
}
constructor(
private fuseConfig: FuseConfigService
)
{
this.onConfigChanged =
this.fuseConfig.onConfigChanged
.subscribe(
(newSettings) => {
this.fuseSettings = newSettings;
}
);
}
ngOnDestroy()
{
this.onConfigChanged.unsubscribe();
}
}

View File

@@ -0,0 +1,18 @@
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</a>
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</span>

View File

@@ -0,0 +1,12 @@
import { Component, HostBinding, Input } from '@angular/core';
@Component({
selector : 'fuse-nav-horizontal-item',
templateUrl: './nav-horizontal-item.component.html',
styleUrls : ['./nav-horizontal-item.component.scss']
})
export class FuseNavHorizontalItemComponent
{
@HostBinding('class') classes = 'nav-item';
@Input() item: any;
}

View File

@@ -1,4 +1,5 @@
<div class="nav" [ngClass]="{'horizontal':layout === 'horizontal', 'vertical':layout === 'vertical'}">
<div id="main-navigation" class="nav"
[ngClass]="{'horizontal':layout === 'horizontal', 'vertical':layout === 'vertical'}">
<!-- Vertical Navigation Layout -->
<ng-container *ngIf="layout === 'vertical'">
@@ -6,7 +7,7 @@
<ng-container *ngFor="let item of navigation">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapsable *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapsable>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container>
@@ -19,9 +20,8 @@
<ng-container *ngFor="let item of navigation">
<fuse-nav-horizontal-collapsable *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapsable>
<fuse-nav-horizontal-collapsable *ngIf="item.type=='collapse'"
[item]="item"></fuse-nav-horizontal-collapsable>
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
</ng-container>

View File

@@ -4,7 +4,7 @@ fuse-navigation {
display: flex;
flex: 1 0 auto;
> .nav {
#main-navigation {
margin: 0;
padding: 0;
width: 100%;

View File

@@ -1,8 +1,4 @@
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { Component, Input, ViewEncapsulation } from '@angular/core';
@Component({
selector : 'fuse-navigation',
@@ -10,45 +6,13 @@ import { FuseNavigationService } from '@fuse/components/navigation/navigation.se
styleUrls : ['./navigation.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseNavigationComponent implements OnInit
export class FuseNavigationComponent
{
@Input()
layout = 'vertical';
@Input() layout = 'vertical';
@Input() navigation: any;
@Input()
navigation: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
constructor(
private _fuseNavigationService: FuseNavigationService
)
constructor()
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Load the navigation either from the input or from the service
this.navigation = this.navigation || this._fuseNavigationService.getCurrentNavigation();
// Subscribe to the current navigation changes
this._fuseNavigationService.onNavigationChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
this.navigation = this._fuseNavigationService.getCurrentNavigation();
});
}
}

View File

@@ -6,11 +6,11 @@ import { MatIconModule, MatRippleModule } from '@angular/material';
import { TranslateModule } from '@ngx-translate/core';
import { FuseNavigationComponent } from './navigation.component';
import { FuseNavVerticalItemComponent } from './vertical/item/item.component';
import { FuseNavVerticalCollapsableComponent } from './vertical/collapsable/collapsable.component';
import { FuseNavVerticalGroupComponent } from './vertical/group/group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/item/item.component';
import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/collapsable.component';
import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component';
import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component';
import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component';
import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component';
@NgModule({
imports : [
@@ -29,9 +29,9 @@ import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/
FuseNavigationComponent,
FuseNavVerticalGroupComponent,
FuseNavVerticalItemComponent,
FuseNavVerticalCollapsableComponent,
FuseNavVerticalCollapseComponent,
FuseNavHorizontalItemComponent,
FuseNavHorizontalCollapsableComponent
FuseNavHorizontalCollapseComponent
]
})
export class FuseNavigationModule

View File

@@ -1,350 +1,48 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { EventEmitter, Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { FuseNavigationItem } from '@fuse/types';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseNavigationService
{
onItemCollapsed: Subject<any>;
onItemCollapseToggled: Subject<any>;
flatNavigation: any[] = [];
// Private
private _onNavigationChanged: BehaviorSubject<any>;
private _onNavigationRegistered: BehaviorSubject<any>;
private _onNavigationUnregistered: BehaviorSubject<any>;
onItemCollapsed: Subject<any> = new Subject;
onItemCollapseToggled: Subject<any> = new Subject;
private _currentNavigationKey: string;
private _registry: { [key: string]: any } = {};
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.onItemCollapsed = new Subject();
this.onItemCollapseToggled = new Subject();
// Set the private defaults
this._currentNavigationKey = null;
this._onNavigationChanged = new BehaviorSubject(null);
this._onNavigationRegistered = new BehaviorSubject(null);
this._onNavigationUnregistered = new BehaviorSubject(null);
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Get onNavigationChanged
*
* @returns {Observable<any>}
*/
get onNavigationChanged(): Observable<any>
{
return this._onNavigationChanged.asObservable();
}
/**
* Get onNavigationRegistered
*
* @returns {Observable<any>}
*/
get onNavigationRegistered(): Observable<any>
{
return this._onNavigationRegistered.asObservable();
}
/**
* Get onNavigationUnregistered
*
* @returns {Observable<any>}
*/
get onNavigationUnregistered(): Observable<any>
{
return this._onNavigationUnregistered.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register the given navigation
* with the given key
*
* @param key
* @param navigation
*/
register(key, navigation): void
{
// Check if the key already being used
if ( this._registry[key] )
{
console.error(`The navigation with the key '${key}' already exists. Either unregister it first or use a unique key.`);
return;
}
// Add to the registry
this._registry[key] = navigation;
// Notify the subject
this._onNavigationRegistered.next([key, navigation]);
}
/**
* Unregister the navigation from the registry
* @param key
*/
unregister(key): void
{
// Check if the navigation exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
}
// Unregister the sidebar
delete this._registry[key];
// Notify the subject
this._onNavigationUnregistered.next(key);
}
/**
* Get navigation from registry by key
*
* @param key
* @returns {any}
*/
getNavigation(key): any
{
// Check if the navigation exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
return;
}
// Return the sidebar
return this._registry[key];
}
/**
* Get flattened navigation array
*
* @param navigation
* @param flatNavigation
* @returns {any[]}
*/
getFlatNavigation(navigation, flatNavigation: FuseNavigationItem[] = []): any
getFlatNavigation(navigation)
{
for ( const item of navigation )
for ( const navItem of navigation )
{
if ( item.type === 'item' )
if ( navItem.type === 'item' )
{
flatNavigation.push(item);
this.flatNavigation.push({
title: navItem.title,
type : navItem.type,
icon : navItem.icon || false,
url : navItem.url
});
continue;
}
if ( item.type === 'collapsable' || item.type === 'group' )
if ( navItem.type === 'collapse' || navItem.type === 'group' )
{
if ( item.children )
if ( navItem.children )
{
this.getFlatNavigation(item.children, flatNavigation);
this.getFlatNavigation(navItem.children);
}
}
}
return flatNavigation;
}
/**
* Get the current navigation
*
* @returns {any}
*/
getCurrentNavigation(): any
{
if ( !this._currentNavigationKey )
{
console.warn(`The current navigation is not set.`);
return;
}
return this.getNavigation(this._currentNavigationKey);
}
/**
* Set the navigation with the key
* as the current navigation
*
* @param key
*/
setCurrentNavigation(key): void
{
// Check if the sidebar exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
return;
}
// Set the current navigation key
this._currentNavigationKey = key;
// Notify the subject
this._onNavigationChanged.next(key);
}
/**
* Get navigation item by id from the
* current navigation
*
* @param id
* @param {any} navigation
* @returns {any | boolean}
*/
getNavigationItem(id, navigation = null): any | boolean
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
}
for ( const item of navigation )
{
if ( item.id === id )
{
return item;
}
if ( item.children )
{
const childItem = this.getNavigationItem(id, item.children);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Get the parent of the navigation item
* with the id
*
* @param id
* @param {any} navigation
* @param parent
*/
getNavigationItemParent(id, navigation = null, parent = null): any
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
parent = navigation;
}
for ( const item of navigation )
{
if ( item.id === id )
{
return parent;
}
if ( item.children )
{
const childItem = this.getNavigationItemParent(id, item.children, item);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Add a navigation item to the specified location
*
* @param item
* @param id
*/
addNavigationItem(item, id): void
{
// Get the current navigation
const navigation: any[] = this.getCurrentNavigation();
// Add to the end of the navigation
if ( id === 'end' )
{
navigation.push(item);
return;
}
// Add to the start of the navigation
if ( id === 'start' )
{
navigation.unshift(item);
}
// Add it to a specific location
const parent: any = this.getNavigationItem(id);
if ( parent )
{
// Check if parent has a children entry,
// and add it if it doesn't
if ( !parent.children )
{
parent.children = [];
}
// Add the item
parent.children.push(item);
}
}
/**
* Remove navigation item with the given id
*
* @param id
*/
removeNavigationItem(id): void
{
const item = this.getNavigationItem(id);
// Return, if there is not such an item
if ( !item )
{
return;
}
// Get the parent of the item
let parent = this.getNavigationItemParent(id);
// This check is required because of the first level
// of the navigation, since the first level is not
// inside the 'children' array
parent = parent.children || parent;
// Remove the item
parent.splice(parent.indexOf(item), 1);
return this.flatNavigation;
}
}

View File

@@ -1,65 +0,0 @@
<ng-container *ngIf="!item.hidden">
<!-- normal collapse -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && !item.function"
(click)="toggleOpen($event)" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.url -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && !item.function"
(click)="toggleOpen($event)"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && !item.function"
(click)="toggleOpen($event)"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="toggleOpen($event);item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && item.function"
(click)="toggleOpen($event);item.function()"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && item.function"
(click)="toggleOpen($event);item.function()"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
<mat-icon class="collapsable-arrow">keyboard_arrow_right</mat-icon>
</ng-template>
<div class="children" [@slideInOut]="isOpen">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapsable *ngIf="item.type=='collapsable'"
[item]="item"></fuse-nav-vertical-collapsable>
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
</ng-container>
</div>
</ng-container>

View File

@@ -1,25 +0,0 @@
import { Component, HostBinding, Input } from '@angular/core';
import { FuseNavigationItem } from '@fuse/types';
@Component({
selector : 'fuse-nav-vertical-group',
templateUrl: './group.component.html',
styleUrls : ['./group.component.scss']
})
export class FuseNavVerticalGroupComponent
{
@HostBinding('class')
classes = 'nav-group nav-item';
@Input()
item: FuseNavigationItem;
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -1,48 +0,0 @@
<ng-container *ngIf="!item.hidden">
<!-- item.url -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && !item.function"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && !item.function"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && !item.externalUrl && item.function"
(click)="item.function()"
[routerLink]="[item.url]" [routerLinkActive]="['active', 'mat-accent-bg']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.externalUrl && item.function -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="item.url && item.externalUrl && item.function"
(click)="item.function()"
[href]="item.url" [target]="item.openInNewTab ? '_blank' : '_self'" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</ng-template>
</ng-container>

View File

@@ -1,24 +0,0 @@
import { Component, HostBinding, Input } from '@angular/core';
import { FuseNavigationItem } from '@fuse/types';
@Component({
selector : 'fuse-nav-vertical-item',
templateUrl: './item.component.html',
styleUrls : ['./item.component.scss']
})
export class FuseNavVerticalItemComponent
{
@HostBinding('class')
classes = 'nav-item';
@Input()
item: FuseNavigationItem;
/**
* Constructor
*/
constructor()
{
}
}

View File

@@ -0,0 +1,21 @@
<ng-container *ngIf="!item.hidden">
<a class="nav-link" matRipple (click)="toggleOpen($event)">
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
<mat-icon class="collapse-arrow">keyboard_arrow_right</mat-icon>
</a>
<div class="children" [@slideInOut]="isOpen">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
</ng-container>
</div>
</ng-container>

View File

@@ -20,7 +20,7 @@
.nav-link {
.collapsable-arrow {
.collapse-arrow {
transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s;
transform: rotate(0);
}
@@ -34,9 +34,13 @@
> .nav-link {
.collapsable-arrow {
.collapse-arrow {
transform: rotate(90deg);
}
}
> .children {
}
}
}

View File

@@ -1,79 +1,46 @@
import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, HostBinding, Input, OnInit } from '@angular/core';
import { FuseNavigationService } from '../../navigation.service';
import { NavigationEnd, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { FuseNavigationItem } from '@fuse/types';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { fuseAnimations } from '../../../../animations/index';
@Component({
selector : 'fuse-nav-vertical-collapsable',
templateUrl: './collapsable.component.html',
styleUrls : ['./collapsable.component.scss'],
selector : 'fuse-nav-vertical-collapse',
templateUrl: './nav-vertical-collapse.component.html',
styleUrls : ['./nav-vertical-collapse.component.scss'],
animations : fuseAnimations
})
export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
export class FuseNavVerticalCollapseComponent implements OnInit
{
@Input()
item: FuseNavigationItem;
@Input() item: any;
@HostBinding('class') classes = 'nav-collapse nav-item';
@HostBinding('class.open') public isOpen = false;
@HostBinding('class')
classes = 'nav-collapsable nav-item';
@HostBinding('class.open')
public isOpen = false;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FuseNavigationService} _fuseNavigationService
* @param {Router} _router
*/
constructor(
private _fuseNavigationService: FuseNavigationService,
private _router: Router
private navigationService: FuseNavigationService,
private router: Router
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Listen for router events
this._router.events
.pipe(
filter(event => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll)
)
.subscribe((event: NavigationEnd) => {
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) )
// Listen for route changes
router.events.subscribe(
(event) => {
if ( event instanceof NavigationEnd )
{
this.expand();
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) )
{
this.expand();
}
else
{
this.collapse();
}
}
else
{
this.collapse();
}
});
}
);
// Listen for collapsing of any navigation item
this._fuseNavigationService.onItemCollapsed
.pipe(takeUntil(this._unsubscribeAll))
this.navigationService.onItemCollapsed
.subscribe(
(clickedItem) => {
if ( clickedItem && clickedItem.children )
@@ -87,7 +54,7 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this._router.url) )
if ( this.isUrlInChildren(this.item, this.router.url) )
{
return;
}
@@ -100,10 +67,13 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
}
}
);
}
ngOnInit()
{
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this._router.url) )
if ( this.isUrlInChildren(this.item, this.router.url) )
{
this.expand();
}
@@ -113,40 +83,26 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
}
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle collapse
*
* @param ev
*/
toggleOpen(ev): void
toggleOpen(ev)
{
ev.preventDefault();
this.isOpen = !this.isOpen;
// Navigation collapse toggled...
this._fuseNavigationService.onItemCollapsed.next(this.item);
this._fuseNavigationService.onItemCollapseToggled.next();
this.navigationService.onItemCollapsed.next(this.item);
this.navigationService.onItemCollapseToggled.next();
}
/**
* Expand the collapsable navigation
*/
expand(): void
expand()
{
if ( this.isOpen )
{
@@ -154,13 +110,13 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
}
this.isOpen = true;
this._fuseNavigationService.onItemCollapseToggled.next();
this.navigationService.onItemCollapseToggled.next();
}
/**
* Collapse the collapsable navigation
*/
collapse(): void
collapse()
{
if ( !this.isOpen )
{
@@ -168,7 +124,7 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
}
this.isOpen = false;
this._fuseNavigationService.onItemCollapseToggled.next();
this.navigationService.onItemCollapseToggled.next();
}
/**
@@ -177,9 +133,9 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
*
* @param parent
* @param item
* @returns {boolean}
* @return {any}
*/
isChildrenOf(parent, item): boolean
isChildrenOf(parent, item)
{
if ( !parent.children )
{
@@ -206,9 +162,9 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
*
* @param parent
* @param url
* @returns {boolean}
* @returns {any}
*/
isUrlInChildren(parent, url): boolean
isUrlInChildren(parent, url)
{
if ( !parent.children )
{

View File

@@ -1,14 +1,13 @@
<ng-container *ngIf="!item.hidden">
<div class="group-title" [ngClass]="item.classes">
<div class="group-title">
<span class="hint-text" [translate]="item.translate">{{ item.title }}</span>
</div>
<div class="group-items">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapsable *ngIf="item.type=='collapsable'"
[item]="item"></fuse-nav-vertical-collapsable>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container>
</div>

View File

@@ -0,0 +1,17 @@
import { Component, HostBinding, Input } from '@angular/core';
@Component({
selector : 'fuse-nav-vertical-group',
templateUrl: './nav-vertical-group.component.html',
styleUrls : ['./nav-vertical-group.component.scss']
})
export class FuseNavVerticalGroupComponent
{
@HostBinding('class') classes = 'nav-group nav-item';
@Input() item: any;
constructor()
{
}
}

View File

@@ -0,0 +1,22 @@
<ng-container *ngIf="!item.hidden">
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</a>
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</span>
</ng-container>

View File

@@ -0,0 +1,16 @@
import { Component, HostBinding, Input } from '@angular/core';
@Component({
selector : 'fuse-nav-vertical-item',
templateUrl: './nav-vertical-item.component.html',
styleUrls : ['./nav-vertical-item.component.scss']
})
export class FuseNavVerticalItemComponent
{
@HostBinding('class') classes = 'nav-item';
@Input() item: any;
constructor()
{
}
}

View File

@@ -1,25 +1,21 @@
<div class="fuse-search-bar" [ngClass]="{'expanded':!collapsed}">
<div class="fuse-search-bar-content" [ngClass]="fuseConfig.layout.toolbar.background">
<div class="fuse-search-bar" [ngClass]="{'expanded':!collapsed}" fxFlex="0 1 auto">
<div [ngClass]="toolbarColor" fxLayout="row" fxLayoutAlign="start center" fxFlex>
<label for="fuse-search-bar-input">
<button mat-icon-button class="fuse-search-bar-expander" aria-label="Expand Search Bar" (click)="expand()"
*ngIf="collapsed">
<mat-icon class="s-24 secondary-text">search</mat-icon>
<mat-icon class="s-24">search</mat-icon>
</button>
<!--<span class="fuse-search-bar-loader" fxLayout="row" fxLayoutAlign="center center" *ngIf="!collapsed">
<mat-progress-spinner color="mat-accent" mode="indeterminate"></mat-progress-spinner>
</span>-->
</label>
<input id="fuse-search-bar-input" class="ml-24" type="text" placeholder="Search" (input)="search($event)"
fxFlex>
<input id="fuse-search-bar-input" class="ml-24" type="text" placeholder="Search" (input)="search($event)" fxFlex>
<button mat-icon-button class="fuse-search-bar-collapser" (click)="collapse()"
<button mat-icon-button class="fuse-search-bar-collapser mat-icon-button" (click)="collapse()"
aria-label="Collapse Search Bar">
<mat-icon class="s-24 secondary-text">close</mat-icon>
<mat-icon class="s-24">close</mat-icon>
</button>
</div>
</div>

View File

@@ -3,59 +3,48 @@
:host {
.fuse-search-bar {
display: flex;
flex: 0 1 auto;
min-width: 64px;
height: 64px;
font-size: 13px;
@include media-breakpoint-down('xs') {
@include media-breakpoint-down('sm') {
height: 56px;
}
.fuse-search-bar-content {
display: flex;
flex: 1 1 auto;
align-items: center;
justify-content: flex-start;
.fuse-search-bar-expander,
.fuse-search-bar-collapser {
cursor: pointer;
padding: 0 20px;
margin: 0;
width: 64px !important;
height: 64px !important;
line-height: 64px !important;
.fuse-search-bar-expander,
.fuse-search-bar-collapser {
cursor: pointer;
padding: 0 20px;
margin: 0;
width: 64px !important;
height: 64px !important;
line-height: 64px !important;
@include media-breakpoint-down('xs') {
height: 56px !important;
line-height: 56px !important;
}
@include media-breakpoint-down('sm') {
height: 56px !important;
line-height: 56px !important;
}
}
.fuse-search-bar-loader {
width: 64px !important;
height: 64px !important;
line-height: 64px !important;
@include media-breakpoint-down('xs') {
height: 56px !important;
line-height: 56px !important;
}
.fuse-search-bar-loader {
width: 64px !important;
height: 64px !important;
line-height: 64px !important;
@include media-breakpoint-down('sm') {
height: 56px !important;
line-height: 56px !important;
}
}
.fuse-search-bar-collapser {
display: none;
}
.fuse-search-bar-collapser {
display: none;
}
#fuse-search-bar-input {
display: none;
flex: 1 0 auto;
min-height: 64px;
background-color: transparent;
font-size: 16px;
}
#fuse-search-bar-input {
display: none;
min-height: 64px;
background-color: transparent;
font-size: 16px;
}
&.expanded {
@@ -66,15 +55,12 @@
left: 0;
z-index: 10;
.fuse-search-bar-content {
#fuse-search-bar-input {
display: block;
}
#fuse-search-bar-input {
display: flex;
}
.fuse-search-bar-collapser {
display: flex;
}
.fuse-search-bar-collapser {
display: block;
}
}
}

View File

@@ -1,6 +1,5 @@
import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Component, EventEmitter, Output } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { FuseConfigService } from '@fuse/services/config.service';
@@ -9,91 +8,42 @@ import { FuseConfigService } from '@fuse/services/config.service';
templateUrl: './search-bar.component.html',
styleUrls : ['./search-bar.component.scss']
})
export class FuseSearchBarComponent implements OnInit, OnDestroy
export class FuseSearchBarComponent
{
collapsed: boolean;
fuseConfig: any;
toolbarColor: string;
@Output() onInput: EventEmitter<any> = new EventEmitter();
onConfigChanged: Subscription;
@Output()
input: EventEmitter<any>;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FuseConfigService} _fuseConfigService
*/
constructor(
private _fuseConfigService: FuseConfigService
private fuseConfig: FuseConfigService
)
{
// Set the defaults
this.input = new EventEmitter();
this.collapsed = true;
// Set the private defaults
this._unsubscribeAll = new Subject();
this.onConfigChanged =
this.fuseConfig.onConfigChanged
.subscribe(
(newSettings) => {
this.toolbarColor = newSettings.colorClasses.toolbar;
}
);
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to config changes
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(
(config) => {
this.fuseConfig = config;
}
);
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Collapse
*/
collapse(): void
collapse()
{
this.collapsed = true;
}
/**
* Expand
*/
expand(): void
expand()
{
this.collapsed = false;
}
/**
* Search
*
* @param event
*/
search(event): void
search(event)
{
this.input.emit(event.target.value);
const value = event.target.value;
this.onInput.emit(value);
}
}

View File

@@ -7,7 +7,7 @@
</button>
</div>
<div class="shortcuts" fxHide fxShow.gt-sm>
<div class="shortcuts" fxHide fxShow.gt-sm [ngClass]="toolbarColor">
<div fxLayout="row" fxLayoutAlign="space-between center" fxFlex="0 1 auto">
@@ -17,7 +17,7 @@
*ngFor="let shortcutItem of shortcutItems">
<a mat-icon-button matTooltip="{{shortcutItem.title}}" [routerLink]="shortcutItem.url">
<mat-icon class="secondary-text" *ngIf="shortcutItem.icon">{{shortcutItem.icon}}</mat-icon>
<mat-icon *ngIf="shortcutItem.icon">{{shortcutItem.icon}}</mat-icon>
<span *ngIf="!shortcutItem.icon" class="h2 secondary-text text-bold">
{{shortcutItem.title.substr(0, 1).toUpperCase()}}
</span>
@@ -42,70 +42,46 @@
<mat-menu #addMenu="matMenu" class="w-240">
<mat-form-field class="px-16 w-100-p" (click)="$event.stopPropagation()" floatLabel="never">
<mat-form-field class="px-16 w-100-p" (click)="$event.stopPropagation()" floatPlaceholder="never">
<input #searchInput matInput placeholder="Search for an app or a page" (input)="search($event)">
</mat-form-field>
<mat-divider></mat-divider>
<mat-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<mat-list-item *ngFor="let shortcutItem of shortcutItems"
(click)="toggleShortcut($event, shortcutItem)">
<div class="w-100-p" fxLayout="row" fxLayoutAlign="start center">
<mat-icon mat-list-icon class="mr-8 secondary-text" *ngIf="shortcutItem.icon">
{{shortcutItem.icon}}
</mat-icon>
<mat-icon mat-list-icon class="mr-8" *ngIf="shortcutItem.icon">{{shortcutItem.icon}}</mat-icon>
<span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row"
fxLayoutAlign="center center" *ngIf="!shortcutItem.icon">
{{shortcutItem.title.substr(0, 1).toUpperCase()}}
</span>
<p matLine fxFlex>{{shortcutItem.title}}</p>
<mat-icon class="ml-8 amber-fg">star</mat-icon>
<mat-icon class="ml-8">star</mat-icon>
</div>
</mat-list-item>
<mat-list-item *ngIf="shortcutItems.length === 0">
<p>
<small>No shortcuts yet!</small>
</p>
</mat-list-item>
</mat-nav-list>
<mat-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<mat-list-item *ngFor="let navigationItem of filteredNavigationItems"
(click)="toggleShortcut($event, navigationItem)">
<div class="w-100-p" fxLayout="row" fxLayoutAlign="start center">
<mat-icon mat-list-icon class="mr-8 secondary-text" *ngIf="navigationItem.icon">
{{navigationItem.icon}}
</mat-icon>
<mat-icon mat-list-icon class="mr-8" *ngIf="navigationItem.icon">{{navigationItem.icon}}</mat-icon>
<span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row"
fxLayoutAlign="center center" *ngIf="!navigationItem.icon">
{{navigationItem.title.substr(0, 1).toUpperCase()}}
</span>
<p matLine fxFlex>{{navigationItem.title}}</p>
<mat-icon class="ml-8 amber-fg" *ngIf="isInShortcuts(navigationItem)">star</mat-icon>
<mat-icon class="ml-8" *ngIf="isInShortcuts(navigationItem)">star</mat-icon>
</div>
</mat-list-item>
</mat-nav-list>
</mat-menu>
</div>

View File

@@ -1,11 +1,13 @@
import { Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { ObservableMedia } from '@angular/flex-layout';
import { CookieService } from 'ngx-cookie-service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseConfigService } from '@fuse/services/config.service';
import { navigation } from 'app/navigation/navigation';
@Component({
selector : 'fuse-shortcuts',
@@ -14,67 +16,45 @@ import { FuseNavigationService } from '@fuse/components/navigation/navigation.se
})
export class FuseShortcutsComponent implements OnInit, OnDestroy
{
shortcutItems: any[];
shortcutItems: any[] = [];
navigationItems: any[];
filteredNavigationItems: any[];
searching: boolean;
mobileShortcutsPanelActive: boolean;
searching = false;
mobileShortcutsPanelActive = false;
toolbarColor: string;
matchMediaSubscription: Subscription;
onConfigChanged: Subscription;
@Input()
navigation: any;
@ViewChild('searchInput') searchInputField;
@ViewChild('shortcuts') shortcutsEl: ElementRef;
@ViewChild('searchInput')
searchInputField;
@ViewChild('shortcuts')
shortcutsEl: ElementRef;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {Renderer2} _renderer
* @param {CookieService} _cookieService
* @param {FuseMatchMediaService} _fuseMatchMediaService
* @param {FuseNavigationService} _fuseNavigationService
* @param {ObservableMedia} _observableMedia
*/
constructor(
private _cookieService: CookieService,
private _fuseMatchMediaService: FuseMatchMediaService,
private _fuseNavigationService: FuseNavigationService,
private _observableMedia: ObservableMedia,
private _renderer: Renderer2
private renderer: Renderer2,
private observableMedia: ObservableMedia,
private fuseMatchMedia: FuseMatchMediaService,
private fuseNavigationService: FuseNavigationService,
private fuseConfig: FuseConfigService,
private cookieService: CookieService
)
{
// Set the defaults
this.shortcutItems = [];
this.searching = false;
this.mobileShortcutsPanelActive = false;
this.filteredNavigationItems = this.navigationItems = this.fuseNavigationService.getFlatNavigation(navigation);
// Set the private defaults
this._unsubscribeAll = new Subject();
this.onConfigChanged =
this.fuseConfig.onConfigChanged
.subscribe(
(newSettings) => {
this.toolbarColor = newSettings.colorClasses.toolbar;
}
);
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
ngOnInit()
{
// Get the navigation items and flatten them
this.filteredNavigationItems = this.navigationItems = this._fuseNavigationService.getFlatNavigation(this.navigation);
const cookieExists = this._cookieService.check('FUSE2.shortcuts');
const cookieExists = this.cookieService.check('FUSE2.shortcuts');
if ( cookieExists )
{
this.shortcutItems = JSON.parse(this._cookieService.get('FUSE2.shortcuts'));
this.shortcutItems = JSON.parse(this.cookieService.get('FUSE2.shortcuts'));
}
else
{
@@ -82,61 +62,46 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems = [
{
'title': 'Calendar',
'type' : 'item',
'type' : 'nav-item',
'icon' : 'today',
'url' : '/apps/calendar'
},
{
'title': 'Mail',
'type' : 'item',
'type' : 'nav-item',
'icon' : 'email',
'url' : '/apps/mail'
},
{
'title': 'Contacts',
'type' : 'item',
'type' : 'nav-item',
'icon' : 'account_box',
'url' : '/apps/contacts'
},
{
'title': 'To-Do',
'type' : 'item',
'type' : 'nav-item',
'icon' : 'check_box',
'url' : '/apps/todo'
}
];
}
this._fuseMatchMediaService.onMediaChange
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
if ( this._observableMedia.isActive('gt-sm') )
this.matchMediaSubscription =
this.fuseMatchMedia.onMediaChange.subscribe(() => {
if ( this.observableMedia.isActive('gt-sm') )
{
this.hideMobileShortcutsPanel();
}
});
}
/**
* On destroy
*/
ngOnDestroy(): void
ngOnDestroy()
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
this.matchMediaSubscription.unsubscribe();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Search
*
* @param event
*/
search(event): void
search(event)
{
const value = event.target.value.toLowerCase();
@@ -155,13 +120,7 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
});
}
/**
* Toggle shortcut
*
* @param event
* @param itemToToggle
*/
toggleShortcut(event, itemToToggle): void
toggleShortcut(event, itemToToggle)
{
event.stopPropagation();
@@ -172,7 +131,7 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems.splice(i, 1);
// Save to the cookies
this._cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
return;
}
@@ -181,47 +140,32 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems.push(itemToToggle);
// Save to the cookies
this._cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
}
/**
* Is in shortcuts?
*
* @param navigationItem
* @returns {any}
*/
isInShortcuts(navigationItem): any
isInShortcuts(navigationItem)
{
return this.shortcutItems.find(item => {
return item.url === navigationItem.url;
});
}
/**
* On menu open
*/
onMenuOpen(): void
onMenuOpen()
{
setTimeout(() => {
this.searchInputField.nativeElement.focus();
});
}
/**
* Show mobile shortcuts
*/
showMobileShortcutsPanel(): void
showMobileShortcutsPanel()
{
this.mobileShortcutsPanelActive = true;
this._renderer.addClass(this.shortcutsEl.nativeElement, 'show-mobile-panel');
this.renderer.addClass(this.shortcutsEl.nativeElement, 'show-mobile-panel');
}
/**
* Hide mobile shortcuts
*/
hideMobileShortcutsPanel(): void
hideMobileShortcutsPanel()
{
this.mobileShortcutsPanelActive = false;
this._renderer.removeClass(this.shortcutsEl.nativeElement, 'show-mobile-panel');
this.renderer.removeClass(this.shortcutsEl.nativeElement, 'show-mobile-panel');
}
}

View File

@@ -1,5 +1,3 @@
@import "src/@fuse/scss/fuse";
fuse-sidebar {
display: flex;
flex-direction: column;
@@ -7,27 +5,22 @@ fuse-sidebar {
position: absolute;
top: 0;
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
overflow: hidden;
width: 280px;
min-width: 280px;
max-width: 280px;
z-index: 1000;
transition-property: transform, width, min-width, max-width;
transition-duration: 150ms;
transition-timing-function: ease-in-out;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35);
background: white;
@include media-breakpoint-down('xs') {
min-width: 0 !important;
max-width: 80vw !important;
width: 80vw !important;
}
&.left-positioned {
&.left-aligned {
left: 0;
transform: translateX(-100%);
}
&.right-positioned {
&.right-aligned {
right: 0;
transform: translateX(100%);
}
@@ -45,12 +38,12 @@ fuse-sidebar {
position: absolute !important;
top: 0;
bottom: 0;
}
&.animations-enabled {
transition-property: transform, width, min-width, max-width;
transition-duration: 150ms;
transition-timing-function: ease-in-out;
&:not(.unfolded) {
width: 64px;
min-width: 64px;
max-width: 64px;
}
}
}
@@ -60,11 +53,7 @@ fuse-sidebar {
bottom: 0;
left: 0;
right: 0;
z-index: 999;
z-index: 3;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
&.fuse-sidebar-overlay-invisible {
background-color: transparent;
}
}

View File

@@ -1,12 +1,11 @@
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, OnInit, Output, Renderer2, RendererStyleFlags2, ViewEncapsulation } from '@angular/core';
import { Component, ElementRef, HostBinding, HostListener, Inject, Input, OnDestroy, OnInit, Renderer2, ViewEncapsulation } from '@angular/core';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { ObservableMedia } from '@angular/flex-layout';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Subscription } from 'rxjs/Subscription';
import { FuseSidebarService } from './sidebar.service';
import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseConfigService } from '@fuse/services/config.service';
import { DOCUMENT } from '@angular/common';
@Component({
selector : 'fuse-sidebar',
@@ -20,13 +19,9 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@Input()
name: string;
// Key
// Align
@Input()
key: string;
// Position
@Input()
position: 'left' | 'right';
align: string;
// Open
@HostBinding('class.open')
@@ -40,196 +35,79 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostBinding('class.locked-open')
isLockedOpen: boolean;
// Folded width
// Folded
@HostBinding('class.folded')
@Input()
foldedWidth: number;
set folded(value)
{
this._folded = value;
// Folded auto trigger on hover
@Input()
foldedAutoTriggerOnHover: boolean;
if ( value )
{
this.fold();
}
else
{
this.unfold();
}
}
get folded()
{
return this._folded;
}
// Folded unfolded
@HostBinding('class.unfolded')
unfolded: boolean;
// Invisible overlay
@Input()
invisibleOverlay: boolean;
// Folded changed
@Output()
foldedChanged: EventEmitter<boolean>;
// Opened changed
@Output()
openedChanged: EventEmitter<boolean>;
// Private
private _folded: boolean;
private _fuseConfig: any;
private _folded = false;
private _wasActive: boolean;
private _wasFolded: boolean;
private _backdrop: HTMLElement | null = null;
private _player: AnimationPlayer;
private _unsubscribeAll: Subject<any>;
@HostBinding('class.animations-enabled')
private _animationsEnabled: boolean;
private _matchMediaWatcher: Subscription;
/**
* Constructor
*
* @param {AnimationBuilder} _animationBuilder
* @param {ChangeDetectorRef} _changeDetectorRef
* @param {ElementRef} _elementRef
* @param {FuseConfigService} _fuseConfigService
* @param {FuseMatchMediaService} _fuseMatchMediaService
* @param {FuseSidebarService} _fuseSidebarService
* @param {ObservableMedia} _observableMedia
* @param {Renderer2} _renderer
* @param renderer
* @param elementRef
* @param animationBuilder
* @param sidebarService
* @param matchMedia
* @param media
* @param document
*/
constructor(
private _animationBuilder: AnimationBuilder,
private _changeDetectorRef: ChangeDetectorRef,
private _elementRef: ElementRef,
private _fuseConfigService: FuseConfigService,
private _fuseMatchMediaService: FuseMatchMediaService,
private _fuseSidebarService: FuseSidebarService,
private _observableMedia: ObservableMedia,
private _renderer: Renderer2
private renderer: Renderer2,
private elementRef: ElementRef,
private animationBuilder: AnimationBuilder,
private sidebarService: FuseSidebarService,
private matchMedia: FuseMatchMediaService,
private media: ObservableMedia,
@Inject(DOCUMENT) private document: any
)
{
// Set the defaults
this.foldedAutoTriggerOnHover = true;
this.foldedWidth = 64;
this.foldedChanged = new EventEmitter();
this.openedChanged = new EventEmitter();
this.opened = false;
this.position = 'left';
this.invisibleOverlay = false;
// Set the private defaults
this._animationsEnabled = false;
this._folded = false;
this._unsubscribeAll = new Subject();
this.folded = false;
this.align = 'left';
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Folded
*
* @param {boolean} value
*/
@Input()
set folded(value: boolean)
{
// Set the folded
this._folded = value;
// Return if the sidebar is closed
if ( !this.opened )
{
return;
}
// Programmatically add/remove padding to the element
// that comes after or before based on the position
let sibling,
styleRule;
const styleValue = this.foldedWidth + 'px';
// Get the sibling and set the style rule
if ( this.position === 'left' )
{
sibling = this._elementRef.nativeElement.nextElementSibling;
styleRule = 'padding-left';
}
else
{
sibling = this._elementRef.nativeElement.previousElementSibling;
styleRule = 'padding-right';
}
// If there is no sibling, return...
if ( !sibling )
{
return;
}
// If folded...
if ( value )
{
// Fold the sidebar
this.fold();
// Set the folded width
this._renderer.setStyle(this._elementRef.nativeElement, 'width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'min-width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'max-width', styleValue);
// Set the style and class
this._renderer.setStyle(sibling, styleRule, styleValue, RendererStyleFlags2.Important + RendererStyleFlags2.DashCase);
this._renderer.addClass(this._elementRef.nativeElement, 'folded');
}
// If unfolded...
else
{
// Unfold the sidebar
this.unfold();
// Remove the folded width
this._renderer.removeStyle(this._elementRef.nativeElement, 'width');
this._renderer.removeStyle(this._elementRef.nativeElement, 'min-width');
this._renderer.removeStyle(this._elementRef.nativeElement, 'max-width');
// Remove the style and class
this._renderer.removeStyle(sibling, styleRule);
this._renderer.removeClass(this._elementRef.nativeElement, 'folded');
}
// Emit the 'foldedChanged' event
this.foldedChanged.emit(this.folded);
}
get folded(): boolean
{
return this._folded;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to config changes
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._fuseConfig = config;
});
// Register the sidebar
this._fuseSidebarService.register(this.name, this);
this.sidebarService.register(this.name, this);
// Setup visibility
this._setupVisibility();
// Setup position
this._setupPosition();
// Setup alignment
this._setupAlignment();
// Setup lockedOpen
this._setupLockedOpen();
// Setup folded
this._setupFolded();
}
/**
@@ -237,54 +115,27 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
*/
ngOnDestroy(): void
{
// If the sidebar is folded, unfold it to revert modifications
if ( this.folded )
{
this.unfold();
}
// Unregister the sidebar
this._fuseSidebarService.unregister(this.name);
this.sidebarService.unregister(this.name);
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Setup the visibility of the sidebar
*
* @private
*/
private _setupVisibility(): void
{
// Remove the existing box-shadow
this._renderer.setStyle(this._elementRef.nativeElement, 'box-shadow', 'none');
// Make the sidebar invisible
this._renderer.setStyle(this._elementRef.nativeElement, 'visibility', 'hidden');
// Unregister the media watcher
this._matchMediaWatcher.unsubscribe();
}
/**
* Setup the sidebar position
* Setup the alignment
*
* @private
*/
private _setupPosition(): void
private _setupAlignment(): void
{
// Add the correct class name to the sidebar
// element depending on the position attribute
if ( this.position === 'right' )
if ( this.align === 'left' )
{
this._renderer.addClass(this._elementRef.nativeElement, 'right-positioned');
this.renderer.addClass(this.elementRef.nativeElement, 'left-aligned');
}
else
{
this._renderer.addClass(this._elementRef.nativeElement, 'left-positioned');
this.renderer.addClass(this.elementRef.nativeElement, 'right-aligned');
}
}
@@ -298,26 +149,19 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// Return if the lockedOpen wasn't set
if ( !this.lockedOpen )
{
// Return
return;
}
// Set the wasActive for the first time
this._wasActive = false;
// Set the wasFolded
this._wasFolded = this.folded;
// Show the sidebar
this._showSidebar();
// Act on every media change
this._fuseMatchMediaService.onMediaChange
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
this._matchMediaWatcher =
this.matchMedia.onMediaChange.subscribe(() => {
// Get the active status
const isActive = this._observableMedia.isActive(this.lockedOpen);
const isActive = this.media.isActive(this.lockedOpen);
// If the both status are the same, don't act
if ( this._wasActive === isActive )
@@ -325,36 +169,14 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return;
}
// Store the new active status
this._wasActive = isActive;
// Activate the lockedOpen
if ( isActive )
{
// Set the lockedOpen status
this.isLockedOpen = true;
// Show the sidebar
this._showSidebar();
// Force the the opened status to true
this.opened = true;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// If the sidebar was folded, forcefully fold it again
if ( this._wasFolded )
{
// Enable the animations
this._enableAnimations();
// Fold
this.folded = true;
// Mark for check
this._changeDetectorRef.markForCheck();
}
// Hide the backdrop if any exists
this._hideBackdrop();
}
// De-Activate the lockedOpen
else
@@ -364,225 +186,10 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// Unfold the sidebar in case if it was folded
this.unfold();
// Force the the opened status to close
this.opened = false;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Hide the sidebar
this._hideSidebar();
}
// Store the new active status
this._wasActive = isActive;
});
}
/**
* Setup the initial folded status
*
* @private
*/
private _setupFolded(): void
{
// Return, if sidebar is not folded
if ( !this.folded )
{
return;
}
// Return if the sidebar is closed
if ( !this.opened )
{
return;
}
// Programmatically add/remove padding to the element
// that comes after or before based on the position
let sibling,
styleRule;
const styleValue = this.foldedWidth + 'px';
// Get the sibling and set the style rule
if ( this.position === 'left' )
{
sibling = this._elementRef.nativeElement.nextElementSibling;
styleRule = 'padding-left';
}
else
{
sibling = this._elementRef.nativeElement.previousElementSibling;
styleRule = 'padding-right';
}
// If there is no sibling, return...
if ( !sibling )
{
return;
}
// Fold the sidebar
this.fold();
// Set the folded width
this._renderer.setStyle(this._elementRef.nativeElement, 'width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'min-width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'max-width', styleValue);
// Set the style and class
this._renderer.setStyle(sibling, styleRule, styleValue, RendererStyleFlags2.Important + RendererStyleFlags2.DashCase);
this._renderer.addClass(this._elementRef.nativeElement, 'folded');
}
/**
* Show the backdrop
*
* @private
*/
private _showBackdrop(): void
{
// Create the backdrop element
this._backdrop = this._renderer.createElement('div');
// Add a class to the backdrop element
this._backdrop.classList.add('fuse-sidebar-overlay');
// Add a class depending on the invisibleOverlay option
if ( this.invisibleOverlay )
{
this._backdrop.classList.add('fuse-sidebar-overlay-invisible');
}
// Append the backdrop to the parent of the sidebar
this._renderer.appendChild(this._elementRef.nativeElement.parentElement, this._backdrop);
// Create the enter animation and attach it to the player
this._player =
this._animationBuilder
.build([
animate('300ms ease', style({opacity: 1}))
]).create(this._backdrop);
// Play the animation
this._player.play();
// Add an event listener to the overlay
this._backdrop.addEventListener('click', () => {
this.close();
}
);
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Hide the backdrop
*
* @private
*/
private _hideBackdrop(): void
{
if ( !this._backdrop )
{
return;
}
// Create the leave animation and attach it to the player
this._player =
this._animationBuilder
.build([
animate('300ms ease', style({opacity: 0}))
]).create(this._backdrop);
// Play the animation
this._player.play();
// Once the animation is done...
this._player.onDone(() => {
// If the backdrop still exists...
if ( this._backdrop )
{
// Remove the backdrop
this._backdrop.parentNode.removeChild(this._backdrop);
this._backdrop = null;
}
});
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Change some properties of the sidebar
* and make it visible
*
* @private
*/
private _showSidebar(): void
{
// Remove the box-shadow style
this._renderer.removeStyle(this._elementRef.nativeElement, 'box-shadow');
// Make the sidebar invisible
this._renderer.removeStyle(this._elementRef.nativeElement, 'visibility');
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Change some properties of the sidebar
* and make it invisible
*
* @private
*/
private _hideSidebar(delay = true): void
{
const delayAmount = delay ? 300 : 0;
// Add a delay so close animation can play
setTimeout(() => {
// Remove the box-shadow
this._renderer.setStyle(this._elementRef.nativeElement, 'box-shadow', 'none');
// Make the sidebar invisible
this._renderer.setStyle(this._elementRef.nativeElement, 'visibility', 'hidden');
}, delayAmount);
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Enable the animations
*
* @private
*/
private _enableAnimations(): void
{
// Return if animations already enabled
if ( this._animationsEnabled )
{
return;
}
// Enable the animations
this._animationsEnabled = true;
// Mark for check
this._changeDetectorRef.markForCheck();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the sidebar
*/
@@ -593,23 +200,14 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return;
}
// Enable the animations
this._enableAnimations();
// Show the sidebar
this._showSidebar();
// Show the backdrop
this._showBackdrop();
this.showBackdrop();
// Set the opened status
this.opened = true;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Mark for check
this._changeDetectorRef.markForCheck();
// Add a css class to the body
this.renderer.addClass(this.document.body, 'fuse-sidebar-opened');
}
/**
@@ -617,28 +215,19 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
*/
close(): void
{
if ( !this.opened || this.isLockedOpen )
if ( !this.opened )
{
return;
}
// Enable the animations
this._enableAnimations();
// Hide the backdrop
this._hideBackdrop();
this.hideBackdrop();
// Set the opened status
this.opened = false;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Hide the sidebar
this._hideSidebar();
// Mark for check
this._changeDetectorRef.markForCheck();
// Remove the css class from the body
this.renderer.removeClass(this.document.body, 'fuse-sidebar-opened');
}
/**
@@ -662,13 +251,17 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostListener('mouseenter')
onMouseEnter(): void
{
// Only work if the auto trigger is enabled
if ( !this.foldedAutoTriggerOnHover )
// Only work if the sidebar is folded
if ( !this.folded )
{
return;
}
this.unfoldTemporarily();
// Unfold the sidebar temporarily
this.unfolded = true;
// Add a css class to the body
this.renderer.addClass(this.document.body, 'fuse-sidebar-folded-unfolded');
}
/**
@@ -677,13 +270,17 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostListener('mouseleave')
onMouseLeave(): void
{
// Only work if the auto trigger is enabled
if ( !this.foldedAutoTriggerOnHover )
// Only work if the sidebar is folded
if ( !this.folded )
{
return;
}
this.foldTemporarily();
// Fold the sidebar back
this.unfolded = false;
// Remove the css class from the body
this.renderer.removeClass(this.document.body, 'fuse-sidebar-folded-unfolded');
}
/**
@@ -691,20 +288,8 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
*/
fold(): void
{
// Only work if the sidebar is not folded
if ( this.folded )
{
return;
}
// Enable the animations
this._enableAnimations();
// Fold
this.folded = true;
// Mark for check
this._changeDetectorRef.markForCheck();
// Add a css class to the body
this.renderer.addClass(this.document.body, 'fuse-sidebar-folded');
}
/**
@@ -712,20 +297,8 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
*/
unfold(): void
{
// Only work if the sidebar is folded
if ( !this.folded )
{
return;
}
// Enable the animations
this._enableAnimations();
// Unfold
this.folded = false;
// Mark for check
this._changeDetectorRef.markForCheck();
// Remove the css class from the body
this.renderer.removeClass(this.document.body, 'fuse-sidebar-folded');
}
/**
@@ -733,67 +306,70 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
*/
toggleFold(): void
{
if ( this.folded )
{
this.unfold();
}
else
{
this.fold();
}
this.folded = !this.folded;
}
/**
* Fold the temporarily unfolded sidebar back
* Show the backdrop
*/
foldTemporarily(): void
showBackdrop(): void
{
// Only work if the sidebar is folded
if ( !this.folded )
// Create the backdrop element
this._backdrop = this.renderer.createElement('div');
// Add a class to the backdrop element
this._backdrop.classList.add('fuse-sidebar-overlay');
// Append the backdrop to the parent of the sidebar
this.renderer.appendChild(this.elementRef.nativeElement.parentElement, this._backdrop);
// Create the enter animation and attach it to the player
this._player =
this.animationBuilder
.build([
animate('300ms ease', style({opacity: 1}))
]).create(this._backdrop);
// Play the animation
this._player.play();
// Add an event listener to the overlay
this._backdrop.addEventListener('click', () => {
this.close();
}
);
}
/**
* Hide the backdrop
*/
hideBackdrop(): void
{
if ( !this._backdrop )
{
return;
}
// Enable the animations
this._enableAnimations();
// Create the leave animation and attach it to the player
this._player =
this.animationBuilder
.build([
animate('300ms ease', style({opacity: 0}))
]).create(this._backdrop);
// Fold the sidebar back
this.unfolded = false;
// Play the animation
this._player.play();
// Set the folded width
const styleValue = this.foldedWidth + 'px';
// Once the animation is done...
this._player.onDone(() => {
this._renderer.setStyle(this._elementRef.nativeElement, 'width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'min-width', styleValue);
this._renderer.setStyle(this._elementRef.nativeElement, 'max-width', styleValue);
// Mark for check
this._changeDetectorRef.markForCheck();
}
/**
* Unfold the sidebar temporarily
*/
unfoldTemporarily(): void
{
// Only work if the sidebar is folded
if ( !this.folded )
{
return;
}
// Enable the animations
this._enableAnimations();
// Unfold the sidebar temporarily
this.unfolded = true;
// Remove the folded width
this._renderer.removeStyle(this._elementRef.nativeElement, 'width');
this._renderer.removeStyle(this._elementRef.nativeElement, 'min-width');
this._renderer.removeStyle(this._elementRef.nativeElement, 'max-width');
// Mark for check
this._changeDetectorRef.markForCheck();
// If the backdrop still exists...
if ( this._backdrop )
{
// Remove the backdrop
this._backdrop.parentNode.removeChild(this._backdrop);
this._backdrop = null;
}
});
}
}

View File

@@ -2,9 +2,7 @@ import { Injectable } from '@angular/core';
import { FuseSidebarComponent } from './sidebar.component';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseSidebarService
{
// Private
@@ -48,7 +46,7 @@ export class FuseSidebarService
// Check if the sidebar exists
if ( !this._registry[key] )
{
console.warn(`The sidebar with the key '${key}' doesn't exist in the registry.`);
console.error(`The sidebar with the key '${key}' doesn't exist in the registry.`);
}
// Unregister the sidebar
@@ -59,14 +57,13 @@ export class FuseSidebarService
* Return the sidebar with the given key
*
* @param key
* @returns {FuseSidebarComponent}
*/
getSidebar(key): FuseSidebarComponent
getSidebar(key): any
{
// Check if the sidebar exists
if ( !this._registry[key] )
{
console.warn(`The sidebar with the key '${key}' doesn't exist in the registry.`);
console.error(`The sidebar with the key '${key}' doesn't exist in the registry.`);
return;
}

View File

@@ -1,495 +1,105 @@
<div class="theme-options-panel" fusePerfectScrollbar>
<button #openButton mat-icon-button class="open-button mat-primary-bg mat-elevation-z2" (click)="openBar()">
<mat-icon>settings</mat-icon>
</button>
<div class="header">
<div class="theme-options-panel-overlay" #overlay [fxHide]="barClosed" [@fadeInOut]="!barClosed"></div>
<span class="title">Theme Options</span>
<div #panel class="theme-options-panel mat-white-bg mat-elevation-z8">
<button mat-icon-button class="close-button" (click)="toggleSidebarOpen('themeOptionsPanel')">
<mat-icon>close</mat-icon>
</button>
<button mat-icon-button class="close-button" (click)="closeBar()">
<mat-icon>close</mat-icon>
</button>
<div class="theme-options-panel-inner" fxLayout="column" fxLayoutAlign="start start">
<h3>Navigation:</h3>
<mat-radio-group [(ngModel)]="config.layout.navigation" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="top">Top</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="left">Left</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="right">Right</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3>Navigation Fold (for vertical navigation):</h3>
<mat-slide-toggle [(ngModel)]="config.layout.navigationFolded"
(change)="onSettingsChange()">
Folded
</mat-slide-toggle>
<h3 class="mt-24">Toolbar:</h3>
<mat-radio-group [(ngModel)]="config.layout.toolbar" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="below">Below</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="above">Above</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24">Footer:</h3>
<mat-radio-group [(ngModel)]="config.layout.footer" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="below">Below</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="above">Above</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24">Layout Mode:</h3>
<mat-radio-group [(ngModel)]="config.layout.mode" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="boxed">Boxed</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="fullwidth">Fullwidth</mat-radio-button>
</mat-radio-group>
<mat-divider></mat-divider>
<h3>Colors:</h3>
<div class="colors">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Toolbar Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.toolbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Navigation Bar Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.navbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Footer Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.footer"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
</div>
<mat-divider></mat-divider>
<h3>Router Animation:</h3>
<mat-form-field class="w-100-p">
<mat-select class="p-0" [(ngModel)]="config.routerAnimation">
<mat-option value="none">
None
</mat-option>
<mat-option value="slideUp">
Slide up
</mat-option>
<mat-option value="slideDown">
Slide down
</mat-option>
<mat-option value="slideRight">
Slide right
</mat-option>
<mat-option value="slideLeft">
Slide left
</mat-option>
<mat-option value="fadeIn">
Fade in
</mat-option>
</mat-select>
</mat-form-field>
</div>
<form [formGroup]="form">
<!-- LAYOUT STYLES -->
<div class="group" formGroupName="layout">
<h2>Layout Styles</h2>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="style">
<mat-radio-button class="mb-12" value="vertical-layout-1">
Vertical Layout #1
</mat-radio-button>
<mat-radio-button class="mb-12" value="vertical-layout-2">
Vertical Layout #2
</mat-radio-button>
<mat-radio-button class="mb-12" value="vertical-layout-3">
Vertical Layout #3
</mat-radio-button>
<mat-radio-button class="mb-12" value="horizontal-layout-1">
Horizontal Layout #1
</mat-radio-button>
</mat-radio-group>
<!-- DIFFERENT FORMS BASED ON LAYOUT STYLES -->
<ng-container [ngSwitch]="fuseConfig.layout.style">
<!-- VERTICAL LAYOUT #1 -->
<ng-container *ngSwitchCase="'vertical-layout-1'">
<!-- LAYOUT WIDTH -->
<div class="group mt-32">
<h2>Layout Width</h2>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="width">
<mat-radio-button class="mb-12" value="fullwidth">Fullwidth</mat-radio-button>
<mat-radio-button class="mb-12" value="boxed">Boxed</mat-radio-button>
</mat-radio-group>
</div>
<!-- NAVBAR -->
<div class="group" formGroupName="navbar">
<h2>Navbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<mat-slide-toggle class="mt-24" formControlName="folded">
Folded
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-16" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-16" value="right">Right</mat-radio-button>
</mat-radio-group>
<h3 class="mt-8">Variant:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="variant">
<mat-radio-button class="mb-16" value="vertical-style-1">Style 1</mat-radio-button>
<mat-radio-button class="mb-16" value="vertical-style-2">Style 2</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.navbar.background">
</fuse-material-color-picker>
</div>
<!-- TOOLBAR -->
<div class="group" formGroupName="toolbar">
<h2>Toolbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above">Above</mat-radio-button>
<mat-radio-button class="mb-12" value="below-static">Below Static</mat-radio-button>
<mat-radio-button class="mb-12" value="below-fixed">Below Fixed</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.toolbar.background">
</fuse-material-color-picker>
</div>
<!-- FOOTER -->
<div class="group" formGroupName="footer">
<h2>Footer</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above">Above</mat-radio-button>
<mat-radio-button class="mb-12" value="below-static">Below Static</mat-radio-button>
<mat-radio-button class="mb-12" value="below-fixed">Below Fixed</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.footer.background">
</fuse-material-color-picker>
</div>
<!-- SIDE PANEL -->
<div class="group" formGroupName="sidepanel">
<h2>Side Panel</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-12" value="right">Right</mat-radio-button>
</mat-radio-group>
</div>
</ng-container>
<!-- VERTICAL LAYOUT #2 -->
<ng-container *ngSwitchCase="'vertical-layout-2'">
<!-- LAYOUT WIDTH -->
<div class="group mt-32">
<h2>Layout Width</h2>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="width">
<mat-radio-button class="mb-12" value="fullwidth">Fullwidth</mat-radio-button>
<mat-radio-button class="mb-12" value="boxed">Boxed</mat-radio-button>
</mat-radio-group>
</div>
<!-- NAVBAR -->
<div class="group" formGroupName="navbar">
<h2>Navbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<mat-slide-toggle class="mt-24" formControlName="folded">
Folded
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-16" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-16" value="right">Right</mat-radio-button>
</mat-radio-group>
<h3 class="mt-8">Variant:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="variant">
<mat-radio-button class="mb-16" value="vertical-style-1">Style 1</mat-radio-button>
<mat-radio-button class="mb-16" value="vertical-style-2">Style 2</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.navbar.background">
</fuse-material-color-picker>
</div>
<!-- TOOLBAR -->
<div class="group" formGroupName="toolbar">
<h2>Toolbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above-static">Above Static</mat-radio-button>
<mat-radio-button class="mb-12" value="above-fixed">Above Fixed</mat-radio-button>
<mat-radio-button class="mb-12" value="below">Below</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.toolbar.background">
</fuse-material-color-picker>
</div>
<!-- FOOTER -->
<div class="group" formGroupName="footer">
<h2>Footer</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above-static">Above Static</mat-radio-button>
<mat-radio-button class="mb-12" value="above-fixed">Above Fixed</mat-radio-button>
<mat-radio-button class="mb-12" value="below">Below</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.footer.background">
</fuse-material-color-picker>
</div>
<!-- SIDE PANEL -->
<div class="group" formGroupName="sidepanel">
<h2>Side Panel</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-12" value="right">Right</mat-radio-button>
</mat-radio-group>
</div>
</ng-container>
<!-- VERTICAL LAYOUT #3 -->
<ng-container *ngSwitchCase="'vertical-layout-3'">
<!-- LAYOUT WIDTH -->
<div class="group mt-32">
<h2>Layout Width</h2>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="width">
<mat-radio-button class="mb-12" value="fullwidth">Fullwidth</mat-radio-button>
<mat-radio-button class="mb-12" value="boxed">Boxed</mat-radio-button>
</mat-radio-group>
</div>
<!-- NAVBAR -->
<div class="group" formGroupName="navbar">
<h2>Navbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<mat-slide-toggle class="mt-24" formControlName="folded">
Folded
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-16" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-16" value="right">Right</mat-radio-button>
</mat-radio-group>
<h3 class="mt-8">Variant:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="variant">
<mat-radio-button class="mb-16" value="vertical-style-1">Style 1</mat-radio-button>
<mat-radio-button class="mb-16" value="vertical-style-2">Style 2</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.navbar.background">
</fuse-material-color-picker>
</div>
<!-- TOOLBAR -->
<div class="group" formGroupName="toolbar">
<h2>Toolbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above-static">Above Static</mat-radio-button>
<mat-radio-button class="mb-12" value="above-fixed">Above Fixed</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.toolbar.background">
</fuse-material-color-picker>
</div>
<!-- FOOTER -->
<div class="group" formGroupName="footer">
<h2>Footer</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above-static">Above Static</mat-radio-button>
<mat-radio-button class="mb-12" value="above-fixed">Above Fixed</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.footer.background">
</fuse-material-color-picker>
</div>
<!-- SIDE PANEL -->
<div class="group" formGroupName="sidepanel">
<h2>Side Panel</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-12" value="right">Right</mat-radio-button>
</mat-radio-group>
</div>
</ng-container>
<!-- HORIZONTAL LAYOUT #1 -->
<ng-container *ngSwitchCase="'horizontal-layout-1'">
<!-- LAYOUT WIDTH -->
<div class="group mt-32">
<h2>Layout Width</h2>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="width">
<mat-radio-button class="mb-12" value="fullwidth">Fullwidth</mat-radio-button>
<mat-radio-button class="mb-12" value="boxed">Boxed</mat-radio-button>
</mat-radio-group>
</div>
<!-- NAVBAR -->
<div class="group" formGroupName="navbar">
<h2>Navbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-16" value="top">Top</mat-radio-button>
</mat-radio-group>
<h3 class="mt-8">Variant (Vertical):</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="variant">
<mat-radio-button class="mb-16" value="vertical-style-1">Style 1</mat-radio-button>
<mat-radio-button class="mb-16" value="vertical-style-2">Style 2</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.navbar.background">
</fuse-material-color-picker>
</div>
<!-- TOOLBAR -->
<div class="group" formGroupName="toolbar">
<h2>Toolbar</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above">Above</mat-radio-button>
<mat-radio-button class="mb-12" value="below">Below</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.toolbar.background">
</fuse-material-color-picker>
</div>
<!-- FOOTER -->
<div class="group" formGroupName="footer">
<h2>Footer</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="above-fixed">Above Fixed</mat-radio-button>
<mat-radio-button class="mb-12" value="above-static">Above Static</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24 mb-8">Color:</h3>
<fuse-material-color-picker class="mb-16"
[(selectedClass)]="fuseConfig.layout.footer.background">
</fuse-material-color-picker>
</div>
<!-- SIDE PANEL -->
<div class="group" formGroupName="sidepanel">
<h2>Side Panel</h2>
<mat-slide-toggle formControlName="hidden">
Hide
</mat-slide-toggle>
<h3 class="mt-24">Position:</h3>
<mat-radio-group fxLayout="column" fxLayoutAlign="start start" formControlName="position">
<mat-radio-button class="mb-12" value="left">Left</mat-radio-button>
<mat-radio-button class="mb-12" value="right">Right</mat-radio-button>
</mat-radio-group>
</div>
</ng-container>
</ng-container>
</div>
<!-- CUSTOM SCROLLBARS -->
<div class="group">
<h2>Custom scrollbars</h2>
<mat-slide-toggle class="mb-12" formControlName="customScrollbars">
Enable custom scrollbars
</mat-slide-toggle>
</div>
</form>
</div>

View File

@@ -10,69 +10,106 @@
}
:host {
display: flex;
overflow: hidden;
position: fixed;
display: block;
right: 0;
top: 160px;
z-index: 998;
&.bar-closed .theme-options-panel {
display: none;
}
.theme-options-panel {
display: flex;
flex-direction: column;
flex: 1 0 auto;
padding: 40px 24px 24px 24px;
position: absolute;
right: 0;
top: 0;
width: 360px;
transform: translate3d(100%, 0, 0);
z-index: 999;
max-height: calc(100vh - 200px);
padding: 24px;
overflow: auto;
.header {
display: flex;
flex: 0 1 auto;
margin-bottom: 32px;
align-items: center;
justify-content: space-between;
.title {
font-size: 20px;
font-weight: 500;
padding-left: 4px;
}
@include media-breakpoint-down('xs') {
top: -120px;
max-height: calc(100vh - 100px);
width: 90vw;
}
form {
display: flex;
flex: 1 1 auto;
flex-direction: column;
.close-button {
position: absolute;
top: 8px;
right: 8px;
}
.group {
display: flex;
flex: 1 0 auto;
flex-direction: column;
position: relative;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 2px;
padding: 28px 16px 8px 16px;
margin: 16px 0;
h3 {
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.54);
}
h2 {
position: absolute;
top: -11px;
left: 8px;
margin: 0;
padding: 0 8px;
font-size: 16px;
font-weight: 500;
background: white;
color: rgba(0, 0, 0, 0.54);
}
.mat-divider {
display: block !important;
width: 100%;
margin: 24px 0 16px 0;
}
h3 {
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.54);
margin: 24px 0 16px 0;
padding: 0;
&:first-of-type {
margin-top: 0;
}
}
}
.colors {
display: block !important;
width: 100%;
}
}
.theme-options-panel-overlay {
position: fixed;
display: block;
background: rgba(0, 0, 0, 0);
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 998;
@include media-breakpoint-down('sm') {
background: rgba(0, 0, 0, 0.37);
}
&.hidden {
display: none;
}
}
.mat-list .mat-list-item {
font-size: 15px;
}
.mat-divider {
margin: 16px;
}
.open-button {
position: absolute;
top: 0;
left: -48px;
width: 48px;
height: 48px;
line-height: 48px;
text-align: center;
cursor: pointer;
border-radius: 0;
margin: 0;
pointer-events: auto;
opacity: .75;
z-index: 998;
mat-icon {
animation: rotating 3s linear infinite;
}
&:hover {
opacity: 1;
}
}
}

View File

@@ -1,12 +1,12 @@
import { Component, HostBinding, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Component, ElementRef, HostBinding, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
import { Subscription } from 'rxjs/Subscription';
import { fuseAnimations } from '@fuse/animations';
import { FuseConfigService } from '@fuse/services/config.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
import { navigation } from 'app/navigation/navigation';
@Component({
selector : 'fuse-theme-options',
@@ -16,118 +16,42 @@ import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
})
export class FuseThemeOptionsComponent implements OnInit, OnDestroy
{
fuseConfig: any;
form: FormGroup;
@ViewChild('openButton') openButton;
@ViewChild('panel') panel;
@ViewChild('overlay') overlay: ElementRef;
@HostBinding('class.bar-closed')
barClosed: boolean;
public player: AnimationPlayer;
config: any;
// Private
private _unsubscribeAll: Subject<any>;
onConfigChanged: Subscription;
@HostBinding('class.bar-closed') barClosed: boolean;
/**
* Constructor
*
* @param {FormBuilder} _formBuilder
* @param {FuseConfigService} _fuseConfigService
* @param {FuseNavigationService} _fuseNavigationService
* @param {FuseSidebarService} _fuseSidebarService
* @param {Renderer2} _renderer
*/
constructor(
private _formBuilder: FormBuilder,
private _fuseConfigService: FuseConfigService,
private _fuseNavigationService: FuseNavigationService,
private _fuseSidebarService: FuseSidebarService,
private _renderer: Renderer2
private animationBuilder: AnimationBuilder,
private fuseConfig: FuseConfigService,
private navigationService: FuseNavigationService,
private renderer: Renderer2
)
{
// Set the defaults
this.barClosed = true;
// Set the private defaults
this._unsubscribeAll = new Subject();
}
this.onConfigChanged =
this.fuseConfig.onConfigChanged
.subscribe(
(newConfig) => {
this.config = newConfig;
}
);
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
// Get the nav model and add customize nav item
// that opens the bar programmatically
const nav: any = navigation;
/**
* On init
*/
ngOnInit(): void
{
// Build the config form
// noinspection TypeScriptValidateTypes
this.form = this._formBuilder.group({
layout : this._formBuilder.group({
style : new FormControl(),
width : new FormControl(),
navbar : this._formBuilder.group({
background: new FormControl(),
folded : new FormControl(),
hidden : new FormControl(),
position : new FormControl(),
variant : new FormControl()
}),
toolbar : this._formBuilder.group({
background: new FormControl(),
hidden : new FormControl(),
position : new FormControl()
}),
footer : this._formBuilder.group({
background: new FormControl(),
hidden : new FormControl(),
position : new FormControl()
}),
sidepanel: this._formBuilder.group({
hidden: new FormControl(),
position : new FormControl()
})
}),
customScrollbars: new FormControl()
});
// Subscribe to the config changes
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
// Update the stored config
this.fuseConfig = config;
// Set the config form values without emitting an event
// so that we don't end up with an infinite loop
this.form.setValue(config, {emitEvent: false});
});
// Subscribe to the specific form value changes (layout.style)
this.form.get('layout.style').valueChanges
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) => {
// Reset the form values based on the
// selected layout style
this._resetFormValues(value);
});
// Subscribe to the form value changes
this.form.valueChanges
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
// Update the config
this._fuseConfigService.config = config;
});
// Add customize nav item that opens the bar programmatically
const customFunctionNavItem = {
nav.push({
'id' : 'custom-function',
'title' : 'Custom Function',
'type' : 'group',
'icon' : 'settings',
'children': [
{
'id' : 'customize',
@@ -135,173 +59,57 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
'type' : 'item',
'icon' : 'settings',
'function': () => {
this.toggleSidebarOpen('themeOptionsPanel');
this.openBar();
}
}
]
};
this._fuseNavigationService.addNavigationItem(customFunctionNavItem, 'end');
});
}
/**
* On destroy
*/
ngOnDestroy(): void
ngOnInit()
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
// Remove the custom function menu
this._fuseNavigationService.removeNavigationItem('custom-function');
this.renderer.listen(this.overlay.nativeElement, 'click', () => {
this.closeBar();
});
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Reset the form values based on the
* selected layout style
*
* @param value
* @private
*/
private _resetFormValues(value): void
ngOnDestroy()
{
switch ( value )
{
// Vertical Layout #1
case 'vertical-layout-1':
{
this.form.patchValue({
layout: {
width : 'fullwidth',
navbar : {
background: 'mat-fuse-dark-700-bg',
folded : false,
hidden : false,
position : 'left',
variant : 'vertical-style-1'
},
toolbar: {
background: 'mat-white-500-bg',
hidden : false,
position : 'below-static'
},
footer : {
background: 'mat-fuse-dark-900-bg',
hidden : false,
position : 'below-static'
}
}
});
break;
}
// Vertical Layout #2
case 'vertical-layout-2':
{
this.form.patchValue({
layout: {
width : 'fullwidth',
navbar : {
background: 'mat-fuse-dark-700-bg',
folded : false,
hidden : false,
position : 'left',
variant : 'vertical-style-1'
},
toolbar: {
background: 'mat-white-500-bg',
hidden : false,
position : 'below'
},
footer : {
background: 'mat-fuse-dark-900-bg',
hidden : false,
position : 'below'
}
}
});
break;
}
// Vertical Layout #3
case 'vertical-layout-3':
{
this.form.patchValue({
layout: {
width : 'fullwidth',
navbar : {
background: 'mat-fuse-dark-700-bg',
folded : false,
hidden : false,
position : 'left',
layout : 'vertical-style-1'
},
toolbar: {
background: 'mat-white-500-bg',
hidden : false,
position : 'above-static'
},
footer : {
background: 'mat-fuse-dark-900-bg',
hidden : false,
position : 'above-static'
}
}
});
break;
}
// Horizontal Layout #1
case 'horizontal-layout-1':
{
this.form.patchValue({
layout: {
width : 'fullwidth',
navbar : {
background: 'mat-fuse-dark-700-bg',
folded : false,
hidden : false,
position : 'top',
variant : 'vertical-style-1'
},
toolbar: {
background: 'mat-white-500-bg',
hidden : false,
position : 'above'
},
footer : {
background: 'mat-fuse-dark-900-bg',
hidden : false,
position : 'above-fixed'
}
}
});
break;
}
}
this.onConfigChanged.unsubscribe();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle sidebar open
*
* @param key
*/
toggleSidebarOpen(key): void
onSettingsChange()
{
this._fuseSidebarService.getSidebar(key).toggleOpen();
this.fuseConfig.setConfig(this.config);
}
closeBar()
{
this.player =
this.animationBuilder
.build([
style({transform: 'translate3d(0,0,0)'}),
animate('400ms ease', style({transform: 'translate3d(100%,0,0)'}))
]).create(this.panel.nativeElement);
this.player.play();
this.player.onDone(() => {
this.barClosed = true;
});
}
openBar()
{
this.barClosed = false;
this.player =
this.animationBuilder
.build([
style({transform: 'translate3d(100%,0,0)'}),
animate('400ms ease', style({transform: 'translate3d(0,0,0)'}))
]).create(this.panel.nativeElement);
this.player.play();
}
}

View File

@@ -1,13 +1,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule } from '@angular/material';
import { FuseDirectivesModule } from '@fuse/directives/directives';
import { FuseSidebarModule } from '@fuse/components/sidebar/sidebar.module';
import { FuseMaterialColorPickerModule } from '@fuse/components/material-color-picker/material-color-picker.module';
import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component';
@NgModule({
@@ -17,7 +14,6 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
imports : [
CommonModule,
FormsModule,
ReactiveFormsModule,
FlexLayoutModule,
@@ -30,9 +26,7 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
MatSelectModule,
MatSlideToggleModule,
FuseDirectivesModule,
FuseMaterialColorPickerModule,
FuseSidebarModule
FuseMaterialColorPickerModule
],
exports : [
FuseThemeOptionsComponent

View File

@@ -5,14 +5,7 @@ import { Directive, ElementRef } from '@angular/core';
})
export class FuseWidgetToggleDirective
{
/**
* Constructor
*
* @param {ElementRef} elementRef
*/
constructor(
public elementRef: ElementRef
)
constructor(public el: ElementRef)
{
}
}

View File

@@ -67,16 +67,16 @@ fuse-widget {
&.mat-form-field-type-mat-select {
.mat-form-field-wrapper {
.mat-input-wrapper {
padding: 16px 0;
.mat-form-field-infix {
.mat-input-infix {
border: none;
padding: 0;
}
}
.mat-form-field-underline {
.mat-input-underline {
display: none;
}
}

View File

@@ -10,38 +10,19 @@ import { FuseWidgetToggleDirective } from './widget-toggle.directive';
export class FuseWidgetComponent implements AfterContentInit
{
@HostBinding('class.flipped')
flipped = false;
@HostBinding('class.flipped') flipped = false;
@ContentChildren(FuseWidgetToggleDirective, {descendants: true}) toggleButtons: QueryList<FuseWidgetToggleDirective>;
@ContentChildren(FuseWidgetToggleDirective, {descendants: true})
toggleButtons: QueryList<FuseWidgetToggleDirective>;
/**
* Constructor
*
* @param {ElementRef} _elementRef
* @param {Renderer2} _renderer
*/
constructor(
private _elementRef: ElementRef,
private _renderer: Renderer2
)
constructor(private el: ElementRef, private renderer: Renderer2)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* After content init
*/
ngAfterContentInit(): void
ngAfterContentInit()
{
// Listen for the flip button click
setTimeout(() => {
this.toggleButtons.forEach(flipButton => {
this._renderer.listen(flipButton.elementRef.nativeElement, 'click', (event) => {
this.renderer.listen(flipButton.el.nativeElement, 'click', (event) => {
event.preventDefault();
event.stopPropagation();
this.toggle();
@@ -50,14 +31,7 @@ export class FuseWidgetComponent implements AfterContentInit
});
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle the flipped status
*/
toggle(): void
toggle()
{
this.flipped = !this.flipped;
}

View File

@@ -1,14 +1,12 @@
import { NgModule } from '@angular/core';
import { FuseIfOnDomDirective } from '@fuse/directives/fuse-if-on-dom/fuse-if-on-dom.directive';
import { FuseInnerScrollDirective } from '@fuse/directives/fuse-inner-scroll/fuse-inner-scroll.directive';
import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '@fuse/directives/fuse-mat-sidenav/fuse-mat-sidenav.directive';
@NgModule({
declarations: [
FuseIfOnDomDirective,
FuseInnerScrollDirective,
FuseMatSidenavHelperDirective,
FuseMatSidenavTogglerDirective,
FusePerfectScrollbarDirective
@@ -16,7 +14,6 @@ import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '@
imports : [],
exports : [
FuseIfOnDomDirective,
FuseInnerScrollDirective,
FuseMatSidenavHelperDirective,
FuseMatSidenavTogglerDirective,
FusePerfectScrollbarDirective

View File

@@ -5,44 +5,28 @@ import { AfterContentChecked, Directive, ElementRef, TemplateRef, ViewContainerR
})
export class FuseIfOnDomDirective implements AfterContentChecked
{
isCreated: boolean;
isCreated = false;
/**
* Constructor
*
* @param {ElementRef} _elementRef
* @param {TemplateRef<any>} _templateRef
* @param {ViewContainerRef} _viewContainerRef
*/
constructor(
private _elementRef: ElementRef,
private _templateRef: TemplateRef<any>,
private _viewContainerRef: ViewContainerRef
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private element: ElementRef
)
{
// Set the defaults
this.isCreated = false;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* After content checked
*/
ngAfterContentChecked(): void
ngAfterContentChecked()
{
if ( document.body.contains(this._elementRef.nativeElement) && !this.isCreated )
if ( document.body.contains(this.element.nativeElement) && !this.isCreated )
{
setTimeout(() => {
this._viewContainerRef.createEmbeddedView(this._templateRef);
this.viewContainer.createEmbeddedView(this.templateRef);
}, 300);
this.isCreated = true;
}
else if ( this.isCreated && !document.body.contains(this._elementRef.nativeElement) )
else if ( this.isCreated && !document.body.contains(this.element.nativeElement) )
{
this._viewContainerRef.clear();
this.viewContainer.clear();
this.isCreated = false;
}
}

View File

@@ -1,115 +0,0 @@
import { Directive, ElementRef, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMatchMediaService } from '@fuse/services/match-media.service';
@Directive({
selector: '.inner-scroll'
})
export class FuseInnerScrollDirective implements OnInit, OnDestroy
{
// Private
private _parent: any;
private _grandParent: any;
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ElementRef} _elementRef
* @param {FuseMatchMediaService} _fuseMediaMatchService
* @param {Renderer2} _renderer
*/
constructor(
private _elementRef: ElementRef,
private _fuseMediaMatchService: FuseMatchMediaService,
private _renderer: Renderer2
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the parent
this._parent = this._renderer.parentNode(this._elementRef.nativeElement);
// Return, if there is no parent
if ( !this._parent )
{
return;
}
// Get the grand parent
this._grandParent = this._renderer.parentNode(this._parent);
// Register to the media query changes
this._fuseMediaMatchService.onMediaChange
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((alias) => {
if ( alias === 'xs' )
{
this._removeClass();
}
else
{
this._addClass();
}
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Return, if there is no parent
if ( !this._parent )
{
return;
}
// Remove the class
this._removeClass();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Add the class name
*
* @private
*/
private _addClass(): void
{
// Add the inner-scroll class
this._renderer.addClass(this._grandParent, 'inner-scroll');
}
/**
* Remove the class name
* @private
*/
private _removeClass(): void
{
// Remove the inner-scroll class
this._renderer.removeClass(this._grandParent, 'inner-scroll');
}
}

View File

@@ -1,8 +1,7 @@
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
import { MatSidenav } from '@angular/material';
import { ObservableMedia } from '@angular/flex-layout';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Subscription } from 'rxjs/Subscription';
import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseMatSidenavHelperService } from '@fuse/directives/fuse-mat-sidenav/fuse-mat-sidenav.service';
@@ -12,91 +11,56 @@ import { FuseMatSidenavHelperService } from '@fuse/directives/fuse-mat-sidenav/f
})
export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
{
@HostBinding('class.mat-is-locked-open')
isLockedOpen: boolean;
matchMediaSubscription: Subscription;
@HostBinding('class.mat-is-locked-open') isLockedOpen = true;
@Input('fuseMatSidenavHelper') id: string;
@Input('mat-is-locked-open') matIsLockedOpenBreakpoint: string;
@Input('fuseMatSidenavHelper')
id: string;
@Input('mat-is-locked-open')
matIsLockedOpenBreakpoint: string;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FuseMatchMediaService} _fuseMatchMediaService
* @param {FuseMatSidenavHelperService} _fuseMatSidenavHelperService
* @param {MatSidenav} _matSidenav
* @param {ObservableMedia} _observableMedia
*/
constructor(
private _fuseMatchMediaService: FuseMatchMediaService,
private _fuseMatSidenavHelperService: FuseMatSidenavHelperService,
private _matSidenav: MatSidenav,
private _observableMedia: ObservableMedia
private fuseMatSidenavService: FuseMatSidenavHelperService,
private fuseMatchMedia: FuseMatchMediaService,
private observableMedia: ObservableMedia,
private matSidenav: MatSidenav
)
{
// Set the defaults
this.isLockedOpen = true;
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
ngOnInit()
{
// Register the sidenav to the service
this._fuseMatSidenavHelperService.setSidenav(this.id, this._matSidenav);
this.fuseMatSidenavService.setSidenav(this.id, this.matSidenav);
if ( this._observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
{
this.isLockedOpen = true;
this._matSidenav.mode = 'side';
this._matSidenav.toggle(true);
this.matSidenav.mode = 'side';
this.matSidenav.toggle(true);
}
else
{
this.isLockedOpen = false;
this._matSidenav.mode = 'over';
this._matSidenav.toggle(false);
this.matSidenav.mode = 'over';
this.matSidenav.toggle(false);
}
this._fuseMatchMediaService.onMediaChange
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
if ( this._observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
{
this.isLockedOpen = true;
this._matSidenav.mode = 'side';
this._matSidenav.toggle(true);
}
else
{
this.isLockedOpen = false;
this._matSidenav.mode = 'over';
this._matSidenav.toggle(false);
}
});
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
{
this.isLockedOpen = true;
this.matSidenav.mode = 'side';
this.matSidenav.toggle(true);
}
else
{
this.isLockedOpen = false;
this.matSidenav.mode = 'over';
this.matSidenav.toggle(false);
}
});
}
/**
* On destroy
*/
ngOnDestroy(): void
ngOnDestroy()
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
this.matchMediaSubscription.unsubscribe();
}
}
@@ -105,29 +69,15 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
})
export class FuseMatSidenavTogglerDirective
{
@Input('fuseMatSidenavToggler')
id;
@Input('fuseMatSidenavToggler') id;
/**
* Constructor
*
* @param {FuseMatSidenavHelperService} _fuseMatSidenavHelperService
*/
constructor(
private _fuseMatSidenavHelperService: FuseMatSidenavHelperService)
constructor(private fuseMatSidenavService: FuseMatSidenavHelperService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On click
*/
@HostListener('click')
onClick()
{
this._fuseMatSidenavHelperService.getSidenav(this.id).toggle();
this.fuseMatSidenavService.getSidenav(this.id).toggle();
}
}

View File

@@ -1,43 +1,22 @@
import { Injectable } from '@angular/core';
import { MatSidenav } from '@angular/material';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseMatSidenavHelperService
{
sidenavInstances: MatSidenav[];
/**
* Constructor
*/
constructor()
{
this.sidenavInstances = [];
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Set sidenav
*
* @param id
* @param instance
*/
setSidenav(id, instance): void
setSidenav(id, instance)
{
this.sidenavInstances[id] = instance;
}
/**
* Get sidenav
*
* @param id
* @returns {any}
*/
getSidenav(id): any
getSidenav(id)
{
return this.sidenavInstances[id];
}

View File

@@ -1,247 +1,72 @@
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { AfterViewInit, Directive, ElementRef, HostListener, OnDestroy, OnInit } from '@angular/core';
import { Platform } from '@angular/cdk/platform';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { Subscription } from 'rxjs/Subscription';
import PerfectScrollbar from 'perfect-scrollbar';
import * as _ from 'lodash';
import { FuseConfigService } from '@fuse/services/config.service';
@Directive({
selector: '[fusePerfectScrollbar]'
})
export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnDestroy
{
isInitialized: boolean;
isMobile: boolean;
onConfigChanged: Subscription;
isDisableCustomScrollbars = false;
isMobile = false;
isInitialized = true;
ps: PerfectScrollbar;
// Private
private _enabled: boolean | '';
private _debouncedUpdate: any;
private _options: any;
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ElementRef} elementRef
* @param {FuseConfigService} _fuseConfigService
* @param {Platform} _platform
* @param {Router} _router
*/
constructor(
public elementRef: ElementRef,
private _fuseConfigService: FuseConfigService,
private _platform: Platform,
private _router: Router
public element: ElementRef,
private fuseConfig: FuseConfigService,
private platform: Platform
)
{
// Set the defaults
this.isInitialized = false;
this.isMobile = false;
// Set the private defaults
this._enabled = false;
this._debouncedUpdate = _.debounce(this.update, 150);
this._options = {
updateOnRouteChange: false
};
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Perfect Scrollbar options
*
* @param value
*/
@Input()
set fusePerfectScrollbarOptions(value)
ngOnInit()
{
// Merge the options
this._options = _.merge({}, this._options, value);
}
get fusePerfectScrollbarOptions(): any
{
// Return the options
return this._options;
}
/**
* Is enabled
*
* @param {boolean | ""} value
*/
@Input('fusePerfectScrollbar')
set enabled(value: boolean | '')
{
// If nothing is provided with the directive (empty string),
// we will take that as a true
if ( value === '' )
{
value = true;
}
// Return, if both values are the same
if ( this.enabled === value )
{
return;
}
// Store the value
this._enabled = value;
// If enabled...
if ( this.enabled )
{
// Init the directive
this._init();
}
else
{
// Otherwise destroy it
this._destroy();
}
}
get enabled(): boolean | ''
{
// Return the enabled status
return this._enabled;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* After view init
*/
ngAfterViewInit(): void
{
// Check if scrollbars enabled or not from the main config
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(
this.onConfigChanged =
this.fuseConfig.onConfigChanged.subscribe(
(settings) => {
this.enabled = settings.customScrollbars;
this.isDisableCustomScrollbars = !settings.customScrollbars;
}
);
// Scroll to the top on every route change
if ( this.fusePerfectScrollbarOptions.updateOnRouteChange )
{
this._router.events
.pipe(
takeUntil(this._unsubscribeAll),
filter(event => event instanceof NavigationEnd)
)
.subscribe(() => {
setTimeout(() => {
this.scrollToTop();
this.update();
}, 0);
});
}
}
/**
* On destroy
*/
ngOnDestroy(): void
{
this._destroy();
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
_init(): void
{
// Return, if already initialized
if ( this.isInitialized )
{
return;
}
// Check if is mobile
if ( this._platform.ANDROID || this._platform.IOS )
if ( this.platform.ANDROID || this.platform.IOS )
{
this.isMobile = true;
}
}
// Return if it's mobile
if ( this.isMobile )
ngAfterViewInit()
{
if ( this.isMobile || this.isDisableCustomScrollbars )
{
// Return...
this.isInitialized = false;
return;
}
// Set as initialized
this.isInitialized = true;
// Initialize the perfect-scrollbar
this.ps = new PerfectScrollbar(this.elementRef.nativeElement, {
...this.fusePerfectScrollbarOptions
this.ps = new PerfectScrollbar(this.element.nativeElement, {
wheelPropagation: true
});
}
/**
* Destroy
*
* @private
*/
_destroy(): void
ngOnDestroy()
{
if ( !this.isInitialized || !this.ps )
{
return;
}
this.onConfigChanged.unsubscribe();
// Destroy the perfect-scrollbar
this.ps.destroy();
// Clean up
this.ps = null;
this.isInitialized = false;
}
/**
* Update scrollbars on window resize
*
* @private
*/
@HostListener('window:resize')
_updateOnResize(): void
{
this._debouncedUpdate();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Document click
*
* @param {Event} event
*/
@HostListener('document:click', ['$event'])
documentClick(event: Event): void
{
@@ -257,10 +82,7 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
this.ps.update();
}
/**
* Update the scrollbar
*/
update(): void
update()
{
if ( !this.isInitialized )
{
@@ -271,108 +93,62 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
this.ps.update();
}
/**
* Destroy the scrollbar
*/
destroy(): void
destroy()
{
this.ngOnDestroy();
}
/**
* Scroll to X
*
* @param {number} x
* @param {number} speed
*/
scrollToX(x: number, speed?: number): void
scrollToX(x: number, speed?: number)
{
this.animateScrolling('scrollLeft', x, speed);
}
/**
* Scroll to Y
*
* @param {number} y
* @param {number} speed
*/
scrollToY(y: number, speed?: number): void
scrollToY(y: number, speed?: number)
{
this.animateScrolling('scrollTop', y, speed);
}
/**
* Scroll to top
*
* @param {number} offset
* @param {number} speed
*/
scrollToTop(offset?: number, speed?: number): void
scrollToTop(offset?: number, speed?: number)
{
this.animateScrolling('scrollTop', (offset || 0), speed);
}
/**
* Scroll to left
*
* @param {number} offset
* @param {number} speed
*/
scrollToLeft(offset?: number, speed?: number): void
scrollToLeft(offset?: number, speed?: number)
{
this.animateScrolling('scrollLeft', (offset || 0), speed);
}
/**
* Scroll to right
*
* @param {number} offset
* @param {number} speed
*/
scrollToRight(offset?: number, speed?: number): void
scrollToRight(offset?: number, speed?: number)
{
const width = this.elementRef.nativeElement.scrollWidth;
const width = this.element.nativeElement.scrollWidth;
this.animateScrolling('scrollLeft', width - (offset || 0), speed);
}
/**
* Scroll to bottom
*
* @param {number} offset
* @param {number} speed
*/
scrollToBottom(offset?: number, speed?: number): void
scrollToBottom(offset?: number, speed?: number)
{
const height = this.elementRef.nativeElement.scrollHeight;
const height = this.element.nativeElement.scrollHeight;
this.animateScrolling('scrollTop', height - (offset || 0), speed);
}
/**
* Animate scrolling
*
* @param {string} target
* @param {number} value
* @param {number} speed
*/
animateScrolling(target: string, value: number, speed?: number): void
animateScrolling(target: string, value: number, speed?: number)
{
if ( !speed )
{
this.elementRef.nativeElement[target] = value;
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
this.update();
}
else if ( value !== this.elementRef.nativeElement[target] )
else if ( value !== this.element.nativeElement[target] )
{
let newValue = 0;
let scrollCount = 0;
let oldTimestamp = performance.now();
let oldValue = this.elementRef.nativeElement[target];
let oldValue = this.element.nativeElement[target];
const cosParameter = (oldValue - value) / 2;
@@ -382,11 +158,11 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
// Only continue animation if scroll position has not changed
if ( this.elementRef.nativeElement[target] === oldValue )
if ( this.element.nativeElement[target] === oldValue )
{
if ( scrollCount >= Math.PI )
{
this.elementRef.nativeElement[target] = value;
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
@@ -395,7 +171,7 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
}
else
{
this.elementRef.nativeElement[target] = oldValue = newValue;
this.element.nativeElement[target] = oldValue = newValue;
oldTimestamp = newTimestamp;

View File

@@ -1,8 +1,27 @@
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { FUSE_CONFIG } from '@fuse/services/config.service';
import { FUSE_CONFIG, FuseConfigService } from '@fuse/services/config.service';
import { FuseCopierService } from '@fuse/services/copier.service';
import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseMatSidenavHelperService } from '@fuse/directives/fuse-mat-sidenav/fuse-mat-sidenav.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
import { FuseSplashScreenService } from '@fuse/services/splash-screen.service';
import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service';
@NgModule()
@NgModule({
entryComponents: [],
providers : [
FuseConfigService,
FuseCopierService,
FuseMatchMediaService,
FuseMatSidenavHelperService,
FuseNavigationService,
FuseSidebarService,
FuseSplashScreenService,
FuseTranslationLoaderService
]
})
export class FuseModule
{
constructor(@Optional() @SkipSelf() parentModule: FuseModule)

View File

@@ -3,14 +3,7 @@ import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'camelCaseToDash'})
export class CamelCaseToDashPipe implements PipeTransform
{
/**
* Transform
*
* @param {string} value
* @param {any[]} args
* @returns {string}
*/
transform(value: string, args: any[] = []): string
transform(value: string, args: any[] = [])
{
return value ? String(value).replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`) : '';
}

View File

@@ -4,14 +4,6 @@ import { FuseUtils } from '@fuse/utils';
@Pipe({name: 'filter'})
export class FilterPipe implements PipeTransform
{
/**
* Transform
*
* @param {any[]} mainArr
* @param {string} searchText
* @param {string} property
* @returns {any}
*/
transform(mainArr: any[], searchText: string, property: string): any
{
return FuseUtils.filterArrayByString(mainArr, searchText);

View File

@@ -6,14 +6,6 @@ import { Pipe, PipeTransform } from '@angular/core';
})
export class GetByIdPipe implements PipeTransform
{
/**
* Transform
*
* @param {any[]} value
* @param {number} id
* @param {string} property
* @returns {any}
*/
transform(value: any[], id: number, property: string): any
{
const foundItem = value.find(item => {

View File

@@ -3,14 +3,7 @@ import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'htmlToPlaintext'})
export class HtmlToPlaintextPipe implements PipeTransform
{
/**
* Transform
*
* @param {string} value
* @param {any[]} args
* @returns {string}
*/
transform(value: string, args: any[] = []): string
transform(value: string, args: any[] = [])
{
return value ? String(value).replace(/<[^>]+>/gm, '') : '';
}

View File

@@ -3,13 +3,6 @@ import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform
{
/**
* Transform
*
* @param value
* @param {string[]} args
* @returns {any}
*/
transform(value: any, args: string[]): any
{
const keys: any[] = [];

View File

@@ -1,6 +1,3 @@
// This file meant to be imported only once! Use fuse.scss to access
// to the core Fuse and Angular Material mixins
// ngx-datatable
@import '~@swimlane/ngx-datatable/release/themes/material';
@@ -10,13 +7,10 @@
// Fuse
@import "fuse";
// Include core Angular Material styles
// Theming
@include mat-core();
// Setup the typography
@include angular-material-typography($typography);
// Create an Angular Material theme from the $theme map
// Include theme styles for core and each component used in your app.
@include angular-material-theme($theme);
// Partials
@@ -30,7 +24,6 @@
@import "partials/material";
@import "partials/angular-material-fix";
@import "partials/typography";
@import "partials/docs";
@import "partials/page-layouts";
@import "partials/cards";
@import "partials/navigation";

View File

@@ -1,5 +1,4 @@
// Material theming
@import "theming";
// Breakpoint mixins
// Variables
@import "variables/theme";
// Mixins
@import "mixins/breakpoints";

View File

@@ -7,7 +7,7 @@
}
// Fix: "Inconsistent font sizes across elements"
.mat-form-field-wrapper {
.mat-input-wrapper {
font-size: 16px;
}
@@ -34,7 +34,7 @@
&.mat-form-field-type-mat-select {
.mat-form-field-infix {
.mat-input-infix {
display: inline-flex;
width: auto;
@@ -57,7 +57,7 @@
}
}
// Fix: Stepper icons are broken due to Fuse's icon helpers
// Fix: "Stepper icons are broken due to Fuse's icon helpers"
mat-horizontal-stepper,
mat-vertical-stepper {
@@ -68,25 +68,11 @@ mat-vertical-stepper {
width: 16px !important;
min-width: 0 !important;
min-height: 0 !important;
color: inherit !important;
color: rgba(255, 255, 255, 0.87) !important;
}
}
}
mat-vertical-stepper {
padding: 16px 0;
}
// Fix: Chip remove icon is broken due to Fuse's icon helpers
mat-chip {
mat-icon {
min-width: 0 !important;
min-height: 0 !important;
}
}
// Fix: Mat-card-image requires a bigger width than 100%
.mat-card-image {
max-width: none !important;
}

View File

@@ -1,6 +1,6 @@
.secondary-text,
.icon,
i {
.mat-icon,
.icon {
color: rgba(0, 0, 0, 0.54);
}
@@ -14,7 +14,7 @@ i {
}
// Material colors map
$matPalettes: (
$matColorsMap: (
primary: $primary,
accent: $accent,
warn: $warn,
@@ -43,91 +43,75 @@ $matPalettes: (
);
// Material color hues list
$matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A700;
$matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A700;
// Text color levels generator mixin
@mixin generateTextColorLevels($classes, $contrast) {
@mixin generateTextColorLevels($baseTextColor) {
// If the contrast is dark...
@if ($contrast == 'dark') {
// If the base text color is black...
@if (rgba(black, 1) == rgba($baseTextColor, 1)) {
// Put down the color classes
#{$classes} {
.mat-icon,
.icon {
color: rgba(0, 0, 0, 0.54);
}
i,
.icon {
color: rgba(0, 0, 0, 0.54);
}
&.secondary-text,
.secondary-text {
color: rgba(0, 0, 0, 0.54) !important;
}
&.secondary-text,
.secondary-text {
color: rgba(0, 0, 0, 0.54) !important;
}
&.hint-text,
.hint-text,
&.disabled-text,
.disabled-text {
color: rgba(0, 0, 0, 0.38) !important;
}
&.hint-text,
.hint-text,
&.disabled-text,
.disabled-text {
color: rgba(0, 0, 0, 0.38) !important;
}
&.divider,
.divider {
color: rgba(0, 0, 0, 0.12) !important;
}
&.divider,
.divider {
color: rgba(0, 0, 0, 0.12) !important;
}
.mat-ripple-element {
background: rgba(0, 0, 0, 0.1);
}
.adaptive-border-color {
border-color: rgba(0, 0, 0, 0.12);
}
.mat-ripple-element {
background: rgba(0, 0, 0, 0.1);
}
}
// If the base text color is white...
@else {
// Put down the color classes
#{$classes} {
.mat-icon,
.icon {
color: rgba(255, 255, 255, 1);
}
i,
.icon {
color: rgba(255, 255, 255, 1);
}
&.secondary-text,
.secondary-text {
color: rgba(255, 255, 255, 0.70) !important;
}
&.secondary-text,
.secondary-text {
color: rgba(255, 255, 255, 0.70) !important;
}
&.hint-text,
.hint-text,
&.disabled-text,
.disabled-text {
color: rgba(255, 255, 255, 0.50) !important;
}
&.hint-text,
.hint-text,
&.disabled-text,
.disabled-text {
color: rgba(255, 255, 255, 0.50) !important;
}
&.divider,
.divider {
color: rgba(255, 255, 255, 0.12) !important;
}
&.divider,
.divider {
color: rgba(255, 255, 255, 0.12) !important;
}
.mat-ripple-element {
background: rgba(255, 255, 255, 0.1);
}
.adaptive-border-color {
border-color: rgba(255, 255, 255, 0.12);
}
.mat-ripple-element {
background: rgba(255, 255, 255, 0.1);
}
}
}
@mixin generateMaterialElementColors($classes, $contrast) {
@mixin generateMaterialElementColors($contrastColor) {
// If the contrast color is light...
// If the contrast color is white...
$fuseForeground: (
base: white,
text: white,
@@ -135,8 +119,8 @@ $matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A70
divider: rgba(white, 0.12),
);
// If the contrast color is dark...
@if ($contrast == 'dark') {
// If the contrast color is black...
@if (rgba(black, 1) == rgba($contrastColor, 1)) {
$fuseForeground: (
base: black,
@@ -145,47 +129,43 @@ $matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A70
);
}
// Put down the color classes
#{$classes} {
// Native Input
input[type="text"] {
color: map_get($fuseForeground, base);
}
// Native Input
input[type="text"] {
color: map_get($fuseForeground, base);
}
// Input
.mat-input-placeholder {
color: map_get($fuseForeground, hint-text);
}
// Input
.mat-form-field-label {
color: map_get($fuseForeground, hint-text);
}
.mat-input-underline {
background-color: map_get($fuseForeground, divider);
}
.mat-form-field-underline {
background-color: map_get($fuseForeground, divider);
}
// Select
.mat-select-trigger,
.mat-select-arrow {
color: map_get($fuseForeground, hint-text);
}
// Select
.mat-select-trigger,
.mat-select-arrow {
color: map_get($fuseForeground, hint-text);
}
.mat-select-underline {
background-color: map_get($fuseForeground, divider);
}
.mat-select-underline {
background-color: map_get($fuseForeground, divider);
}
.mat-select-disabled .mat-select-value,
.mat-select-arrow,
.mat-select-trigger {
color: map_get($fuseForeground, hint-text);
}
.mat-select-disabled .mat-select-value,
.mat-select-arrow,
.mat-select-trigger {
color: map_get($fuseForeground, hint-text);
}
.mat-select-content,
.mat-select-panel-done-animating {
background: map_get($background, card);
}
.mat-select-content,
.mat-select-panel-done-animating {
background: map_get($background, card);
}
.mat-select-value {
color: map_get($fuseForeground, text);
}
.mat-select-value {
color: map_get($fuseForeground, text);
}
}
@@ -200,6 +180,14 @@ $matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A70
background-color: $color !important;
color: $contrastColor !important;
// Generate text color levels
// based on current contrast color
@include generateTextColorLevels($contrastColor);
// Generate material element colors
// based on current contrast color
@include generateMaterialElementColors($contrastColor);
&[disabled] {
background-color: rgba($color, .12) !important;
color: rgba($contrastColor, .26) !important;
@@ -208,6 +196,14 @@ $matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A70
.#{$colorName}#{$hue}-fg {
color: $color !important;
// Generate text color levels
// based on current contrast color
@include generateTextColorLevels($color);
// Generate material element colors
// based on current contrast color
@include generateMaterialElementColors($color);
}
.#{$colorName}#{$hue}-border {
@@ -231,128 +227,22 @@ $matHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A70
}
}
@mixin generateFuseColorClasses($primary, $accent, $warn) {
$palettes: (
primary: $primary,
accent: $accent,
warn: $warn
);
// Define contrast lists
$light-contrasting-classes: ();
$dark-contrasting-classes: ();
// Generate the color classes...
@each $paletteName, $palette in $palettes {
// Get the contrasts map
$contrasts: map-get($palette, 'contrast');
@each $hue in $matHues {
// Get the color and the contrasting color
$color: map-get($palette, $hue);
$contrast: map-get($contrasts, $hue);
@if ($color != null and $contrast != null) {
// Generate color classes
@include generateColorClasses($paletteName, $color, $contrast, '-#{$hue}');
// If the contrast color is dark
@if (rgba(black, 1) == rgba($contrast, 1)) {
$dark-contrasting-classes: append($dark-contrasting-classes, unquote('.mat-#{$paletteName}-#{$hue}-bg'), 'comma');
}
// if the contrast color is light
@else {
$light-contrasting-classes: append($light-contrasting-classes, unquote('.mat-#{$paletteName}-#{$hue}-bg'), 'comma');
}
// Run the generator one more time for default values (500)
@if ($hue == 500) {
// Generate color classes
@include generateColorClasses($paletteName, $color, $contrast, '');
// Add color to the correct list depending on the contrasting color
// If the contrast color is dark
@if (rgba(black, 1) == rgba($contrast, 1)) {
$dark-contrasting-classes: append($dark-contrasting-classes, unquote('.mat-#{$paletteName}-bg'), 'comma');
}
// if the contrast color is light
@else {
$light-contrasting-classes: append($light-contrasting-classes, unquote('.mat-#{$paletteName}-bg'), 'comma');
}
}
}
}
}
// Generate contrasting colors
@include generateTextColorLevels($dark-contrasting-classes, 'dark');
@include generateTextColorLevels($light-contrasting-classes, 'light');
@include generateMaterialElementColors($dark-contrasting-classes, 'dark');
@include generateMaterialElementColors($light-contrasting-classes, 'light');
}
// Generate the color classes...
@each $colorName, $colorMap in $matColorsMap {
// Define contrast lists
$light-contrasting-classes: ();
$dark-contrasting-classes: ();
@each $hue in $matColorHues {
@each $paletteName, $palette in $matPalettes {
$color: map-get($colorMap, $hue);
$contrastColor: map-get(map-get($colorMap, 'contrast'), $hue);
// Get the contrasts map
$contrasts: map-get($palette, 'contrast');
@if ($color != null and $contrastColor != null) {
@each $hue in $matHues {
// Get the color and the contrasting color
$color: map-get($palette, $hue);
$contrast: map-get($contrasts, $hue);
@if ($color != null and $contrast != null) {
// Generate color classes
@include generateColorClasses($paletteName, $color, $contrast, '-#{$hue}');
// Add color to the correct list depending on the contrasting color
// If the contrast color is dark
@if (rgba(black, 1) == rgba($contrast, 1)) {
$dark-contrasting-classes: append($dark-contrasting-classes, unquote('.mat-#{$paletteName}-#{$hue}-bg'), 'comma');
}
// if the contrast color is light
@else {
$light-contrasting-classes: append($light-contrasting-classes, unquote('.mat-#{$paletteName}-#{$hue}-bg'), 'comma');
}
@include generateColorClasses($colorName, $color, $contrastColor, '-#{$hue}');
// Run the generator one more time for default values (500)
@if ($hue == 500) {
// Generate color classes
@include generateColorClasses($paletteName, $color, $contrast, '');
// Add color to the correct list depending on the contrasting color
// If the contrast color is dark
@if (rgba(black, 1) == rgba($contrast, 1)) {
$dark-contrasting-classes: append($dark-contrasting-classes, unquote('.mat-#{$paletteName}-bg'), 'comma');
}
// if the contrast color is light
@else {
$light-contrasting-classes: append($light-contrasting-classes, unquote('.mat-#{$paletteName}-bg'), 'comma');
}
@include generateColorClasses($colorName, $color, $contrastColor, '');
}
}
}
}
// Generate contrasting colors
@include generateTextColorLevels($dark-contrasting-classes, 'dark');
@include generateTextColorLevels($light-contrasting-classes, 'light');
@include generateMaterialElementColors($dark-contrasting-classes, 'dark');
@include generateMaterialElementColors($light-contrasting-classes, 'light');

View File

@@ -1,42 +0,0 @@
.docs {
font-size: 16px;
> .content {
max-width: 980px;
> .main-title {
&:first-child {
margin-top: 0;
}
}
}
.main-title {
display: flex;
margin-top: 72px;
font-size: 24px;
}
.section-title {
display: inline-flex;
font-size: 18px;
margin-top: 24px;
border-bottom: 1px solid #F44336;
color: #F44336;
}
ol,
ul {
padding-left: 24px;
li {
margin-bottom: 12px;
line-height: 1.7;
}
}
p {
line-height: 1.7;
}
}

View File

@@ -1,13 +1,6 @@
html,
body {
display: flex;
flex: 1 0 auto;
width: 100%;
height: 100%;
max-height: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background: #F5F5F5;
}
> mat-sidenav-container {
height: 100%;
}
}

View File

@@ -1,5 +1,6 @@
i,
mat-icon {
color: rgba(0, 0, 0, 0.54);
font-size: 24px;
width: 24px;
height: 24px;

View File

@@ -42,7 +42,7 @@
color: currentColor;
> .nav-link-title {
flex: 1 1 auto;
flex: 1;
white-space: nowrap;
}
@@ -58,7 +58,7 @@
transition: opacity 0.2s ease-in-out 0.1s;
margin-left: 8px;
+ .collapsable-arrow {
+ .collapse-arrow {
margin-left: 8px;
}
}
@@ -72,9 +72,14 @@
}
&.active {
background-color: mat-color($accent);
.nav-link-icon {
opacity: 1;
.mat-ripple-element {
background-color: mat-color($accent, default-contrast, 0.1);
}
&, .nav-link-icon {
color: mat-color($accent, default-contrast);
}
.nav-link-badge {
@@ -85,11 +90,10 @@
.nav-link-icon {
margin-right: 16px;
opacity: 0.7;
}
.nav-link-icon,
.collapsable-arrow {
.collapse-arrow {
font-size: 16px;
width: 16px;
height: 16px;
@@ -99,7 +103,7 @@
}
}
&.nav-collapsable {
&.nav-collapse {
display: block;
> .children {
@@ -131,7 +135,7 @@
> .nav-item {
&.nav-collapsable {
&.nav-collapse {
background: transparent;
transition: background 200ms ease-in-out;
@@ -145,7 +149,7 @@
> .group-items {
> .nav-collapsable {
> .nav-collapse {
background: transparent;
transition: background 200ms ease-in-out;
@@ -172,7 +176,7 @@
.nav-item {
&.nav-collapsable {
&.nav-collapse {
position: relative;
.children {
@@ -201,13 +205,13 @@
height: 56px;
}
&.nav-collapsable {
&.nav-collapse {
position: relative;
> .nav-link {
height: 56px;
.collapsable-arrow {
.collapse-arrow {
display: none;
}
}
@@ -219,26 +223,4 @@
}
}
}
// Material style
&.material {
.nav-subheader {
border-top: 1px solid rgba(0, 0, 0, 0.12);
&:first-child {
border-top: none;
}
}
.nav-item {
.nav-link {
height: 40px;
padding: 0 16px;
margin: 4px 8px;
border-radius: 4px;
}
}
}
}

View File

@@ -10,9 +10,13 @@ $header-height-sm: 100px !default;
$carded-header-height-without-toolbar: $carded-header-height - $carded-toolbar-height;
$carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-toolbar-height;
// Top bg image
$top-bg-image: url('assets/images/backgrounds/header-bg.png');
.page-layout {
position: relative;
overflow: hidden;
overflow-x: hidden;
overflow-y: auto;
// Carded layout
&.carded {
@@ -23,13 +27,15 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
min-width: 100%;
// Top bg
> .top-bg {
.top-bg {
position: absolute;
z-index: 1;
top: 0;
right: 0;
left: 0;
height: $carded-header-height;
background-image: $top-bg-image;
background-size: cover;
@include media-breakpoint-down('sm') {
height: $carded-header-height-sm;
@@ -39,215 +45,29 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
// Fullwidth
&.fullwidth {
// Single scroll
&.single-scroll {
> .center {
flex: 1 0 auto;
max-height: none;
}
}
// Center
> .center {
display: flex;
flex-direction: column;
flex: 1 0 auto;
flex: 1;
position: relative;
z-index: 2;
padding: 0 32px;
width: 100%;
min-width: 0;
min-width: 100%;
max-width: 100%;
max-height: 100%;
> .header {
height: $carded-header-height-without-toolbar !important;
min-height: $carded-header-height-without-toolbar !important;
max-height: $carded-header-height-without-toolbar !important;
@include media-breakpoint-down('sm') {
height: $carded-header-height-without-toolbar-sm !important;
min-height: $carded-header-height-without-toolbar-sm !important;
max-height: $carded-header-height-without-toolbar-sm !important;
}
}
> .content-card {
display: flex;
flex-direction: column;
flex: 1 0 auto;
overflow: hidden;
@include mat-elevation(7);
> .toolbar {
display: flex;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
height: $carded-toolbar-height;
min-height: $carded-toolbar-height;
max-height: $carded-toolbar-height;
}
> .content {
flex: 1 0 auto;
}
}
}
// Tabbed
&.tabbed {
> .center {
width: 100%;
min-width: 0;
> .header {
flex: 1 1 auto;
}
> .content-card {
> .content {
display: flex;
> .mat-tab-group {
overflow: hidden;
.mat-tab-header {
.mat-tab-label {
height: 64px;
}
}
.mat-tab-body {
overflow: hidden;
.mat-tab-body-content {
overflow: hidden;
.tab-content {
position: relative;
width: 100%;
height: 100%;
}
}
}
}
}
}
}
}
// Inner scroll
&.inner-scroll {
flex: 1 1 auto;
> .center {
flex: 1 1 auto;
> .content-card {
flex: 1 1 auto;
> .content {
overflow: auto;
flex: 1 1 auto;
}
}
}
// Tabbed
&.tabbed {
> .center {
> .content-card {
> .content {
> .mat-tab-group {
.mat-tab-body {
.mat-tab-body-content {
.tab-content {
overflow: auto;
}
}
}
}
}
}
}
}
}
}
// Left / Right sidebar
&.left-sidebar,
&.right-sidebar {
flex-direction: row;
// Sidebar
> .sidebar {
display: flex;
flex-direction: column;
flex: 1 1 auto;
width: 240px;
min-width: 240px;
max-width: 240px;
height: auto;
overflow: hidden;
@include mat-elevation(7);
&.locked-open {
background: none;
box-shadow: none;
+ .center {
z-index: 1001;
}
&.left-positioned {
+ .center {
margin-left: 0;
}
}
&.right-positioned {
+ .center {
margin-right: 0;
}
}
}
.header {
height: $carded-header-height;
min-height: $carded-header-height;
max-height: $carded-header-height;
@include media-breakpoint-down('sm') {
height: $carded-header-height-sm;
min-height: $carded-header-height-sm;
max-height: $carded-header-height-sm;
}
}
.content {
background: transparent;
flex: 1 1 auto;
}
}
// Center
> .center {
display: flex;
flex-direction: column;
flex: 1 1 auto;
position: relative;
z-index: 3;
margin-left: 32px;
margin-right: 32px;
min-width: 0;
> .header {
display: flex;
height: $carded-header-height-without-toolbar;
min-height: $carded-header-height-without-toolbar;
max-height: $carded-header-height-without-toolbar;
@@ -259,32 +79,146 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
}
}
> .content-card {
.content-card {
display: flex;
flex-direction: column;
flex: 1 1 auto;
flex: 1;
overflow: hidden;
@include mat-elevation(7);
> .toolbar {
.toolbar {
display: flex;
justify-content: flex-start;
align-items: center;
flex: 1 1 auto;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
height: $carded-toolbar-height;
min-height: $carded-toolbar-height;
max-height: $carded-toolbar-height;
.sidebar-toggle {
margin: 0 8px 0 0 !important;
padding: 0 !important;
border-radius: 0;
}
}
> .content {
flex: 1 1 auto;
display: flex;
flex: 1;
overflow: auto;
}
}
}
}
// Left sidenav - Right sidenav
&.left-sidenav,
&.right-sidenav {
// Single scroll
&.single-scroll {
> mat-sidenav-container {
flex: 1 0 auto;
}
}
> mat-sidenav-container {
display: flex;
flex: 1;
background: none;
z-index: 2;
width: 100%;
.sidenav {
display: flex;
flex-direction: column;
flex: 1;
width: 240px;
min-width: 240px;
max-width: 240px;
height: auto;
z-index: 4;
overflow-y: hidden;
@include mat-elevation(7);
&.mat-is-locked-open {
background: none;
box-shadow: none;
}
.header {
height: $carded-header-height;
min-height: $carded-header-height;
max-height: $carded-header-height;
@include media-breakpoint-down('sm') {
height: $carded-header-height-sm;
min-height: $carded-header-height-sm;
max-height: $carded-header-height-sm;
}
}
.content {
background: transparent;
overflow: auto;
}
}
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
flex: 1;
height: auto;
overflow: visible;
// Center
.center {
display: flex;
flex-direction: column;
flex: 1;
position: relative;
z-index: 3;
margin-left: 32px;
margin-right: 32px;
.header {
display: flex;
height: $carded-header-height-without-toolbar;
min-height: $carded-header-height-without-toolbar;
max-height: $carded-header-height-without-toolbar;
@include media-breakpoint-down('sm') {
height: $carded-header-height-without-toolbar-sm;
min-height: $carded-header-height-without-toolbar-sm;
max-height: $carded-header-height-without-toolbar-sm;
}
}
.content-card {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
@include mat-elevation(7);
.toolbar {
display: flex;
justify-content: flex-start;
align-items: center;
flex: 1;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
height: $carded-toolbar-height;
min-height: $carded-toolbar-height;
max-height: $carded-toolbar-height;
.sidenav-toggle {
margin: 0 8px 0 0 !important;
padding: 0 !important;
border-radius: 0;
}
}
.content {
display: flex;
flex: 1;
overflow: auto;
}
}
}
}
}
@@ -292,93 +226,51 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
// Tabbed
&.tabbed {
> .center {
width: calc(100% - 32px);
min-width: 0;
> mat-sidenav-container {
@include media-breakpoint-down('md') {
width: calc(100% - 64px);
}
> .mat-sidenav-content,
> .mat-drawer-content {
width: calc(100% - 240px);
min-width: 0;
> .header {
flex: 1 1 auto;
}
.center {
width: calc(100% - 32px);
min-width: 0;
> .content-card {
@include media-breakpoint-down('md') {
width: calc(100% - 64px);
}
> .content {
display: flex;
.header {
flex: 1;
}
> .mat-tab-group {
overflow: hidden;
.content-card {
.mat-tab-header {
.content {
.mat-tab-label {
height: 64px;
}
}
.mat-tab-body {
overflow: hidden;
.mat-tab-body-content {
.mat-tab-group {
overflow: hidden;
.tab-content {
position: relative;
width: 100%;
height: 100%;
.mat-tab-header {
.mat-tab-label {
height: 64px;
}
}
}
}
}
}
}
}
}
// Inner scroll
&.inner-scroll {
flex: 1 1 auto;
.mat-tab-body {
overflow: hidden;
> .sidebar {
.mat-tab-body-content {
overflow: hidden;
.content {
overflow: auto;
}
}
> .center {
flex: 1 1 auto;
> .content-card {
flex: 1 1 auto;
> .content {
flex: 1 1 auto;
overflow: auto;
}
}
}
// Tabbed
&.tabbed {
> .center {
> .content-card {
> .content {
> .mat-tab-group {
.mat-tab-body {
.mat-tab-body-content {
.tab-content {
overflow: auto;
.tab-content {
position: relative;
width: 100%;
height: 100%;
overflow: auto;
}
}
}
}
@@ -390,15 +282,48 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
}
}
// Right sidebar specific
&.right-sidebar {
// Left sidenav
&.left-sidenav {
> .sidebar {
order: 2;
// Sidenav
> mat-sidenav-container {
.sidenav {
&.mat-is-locked-open {
~ .mat-sidenav-content,
~ .mat-drawer-content {
.center {
margin-left: 0;
}
}
}
}
}
}
> .center {
order: 1;
// Right sidenav
&.right-sidenav {
// Sidenav
> mat-sidenav-container {
.sidenav {
order: 999;
&.mat-is-locked-open {
~ .mat-sidenav-content,
~ .mat-drawer-content {
.center {
margin-right: 0;
}
}
}
}
}
}
}
@@ -411,17 +336,20 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
width: 100%;
min-width: 100%;
// Top bg
> .header {
background-image: $top-bg-image;
background-size: cover;
}
// Fullwidth
&.fullwidth {
> .content {
flex: 1 1 auto;
min-width: 0;
}
overflow: auto;
}
&.fullwidth,
&.inner-sidebar {
&.inner-sidenav {
min-height: 100%;
> .header {
height: $header-height;
@@ -430,138 +358,109 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
}
}
// Left / Right sidebar
&.left-sidebar,
&.right-sidebar {
flex-direction: row;
// Left sidenav - Right sidenav
&.left-sidenav,
&.right-sidenav {
// Sidebar
> .sidebar {
width: 240px;
min-width: 240px;
max-width: 240px;
overflow: hidden;
@include mat-elevation(7);
// Single scroll
&.single-scroll {
&.locked-open {
background: none;
box-shadow: none;
> mat-sidenav-container {
flex: 1 0 auto;
+ .center {
z-index: 1001;
> .mat-sidenav-content,
> .mat-drawer-content {
flex: 1 0 auto;
max-height: none;
}
&.left-positioned {
+ .center {
margin-left: 0;
}
}
&.right-positioned {
+ .center {
margin-right: 0;
}
}
}
.content {
flex: 1 1 auto;
}
}
// Center
> .center {
position: relative;
// Inner Sidenav
&.inner-sidenav {
> mat-sidenav-container {
flex: 1;
.sidenav {
.sidenav-content {
height: 100%;
}
}
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
height: auto;
.center {
flex: 1;
min-height: 100%;
@include mat-elevation(0);
.content {
display: flex;
flex: 1 0 auto;
}
}
}
}
}
> mat-sidenav-container {
display: flex;
flex-direction: column;
flex: 1 1 auto;
z-index: 3;
min-width: 0;
@include mat-elevation(7);
flex: 1;
background: none;
z-index: 2;
width: 100%;
> .header {
height: $header-height;
min-height: $header-height;
max-height: $header-height;
}
.sidenav {
width: 240px;
min-width: 240px;
max-width: 240px;
z-index: 51;
@include mat-elevation(7);
> .content {
flex: 1 0 auto;
}
}
&.mat-is-locked-open {
width: 220px;
min-width: 220px;
max-width: 220px;
box-shadow: none;
background: transparent;
}
// Inner scroll
&.inner-scroll {
flex: 1 1 auto;
> .sidebar {
.content {
overflow: auto;
.sidenav-content {
height: 100%;
}
}
> .center {
flex: 1 1 auto;
overflow: auto;
}
}
// Inner Sidebar
&.inner-sidebar {
flex-direction: column;
overflow: hidden;
height: 100%;
> .content {
> .mat-sidenav-content,
> .mat-drawer-content {
display: flex;
min-height: 0;
flex: 1;
height: auto;
overflow: visible;
max-height: 100%;
> .sidebar {
.header {
height: $header-height;
min-height: $header-height;
max-height: $header-height;
background-image: $top-bg-image;
}
&.locked-open {
background: none;
box-shadow: none;
}
.center {
display: flex;
flex-direction: column;
flex: 1;
overflow: auto;
@include mat-elevation(7);
.content {
overflow: auto;
}
}
> .center {
flex: 1 1 auto;
overflow: auto;
}
}
}
}
// Right sidebar specific
&.right-sidebar {
> .sidebar {
order: 2;
}
> .center {
order: 1;
}
// Inner sidebar
&.inner-sidebar {
> .content {
> .sidebar {
order: 2;
}
> .center {
order: 1;
}
}
}
}
@@ -570,7 +469,7 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
&.tabbed {
min-height: 100%;
> .header {
.header {
height: $header-height;
min-height: $header-height;
max-height: $header-height;
@@ -578,7 +477,7 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
> .content {
> .mat-tab-group {
.mat-tab-group {
.mat-tab-labels {
padding: 0 24px;
@@ -596,6 +495,50 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
@include media-breakpoint-down('xs') {
// Activate single-scroll
&.carded {
&.fullwidth {
> .center {
flex: 1 0 auto;
max-height: none;
}
}
&.left-sidenav,
&.right-sidenav {
> mat-sidenav-container {
flex: 1 0 auto;
}
}
}
&.simple {
&.fullwidth {
> .content {
flex: 1 0 auto;
}
}
&.left-sidenav,
&.right-sidenav {
> mat-sidenav-container {
flex: 1 0 auto !important;
> .mat-sidenav-content,
> .mat-drawer-content {
flex: 1 0 auto;
}
}
}
}
// End - Activate single-scroll
// Smaller margins
&.carded {
@@ -606,11 +549,18 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
}
}
&.left-sidebar,
&.right-sidebar {
&.left-sidenav,
&.right-sidenav {
> .center {
margin: 0 16px;
> mat-sidenav-container {
> .mat-sidenav-content,
> .mat-drawer-content {
.center {
margin: 0 16px;
}
}
}
}
}

View File

@@ -34,13 +34,13 @@
}
/* General styles */
app {
fuse-root {
fuse-sidebar,
navbar,
toolbar,
footer,
.theme-options-button,
fuse-navbar-vertical,
fuse-navbar-horizontal,
fuse-toolbar,
fuse-footer,
fuse-quick-panel,
fuse-theme-options,
.ps > .ps__rail-x,
.ps > .ps__rail-y {

View File

@@ -28,7 +28,7 @@ html, body {
}
// Reset non angular-material input's default browser/os styles
*:not(mat-form-field) {
*:not(mat-input-container) {
> input {
border: none;
@@ -55,7 +55,7 @@ html, body {
}
}
*:not(mat-form-field) {
*:not(mat-input-container) {
> input[type="button"],
> button,

View File

@@ -274,119 +274,4 @@ strong {
// Nowrap
.text-nowrap {
white-space: nowrap;
}
// Changelog
.changelog {
.entry {
background: white;
margin-bottom: 24px;
padding: 24px 32px;
@include mat-elevation(2);
> .title {
display: flex;
align-items: center;
margin-bottom: 24px;
.version {
font-size: 24px;
}
.date {
margin-left: 8px;
font-size: 17px;
opacity: 0.54;
}
}
.groups {
div {
margin-bottom: 32px;
&:last-child {
margin-bottom: 0;
}
}
.title {
display: inline-flex;
font-size: 13px;
color: white;
letter-spacing: 0.015em;
line-height: 1;
padding: 5px 8px;
border-radius: 2px;
}
.breaking-changes {
.title {
background: #F44336;
}
}
.new {
.title {
background: #43A047;
}
}
.improved {
.title {
background: #673AB7;
}
}
.fixed {
.title {
background: #2196F3;
}
}
ul {
padding-left: 24px;
li {
margin-bottom: 6px;
letter-spacing: 0.015em;
}
}
}
}
}
// Message boxes
.message-box {
padding: 16px;
background: #607D8B;
border-left: 6px solid #37474F;
color: rgba(255, 255, 255, 1);
&.error {
background: #EF5350;
border-left-color: #B71C1C;
}
&.warning {
background: #FFECB3;
border-left-color: #FFC107;
color: rgba(0, 0, 0, 0.87);
}
&.success {
background: #4CAF50;
border-left-color: #2E7D32;
}
&.info {
background: #B3E5FC;
border-left-color: #03A9F4;
color: rgba(0, 0, 0, 0.87);
}
}

View File

@@ -104,9 +104,9 @@ $code-color-attr-name: #B65611 !default;
// whitespace management
white-space: pre; // fallback
//white-space: pre-wrap;
//word-break: break-all;
//word-wrap: break-word;
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
font-family: $code-font-family;
font-size: $code-font-size;

View File

@@ -1,6 +1,5 @@
@import '~@angular/material/theming';
// Custom color maps
$mat-white: (
500: white,
contrast: (
@@ -48,19 +47,13 @@ $mat-fusedark: (
)
);
// Define the Material palettes
// Palettes
$primary: mat-palette($mat-fusedark);
$accent: mat-palette($mat-light-blue, 600, 400, 700);
$warn: mat-palette($mat-red);
// Create the Material theme object
// Create the theme object (a Sass map containing all of the palettes).
$theme: mat-light-theme($primary, $accent, $warn);
// Store the background and foreground colors for easier access
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
// Force the input field font sizes to 16px
$typography: mat-typography-config(
$input: mat-typography-level(16px, 1.125, 400)
)

View File

@@ -1,157 +1,113 @@
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { Inject, Injectable, InjectionToken, Optional } from '@angular/core';
import { NavigationStart, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Platform } from '@angular/cdk/platform';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import * as _ from 'lodash';
// Create the injection token for the custom settings
// Define the default config
const DEFAULT_CONFIG = {
layout : {
navigation : 'left', // 'right', 'left', 'top', 'none'
navigationFolded: false, // true, false
toolbar : 'below', // 'above', 'below', 'none'
footer : 'below', // 'above', 'below', 'none'
mode : 'fullwidth' // 'boxed', 'fullwidth'
},
colorClasses : {
toolbar: 'mat-white-500-bg',
navbar : 'mat-fuse-dark-700-bg',
footer : 'mat-fuse-dark-900-bg'
},
customScrollbars: true,
routerAnimation : 'fadeIn' // fadeIn, slideUp, slideDown, slideRight, slideLeft, none
};
// Create the injection token for the custom config
export const FUSE_CONFIG = new InjectionToken('fuseCustomConfig');
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseConfigService
{
// Private
private _configSubject: BehaviorSubject<any>;
private readonly _defaultConfig: any;
config: any;
defaultConfig: any;
onConfigChanged: BehaviorSubject<any>;
/**
* Constructor
*
* @param {Platform} _platform
* @param {Router} _router
* @param _config
* @param router
* @param platform
* @param config
*/
constructor(
private _platform: Platform,
private _router: Router,
@Inject(FUSE_CONFIG) private _config
private router: Router,
public platform: Platform,
@Inject(FUSE_CONFIG) @Optional() config
)
{
// Set the default config from the user provided config (from forRoot)
this._defaultConfig = _config;
// Set the default settings from the constant
this.defaultConfig = DEFAULT_CONFIG;
// Initialize the service
this._init();
}
// If custom config provided with forRoot,
// use them as default config...
if ( config )
{
this.defaultConfig = config;
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Set and get the config
*/
set config(value)
{
// Get the value from the behavior subject
let config = this._configSubject.getValue();
// Merge the new config
config = _.merge({}, config, value);
// Notify the observers
this._configSubject.next(config);
}
get config(): any | Observable<any>
{
return this._configSubject.asObservable();
}
/**
* Get default config
*
* @returns {any}
*/
get defaultConfig(): any
{
return this._defaultConfig;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
/**
* Disable custom scrollbars if browser is mobile
* Disable Custom Scrollbars if Browser is Mobile
*/
if ( this._platform.ANDROID || this._platform.IOS )
if ( this.platform.ANDROID || this.platform.IOS )
{
this._defaultConfig.customScrollbars = false;
this.defaultConfig.customScrollbars = false;
}
// Set the config from the default config
this._configSubject = new BehaviorSubject(_.cloneDeep(this._defaultConfig));
this.config = {...this.defaultConfig};
// Reload the default config on every navigation start if
// the current config is different from the default one
this._router.events
.pipe(filter(event => event instanceof NavigationStart))
.subscribe(() => {
if ( !_.isEqual(this._configSubject.getValue(), this._defaultConfig) )
// Reload the default settings for the
// layout on every navigation start
router.events.subscribe(
(event) => {
if ( event instanceof NavigationStart )
{
// Clone the default config
const config = _.cloneDeep(this._defaultConfig);
// Set the config
this._configSubject.next(config);
this.setConfig({
layout: this.defaultConfig.layout
}
);
}
});
}
);
// Create the behavior subject
this.onConfigChanged = new BehaviorSubject(this.config);
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Set config
* Set the new config from given object
*
* @param value
* @param {{emitEvent: boolean}} opts
* @param config
*/
setConfig(value, opts = {emitEvent: true}): void
setConfig(config): void
{
// Get the value from the behavior subject
let config = this._configSubject.getValue();
// Set the config from the given object
// Ugly, but works for now...
this.config = {
...this.config,
...config,
layout : {
...this.config.layout,
...config.layout,
},
colorClasses: {
...this.config.colorClasses,
...config.colorClasses
}
};
// Merge the new config
config = _.merge({}, config, value);
// If emitEvent option is true...
if ( opts.emitEvent === true )
{
// Notify the observers
this._configSubject.next(config);
}
}
/**
* Get config
*
* @returns {Observable<any>}
*/
getConfig(): Observable<any>
{
return this._configSubject.asObservable();
}
/**
* Reset to the default config
*/
resetToDefaults(): void
{
// Set the config from the default config
this._configSubject.next(_.cloneDeep(this._defaultConfig));
// Trigger the event
this.onConfigChanged.next(this.config);
}
}

View File

@@ -1,31 +1,26 @@
/**
* This class is based on the code in the following projects:
* https://github.com/zenorocha/select
* https://github.com/zenorocha/clipboard.js/
*
* - https://github.com/zenorocha/select
* - https://github.com/zenorocha/clipboard.js/
*
* Both released under MIT license - © Zeno Rocha
*/
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseCopierService
{
private textarea: HTMLTextAreaElement;
/**
* Copy the text value to the clipboard
*
* @param {string} text
* @returns {boolean}
*/
/** Copy the text value to the clipboard. */
copyText(text: string): boolean
{
this.createTextareaAndSelect(text);
const copySuccessful = document.execCommand('copy');
this._removeFake();
this.removeFake();
return copySuccessful;
}
@@ -33,10 +28,8 @@ export class FuseCopierService
/**
* Creates a hidden textarea element, sets its value from `text` property,
* and makes a selection on it.
*
* @param {string} text
*/
private createTextareaAndSelect(text: string): void
private createTextareaAndSelect(text: string)
{
// Create a fake element to hold the contents to copy
this.textarea = document.createElement('textarea');
@@ -60,12 +53,8 @@ export class FuseCopierService
this.textarea.setSelectionRange(0, this.textarea.value.length);
}
/**
* Remove the text area from the DOM
*
* @private
*/
private _removeFake(): void
/** Remove the text area from the DOM. */
private removeFake()
{
if ( this.textarea )
{

View File

@@ -1,91 +0,0 @@
import { Injectable } from '@angular/core';
import { NavigationEnd, NavigationStart, Router } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class FuseLoadingBarService
{
// Private
private _visible: BehaviorSubject<boolean>;
/**
* Constructor
*
* @param {Router} _router
*/
constructor(
private _router: Router
)
{
// Initialize the service
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
get visible(): Observable<any>
{
// Return the _visible as observable
return this._visible.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
// Initialize the behavior subject
this._visible = new BehaviorSubject(false);
// Subscribe to the router events to show/hide the loading bar
this._router.events
.pipe(
filter((event) => event instanceof NavigationStart)
)
.subscribe(() => {
this.showLoadingBar();
});
this._router.events
.pipe(
filter((event) => event instanceof NavigationEnd)
)
.subscribe(() => {
this.hideLoadingBar();
});
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Show the loading bar
*/
showLoadingBar(): void
{
// Show
this._visible.next(true);
}
/**
* Hide the loading bar
*/
hideLoadingBar(): void
{
// Hide
this._visible.next(false);
}
}

View File

@@ -1,51 +1,23 @@
import { MediaChange, ObservableMedia } from '@angular/flex-layout';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseMatchMediaService
{
activeMediaQuery: string;
onMediaChange: BehaviorSubject<string> = new BehaviorSubject<string>('');
/**
* Constructor
*
* @param {ObservableMedia} _observableMedia
*/
constructor(
private _observableMedia: ObservableMedia
)
constructor(private observableMedia: ObservableMedia)
{
// Set the defaults
this.activeMediaQuery = '';
// Initialize
this._init();
this.observableMedia.subscribe((change: MediaChange) => {
if ( this.activeMediaQuery !== change.mqAlias )
{
this.activeMediaQuery = change.mqAlias;
this.onMediaChange.next(change.mqAlias);
}
});
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
this._observableMedia
.subscribe((change: MediaChange) => {
if ( this.activeMediaQuery !== change.mqAlias )
{
this.activeMediaQuery = change.mqAlias;
this.onMediaChange.next(change.mqAlias);
}
});
}
}

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