Compare commits

..

77 Commits

Author SHA1 Message Date
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
1509 changed files with 17818 additions and 103548 deletions

67
.angular-cli.json Normal file
View File

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

View File

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

5
.gitignore vendored
View File

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

16
CREDITS
View File

@@ -1,16 +0,0 @@
// -----------------------------------------------------------------------------------------------------
// @ Image/Vector/Icon Credits
// -----------------------------------------------------------------------------------------------------
Avatars - https://uifaces.co/
Flag icons - http://www.famfamfam.com/lab/icons/flags/
Frame vector created by Freepik - https://www.freepik.com/free-photos-vectors/frame
A Walk Amongst Friends - Photo by Kristin Ellis on Unsplash - https://unsplash.com/photos/CbZOGbazDWQ
Sunrise at Moraine Lake - Photo by Marlon Martinez on Unsplash - https://unsplash.com/photos/woNYcfrnp9M
Braies Lake - Photo by Luca Nicoletti on Unsplash - https://unsplash.com/photos/dH-L5zPcv3E
Lago di Sorapis - Photo by eberhard grossgasteiger on Unsplash - https://unsplash.com/photos/6uDg_zb20EM
Lago di Braies - Photo by Salmen Bejaoui on Unsplash - https://unsplash.com/photos/uXTozY3CcQg
Reaching - Photo by Justin Novello on Unsplash - https://unsplash.com/photos/Y14TNvIDllM
Yosemite - Photo by Tim Mossholder on Unsplash - https://unsplash.com/photos/ZCrtRSSUpGI
Never Stop Changing - Photo by John Westrock on Unsplash - https://unsplash.com/photos/_GY56uSG70U
Fall glow - Photo by Casey Horner on Unsplash - https://unsplash.com/photos/gz19zOdgN7w
First snow - Photo by eberhard grossgasteiger on Unsplash - https://unsplash.com/photos/LRrGf6dBjA4

View File

@@ -1,2 +1 @@
This project is protected by Envato's Regular License. For more information,
check the official license page at https://themeforest.net/licenses/terms/regular
https://themeforest.net/licenses/terms/regular

View File

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

View File

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

View File

@@ -1,12 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

14
e2e/app.e2e-spec.ts Normal file
View File

@@ -0,0 +1,14 @@
import { Fuse2Page } from './app.po';
describe('Fuse2 App', () => {
let page: Fuse2Page;
beforeEach(() => {
page = new Fuse2Page();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});

11
e2e/app.po.ts Normal file
View File

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class Fuse2Page {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

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

View File

@@ -1,23 +0,0 @@
import { FusePage } from './app.po';
import { browser, logging } from 'protractor';
describe('Fuse App', () => {
let page: FusePage;
beforeEach(() => {
page = new FusePage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to Fuse!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE
} as logging.Entry));
});
});

View File

@@ -1,14 +0,0 @@
import { browser, by, element } from 'protractor';
export class FusePage
{
navigateTo(): Promise<any>
{
return browser.get('/') as Promise<any>;
}
getParagraphText(): Promise<string>
{
return element(by.css('app #main')).getText() as Promise<string>;
}
}

View File

