Compare commits

..

83 Commits

Author SHA1 Message Date
Sercan Yemen
3bd2ad9519 Merge branch 'master' into skeleton 2018-05-09 18:18:30 +03:00
Sercan Yemen
eb231c5ca8 angular.json for skeleton 2018-05-06 14:47:26 +03:00
Sercan Yemen
954d61b73a Merge branch 'master' into skeleton 2018-05-06 14:47:07 +03:00
Sercan Yemen
46c37042a2 Merge branch 'master' into skeleton 2018-04-04 14:42:49 +03:00
Sercan Yemen
47ee65a980 Merge branch 'master' into skeleton 2018-03-31 13:22:27 +03:00
Sercan Yemen
5f974c4ed2 Merge branch 'master' into skeleton 2018-03-11 18:27:10 +03:00
Sercan Yemen
605f4d9463 Merge branch 'master' into skeleton 2018-03-10 14:35:24 +03:00
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
1291 changed files with 3437 additions and 79142 deletions

View File

@@ -1,6 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*] [*]
charset=utf-8 charset = utf-8
end_of_line=lf indent_style = space
insert_final_newline=false indent_size = 2
indent_style=space insert_final_newline = true
indent_size=4 trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

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 6+ and Angular Material 2
## The Community ## The Community

View File

@@ -24,8 +24,7 @@
"tsConfig": "src/tsconfig.app.json", "tsConfig": "src/tsconfig.app.json",
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets", "src/assets"
"src/app/main/angular-material-elements"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss"
@@ -49,18 +48,6 @@
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true "buildOptimizer": true
},
"ec": {
"sourceMap": true,
"extractCss": true
},
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
} }
} }
}, },
@@ -75,10 +62,12 @@
}, },
"hmr": { "hmr": {
"hmr": true, "hmr": true,
"browserTarget": "fuse:build:hmr" "fileReplacements": [
}, {
"ec": { "replace": "src/environments/environment.ts",
"browserTarget": "fuse:build:ec" "with": "src/environments/environment.hmr.ts"
}
]
} }
} }
}, },
@@ -113,9 +102,7 @@
"src/tsconfig.spec.json" "src/tsconfig.spec.json"
], ],
"exclude": [ "exclude": [
"**/node_modules/**", "**/node_modules/**"
"**/src/app/fake-db/**/*",
"**/src/assets/angular-material-examples/**/*"
] ]
} }
} }
@@ -137,9 +124,7 @@
"options": { "options": {
"tsConfig": "e2e/tsconfig.e2e.json", "tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [ "exclude": [
"**/node_modules/**", "**/node_modules/**"
"**/src/app/fake-db/**/*",
"**/src/assets/angular-material-examples/**/*"
] ]
} }
} }

2389
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
{ {
"name": "fuse", "name": "fuse",
"version": "6.2.1", "version": "6.0.1",
"license": "https://themeforest.net/licenses/terms/regular", "license": "https://themeforest.net/licenses/terms/regular",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --open", "start": "ng serve --open",
"start-hmr": "ng serve --configuration hmr --source-map=false --hmr-warning=false", "start-hmr": "ng serve --configuration hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --configuration hmr --source-map=true --hmr-warning=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": "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-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", "build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
@@ -18,71 +18,71 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@agm/core": "1.0.0-beta.3", "@agm/core": "1.0.0-beta.2",
"@angular/animations": "6.0.7", "@angular/animations": "6.0.0",
"@angular/cdk": "6.3.3", "@angular/cdk": "6.0.1",
"@angular/common": "6.0.7", "@angular/common": "6.0.0",
"@angular/compiler": "6.0.7", "@angular/compiler": "6.0.0",
"@angular/core": "6.0.7", "@angular/core": "6.0.0",
"@angular/flex-layout": "6.0.0-beta.16", "@angular/flex-layout": "6.0.0-beta.15",
"@angular/forms": "6.0.7", "@angular/forms": "6.0.0",
"@angular/http": "6.0.7", "@angular/http": "6.0.0",
"@angular/material": "6.3.3", "@angular/material": "6.0.1",
"@angular/material-moment-adapter": "6.3.3", "@angular/material-moment-adapter": "6.0.1",
"@angular/platform-browser": "6.0.7", "@angular/platform-browser": "6.0.0",
"@angular/platform-browser-dynamic": "6.0.7", "@angular/platform-browser-dynamic": "6.0.0",
"@angular/router": "6.0.7", "@angular/router": "6.0.0",
"@ngrx/effects": "6.0.1", "@ngrx/effects": "6.0.0-beta.1",
"@ngrx/router-store": "6.0.1", "@ngrx/router-store": "6.0.0-beta.1",
"@ngrx/store": "6.0.1", "@ngrx/store": "6.0.0-beta.1",
"@ngrx/store-devtools": "6.0.1", "@ngrx/store-devtools": "6.0.0-beta.1",
"@ngx-translate/core": "10.0.2", "@ngx-translate/core": "10.0.1",
"@swimlane/ngx-charts": "8.1.0", "@swimlane/ngx-charts": "8.0.0",
"@swimlane/ngx-datatable": "13.0.1", "@swimlane/ngx-datatable": "12.0.0",
"@swimlane/ngx-dnd": "4.0.0", "@swimlane/ngx-dnd": "4.0.0",
"@types/prismjs": "1.9.0", "@types/prismjs": "1.9.0",
"angular-calendar": "0.25.2", "angular-calendar": "0.24.0",
"angular-in-memory-web-api": "0.6.0", "angular-in-memory-web-api": "0.6.0",
"chart.js": "2.7.2", "chart.js": "2.7.2",
"classlist.js": "1.1.20150312", "classlist.js": "1.1.20150312",
"core-js": "2.5.7", "core-js": "2.5.6",
"d3": "5.5.0", "d3": "5.2.0",
"hammerjs": "2.0.8", "hammerjs": "2.0.8",
"lodash": "4.17.10", "lodash": "4.17.10",
"moment": "2.22.2", "moment": "2.22.1",
"ng2-charts": "1.6.0", "ng2-charts": "1.6.0",
"ngrx-store-freeze": "0.2.4", "ngrx-store-freeze": "0.2.2",
"ngx-color-picker": "6.4.0", "ngx-color-picker": "6.0.0",
"ngx-cookie-service": "1.0.10", "ngx-cookie-service": "1.0.10",
"perfect-scrollbar": "1.4.0", "perfect-scrollbar": "1.3.0",
"prismjs": "1.15.0", "prismjs": "1.14.0",
"rxjs": "6.2.1", "rxjs": "6.1.0",
"rxjs-compat": "6.2.1", "rxjs-compat": "6.1.0",
"web-animations-js": "2.3.1", "web-animations-js": "2.3.1",
"zone.js": "0.8.26" "zone.js": "0.8.26"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "6.0.8", "@angular/cli": "6.0.0",
"@angular/compiler-cli": "6.0.7", "@angular/compiler-cli": "6.0.0",
"@angular/language-service": "6.0.7", "@angular/language-service": "6.0.0",
"@angular-devkit/build-angular": "0.6.8", "@angular-devkit/build-angular": "0.6.0",
"@angularclass/hmr": "2.1.3", "@angularclass/hmr": "2.1.3",
"@types/jasmine": "2.8.8", "@types/jasmine": "2.8.7",
"@types/jasminewd2": "2.0.3", "@types/jasminewd2": "2.0.3",
"@types/lodash": "4.14.110", "@types/lodash": "4.14.108",
"@types/node": "8.9.5", "@types/node": "8.9.5",
"codelyzer": "4.2.1", "codelyzer": "4.2.1",
"jasmine-core": "2.99.1", "jasmine-core": "2.99.1",
"jasmine-spec-reporter": "4.2.1", "jasmine-spec-reporter": "4.2.1",
"karma": "1.7.1", "karma": "1.7.1",
"karma-chrome-launcher": "2.2.0", "karma-chrome-launcher": "2.2.0",
"karma-coverage-istanbul-reporter": "2.0.1", "karma-coverage-istanbul-reporter": "1.4.2",
"karma-jasmine": "1.1.2", "karma-jasmine": "1.1.2",
"karma-jasmine-html-reporter": "0.2.2", "karma-jasmine-html-reporter": "0.2.2",
"protractor": "5.3.2", "protractor": "5.3.1",
"ts-node": "5.0.1", "ts-node": "5.0.1",
"tslint": "5.9.1", "tslint": "5.9.1",
"typescript": "2.7.2", "typescript": "2.7.2",
"webpack-bundle-analyzer": "2.13.1" "webpack-bundle-analyzer": "2.11.1"
} }
} }

View File

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

View File

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

View File

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

View File

