Compare commits

..

76 Commits

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

5
.gitignore vendored
View File

@@ -30,10 +30,13 @@
/coverage /coverage
/libpeerconnection.log /libpeerconnection.log
npm-debug.log npm-debug.log
yarn-error.log
testem.log testem.log
/typings /typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files # System Files
.DS_Store .DS_Store
Thumbs.db 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, https://themeforest.net/licenses/terms/regular
check the official license page at 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 ## The Community
@@ -14,11 +14,11 @@ Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app w
## Code scaffolding ## 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 ## 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 ## 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 ## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## 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).

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", "extends": "../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/app", "outDir": "../out-tsc/e2e",
"module": "commonjs", "baseUrl": "./",
"target": "es5", "module": "commonjs",
"types": [ "target": "es5",
"jasmine", "types": [
"jasminewd2", "jasmine",
"node" "jasminewd2",
] "node"
} ]
}
} }

View File

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

24095
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -1,110 +1,55 @@
import { Component, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { interval, Subject } from 'rxjs'; import { Observable } from 'rxjs/Observable';
import { map, takeUntil } from 'rxjs/operators'; import 'rxjs/add/observable/interval';
import * as moment from 'moment'; import * as moment from 'moment';
@Component({ @Component({
selector : 'fuse-countdown', selector : 'fuse-countdown',
templateUrl: './countdown.component.html', templateUrl: './countdown.component.html',
styleUrls : ['./countdown.component.scss'], styleUrls : ['./countdown.component.scss']
encapsulation: ViewEncapsulation.None
}) })
export class FuseCountdownComponent implements OnInit, OnDestroy export class FuseCountdownComponent implements OnInit
{ {
// Event date @Input('eventDate') eventDate;
@Input('eventDate')
eventDate;
countdown: any; countdown: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
* Constructor
*/
constructor() constructor()
{ {
// Set the defaults
this.countdown = { this.countdown = {
days : '', days : '',
hours : '', hours : '',
minutes: '', minutes: '',
seconds: '' seconds: ''
}; };
// Set the private defaults
this._unsubscribeAll = new Subject();
} }
// ----------------------------------------------------------------------------------------------------- ngOnInit()
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{ {
const currDate = moment(); const currDate = moment();
const eventDate = moment(this.eventDate); const eventDate = moment(this.eventDate);
// Get the difference in between the current date and event date in seconds
let diff = eventDate.diff(currDate, 'seconds'); let diff = eventDate.diff(currDate, 'seconds');
// Calculate the remaining time for the first time so there will be no const countDown =
// delay on the countdown Observable
this.countdown = this._secondsToRemaining(diff); .interval(1000)
.map(value => {
return diff = diff - 1;
})
.map(value => {
const timeLeft = moment.duration(value, 'seconds');
// Create a subscribable interval return {
const countDown = interval(1000) days : timeLeft.asDays().toFixed(0),
.pipe( hours : timeLeft.hours(),
map(value => { minutes: timeLeft.minutes(),
return diff = diff - 1; seconds: timeLeft.seconds()
}), };
map(value => { });
return this._secondsToRemaining(value);
})
);
// Subscribe to the countdown interval countDown.subscribe(value => {
countDown this.countdown = value;
.pipe(takeUntil(this._unsubscribeAll)) });
.subscribe(value => {
this.countdown = value;
});
} }
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
// -----------------------------------------------------------------------------------------------------
// @ 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 --> <!-- DEMO CONTENT -->
<div class="demo-content line-height-1.75"> <div class="demo-content">
<h1 class="m-0">Early Sunrise in Winter</h1> <img src="assets/images/beach.jpg" alt="beach" style="max-width: 640px; width: 100%;">
<h4 class="mt-0 secondary-text">Demo Content</h4>
<h1>Early Sunrise</h1>
<h4 class="secondary-text">Demo Content</h4>
<p> <p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse tortor nibh, convallis sed purus nec, 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. vestibulum. Suspendisse euismod in urna eu posuere.
</p> </p>
<blockquote class="my-24"> <blockquote>
<p> <p>
Nunc vel lacinia lorem. Nullam tincidunt sed purus eu placerat. Donec id dictum erat. Etiam enim ex, dapibus 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 et tortor id, posuere pretium est. Maecenas fringilla ipsum vitae neque elementum, at eleifend ante
@@ -22,12 +24,16 @@
</blockquote> </blockquote>
<p> <p>
Ut ornare sit amet velit vel congue. Ut nec tristique eros. Lorem ipsum dolor sit amet, consectetur Ut ornare sit amet velit vel congue. Ut nec tristique eros. Lorem ipsum dolor sit amet, consectetur adipiscing
<b>adipiscing elit</b>. Vivamus sed lorem quis nibh porta iaculis. Vestibulum ut eleifend ante, at semper mi. elit. Vivamus sed lorem quis nibh porta iaculis. Vestibulum ut eleifend ante, at semper mi. Nam imperdiet est
Nam imperdiet est nisi, quis hendrerit tellus convallis et. Morbi in luctus neque. Curabitur elementum ut est et nisi, quis hendrerit tellus convallis et. Morbi in luctus neque. Curabitur elementum ut est et gravida. In hac
gravida. In hac habitasse platea dictumst. In et placerat eros, eu tempor turpis. Curabitur ac felis finibus, habitasse platea dictumst.
elementum lectus vitae, venenatis est. Integer mollis nisl a eros scelerisque varius. Etiam venenatis lectus vel </p>
erat condimentum tristique vel vel mi. Nulla id euismod mi, et mollis tellus.
<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>
<p> <p>
@@ -37,12 +43,6 @@
velit. velit.
</p> </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> <p>
Quisque sit amet risus enim. Aliquam sit amet interdum justo, at ultricies sapien. Suspendisse et semper urna, 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 in gravida eros. Quisque id nibh iaculis, euismod urna sed, egestas nisi. Donec eros metus, congue a imperdiet
@@ -52,18 +52,10 @@
<p> <p>
Ut auctor, metus sed dapibus tempus, urna diam auctor odio, in malesuada odio risus vitae nisi. Etiam blandit 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 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> sagittis augue. Sed venenatis rhoncus enim eget ornare. Donec viverra sed felis at venenatis. Mauris aliquam
Mauris aliquam fringilla nulla, sit amet congue felis dignissim at. fringilla nulla, sit amet congue felis dignissim at.
</p> </p>
<ul>
<li>Orci varius</li>
<li>Magnis dis</li>
<li>Conubia nostra</li>
<li>Semper urna</li>
<li>Donec viverra</li>
</ul>
<p> <p>
Quisque accumsan augue tempor ante mollis, sed placerat diam porttitor. Vestibulum dignissim sem vel velit 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 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 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 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 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> </p>
</div> </div>
<!-- / DEMO CONTENT --> <!-- / DEMO CONTENT -->

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
.fuse-material-color-picker-menu { .fuse-material-color-picker-menu {
width: 245px; width: 208px;
.mat-menu-content { .mat-menu-content {
padding: 0; padding: 0;
@@ -7,29 +7,44 @@
.views { .views {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 165px; position: relative;
overflow: hidden;
min-height: 258px;
height: 308px;
background-color: #F7F7F7;
.view { .view {
overflow: hidden; position: absolute;
width: 208px;
height: 100%;
bottom: 0;
left: 0;
right: 0;
top: 0;
.colors { .colors {
padding: 1px 0 0 0; position: relative;
margin-left: -1px; padding: 4px;
.color { .color {
width: 40px; position: relative;
height: 40px; width: 46px;
margin: 0 0 1px 1px; height: 46px;
margin: 2px;
border-radius: 0; border-radius: 0;
cursor: pointer; cursor: pointer;
transition: border-radius .4s cubic-bezier(.25, .8, .25, 1);
&:hover { .label {
border-radius: 20%; padding: 2px;
font-size: 10px;
} }
&.selected { mat-icon {
border-radius: 50% !important; 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 { fuseAnimations } from '@fuse/animations';
import { MatColors } from '@fuse/mat-colors'; 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({ @Component({
selector : 'fuse-material-color-picker', selector : 'fuse-material-color-picker',
templateUrl : './material-color-picker.component.html', templateUrl : './material-color-picker.component.html',
styleUrls : ['./material-color-picker.component.scss'], styleUrls : ['./material-color-picker.component.scss'],
animations : fuseAnimations, animations : fuseAnimations,
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None
providers : [FUSE_MATERIAL_COLOR_PICKER_VALUE_ACCESSOR]
}) })
export class FuseMaterialColorPickerComponent implements ControlValueAccessor export class FuseMaterialColorPickerComponent implements OnChanges
{ {
colors: any; colors: any;
hues: string[];
view: string;
selectedColor: any; selectedColor: any;
selectedPalette: string; hues: string[];
selectedHue: string; view = 'palettes';
// Color changed @Input() selectedPalette = '';
@Output() @Input() selectedHue = '';
colorChanged: EventEmitter<any>; @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 _selectedClass = '';
private _color: string; @Input()
private _modelChange: (value: any) => void; set selectedClass(value)
private _modelTouched: (value: any) => void; {
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() constructor()
{ {
// Set the defaults
this.colorChanged = new EventEmitter();
this.colors = MatColors.all; this.colors = MatColors.all;
this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']; 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 = () => {
};
} }
// ----------------------------------------------------------------------------------------------------- ngOnChanges(changes: any)
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Selected class
*
* @param value
*/
@Input()
set color(value)
{ {
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; return;
} }
if ( changes.selectedPalette || changes.selectedHue || changes.selectedClass || changes.selectedBg )
// 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 )
{ {
return; this.updateSelectedColor();
} }
// Set the color
this.color = color;
// Update the selected color
this.updateSelectedColor();
} }
// ----------------------------------------------------------------------------------------------------- selectPalette(palette)
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Select palette
*
* @param event
* @param palette
*/
selectPalette(event, palette): void
{ {
// Stop propagation
event.stopPropagation();
// Go to 'hues' view
this.view = 'hues';
// Update the selected palette
this.selectedPalette = palette; this.selectedPalette = palette;
// Update the selected color
this.updateSelectedColor(); this.updateSelectedColor();
this.view = 'hues';
} }
/** selectHue(hue)
* Select hue
*
* @param event
* @param hue
*/
selectHue(event, hue): void
{ {
// Stop propagation
event.stopPropagation();
// Update the selected huse
this.selectedHue = hue; this.selectedHue = hue;
// Update the selected color
this.updateSelectedColor(); this.updateSelectedColor();
} }
/** removeColor()
* Remove color
*
* @param event
*/
removeColor(event): void
{ {
// Stop propagation
event.stopPropagation();
// Return to the 'palettes' view
this.view = 'palettes';
// Clear the selected palette and hue
this.selectedPalette = ''; this.selectedPalette = '';
this.selectedHue = ''; this.selectedHue = '';
// Update the selected color
this.updateSelectedColor(); 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'; this.view = 'palettes';
} }
/** updateSelectedColor()
* On menu open {
*/ setTimeout(() => {
onMenuOpen(): void
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 === '' ) if ( this.selectedPalette === '' )
{ {

View File

@@ -1,10 +1,8 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FusePipesModule } from '@fuse/pipes/pipes.module'; import { FusePipesModule } from '@fuse/pipes/pipes.module';
@@ -22,7 +20,7 @@ import { FuseMaterialColorPickerComponent } from '@fuse/components/material-colo
MatButtonModule, MatButtonModule,
MatIconModule, MatIconModule,
MatMenuModule, MatMenuModule,
MatTooltipModule, MatRippleModule,
FusePipesModule 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 --> <!-- Vertical Navigation Layout -->
<ng-container *ngIf="layout === 'vertical'"> <ng-container *ngIf="layout === 'vertical'">
@@ -6,8 +7,7 @@
<ng-container *ngFor="let item of navigation"> <ng-container *ngFor="let item of navigation">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group> <fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapsable *ngIf="item.type=='collapsable'" <fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
[item]="item"></fuse-nav-vertical-collapsable>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item> <fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container> </ng-container>
@@ -20,9 +20,8 @@
<ng-container *ngFor="let item of navigation"> <ng-container *ngFor="let item of navigation">
<fuse-nav-horizontal-collapsable *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapsable> <fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapsable *ngIf="item.type=='collapsable'" <fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
[item]="item"></fuse-nav-horizontal-collapsable>
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item> <fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
</ng-container> </ng-container>

View File

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

View File

@@ -1,75 +1,18 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Input, ViewEncapsulation } from '@angular/core';
import { merge, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@Component({ @Component({
selector : 'fuse-navigation', selector : 'fuse-navigation',
templateUrl : './navigation.component.html', templateUrl : './navigation.component.html',
styleUrls : ['./navigation.component.scss'], styleUrls : ['./navigation.component.scss'],
encapsulation : ViewEncapsulation.None, encapsulation: ViewEncapsulation.None
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseNavigationComponent implements OnInit export class FuseNavigationComponent
{ {
@Input() @Input() layout = 'vertical';
layout = 'vertical'; @Input() navigation: any;
@Input() constructor()
navigation: any;
// Private
private _unsubscribeAll: Subject<any>;
/**
*
* @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
{
// 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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { MatRippleModule } from '@angular/material/core'; import { MatIconModule, MatRippleModule } from '@angular/material';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { FuseNavigationComponent } from './navigation.component'; import { FuseNavigationComponent } from './navigation.component';
import { FuseNavVerticalItemComponent } from './vertical/item/item.component'; import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component';
import { FuseNavVerticalCollapsableComponent } from './vertical/collapsable/collapsable.component'; import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component';
import { FuseNavVerticalGroupComponent } from './vertical/group/group.component'; import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/item/item.component'; import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component';
import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/collapsable.component'; import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component';
@NgModule({ @NgModule({
imports : [ imports : [
@@ -30,9 +29,9 @@ import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/
FuseNavigationComponent, FuseNavigationComponent,
FuseNavVerticalGroupComponent, FuseNavVerticalGroupComponent,
FuseNavVerticalItemComponent, FuseNavVerticalItemComponent,
FuseNavVerticalCollapsableComponent, FuseNavVerticalCollapseComponent,
FuseNavHorizontalItemComponent, FuseNavHorizontalItemComponent,
FuseNavHorizontalCollapsableComponent FuseNavHorizontalCollapseComponent
] ]
}) })
export class FuseNavigationModule export class FuseNavigationModule

View File

@@ -1,425 +1,48 @@
import { Injectable } from '@angular/core'; import { EventEmitter, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { Subject } from 'rxjs/Subject';
import * as _ from 'lodash';
import { FuseNavigationItem } from '@fuse/types'; @Injectable()
@Injectable({
providedIn: 'root'
})
export class FuseNavigationService export class FuseNavigationService
{ {
onItemCollapsed: Subject<any>; flatNavigation: any[] = [];
onItemCollapseToggled: Subject<any>;
// Private onItemCollapsed: Subject<any> = new Subject;
private _onNavigationChanged: BehaviorSubject<any>; onItemCollapseToggled: Subject<any> = new Subject;
private _onNavigationRegistered: BehaviorSubject<any>;
private _onNavigationUnregistered: BehaviorSubject<any>;
private _onNavigationItemAdded: BehaviorSubject<any>;
private _onNavigationItemUpdated: BehaviorSubject<any>;
private _onNavigationItemRemoved: BehaviorSubject<any>;
private _currentNavigationKey: string;
private _registry: { [key: string]: any } = {};
/**
* Constructor
*/
constructor() constructor()
{ {
// Set the defaults
this.onItemCollapsed = new Subject();
this.onItemCollapseToggled = new Subject();
// Set the private defaults
this._currentNavigationKey = null;
this._onNavigationChanged = new BehaviorSubject(null);
this._onNavigationRegistered = new BehaviorSubject(null);
this._onNavigationUnregistered = new BehaviorSubject(null);
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 * Get flattened navigation array
*
* @param navigation * @param navigation
* @param flatNavigation
* @returns {any[]} * @returns {any[]}
*/ */
getFlatNavigation(navigation, flatNavigation: FuseNavigationItem[] = []): any getFlatNavigation(navigation)
{ {
for ( const item of navigation ) for ( const navItem of navigation )
{ {
if ( item.type === 'item' ) if ( navItem.type === 'item' )
{ {
flatNavigation.push(item); this.flatNavigation.push({
title: navItem.title,
type : navItem.type,
icon : navItem.icon || false,
url : navItem.url
});
continue; continue;
} }
if ( item.type === 'collapsable' || item.type === 'group' ) if ( navItem.type === 'collapse' || navItem.type === 'group' )
{ {
if ( item.children ) if ( navItem.children )
{ {
this.getFlatNavigation(item.children, flatNavigation); this.getFlatNavigation(navItem.children);
} }
} }
} }
return flatNavigation; return this.flatNavigation;
}
/**
* Get the current navigation
*
* @returns {any}
*/
getCurrentNavigation(): any
{
if ( !this._currentNavigationKey )
{
console.warn(`The current navigation is not set.`);
return;
}
return this.getNavigation(this._currentNavigationKey);
}
/**
* Set the navigation with the key
* as the current navigation
*
* @param key
*/
setCurrentNavigation(key): void
{
// Check if the sidebar exists
if ( !this._registry[key] )
{
console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`);
return;
}
// Set the current navigation key
this._currentNavigationKey = key;
// Notify the subject
this._onNavigationChanged.next(key);
}
/**
* Get navigation item by id from the
* current navigation
*
* @param id
* @param {any} navigation
* @returns {any | boolean}
*/
getNavigationItem(id, navigation = null): any | boolean
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
}
for ( const item of navigation )
{
if ( item.id === id )
{
return item;
}
if ( item.children )
{
const childItem = this.getNavigationItem(id, item.children);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Get the parent of the navigation item
* with the id
*
* @param id
* @param {any} navigation
* @param parent
*/
getNavigationItemParent(id, navigation = null, parent = null): any
{
if ( !navigation )
{
navigation = this.getCurrentNavigation();
parent = navigation;
}
for ( const item of navigation )
{
if ( item.id === id )
{
return parent;
}
if ( item.children )
{
const childItem = this.getNavigationItemParent(id, item.children, item);
if ( childItem )
{
return childItem;
}
}
}
return false;
}
/**
* Add a navigation item to the specified location
*
* @param item
* @param id
*/
addNavigationItem(item, id): void
{
// Get the current navigation
const navigation: any[] = this.getCurrentNavigation();
// Add to the end of the navigation
if ( id === 'end' )
{
navigation.push(item);
// 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);
} }
} }

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,259 +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
{
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 {boolean}
*/
isUrlInChildren(parent, url): boolean
{
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,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 { .nav-link {
.collapsable-arrow { .collapse-arrow {
transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s; transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s;
transform: rotate(0); transform: rotate(0);
} }
@@ -34,9 +34,13 @@
> .nav-link { > .nav-link {
.collapsable-arrow { .collapse-arrow {
transform: rotate(90deg); transform: rotate(90deg);
} }
} }
> .children {
}
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,8 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule, MatIconModule } from '@angular/material';
import { MatIconModule } from '@angular/material/icon';
import { FuseSearchBarComponent } from './search-bar.component'; 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> </button>
</div> </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"> <div fxLayout="row" fxLayoutAlign="space-between center" fxFlex="0 1 auto">
@@ -17,7 +17,7 @@
*ngFor="let shortcutItem of shortcutItems"> *ngFor="let shortcutItem of shortcutItems">
<a mat-icon-button matTooltip="{{shortcutItem.title}}" [routerLink]="shortcutItem.url"> <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"> <span *ngIf="!shortcutItem.icon" class="h2 secondary-text text-bold">
{{shortcutItem.title.substr(0, 1).toUpperCase()}} {{shortcutItem.title.substr(0, 1).toUpperCase()}}
</span> </span>
@@ -42,70 +42,46 @@
<mat-menu #addMenu="matMenu" class="w-240"> <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)"> <input #searchInput matInput placeholder="Search for an app or a page" (input)="search($event)">
</mat-form-field> </mat-form-field>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<mat-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar> <mat-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<mat-list-item *ngFor="let shortcutItem of shortcutItems" <mat-list-item *ngFor="let shortcutItem of shortcutItems"
(click)="toggleShortcut($event, shortcutItem)"> (click)="toggleShortcut($event, shortcutItem)">
<div class="w-100-p" fxLayout="row" fxLayoutAlign="start center"> <div class="w-100-p" fxLayout="row" fxLayoutAlign="start center">
<mat-icon mat-list-icon class="mr-8" *ngIf="shortcutItem.icon">{{shortcutItem.icon}}</mat-icon>
<mat-icon mat-list-icon class="mr-8 secondary-text" *ngIf="shortcutItem.icon">
{{shortcutItem.icon}}
</mat-icon>
<span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row" <span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row"
fxLayoutAlign="center center" *ngIf="!shortcutItem.icon"> fxLayoutAlign="center center" *ngIf="!shortcutItem.icon">
{{shortcutItem.title.substr(0, 1).toUpperCase()}} {{shortcutItem.title.substr(0, 1).toUpperCase()}}
</span> </span>
<p matLine fxFlex>{{shortcutItem.title}}</p> <p matLine fxFlex>{{shortcutItem.title}}</p>
<mat-icon class="ml-8">star</mat-icon>
<mat-icon class="ml-8 amber-fg">star</mat-icon>
</div> </div>
</mat-list-item> </mat-list-item>
<mat-list-item *ngIf="shortcutItems.length === 0"> <mat-list-item *ngIf="shortcutItems.length === 0">
<p> <p>
<small>No shortcuts yet!</small> <small>No shortcuts yet!</small>
</p> </p>
</mat-list-item> </mat-list-item>
</mat-nav-list> </mat-nav-list>
<mat-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar> <mat-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<mat-list-item *ngFor="let navigationItem of filteredNavigationItems" <mat-list-item *ngFor="let navigationItem of filteredNavigationItems"
(click)="toggleShortcut($event, navigationItem)"> (click)="toggleShortcut($event, navigationItem)">
<div class="w-100-p" fxLayout="row" fxLayoutAlign="start center"> <div class="w-100-p" fxLayout="row" fxLayoutAlign="start center">
<mat-icon mat-list-icon class="mr-8" *ngIf="navigationItem.icon">{{navigationItem.icon}}</mat-icon>
<mat-icon mat-list-icon class="mr-8 secondary-text" *ngIf="navigationItem.icon">
{{navigationItem.icon}}
</mat-icon>
<span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row" <span class="h2 w-32 h-32 p-4 mr-8 secondary-text text-bold" fxLayout="row"
fxLayoutAlign="center center" *ngIf="!navigationItem.icon"> fxLayoutAlign="center center" *ngIf="!navigationItem.icon">
{{navigationItem.title.substr(0, 1).toUpperCase()}} {{navigationItem.title.substr(0, 1).toUpperCase()}}
</span> </span>
<p matLine fxFlex>{{navigationItem.title}}</p> <p matLine fxFlex>{{navigationItem.title}}</p>
<mat-icon class="ml-8" *ngIf="isInShortcuts(navigationItem)">star</mat-icon>
<mat-icon class="ml-8 amber-fg" *ngIf="isInShortcuts(navigationItem)">star</mat-icon>
</div> </div>
</mat-list-item> </mat-list-item>
</mat-nav-list> </mat-nav-list>
</mat-menu> </mat-menu>
</div> </div>

View File

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

View File

@@ -2,14 +2,7 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatTooltipModule } from '@angular/material';
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 { CookieService } from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';
import { FuseShortcutsComponent } from './shortcuts.component'; 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 { fuse-sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -7,27 +5,22 @@ fuse-sidebar {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
overflow-x: hidden; overflow: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
width: 280px; width: 280px;
min-width: 280px; min-width: 280px;
max-width: 280px; max-width: 280px;
z-index: 1000; z-index: 1000;
transition-property: transform, width, min-width, max-width;
transition-duration: 150ms;
transition-timing-function: ease-in-out;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35); box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.35);
@include media-breakpoint('xs') { &.left-aligned {
min-width: 0 !important;
max-width: 80vw !important;
width: 80vw !important;
}
&.left-positioned {
left: 0; left: 0;
transform: translateX(-100%); transform: translateX(-100%);
} }
&.right-positioned { &.right-aligned {
right: 0; right: 0;
transform: translateX(100%); transform: translateX(100%);
} }
@@ -45,12 +38,12 @@ fuse-sidebar {
position: absolute !important; position: absolute !important;
top: 0; top: 0;
bottom: 0; bottom: 0;
}
&.animations-enabled { &:not(.unfolded) {
transition-property: transform, width, min-width, max-width; width: 64px;
transition-duration: 150ms; min-width: 64px;
transition-timing-function: ease-in-out; max-width: 64px;
}
} }
} }
@@ -60,6 +53,7 @@ fuse-sidebar {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
z-index: 999; z-index: 3;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0; opacity: 0;
} }

View File

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

View File

@@ -2,9 +2,7 @@ import { Injectable } from '@angular/core';
import { FuseSidebarComponent } from './sidebar.component'; import { FuseSidebarComponent } from './sidebar.component';
@Injectable({ @Injectable()
providedIn: 'root'
})
export class FuseSidebarService export class FuseSidebarService
{ {
// Private // Private
@@ -48,7 +46,7 @@ export class FuseSidebarService
// Check if the sidebar exists // Check if the sidebar exists
if ( !this._registry[key] ) 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 // Unregister the sidebar
@@ -59,14 +57,13 @@ export class FuseSidebarService
* Return the sidebar with the given key * Return the sidebar with the given key
* *
* @param key * @param key
* @returns {FuseSidebarComponent}
*/ */
getSidebar(key): FuseSidebarComponent getSidebar(key): any
{ {
// Check if the sidebar exists // Check if the sidebar exists
if ( !this._registry[key] ) 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; 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')"> <button mat-icon-button class="close-button" (click)="closeBar()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
<div class="theme-options-panel-inner" fxLayout="column" fxLayoutAlign="start start">
<h3>Navigation:</h3>
<mat-radio-group [(ngModel)]="config.layout.navigation" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="top">Top</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="left">Left</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="right">Right</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3>Navigation Fold (for vertical navigation):</h3>
<mat-slide-toggle [(ngModel)]="config.layout.navigationFolded"
(change)="onSettingsChange()">
Folded
</mat-slide-toggle>
<h3 class="mt-24">Toolbar:</h3>
<mat-radio-group [(ngModel)]="config.layout.toolbar" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="below">Below</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="above">Above</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24">Footer:</h3>
<mat-radio-group [(ngModel)]="config.layout.footer" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="below">Below</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="above">Above</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
</mat-radio-group>
<h3 class="mt-24">Layout Mode:</h3>
<mat-radio-group [(ngModel)]="config.layout.mode" (ngModelChange)="onSettingsChange()"
fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign="start start">
<mat-radio-button class="mr-8 mb-8" value="boxed">Boxed</mat-radio-button>
<mat-radio-button class="mr-8 mb-8" value="fullwidth">Fullwidth</mat-radio-button>
</mat-radio-group>
<mat-divider></mat-divider>
<h3>Colors:</h3>
<div class="colors">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Toolbar Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.toolbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Navigation Bar Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.navbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Footer Color</h4>
<fuse-material-color-picker [(selectedClass)]="config.colorClasses.footer"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div>
</div>
<mat-divider></mat-divider>
<h3>Router Animation:</h3>
<mat-form-field class="w-100-p">
<mat-select class="p-0" [(ngModel)]="config.routerAnimation">
<mat-option value="none">
None
</mat-option>
<mat-option value="slideUp">
Slide up
</mat-option>
<mat-option value="slideDown">
Slide down
</mat-option>
<mat-option value="slideRight">
Slide right
</mat-option>
<mat-option value="slideLeft">
Slide left
</mat-option>
<mat-option value="fadeIn">
Fade in
</mat-option>
</mat-select>
</mat-form-field>
</div> </div>
<form [formGroup]="form">
<!-- 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> </div>

View File

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

View File

@@ -1,341 +1,115 @@
import { Component, HostBinding, Inject, OnDestroy, OnInit, Renderer2, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, HostBinding, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
import { DOCUMENT } from '@angular/common'; import { Subscription } from 'rxjs/Subscription';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations'; import { fuseAnimations } from '@fuse/animations';
import { FuseConfigService } from '@fuse/services/config.service'; import { FuseConfigService } from '@fuse/services/config.service';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service';
import { navigation } from 'app/navigation/navigation';
@Component({ @Component({
selector : 'fuse-theme-options', selector : 'fuse-theme-options',
templateUrl : './theme-options.component.html', templateUrl: './theme-options.component.html',
styleUrls : ['./theme-options.component.scss'], styleUrls : ['./theme-options.component.scss'],
encapsulation: ViewEncapsulation.None, animations : fuseAnimations
animations : fuseAnimations
}) })
export class FuseThemeOptionsComponent implements OnInit, OnDestroy export class FuseThemeOptionsComponent implements OnInit, OnDestroy
{ {
fuseConfig: any; @ViewChild('openButton') openButton;
form: FormGroup; @ViewChild('panel') panel;
@ViewChild('overlay') overlay: ElementRef;
@HostBinding('class.bar-closed') public player: AnimationPlayer;
barClosed: boolean; config: any;
// Private onConfigChanged: Subscription;
private _unsubscribeAll: Subject<any>;
@HostBinding('class.bar-closed') barClosed: boolean;
/**
* Constructor
*
* @param {DOCUMENT} document
* @param {FormBuilder} _formBuilder
* @param {FuseConfigService} _fuseConfigService
* @param {FuseNavigationService} _fuseNavigationService
* @param {FuseSidebarService} _fuseSidebarService
* @param {Renderer2} _renderer
*/
constructor( constructor(
@Inject(DOCUMENT) private document: any, private animationBuilder: AnimationBuilder,
private _formBuilder: FormBuilder, private fuseConfig: FuseConfigService,
private _fuseConfigService: FuseConfigService, private navigationService: FuseNavigationService,
private _fuseNavigationService: FuseNavigationService, private renderer: Renderer2
private _fuseSidebarService: FuseSidebarService,
private _renderer: Renderer2
) )
{ {
// Set the defaults
this.barClosed = true; this.barClosed = true;
// Set the private defaults this.onConfigChanged =
this._unsubscribeAll = new Subject(); this.fuseConfig.onConfigChanged
} .subscribe(
(newConfig) => {
this.config = newConfig;
}
);
// ----------------------------------------------------------------------------------------------------- // Get the nav model and add customize nav item
// @ Lifecycle hooks // that opens the bar programmatically
// ----------------------------------------------------------------------------------------------------- const nav: any = navigation;
/** nav.push({
* On init 'id' : 'custom-function',
*/ 'title' : 'Custom Function',
ngOnInit(): void 'type' : 'group',
{ 'children': [
// 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: [
{ {
id : 'customize', 'id' : 'customize',
title : 'Customize', 'title' : 'Customize',
type : 'item', 'type' : 'item',
icon : 'settings', 'icon' : 'settings',
function: () => { 'function': () => {
this.toggleSidebarOpen('themeOptionsPanel'); this.openBar();
} }
} }
] ]
}; });
this._fuseNavigationService.addNavigationItem(customFunctionNavItem, 'end');
} }
/** ngOnInit()
* On destroy
*/
ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions this.renderer.listen(this.overlay.nativeElement, 'click', () => {
this._unsubscribeAll.next(); this.closeBar();
this._unsubscribeAll.complete(); });
// Remove the custom function menu
this._fuseNavigationService.removeNavigationItem('custom-function');
} }
// ----------------------------------------------------------------------------------------------------- ngOnDestroy()
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Reset the form values based on the
* selected layout style
*
* @param value
* @private
*/
private _resetFormValues(value): void
{ {
switch ( value ) this.onConfigChanged.unsubscribe();
{
// 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;
}
}
} }
// ----------------------------------------------------------------------------------------------------- onSettingsChange()
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Toggle sidebar open
*
* @param key
*/
toggleSidebarOpen(key): void
{ {
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 { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule } from '@angular/material';
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 { FuseDirectivesModule } from '@fuse/directives/directives';
import { FuseMaterialColorPickerModule } from '@fuse/components/material-color-picker/material-color-picker.module'; import { FuseMaterialColorPickerModule } from '@fuse/components/material-color-picker/material-color-picker.module';
import { FuseSidebarModule } from '@fuse/components/sidebar/sidebar.module';
import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component'; import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-options.component';
@NgModule({ @NgModule({
@@ -25,12 +14,10 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
imports : [ imports : [
CommonModule, CommonModule,
FormsModule, FormsModule,
ReactiveFormsModule,
FlexLayoutModule, FlexLayoutModule,
MatButtonModule, MatButtonModule,
MatCheckboxModule,
MatDividerModule, MatDividerModule,
MatFormFieldModule, MatFormFieldModule,
MatIconModule, MatIconModule,
@@ -39,9 +26,7 @@ import { FuseThemeOptionsComponent } from '@fuse/components/theme-options/theme-
MatSelectModule, MatSelectModule,
MatSlideToggleModule, MatSlideToggleModule,
FuseDirectivesModule, FuseMaterialColorPickerModule
FuseMaterialColorPickerModule,
FuseSidebarModule
], ],
exports : [ exports : [
FuseThemeOptionsComponent FuseThemeOptionsComponent

View File

@@ -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 export class FuseWidgetToggleDirective
{ {
/** constructor(public el: ElementRef)
* Constructor
*
* @param {ElementRef} elementRef
*/
constructor(
public elementRef: ElementRef
)
{ {
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

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