@@ -1,13 +1,14 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@@ -1,33 +1,33 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config)
{
module.exports = function (config) {
config.set({
basePath : '',
frameworks : ['jasmine', '@angular-devkit/build-angular'],
plugins : [
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
require('@angular/cli/plugins/karma')
],
client : {
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir : require('path').join(__dirname, './coverage/fuse'),
reports : ['html', 'lcovonly', 'text-summary'],
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
reporters : ['progress', 'kjhtml'],
port : 9876,
colors : true,
logLevel : config.LOG_INFO,
autoWatch : true,
browsers : ['Chrome'],
singleRun : false,
restartOnFileChange : true
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

24068
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,88 +1,85 @@
{
"name": "fuse",
"version": "8.1.2",
"license": "https://themeforest.net/licenses/terms/regular",
"scripts": {
"ng": "ng",
"start": "ng serve --open",
"start-hmr": "ng serve --configuration hmr --source-map=false --hmr-warning=false",
"start-hmr-sourcemaps": "ng serve --configuration hmr --source-map=true --hmr-warning=false",
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev",
"build-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev --stats-json",
"build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
"build-prod-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod --stats-json",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"bundle-report": "webpack-bundle-analyzer dist/stats.json"
},
"private": true,
"dependencies": {
"@agm/core": "1.0.0-beta.7",
"@angular/animations": "8.1.2",
"@angular/cdk": "8.1.1",
"@angular/common": "8.1.2",
"@angular/compiler": "8.1.2",
"@angular/core": "8.1.2",
"@angular/flex-layout": "8.0.0-beta.26",
"@angular/forms": "8.1.2",
"@angular/material": "8.1.1",
"@angular/material-moment-adapter": "8.1.1",
"@angular/platform-browser": "8.1.2",
"@angular/platform-browser-dynamic": "8.1.2",
"@angular/router": "8.1.2",
"@ngrx/effects": "8.1.0",
"@ngrx/router-store": "8.1.0",
"@ngrx/store": "8.1.0",
"@ngrx/store-devtools": "8.1.0",
"@ngx-translate/core": "11.0.1",
"@swimlane/dragula": "3.8.0",
"@swimlane/ngx-charts": "12.0.1",
"@swimlane/ngx-datatable": "15.0.2",
"@swimlane/ngx-dnd": "8.0.0",
"@types/prismjs": "1.16.0",
"angular-calendar": "0.27.13",
"angular-in-memory-web-api": "0.8.0",
"chart.js": "2.8.0",
"classlist.js": "1.1.20150312",
"d3": "5.9.7",
"date-fns": "1.30.1",
"hammerjs": "2.0.8",
"lodash": "4.17.15",
"moment": "2.24.0",
"ng2-charts": "2.3.0",
"ngrx-store-freeze": "0.2.4",
"ngx-color-picker": "8.1.0",
"ngx-cookie-service": "2.2.0",
"perfect-scrollbar": "1.4.0",
"prismjs": "1.16.0",
"rxjs": "6.5.2",
"web-animations-js": "2.3.2",
"zone.js": "0.9.1"
},
"devDependencies": {
"@angular/cli": "8.1.2",
"@angular/compiler-cli": "8.1.2",
"@angular/language-service": "8.1.2",
"@angular-devkit/build-angular": "0.801.2",
"@angularclass/hmr": "2.1.3",
"@types/jasmine": "3.3.14",
"@types/jasminewd2": "2.0.6",
"@types/lodash": "4.14.136",
"@types/node": "8.9.5",
"codelyzer": "5.1.0",
"jasmine-core": "3.4.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "4.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-coverage-istanbul-reporter": "2.0.5",
"karma-jasmine": "2.0.1",
"karma-jasmine-html-reporter": "1.4.2",
"protractor": "5.4.2",
"ts-node": "7.0.1",
"tslib": "1.10.0",
"tslint": "5.15.0",
"typescript": "3.4.5",
"webpack-bundle-analyzer": "3.3.2"
}
"name": "fuse",
"version": "5.2.10",
"license": "https://themeforest.net/licenses/terms/regular",
"scripts": {
"ng": "ng",
"start": "ng serve --open",
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev",
"build-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev --stats-json",
"build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
"build-prod-stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod --stats-json",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"bundle-report": "webpack-bundle-analyzer dist/stats.json"
},
"private": true,
"dependencies": {
"@agm/core": "1.0.0-beta.2",
"@angular/animations": "5.2.8",
"@angular/cdk": "5.2.4",
"@angular/common": "5.2.8",
"@angular/compiler": "5.2.8",
"@angular/core": "5.2.8",
"@angular/flex-layout": "5.0.0-beta.13",
"@angular/forms": "5.2.8",
"@angular/http": "5.2.8",
"@angular/material": "5.2.4",
"@angular/material-moment-adapter": "5.2.4",
"@angular/platform-browser": "5.2.8",
"@angular/platform-browser-dynamic": "5.2.8",
"@angular/router": "5.2.8",
"@ngrx/effects": "5.2.0",
"@ngrx/router-store": "5.2.0",
"@ngrx/store": "5.2.0",
"@ngrx/store-devtools": "5.2.0",
"@ngx-translate/core": "9.1.1",
"@swimlane/ngx-charts": "7.1.1",
"@swimlane/ngx-datatable": "11.2.0",
"@swimlane/ngx-dnd": "3.1.0",
"@types/prismjs": "1.9.0",
"angular-calendar": "0.23.6",
"angular-in-memory-web-api": "0.5.3",
"chart.js": "2.7.2",
"classlist.js": "1.1.20150312",
"core-js": "2.5.3",
"d3": "4.13.0",
"hammerjs": "2.0.8",
"intl": "1.2.5",
"moment": "2.21.0",
"ng2-charts": "1.6.0",
"ngrx-store-freeze": "0.2.1",
"ngx-color-picker": "5.3.4",
"ngx-cookie-service": "1.0.10",
"perfect-scrollbar": "1.3.0",
"prismjs": "1.11.0",
"rxjs": "5.5.6",
"web-animations-js": "2.3.1",
"zone.js": "0.8.20"
},
"devDependencies": {
"@angular/cli": "1.7.3",
"@angular/compiler-cli": "5.2.8",
"@angular/language-service": "5.2.8",
"@angularclass/hmr": "2.1.3",
"@types/jasmine": "2.8.6",
"@types/jasminewd2": "2.0.3",
"@types/node": "6.0.101",
"codelyzer": "4.2.1",
"jasmine-core": "2.8.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "2.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-coverage-istanbul-reporter": "1.4.2",
"karma-jasmine": "1.1.1",
"karma-jasmine-html-reporter": "0.2.2",
"protractor": "5.1.2",
"ts-node": "4.1.0",
"tslint": "5.9.1",
"typescript": "2.6.2",
"webpack-bundle-analyzer": "2.11.1"
}
}

28
protractor.conf.js Normal file
View File

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

View File

@@ -51,23 +51,26 @@ export const fuseAnimations = [
]),
trigger('fadeInOut', [
state('0, void', style({
state('0', style({
display: 'none',
opacity: 0
})),
state('1, *', style({
state('1', style({
display: 'block',
opacity: 1
})),
transition('1 => 0', animate('300ms ease-out')),
transition('0 => 1', animate('300ms ease-in')),
transition('void <=> *', animate('300ms ease-in'))
transition('0 => 1', animate('300ms ease-in'))
]),
trigger('slideInOut', [
state('0', style({
height: '0px'
height : '0px',
display: 'none'
})),
state('1', style({
height: '*'
height : '*',
display: 'block'
})),
transition('1 => 0', animate('300ms ease-out')),
transition('0 => 1', animate('300ms ease-in'))
@@ -117,15 +120,17 @@ export const fuseAnimations = [
})
)
]
)
),
]),
trigger('slideInLeft', [
state('void', style({
transform: 'translateX(-100%)',
display : 'none'
})),
state('*', style({
transform: 'translateX(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
@@ -134,9 +139,11 @@ export const fuseAnimations = [
trigger('slideInRight', [
state('void', style({
transform: 'translateX(100%)',
display : 'none'
})),
state('*', style({
transform: 'translateX(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
@@ -145,9 +152,11 @@ export const fuseAnimations = [
trigger('slideInTop', [
state('void', style({
transform: 'translateY(-100%)',
display : 'none'
})),
state('*', style({
transform: 'translateY(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
@@ -157,9 +166,11 @@ export const fuseAnimations = [
state('void',
style({
transform: 'translateY(100%)',
display : 'none'
})),
state('*', style({
transform: 'translateY(0)',
display : 'flex'
})),
transition('void => *', animate('300ms')),
transition('* => void', animate('300ms'))
@@ -176,14 +187,10 @@ export const fuseAnimations = [
transition('* => void', animate('300ms ease-in'))
]),
// -----------------------------------------------------------------------------------------------------
// @ Router animations
// -----------------------------------------------------------------------------------------------------
trigger('routerTransitionLeft', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -192,7 +199,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateX(100%)',
opacity : 0
@@ -200,7 +207,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateX(0)',
opacity : 1
@@ -211,7 +218,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateX(100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -220,8 +227,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -229,7 +236,7 @@ export const fuseAnimations = [
trigger('routerTransitionRight', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -238,7 +245,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateX(-100%)',
opacity : 0
@@ -246,7 +253,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateX(0)',
opacity : 1
@@ -257,7 +264,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateX(-100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -266,8 +273,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -275,7 +282,7 @@ export const fuseAnimations = [
trigger('routerTransitionUp', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -284,14 +291,14 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateY(100%)',
opacity : 0
})
], {optional: true}),
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateY(0)',
opacity : 1
@@ -302,7 +309,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateY(100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -311,15 +318,15 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
]),
trigger('routerTransitionDown', [
transition('* => *', [
query('content > :enter, content > :leave', [
query('fuse-content > :enter, fuse-content > :leave', [
style({
position: 'absolute',
top : 0,
@@ -328,7 +335,7 @@ export const fuseAnimations = [
right : 0
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
transform: 'translateY(-100%)',
opacity : 0
@@ -336,7 +343,7 @@ export const fuseAnimations = [
], {optional: true}),
sequence([
group([
query('content > :leave', [
query('fuse-content > :leave', [
style({
transform: 'translateY(0)',
opacity : 1
@@ -347,7 +354,7 @@ export const fuseAnimations = [
opacity : 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({transform: 'translateY(-100%)'}),
animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({
@@ -356,8 +363,8 @@ export const fuseAnimations = [
}))
], {optional: true})
]),
query('content > :leave', animateChild(), {optional: true}),
query('content > :enter', animateChild(), {optional: true})
query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true})
])
])
]),
@@ -366,7 +373,7 @@ export const fuseAnimations = [
transition('* => *', group([
query('content > :enter, content > :leave ', [
query('fuse-content > :enter, fuse-content > :leave ', [
style({
position: 'absolute',
top : 0,
@@ -376,12 +383,12 @@ export const fuseAnimations = [
})
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
opacity: 0
})
], {optional: true}),
query('content > :leave', [
query('fuse-content > :leave', [
style({
opacity: 1
}),
@@ -390,7 +397,7 @@ export const fuseAnimations = [
opacity: 0
}))
], {optional: true}),
query('content > :enter', [
query('fuse-content > :enter', [
style({
opacity: 0
}),
@@ -399,8 +406,8 @@ export const fuseAnimations = [
opacity: 1
}))
], {optional: true}),
query('content > :enter', animateChild(), {optional: true}),
query('content > :leave', animateChild(), {optional: true})
query('fuse-content > :enter', animateChild(), {optional: true}),
query('fuse-content > :leave', animateChild(), {optional: true})
]))
])
];

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import { MatDialogRef } from '@angular/material';
@Component({
selector : 'fuse-confirm-dialog',
@@ -10,14 +10,7 @@ export class FuseConfirmDialogComponent
{
public confirmMessage: string;
/**
* Constructor
*
* @param {MatDialogRef<FuseConfirmDialogComponent>} dialogRef
*/
constructor(
public dialogRef: MatDialogRef<FuseConfirmDialogComponent>
)
constructor(public dialogRef: MatDialogRef<FuseConfirmDialogComponent>)
{
}

View File

@@ -1,6 +1,5 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule, MatDialogModule } from '@angular/material';
import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component';

View File

@@ -1,4 +1,4 @@
fuse-countdown {
:host {
display: flex;
flex-direction: row;
align-items: center;

View File

@@ -1,110 +1,55 @@
import { Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { interval, Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import * as moment from 'moment';
@Component({
selector : 'fuse-countdown',
templateUrl: './countdown.component.html',
styleUrls : ['./countdown.component.scss'],
encapsulation: ViewEncapsulation.None
styleUrls : ['./countdown.component.scss']
})
export class FuseCountdownComponent implements OnInit, OnDestroy
export class FuseCountdownComponent implements OnInit
{
// Event date
@Input('eventDate')
eventDate;
@Input('eventDate') eventDate;
countdown: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.countdown = {
days : '',
hours : '',
minutes: '',
seconds: ''
};
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
ngOnInit()
{
const currDate = moment();
const eventDate = moment(this.eventDate);
// Get the difference in between the current date and event date in seconds
let diff = eventDate.diff(currDate, 'seconds');
// Calculate the remaining time for the first time so there will be no
// delay on the countdown
this.countdown = this._secondsToRemaining(diff);
const countDown =
Observable
.interval(1000)
.map(value => {
return diff = diff - 1;
})
.map(value => {
const timeLeft = moment.duration(value, 'seconds');
// Create a subscribable interval
const countDown = interval(1000)
.pipe(
map(value => {
return diff = diff - 1;
}),
map(value => {
return this._secondsToRemaining(value);
})
);
return {
days : timeLeft.asDays().toFixed(0),
hours : timeLeft.hours(),
minutes: timeLeft.minutes(),
seconds: timeLeft.seconds()
};
});
// Subscribe to the countdown interval
countDown
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(value => {
this.countdown = value;
});
countDown.subscribe(value => {
this.countdown = value;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Converts given seconds to a remaining time
*
* @param seconds
* @private
*/
private _secondsToRemaining(seconds): any
{
const timeLeft = moment.duration(seconds, 'seconds');
return {
days : timeLeft.asDays().toFixed(0),
hours : timeLeft.hours(),
minutes: timeLeft.minutes(),
seconds: timeLeft.seconds()
};
}
}

View File

@@ -1,17 +0,0 @@
@mixin fuse-countdown-theme($theme) {
$foreground: map-get($theme, foreground);
fuse-countdown {
.fuse-countdown {
.time {
.title {
color: map-get($foreground, secondary-text);
}
}
}
}
}

View File

@@ -1,8 +1,10 @@
<!-- DEMO CONTENT -->
<div class="demo-content line-height-1.75">
<div class="demo-content">
<h1 class="m-0">Early Sunrise in Winter</h1>
<h4 class="mt-0 secondary-text">Demo Content</h4>
<img src="assets/images/beach.jpg" alt="beach" style="max-width: 640px; width: 100%;">
<h1>Early Sunrise</h1>
<h4 class="secondary-text">Demo Content</h4>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse tortor nibh, convallis sed purus nec,
@@ -10,7 +12,7 @@
vestibulum. Suspendisse euismod in urna eu posuere.
</p>
<blockquote class="my-24">
<blockquote>
<p>
Nunc vel lacinia lorem. Nullam tincidunt sed purus eu placerat. Donec id dictum erat. Etiam enim ex, dapibus
et tortor id, posuere pretium est. Maecenas fringilla ipsum vitae neque elementum, at eleifend ante
@@ -22,12 +24,16 @@
</blockquote>
<p>
Ut ornare sit amet velit vel congue. Ut nec tristique eros. Lorem ipsum dolor sit amet, consectetur
<b>adipiscing elit</b>. Vivamus sed lorem quis nibh porta iaculis. Vestibulum ut eleifend ante, at semper mi.
Nam imperdiet est nisi, quis hendrerit tellus convallis et. Morbi in luctus neque. Curabitur elementum ut est et
gravida. In hac habitasse platea dictumst. In et placerat eros, eu tempor turpis. Curabitur ac felis finibus,
elementum lectus vitae, venenatis est. Integer mollis nisl a eros scelerisque varius. Etiam venenatis lectus vel
erat condimentum tristique vel vel mi. Nulla id euismod mi, et mollis tellus.
Ut ornare sit amet velit vel congue. Ut nec tristique eros. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Vivamus sed lorem quis nibh porta iaculis. Vestibulum ut eleifend ante, at semper mi. Nam imperdiet est
nisi, quis hendrerit tellus convallis et. Morbi in luctus neque. Curabitur elementum ut est et gravida. In hac
habitasse platea dictumst.
</p>
<p>
In et placerat eros, eu tempor turpis. Curabitur ac felis finibus, elementum lectus vitae, venenatis est.
Integer mollis nisl a eros scelerisque varius. Etiam venenatis lectus vel erat condimentum tristique vel vel mi.
Nulla id euismod mi, et mollis tellus.
</p>
<p>
@@ -37,12 +43,6 @@
velit.
</p>
<img class="mt-24 w-100-p" src="assets/images/demo-content/morain-lake.jpg" style="max-width: 640px">
<p class="mt-8 mb-24 secondary-text">
<em>Nullam tincidunt sed purus eu placerat. Donec id dictum erat. Etiam enim ex, dapibus et tortor id.</em>
</p>
<p>
Quisque sit amet risus enim. Aliquam sit amet interdum justo, at ultricies sapien. Suspendisse et semper urna,
in gravida eros. Quisque id nibh iaculis, euismod urna sed, egestas nisi. Donec eros metus, congue a imperdiet
@@ -52,18 +52,10 @@
<p>
Ut auctor, metus sed dapibus tempus, urna diam auctor odio, in malesuada odio risus vitae nisi. Etiam blandit
ante urna, vitae placerat massa mollis in. Duis nec urna ac purus semper dictum ut eget justo. Aenean non
sagittis augue. Sed venenatis rhoncus enim eget ornare. <a href="#">Donec viverra sed felis at venenatis.</a>
Mauris aliquam fringilla nulla, sit amet congue felis dignissim at.
sagittis augue. Sed venenatis rhoncus enim eget ornare. Donec viverra sed felis at venenatis. Mauris aliquam
fringilla nulla, sit amet congue felis dignissim at.
</p>
<ul>
<li>Orci varius</li>
<li>Magnis dis</li>
<li>Conubia nostra</li>
<li>Semper urna</li>
<li>Donec viverra</li>
</ul>
<p>
Quisque accumsan augue tempor ante mollis, sed placerat diam porttitor. Vestibulum dignissim sem vel velit
eleifend, non pellentesque quam convallis. Pellentesque est dolor, dignissim ac tortor tristique, hendrerit
@@ -77,7 +69,7 @@
Etiam blandit nunc arcu, et consectetur orci blandit a. Aliquam condimentum pharetra quam at ultricies. Nunc vel
lacinia lorem. Nullam tincidunt sed purus eu placerat. Donec id dictum erat. Etiam enim ex, dapibus et tortor
id, posuere pretium est. Maecenas fringilla ipsum vitae neque elementum, at eleifend ante sollicitudin. Donec
viverra augue dolor, a venenatis tellus consectetur sit amet.
viverra augue dolor, a venenatis tellus consectetur sit amet...
</p>
</div>
<!-- / DEMO CONTENT -->

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,6 @@
:host {
display: block;
width: 100%;
padding: 8px;
background: #263238;
cursor: text;
overflow: auto;
-webkit-overflow-scrolling: touch;
}

View File

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

View File

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

View File

@@ -4,7 +4,6 @@ export * from './demo/demo.module';
export * from './highlight/highlight.module';
export * from './material-color-picker/material-color-picker.module';
export * from './navigation/navigation.module';
export * from './progress-bar/progress-bar.module';
export * from './search-bar/search-bar.module';
export * from './shortcuts/shortcuts.module';
export * from './sidebar/sidebar.module';

View File

@@ -1,20 +1,20 @@
<button mat-icon-button
type="button"
class="mat-elevation-z1"
[matMenuTriggerFor]="colorMenu"
(menuOpened)="onMenuOpen()"
[ngClass]="selectedPalette + '-' + selectedHue">
[ngClass]="'mat-'+selectedPalette+'-'+selectedHue+'-bg'">
<mat-icon>palette</mat-icon>
</button>
<mat-menu #colorMenu="matMenu" class="fuse-material-color-picker-menu mat-elevation-z8">
<mat-menu #colorMenu="matMenu" class="fuse-material-color-picker-menu">
<header [ngClass]="selectedColor?.class || 'accent'" class="mat-elevation-z4"
<header [ngClass]="selectedColor?.class || 'mat-accent-bg'" class="mat-elevation-z4"
fxLayout="row" fxLayoutAlign="space-between center">
<button mat-icon-button
class="secondary-text"
[style.visibility]="view === 'hues' ? 'visible' : 'hidden'"
(click)="goToPalettesView($event)" aria-label="Palette">
[style.visibility]="view==='hues'?'visible':'hidden'"
(click)="$event.stopPropagation();backToPaletteSelection()" aria-label="Palette">
<mat-icon class="s-20">arrow_back</mat-icon>
</button>
@@ -23,40 +23,45 @@
</span>
<span *ngIf="!selectedColor?.palette">
Select a Color
Select Color
</span>
<button mat-icon-button
class="remove-color-button secondary-text"
(click)="removeColor($event)"
aria-label="Remove color"
matTooltip="Remove color">
class="remove-color-button"
(click)="$event.stopPropagation();removeColor()"
aria-label="Remove Color">
<mat-icon class="s-20">delete</mat-icon>
</button>
</header>
<div [ngSwitch]="view" class="views">
<div class="view" *ngSwitchCase="'palettes'">
<div fxLayout="row wrap" fxLayoutAlign="start start" class="colors" fusePerfectScrollbar>
<div class="color" fxLayout="row" fxLayoutAlign="center center"
<div class="color"
[ngClass]="'mat-'+color.key+'-bg'"
*ngFor="let color of (colors | keys)"
[ngClass]="color.key"
[class.selected]="selectedPalette === color.key"
(click)="selectPalette($event, color.key)">
(click)="$event.stopPropagation();selectPalette(color.key)"
fxLayout="row" fxLayoutAlign="start end" mat-ink-ripple>
<span class="label">
{{color.key}}
</span>
</div>
</div>
</div>
<div class="view" *ngSwitchCase="'hues'">
<div class="view" *ngSwitchCase="'hues'" >
<div fxLayout="row wrap" fxLayoutAlign="start start" class="colors" fusePerfectScrollbar>
<div class="color" fxLayout="row" fxLayoutAlign="center center"
*ngFor="let hue of hues"
[fxHide]="selectedPalette === 'fuse-white' && hue !== '500' || selectedPalette === 'fuse-black' && hue !== '500'"
[ngClass]="selectedPalette + '-' + hue"
[class.selected]="selectedHue === hue"
(click)="selectHue($event, hue)">
<div class="color" *ngFor="let hue of hues"
[fxHide]="selectedPalette === 'white' && hue !== '500'|| selectedPalette === 'black' && hue !== '500'"
[ngClass]="'mat-'+selectedPalette+'-'+hue+'-bg'"
(click)="selectHue(hue)" fxLayout="row" fxLayoutAlign="start end" mat-ink-ripple>
<span class="label">
{{hue}}
</span>
<mat-icon *ngIf="selectedHue === hue" class="s-16">check</mat-icon>
</div>
</div>
</div>

View File

@@ -1,5 +1,5 @@
.fuse-material-color-picker-menu {
width: 245px;
width: 208px;
.mat-menu-content {
padding: 0;
@@ -7,29 +7,44 @@
.views {
display: flex;
flex-direction: column;
min-height: 165px;
position: relative;
overflow: hidden;
min-height: 258px;
height: 308px;
background-color: #F7F7F7;
.view {
overflow: hidden;
position: absolute;
width: 208px;
height: 100%;
bottom: 0;
left: 0;
right: 0;
top: 0;
.colors {
padding: 1px 0 0 0;
margin-left: -1px;
position: relative;
padding: 4px;
.color {
width: 40px;
height: 40px;
margin: 0 0 1px 1px;
position: relative;
width: 46px;
height: 46px;
margin: 2px;
border-radius: 0;
cursor: pointer;
transition: border-radius .4s cubic-bezier(.25, .8, .25, 1);
&:hover {
border-radius: 20%;
.label {
padding: 2px;
font-size: 10px;
}
&.selected {
border-radius: 50% !important;
mat-icon {
position: absolute;
top: 2px;
right: 2px;
font-size: 16px;
opacity: 0.7;
}
}
}

View File

@@ -1,253 +1,179 @@
import { Component, EventEmitter, forwardRef, Input, Output, ViewEncapsulation } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core';
import { fuseAnimations } from '@fuse/animations';
import { MatColors } from '@fuse/mat-colors';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export const FUSE_MATERIAL_COLOR_PICKER_VALUE_ACCESSOR: any = {
provide : NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FuseMaterialColorPickerComponent),
multi : true
};
@Component({
selector : 'fuse-material-color-picker',
templateUrl : './material-color-picker.component.html',
styleUrls : ['./material-color-picker.component.scss'],
animations : fuseAnimations,
encapsulation: ViewEncapsulation.None,
providers : [FUSE_MATERIAL_COLOR_PICKER_VALUE_ACCESSOR]
encapsulation: ViewEncapsulation.None
})
export class FuseMaterialColorPickerComponent implements ControlValueAccessor
export class FuseMaterialColorPickerComponent implements OnChanges
{
colors: any;
hues: string[];
view: string;
selectedColor: any;
selectedPalette: string;
selectedHue: string;
hues: string[];
view = 'palettes';
// Color changed
@Output()
colorChanged: EventEmitter<any>;
@Input() selectedPalette = '';
@Input() selectedHue = '';
@Input() selectedFg = '';
@Input() value: any;
@Output() onValueChange = new EventEmitter();
@Output() selectedPaletteChange = new EventEmitter();
@Output() selectedHueChange = new EventEmitter();
@Output() selectedClassChange = new EventEmitter();
@Output() selectedBgChange = new EventEmitter();
@Output() selectedFgChange = new EventEmitter();
// Private
private _color: string;
private _modelChange: (value: any) => void;
private _modelTouched: (value: any) => void;
_selectedClass = '';
@Input()
set selectedClass(value)
{
if ( value && value !== '' && this._selectedClass !== value )
{
const color = value.split('-');
if ( color.length >= 5 )
{
this.selectedPalette = color[1] + '-' + color[2];
this.selectedHue = color[3];
}
else
{
this.selectedPalette = color[1];
this.selectedHue = color[2];
}
}
this._selectedClass = value;
}
get selectedClass(): string
{
return this._selectedClass;
}
_selectedBg = '';
@Input()
set selectedBg(value)
{
if ( value && value !== '' && this._selectedBg !== value )
{
for ( const palette in this.colors )
{
if ( !this.colors.hasOwnProperty(palette) )
{
continue;
}
for ( const hue of this.hues )
{
if ( this.colors[palette][hue] === value )
{
this.selectedPalette = palette;
this.selectedHue = hue;
break;
}
}
}
}
this._selectedBg = value;
}
get selectedBg(): string
{
return this._selectedBg;
}
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.colorChanged = new EventEmitter();
this.colors = MatColors.all;
this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700'];
this.selectedHue = '500';
this.view = 'palettes';
// Set the private defaults
this._color = '';
this._modelChange = () => {
};
this._modelTouched = () => {
};
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Selected class
*
* @param value
*/
@Input()
set color(value)
ngOnChanges(changes: any)
{
if ( !value || value === '' || this._color === value )
if ( changes.selectedBg && changes.selectedBg.currentValue === '' ||
changes.selectedClass && changes.selectedClass.currentValue === '' ||
changes.selectedPalette && changes.selectedPalette.currentValue === '' )
{
this.removeColor();
return;
}
// Split the color value (red-400, blue-500, fuse-navy-700 etc.)
const colorParts = value.split('-');
// Take the very last part as the selected hue value
this.selectedHue = colorParts[colorParts.length - 1];
// Remove the last part
colorParts.pop();
// Rejoin the remaining parts as the selected palette name
this.selectedPalette = colorParts.join('-');
// Store the color value
this._color = value;
}
get color(): string
{
return this._color;
}
// -----------------------------------------------------------------------------------------------------
// @ Control Value Accessor implementation
// -----------------------------------------------------------------------------------------------------
/**
* Register on change function
*
* @param fn
*/
registerOnChange(fn: any): void
{
this._modelChange = fn;
}
/**
* Register on touched function
*
* @param fn
*/
registerOnTouched(fn: any): void
{
this._modelTouched = fn;
}
/**
* Write value to the view from model
*
* @param color
*/
writeValue(color: any): void
{
// Return if null
if ( !color )
if ( changes.selectedPalette || changes.selectedHue || changes.selectedClass || changes.selectedBg )
{
return;
this.updateSelectedColor();
}
// Set the color
this.color = color;
// Update the selected color
this.updateSelectedColor();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Select palette
*
* @param event
* @param palette
*/
selectPalette(event, palette): void
selectPalette(palette)
{
// Stop propagation
event.stopPropagation();
// Go to 'hues' view
this.view = 'hues';
// Update the selected palette
this.selectedPalette = palette;
// Update the selected color
this.updateSelectedColor();
this.view = 'hues';
}
/**
* Select hue
*
* @param event
* @param hue
*/
selectHue(event, hue): void
selectHue(hue)
{
// Stop propagation
event.stopPropagation();
// Update the selected huse
this.selectedHue = hue;
// Update the selected color
this.updateSelectedColor();
}
/**
* Remove color
*
* @param event
*/
removeColor(event): void
removeColor()
{
// Stop propagation
event.stopPropagation();
// Return to the 'palettes' view
this.view = 'palettes';
// Clear the selected palette and hue
this.selectedPalette = '';
this.selectedHue = '';
// Update the selected color
this.updateSelectedColor();
}
/**
* Update selected color
*/
updateSelectedColor(): void
{
if ( this.selectedColor && this.selectedColor.palette === this.selectedPalette && this.selectedColor.hue === this.selectedHue )
{
return;
}
// Set the selected color object
this.selectedColor = {
palette: this.selectedPalette,
hue : this.selectedHue,
class : this.selectedPalette + '-' + this.selectedHue,
bg : this.selectedPalette === '' ? '' : MatColors.getColor(this.selectedPalette)[this.selectedHue],
fg : this.selectedPalette === '' ? '' : MatColors.getColor(this.selectedPalette).contrast[this.selectedHue]
};
// Emit the color changed event
this.colorChanged.emit(this.selectedColor);
// Mark the model as touched
this._modelTouched(this.selectedColor.class);
// Update the model
this._modelChange(this.selectedColor.class);
}
/**
* Go to palettes view
*
* @param event
*/
goToPalettesView(event): void
{
// Stop propagation
event.stopPropagation();
this.view = 'palettes';
}
/**
* On menu open
*/
onMenuOpen(): void
updateSelectedColor()
{
setTimeout(() => {
if ( this.selectedColor && this.selectedPalette === this.selectedColor.palette && this.selectedHue === this.selectedColor.hue )
{
return;
}
if ( this.selectedPalette !== '' && this.selectedHue !== '' )
{
this.selectedBg = MatColors.getColor(this.selectedPalette)[this.selectedHue];
this.selectedFg = MatColors.getColor(this.selectedPalette).contrast[this.selectedHue];
this.selectedClass = 'mat-' + this.selectedPalette + '-' + this.selectedHue + '-bg';
}
else
{
this.selectedBg = '';
this.selectedFg = '';
}
this.selectedColor = {
palette: this.selectedPalette,
hue : this.selectedHue,
class : this.selectedClass,
bg : this.selectedBg,
fg : this.selectedFg
};
this.selectedPaletteChange.emit(this.selectedPalette);
this.selectedHueChange.emit(this.selectedHue);
this.selectedClassChange.emit(this.selectedClass);
this.selectedBgChange.emit(this.selectedBg);
this.selectedFgChange.emit(this.selectedFg);
this.value = this.selectedColor;
this.onValueChange.emit(this.selectedColor);
});
}
backToPaletteSelection()
{
this.view = 'palettes';
}
onMenuOpen()
{
if ( this.selectedPalette === '' )
{

View File

@@ -1,10 +1,8 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material';
import { FusePipesModule } from '@fuse/pipes/pipes.module';
@@ -22,7 +20,7 @@ import { FuseMaterialColorPickerComponent } from '@fuse/components/material-colo
MatButtonModule,
MatIconModule,
MatMenuModule,
MatTooltipModule,
MatRippleModule,
FusePipesModule
],

View File

@@ -1,14 +0,0 @@
@mixin fuse-material-color-picker-theme($theme) {
$background: map-get($theme, background);
.fuse-material-color-picker-menu {
.mat-menu-content {
.views {
background: #303030;
}
}
}
}

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">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
<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'">
<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.primaryBackground}}">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
<span class="nav-link-title" [translate]="item.translate">{{item.title}}</span>
<span class="nav-link-badge" *ngIf="item.badge" [translate]="item.badge.translate"
[ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}">
{{item.badge.title}}
</span>
</ng-template>
</ng-container>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,75 +1,18 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { Component, Input, ViewEncapsulation } from '@angular/core';
@Component({
selector : 'fuse-navigation',
templateUrl : './navigation.component.html',
styleUrls : ['./navigation.component.scss'],
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
selector : 'fuse-navigation',
templateUrl : './navigation.component.html',
styleUrls : ['./navigation.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseNavigationComponent implements OnInit
export class FuseNavigationComponent
{
@Input()
layout = 'vertical';
@Input() layout = 'vertical';
@Input() navigation: any;
@Input()
navigation: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
*
* @param {ChangeDetectorRef} _changeDetectorRef
* @param {FuseNavigationService} _fuseNavigationService
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService
)
constructor()
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Load the navigation either from the input or from the service
this.navigation = this.navigation || this._fuseNavigationService.getCurrentNavigation();
// Subscribe to the current navigation changes
this._fuseNavigationService.onNavigationChanged
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
// Load the navigation
this.navigation = this._fuseNavigationService.getCurrentNavigation();
// Mark for check
this._changeDetectorRef.markForCheck();
});
// Subscribe to navigation item
merge(
this._fuseNavigationService.onNavigationItemAdded,
this._fuseNavigationService.onNavigationItemUpdated,
this._fuseNavigationService.onNavigationItemRemoved
).pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
}

View File

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

View File

@@ -1,425 +1,48 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import * as _ from 'lodash';
import { EventEmitter, Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { FuseNavigationItem } from '@fuse/types';
@Injectable({
providedIn: 'root'
})
@Injectable()
export class FuseNavigationService
{
onItemCollapsed: Subject<any>;
onItemCollapseToggled: Subject<any>;
flatNavigation: any[] = [];
// Private
private _onNavigationChanged: BehaviorSubject<any>;
private _onNavigationRegistered: BehaviorSubject<any>;
private _onNavigationUnregistered: BehaviorSubject<any>;
private _onNavigationItemAdded: BehaviorSubject<any>;
private _onNavigationItemUpdated: BehaviorSubject<any>;
private _onNavigationItemRemoved: BehaviorSubject<any>;
onItemCollapsed: Subject<any> = new Subject;
onItemCollapseToggled: Subject<any> = new Subject;
private _currentNavigationKey: string;
private _registry: { [key: string]: any } = {};
/**
* Constructor
*/
constructor()
{
// Set the defaults
this.onItemCollapsed = new Subject();
this.onItemCollapseToggled = new Subject();
// Set the private defaults
this._currentNavigationKey = null;
this._onNavigationChanged = new BehaviorSubject(null);
this._onNavigationRegistered = new BehaviorSubject(null);
this._onNavigationUnregistered = new BehaviorSubject(null);
this._onNavigationItemAdded = new BehaviorSubject(null);
this._onNavigationItemUpdated = new BehaviorSubject(null);
this._onNavigationItemRemoved = 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();
}
/**
* Get onNavigationItemAdded
*
* @returns {Observable<any>}
*/
get onNavigationItemAdded(): Observable<any>
{
return this._onNavigationItemAdded.asObservable();
}
/**
* Get onNavigationItemUpdated
*
* @returns {Observable<any>}
*/
get onNavigationItemUpdated(): Observable<any>
{
return this._onNavigationItemUpdated.asObservable();
}
/**
* Get onNavigationItemRemoved
*
* @returns {Observable<any>}
*/
get onNavigationItemRemoved(): Observable<any>
{
return this._onNavigationItemRemoved.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register the given navigation
* with the given key
*
* @param key
* @param navigation
*/
register(key, navigation): void
{
// Check if the key already being used
if ( this._registry[key] )
{
console.error(`The navigation with the key '${key}' already exists. Either unregister it first or use a unique key.`);
return;
}
// Add to the registry
this._registry[key] = navigation;
// Notify the subject
this._onNavigationRegistered.next([key, navigation]);
}
/**
* Unregister the navigation from the registry
* @param key
*/
unregister(key): void
{
// Check if the navigation exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
}
// Unregister the sidebar
delete this._registry[key];
// Notify the subject
this._onNavigationUnregistered.next(key);
}
/**
* Get navigation from registry by key
*
* @param key
* @returns {any}
*/
getNavigation(key): any
{
// Check if the navigation exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
return;
}
// Return the sidebar
return this._registry[key];
}
/**
* Get flattened navigation array
*
* @param navigation
* @param flatNavigation
* @returns {any[]}
*/
getFlatNavigation(navigation, flatNavigation: FuseNavigationItem[] = []): any
getFlatNavigation(navigation)
{
for ( const item of navigation )
for ( const navItem of navigation )
{
if ( item.type === 'item' )
if ( navItem.type === 'item' )
{
flatNavigation.push(item);
this.flatNavigation.push({
title: navItem.title,
type : navItem.type,
icon : navItem.icon || false,
url : navItem.url
});
continue;
}
if ( item.type === 'collapsable' || item.type === 'group' )
if ( navItem.type === 'collapse' || navItem.type === 'group' )
{
if ( item.children )
if ( navItem.children )
{
this.getFlatNavigation(item.children, flatNavigation);
this.getFlatNavigation(navItem.children);
}
}
}
return flatNavigation;
}
/**
* Get the current navigation
*
* @returns {any}
*/
getCurrentNavigation(): any
{
if ( !this._currentNavigationKey )
{
console.warn(`The current navigation is not set.`);
return;
}
return this.getNavigation(this._currentNavigationKey);
}
/**
* Set the navigation with the key
* as the current navigation
*
* @param key
*/
setCurrentNavigation(key): void
{
// Check if the sidebar exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
return;
}
// Set the current navigation key
this._currentNavigationKey = key;
// Notify the subject
this._onNavigationChanged.next(key);
}
/**
* Get navigation item by id from the
* current navigation
*
* @param id
* @param {any} navigation
* @returns {any | boolean}
*/
getNavigationItem(id, navigation = null): any | boolean
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
}
for ( const item of navigation )
{
if ( item.id === id )
{
return item;
}
if ( item.children )
{
const childItem = this.getNavigationItem(id, item.children);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Get the parent of the navigation item
* with the id
*
* @param id
* @param {any} navigation
* @param parent
*/
getNavigationItemParent(id, navigation = null, parent = null): any
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
parent = navigation;
}
for ( const item of navigation )
{
if ( item.id === id )
{
return parent;
}
if ( item.children )
{
const childItem = this.getNavigationItemParent(id, item.children, item);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Add a navigation item to the specified location
*
* @param item
* @param id
*/
addNavigationItem(item, id): void
{
// Get the current navigation
const navigation: any[] = this.getCurrentNavigation();
// Add to the end of the navigation
if ( id === 'end' )
{
navigation.push(item);
// Trigger the observable
this._onNavigationItemAdded.next(true);
return;
}
// Add to the start of the navigation
if ( id === 'start' )
{
navigation.unshift(item);
// Trigger the observable
this._onNavigationItemAdded.next(true);
return;
}
// 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);
}
// Trigger the observable
this._onNavigationItemAdded.next(true);
}
/**
* Update navigation item with the given id
*
* @param id
* @param properties
*/
updateNavigationItem(id, properties): void
{
// Get the navigation item
const navigationItem = this.getNavigationItem(id);
// If there is no navigation with the give id, return
if ( !navigationItem )
{
return;
}
// Merge the navigation properties
_.merge(navigationItem, properties);
// Trigger the observable
this._onNavigationItemUpdated.next(true);
}
/**
* 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);
// Trigger the observable
this._onNavigationItemRemoved.next(true);
return this.flatNavigation;
}
}

View File

@@ -1,65 +0,0 @@
<ng-container *ngIf="!item.hidden">
<!-- normal collapsable -->
<a class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && !item.function"
(click)="toggleOpen($event)">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<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()">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
<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'">
<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,268 +0,0 @@
import { ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { merge, Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { FuseNavigationItem } from '@fuse/types';
import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({
selector : 'fuse-nav-vertical-collapsable',
templateUrl: './collapsable.component.html',
styleUrls : ['./collapsable.component.scss'],
animations : fuseAnimations
})
export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy
{
@Input()
item: FuseNavigationItem;
@HostBinding('class')
classes = 'nav-collapsable nav-item';
@HostBinding('class.open')
public isOpen = false;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {ChangeDetectorRef} _changeDetectorRef
* @param {FuseNavigationService} _fuseNavigationService
* @param {Router} _router
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
private _router: Router
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Listen for router events
this._router.events
.pipe(
filter(event => event instanceof NavigationEnd),
takeUntil(this._unsubscribeAll)
)
.subscribe((event: NavigationEnd) => {
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) )
{
this.expand();
}
else
{
this.collapse();
}
});
// Listen for collapsing of any navigation item
this._fuseNavigationService.onItemCollapsed
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(
(clickedItem) => {
if ( clickedItem && clickedItem.children )
{
// Check if the clicked item is one
// of the children of this item
if ( this.isChildrenOf(this.item, clickedItem) )
{
return;
}
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this._router.url) )
{
return;
}
// If the clicked item is not this item, collapse...
if ( this.item !== clickedItem )
{
this.collapse();
}
}
}
);
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this._router.url) )
{
this.expand();
}
else
{
this.collapse();
}
// Subscribe to navigation item
merge(
this._fuseNavigationService.onNavigationItemAdded,
this._fuseNavigationService.onNavigationItemUpdated,
this._fuseNavigationService.onNavigationItemRemoved
).pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle collapse
*
* @param ev
*/
toggleOpen(ev): void
{
ev.preventDefault();
this.isOpen = !this.isOpen;
// Navigation collapse toggled...
this._fuseNavigationService.onItemCollapsed.next(this.item);
this._fuseNavigationService.onItemCollapseToggled.next();
}
/**
* Expand the collapsable navigation
*/
expand(): void
{
if ( this.isOpen )
{
return;
}
this.isOpen = true;
// Mark for check
this._changeDetectorRef.markForCheck();
this._fuseNavigationService.onItemCollapseToggled.next();
}
/**
* Collapse the collapsable navigation
*/
collapse(): void
{
if ( !this.isOpen )
{
return;
}
this.isOpen = false;
// Mark for check
this._changeDetectorRef.markForCheck();
this._fuseNavigationService.onItemCollapseToggled.next();
}
/**
* Check if the given parent has the
* given item in one of its children
*
* @param parent
* @param item
* @returns {boolean}
*/
isChildrenOf(parent, item): boolean
{
const children = parent.children;
if ( !children )
{
return false;
}
if ( children.indexOf(item) > -1 )
{
return true;
}
for ( const child of children )
{
if ( child.children )
{
if ( this.isChildrenOf(child, item) )
{
return true;
}
}
}
return false;
}
/**
* Check if the given url can be found
* in one of the given parent's children
*
* @param parent
* @param url
* @returns {boolean}
*/
isUrlInChildren(parent, url): boolean
{
const children = parent.children;
if ( !children )
{
return false;
}
for ( const child of children )
{
if ( child.children )
{
if ( this.isUrlInChildren(child, url) )
{
return true;
}
}
if ( child.url === url || url.includes(child.url) )
{
return true;
}
}
return false;
}
}

View File

@@ -1,74 +0,0 @@
import { ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationItem } from '@fuse/types';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({
selector : 'fuse-nav-vertical-group',
templateUrl: './group.component.html',
styleUrls : ['./group.component.scss']
})
export class FuseNavVerticalGroupComponent implements OnInit, OnDestroy
{
@HostBinding('class')
classes = 'nav-group nav-item';
@Input()
item: FuseNavigationItem;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
/**
*
* @param {ChangeDetectorRef} _changeDetectorRef
* @param {FuseNavigationService} _fuseNavigationService
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to navigation item
merge(
this._fuseNavigationService.onNavigationItemAdded,
this._fuseNavigationService.onNavigationItemUpdated,
this._fuseNavigationService.onNavigationItemRemoved
).pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<!-- item.function -->
<span class="nav-link" [ngClass]="item.classes" *ngIf="!item.url && item.function"
(click)="item.function()">
<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', 'accent']"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[target]="item.openInNewTab ? '_blank' : '_self'">
<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'">
<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,73 +0,0 @@
import { ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationItem } from '@fuse/types';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({
selector : 'fuse-nav-vertical-item',
templateUrl: './item.component.html',
styleUrls : ['./item.component.scss']
})
export class FuseNavVerticalItemComponent implements OnInit, OnDestroy
{
@HostBinding('class')
classes = 'nav-item';
@Input()
item: FuseNavigationItem;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
/**
*
* @param {ChangeDetectorRef} _changeDetectorRef
* @param {FuseNavigationService} _fuseNavigationService
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService
)
{
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to navigation item
merge(
this._fuseNavigationService.onNavigationItemAdded,
this._fuseNavigationService.onNavigationItemUpdated,
this._fuseNavigationService.onNavigationItemRemoved
).pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
// Mark for check
this._changeDetectorRef.markForCheck();
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

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

View File

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

View File

@@ -0,0 +1,193 @@
import { Component, HostBinding, Input, OnInit } from '@angular/core';
import { FuseNavigationService } from '../../navigation.service';
import { NavigationEnd, Router } from '@angular/router';
import { fuseAnimations } from '../../../../animations/index';
@Component({
selector : 'fuse-nav-vertical-collapse',
templateUrl: './nav-vertical-collapse.component.html',
styleUrls : ['./nav-vertical-collapse.component.scss'],
animations : fuseAnimations
})
export class FuseNavVerticalCollapseComponent implements OnInit
{
@Input() item: any;
@HostBinding('class') classes = 'nav-collapse nav-item';
@HostBinding('class.open') public isOpen = false;
constructor(
private navigationService: FuseNavigationService,
private router: Router
)
{
// Listen for route changes
router.events.subscribe(
(event) => {
if ( event instanceof 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();
}
else
{
this.collapse();
}
}
}
);
// Listen for collapsing of any navigation item
this.navigationService.onItemCollapsed
.subscribe(
(clickedItem) => {
if ( clickedItem && clickedItem.children )
{
// Check if the clicked item is one
// of the children of this item
if ( this.isChildrenOf(this.item, clickedItem) )
{
return;
}
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this.router.url) )
{
return;
}
// If the clicked item is not this item, collapse...
if ( this.item !== clickedItem )
{
this.collapse();
}
}
}
);
}
ngOnInit()
{
// Check if the url can be found in
// one of the children of this item
if ( this.isUrlInChildren(this.item, this.router.url) )
{
this.expand();
}
else
{
this.collapse();
}
}
/**
* Toggle collapse
*
* @param ev
*/
toggleOpen(ev)
{
ev.preventDefault();
this.isOpen = !this.isOpen;
// Navigation collapse toggled...
this.navigationService.onItemCollapsed.next(this.item);
this.navigationService.onItemCollapseToggled.next();
}
/**
* Expand the collapsable navigation
*/
expand()
{
if ( this.isOpen )
{
return;
}
this.isOpen = true;
this.navigationService.onItemCollapseToggled.next();
}
/**
* Collapse the collapsable navigation
*/
collapse()
{
if ( !this.isOpen )
{
return;
}
this.isOpen = false;
this.navigationService.onItemCollapseToggled.next();
}
/**
* Check if the given parent has the
* given item in one of its children
*
* @param parent
* @param item
* @return {any}
*/
isChildrenOf(parent, item)
{
if ( !parent.children )
{
return false;
}
if ( parent.children.indexOf(item) !== -1 )
{
return true;
}
for ( const children of parent.children )
{
if ( children.children )
{
return this.isChildrenOf(children, item);
}
}
}
/**
* Check if the given url can be found
* in one of the given parent's children
*
* @param parent
* @param url
* @returns {any}
*/
isUrlInChildren(parent, url)
{
if ( !parent.children )
{
return false;
}
for ( let i = 0; i < parent.children.length; i++ )
{
if ( parent.children[i].children )
{
if ( this.isUrlInChildren(parent.children[i], url) )
{
return true;
}
}
if ( parent.children[i].url === url || url.includes(parent.children[i].url) )
{
return true;
}
}
return false;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
<ng-container *ngIf="visible">
<mat-progress-bar color="accent" [bufferValue]="bufferValue" [mode]="mode" [value]="value"></mat-progress-bar>
</ng-container>

View File

@@ -1,17 +0,0 @@
@import "src/@fuse/scss/fuse";
fuse-progress-bar {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
z-index: 99998;
mat-progress-bar {
.mat-progress-bar-buffer {
background-color: #C5C6CB !important;
}
}
}

View File

@@ -1,93 +0,0 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseProgressBarService } from '@fuse/components/progress-bar/progress-bar.service';
@Component({
selector : 'fuse-progress-bar',
templateUrl : './progress-bar.component.html',
styleUrls : ['./progress-bar.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FuseProgressBarComponent implements OnInit, OnDestroy
{
bufferValue: number;
mode: 'determinate' | 'indeterminate' | 'buffer' | 'query';
value: number;
visible: boolean;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*
* @param {FuseProgressBarService} _fuseProgressBarService
*/
constructor(
private _fuseProgressBarService: FuseProgressBarService
)
{
// Set the defaults
// Set the private defaults
this._unsubscribeAll = new Subject();
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to the progress bar service properties
// Buffer value
this._fuseProgressBarService.bufferValue
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((bufferValue) => {
this.bufferValue = bufferValue;
});
// Mode
this._fuseProgressBarService.mode
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((mode) => {
this.mode = mode;
});
// Value
this._fuseProgressBarService.value
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) => {
this.value = value;
});
// Visible
this._fuseProgressBarService.visible
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((visible) => {
this.visible = visible;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
}

View File

@@ -1,29 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { FuseProgressBarComponent } from './progress-bar.component';
@NgModule({
declarations: [
FuseProgressBarComponent
],
imports : [
CommonModule,
RouterModule,
MatButtonModule,
MatIconModule,
MatProgressBarModule
],
exports : [
FuseProgressBarComponent
]
})
export class FuseProgressBarModule
{
}

View File

@@ -1,132 +0,0 @@
import { Injectable } from '@angular/core';
import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class FuseProgressBarService
{
// Private
private _bufferValue: BehaviorSubject<number>;
private _mode: BehaviorSubject<string>;
private _value: BehaviorSubject<number>;
private _visible: BehaviorSubject<boolean>;
/**
* Constructor
*
* @param {Router} _router
*/
constructor(
private _router: Router
)
{
// Initialize the service
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Buffer value
*/
get bufferValue(): Observable<any>
{
return this._bufferValue.asObservable();
}
setBufferValue(value: number): void
{
this._bufferValue.next(value);
}
/**
* Mode
*/
get mode(): Observable<any>
{
return this._mode.asObservable();
}
setMode(value: 'determinate' | 'indeterminate' | 'buffer' | 'query'): void
{
this._mode.next(value);
}
/**
* Value
*/
get value(): Observable<any>
{
return this._value.asObservable();
}
setValue(value: number): void
{
this._value.next(value);
}
/**
* Visible
*/
get visible(): Observable<any>
{
return this._visible.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
// Initialize the behavior subjects
this._bufferValue = new BehaviorSubject(0);
this._mode = new BehaviorSubject('indeterminate');
this._value = new BehaviorSubject(0);
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.show();
});
this._router.events
.pipe(filter((event) => event instanceof NavigationEnd || event instanceof NavigationError || event instanceof NavigationCancel))
.subscribe(() => {
this.hide();
});
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Show the progress bar
*/
show(): void
{
this._visible.next(true);
}
/**
* Hide the progress bar
*/
hide(): void
{
this._visible.next(false);
}
}

View File

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

View File

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

View File

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

View File

@@ -2,8 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule, MatIconModule } from '@angular/material';
import { FuseSearchBarComponent } from './search-bar.component';

View File

@@ -1,11 +0,0 @@
@mixin fuse-search-bar-theme($theme) {
$background: map-get($theme, background);
.fuse-search-bar {
&.expanded {
background-color: map-get($background, background);
}
}
}

View File

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

View File

@@ -2,7 +2,7 @@
:host {
@include media-breakpoint('lt-md') {
@include media-breakpoint-down('sm') {
#fuse-shortcuts {
@@ -19,10 +19,6 @@
display: flex !important;
flex: 1;
height: 100%;
> div {
flex: 1 1 auto !important;
}
}
}
}

View File

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

View File

@@ -2,14 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatTooltipModule } from '@angular/material';
import { CookieService } from 'ngx-cookie-service';
import { FuseShortcutsComponent } from './shortcuts.component';

View File

@@ -1,11 +0,0 @@
@mixin fuse-shortcuts-theme($theme) {
$background: map-get($theme, background);
#fuse-shortcuts {
&.show-mobile-panel {
background-color: map-get($background, background);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
@mixin fuse-sidebar-theme($theme) {
$background: map-get($theme, background);
fuse-sidebar {
background: map-get($background, background);
}
.fuse-sidebar-overlay {
background-color: rgba(0, 0, 0, 0.6);
&.fuse-sidebar-overlay-invisible {
background-color: transparent;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,21 +1,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatOptionModule } from '@angular/material/core';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule } from '@angular/material';
import { FuseDirectivesModule } from '@fuse/directives/directives';
import { FuseMaterialColorPickerModule } from '@fuse/components/material-color-picker/material-color-picker.module';
import { FuseSidebarModule } from '@fuse/components/sidebar/sidebar.module';
import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component';
@NgModule({
@@ -25,12 +14,10 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
imports : [
CommonModule,
FormsModule,
ReactiveFormsModule,
FlexLayoutModule,
MatButtonModule,
MatCheckboxModule,
MatDividerModule,
MatFormFieldModule,
MatIconModule,
@@ -39,9 +26,7 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
MatSelectModule,
MatSlideToggleModule,
FuseDirectivesModule,
FuseMaterialColorPickerModule,
FuseSidebarModule
FuseMaterialColorPickerModule
],
exports : [
FuseThemeOptionsComponent

View File

@@ -1,27 +0,0 @@
@mixin fuse-theme-options-theme($theme) {
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
fuse-theme-options {
.theme-options-panel {
form {
.group {
border: 1px solid map-get($foreground, divider);
h2 {
background: map-get($background, background);
color: map-get($foreground, secondary-text);
}
h3 {
color: map-get($foreground, secondary-text);
}
}
}
}
}
}

View File

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

View File

@@ -20,13 +20,11 @@ fuse-widget {
width: 100%;
opacity: 1;
z-index: 10;
border-radius: 8px;
border-radius: 2px;
transition: transform 0.5s ease-out 0s, visibility 0s ease-in 0.2s, opacity 0s ease-in 0.2s;
transform: rotateY(0deg);
backface-visibility: hidden;
border: 1px solid;
}
> .fuse-widget-back {
display: block;
position: absolute;
@@ -38,11 +36,9 @@ fuse-widget {
visibility: hidden;
opacity: 0;
z-index: 10;
border-radius: 8px;
transition: transform 0.5s ease-out 0s, visibility 0s ease-in 0.2s, opacity 0s ease-in 0.2s;
transform: rotateY(180deg);
backface-visibility: hidden;
border: 1px solid;
[fuseWidgetToggle] {
position: absolute;
@@ -71,16 +67,16 @@ fuse-widget {
&.mat-form-field-type-mat-select {
.mat-form-field-wrapper {
.mat-input-wrapper {
padding: 16px 0;
.mat-form-field-infix {
.mat-input-infix {
border: none;
padding: 0;
}
}
.mat-form-field-underline {
.mat-input-underline {
display: none;
}
}

View File

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

View File

@@ -1,14 +0,0 @@
@mixin fuse-widget-theme($theme) {
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
fuse-widget {
> .fuse-widget-front,
> .fuse-widget-back {
background: map-get($background, card);
border-color: map-get($foreground, divider);
}
}
}

View File

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

View File

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

View File

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

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