@@ -7,9 +7,6 @@ import { Component } from '@angular/core';
}) })
export class FuseDemoContentComponent export class FuseDemoContentComponent
{ {
/**
* Constructor
*/
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> <mat-list>
<h3 matSubheader>Sidebar Demo</h3> <h3 matSubheader>Sidenav Demo</h3>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 1</span> <span>Sidenav Item 1</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 2</span> <span>Sidenav Item 2</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 3</span> <span>Sidenav Item 3</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 4</span> <span>Sidenav Item 4</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 5</span> <span>Sidenav Item 5</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 6</span> <span>Sidenav Item 6</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 7</span> <span>Sidenav Item 7</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 8</span> <span>Sidenav Item 8</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 9</span> <span>Sidenav Item 9</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 10</span> <span>Sidenav Item 10</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 11</span> <span>Sidenav Item 11</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 12</span> <span>Sidenav Item 12</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 13</span> <span>Sidenav Item 13</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 14</span> <span>Sidenav Item 14</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 15</span> <span>Sidenav Item 15</span>
</mat-list-item> </mat-list-item>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-list-item> <mat-list-item>
<span>Sidebar Item 16</span> <span>Sidenav Item 16</span>
</mat-list-item> </mat-list-item>
</mat-list> </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 { MatDividerModule, MatListModule } from '@angular/material';
import { FuseDemoContentComponent } from './demo-content/demo-content.component'; 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({ @NgModule({
declarations: [ declarations: [
FuseDemoContentComponent, FuseDemoContentComponent,
FuseDemoSidebarComponent FuseDemoSidenavComponent
], ],
imports : [ imports : [
RouterModule, RouterModule,
@@ -19,7 +19,7 @@ import { FuseDemoSidebarComponent } from './demo-sidebar/demo-sidebar.component'
], ],
exports : [ exports : [
FuseDemoContentComponent, FuseDemoContentComponent,
FuseDemoSidebarComponent FuseDemoSidenavComponent
] ]
}) })
export class FuseDemoModule export class FuseDemoModule

View File

@@ -3,5 +3,4 @@
padding: 8px; padding: 8px;
background: #263238; background: #263238;
cursor: text; 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 { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import * as Prism from 'prismjs/prism'; import * as Prism from 'prismjs/prism';
import '@fuse/components/highlight/prism-languages'; import './prism-languages';
@Component({ @Component({
selector : 'fuse-highlight', selector : 'fuse-highlight',
template : '', template : ' ',
styleUrls: ['./highlight.component.scss'] styleUrls: ['./highlight.component.scss']
}) })
export class FuseHighlightComponent implements OnInit, OnDestroy export class FuseHighlightComponent implements OnInit
{ {
// Source @ContentChild('source') source: ElementRef;
@ContentChild('source') @Input('lang') lang: string;
source: ElementRef; @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( constructor(
private _elementRef: ElementRef, private elementRef: ElementRef,
private _httpClient: HttpClient private http: HttpClient
) )
{ {
// Set the private defaults
this._unsubscribeAll = new Subject();
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{ {
// If there is no language defined, return... // If there is no language defined, return...
if ( !this.lang ) if ( !this.lang )
@@ -61,13 +34,11 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
if ( this.path ) if ( this.path )
{ {
// Get the source // Get the source
this._httpClient.get(this.path, {responseType: 'text'}) this.http.get(this.path, {responseType: 'text'}).subscribe((response) => {
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((response) => {
// Highlight it // Highlight it
this.highlight(response); this.highlight(response);
}); });
} }
// If the path is not defined and the source element exists... // If the path is not defined and the source element exists...
@@ -78,26 +49,7 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
} }
} }
/** highlight(sourceCode)
* 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
{ {
// Split the source into lines // Split the source into lines
const sourceLines = sourceCode.split('\n'); const sourceLines = sourceCode.split('\n');
@@ -142,8 +94,9 @@ export class FuseHighlightComponent implements OnInit, OnDestroy
const highlightedCode = Prism.highlight(source, Prism.languages[this.lang]); const highlightedCode = Prism.highlight(source, Prism.languages[this.lang]);
// Replace the innerHTML of the component with the highlighted code // 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>'; '<pre><code class="highlight language-' + this.lang + '">' + highlightedCode + '</code></pre>';
} }
} }

View File

@@ -1,5 +1,4 @@
import 'prismjs/prism'; import 'prismjs/prism';
import 'prismjs/components/prism-bash';
import 'prismjs/components/prism-c'; import 'prismjs/components/prism-c';
import 'prismjs/components/prism-cpp'; import 'prismjs/components/prism-cpp';
import 'prismjs/components/prism-csharp'; import 'prismjs/components/prism-csharp';

View File

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

View File

@@ -1,6 +1,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material'; import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material';
import { FusePipesModule } from '@fuse/pipes/pipes.module'; 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,52 @@
<ng-container *ngIf="!item.hidden">
<!-- normal collapse -->
<a class="nav-link" *ngIf="!item.url && !item.function" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.url -->
<a class="nav-link" *ngIf="item.url && !item.function"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" *ngIf="!item.url && item.function" (click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" *ngIf="item.url && item.function" (click)="item.function()"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" 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="collapse-arrow">keyboard_arrow_right</mat-icon>
</ng-template>
<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>
</ng-container>

View File

@@ -0,0 +1,51 @@
import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { fuseAnimations } from '../../../../animations/index';
import { FuseConfigService } from '../../../../services/config.service';
@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,30 @@
<ng-container *ngIf="!item.hidden">
<!-- item.url -->
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" *ngIf="item.function" (click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" *ngIf="item.url && item.function" (click)="item.function()"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" 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

@@ -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 --> <!-- Vertical Navigation Layout -->
<ng-container *ngIf="layout === 'vertical'"> <ng-container *ngIf="layout === 'vertical'">
@@ -6,7 +7,7 @@
<ng-container *ngFor="let item of navigation"> <ng-container *ngFor="let item of navigation">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group> <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> <fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container> </ng-container>
@@ -19,9 +20,8 @@
<ng-container *ngFor="let item of navigation"> <ng-container *ngFor="let item of navigation">
<fuse-nav-horizontal-collapsable *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapsable> <fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapsable *ngIf="item.type=='collapse'" <fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
[item]="item"></fuse-nav-horizontal-collapsable>
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item> <fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
</ng-container> </ng-container>

View File

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

View File

@@ -1,8 +1,4 @@
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Input, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({ @Component({
selector : 'fuse-navigation', selector : 'fuse-navigation',
@@ -10,45 +6,13 @@ import { FuseNavigationService } from '@fuse/components/navigation/navigation.se
styleUrls : ['./navigation.component.scss'], styleUrls : ['./navigation.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class FuseNavigationComponent implements OnInit export class FuseNavigationComponent
{ {
@Input() @Input() layout = 'vertical';
layout = 'vertical'; @Input() navigation: any;
@Input() constructor()
navigation: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
constructor(
private _fuseNavigationService: FuseNavigationService
)
{ {
// 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 { TranslateModule } from '@ngx-translate/core';
import { FuseNavigationComponent } from './navigation.component'; import { FuseNavigationComponent } from './navigation.component';
import { FuseNavVerticalItemComponent } from './vertical/item/item.component'; import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component';
import { FuseNavVerticalCollapsableComponent } from './vertical/collapsable/collapsable.component'; import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component';
import { FuseNavVerticalGroupComponent } from './vertical/group/group.component'; import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/item/item.component'; import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component';
import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/collapsable.component'; import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component';
@NgModule({ @NgModule({
imports : [ imports : [
@@ -29,9 +29,9 @@ import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/
FuseNavigationComponent, FuseNavigationComponent,
FuseNavVerticalGroupComponent, FuseNavVerticalGroupComponent,
FuseNavVerticalItemComponent, FuseNavVerticalItemComponent,
FuseNavVerticalCollapsableComponent, FuseNavVerticalCollapseComponent,
FuseNavHorizontalItemComponent, FuseNavHorizontalItemComponent,
FuseNavHorizontalCollapsableComponent FuseNavHorizontalCollapseComponent
] ]
}) })
export class FuseNavigationModule export class FuseNavigationModule

View File

@@ -1,350 +1,48 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { FuseNavigationItem } from '@fuse/types'; @Injectable()
@Injectable({
providedIn: 'root'
})
export class FuseNavigationService export class FuseNavigationService
{ {
onItemCollapsed: Subject<any>; flatNavigation: any[] = [];
onItemCollapseToggled: Subject<any>;
// Private onItemCollapsed: Subject<any> = new Subject;
private _onNavigationChanged: BehaviorSubject<any>; onItemCollapseToggled: Subject<any> = new Subject;
private _onNavigationRegistered: BehaviorSubject<any>;
private _onNavigationUnregistered: BehaviorSubject<any>;
private _currentNavigationKey: string;
private _registry: { [key: string]: any } = {};
/**
* Constructor
*/
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 * Get flattened navigation array
*
* @param navigation * @param navigation
* @param flatNavigation
* @returns {any[]} * @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; 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; return this.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);
} }
} }

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,45 @@
<ng-container *ngIf="!item.hidden">
<!-- normal collapse -->
<a class="nav-link" *ngIf="!item.url && !item.function" (click)="toggleOpen($event)" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.url -->
<a class="nav-link" *ngIf="item.url && !item.function" (click)="toggleOpen($event)"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" *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" *ngIf="item.url && item.function" (click)="toggleOpen($event);item.function()"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" 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="collapse-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-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 { .nav-link {
.collapsable-arrow { .collapse-arrow {
transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s; transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s;
transform: rotate(0); transform: rotate(0);
} }
@@ -34,9 +34,13 @@
> .nav-link { > .nav-link {
.collapsable-arrow { .collapse-arrow {
transform: rotate(90deg); 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 { NavigationEnd, Router } from '@angular/router';
import { Subject } from 'rxjs'; import { fuseAnimations } from '../../../../animations/index';
import { filter, takeUntil } from 'rxjs/operators';
import { FuseNavigationItem } from '@fuse/types';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({ @Component({
selector : 'fuse-nav-vertical-collapsable', selector : 'fuse-nav-vertical-collapse',
templateUrl: './collapsable.component.html', templateUrl: './nav-vertical-collapse.component.html',
styleUrls : ['./collapsable.component.scss'], styleUrls : ['./nav-vertical-collapse.component.scss'],
animations : fuseAnimations animations : fuseAnimations
}) })
export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy export class FuseNavVerticalCollapseComponent implements OnInit
{ {
@Input() @Input() item: any;
item: FuseNavigationItem; @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( constructor(
private _fuseNavigationService: FuseNavigationService, private navigationService: FuseNavigationService,
private _router: Router private router: Router
) )
{ {
// Set the private defaults // Listen for route changes
this._unsubscribeAll = new Subject(); router.events.subscribe(
} (event) => {
if ( event instanceof NavigationEnd )
// -----------------------------------------------------------------------------------------------------
// @ 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) )
{ {
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 // Listen for collapsing of any navigation item
this._fuseNavigationService.onItemCollapsed this.navigationService.onItemCollapsed
.pipe(takeUntil(this._unsubscribeAll))
.subscribe( .subscribe(
(clickedItem) => { (clickedItem) => {
if ( clickedItem && clickedItem.children ) if ( clickedItem && clickedItem.children )
@@ -87,7 +54,7 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
// Check if the url can be found in // Check if the url can be found in
// one of the children of this item // one of the children of this item
if ( this.isUrlInChildren(this.item, this._router.url) ) if ( this.isUrlInChildren(this.item, this.router.url) )
{ {
return; return;
} }
@@ -100,10 +67,13 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
} }
} }
); );
}
ngOnInit()
{
// Check if the url can be found in // Check if the url can be found in
// one of the children of this item // 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(); 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 * Toggle collapse
* *
* @param ev * @param ev
*/ */
toggleOpen(ev): void toggleOpen(ev)
{ {
ev.preventDefault(); ev.preventDefault();
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
// Navigation collapse toggled... // Navigation collapse toggled...
this._fuseNavigationService.onItemCollapsed.next(this.item); this.navigationService.onItemCollapsed.next(this.item);
this._fuseNavigationService.onItemCollapseToggled.next(); this.navigationService.onItemCollapseToggled.next();
} }
/** /**
* Expand the collapsable navigation * Expand the collapsable navigation
*/ */
expand(): void expand()
{ {
if ( this.isOpen ) if ( this.isOpen )
{ {
@@ -154,13 +110,13 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
} }
this.isOpen = true; this.isOpen = true;
this._fuseNavigationService.onItemCollapseToggled.next(); this.navigationService.onItemCollapseToggled.next();
} }
/** /**
* Collapse the collapsable navigation * Collapse the collapsable navigation
*/ */
collapse(): void collapse()
{ {
if ( !this.isOpen ) if ( !this.isOpen )
{ {
@@ -168,7 +124,7 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
} }
this.isOpen = false; this.isOpen = false;
this._fuseNavigationService.onItemCollapseToggled.next(); this.navigationService.onItemCollapseToggled.next();
} }
/** /**
@@ -177,9 +133,9 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
* *
* @param parent * @param parent
* @param item * @param item
* @returns {boolean} * @return {any}
*/ */
isChildrenOf(parent, item): boolean isChildrenOf(parent, item)
{ {
if ( !parent.children ) if ( !parent.children )
{ {
@@ -206,9 +162,9 @@ export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
* *
* @param parent * @param parent
* @param url * @param url
* @returns {boolean} * @returns {any}
*/ */
isUrlInChildren(parent, url): boolean isUrlInChildren(parent, url)
{ {
if ( !parent.children ) if ( !parent.children )
{ {

View File

@@ -1,14 +1,13 @@
<ng-container *ngIf="!item.hidden"> <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> <span class="hint-text" [translate]="item.translate">{{ item.title }}</span>
</div> </div>
<div class="group-items"> <div class="group-items">
<ng-container *ngFor="let item of item.children"> <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-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapsable *ngIf="item.type=='collapsable'" <fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
[item]="item"></fuse-nav-vertical-collapsable>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item> <fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container> </ng-container>
</div> </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,31 @@
<ng-container *ngIf="!item.hidden">
<!-- item.url -->
<a class="nav-link" *ngIf="item.url && !item.function"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" *ngIf="!item.url && item.function" (click)="item.function()" matRipple>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</span>
<!-- item.url && item.function -->
<a class="nav-link" *ngIf="item.url && item.function" (click)="item.function()"
[routerLink]="[item.url]" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" 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

@@ -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,11 +1,11 @@
<div class="fuse-search-bar" [ngClass]="{'expanded':!collapsed}"> <div class="fuse-search-bar" [ngClass]="{'expanded':!collapsed}">
<div class="fuse-search-bar-content" [ngClass]="fuseConfig.layout.toolbar.background"> <div class="fuse-search-bar-content" [ngClass]="toolbarColor">
<label for="fuse-search-bar-input"> <label for="fuse-search-bar-input">
<button mat-icon-button class="fuse-search-bar-expander" aria-label="Expand Search Bar" (click)="expand()" <button mat-icon-button class="fuse-search-bar-expander" aria-label="Expand Search Bar" (click)="expand()"
*ngIf="collapsed"> *ngIf="collapsed">
<mat-icon class="s-24 secondary-text">search</mat-icon> <mat-icon class="s-24">search</mat-icon>
</button> </button>
<!--<span class="fuse-search-bar-loader" fxLayout="row" fxLayoutAlign="center center" *ngIf="!collapsed"> <!--<span class="fuse-search-bar-loader" fxLayout="row" fxLayoutAlign="center center" *ngIf="!collapsed">
<mat-progress-spinner color="mat-accent" mode="indeterminate"></mat-progress-spinner> <mat-progress-spinner color="mat-accent" mode="indeterminate"></mat-progress-spinner>
@@ -17,7 +17,7 @@
<button mat-icon-button class="fuse-search-bar-collapser" (click)="collapse()" <button mat-icon-button class="fuse-search-bar-collapser" (click)="collapse()"
aria-label="Collapse Search Bar"> aria-label="Collapse Search Bar">
<mat-icon class="s-24 secondary-text">close</mat-icon> <mat-icon class="s-24">close</mat-icon>
</button> </button>
</div> </div>

View File

@@ -9,7 +9,7 @@
height: 64px; height: 64px;
font-size: 13px; font-size: 13px;
@include media-breakpoint-down('xs') { @include media-breakpoint-down('sm') {
height: 56px; height: 56px;
} }
@@ -28,7 +28,7 @@
height: 64px !important; height: 64px !important;
line-height: 64px !important; line-height: 64px !important;
@include media-breakpoint-down('xs') { @include media-breakpoint-down('sm') {
height: 56px !important; height: 56px !important;
line-height: 56px !important; line-height: 56px !important;
} }
@@ -39,7 +39,7 @@
height: 64px !important; height: 64px !important;
line-height: 64px !important; line-height: 64px !important;
@include media-breakpoint-down('xs') { @include media-breakpoint-down('sm') {
height: 56px !important; height: 56px !important;
line-height: 56px !important; line-height: 56px !important;
} }

View File

@@ -1,6 +1,5 @@
import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core';
import { Subject } from 'rxjs'; import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseConfigService } from '@fuse/services/config.service'; import { FuseConfigService } from '@fuse/services/config.service';
@@ -9,91 +8,42 @@ import { FuseConfigService } from '@fuse/services/config.service';
templateUrl: './search-bar.component.html', templateUrl: './search-bar.component.html',
styleUrls : ['./search-bar.component.scss'] styleUrls : ['./search-bar.component.scss']
}) })
export class FuseSearchBarComponent implements OnInit, OnDestroy export class FuseSearchBarComponent
{ {
collapsed: boolean; 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( constructor(
private _fuseConfigService: FuseConfigService private fuseConfig: FuseConfigService
) )
{ {
// Set the defaults
this.input = new EventEmitter();
this.collapsed = true; this.collapsed = true;
this.onConfigChanged =
// Set the private defaults this.fuseConfig.onConfigChanged
this._unsubscribeAll = new Subject(); .subscribe(
(newSettings) => {
this.toolbarColor = newSettings.colorClasses.toolbar;
}
);
} }
// ----------------------------------------------------------------------------------------------------- collapse()
// @ 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
{ {
this.collapsed = true; this.collapsed = true;
} }
/** expand()
* Expand
*/
expand(): void
{ {
this.collapsed = false; this.collapsed = false;
} }
/** search(event)
* Search
*
* @param event
*/
search(event): void
{ {
this.input.emit(event.target.value); const value = event.target.value;
this.onInput.emit(value);
} }
} }

View File

@@ -7,7 +7,7 @@
</button> </button>
</div> </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"> <div fxLayout="row" fxLayoutAlign="space-between center" fxFlex="0 1 auto">

View File

@@ -1,11 +1,12 @@
import { Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core'; import { Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ObservableMedia } from '@angular/flex-layout'; import { ObservableMedia } from '@angular/flex-layout';
import { Subscription } from 'rxjs';
import { CookieService } from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMatchMediaService } from '@fuse/services/match-media.service'; import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseConfigService } from '@fuse/services/config.service';
@Component({ @Component({
selector : 'fuse-shortcuts', selector : 'fuse-shortcuts',
@@ -14,67 +15,48 @@ import { FuseNavigationService } from '@fuse/components/navigation/navigation.se
}) })
export class FuseShortcutsComponent implements OnInit, OnDestroy export class FuseShortcutsComponent implements OnInit, OnDestroy
{ {
shortcutItems: any[]; shortcutItems: any[] = [];
navigationItems: any[]; navigationItems: any[];
filteredNavigationItems: any[]; filteredNavigationItems: any[];
searching: boolean; searching = false;
mobileShortcutsPanelActive: boolean; mobileShortcutsPanelActive = false;
toolbarColor: string;
matchMediaSubscription: Subscription;
onConfigChanged: Subscription;
@Input() @Input() navigation: any;
navigation: any;
@ViewChild('searchInput') @ViewChild('searchInput') searchInputField;
searchInputField; @ViewChild('shortcuts') shortcutsEl: ElementRef;
@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( constructor(
private _cookieService: CookieService, private renderer: Renderer2,
private _fuseMatchMediaService: FuseMatchMediaService, private observableMedia: ObservableMedia,
private _fuseNavigationService: FuseNavigationService, private fuseMatchMedia: FuseMatchMediaService,
private _observableMedia: ObservableMedia, private fuseNavigationService: FuseNavigationService,
private _renderer: Renderer2 private fuseConfig: FuseConfigService,
private cookieService: CookieService
) )
{ {
// Set the defaults this.onConfigChanged =
this.shortcutItems = []; this.fuseConfig.onConfigChanged
this.searching = false; .subscribe(
this.mobileShortcutsPanelActive = false; (newSettings) => {
this.toolbarColor = newSettings.colorClasses.toolbar;
// Set the private defaults }
this._unsubscribeAll = new Subject(); );
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{ {
// Get the navigation items and flatten them // Get the navigation items and flatten them
this.filteredNavigationItems = this.navigationItems = this._fuseNavigationService.getFlatNavigation(this.navigation); 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 ) if ( cookieExists )
{ {
this.shortcutItems = JSON.parse(this._cookieService.get('FUSE2.shortcuts')); this.shortcutItems = JSON.parse(this.cookieService.get('FUSE2.shortcuts'));
} }
else else
{ {
@@ -82,61 +64,46 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems = [ this.shortcutItems = [
{ {
'title': 'Calendar', 'title': 'Calendar',
'type' : 'item', 'type' : 'nav-item',
'icon' : 'today', 'icon' : 'today',
'url' : '/apps/calendar' 'url' : '/apps/calendar'
}, },
{ {
'title': 'Mail', 'title': 'Mail',
'type' : 'item', 'type' : 'nav-item',
'icon' : 'email', 'icon' : 'email',
'url' : '/apps/mail' 'url' : '/apps/mail'
}, },
{ {
'title': 'Contacts', 'title': 'Contacts',
'type' : 'item', 'type' : 'nav-item',
'icon' : 'account_box', 'icon' : 'account_box',
'url' : '/apps/contacts' 'url' : '/apps/contacts'
}, },
{ {
'title': 'To-Do', 'title': 'To-Do',
'type' : 'item', 'type' : 'nav-item',
'icon' : 'check_box', 'icon' : 'check_box',
'url' : '/apps/todo' 'url' : '/apps/todo'
} }
]; ];
} }
this._fuseMatchMediaService.onMediaChange this.matchMediaSubscription =
.pipe(takeUntil(this._unsubscribeAll)) this.fuseMatchMedia.onMediaChange.subscribe(() => {
.subscribe(() => { if ( this.observableMedia.isActive('gt-sm') )
if ( this._observableMedia.isActive('gt-sm') )
{ {
this.hideMobileShortcutsPanel(); this.hideMobileShortcutsPanel();
} }
}); });
} }
/** ngOnDestroy()
* On destroy
*/
ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions this.matchMediaSubscription.unsubscribe();
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
} }
// ----------------------------------------------------------------------------------------------------- search(event)
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Search
*
* @param event
*/
search(event): void
{ {
const value = event.target.value.toLowerCase(); const value = event.target.value.toLowerCase();
@@ -155,13 +122,7 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
}); });
} }
/** toggleShortcut(event, itemToToggle)
* Toggle shortcut
*
* @param event
* @param itemToToggle
*/
toggleShortcut(event, itemToToggle): void
{ {
event.stopPropagation(); event.stopPropagation();
@@ -172,7 +133,7 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems.splice(i, 1); this.shortcutItems.splice(i, 1);
// Save to the cookies // Save to the cookies
this._cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems)); this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
return; return;
} }
@@ -181,47 +142,32 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
this.shortcutItems.push(itemToToggle); this.shortcutItems.push(itemToToggle);
// Save to the cookies // Save to the cookies
this._cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems)); this.cookieService.set('FUSE2.shortcuts', JSON.stringify(this.shortcutItems));
} }
/** isInShortcuts(navigationItem)
* Is in shortcuts?
*
* @param navigationItem
* @returns {any}
*/
isInShortcuts(navigationItem): any
{ {
return this.shortcutItems.find(item => { return this.shortcutItems.find(item => {
return item.url === navigationItem.url; return item.url === navigationItem.url;
}); });
} }
/** onMenuOpen()
* On menu open
*/
onMenuOpen(): void
{ {
setTimeout(() => { setTimeout(() => {
this.searchInputField.nativeElement.focus(); this.searchInputField.nativeElement.focus();
}); });
} }
/** showMobileShortcutsPanel()
* Show mobile shortcuts
*/
showMobileShortcutsPanel(): void
{ {
this.mobileShortcutsPanelActive = true; this.mobileShortcutsPanelActive = true;
this._renderer.addClass(this.shortcutsEl.nativeElement, 'show-mobile-panel'); this.renderer.addClass(this.shortcutsEl.nativeElement, 'show-mobile-panel');
} }
/** hideMobileShortcutsPanel()
* Hide mobile shortcuts
*/
hideMobileShortcutsPanel(): void
{ {
this.mobileShortcutsPanelActive = false; 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 { fuse-sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -13,21 +11,17 @@ fuse-sidebar {
min-width: 280px; min-width: 280px;
max-width: 280px; max-width: 280px;
z-index: 1000; 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); box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35);
background: white;
@include media-breakpoint-down('xs') { &.left-aligned {
min-width: 0 !important;
max-width: 80vw !important;
width: 80vw !important;
}
&.left-positioned {
left: 0; left: 0;
transform: translateX(-100%); transform: translateX(-100%);
} }
&.right-positioned { &.right-aligned {
right: 0; right: 0;
transform: translateX(100%); transform: translateX(100%);
} }
@@ -45,12 +39,12 @@ fuse-sidebar {
position: absolute !important; position: absolute !important;
top: 0; top: 0;
bottom: 0; bottom: 0;
}
&.animations-enabled { &:not(.unfolded) {
transition-property: transform, width, min-width, max-width; width: 64px;
transition-duration: 150ms; min-width: 64px;
transition-timing-function: ease-in-out; max-width: 64px;
}
} }
} }
@@ -60,11 +54,7 @@ fuse-sidebar {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
z-index: 999; z-index: 3;
background-color: rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0.6);
opacity: 0; opacity: 0;
&.fuse-sidebar-overlay-invisible {
background-color: transparent;
}
} }

View File

@@ -1,8 +1,7 @@
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, OnInit, Output, Renderer2, RendererStyleFlags2, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, HostBinding, HostListener, Input, OnDestroy, OnInit, Renderer2, ViewEncapsulation } from '@angular/core';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { ObservableMedia } from '@angular/flex-layout'; import { ObservableMedia } from '@angular/flex-layout';
import { Subject } from 'rxjs'; import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseSidebarService } from './sidebar.service'; import { FuseSidebarService } from './sidebar.service';
import { FuseMatchMediaService } from '@fuse/services/match-media.service'; import { FuseMatchMediaService } from '@fuse/services/match-media.service';
@@ -20,13 +19,9 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@Input() @Input()
name: string; name: string;
// Key // Align
@Input() @Input()
key: string; align: 'left' | 'right';
// Position
@Input()
position: 'left' | 'right';
// Open // Open
@HostBinding('class.open') @HostBinding('class.open')
@@ -40,118 +35,37 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostBinding('class.locked-open') @HostBinding('class.locked-open')
isLockedOpen: boolean; isLockedOpen: boolean;
// Folded width // Folded
@Input() @HostBinding('class.folded')
foldedWidth: number;
// Folded auto trigger on hover
@Input()
foldedAutoTriggerOnHover: boolean;
// 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 _wasActive: boolean;
private _wasFolded: boolean;
private _backdrop: HTMLElement | null = null;
private _player: AnimationPlayer;
private _unsubscribeAll: Subject<any>;
@HostBinding('class.animations-enabled')
private _animationsEnabled: boolean;
/**
* 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
*/
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
)
{
// 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();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Folded
*
* @param {boolean} value
*/
@Input() @Input()
set folded(value: boolean) set folded(value: boolean)
{ {
// Set the folded // Only work if the sidebar is not closed
this._folded = value;
// Return if the sidebar is closed
if ( !this.opened ) if ( !this.opened )
{ {
return; return;
} }
// Programmatically add/remove padding to the element // Set the folded
// that comes after or before based on the position this._folded = value;
// Programmatically add/remove margin to the element
// that comes after or before based on the alignment
let sibling, let sibling,
styleRule; styleRule;
const styleValue = this.foldedWidth + 'px'; const styleValue = '64px';
// Get the sibling and set the style rule // Get the sibling and set the style rule
if ( this.position === 'left' ) if ( this.align === 'left' )
{ {
sibling = this._elementRef.nativeElement.nextElementSibling; sibling = this.elementRef.nativeElement.nextElementSibling;
styleRule = 'padding-left'; styleRule = 'marginLeft';
} }
else else
{ {
sibling = this._elementRef.nativeElement.previousElementSibling; sibling = this.elementRef.nativeElement.previousElementSibling;
styleRule = 'padding-right'; styleRule = 'marginRight';
} }
// If there is no sibling, return... // If there is no sibling, return...
@@ -163,36 +77,15 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// If folded... // If folded...
if ( value ) if ( value )
{ {
// Fold the sidebar // Set the style
this.fold(); this.renderer.setStyle(sibling, styleRule, styleValue);
// 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... // If unfolded...
else else
{ {
// Unfold the sidebar // Remove the style
this.unfold(); this.renderer.removeStyle(sibling, styleRule);
// 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 get folded(): boolean
@@ -200,36 +93,57 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return this._folded; return this._folded;
} }
// ----------------------------------------------------------------------------------------------------- // Folded unfolded
// @ Lifecycle hooks @HostBinding('class.unfolded')
// ----------------------------------------------------------------------------------------------------- unfolded: boolean;
// Private
private _folded: boolean;
private _wasActive: boolean;
private _backdrop: HTMLElement | null = null;
private _player: AnimationPlayer;
private _onMediaChangeSubscription: Subscription;
/**
* Constructor
*
* @param {Renderer2} renderer
* @param {ElementRef} elementRef
* @param {AnimationBuilder} animationBuilder
* @param {ObservableMedia} observableMedia
* @param {FuseConfigService} fuseConfigService
* @param {FuseSidebarService} fuseSidebarService
* @param {FuseMatchMediaService} fuseMatchMediaService
*/
constructor(
private renderer: Renderer2,
private elementRef: ElementRef,
private animationBuilder: AnimationBuilder,
private observableMedia: ObservableMedia,
private fuseConfigService: FuseConfigService,
private fuseSidebarService: FuseSidebarService,
private fuseMatchMediaService: FuseMatchMediaService
)
{
// Set the defaults
this.opened = false;
this.folded = false;
this.align = 'left';
}
/** /**
* On init * On init
*/ */
ngOnInit(): void ngOnInit(): void
{ {
// Subscribe to config changes
this._fuseConfigService.config
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((config) => {
this._fuseConfig = config;
});
// Register the sidebar // Register the sidebar
this._fuseSidebarService.register(this.name, this); this.fuseSidebarService.register(this.name, this);
// Setup visibility // Setup alignment
this._setupVisibility(); this._setupAlignment();
// Setup position
this._setupPosition();
// Setup lockedOpen // Setup lockedOpen
this._setupLockedOpen(); this._setupLockedOpen();
// Setup folded
this._setupFolded();
} }
/** /**
@@ -244,47 +158,28 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
} }
// Unregister the sidebar // Unregister the sidebar
this._fuseSidebarService.unregister(this.name); this.fuseSidebarService.unregister(this.name);
// Unsubscribe from all subscriptions // Unsubscribe from the media watcher subscription
this._unsubscribeAll.next(); this._onMediaChangeSubscription.unsubscribe();
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');
} }
/** /**
* Setup the sidebar position * Set the sidebar alignment
* *
* @private * @private
*/ */
private _setupPosition(): void private _setupAlignment(): void
{ {
// Add the correct class name to the sidebar // Add the correct class name to the sidebar
// element depending on the position attribute // element depending on the align attribute
if ( this.position === 'right' ) if ( this.align === 'right' )
{ {
this._renderer.addClass(this._elementRef.nativeElement, 'right-positioned'); this.renderer.addClass(this.elementRef.nativeElement, 'right-aligned');
} }
else else
{ {
this._renderer.addClass(this._elementRef.nativeElement, 'left-positioned'); this.renderer.addClass(this.elementRef.nativeElement, 'left-aligned');
} }
} }
@@ -298,26 +193,19 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// Return if the lockedOpen wasn't set // Return if the lockedOpen wasn't set
if ( !this.lockedOpen ) if ( !this.lockedOpen )
{ {
// Return
return; return;
} }
// Set the wasActive for the first time // Set the wasActive for the first time
this._wasActive = false; this._wasActive = false;
// Set the wasFolded
this._wasFolded = this.folded;
// Show the sidebar
this._showSidebar();
// Act on every media change // Act on every media change
this._fuseMatchMediaService.onMediaChange this._onMediaChangeSubscription =
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => { this.fuseMatchMediaService.onMediaChange.subscribe(() => {
// Get the active status // Get the active status
const isActive = this._observableMedia.isActive(this.lockedOpen); const isActive = this.observableMedia.isActive(this.lockedOpen);
// If the both status are the same, don't act // If the both status are the same, don't act
if ( this._wasActive === isActive ) if ( this._wasActive === isActive )
@@ -331,30 +219,18 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// Set the lockedOpen status // Set the lockedOpen status
this.isLockedOpen = true; this.isLockedOpen = true;
// Show the sidebar
this._showSidebar();
// Force the the opened status to true // Force the the opened status to true
this.opened = true; this.opened = true;
// Emit the 'openedChanged' event // Read the folded setting from the config
this.openedChanged.emit(this.opened); // and fold the sidebar if it's true
if ( this.fuseConfigService.config.layout.navigationFolded )
// If the sidebar was folded, forcefully fold it again
if ( this._wasFolded )
{ {
// Enable the animations this.fold();
this._enableAnimations();
// Fold
this.folded = true;
// Mark for check
this._changeDetectorRef.markForCheck();
} }
// Hide the backdrop if any exists // Hide the backdrop if any exists
this._hideBackdrop(); this.hideBackdrop();
} }
// De-Activate the lockedOpen // De-Activate the lockedOpen
else else
@@ -367,12 +243,6 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
// Force the the opened status to close // Force the the opened status to close
this.opened = false; this.opened = false;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Hide the sidebar
this._hideSidebar();
} }
// Store the new active status // Store the new active status
@@ -380,209 +250,6 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
}); });
} }
/**
* 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 * Open the sidebar
*/ */
@@ -593,23 +260,11 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return; return;
} }
// Enable the animations
this._enableAnimations();
// Show the sidebar
this._showSidebar();
// Show the backdrop // Show the backdrop
this._showBackdrop(); this.showBackdrop();
// Set the opened status // Set the opened status
this.opened = true; this.opened = true;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Mark for check
this._changeDetectorRef.markForCheck();
} }
/** /**
@@ -622,23 +277,11 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return; return;
} }
// Enable the animations
this._enableAnimations();
// Hide the backdrop // Hide the backdrop
this._hideBackdrop(); this.hideBackdrop();
// Set the opened status // Set the opened status
this.opened = false; this.opened = false;
// Emit the 'openedChanged' event
this.openedChanged.emit(this.opened);
// Hide the sidebar
this._hideSidebar();
// Mark for check
this._changeDetectorRef.markForCheck();
} }
/** /**
@@ -662,13 +305,14 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostListener('mouseenter') @HostListener('mouseenter')
onMouseEnter(): void onMouseEnter(): void
{ {
// Only work if the auto trigger is enabled // Only work if the sidebar is folded
if ( !this.foldedAutoTriggerOnHover ) if ( !this.folded )
{ {
return; return;
} }
this.unfoldTemporarily(); // Unfold the sidebar temporarily
this.unfolded = true;
} }
/** /**
@@ -677,13 +321,14 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
@HostListener('mouseleave') @HostListener('mouseleave')
onMouseLeave(): void onMouseLeave(): void
{ {
// Only work if the auto trigger is enabled // Only work if the sidebar is folded
if ( !this.foldedAutoTriggerOnHover ) if ( !this.folded )
{ {
return; return;
} }
this.foldTemporarily(); // Fold the sidebar back
this.unfolded = false;
} }
/** /**
@@ -697,14 +342,8 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return; return;
} }
// Enable the animations
this._enableAnimations();
// Fold // Fold
this.folded = true; this.folded = true;
// Mark for check
this._changeDetectorRef.markForCheck();
} }
/** /**
@@ -718,14 +357,8 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
return; return;
} }
// Enable the animations
this._enableAnimations();
// Unfold // Unfold
this.folded = false; this.folded = false;
// Mark for check
this._changeDetectorRef.markForCheck();
} }
/** /**
@@ -744,56 +377,66 @@ export class FuseSidebarComponent implements OnInit, OnDestroy
} }
/** /**
* Fold the temporarily unfolded sidebar back * Show the backdrop
*/ */
foldTemporarily(): void showBackdrop(): void
{ {
// Only work if the sidebar is folded // Create the backdrop element
if ( !this.folded ) this._backdrop = this.renderer.createElement('div');
{
return;
}
// Enable the animations // Add a class to the backdrop element
this._enableAnimations(); this._backdrop.classList.add('fuse-sidebar-overlay');
// Fold the sidebar back // Append the backdrop to the parent of the sidebar
this.unfolded = false; this.renderer.appendChild(this.elementRef.nativeElement.parentElement, this._backdrop);
// Set the folded width // Create the enter animation and attach it to the player
const styleValue = this.foldedWidth + 'px'; this._player =
this.animationBuilder
.build([
animate('300ms ease', style({opacity: 1}))
]).create(this._backdrop);
this._renderer.setStyle(this._elementRef.nativeElement, 'width', styleValue); // Play the animation
this._renderer.setStyle(this._elementRef.nativeElement, 'min-width', styleValue); this._player.play();
this._renderer.setStyle(this._elementRef.nativeElement, 'max-width', styleValue);
// Mark for check // Add an event listener to the overlay
this._changeDetectorRef.markForCheck(); this._backdrop.addEventListener('click', () => {
this.close();
}
);
} }
/** /**
* Unfold the sidebar temporarily * Hide the backdrop
*/ */
unfoldTemporarily(): void hideBackdrop(): void
{ {
// Only work if the sidebar is folded if ( !this._backdrop )
if ( !this.folded )
{ {
return; return;
} }
// Enable the animations // Create the leave animation and attach it to the player
this._enableAnimations(); this._player =
this.animationBuilder
.build([
animate('300ms ease', style({opacity: 0}))
]).create(this._backdrop);
// Unfold the sidebar temporarily // Play the animation
this.unfolded = true; this._player.play();
// Remove the folded width // Once the animation is done...
this._renderer.removeStyle(this._elementRef.nativeElement, 'width'); this._player.onDone(() => {
this._renderer.removeStyle(this._elementRef.nativeElement, 'min-width');
this._renderer.removeStyle(this._elementRef.nativeElement, 'max-width');
// Mark for check // If the backdrop still exists...
this._changeDetectorRef.markForCheck(); 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'; import { FuseSidebarComponent } from './sidebar.component';
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseSidebarService export class FuseSidebarService
{ {
// Private // Private

View File

@@ -1,427 +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')"> <button mat-icon-button class="close-button" (click)="closeBar()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </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> </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>
</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>
</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>
</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>
</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> </div>

View File

@@ -10,69 +10,106 @@
} }
:host { :host {
display: flex; position: fixed;
overflow: hidden; display: block;
right: 0;
top: 160px;
z-index: 998;
&.bar-closed .theme-options-panel {
display: none;
}
.theme-options-panel { .theme-options-panel {
display: flex; position: absolute;
flex-direction: column; right: 0;
flex: 1 0 auto; top: 0;
padding: 40px 24px 24px 24px; width: 360px;
transform: translate3d(100%, 0, 0);
z-index: 999;
max-height: calc(100vh - 200px);
padding: 24px;
overflow: auto; overflow: auto;
.header { @include media-breakpoint-down('xs') {
display: flex; top: -120px;
flex: 0 1 auto; max-height: calc(100vh - 100px);
margin-bottom: 32px; width: 90vw;
align-items: center;
justify-content: space-between;
.title {
font-size: 20px;
font-weight: 500;
padding-left: 4px;
}
} }
form { .close-button {
display: flex; position: absolute;
flex: 1 1 auto; top: 8px;
flex-direction: column; right: 8px;
}
.group { h3 {
display: flex; font-size: 14px;
flex: 1 0 auto; font-weight: 500;
flex-direction: column; color: rgba(0, 0, 0, 0.54);
position: relative; }
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 2px;
padding: 28px 16px 8px 16px;
margin: 16px 0;
h2 { .mat-divider {
position: absolute; display: block !important;
top: -11px; width: 100%;
left: 8px; margin: 24px 0 16px 0;
margin: 0; }
padding: 0 8px;
font-size: 16px;
font-weight: 500;
background: white;
color: rgba(0, 0, 0, 0.54);
}
h3 { .colors {
font-size: 14px; display: block !important;
font-weight: 500; width: 100%;
color: rgba(0, 0, 0, 0.54);
margin: 24px 0 16px 0;
padding: 0;
&:first-of-type {
margin-top: 0;
}
}
}
} }
} }
.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,10 @@
import { Component, HostBinding, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { Component, ElementRef, HostBinding, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
import { Subject } from 'rxjs'; import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations'; import { fuseAnimations } from '@fuse/animations';
import { FuseConfigService } from '@fuse/services/config.service'; import { FuseConfigService } from '@fuse/services/config.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
@Component({ @Component({
selector : 'fuse-theme-options', selector : 'fuse-theme-options',
@@ -16,114 +14,50 @@ import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
}) })
export class FuseThemeOptionsComponent implements OnInit, OnDestroy export class FuseThemeOptionsComponent implements OnInit, OnDestroy
{ {
fuseConfig: any; @Input() navigation;
form: FormGroup; @ViewChild('openButton') openButton;
@ViewChild('panel') panel;
@ViewChild('overlay') overlay: ElementRef;
@HostBinding('class.bar-closed') public player: AnimationPlayer;
barClosed: boolean; config: any;
// Private onConfigChanged: Subscription;
private _unsubscribeAll: Subject<any>;
@HostBinding('class.bar-closed') barClosed: boolean;
/**
* Constructor
*
* @param {FormBuilder} _formBuilder
* @param {FuseConfigService} _fuseConfigService
* @param {FuseNavigationService} _fuseNavigationService
* @param {FuseSidebarService} _fuseSidebarService
* @param {Renderer2} _renderer
*/
constructor( constructor(
private _formBuilder: FormBuilder, private animationBuilder: AnimationBuilder,
private _fuseConfigService: FuseConfigService, private fuseConfig: FuseConfigService,
private _fuseNavigationService: FuseNavigationService, private navigationService: FuseNavigationService,
private _fuseSidebarService: FuseSidebarService, private renderer: Renderer2
private _renderer: Renderer2
) )
{ {
// Set the defaults
this.barClosed = true; this.barClosed = true;
// Set the private defaults this.onConfigChanged =
this._unsubscribeAll = new Subject(); this.fuseConfig.onConfigChanged
.subscribe(
(newConfig) => {
this.config = newConfig;
}
);
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{ {
// Build the config form this.renderer.listen(this.overlay.nativeElement, 'click', () => {
// noinspection TypeScriptValidateTypes this.closeBar();
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()
})
}),
customScrollbars: new FormControl()
}); });
// Subscribe to the config changes // Get the nav model and add customize nav item
this._fuseConfigService.config // that opens the bar programmatically
.pipe(takeUntil(this._unsubscribeAll)) const nav: any = this.navigation;
.subscribe((config) => {
// Update the stored config nav.push({
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 = {
'id' : 'custom-function', 'id' : 'custom-function',
'title' : 'Custom Function', 'title' : 'Custom Function',
'type' : 'group', 'type' : 'group',
'icon' : 'settings',
'children': [ 'children': [
{ {
'id' : 'customize', 'id' : 'customize',
@@ -131,173 +65,50 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
'type' : 'item', 'type' : 'item',
'icon' : 'settings', 'icon' : 'settings',
'function': () => { 'function': () => {
this.toggleSidebarOpen('themeOptionsPanel'); this.openBar();
} }
} }
] ]
}; });
this._fuseNavigationService.addNavigationItem(customFunctionNavItem, 'end');
} }
/** ngOnDestroy()
* On destroy
*/
ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions this.onConfigChanged.unsubscribe();
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
// Remove the custom function menu
this._fuseNavigationService.removeNavigationItem('custom-function');
} }
// ----------------------------------------------------------------------------------------------------- onSettingsChange()
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Reset the form values based on the
* selected layout style
*
* @param value
* @private
*/
private _resetFormValues(value): void
{ {
switch ( value ) this.fuseConfig.setConfig(this.config);
{
// 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;
}
}
} }
// ----------------------------------------------------------------------------------------------------- closeBar()
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle sidebar open
*
* @param key
*/
toggleSidebarOpen(key): void
{ {
this._fuseSidebarService.getSidebar(key).toggleOpen(); 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule } from '@angular/material'; 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 { FuseMaterialColorPickerModule } from '@fuse/components/material-color-picker/material-color-picker.module';
import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component'; import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component';
@NgModule({ @NgModule({
@@ -17,7 +14,6 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
imports : [ imports : [
CommonModule, CommonModule,
FormsModule, FormsModule,
ReactiveFormsModule,
FlexLayoutModule, FlexLayoutModule,
@@ -30,9 +26,7 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
MatSelectModule, MatSelectModule,
MatSlideToggleModule, MatSlideToggleModule,
FuseDirectivesModule, FuseMaterialColorPickerModule
FuseMaterialColorPickerModule,
FuseSidebarModule
], ],
exports : [ exports : [
FuseThemeOptionsComponent FuseThemeOptionsComponent

View File

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

View File

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

View File

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

View File

@@ -5,44 +5,28 @@ import { AfterContentChecked, Directive, ElementRef, TemplateRef, ViewContainerR
}) })
export class FuseIfOnDomDirective implements AfterContentChecked export class FuseIfOnDomDirective implements AfterContentChecked
{ {
isCreated: boolean; isCreated = false;
/**
* Constructor
*
* @param {ElementRef} _elementRef
* @param {TemplateRef<any>} _templateRef
* @param {ViewContainerRef} _viewContainerRef
*/
constructor( constructor(
private _elementRef: ElementRef, private templateRef: TemplateRef<any>,
private _templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef,
private _viewContainerRef: ViewContainerRef private element: ElementRef
) )
{ {
// Set the defaults
this.isCreated = false;
} }
// ----------------------------------------------------------------------------------------------------- ngAfterContentChecked()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* After content checked
*/
ngAfterContentChecked(): void
{ {
if ( document.body.contains(this._elementRef.nativeElement) && !this.isCreated ) if ( document.body.contains(this.element.nativeElement) && !this.isCreated )
{ {
setTimeout(() => { setTimeout(() => {
this._viewContainerRef.createEmbeddedView(this._templateRef); this.viewContainer.createEmbeddedView(this.templateRef);
}, 300); }, 300);
this.isCreated = true; 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; 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 { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
import { MatSidenav } from '@angular/material'; import { MatSidenav } from '@angular/material';
import { ObservableMedia } from '@angular/flex-layout'; import { ObservableMedia } from '@angular/flex-layout';
import { Subject } from 'rxjs'; import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMatchMediaService } from '@fuse/services/match-media.service'; import { FuseMatchMediaService } from '@fuse/services/match-media.service';
import { FuseMatSidenavHelperService } from '@fuse/directives/fuse-mat-sidenav/fuse-mat-sidenav.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 export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
{ {
@HostBinding('class.mat-is-locked-open') matchMediaSubscription: Subscription;
isLockedOpen: boolean; @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( constructor(
private _fuseMatchMediaService: FuseMatchMediaService, private fuseMatSidenavService: FuseMatSidenavHelperService,
private _fuseMatSidenavHelperService: FuseMatSidenavHelperService, private fuseMatchMedia: FuseMatchMediaService,
private _matSidenav: MatSidenav, private observableMedia: ObservableMedia,
private _observableMedia: ObservableMedia private matSidenav: MatSidenav
) )
{ {
// Set the defaults
this.isLockedOpen = true;
// Set the private defaults
this._unsubscribeAll = new Subject();
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{ {
// Register the sidenav to the service this.fuseMatSidenavService.setSidenav(this.id, this.matSidenav);
this._fuseMatSidenavHelperService.setSidenav(this.id, this._matSidenav);
if ( this._observableMedia.isActive(this.matIsLockedOpenBreakpoint) ) if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
{ {
this.isLockedOpen = true; this.isLockedOpen = true;
this._matSidenav.mode = 'side'; this.matSidenav.mode = 'side';
this._matSidenav.toggle(true); this.matSidenav.toggle(true);
} }
else else
{ {
this.isLockedOpen = false; this.isLockedOpen = false;
this._matSidenav.mode = 'over'; this.matSidenav.mode = 'over';
this._matSidenav.toggle(false); this.matSidenav.toggle(false);
} }
this._fuseMatchMediaService.onMediaChange this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
.pipe(takeUntil(this._unsubscribeAll)) if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
.subscribe(() => { {
if ( this._observableMedia.isActive(this.matIsLockedOpenBreakpoint) ) this.isLockedOpen = true;
{ this.matSidenav.mode = 'side';
this.isLockedOpen = true; this.matSidenav.toggle(true);
this._matSidenav.mode = 'side'; }
this._matSidenav.toggle(true); else
} {
else this.isLockedOpen = false;
{ this.matSidenav.mode = 'over';
this.isLockedOpen = false; this.matSidenav.toggle(false);
this._matSidenav.mode = 'over'; }
this._matSidenav.toggle(false); });
}
});
} }
/** ngOnDestroy()
* On destroy
*/
ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions this.matchMediaSubscription.unsubscribe();
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
} }
} }
@@ -105,29 +69,15 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
}) })
export class FuseMatSidenavTogglerDirective export class FuseMatSidenavTogglerDirective
{ {
@Input('fuseMatSidenavToggler') @Input('fuseMatSidenavToggler') id;
id;
/** constructor(private fuseMatSidenavService: FuseMatSidenavHelperService)
* Constructor
*
* @param {FuseMatSidenavHelperService} _fuseMatSidenavHelperService
*/
constructor(
private _fuseMatSidenavHelperService: FuseMatSidenavHelperService)
{ {
} }
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* On click
*/
@HostListener('click') @HostListener('click')
onClick() 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 { Injectable } from '@angular/core';
import { MatSidenav } from '@angular/material'; import { MatSidenav } from '@angular/material';
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseMatSidenavHelperService export class FuseMatSidenavHelperService
{ {
sidenavInstances: MatSidenav[]; sidenavInstances: MatSidenav[];
/**
* Constructor
*/
constructor() constructor()
{ {
this.sidenavInstances = []; this.sidenavInstances = [];
} }
// ----------------------------------------------------------------------------------------------------- setSidenav(id, instance)
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Set sidenav
*
* @param id
* @param instance
*/
setSidenav(id, instance): void
{ {
this.sidenavInstances[id] = instance; this.sidenavInstances[id] = instance;
} }
/** getSidenav(id)
* Get sidenav
*
* @param id
* @returns {any}
*/
getSidenav(id): any
{ {
return this.sidenavInstances[id]; return this.sidenavInstances[id];
} }

View File

@@ -1,247 +1,72 @@
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core'; import { AfterViewInit, Directive, ElementRef, HostListener, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { Platform } from '@angular/cdk/platform'; import { Platform } from '@angular/cdk/platform';
import { Subject } from 'rxjs'; import { Subscription } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import PerfectScrollbar from 'perfect-scrollbar'; import PerfectScrollbar from 'perfect-scrollbar';
import * as _ from 'lodash';
import { FuseConfigService } from '@fuse/services/config.service'; import { FuseConfigService } from '@fuse/services/config.service';
@Directive({ @Directive({
selector: '[fusePerfectScrollbar]' selector: '[fusePerfectScrollbar]'
}) })
export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnDestroy
{ {
isInitialized: boolean; onConfigChanged: Subscription;
isMobile: boolean; isDisableCustomScrollbars = false;
isMobile = false;
isInitialized = true;
ps: PerfectScrollbar; 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( constructor(
public elementRef: ElementRef, public element: ElementRef,
private _fuseConfigService: FuseConfigService, private fuseConfig: FuseConfigService,
private _platform: Platform, private platform: Platform
private _router: Router
) )
{ {
// 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();
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Perfect Scrollbar options
*
* @param value
*/
@Input()
set fusePerfectScrollbarOptions(value)
{ {
// Merge the options this.onConfigChanged =
this._options = _.merge({}, this._options, value); this.fuseConfig.onConfigChanged.subscribe(
}
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(
(settings) => { (settings) => {
this.enabled = settings.customScrollbars; this.isDisableCustomScrollbars = !settings.customScrollbars;
} }
); );
// Scroll to the top on every route change if ( this.platform.ANDROID || this.platform.IOS )
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 )
{ {
this.isMobile = true; this.isMobile = true;
} }
}
// Return if it's mobile ngAfterViewInit()
if ( this.isMobile ) {
if ( this.isMobile || this.isDisableCustomScrollbars )
{ {
// Return... this.isInitialized = false;
return; return;
} }
// Set as initialized
this.isInitialized = true;
// Initialize the perfect-scrollbar // Initialize the perfect-scrollbar
this.ps = new PerfectScrollbar(this.elementRef.nativeElement, { this.ps = new PerfectScrollbar(this.element.nativeElement, {
...this.fusePerfectScrollbarOptions wheelPropagation: true
}); });
} }
/** ngOnDestroy()
* Destroy
*
* @private
*/
_destroy(): void
{ {
if ( !this.isInitialized || !this.ps ) if ( !this.isInitialized || !this.ps )
{ {
return; return;
} }
this.onConfigChanged.unsubscribe();
// Destroy the perfect-scrollbar // Destroy the perfect-scrollbar
this.ps.destroy(); 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']) @HostListener('document:click', ['$event'])
documentClick(event: Event): void documentClick(event: Event): void
{ {
@@ -257,10 +82,7 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
this.ps.update(); this.ps.update();
} }
/** update()
* Update the scrollbar
*/
update(): void
{ {
if ( !this.isInitialized ) if ( !this.isInitialized )
{ {
@@ -271,108 +93,62 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
this.ps.update(); this.ps.update();
} }
/** destroy()
* Destroy the scrollbar
*/
destroy(): void
{ {
this.ngOnDestroy(); this.ngOnDestroy();
} }
/** scrollToX(x: number, speed?: number)
* Scroll to X
*
* @param {number} x
* @param {number} speed
*/
scrollToX(x: number, speed?: number): void
{ {
this.animateScrolling('scrollLeft', x, speed); this.animateScrolling('scrollLeft', x, speed);
} }
/** scrollToY(y: number, speed?: number)
* Scroll to Y
*
* @param {number} y
* @param {number} speed
*/
scrollToY(y: number, speed?: number): void
{ {
this.animateScrolling('scrollTop', y, speed); this.animateScrolling('scrollTop', y, speed);
} }
/** scrollToTop(offset?: number, speed?: number)
* Scroll to top
*
* @param {number} offset
* @param {number} speed
*/
scrollToTop(offset?: number, speed?: number): void
{ {
this.animateScrolling('scrollTop', (offset || 0), speed); this.animateScrolling('scrollTop', (offset || 0), speed);
} }
/** scrollToLeft(offset?: number, speed?: number)
* Scroll to left
*
* @param {number} offset
* @param {number} speed
*/
scrollToLeft(offset?: number, speed?: number): void
{ {
this.animateScrolling('scrollLeft', (offset || 0), speed); this.animateScrolling('scrollLeft', (offset || 0), speed);
} }
/** scrollToRight(offset?: number, speed?: number)
* Scroll to right
*
* @param {number} offset
* @param {number} speed
*/
scrollToRight(offset?: number, speed?: number): void
{ {
const width = this.elementRef.nativeElement.scrollWidth; const width = this.element.nativeElement.scrollWidth;
this.animateScrolling('scrollLeft', width - (offset || 0), speed); this.animateScrolling('scrollLeft', width - (offset || 0), speed);
} }
/** scrollToBottom(offset?: number, speed?: number)
* Scroll to bottom
*
* @param {number} offset
* @param {number} speed
*/
scrollToBottom(offset?: number, speed?: number): void
{ {
const height = this.elementRef.nativeElement.scrollHeight; const height = this.element.nativeElement.scrollHeight;
this.animateScrolling('scrollTop', height - (offset || 0), speed); this.animateScrolling('scrollTop', height - (offset || 0), speed);
} }
/** animateScrolling(target: string, value: number, speed?: number)
* Animate scrolling
*
* @param {string} target
* @param {number} value
* @param {number} speed
*/
animateScrolling(target: string, value: number, speed?: number): void
{ {
if ( !speed ) if ( !speed )
{ {
this.elementRef.nativeElement[target] = value; this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that // PS has weird event sending order, this is a workaround for that
this.update(); this.update();
this.update(); this.update();
} }
else if ( value !== this.elementRef.nativeElement[target] ) else if ( value !== this.element.nativeElement[target] )
{ {
let newValue = 0; let newValue = 0;
let scrollCount = 0; let scrollCount = 0;
let oldTimestamp = performance.now(); let oldTimestamp = performance.now();
let oldValue = this.elementRef.nativeElement[target]; let oldValue = this.element.nativeElement[target];
const cosParameter = (oldValue - value) / 2; const cosParameter = (oldValue - value) / 2;
@@ -382,11 +158,11 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount)); newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
// Only continue animation if scroll position has not changed // 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 ) 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 // PS has weird event sending order, this is a workaround for that
this.update(); this.update();
@@ -395,7 +171,7 @@ export class FusePerfectScrollbarDirective implements AfterViewInit, OnDestroy
} }
else else
{ {
this.elementRef.nativeElement[target] = oldValue = newValue; this.element.nativeElement[target] = oldValue = newValue;
oldTimestamp = newTimestamp; oldTimestamp = newTimestamp;

View File

@@ -1,8 +1,27 @@
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; 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 export class FuseModule
{ {
constructor(@Optional() @SkipSelf() parentModule: FuseModule) constructor(@Optional() @SkipSelf() parentModule: FuseModule)

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,7 +30,6 @@
@import "partials/material"; @import "partials/material";
@import "partials/angular-material-fix"; @import "partials/angular-material-fix";
@import "partials/typography"; @import "partials/typography";
@import "partials/docs";
@import "partials/page-layouts"; @import "partials/page-layouts";
@import "partials/cards"; @import "partials/cards";
@import "partials/navigation"; @import "partials/navigation";

View File

@@ -84,9 +84,4 @@ mat-chip {
min-width: 0 !important; min-width: 0 !important;
min-height: 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

@@ -14,7 +14,7 @@ i {
} }
// Material colors map // Material colors map
$matPalettes: ( $matColorsMap: (
primary: $primary, primary: $primary,
accent: $accent, accent: $accent,
warn: $warn, warn: $warn,
@@ -43,91 +43,75 @@ $matPalettes: (
); );
// Material color hues list // 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 // Text color levels generator mixin
@mixin generateTextColorLevels($classes, $contrast) { @mixin generateTextColorLevels($baseTextColor) {
// If the contrast is dark... // If the base text color is black...
@if ($contrast == 'dark') { @if (rgba(black, 1) == rgba($baseTextColor, 1)) {
// Put down the color classes i,
#{$classes} { .icon {
color: rgba(0, 0, 0, 0.54);
}
i, &.secondary-text,
.icon { .secondary-text {
color: rgba(0, 0, 0, 0.54); color: rgba(0, 0, 0, 0.54) !important;
} }
&.secondary-text, &.hint-text,
.secondary-text { .hint-text,
color: rgba(0, 0, 0, 0.54) !important; &.disabled-text,
} .disabled-text {
color: rgba(0, 0, 0, 0.38) !important;
}
&.hint-text, &.divider,
.hint-text, .divider {
&.disabled-text, color: rgba(0, 0, 0, 0.12) !important;
.disabled-text { }
color: rgba(0, 0, 0, 0.38) !important;
}
&.divider, .mat-ripple-element {
.divider { background: rgba(0, 0, 0, 0.1);
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);
}
} }
} }
// If the base text color is white... // If the base text color is white...
@else { @else {
// Put down the color classes i,
#{$classes} { .icon {
color: rgba(255, 255, 255, 1);
}
i, &.secondary-text,
.icon { .secondary-text {
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 0.70) !important;
} }
&.secondary-text, &.hint-text,
.secondary-text { .hint-text,
color: rgba(255, 255, 255, 0.70) !important; &.disabled-text,
} .disabled-text {
color: rgba(255, 255, 255, 0.50) !important;
}
&.hint-text, &.divider,
.hint-text, .divider {
&.disabled-text, color: rgba(255, 255, 255, 0.12) !important;
.disabled-text { }
color: rgba(255, 255, 255, 0.50) !important;
}
&.divider, .mat-ripple-element {
.divider { background: rgba(255, 255, 255, 0.1);
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);
}
} }
} }
} }
@mixin generateMaterialElementColors($classes, $contrast) { @mixin generateMaterialElementColors($contrastColor) {
// If the contrast color is light... // If the contrast color is white...
$fuseForeground: ( $fuseForeground: (
base: white, base: white,
text: 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), divider: rgba(white, 0.12),
); );
// If the contrast color is dark... // If the contrast color is black...
@if ($contrast == 'dark') { @if (rgba(black, 1) == rgba($contrastColor, 1)) {
$fuseForeground: ( $fuseForeground: (
base: black, 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 // Native Input
#{$classes} { input[type="text"] {
color: map_get($fuseForeground, base);
}
// Native Input // Input
input[type="text"] { .mat-form-field-label {
color: map_get($fuseForeground, base); color: map_get($fuseForeground, hint-text);
} }
// Input .mat-form-field-underline {
.mat-form-field-label { background-color: map_get($fuseForeground, divider);
color: map_get($fuseForeground, hint-text); }
}
.mat-form-field-underline { // Select
background-color: map_get($fuseForeground, divider); .mat-select-trigger,
} .mat-select-arrow {
color: map_get($fuseForeground, hint-text);
}
// Select .mat-select-underline {
.mat-select-trigger, background-color: map_get($fuseForeground, divider);
.mat-select-arrow { }
color: map_get($fuseForeground, hint-text);
}
.mat-select-underline { .mat-select-disabled .mat-select-value,
background-color: map_get($fuseForeground, divider); .mat-select-arrow,
} .mat-select-trigger {
color: map_get($fuseForeground, hint-text);
}
.mat-select-disabled .mat-select-value, .mat-select-content,
.mat-select-arrow, .mat-select-panel-done-animating {
.mat-select-trigger { background: map_get($background, card);
color: map_get($fuseForeground, hint-text); }
}
.mat-select-content, .mat-select-value {
.mat-select-panel-done-animating { color: map_get($fuseForeground, text);
background: map_get($background, card);
}
.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; background-color: $color !important;
color: $contrastColor !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] { &[disabled] {
background-color: rgba($color, .12) !important; background-color: rgba($color, .12) !important;
color: rgba($contrastColor, .26) !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 { .#{$colorName}#{$hue}-fg {
color: $color !important; 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 { .#{$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... // Generate the color classes...
@each $colorName, $colorMap in $matColorsMap {
// Define contrast lists @each $hue in $matColorHues {
$light-contrasting-classes: ();
$dark-contrasting-classes: ();
@each $paletteName, $palette in $matPalettes { $color: map-get($colorMap, $hue);
$contrastColor: map-get(map-get($colorMap, 'contrast'), $hue);
// Get the contrasts map @if ($color != null and $contrastColor != null) {
$contrasts: map-get($palette, 'contrast');
@each $hue in $matHues { @include generateColorClasses($colorName, $color, $contrastColor, '-#{$hue}');
// 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');
}
// Run the generator one more time for default values (500) // Run the generator one more time for default values (500)
@if ($hue == 500) { @if ($hue == 500) {
@include generateColorClasses($colorName, $color, $contrastColor, '');
// 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');

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 { body {
display: flex;
flex: 1 0 auto; > mat-sidenav-container {
width: 100%; height: 100%;
height: 100%; }
max-height: 100%; }
min-height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background: #F5F5F5;
}

View File

@@ -42,7 +42,7 @@
color: currentColor; color: currentColor;
> .nav-link-title { > .nav-link-title {
flex: 1 1 auto; flex: 1;
white-space: nowrap; white-space: nowrap;
} }
@@ -58,7 +58,7 @@
transition: opacity 0.2s ease-in-out 0.1s; transition: opacity 0.2s ease-in-out 0.1s;
margin-left: 8px; margin-left: 8px;
+ .collapsable-arrow { + .collapse-arrow {
margin-left: 8px; margin-left: 8px;
} }
} }
@@ -72,9 +72,14 @@
} }
&.active { &.active {
background-color: mat-color($accent);
.nav-link-icon { .mat-ripple-element {
opacity: 1; background-color: mat-color($accent, default-contrast, 0.1);
}
&, .nav-link-icon {
color: mat-color($accent, default-contrast);
} }
.nav-link-badge { .nav-link-badge {
@@ -85,11 +90,10 @@
.nav-link-icon { .nav-link-icon {
margin-right: 16px; margin-right: 16px;
opacity: 0.7;
} }
.nav-link-icon, .nav-link-icon,
.collapsable-arrow { .collapse-arrow {
font-size: 16px; font-size: 16px;
width: 16px; width: 16px;
height: 16px; height: 16px;
@@ -99,7 +103,7 @@
} }
} }
&.nav-collapsable { &.nav-collapse {
display: block; display: block;
> .children { > .children {
@@ -131,7 +135,7 @@
> .nav-item { > .nav-item {
&.nav-collapsable { &.nav-collapse {
background: transparent; background: transparent;
transition: background 200ms ease-in-out; transition: background 200ms ease-in-out;
@@ -145,7 +149,7 @@
> .group-items { > .group-items {
> .nav-collapsable { > .nav-collapse {
background: transparent; background: transparent;
transition: background 200ms ease-in-out; transition: background 200ms ease-in-out;
@@ -172,7 +176,7 @@
.nav-item { .nav-item {
&.nav-collapsable { &.nav-collapse {
position: relative; position: relative;
.children { .children {
@@ -201,13 +205,13 @@
height: 56px; height: 56px;
} }
&.nav-collapsable { &.nav-collapse {
position: relative; position: relative;
> .nav-link { > .nav-link {
height: 56px; height: 56px;
.collapsable-arrow { .collapse-arrow {
display: none; 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: $carded-header-height - $carded-toolbar-height;
$carded-header-height-without-toolbar-sm: $carded-header-height-sm - $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 { .page-layout {
position: relative; position: relative;
overflow: hidden; overflow-x: hidden;
overflow-y: auto;
// Carded layout // Carded layout
&.carded { &.carded {
@@ -23,13 +27,15 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
min-width: 100%; min-width: 100%;
// Top bg // Top bg
> .top-bg { .top-bg {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
top: 0; top: 0;
right: 0; right: 0;
left: 0; left: 0;
height: $carded-header-height; height: $carded-header-height;
background-image: $top-bg-image;
background-size: cover;
@include media-breakpoint-down('sm') { @include media-breakpoint-down('sm') {
height: $carded-header-height-sm; height: $carded-header-height-sm;
@@ -39,215 +45,29 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
// Fullwidth // Fullwidth
&.fullwidth { &.fullwidth {
// Single scroll
&.single-scroll {
> .center {
flex: 1 0 auto;
max-height: none;
}
}
// Center // Center
> .center { > .center {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 0 auto; flex: 1;
position: relative; position: relative;
z-index: 2; z-index: 2;
padding: 0 32px; padding: 0 32px;
width: 100%; width: 100%;
min-width: 0; min-width: 100%;
max-width: 100%; max-width: 100%;
max-height: 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 { .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; height: $carded-header-height-without-toolbar;
min-height: $carded-header-height-without-toolbar; min-height: $carded-header-height-without-toolbar;
max-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; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1;
overflow: hidden; overflow: hidden;
@include mat-elevation(7); @include mat-elevation(7);
> .toolbar { .toolbar {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
flex: 1 1 auto;
border-bottom: 1px solid rgba(0, 0, 0, 0.12); border-bottom: 1px solid rgba(0, 0, 0, 0.12);
height: $carded-toolbar-height; height: $carded-toolbar-height;
min-height: $carded-toolbar-height; min-height: $carded-toolbar-height;
max-height: $carded-toolbar-height; max-height: $carded-toolbar-height;
.sidebar-toggle {
margin: 0 8px 0 0 !important;
padding: 0 !important;
border-radius: 0;
}
} }
> .content { > .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
&.tabbed { &.tabbed {
> .center { > mat-sidenav-container {
width: calc(100% - 32px);
min-width: 0;
@include media-breakpoint-down('md') { > .mat-sidenav-content,
width: calc(100% - 64px); > .mat-drawer-content {
} width: calc(100% - 240px);
min-width: 0;
> .header { .center {
flex: 1 1 auto; width: calc(100% - 32px);
} min-width: 0;
> .content-card { @include media-breakpoint-down('md') {
width: calc(100% - 64px);
}
> .content { .header {
display: flex; flex: 1;
}
> .mat-tab-group { .content-card {
overflow: hidden;
.mat-tab-header { .content {
.mat-tab-label { .mat-tab-group {
height: 64px;
}
}
.mat-tab-body {
overflow: hidden;
.mat-tab-body-content {
overflow: hidden; overflow: hidden;
.tab-content { .mat-tab-header {
position: relative;
width: 100%; .mat-tab-label {
height: 100%; height: 64px;
}
} }
}
}
}
}
}
}
}
// Inner scroll .mat-tab-body {
&.inner-scroll { overflow: hidden;
flex: 1 1 auto;
> .sidebar { .mat-tab-body-content {
overflow: hidden;
.content { .tab-content {
overflow: auto; position: relative;
} width: 100%;
} height: 100%;
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;
} }
} }
} }
@@ -390,15 +282,48 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
} }
} }
// Right sidebar specific // Left sidenav
&.right-sidebar { &.left-sidenav {
> .sidebar { // Sidenav
order: 2; > mat-sidenav-container {
.sidenav {
&.mat-is-locked-open {
~ .mat-sidenav-content,
~ .mat-drawer-content {
.center {
margin-left: 0;
}
}
}
}
} }
}
> .center { // Right sidenav
order: 1; &.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%; width: 100%;
min-width: 100%; min-width: 100%;
// Top bg
> .header {
background-image: $top-bg-image;
background-size: cover;
}
// Fullwidth // Fullwidth
&.fullwidth { &.fullwidth {
overflow: auto;
> .content {
flex: 1 1 auto;
min-width: 0;
}
} }
&.fullwidth, &.fullwidth,
&.inner-sidebar { &.inner-sidenav {
min-height: 100%;
> .header { > .header {
height: $header-height; height: $header-height;
@@ -430,138 +358,109 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
} }
} }
// Left / Right sidebar // Left sidenav - Right sidenav
&.left-sidebar, &.left-sidenav,
&.right-sidebar { &.right-sidenav {
flex-direction: row;
// Sidebar // Single scroll
> .sidebar { &.single-scroll {
width: 240px;
min-width: 240px;
max-width: 240px;
overflow: hidden;
@include mat-elevation(7);
&.locked-open { > mat-sidenav-container {
background: none; flex: 1 0 auto;
box-shadow: none;
+ .center { > .mat-sidenav-content,
z-index: 1001; > .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 // Inner Sidenav
> .center { &.inner-sidenav {
position: relative;
> 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; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1;
z-index: 3; background: none;
min-width: 0; z-index: 2;
@include mat-elevation(7); width: 100%;
> .header { .sidenav {
height: $header-height; width: 240px;
min-height: $header-height; min-width: 240px;
max-height: $header-height; max-width: 240px;
} z-index: 51;
@include mat-elevation(7);
> .content { &.mat-is-locked-open {
flex: 1 0 auto; width: 220px;
} min-width: 220px;
} max-width: 220px;
box-shadow: none;
background: transparent;
}
// Inner scroll .sidenav-content {
&.inner-scroll { height: 100%;
flex: 1 1 auto;
> .sidebar {
.content {
overflow: auto;
} }
} }
> .center { > .mat-sidenav-content,
flex: 1 1 auto; > .mat-drawer-content {
overflow: auto;
}
}
// Inner Sidebar
&.inner-sidebar {
flex-direction: column;
overflow: hidden;
height: 100%;
> .content {
display: flex; 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 { .center {
background: none; display: flex;
box-shadow: none; flex-direction: column;
} flex: 1;
overflow: auto;
@include mat-elevation(7);
.content { .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 { &.tabbed {
min-height: 100%; min-height: 100%;
> .header { .header {
height: $header-height; height: $header-height;
min-height: $header-height; min-height: $header-height;
max-height: $header-height; max-height: $header-height;
@@ -578,7 +477,7 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
> .content { > .content {
> .mat-tab-group { .mat-tab-group {
.mat-tab-labels { .mat-tab-labels {
padding: 0 24px; padding: 0 24px;
@@ -596,6 +495,50 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
@include media-breakpoint-down('xs') { @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 // Smaller margins
&.carded { &.carded {
@@ -606,11 +549,18 @@ $carded-header-height-without-toolbar-sm: $carded-header-height-sm - $carded-too
} }
} }
&.left-sidebar, &.left-sidenav,
&.right-sidebar { &.right-sidenav {
> .center { > mat-sidenav-container {
margin: 0 16px;
> .mat-sidenav-content,
> .mat-drawer-content {
.center {
margin: 0 16px;
}
}
} }
} }
} }

View File

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

View File

@@ -274,119 +274,4 @@ strong {
// Nowrap // Nowrap
.text-nowrap { .text-nowrap {
white-space: 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 // whitespace management
white-space: pre; // fallback white-space: pre; // fallback
//white-space: pre-wrap; white-space: pre-wrap;
//word-break: break-all; word-break: break-all;
//word-wrap: break-word; word-wrap: break-word;
font-family: $code-font-family; font-family: $code-font-family;
font-size: $code-font-size; font-size: $code-font-size;

View File

@@ -1,157 +1,93 @@
import { Inject, Injectable, InjectionToken } from '@angular/core'; import { Inject, Injectable, InjectionToken } from '@angular/core';
import { NavigationStart, Router } from '@angular/router'; import { NavigationEnd, NavigationStart, Router } from '@angular/router';
import { Platform } from '@angular/cdk/platform'; import { Platform } from '@angular/cdk/platform';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { filter } from 'rxjs/operators';
import * as _ from 'lodash'; import * as _ from 'lodash';
// Create the injection token for the custom settings // Create the injection token for the custom config
export const FUSE_CONFIG = new InjectionToken('fuseCustomConfig'); export const FUSE_CONFIG = new InjectionToken('fuseCustomConfig');
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseConfigService export class FuseConfigService
{ {
// Private config: any;
private _configSubject: BehaviorSubject<any>; defaultConfig: any;
private readonly _defaultConfig: any; isSetConfigRan = false;
onConfigChanged: BehaviorSubject<any>;
/** /**
* Constructor * Constructor
* *
* @param {Platform} _platform * @param router
* @param {Router} _router * @param platform
* @param _config * @param config
*/ */
constructor( constructor(
private _platform: Platform, private router: Router,
private _router: Router, public platform: Platform,
@Inject(FUSE_CONFIG) private _config @Inject(FUSE_CONFIG) config
) )
{ {
// Set the default config from the user provided config (from forRoot) // Set the default config from the user provided one (forRoot)
this._defaultConfig = _config; this.defaultConfig = config;
// Initialize the service
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ 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 // Set the config from the default config
this._configSubject = new BehaviorSubject(_.cloneDeep(this._defaultConfig)); this.config = _.cloneDeep(this.defaultConfig);
// Reload the default config on every navigation start if // Reload the default settings for the
// the current config is different from the default one // layout on every navigation start
this._router.events router.events.subscribe(
.pipe(filter(event => event instanceof NavigationStart)) (event) => {
.subscribe(() => {
if ( !_.isEqual(this._configSubject.getValue(), this._defaultConfig) ) if ( event instanceof NavigationStart )
{ {
// Clone the default config this.isSetConfigRan = false;
const config = _.cloneDeep(this._defaultConfig);
// Set the config
this._configSubject.next(config);
} }
});
if ( event instanceof NavigationEnd )
{
if ( this.isSetConfigRan )
{
return;
}
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 config
* @param {{emitEvent: boolean}} opts
*/ */
setConfig(value, opts = {emitEvent: true}): void setConfig(config): void
{ {
// Get the value from the behavior subject // Set the SetConfigRan true
let config = this._configSubject.getValue(); this.isSetConfigRan = true;
// Merge the new config // Merge the config
config = _.merge({}, config, value); this.config = _.merge({}, this.config, config);
// If emitEvent option is true... // Trigger the event
if ( opts.emitEvent === true ) this.onConfigChanged.next(this.config);
{
// 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));
} }
} }

View File

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

@@ -2,50 +2,22 @@ import { MediaChange, ObservableMedia } from '@angular/flex-layout';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseMatchMediaService export class FuseMatchMediaService
{ {
activeMediaQuery: string; activeMediaQuery: string;
onMediaChange: BehaviorSubject<string> = new BehaviorSubject<string>(''); onMediaChange: BehaviorSubject<string> = new BehaviorSubject<string>('');
/** constructor(private observableMedia: ObservableMedia)
* Constructor
*
* @param {ObservableMedia} _observableMedia
*/
constructor(
private _observableMedia: ObservableMedia
)
{ {
// Set the defaults
this.activeMediaQuery = ''; this.activeMediaQuery = '';
// Initialize this.observableMedia.subscribe((change: MediaChange) => {
this._init(); 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);
}
});
}
} }

View File

@@ -3,50 +3,26 @@ import { DOCUMENT } from '@angular/common';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseSplashScreenService export class FuseSplashScreenService
{ {
splashScreenEl: any; splashScreenEl;
player: AnimationPlayer; public player: AnimationPlayer;
/**
* Constructor
*
* @param {AnimationBuilder} _animationBuilder
* @param _document
* @param {Router} _router
*/
constructor( constructor(
private _animationBuilder: AnimationBuilder, private animationBuilder: AnimationBuilder,
@Inject(DOCUMENT) private _document: any, @Inject(DOCUMENT) private document: any,
private _router: Router private router: Router
) )
{
// Initialize
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{ {
// Get the splash screen element // Get the splash screen element
this.splashScreenEl = this._document.body.querySelector('#fuse-splash-screen'); this.splashScreenEl = this.document.body.querySelector('#fuse-splash-screen');
// If the splash screen element exists... // If the splash screen element exists...
if ( this.splashScreenEl ) if ( this.splashScreenEl )
{ {
// Hide it on the first NavigationEnd event // Hide it on the first NavigationEnd event
const hideOnLoad = this._router.events.subscribe((event) => { const hideOnLoad = this.router.events.subscribe((event) => {
if ( event instanceof NavigationEnd ) if ( event instanceof NavigationEnd )
{ {
setTimeout(() => { setTimeout(() => {
@@ -62,17 +38,10 @@ export class FuseSplashScreenService
} }
} }
// ----------------------------------------------------------------------------------------------------- show()
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Show the splash screen
*/
show(): void
{ {
this.player = this.player =
this._animationBuilder this.animationBuilder
.build([ .build([
style({ style({
opacity: '0', opacity: '0',
@@ -86,13 +55,10 @@ export class FuseSplashScreenService
}, 0); }, 0);
} }
/** hide()
* Hide the splash screen
*/
hide(): void
{ {
this.player = this.player =
this._animationBuilder this.animationBuilder
.build([ .build([
style({opacity: '1'}), style({opacity: '1'}),
animate('400ms ease', style({ animate('400ms ease', style({

View File

@@ -7,39 +7,21 @@ export interface Locale
data: Object; data: Object;
} }
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseTranslationLoaderService export class FuseTranslationLoaderService
{ {
/** constructor(private translate: TranslateService)
* Constructor
*
* @param {TranslateService} _translateService
*/
constructor(
private _translateService: TranslateService
)
{ {
} }
// ----------------------------------------------------------------------------------------------------- public loadTranslations(...args: Locale[]): void
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Load translations
*
* @param {Locale} args
*/
loadTranslations(...args: Locale[]): void
{ {
const locales = [...args]; const locales = [...args];
locales.forEach((locale) => { locales.forEach((locale) => {
// use setTranslation() with the third argument set to true // use setTranslation() with the third argument set to true
// to append translations instead of replacing them // to append translations instead of replacing them
this._translateService.setTranslation(locale.lang, locale.data, true); this.translate.setTranslation(locale.lang, locale.data, true);
}); });
} }
} }

View File

@@ -1,25 +0,0 @@
export interface FuseConfig
{
layout: {
style: string,
width: 'fullwidth' | 'boxed',
navbar: {
background: string,
hidden: boolean,
folded: boolean,
position: 'left' | 'right' | 'top',
variant: string
},
toolbar: {
background: string,
hidden: boolean,
position: 'above' | 'above-static' | 'above-fixed' | 'below' | 'below-static' | 'below-fixed'
}
footer: {
background: string,
hidden: boolean,
position: 'above' | 'above-static' | 'above-fixed' | 'below' | 'below-static' | 'below-fixed'
}
};
customScrollbars: boolean;
}

View File

@@ -1,27 +0,0 @@
export interface FuseNavigationItem
{
id: string;
title: string;
type: 'item' | 'group' | 'collapsable';
translate?: string;
icon?: string;
hidden?: boolean;
url?: string;
classes?: string;
exactMatch?: boolean;
externalUrl?: boolean;
openInNewTab?: boolean;
function?: any;
badge?: {
title?: string;
translate?: string;
bg?: string;
fg?: string;
};
children?: FuseNavigationItem[];
}
export interface FuseNavigation extends FuseNavigationItem
{
children?: FuseNavigationItem[];
}

View File

@@ -1,2 +0,0 @@
export * from './fuse-config';
export * from './fuse-navigation';

View File

@@ -1,13 +1,6 @@
export class FuseUtils export class FuseUtils
{ {
/** public static filterArrayByString(mainArr, searchText)
* Filter array by string
*
* @param mainArr
* @param searchText
* @returns {any}
*/
public static filterArrayByString(mainArr, searchText): any
{ {
if ( searchText === '' ) if ( searchText === '' )
{ {
@@ -21,14 +14,7 @@ export class FuseUtils
}); });
} }
/** public static searchInObj(itemObj, searchText)
* Search in object
*
* @param itemObj
* @param searchText
* @returns {boolean}
*/
public static searchInObj(itemObj, searchText): boolean
{ {
for ( const prop in itemObj ) for ( const prop in itemObj )
{ {
@@ -65,14 +51,7 @@ export class FuseUtils
} }
} }
/** public static searchInArray(arr, searchText)
* Search in array
*
* @param arr
* @param searchText
* @returns {boolean}
*/
public static searchInArray(arr, searchText): boolean
{ {
for ( const value of arr ) for ( const value of arr )
{ {
@@ -94,26 +73,14 @@ export class FuseUtils
} }
} }
/** public static searchInString(value, searchText)
* Search in string
*
* @param value
* @param searchText
* @returns {any}
*/
public static searchInString(value, searchText): any
{ {
return value.toLowerCase().includes(searchText); return value.toLowerCase().includes(searchText);
} }
/** public static generateGUID()
* Generate a unique GUID
*
* @returns {string}
*/
public static generateGUID(): string
{ {
function S4(): string function S4()
{ {
return Math.floor((1 + Math.random()) * 0x10000) return Math.floor((1 + Math.random()) * 0x10000)
.toString(16) .toString(16)
@@ -123,13 +90,7 @@ export class FuseUtils
return S4() + S4(); return S4() + S4();
} }
/** public static toggleInArray(item, array)
* Toggle in array
*
* @param item
* @param array
*/
public static toggleInArray(item, array): void
{ {
if ( array.indexOf(item) === -1 ) if ( array.indexOf(item) === -1 )
{ {
@@ -141,13 +102,7 @@ export class FuseUtils
} }
} }
/** public static handleize(text)
* Handleize
*
* @param text
* @returns {string}
*/
public static handleize(text): string
{ {
return text.toString().toLowerCase() return text.toString().toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with - .replace(/\s+/g, '-') // Replace spaces with -

View File

@@ -1,29 +1 @@
<!-- VERTICAL LAYOUT 1 --> <fuse-main></fuse-main>
<ng-container *ngIf="fuseConfig.layout.style === 'vertical-layout-1'">
<vertical-layout-1></vertical-layout-1>
</ng-container>
<!-- VERTICAL LAYOUT 2 -->
<ng-container *ngIf="fuseConfig.layout.style === 'vertical-layout-2'">
<vertical-layout-2></vertical-layout-2>
</ng-container>
<!-- VERTICAL LAYOUT 3 -->
<ng-container *ngIf="fuseConfig.layout.style === 'vertical-layout-3'">
<vertical-layout-3></vertical-layout-3>
</ng-container>
<!-- HORIZONTAL LAYOUT 1 -->
<ng-container *ngIf="fuseConfig.layout.style === 'horizontal-layout-1'">
<horizontal-layout-1></horizontal-layout-1>
</ng-container>
<!-- THEME OPTIONS PANEL -->
<button mat-icon-button class="mat-primary-bg mat-elevation-z2 theme-options-button"
(click)="toggleSidebarOpen('themeOptionsPanel')">
<mat-icon>settings</mat-icon>
</button>
<fuse-sidebar name="themeOptionsPanel" class="theme-options-sidebar" position="right" [invisibleOverlay]="true">
<fuse-theme-options></fuse-theme-options>
</fuse-sidebar>

View File

@@ -1,44 +0,0 @@
@import "src/@fuse/scss/fuse";
:host {
position: relative;
display: flex;
flex: 1 1 auto;
width: 100%;
height: 100%;
min-width: 0;
.theme-options-button {
position: absolute;
top: 160px;
right: 70px;
width: 48px;
height: 48px;
line-height: 48px;
text-align: center;
cursor: pointer;
border-radius: 0;
margin: 0;
pointer-events: auto;
opacity: .90;
z-index: 998;
@include media-breakpoint-down('md') {
right: 0;
}
mat-icon {
animation: rotating 3s linear infinite;
}
&:hover {
opacity: 1;
}
}
.theme-options-sidebar {
width: 360px;
min-width: 360px;
max-width: 360px;
}
}

View File

@@ -1,125 +1,37 @@
import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { Component } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { Platform } from '@angular/cdk/platform';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseConfigService } from '@fuse/services/config.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 { FuseSplashScreenService } from '@fuse/services/splash-screen.service';
import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service'; import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { navigation } from 'app/navigation/navigation'; import { locale as navigationEnglish } from './navigation/i18n/en';
import { locale as navigationEnglish } from 'app/navigation/i18n/en'; import { locale as navigationTurkish } from './navigation/i18n/tr';
import { locale as navigationTurkish } from 'app/navigation/i18n/tr';
@Component({ @Component({
selector : 'app', selector : 'fuse-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls : ['./app.component.scss'] styleUrls : ['./app.component.scss']
}) })
export class AppComponent implements OnInit, OnDestroy export class AppComponent
{ {
navigation: any;
fuseConfig: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {DOCUMENT} document
* @param {FuseConfigService} _fuseConfigService
* @param {FuseNavigationService} _fuseNavigationService
* @param {FuseSidebarService} _fuseSidebarService
* @param {FuseSplashScreenService} _fuseSplashScreenService
* @param {FuseTranslationLoaderService} _fuseTranslationLoaderService
* @param {Platform} _platform
* @param {TranslateService} _translateService
*/
constructor( constructor(
@Inject(DOCUMENT) private document: any, private translate: TranslateService,
private _fuseConfigService: FuseConfigService, private fuseNavigationService: FuseNavigationService,
private _fuseNavigationService: FuseNavigationService, private fuseSplashScreen: FuseSplashScreenService,
private _fuseSidebarService: FuseSidebarService, private fuseTranslationLoader: FuseTranslationLoaderService
private _fuseSplashScreenService: FuseSplashScreenService,
private _fuseTranslationLoaderService: FuseTranslationLoaderService,
private _translateService: TranslateService,
private _platform: Platform
) )
{ {
// Get default navigation
this.navigation = navigation;
// Register the navigation to the service
this._fuseNavigationService.register('main', this.navigation);
// Set the main navigation as our current navigation
this._fuseNavigationService.setCurrentNavigation('main');
// Add languages // Add languages
this._translateService.addLangs(['en', 'tr']); this.translate.addLangs(['en', 'tr']);
// Set the default language // Set the default language
this._translateService.setDefaultLang('en'); this.translate.setDefaultLang('en');
// Set the navigation translations // Set the navigation translations
this._fuseTranslationLoaderService.loadTranslations(navigationEnglish, navigationTurkish); this.fuseTranslationLoader.loadTranslations(navigationEnglish, navigationTurkish);
// Use a language // Use a language
this._translateService.use('en'); this.translate.use('en');
// Add is-mobile class to the body if the platform is mobile
if ( this._platform.ANDROID || this._platform.IOS )
{
this.document.body.className += ' is-mobile';
}
// 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
// -----------------------------------------------------------------------------------------------------
/**
* Toggle sidebar open
*
* @param key
*/
toggleSidebarOpen(key): void
{
this._fuseSidebarService.getSidebar(key).toggleOpen();
} }
} }

View File

@@ -3,47 +3,22 @@ import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
import { MatButtonModule, MatIconModule } from '@angular/material';
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import 'hammerjs'; import 'hammerjs';
import { FuseModule } from '@fuse/fuse.module'; import { FuseModule } from '@fuse/fuse.module';
import { FuseSharedModule } from '@fuse/shared.module'; import { FuseSharedModule } from '@fuse/shared.module';
import { FuseSidebarModule, FuseThemeOptionsModule } from '@fuse/components';
import { fuseConfig } from 'app/fuse-config'; import { fuseConfig } from './fuse-config';
import { FakeDbService } from 'app/fake-db/fake-db.service'; import { AppComponent } from './app.component';
import { AppComponent } from 'app/app.component'; import { FuseMainModule } from './main/main.module';
import { AppStoreModule } from 'app/store/store.module'; import { FuseSampleModule } from './main/content/sample/sample.module';
import { LayoutModule } from 'app/layout/layout.module';
const appRoutes: Routes = [ const appRoutes: Routes = [
{
path : 'apps',
loadChildren: './main/apps/apps.module#AppsModule'
},
{
path : 'pages',
loadChildren: './main/pages/pages.module#PagesModule'
},
{
path : 'ui',
loadChildren: './main/ui/ui.module#UIModule'
},
{
path : 'documentation',
loadChildren: './main/documentation/documentation.module#DocumentationModule'
},
{
path : 'angular-material-elements',
loadChildren: './main/angular-material-elements/angular-material-elements.module#AngularMaterialElementsModule'
},
{ {
path : '**', path : '**',
redirectTo: 'apps/dashboards/analytics' redirectTo: 'sample'
} }
]; ];
@@ -56,29 +31,13 @@ const appRoutes: Routes = [
BrowserAnimationsModule, BrowserAnimationsModule,
HttpClientModule, HttpClientModule,
RouterModule.forRoot(appRoutes), RouterModule.forRoot(appRoutes),
TranslateModule.forRoot(), TranslateModule.forRoot(),
InMemoryWebApiModule.forRoot(FakeDbService, {
delay : 0,
passThruUnknownUrl: true
}),
// Material moment date module // Fuse Main and Shared modules
MatMomentDateModule,
// Material
MatButtonModule,
MatIconModule,
// Fuse modules
FuseModule.forRoot(fuseConfig), FuseModule.forRoot(fuseConfig),
FuseSharedModule, FuseSharedModule,
FuseSidebarModule, FuseMainModule,
FuseThemeOptionsModule, FuseSampleModule
// App modules
LayoutModule,
AppStoreModule
], ],
bootstrap : [ bootstrap : [
AppComponent AppComponent

View File

@@ -1,773 +0,0 @@
export class AcademyFakeDb
{
public static courses = [
{
'id' : '15459251a6d6b397565',
'title' : 'Basics of Angular',
'slug' : 'basics-of-angular',
'category': 'web',
'length' : 30,
'updated' : 'Jun 28, 2017'
},
{
'id' : '154588a0864d2881124',
'title' : 'Basics of TypeScript',
'slug' : 'basics-of-typeScript',
'category': 'web',
'length' : 60,
'updated' : 'Nov 01, 2017'
},
{
'id' : '15453ba60d3baa5daaf',
'title' : 'Android N: Quick Settings',
'slug' : 'android-n-quick-settings',
'category': 'android',
'length' : 120,
'updated' : 'Jun 28, 2017'
},
{
'id' : '15453a06c08fb021776',
'title' : 'Keep Sensitive Data Safe and Private',
'slug' : 'keep-sensitive-data-safe-and-private',
'category': 'android',
'length' : 45,
'updated' : 'Jun 28, 2017'
},
{
'id' : '15427f4c1b7f3953234',
'title' : 'Building a gRPC Service with Java',
'slug' : 'building-a-grpc-service-with-java',
'category': 'cloud',
'length' : 30,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1542d75d929a603125',
'title' : 'Build a PWA Using Workbox',
'slug' : 'build-a-pwa-using-workbox',
'category': 'web',
'length' : 120,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1543ee3a5b43e0f9f45',
'title' : 'Build an App for the Google Assistant with Firebase and Dialogflow',
'slug' : 'build-an-app-for-the-google-assistant-with-firebase-and-dialogflow',
'category': 'firebase',
'length' : 30,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1543cc4515df3146112',
'title' : 'Cloud Functions for Firebase',
'slug' : 'cloud-functions-for-firebase',
'category': 'firebase',
'length' : 45,
'updated' : 'Jun 28, 2017'
},
{
'id' : '154398a4770d7aaf9a2',
'title' : 'Manage Your Pivotal Cloud Foundry App\'s Using Apigee Edge',
'slug' : 'manage-your-pivotal-cloud-foundry-apps-using-apigee-Edge',
'category': 'cloud',
'length' : 90,
'updated' : 'Jun 28, 2017'
},
{
'id' : '15438351f87dcd68567',
'title' : 'Building Beautiful UIs with Flutter',
'your' : 'building-beautiful-uis-with-flutter',
'category': 'web',
'length' : 90,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1544e43dcdae6ebf876',
'title' : 'Cloud Firestore',
'slug' : 'cloud-firestore',
'category': 'firebase',
'length' : 90,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1541ca7af66da284177',
'title' : 'Customize Network Topology with Subnetworks',
'slug' : 'customize-network-topology-with-subnetworks',
'category': 'web',
'length' : 45,
'updated' : 'Jun 28, 2017'
},
{
'id' : '154297167e781781745',
'title' : 'Looking at Campaign Finance with BigQuery',
'slug' : 'looking-at-campaign-finance-with-bigquery',
'category': 'cloud',
'length' : 60,
'updated' : 'Jun 28, 2017'
},
{
'id' : '154537435d5b32bf11a',
'title' : 'Firebase Android',
'slug' : 'firebase-android',
'category': 'android',
'length' : 45,
'updated' : 'Jun 28, 2017'
},
{
'id' : '154204e45a59b168453',
'title' : 'Simulating a Thread Network Using OpenThread',
'slug' : 'simulating-a-thread-network-using-openthread',
'category': 'web',
'length' : 45,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1541dd1e05dfc439216',
'title' : 'Your First Progressive Web App',
'slug' : 'your-first-progressive-web-app',
'category': 'web',
'length' : 30,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1532dfc67e704e48515',
'title' : 'Launch Cloud Datalab',
'slug' : 'launch-cloud-datalab',
'category': 'cloud',
'length' : 60,
'updated' : 'Jun 28, 2017'
},
{
'id' : '1542e43dfaae6ebf226',
'title' : 'Personalize Your iOS App with Firebase User Management',
'slug' : 'personalize-your-ios-app-with-firebase-user-management',
'category': 'firebase',
'length' : 90,
'updated' : 'Jun 28, 2017'
}
];
public static categories = [
{
'id' : 0,
'value': 'web',
'label': 'Web'
},
{
'id' : 1,
'value': 'firebase',
'label': 'Firebase'
},
{
'id' : 2,
'value': 'cloud',
'label': 'Cloud'
},
{
'id' : 3,
'value': 'android',
'label': 'Android'
}
];
private static demoSteps = [
{
'title' : 'Introduction',
'content': '<h1>Step 1 - Introduction</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Get the sample code',
'content': '<h1>Step 2 - Get the sample code</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Create a Firebase project and Set up your app',
'content': '<h1>Step 3 - Create a Firebase project and Set up your app</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Install the Firebase Command Line Interface',
'content': '<h1>Step 4 - Install the Firebase Command Line Interface</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Deploy and run the web app',
'content': '<h1>Step 5 - Deploy and run the web app</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'The Functions Directory',
'content': '<h1>Step 6 - The Functions Directory</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Import the Cloud Functions and Firebase Admin modules',
'content': '<h1>Step 7 - Import the Cloud Functions and Firebase Admin modules</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Welcome New Users',
'content': '<h1>Step 8 - Welcome New Users</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Images moderation',
'content': '<h1>Step 9 - Images moderation</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'New Message Notifications',
'content': '<h1>Step 10 - New Message Notifications</h1>' +
'<br>' +
'This is an example step of the course. You can put anything in here from example codes to videos.' +
'<br><br>' +
'To install the CLI you need to have installed <b>npm</b> which typically comes with <b>NodeJS</b>.' +
'To install or upgrade the CLI run the following <b>npm</b> command:' +
'<br><br>' +
'<code>npm -g install @angular/cli</code>' +
'<br><br>' +
'To verify that the CLI has been installed correctly, open a console and run:' +
'<br><br>' +
'<code>ng version</code>' +
'<br><br>' +
'<h2>Install dependencies</h2>' +
'<br>' +
'To moderate the images we\'ll need a few Node.js packages:' +
'<br><br>' +
'<ul>' +
'<li>' +
'The Google Cloud Vision Client Library for Node.js: @google-cloud/vision to run the image through the Cloud Vision API to detect inappropriate images.' +
'</li>' +
'<br>' +
'<li>' +
'The Google Cloud Storage Client Library for Node.js: @google-cloud/storage to download and upload the images from Cloud Storage.' +
'</li>' +
'<br>' +
'<li>' +
'A Node.js library allowing us to run processes: child-process-promise to run ImageMagick since the ImageMagick command-line tool comes pre-installed on all Functions instances.' +
'</li>' +
'</ul>' +
'<br>' +
'To install these three packages into your Cloud Functions app, run the following npm install --save command. Make sure that you do this from the functions directory.' +
'<br><br>' +
'<code>npm install --save @google-cloud/vision @google-cloud/storage child-process-promise</code>' +
'<br><br>' +
'This will install the three packages locally and add them as declared dependencies in your package.js file.'
},
{
'title' : 'Congratulations!',
'content': '<h1>Step 11 - Congratulations!</h1>' +
'<br>' +
'You\'ve built a full-fidelity, offline-capable progressive web app by leveraging the power of reusable Web Components and Firebase. Why bother with a native app when you know how to do all that?!'
}
];
public static course = [
{
'id' : '15459251a6d6b397565',
'title' : 'Basics of Angular',
'slug' : 'basics-of-angular',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 30,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '154588a0864d2881124',
'title' : 'Basics of TypeScript',
'slug' : 'basics-of-typeScript',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 60,
'totalSteps' : 11,
'updated' : 'Nov 01, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '15453ba60d3baa5daaf',
'title' : 'Android N: Quick Settings',
'slug' : 'android-n-quick-settings',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'android',
'length' : 120,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '15453a06c08fb021776',
'title' : 'Keep Sensitive Data Safe and Private',
'slug' : 'keep-sensitive-data-safe-and-private',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'android',
'length' : 45,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '15427f4c1b7f3953234',
'title' : 'Building a gRPC Service with Java',
'slug' : 'building-a-grpc-service-with-java',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'cloud',
'length' : 30,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1542d75d929a603125',
'title' : 'Build a PWA Using Workbox',
'slug' : 'build-a-pwa-using-workbox',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 120,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1543ee3a5b43e0f9f45',
'title' : 'Build an App for the Google Assistant with Firebase and Dialogflow',
'slug' : 'build-an-app-for-the-google-assistant-with-firebase-and-dialogflow',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'firebase',
'length' : 30,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1543cc4515df3146112',
'title' : 'Cloud Functions for Firebase',
'slug' : 'cloud-functions-for-firebase',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'firebase',
'length' : 45,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '154398a4770d7aaf9a2',
'title' : 'Manage Your Pivotal Cloud Foundry App\'s Using Apigee Edge',
'slug' : 'manage-your-pivotal-cloud-foundry-apps-using-apigee-Edge',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'cloud',
'length' : 90,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '15438351f87dcd68567',
'title' : 'Building Beautiful UIs with Flutter',
'your' : 'building-beautiful-uis-with-flutter',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 90,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1544e43dcdae6ebf876',
'title' : 'Cloud Firestore',
'slug' : 'cloud-firestore',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'firebase',
'length' : 90,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1541ca7af66da284177',
'title' : 'Customize Network Topology with Subnetworks',
'slug' : 'customize-network-topology-with-subnetworks',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 45,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '154297167e781781745',
'title' : 'Looking at Campaign Finance with BigQuery',
'slug' : 'looking-at-campaign-finance-with-bigquery',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'cloud',
'length' : 60,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '154537435d5b32bf11a',
'title' : 'Firebase Android',
'slug' : 'firebase-android',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'android',
'length' : 45,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '154204e45a59b168453',
'title' : 'Simulating a Thread Network Using OpenThread',
'slug' : 'simulating-a-thread-network-using-openthread',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 45,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1541dd1e05dfc439216',
'title' : 'Your First Progressive Web App',
'slug' : 'your-first-progressive-web-app',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'web',
'length' : 30,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1532dfc67e704e48515',
'title' : 'Launch Cloud Datalab',
'slug' : 'launch-cloud-datalab',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'cloud',
'length' : 60,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
},
{
'id' : '1542e43dfaae6ebf226',
'title' : 'Personalize Your iOS App with Firebase User Management',
'slug' : 'personalize-your-ios-app-with-firebase-user-management',
'description': 'Commits that need to be pushed lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'category' : 'firebase',
'length' : 90,
'totalSteps' : 11,
'updated' : 'Jun 28, 2017',
'steps' : AcademyFakeDb.demoSteps
}
];
}

View File

@@ -1,97 +0,0 @@
import {
startOfDay,
endOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours
} from 'date-fns';
export class CalendarFakeDb
{
public static data = [
{
id : 'events',
data: [
{
start : subDays(startOfDay(new Date()), 1),
end : addDays(new Date(), 1),
title : 'A 3 day event',
allDay : false,
color : {
primary : '#ad2121',
secondary: '#FAE3E3'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : startOfDay(new Date()),
title : 'An event with no end date',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : subDays(endOfMonth(new Date()), 3),
end : addDays(endOfMonth(new Date()), 3),
title : 'A long event that spans 2 months',
allDay : false,
color : {
primary : '#1e90ff',
secondary: '#D1E8FF'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
},
{
start : addHours(startOfDay(new Date()), 2),
end : new Date(),
title : 'A draggable and resizable event',
allDay : false,
color : {
primary : '#e3bc08',
secondary: '#FDF1BA'
},
resizable: {
beforeStart: true,
afterEnd : true
},
draggable: true,
meta : {
location: 'Los Angeles',
notes : 'Eos eu verear adipiscing, ex ornatus denique iracundia sed, quodsi oportere appellantur an pri.'
}
}
]
}
];
}

View File

@@ -1,343 +0,0 @@
export class ChatPanelFakeDb
{
public static contacts = [
{
'id' : '5725a680b3249760ea21de52',
'name' : 'Alice Freeman',
'avatar': 'assets/images/avatars/alice.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '2'
},
{
'id' : '5725a680606588342058356d',
'name' : 'Arnold',
'avatar': 'assets/images/avatars/Arnold.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a68009e20d0a9e9acf2a',
'name' : 'Barrera',
'avatar': 'assets/images/avatars/Barrera.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a6809fdd915739187ed5',
'name' : 'Blair',
'avatar': 'assets/images/avatars/Blair.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '3'
},
{
'id' : '5725a68007920cf75051da64',
'name' : 'Boyle',
'avatar': 'assets/images/avatars/Boyle.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '1'
},
{
'id' : '5725a68031fdbb1db2c1af47',
'name' : 'Christy',
'avatar': 'assets/images/avatars/Christy.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680bc670af746c435e2',
'name' : 'Copeland',
'avatar': 'assets/images/avatars/Copeland.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680e7eb988a58ddf303',
'name' : 'Estes',
'avatar': 'assets/images/avatars/Estes.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680dcb077889f758961',
'name' : 'Harper',
'avatar': 'assets/images/avatars/Harper.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a6806acf030f9341e925',
'name' : 'Helen',
'avatar': 'assets/images/avatars/Helen.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680ae1ae9a3c960d487',
'name' : 'Henderson',
'avatar': 'assets/images/avatars/Henderson.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680b8d240c011dd224b',
'name' : 'Josefina',
'avatar': 'assets/images/avatars/Josefina.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a68034cb3968e1f79eac',
'name' : 'Katina',
'avatar': 'assets/images/avatars/Katina.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a6801146cce777df2a08',
'name' : 'Lily',
'avatar': 'assets/images/avatars/Lily.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '10'
},
{
'id' : '5725a6808a178bfd034d6ecf',
'name' : 'Mai',
'avatar': 'assets/images/avatars/Mai.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680653c265f5c79b5a9',
'name' : 'Nancy',
'avatar': 'assets/images/avatars/Nancy.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680bbcec3cc32a8488a',
'name' : 'Nora',
'avatar': 'assets/images/avatars/Nora.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '7'
},
{
'id' : '5725a6803d87f1b77e17b62b',
'name' : 'Odessa',
'avatar': 'assets/images/avatars/Odessa.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...',
'unread': '1'
},
{
'id' : '5725a680e87cb319bd9bd673',
'name' : 'Reyna',
'avatar': 'assets/images/avatars/Reyna.jpg',
'status': 'offline',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a6802d10e277a0f35775',
'name' : 'Shauna',
'avatar': 'assets/images/avatars/Shauna.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680aef1e5cf26dd3d1f',
'name' : 'Shepard',
'avatar': 'assets/images/avatars/Shepard.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a680cd7efa56a45aea5d',
'name' : 'Tillman',
'avatar': 'assets/images/avatars/Tillman.jpg',
'status': 'do-not-disturb',
'mood' : '',
'unread': '99+'
},
{
'id' : '5725a680fb65c91a82cb35e2',
'name' : 'Trevino',
'avatar': 'assets/images/avatars/Trevino.jpg',
'status': 'away',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a68018c663044be49cbf',
'name' : 'Tyson',
'avatar': 'assets/images/avatars/Tyson.jpg',
'status': 'do-not-disturb',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
},
{
'id' : '5725a6809413bf8a0a5272b1',
'name' : 'Velazquez',
'avatar': 'assets/images/avatars/Velazquez.jpg',
'status': 'online',
'mood' : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'
}
];
public static chats = [
{
'id' : '1725a680b3249760ea21de52',
'dialog': [
{
'who' : '5725a680b3249760ea21de52',
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
'time' : '2017-03-22T08:54:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Im having breakfast right now, cant you wait for 10 minutes?',
'time' : '2017-03-22T08:55:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Im having breakfast right now, cant you wait for 10 minutes?',
'time' : '2017-03-22T08:55:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'We are losing money! Quick!',
'time' : '2017-03-22T09:00:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Its not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
'time' : '2017-03-22T09:02:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T09:05:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'We are losing money! Quick!',
'time' : '2017-03-22T09:15:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T09:05:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'We are losing money! Quick!',
'time' : '2017-03-22T09:15:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Its not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
'time' : '2017-03-22T09:20:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T09:22:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'We are losing money! Quick!',
'time' : '2017-03-22T09:25:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Its not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
'time' : '2017-03-22T09:27:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T09:33:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T09:33:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'We are losing money! Quick!',
'time' : '2017-03-22T09:35:28.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Its not my money, you know. I will eat my breakfast and then I will come to the meeting room.',
'time' : '2017-03-22T09:45:28.299Z'
},
{
'who' : '5725a680b3249760ea21de52',
'message': 'You are the worst!',
'time' : '2017-03-22T10:00:28.299Z'
}
]
},
{
'id' : '2725a680b8d240c011dd2243',
'dialog': [
{
'who' : '5725a680606588342058356d',
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
'time' : '2017-04-22T01:00:00.299Z'
},
{
'who' : '5725a6802d10e277a0f35724',
'message': 'Im having breakfast right now, cant you wait for 10 minutes?',
'time' : '2017-04-22T01:05:00.299Z'
},
{
'who' : '5725a680606588342058356d',
'message': 'We are losing money! Quick!',
'time' : '2017-04-22T01:10:00.299Z'
}
]
},
{
'id' : '3725a6809413bf8a0a5272b4',
'dialog': [
{
'who' : '5725a68009e20d0a9e9acf2a',
'message': 'Quickly come to the meeting room 1B, we have a big server issue',
'time' : '2017-04-22T02:10:00.299Z'
}
]
}
];
public static user = [
{
'id' : '5725a6802d10e277a0f35724',
'name' : 'John Doe',
'avatar' : 'assets/images/avatars/profile.jpg',
'status' : 'online',
'mood' : '',
'chatList': [
{
'chatId' : '1725a680b3249760ea21de52',
'contactId' : '5725a680b3249760ea21de52',
'lastMessageTime': '2017-06-12T02:10:18.931Z'
},
{
'chatId' : '2725a680b8d240c011dd2243',
'contactId' : '5725a680606588342058356d',
'lastMessageTime': '2017-02-18T10:30:18.931Z'
},
{
'chatId' : '3725a6809413bf8a0a5272b4',
'contactId' : '5725a68009e20d0a9e9acf2a',
'lastMessageTime': '2017-03-18T12:30:18.931Z'
}
]
}
];
}

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