Merge branch 'master' into skeleton

This commit is contained in:
Sercan Yemen 2017-09-22 16:45:23 +03:00
commit ff0f2933d9
58 changed files with 2697 additions and 2092 deletions

View File

@ -25,6 +25,7 @@
"environmentSource": "environments/environment.ts", "environmentSource": "environments/environment.ts",
"environments": { "environments": {
"dev": "environments/environment.ts", "dev": "environments/environment.ts",
"hmr": "environments/environment.hmr.ts",
"prod": "environments/environment.prod.ts" "prod": "environments/environment.prod.ts"
} }
} }

2067
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,32 @@
{ {
"name": "fuse2", "name": "fuse2",
"version": "1.0.5", "version": "1.1.0",
"license": "", "license": "",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "start-hmr": "ng serve --hmr -e=hmr -sm=false",
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build",
"build-prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --prod",
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e" "e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "4.3.5", "@angular/animations": "4.4.3",
"@angular/cdk": "2.0.0-beta.10", "@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.5", "@angular/common": "4.4.3",
"@angular/compiler": "4.3.5", "@angular/compiler": "4.4.3",
"@angular/core": "4.3.5", "@angular/core": "4.4.3",
"@angular/flex-layout": "2.0.0-beta.9", "@angular/flex-layout": "2.0.0-beta.9",
"@angular/forms": "4.3.5", "@angular/forms": "4.4.3",
"@angular/http": "4.3.5", "@angular/http": "4.4.3",
"@angular/material": "2.0.0-beta.10", "@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.5", "@angular/platform-browser": "4.4.3",
"@angular/platform-browser-dynamic": "4.3.5", "@angular/platform-browser-dynamic": "4.4.3",
"@angular/router": "4.3.5", "@angular/router": "4.4.3",
"@swimlane/ngx-charts": "6.0.2", "@swimlane/ngx-charts": "6.0.2",
"@swimlane/ngx-datatable": "9.3.1", "@swimlane/ngx-datatable": "9.3.1",
"@swimlane/ngx-dnd": "3.0.0", "@swimlane/ngx-dnd": "3.0.0",
@ -39,32 +42,34 @@
"moment": "2.18.1", "moment": "2.18.1",
"ngx-color-picker": "4.3.1", "ngx-color-picker": "4.3.1",
"ngx-cookie-service": "1.0.7", "ngx-cookie-service": "1.0.7",
"ngx-perfect-scrollbar": "4.5.6", "ngx-perfect-scrollbar": "4.6.2",
"perfect-scrollbar": "0.8.1",
"rxjs": "5.4.3", "rxjs": "5.4.3",
"web-animations-js": "2.3.1", "web-animations-js": "2.3.1",
"zone.js": "0.8.17" "zone.js": "0.8.17"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "^1.3.2", "@angular/cli": "1.4.2",
"@angular/compiler-cli": "4.3.5", "@angular/compiler-cli": "4.4.3",
"@angular/language-service": "4.3.5", "@angular/language-service": "4.4.3",
"@ngtools/webpack": "^1.6.2", "@angularclass/hmr": "2.1.3",
"@types/jasmine": "^2.5.54", "@ngtools/webpack": "1.7.1",
"@types/jasminewd2": "^2.0.2", "@types/jasmine": "2.6.0",
"@types/node": "^6.0.88", "@types/jasminewd2": "2.0.2",
"codelyzer": "~3.0.1", "@types/node": "6.0.88",
"jasmine-core": "~2.6.2", "codelyzer": "3.0.1",
"jasmine-spec-reporter": "~4.1.0", "jasmine-core": "2.6.2",
"jasmine-spec-reporter": "4.1.0",
"karma": "1.7.1", "karma": "1.7.1",
"karma-chrome-launcher": "~2.1.1", "karma-chrome-launcher": "2.1.1",
"karma-cli": "~1.0.1", "karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1", "karma-coverage-istanbul-reporter": "1.2.1",
"karma-jasmine": "~1.1.0", "karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "^0.2.2", "karma-jasmine-html-reporter": "0.2.2",
"node-sass": "^4.5.3", "node-sass": "4.5.3",
"protractor": "~5.1.2", "protractor": "5.1.2",
"ts-node": "~3.0.4", "ts-node": "3.0.4",
"tslint": "~5.3.2", "tslint": "5.3.2",
"typescript": "~2.3.3" "typescript": "2.3.3"
} }
} }

View File

@ -11,6 +11,7 @@ import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { FuseMainModule } from './main/main.module'; import { FuseMainModule } from './main/main.module';
import { FuseSplashScreenService } from './core/services/splash-screen.service'; import { FuseSplashScreenService } from './core/services/splash-screen.service';
import { FuseConfigService } from './core/services/config.service'; import { FuseConfigService } from './core/services/config.service';
import { FuseNavigationService } from './core/components/navigation/navigation.service';
import { FuseSampleModule } from './main/content/sample/sample.module'; import { FuseSampleModule } from './main/content/sample/sample.module';
const appRoutes: Routes = [ const appRoutes: Routes = [
@ -37,7 +38,8 @@ const appRoutes: Routes = [
], ],
providers : [ providers : [
FuseSplashScreenService, FuseSplashScreenService,
FuseConfigService FuseConfigService,
FuseNavigationService
], ],
bootstrap : [ bootstrap : [
AppComponent AppComponent

View File

@ -1,10 +1,56 @@
import { sequence, trigger, stagger, animate, style, group, query, transition, keyframes, animateChild, state } from '@angular/animations'; import { sequence, trigger, animate, style, group, query, transition, animateChild, state, animation, useAnimation, stagger } from '@angular/animations';
// const query = (s, a, o = {optional: true}) => q(s, a, o); const customAnimation = animation([
style({
opacity : '{{opacity}}',
transform: 'scale({{scale}}) translate3d({{x}}, {{y}}, {{z}})'
}),
animate('{{duration}} {{delay}} cubic-bezier(0.0, 0.0, 0.2, 1)', style('*'))
], {
params: {
duration: '200ms',
delay : '0ms',
opacity : '0',
scale : '1',
x : '0',
y : '0',
z : '0'
}
});
export class Animations export const fuseAnimations = [
{
public static fadeInOut = trigger('fadeInOut', [ trigger('animate', [transition('void => *', [useAnimation(customAnimation)])]),
trigger('animateStagger', [
state('50', style('*')),
state('100', style('*')),
state('200', style('*')),
transition('void => 50',
query('@*',
[
stagger('50ms', [
animateChild()
])
])),
transition('void => 100',
query('@*',
[
stagger('100ms', [
animateChild()
])
])),
transition('void => 200',
query('@*',
[
stagger('200ms', [
animateChild()
])
]))
]),
trigger('fadeInOut', [
state('0', style({ state('0', style({
display: 'none', display: 'none',
opacity: 0 opacity: 0
@ -15,9 +61,9 @@ export class Animations
})), })),
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'))
]); ]),
public static slideInOut = trigger('slideInOut', [ trigger('slideInOut', [
state('0', style({ state('0', style({
height : '0px', height : '0px',
display: 'none' display: 'none'
@ -28,9 +74,9 @@ export class Animations
})), })),
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'))
]); ]),
public static slideInLeft = trigger('slideInLeft', [ trigger('slideInLeft', [
state('void', style({ state('void', style({
transform: 'translateX(-100%)', transform: 'translateX(-100%)',
display : 'none' display : 'none'
@ -41,9 +87,9 @@ export class Animations
})), })),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]),
public static slideInRight = trigger('slideInRight', [ trigger('slideInRight', [
state('void', style({ state('void', style({
transform: 'translateX(100%)', transform: 'translateX(100%)',
display : 'none' display : 'none'
@ -54,9 +100,9 @@ export class Animations
})), })),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]),
public static slideInTop = trigger('slideInTop', [ trigger('slideInTop', [
state('void', style({ state('void', style({
transform: 'translateY(-100%)', transform: 'translateY(-100%)',
display : 'none' display : 'none'
@ -67,9 +113,9 @@ export class Animations
})), })),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]),
public static slideInBottom = trigger('slideInBottom', [ trigger('slideInBottom', [
state('void', state('void',
style({ style({
transform: 'translateY(100%)', transform: 'translateY(100%)',
@ -81,9 +127,9 @@ export class Animations
})), })),
transition('void => *', animate('300ms')), transition('void => *', animate('300ms')),
transition('* => void', animate('300ms')) transition('* => void', animate('300ms'))
]); ]),
public static routerTransitionLeft = trigger('routerTransitionLeft', [ trigger('routerTransitionLeft', [
transition('* => *', [ transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [ query('fuse-content > :enter, fuse-content > :leave', [
@ -108,7 +154,7 @@ export class Animations
transform: 'translateX(0)', transform: 'translateX(0)',
opacity : 1 opacity : 1
}), }),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateX(-100%)', transform: 'translateX(-100%)',
opacity : 0 opacity : 0
@ -116,7 +162,7 @@ export class Animations
], {optional: true}), ], {optional: true}),
query('fuse-content > :enter', [ query('fuse-content > :enter', [
style({transform: 'translateX(100%)'}), style({transform: 'translateX(100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateX(0%)', transform: 'translateX(0%)',
opacity : 1 opacity : 1
@ -127,9 +173,9 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true}) query('fuse-content > :enter', animateChild(), {optional: true})
]) ])
]) ])
]); ]),
public static routerTransitionRight = trigger('routerTransitionRight', [ trigger('routerTransitionRight', [
transition('* => *', [ transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [ query('fuse-content > :enter, fuse-content > :leave', [
@ -154,7 +200,7 @@ export class Animations
transform: 'translateX(0)', transform: 'translateX(0)',
opacity : 1 opacity : 1
}), }),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateX(100%)', transform: 'translateX(100%)',
opacity : 0 opacity : 0
@ -162,7 +208,7 @@ export class Animations
], {optional: true}), ], {optional: true}),
query('fuse-content > :enter', [ query('fuse-content > :enter', [
style({transform: 'translateX(-100%)'}), style({transform: 'translateX(-100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateX(0%)', transform: 'translateX(0%)',
opacity : 1 opacity : 1
@ -173,9 +219,9 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true}) query('fuse-content > :enter', animateChild(), {optional: true})
]) ])
]) ])
]); ]),
public static routerTransitionUp = trigger('routerTransitionUp', [ trigger('routerTransitionUp', [
transition('* => *', [ transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [ query('fuse-content > :enter, fuse-content > :leave', [
@ -193,14 +239,13 @@ export class Animations
opacity : 0 opacity : 0
}) })
], {optional: true}), ], {optional: true}),
sequence([
group([ group([
query('fuse-content > :leave', [ query('fuse-content > :leave', [
style({ style({
transform: 'translateY(0)', transform: 'translateY(0)',
opacity : 1 opacity : 1
}), }),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateY(-100%)', transform: 'translateY(-100%)',
opacity : 0 opacity : 0
@ -208,7 +253,7 @@ export class Animations
], {optional: true}), ], {optional: true}),
query('fuse-content > :enter', [ query('fuse-content > :enter', [
style({transform: 'translateY(100%)'}), style({transform: 'translateY(100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateY(0%)', transform: 'translateY(0%)',
opacity : 1 opacity : 1
@ -218,10 +263,9 @@ export class Animations
query('fuse-content > :leave', animateChild(), {optional: true}), query('fuse-content > :leave', animateChild(), {optional: true}),
query('fuse-content > :enter', animateChild(), {optional: true}) query('fuse-content > :enter', animateChild(), {optional: true})
]) ])
]) ]),
]);
public static routerTransitionDown = trigger('routerTransitionDown', [ trigger('routerTransitionDown', [
transition('* => *', [ transition('* => *', [
query('fuse-content > :enter, fuse-content > :leave', [ query('fuse-content > :enter, fuse-content > :leave', [
@ -246,7 +290,7 @@ export class Animations
transform: 'translateY(0)', transform: 'translateY(0)',
opacity : 1 opacity : 1
}), }),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateY(100%)', transform: 'translateY(100%)',
opacity : 0 opacity : 0
@ -254,7 +298,7 @@ export class Animations
], {optional: true}), ], {optional: true}),
query('fuse-content > :enter', [ query('fuse-content > :enter', [
style({transform: 'translateY(-100%)'}), style({transform: 'translateY(-100%)'}),
animate('400ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
transform: 'translateY(0%)', transform: 'translateY(0%)',
opacity : 1 opacity : 1
@ -265,11 +309,11 @@ export class Animations
query('fuse-content > :enter', animateChild(), {optional: true}) query('fuse-content > :enter', animateChild(), {optional: true})
]) ])
]) ])
]); ]),
public static routerTransitionFade = trigger('routerTransitionFade', [ trigger('routerTransitionFade', [
transition('* => *', [ transition('* => *', group([
query('fuse-content > :enter, fuse-content > :leave ', [ query('fuse-content > :enter, fuse-content > :leave ', [
style({ style({
@ -280,17 +324,17 @@ export class Animations
right : 0 right : 0
}) })
], {optional: true}), ], {optional: true}),
query('fuse-content > :enter', [ query('fuse-content > :enter', [
style({ style({
opacity: 0 opacity: 0
}) })
], {optional: true}), ], {optional: true}),
// sequence([
query('fuse-content > :leave', [ query('fuse-content > :leave', [
style({ style({
opacity: 1 opacity: 1
}), }),
animate('300ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('300ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
opacity: 0 opacity: 0
})) }))
@ -299,14 +343,13 @@ export class Animations
style({ style({
opacity: 0 opacity: 0
}), }),
animate('300ms cubic-bezier(0.250, 0.460, 0.450, 0.940)', animate('300ms cubic-bezier(0.0, 0.0, 0.2, 1)',
style({ style({
opacity: 1 opacity: 1
})) }))
], {optional: true}), ], {optional: true}),
// ]),
query('fuse-content > :enter', animateChild(), {optional: true}), query('fuse-content > :enter', animateChild(), {optional: true}),
query('fuse-content > :leave', animateChild(), {optional: true}) query('fuse-content > :leave', animateChild(), {optional: true})
]))
]) ])
]); ];
}

View File

@ -45,7 +45,7 @@
<div fxLayout="row" fxLayoutWrap <div fxLayout="row" fxLayoutWrap
fxLayoutAlign="start start" fxLayoutAlign="start start"
class="colors" perfect-scrollbar> class="colors" fusePerfectScrollbar>
<div class="color" <div class="color"
[ngClass]="'md-'+color.key+'-bg'" [ngClass]="'md-'+color.key+'-bg'"
*ngFor="let color of (colors | keys)" *ngFor="let color of (colors | keys)"
@ -63,7 +63,7 @@
[@slideInRight]> [@slideInRight]>
<div fxLayout="row" fxLayoutWrap <div fxLayout="row" fxLayoutWrap
fxLayoutAlign="start start" fxLayoutAlign="start start"
class="colors" perfect-scrollbar> class="colors" fusePerfectScrollbar>
<div class="color" <div class="color"
*ngFor="let hue of hues" *ngFor="let hue of hues"
[fxHide]="selectedPalette === 'white' && hue !== '500'|| selectedPalette === 'black' && hue !== '500'" [fxHide]="selectedPalette === 'white' && hue !== '500'|| selectedPalette === 'black' && hue !== '500'"

View File

@ -1,12 +1,12 @@
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { MatColors } from '../../matColors'; import { MatColors } from '../../matColors';
import { Animations } from '../../animations'; import { fuseAnimations } from '../../animations';
@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 : [Animations.slideInLeft, Animations.slideInRight], animations : fuseAnimations,
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class FuseMaterialColorPickerComponent implements OnInit, OnChanges export class FuseMaterialColorPickerComponent implements OnInit, OnChanges

View File

@ -9,9 +9,8 @@
<div class="{{fuseSettings.colorClasses.navbar}}"> <div class="{{fuseSettings.colorClasses.navbar}}">
<ng-container *ngFor="let item of item.children"> <ng-container *ngFor="let item of item.children">
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item> <fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='nav-collapse'" <fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
[item]="item"></fuse-nav-horizontal-collapse>
</ng-container> </ng-container>
</div> </div>

View File

@ -1,5 +1,5 @@
import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core'; import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core';
import { Animations } from '../../../../animations'; import { fuseAnimations } from '../../../../animations';
import { FuseConfigService } from '../../../../services/config.service'; import { FuseConfigService } from '../../../../services/config.service';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
@ -7,7 +7,7 @@ import { Subscription } from 'rxjs/Subscription';
selector : 'fuse-nav-horizontal-collapse', selector : 'fuse-nav-horizontal-collapse',
templateUrl: './nav-horizontal-collapse.component.html', templateUrl: './nav-horizontal-collapse.component.html',
styleUrls : ['./nav-horizontal-collapse.component.scss'], styleUrls : ['./nav-horizontal-collapse.component.scss'],
animations : [Animations.slideInOut] animations : fuseAnimations
}) })
export class FuseNavHorizontalCollapseComponent implements OnDestroy export class FuseNavHorizontalCollapseComponent implements OnDestroy
{ {

View File

@ -1,27 +1,32 @@
<div id="main-navigation" class="nav" [ngClass]="{'horizontal':layout === 'horizontal'}"> <div id="main-navigation" class="nav"
[ngClass]="{'horizontal':layout === 'horizontal', 'vertical':layout === 'vertical'}">
<!-- Vertical Navigation Layout -->
<ng-container *ngIf="layout === 'vertical'"> <ng-container *ngIf="layout === 'vertical'">
<ng-container *ngFor="let item of verticalNavigation"> <ng-container *ngFor="let item of navigationModel">
<fuse-nav-vertical-subheader *ngIf="item.type=='subheader'" [item]="item"></fuse-nav-vertical-subheader> <fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-vertical-item> <fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-collapse *ngIf="item.type=='nav-collapse'" [item]="item"></fuse-nav-vertical-collapse> <fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container> </ng-container>
</ng-container> </ng-container>
<!-- / Vertical Navigation Layout -->
<!-- Horizontal Navigation Layout -->
<ng-container *ngIf="layout === 'horizontal'"> <ng-container *ngIf="layout === 'horizontal'">
<ng-container *ngFor="let item of horizontalNavigation"> <ng-container *ngFor="let item of navigationModel">
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item> <fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item>
<fuse-nav-horizontal-collapse *ngIf="item.type=='nav-collapse'"
[item]="item"></fuse-nav-horizontal-collapse>
</ng-container> </ng-container>
</ng-container> </ng-container>
<!-- / Horizontal Navigation Layout -->
</div> </div>

View File

@ -1,5 +1,6 @@
import { Component, Input, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnDestroy, ViewEncapsulation } from '@angular/core';
import { FuseNavigationService } from './navigation.service'; import { FuseNavigationService } from './navigation.service';
import { Subscription } from 'rxjs/Subscription';
@Component({ @Component({
selector : 'fuse-navigation', selector : 'fuse-navigation',
@ -7,17 +8,26 @@ import { FuseNavigationService } from './navigation.service';
styleUrls : ['./navigation.component.scss'], styleUrls : ['./navigation.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class FuseNavigationComponent export class FuseNavigationComponent implements OnDestroy
{ {
verticalNavigation: any[]; navigationModel: any[];
horizontalNavigation: any[]; navigationModelChangeSubscription: Subscription;
@Input('layout') layout = 'vertical'; @Input('layout') layout = 'vertical';
constructor(private navigationService: FuseNavigationService) constructor(private fuseNavigationService: FuseNavigationService)
{ {
this.verticalNavigation = navigationService.getNavigation('verticalNavItems'); this.navigationModelChangeSubscription =
this.horizontalNavigation = navigationService.getNavigation('horizontalNavItems'); this.fuseNavigationService.onNavigationModelChange
.subscribe((navigationModel) => {
this.navigationModel = navigationModel;
});
}
ngOnDestroy()
{
console.warn('destroyed');
this.navigationModelChangeSubscription.unsubscribe();
} }
} }

View File

@ -4,7 +4,7 @@ import { RouterModule } from '@angular/router';
import { FuseNavigationComponent } from './navigation.component'; import { FuseNavigationComponent } from './navigation.component';
import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component'; import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component';
import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component'; import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component';
import { FuseNavVerticalSubheaderComponent } from './vertical/nav-subheader/nav-vertical-subheader.component'; import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component';
import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component'; import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component';
import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component'; import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component';
@ -18,7 +18,7 @@ import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/na
], ],
declarations: [ declarations: [
FuseNavigationComponent, FuseNavigationComponent,
FuseNavVerticalSubheaderComponent, FuseNavVerticalGroupComponent,
FuseNavVerticalItemComponent, FuseNavVerticalItemComponent,
FuseNavVerticalCollapseComponent, FuseNavVerticalCollapseComponent,
FuseNavHorizontalItemComponent, FuseNavHorizontalItemComponent,

View File

@ -1,25 +1,43 @@
import { EventEmitter, Injectable } from '@angular/core'; import { EventEmitter, Injectable } from '@angular/core';
import { FuseNavigation } from '../../../navigation.model'; import { NavigationModel } from '../../../navigation.model';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable() @Injectable()
export class FuseNavigationService export class FuseNavigationService
{ {
onNavCollapseToggled = new EventEmitter<any>(); onNavCollapseToggled = new EventEmitter<any>();
navigation: FuseNavigation; onNavigationModelChange: BehaviorSubject<any> = new BehaviorSubject({});
navigationModel: NavigationModel;
flatNavigation: any[] = []; flatNavigation: any[] = [];
constructor() constructor()
{ {
this.navigation = new FuseNavigation(); this.navigationModel = new NavigationModel();
this.onNavigationModelChange.next(this.navigationModel.model);
} }
/** /**
* Get navigation array * Get navigation model
* @returns {any[]} * @returns {any[]}
*/ */
getNavigation(item) getNavigationModel()
{ {
return this.navigation[item]; return this.navigationModel.model;
}
/**
* Set the navigation model
* @param model
*/
setNavigationModel(model)
{
// console.log(model);
this.navigationModel = model;
console.log(this.navigationModel);
this.onNavigationModelChange.next(this.navigationModel.model);
} }
/** /**
@ -31,7 +49,7 @@ export class FuseNavigationService
{ {
if ( !navigationItems ) if ( !navigationItems )
{ {
navigationItems = this.navigation; navigationItems = this.navigationModel.model;
} }
for ( const navItem of navigationItems ) for ( const navItem of navigationItems )
@ -41,7 +59,7 @@ export class FuseNavigationService
continue; continue;
} }
if ( navItem.type === 'nav-item' ) if ( navItem.type === 'item' )
{ {
this.flatNavigation.push({ this.flatNavigation.push({
title: navItem.title, title: navItem.title,
@ -53,7 +71,7 @@ export class FuseNavigationService
continue; continue;
} }
if ( navItem.type === 'nav-collapse' ) if ( navItem.type === 'collapse' || navItem.type === 'group' )
{ {
this.getFlatNavigation(navItem.children); this.getFlatNavigation(navItem.children);
} }

View File

@ -5,7 +5,7 @@
</a> </a>
<div class="children" [@slideInOut]="isOpen"> <div class="children" [@slideInOut]="isOpen">
<ng-container *ngFor="let item of item.children"> <ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-vertical-item> <fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
<fuse-nav-vertical-collapse *ngIf="item.type=='nav-collapse'" [item]="item"></fuse-nav-vertical-collapse> <fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
</ng-container> </ng-container>
</div> </div>

View File

@ -1,13 +1,13 @@
import { Component, HostBinding, Input, OnInit } from '@angular/core'; import { Component, HostBinding, Input, OnInit } from '@angular/core';
import { FuseNavigationService } from '../../navigation.service'; import { FuseNavigationService } from '../../navigation.service';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { Animations } from '../../../../animations'; import { fuseAnimations } from '../../../../animations';
@Component({ @Component({
selector : 'fuse-nav-vertical-collapse', selector : 'fuse-nav-vertical-collapse',
templateUrl: './nav-vertical-collapse.component.html', templateUrl: './nav-vertical-collapse.component.html',
styleUrls : ['./nav-vertical-collapse.component.scss'], styleUrls : ['./nav-vertical-collapse.component.scss'],
animations : [Animations.slideInOut] animations : fuseAnimations
}) })
export class FuseNavVerticalCollapseComponent implements OnInit export class FuseNavVerticalCollapseComponent implements OnInit
{ {
@ -15,21 +15,20 @@ export class FuseNavVerticalCollapseComponent implements OnInit
@HostBinding('class') classes = 'nav-collapse nav-item'; @HostBinding('class') classes = 'nav-collapse nav-item';
@HostBinding('class.open') public isOpen = false; @HostBinding('class.open') public isOpen = false;
constructor(private navigationService: FuseNavigationService, private router: Router) constructor(
private navigationService: FuseNavigationService,
private router: Router
)
{ {
/** // Listen for route changes
* When navigation changed
*/
router.events.subscribe( router.events.subscribe(
(event) => { (event) => {
if ( event instanceof NavigationEnd ) if ( event instanceof NavigationEnd )
{ {
/** // Check if the url can be found in
* Check if the url is child of the collapse // one of the children of this item
*/
if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) ) if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) )
{ {
// console.log(this.item);
this.expand(); this.expand();
} }
else else
@ -40,25 +39,27 @@ export class FuseNavVerticalCollapseComponent implements OnInit
} }
); );
/** // Listen for collapsing of any navigation item
* Whenever a navigation collapse item toggled this.navigationService.onNavCollapseToggled
*/ .subscribe(
this.navigationService.onNavCollapseToggled.subscribe(
(clickedItem) => { (clickedItem) => {
if ( clickedItem.children ) if ( clickedItem.children )
{ {
/** // Check if the clicked item is one
* if clicked collapse is child of this collapse // of the children of this item
* return if ( this.isChildrenOf(this.item, clickedItem) )
*/
if ( this.item.children.indexOf(clickedItem) !== -1 )
{ {
return; return;
} }
/**
* If collapsed item is not related with this collapse // Check if the url can be found in
* collapse // 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 ) if ( this.item !== clickedItem )
{ {
this.collapse(); this.collapse();
@ -69,18 +70,22 @@ export class FuseNavVerticalCollapseComponent implements OnInit
} }
/** /**
* Toggle Collapse * Toggle collapse
*
* @param ev * @param ev
*/ */
toggleOpen(ev) toggleOpen(ev)
{ {
ev.preventDefault(); ev.preventDefault();
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
// Navigation collapse toggled...
this.navigationService.onNavCollapseToggled.emit(this.item); this.navigationService.onNavCollapseToggled.emit(this.item);
} }
/** /**
* Expand * Expand the collapsable navigation
*/ */
expand() expand()
{ {
@ -88,11 +93,12 @@ export class FuseNavVerticalCollapseComponent implements OnInit
{ {
return; return;
} }
this.isOpen = true; this.isOpen = true;
} }
/** /**
* Collapse * Collapse the collapsable navigation
*/ */
collapse() collapse()
{ {
@ -104,29 +110,60 @@ export class FuseNavVerticalCollapseComponent implements OnInit
} }
/** /**
* Checking the url is in children * Check if the given parent has the
* @param arr * 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 * @param url
* @returns {any} * @returns {any}
*/ */
isUrlInChildren(arr, url) isUrlInChildren(parent, url)
{ {
if ( !arr.children ) if ( !parent.children )
{ {
return false; return false;
} }
for ( let i = 0; i < arr.children.length; i++ ) for ( let i = 0; i < parent.children.length; i++ )
{ {
if ( arr.children[i].children ) if ( parent.children[i].children )
{ {
if ( this.isUrlInChildren(arr.children[i], url) ) if ( this.isUrlInChildren(parent.children[i], url) )
{ {
return true; return true;
} }
} }
if ( arr.children[i].url === url ) if ( parent.children[i].url === url )
{ {
return true; return true;
} }
@ -135,11 +172,6 @@ export class FuseNavVerticalCollapseComponent implements OnInit
return false; return false;
} }
public isCollapsed(): boolean
{
return this.isOpen;
}
ngOnInit() ngOnInit()
{ {
} }

View File

@ -0,0 +1,10 @@
<div class="group-title">
<span class="hint-text">{{ item.title }}</span>
</div>
<div class="group-items">
<ng-container *ngFor="let item of item.children">
<fuse-nav-vertical-group *ngIf="item.type=='group'" [item]="item"></fuse-nav-vertical-group>
<fuse-nav-vertical-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-vertical-collapse>
<fuse-nav-vertical-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-vertical-item>
</ng-container>
</div>

View File

@ -0,0 +1,23 @@
:host {
.folded:not(.folded-open) & {
> .group-title {
align-items: center;
> span {
opacity: 0;
transition: opacity 200ms ease;
}
&:before {
content: '';
display: block;
position: absolute;
min-width: 1.6rem;
border-top: 2px solid;
opacity: 0.2;
}
}
}
}

View File

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

View File

@ -1 +0,0 @@
<span class="hint-text">{{ item.title }}</span>

View File

@ -1,20 +0,0 @@
:host {
.folded:not(.folded-open) & {
&:before {
content: '';
display: block;
position: absolute;
min-width: 1.6rem;
border-top: 2px solid;
opacity: 0.2;
}
> span {
opacity: 0;
transition: opacity 200ms ease;
}
}
}

View File

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

View File

@ -47,7 +47,7 @@
</md-input-container> </md-input-container>
<md-divider></md-divider> <md-divider></md-divider>
<md-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" perfect-scrollbar> <md-nav-list *ngIf="!searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<md-list-item *ngFor="let shortcutItem of shortcutItems" <md-list-item *ngFor="let shortcutItem of shortcutItems"
(click)="toggleShortcut($event, shortcutItem)"> (click)="toggleShortcut($event, shortcutItem)">
@ -68,7 +68,7 @@
</md-list-item> </md-list-item>
</md-nav-list> </md-nav-list>
<md-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" perfect-scrollbar> <md-nav-list *ngIf="searching" style="max-height: 312px; overflow: auto" fusePerfectScrollbar>
<md-list-item *ngFor="let navigationItem of filteredNavigationItems" <md-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">

View File

@ -4,85 +4,74 @@
<div class="theme-options-panel-overlay" #overlay [fxHide]="barClosed" [@fadeInOut]="!barClosed"></div> <div class="theme-options-panel-overlay" #overlay [fxHide]="barClosed" [@fadeInOut]="!barClosed"></div>
<div #panel class="theme-options-panel md-white-bg mat-elevation-z8 p-16"> <div #panel class="theme-options-panel md-white-bg mat-elevation-z8">
<button md-icon-button class="close-button" (click)="closeBar()"> <button md-icon-button class="close-button" (click)="closeBar()">
<md-icon>close</md-icon> <md-icon>close</md-icon>
</button> </button>
<md-list> <div class="theme-options-panel-inner" fxLayout="column" fxLayoutAlign="start start">
<h3 md-subheader>Navigation:</h3>
<md-list-item> <h3>Navigation:</h3>
<md-radio-group [(ngModel)]="fuseSettings.layout.navigation" (ngModelChange)="onSettingsChange()" <md-radio-group [(ngModel)]="fuseSettings.layout.navigation" (ngModelChange)="onSettingsChange()"
fxLayout="row" fxLayoutAlign="start center" fxLayoutWrap> fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="top">Top</md-radio-button> <md-radio-button class="mr-8 mb-8" value="top">Top</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="left">Left</md-radio-button> <md-radio-button class="mr-8 mb-8" value="left">Left</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="right">Right</md-radio-button> <md-radio-button class="mr-8 mb-8" value="right">Right</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button> <md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group> </md-radio-group>
</md-list-item>
<h3 md-subheader>Toolbar:</h3> <h3 class="mt-24">Toolbar:</h3>
<md-list-item> <md-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()"
<md-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()"> fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button> <md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button> <md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button> <md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group> </md-radio-group>
</md-list-item>
<h3 md-subheader>Footer:</h3> <h3 class="mt-24">Footer:</h3>
<md-list-item> <md-radio-group [(ngModel)]="fuseSettings.layout.footer" (ngModelChange)="onSettingsChange()"
<md-radio-group [(ngModel)]="fuseSettings.layout.footer" (ngModelChange)="onSettingsChange()"> fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button> <md-radio-button class="mr-8 mb-8" value="below">Below</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button> <md-radio-button class="mr-8 mb-8" value="above">Above</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button> <md-radio-button class="mr-8 mb-8" value="none">None</md-radio-button>
</md-radio-group> </md-radio-group>
</md-list-item>
<h3 md-subheader>Layout Mode:</h3> <h3 class="mt-24">Layout Mode:</h3>
<md-list-item> <md-radio-group [(ngModel)]="fuseSettings.layout.mode" (ngModelChange)="onSettingsChange()"
<md-radio-group [(ngModel)]="fuseSettings.layout.mode" (ngModelChange)="onSettingsChange()"> fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
<md-radio-button class="mr-8 mb-8" value="boxed">Boxed</md-radio-button> <md-radio-button class="mr-8 mb-8" value="boxed">Boxed</md-radio-button>
<md-radio-button class="mr-8 mb-8" value="fullwidth">Fullwidth</md-radio-button> <md-radio-button class="mr-8 mb-8" value="fullwidth">Fullwidth</md-radio-button>
</md-radio-group> </md-radio-group>
</md-list-item>
<md-divider></md-divider> <md-divider></md-divider>
<h3 md-subheader>Colors:</h3> <h3>Colors:</h3>
<div class="colors">
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> <div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Toolbar Color</h4> <h4 class="mr-8">Toolbar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.toolbar" <fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.toolbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker> (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div> </div>
</md-list-item>
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> <div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Navigation Bar Color</h4> <h4 class="mr-8">Navigation Bar Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.navbar" <fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.navbar"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker> (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div> </div>
</md-list-item>
<md-list-item class="mb-8">
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center"> <div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4 class="mr-8">Footer Color</h4> <h4 class="mr-8">Footer Color</h4>
<fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.footer" <fuse-material-color-picker [(selectedClass)]="fuseSettings.colorClasses.footer"
(onValueChange)="onSettingsChange()"></fuse-material-color-picker> (onValueChange)="onSettingsChange()"></fuse-material-color-picker>
</div> </div>
</md-list-item>
</div>
<md-divider></md-divider> <md-divider></md-divider>
<h3 md-subheader>Animation:</h3> <h3>Router Animation:</h3>
<md-list-item>
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
<h4>Router Animation</h4>
<md-select class="p-0" [(ngModel)]="fuseSettings.routerAnimation"> <md-select class="p-0" [(ngModel)]="fuseSettings.routerAnimation">
<md-option value="none"> <md-option value="none">
None None
@ -103,8 +92,7 @@
Fade in Fade in
</md-option> </md-option>
</md-select> </md-select>
</div>
</md-list-item>
</md-list> </div>
</div> </div>

View File

@ -15,6 +15,10 @@
right: 0; right: 0;
top: 160px; top: 160px;
&.bar-closed .theme-options-panel {
display: none;
}
.theme-options-panel { .theme-options-panel {
position: absolute; position: absolute;
right: 0; right: 0;
@ -22,11 +26,14 @@
width: 360px; width: 360px;
transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0);
z-index: 999; z-index: 999;
max-width: 80vw; max-height: calc(100vh - 200px);
max-height: calc(100vh - 180px); padding: 24px;
overflow: auto; overflow: auto;
@include media-breakpoint-down('xs') { @include media-breakpoint-down('xs') {
top: -120px;
max-height: calc(100vh - 100px);
width: 90vw;
} }
.close-button { .close-button {
@ -34,6 +41,23 @@
top: 8px; top: 8px;
right: 8px; right: 8px;
} }
h3 {
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.54);
}
.mat-divider{
display: block !important;
width: 100%;
margin: 24px 0 16px 0;
}
.colors {
display: block !important;
width: 100%;
}
} }
.theme-options-panel-overlay { .theme-options-panel-overlay {
@ -46,6 +70,10 @@
bottom: 0; bottom: 0;
z-index: 998; z-index: 998;
@include media-breakpoint-down('sm') {
background: rgba(0, 0, 0, 0.37);
}
&.hidden { &.hidden {
display: none; display: none;
} }
@ -82,4 +110,5 @@
opacity: 1; opacity: 1;
} }
} }
} }

View File

@ -1,14 +1,14 @@
import { Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core'; import { Component, ElementRef, HostBinding, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations'; import { style, animate, AnimationBuilder, AnimationPlayer } from '@angular/animations';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { FuseConfigService } from '../../services/config.service'; import { FuseConfigService } from '../../services/config.service';
import { Animations } from '../../animations'; import { fuseAnimations } from '../../animations';
@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'],
animations : [Animations.fadeInOut] animations : fuseAnimations
}) })
export class FuseThemeOptionsComponent implements OnInit, OnDestroy export class FuseThemeOptionsComponent implements OnInit, OnDestroy
{ {
@ -18,10 +18,11 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
public player: AnimationPlayer; public player: AnimationPlayer;
fuseSettings: any; fuseSettings: any;
barClosed: boolean;
onSettingsChanged: Subscription; onSettingsChanged: Subscription;
@HostBinding('class.bar-closed') barClosed: boolean;
constructor( constructor(
private animationBuilder: AnimationBuilder, private animationBuilder: AnimationBuilder,
private fuseConfig: FuseConfigService, private fuseConfig: FuseConfigService,
@ -53,8 +54,6 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
closeBar() closeBar()
{ {
this.barClosed = true;
this.player = this.player =
this.animationBuilder this.animationBuilder
.build([ .build([
@ -63,6 +62,10 @@ export class FuseThemeOptionsComponent implements OnInit, OnDestroy
]).create(this.panel.nativeElement); ]).create(this.panel.nativeElement);
this.player.play(); this.player.play();
this.player.onDone(() => {
this.barClosed = true;
});
} }
openBar() openBar()

View File

@ -21,7 +21,7 @@ export class FuseIfOnDomDirective implements AfterContentChecked
{ {
setTimeout(() => { setTimeout(() => {
this.viewContainer.createEmbeddedView(this.templateRef); this.viewContainer.createEmbeddedView(this.templateRef);
}, 0); }, 350);
this.isCreated = true; this.isCreated = true;
} }
else if ( this.isCreated && !document.body.contains(this.element.nativeElement) ) else if ( this.isCreated && !document.body.contains(this.element.nativeElement) )

View File

@ -0,0 +1,173 @@
import { AfterViewInit, Directive, ElementRef, NgZone, OnDestroy, OnInit } from '@angular/core';
import * as Ps from 'perfect-scrollbar';
import { FuseConfigService } from '../../services/config.service';
import { Subscription } from 'rxjs/Subscription';
import { Platform } from '@angular/cdk/platform';
@Directive({
selector: '[fusePerfectScrollbar]'
})
export class FusePerfectScrollbarDirective implements OnInit, AfterViewInit, OnDestroy
{
onSettingsChanged: Subscription;
isDisableCustomScrollbars = false;
isMobile = false;
isInitialized = true;
constructor(
private element: ElementRef,
private zone: NgZone,
private fuseConfig: FuseConfigService,
private platform: Platform
)
{
this.onSettingsChanged =
this.fuseConfig.onSettingsChanged
.subscribe(
(settings) => {
this.isDisableCustomScrollbars = !settings.customScrollbars;
}
);
if ( this.platform.ANDROID || this.platform.IOS )
{
this.isMobile = true;
}
}
ngOnInit()
{
}
ngAfterViewInit()
{
if ( this.isMobile || this.isDisableCustomScrollbars )
{
this.isInitialized = false;
return;
}
this.zone.runOutsideAngular(() => {
// Initialize the perfect-scrollbar
Ps.initialize(this.element.nativeElement);
});
}
ngOnDestroy()
{
if ( !this.isInitialized )
{
return;
}
this.onSettingsChanged.unsubscribe();
// Destroy the perfect-scrollbar
Ps.destroy(this.element.nativeElement);
}
update()
{
if ( !this.isInitialized )
{
return;
}
// Update the perfect-scrollbar
Ps.update(this.element.nativeElement);
}
destroy()
{
this.ngOnDestroy();
}
scrollToX(x: number, speed?: number)
{
this.animateScrolling('scrollLeft', x, speed);
}
scrollToY(y: number, speed?: number)
{
this.animateScrolling('scrollTop', y, speed);
}
scrollToTop(offset?: number, speed?: number)
{
this.animateScrolling('scrollTop', (offset || 0), speed);
}
scrollToLeft(offset?: number, speed?: number)
{
this.animateScrolling('scrollLeft', (offset || 0), speed);
}
scrollToRight(offset?: number, speed?: number)
{
const width = this.element.nativeElement.scrollWidth;
this.animateScrolling('scrollLeft', width - (offset || 0), speed);
}
scrollToBottom(offset?: number, speed?: number)
{
const height = this.element.nativeElement.scrollHeight;
this.animateScrolling('scrollTop', height - (offset || 0), speed);
}
animateScrolling(target: string, value: number, speed?: number)
{
if ( !speed )
{
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
this.update();
}
else if ( value !== this.element.nativeElement[target] )
{
let newValue = 0;
let scrollCount = 0;
let oldTimestamp = performance.now();
let oldValue = this.element.nativeElement[target];
const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp) => {
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));
// Only continue animation if scroll position has not changed
if ( this.element.nativeElement[target] === oldValue )
{
if ( scrollCount >= Math.PI )
{
this.element.nativeElement[target] = value;
// PS has weird event sending order, this is a workaround for that
this.update();
this.update();
}
else
{
this.element.nativeElement[target] = oldValue = newValue;
oldTimestamp = newTimestamp;
window.requestAnimationFrame(step);
}
}
};
window.requestAnimationFrame(step);
}
}
}

View File

@ -1,4 +1,4 @@
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding, AfterViewInit } from '@angular/core'; import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
import { MdSidenav } from '@angular/material'; import { MdSidenav } from '@angular/material';
import { FuseMdSidenavHelperService } from 'app/core/directives/md-sidenav-helper/md-sidenav-helper.service'; import { FuseMdSidenavHelperService } from 'app/core/directives/md-sidenav-helper/md-sidenav-helper.service';
import { FuseMatchMedia } from '../../services/match-media.service'; import { FuseMatchMedia } from '../../services/match-media.service';
@ -8,7 +8,7 @@ import { Subscription } from 'rxjs/Subscription';
@Directive({ @Directive({
selector: '[fuseMdSidenavHelper]' selector: '[fuseMdSidenavHelper]'
}) })
export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDestroy export class FuseMdSidenavHelperDirective implements OnInit, OnDestroy
{ {
matchMediaSubscription: Subscription; matchMediaSubscription: Subscription;
@ -38,6 +38,7 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
this.mdSidenav.mode = 'side'; this.mdSidenav.mode = 'side';
this.mdSidenav.open(); this.mdSidenav.open();
}); });
this.stopTransition = false;
} }
else else
{ {
@ -46,6 +47,10 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
this.mdSidenav.mode = 'over'; this.mdSidenav.mode = 'over';
this.mdSidenav.close(); this.mdSidenav.close();
}); });
setTimeout(() => {
this.stopTransition = false;
}, 3000);
} }
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => { this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
@ -69,13 +74,6 @@ export class FuseMdSidenavHelperDirective implements OnInit, AfterViewInit, OnDe
} }
ngAfterViewInit()
{
setTimeout(() => {
this.stopTransition = false;
}, 0);
}
ngOnDestroy() ngOnDestroy()
{ {
this.matchMediaSubscription.unsubscribe(); this.matchMediaSubscription.unsubscribe();

View File

@ -1,6 +1,5 @@
export class FuseUtils export class FuseUtils
{ {
public static filterArrayByString(mainArr, searchText) public static filterArrayByString(mainArr, searchText)
{ {
if ( searchText === '' ) if ( searchText === '' )
@ -17,7 +16,6 @@ export class FuseUtils
public static searchInObj(itemObj, searchText) public static searchInObj(itemObj, searchText)
{ {
for ( const prop in itemObj ) for ( const prop in itemObj )
{ {
if ( !itemObj.hasOwnProperty(prop) ) if ( !itemObj.hasOwnProperty(prop) )
@ -29,7 +27,7 @@ export class FuseUtils
if ( typeof value === 'string' ) if ( typeof value === 'string' )
{ {
if ( this.searchInSting(value, searchText) ) if ( this.searchInString(value, searchText) )
{ {
return true; return true;
} }
@ -41,7 +39,6 @@ export class FuseUtils
{ {
return true; return true;
} }
} }
if ( typeof value === 'object' ) if ( typeof value === 'object' )
@ -60,7 +57,7 @@ export class FuseUtils
{ {
if ( typeof value === 'string' ) if ( typeof value === 'string' )
{ {
if ( this.searchInSting(value, searchText) ) if ( this.searchInString(value, searchText) )
{ {
return true; return true;
} }
@ -76,7 +73,7 @@ export class FuseUtils
} }
} }
public static searchInSting(value, searchText) public static searchInString(value, searchText)
{ {
return value.toLowerCase().includes(searchText); return value.toLowerCase().includes(searchText);
} }

View File

@ -4,7 +4,6 @@ import { CommonModule } from '@angular/common';
import { MaterialModule } from './material.module'; import { MaterialModule } from './material.module';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { ColorPickerModule } from 'ngx-color-picker'; import { ColorPickerModule } from 'ngx-color-picker';
import { NgxDnDModule } from '@swimlane/ngx-dnd'; import { NgxDnDModule } from '@swimlane/ngx-dnd';
import { NgxDatatableModule } from '@swimlane/ngx-datatable'; import { NgxDatatableModule } from '@swimlane/ngx-datatable';
@ -13,11 +12,11 @@ import { FuseMdSidenavHelperDirective, FuseMdSidenavTogglerDirective } from '../
import { FusePipesModule } from '../pipes/pipes.module'; import { FusePipesModule } from '../pipes/pipes.module';
import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component'; import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component';
import { FuseCountdownComponent } from '../components/countdown/countdown.component'; import { FuseCountdownComponent } from '../components/countdown/countdown.component';
import { FuseNavigationService } from '../components/navigation/navigation.service';
import { FuseMatchMedia } from '../services/match-media.service'; import { FuseMatchMedia } from '../services/match-media.service';
import { FuseNavbarVerticalService } from '../../main/navbar/vertical/navbar-vertical.service'; import { FuseNavbarVerticalService } from '../../main/navbar/vertical/navbar-vertical.service';
import { FuseMdSidenavHelperService } from '../directives/md-sidenav-helper/md-sidenav-helper.service'; import { FuseMdSidenavHelperService } from '../directives/md-sidenav-helper/md-sidenav-helper.service';
import { FuseHljsComponent } from '../components/hljs/hljs.component'; import { FuseHljsComponent } from '../components/hljs/hljs.component';
import { FusePerfectScrollbarDirective } from '../directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive'; import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive';
import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component'; import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component';
import { Md2Module } from 'md2'; import { Md2Module } from 'md2';
@ -31,6 +30,7 @@ import { CookieService } from 'ngx-cookie-service';
FuseCountdownComponent, FuseCountdownComponent,
FuseHljsComponent, FuseHljsComponent,
FuseIfOnDomDirective, FuseIfOnDomDirective,
FusePerfectScrollbarDirective,
FuseMaterialColorPickerComponent FuseMaterialColorPickerComponent
], ],
imports : [ imports : [
@ -39,7 +39,6 @@ import { CookieService } from 'ngx-cookie-service';
CommonModule, CommonModule,
FormsModule, FormsModule,
FusePipesModule, FusePipesModule,
PerfectScrollbarModule,
ReactiveFormsModule, ReactiveFormsModule,
ColorPickerModule, ColorPickerModule,
NgxDnDModule, NgxDnDModule,
@ -56,7 +55,7 @@ import { CookieService } from 'ngx-cookie-service';
FusePipesModule, FusePipesModule,
FuseCountdownComponent, FuseCountdownComponent,
FuseHljsComponent, FuseHljsComponent,
PerfectScrollbarModule, FusePerfectScrollbarDirective,
ReactiveFormsModule, ReactiveFormsModule,
ColorPickerModule, ColorPickerModule,
NgxDnDModule, NgxDnDModule,
@ -70,7 +69,6 @@ import { CookieService } from 'ngx-cookie-service';
], ],
providers : [ providers : [
CookieService, CookieService,
FuseNavigationService,
FuseMatchMedia, FuseMatchMedia,
FuseNavbarVerticalService, FuseNavbarVerticalService,
FuseMdSidenavHelperService FuseMdSidenavHelperService

View File

@ -2,8 +2,8 @@
@import '~@swimlane/ngx-datatable/release/index.css'; @import '~@swimlane/ngx-datatable/release/index.css';
@import '~@swimlane/ngx-datatable/release/themes/material.css'; @import '~@swimlane/ngx-datatable/release/themes/material.css';
@import '~@swimlane/ngx-datatable/release/assets/icons.css'; @import '~@swimlane/ngx-datatable/release/assets/icons.css';
// Perfect Scrollbar // Perfect scrollbar
@import "~perfect-scrollbar/src/css/main"; @import '~perfect-scrollbar/dist/css/perfect-scrollbar.min.css';
// Fuse // Fuse
@import "fuse"; @import "fuse";

View File

@ -4,3 +4,38 @@
border-radius: 50%; border-radius: 50%;
} }
} }
md-sidenav-container {
md-sidenav {
&[md-is-locked-open].md-stop-transition {
transition: none !important;
transform: translate3d(0, 0, 0) !important;
opacity: 0;
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none !important;
}
}
&.mat-sidenav-opened {
&.mat-drawer-side {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none !important;
transform: translate3d(0, 0, 0) !important;
}
}
}
&.mat-drawer-end {
}
}
.mat-drawer-content {
}
}

View File

@ -11,6 +11,21 @@
white-space: nowrap; white-space: nowrap;
} }
.nav-group {
> .group-title {
position: relative;
display: flex;
align-items: center;
height: 48px;
font-weight: 500;
padding-left: 24px;
margin-top: 8px;
font-size: 12px;
white-space: nowrap;
}
}
.nav-item { .nav-item {
.nav-link { .nav-link {
@ -119,6 +134,31 @@
} }
} }
> .nav-group {
> .group-items {
> .nav-collapse {
background: transparent;
transition: background 200ms ease-in-out;
&.open {
background: rgba(0, 0, 0, 0.12);
}
}
}
}
&.vertical {
.nav-group {
.group-title {
text-transform: uppercase;
}
}
}
&.horizontal { &.horizontal {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -137,19 +137,10 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
@include mat-elevation(7); @include mat-elevation(7);
&.md-is-locked-open { &.md-is-locked-open {
position: relative;
background: none; background: none;
box-shadow: none; box-shadow: none;
} }
&.md-stop-transition {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
.header { .header {
height: $carded-header-height; height: $carded-header-height;
min-height: $carded-header-height; min-height: $carded-header-height;
@ -233,7 +224,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
~ .mat-sidenav-content, ~ .mat-sidenav-content,
~ .mat-drawer-content { ~ .mat-drawer-content {
margin-left: 0 !important;
.center { .center {
margin-left: 0; margin-left: 0;
@ -257,7 +247,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
~ .mat-sidenav-content, ~ .mat-sidenav-content,
~ .mat-drawer-content { ~ .mat-drawer-content {
margin-right: 0 !important;
.center { .center {
margin-right: 0; margin-right: 0;
@ -284,6 +273,10 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
} }
// Fullwidth // Fullwidth
&.fullwidth {
overflow: auto;
}
&.fullwidth, &.fullwidth,
&.inner-sidenav { &.inner-sidenav {
min-height: 100%; min-height: 100%;
@ -309,10 +302,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> .mat-drawer-content { > .mat-drawer-content {
flex: 1 0 auto; flex: 1 0 auto;
max-height: none; max-height: none;
> .center {
overflow: hidden;
}
} }
} }
} }
@ -352,6 +341,7 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> md-sidenav-container { > md-sidenav-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
//flex-direction: row;
flex: 1; flex: 1;
background: none; background: none;
z-index: 2; z-index: 2;
@ -372,14 +362,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
background: transparent; background: transparent;
} }
&.md-stop-transition {
~ .mat-sidenav-content,
~ .mat-drawer-content {
transition: none;
}
}
.sidenav-content { .sidenav-content {
height: 100%; height: 100%;
} }
@ -467,7 +449,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
&.simple { &.simple {
&.fullwidth { &.fullwidth {
overflow: visible;
> .content { > .content {
flex: 1 0 auto; flex: 1 0 auto;
@ -483,10 +464,6 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
> .mat-sidenav-content, > .mat-sidenav-content,
> .mat-drawer-content { > .mat-drawer-content {
flex: 1 0 auto; flex: 1 0 auto;
> .center {
overflow: hidden;
}
} }
} }
} }

View File

@ -1,20 +1,23 @@
::-webkit-scrollbar { body:not(.is-mobile) {
::-webkit-scrollbar {
width: 12px; width: 12px;
height: 12px; height: 12px;
background-color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);
} }
::-webkit-scrollbar:hover { ::-webkit-scrollbar:hover {
background-color: rgba(0, 0, 0, 0.12); background-color: rgba(0, 0, 0, 0.12);
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
border: 2px solid transparent; border: 2px solid transparent;
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.37); box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.37);
border-radius: 24px; border-radius: 24px;
} }
::-webkit-scrollbar-thumb:active { ::-webkit-scrollbar-thumb:active {
box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.54); box-shadow: inset 0 0 0 24px rgba(0, 0, 0, 0.54);
border-radius: 24px; border-radius: 24px;
}
} }

View File

@ -1,4 +1,5 @@
.ps { .ps {
position: relative;
> .ps__scrollbar-y-rail { > .ps__scrollbar-y-rail {
z-index: 99999; z-index: 99999;

View File

@ -30,7 +30,7 @@ export class FuseConfigService
colorClasses : { colorClasses : {
toolbar: 'md-white-500-bg', toolbar: 'md-white-500-bg',
navbar : 'md-fuse-dark-500-bg', navbar : 'md-fuse-dark-500-bg',
footer : 'md-fuse-dark-800-bg' footer : 'md-fuse-dark-700-bg'
}, },
customScrollbars: true, customScrollbars: true,
routerAnimation : 'fadeIn' routerAnimation : 'fadeIn'

View File

@ -1,6 +1,6 @@
import { Component, HostBinding, OnInit, OnDestroy } from '@angular/core'; import { Component, HostBinding, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Animations } from '../../core/animations'; import { fuseAnimations } from '../../core/animations';
import { FuseConfigService } from '../../core/services/config.service'; import { FuseConfigService } from '../../core/services/config.service';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/filter';
@ -10,13 +10,7 @@ import 'rxjs/add/operator/map';
selector : 'fuse-content', selector : 'fuse-content',
templateUrl: './content.component.html', templateUrl: './content.component.html',
styleUrls : ['./content.component.scss'], styleUrls : ['./content.component.scss'],
animations : [ animations : fuseAnimations
Animations.routerTransitionUp,
Animations.routerTransitionDown,
Animations.routerTransitionRight,
Animations.routerTransitionLeft,
Animations.routerTransitionFade
]
}) })
export class FuseContentComponent implements OnInit, OnDestroy export class FuseContentComponent implements OnInit, OnDestroy
{ {

View File

@ -1,4 +1,4 @@
<div class="page-layout blank p-24" perfect-scrollbar> <div class="page-layout blank p-24" fusePerfectScrollbar>
<h2>Sample Page</h2> <h2>Sample Page</h2>

View File

@ -1,14 +1,20 @@
<md-toolbar> <md-toolbar>
<div fxLayout="row" fxLayoutAlign="center center" fxFlex> <div fxLayout="row" fxLayoutAlign="center center" fxLayoutAlign.gt-xs="space-between center" fxFlex>
<a href="http://themeforest.net/item/fuse-angularjs-material-design-admin-template/12931855?ref=srcn" <a href="http://themeforest.net/item/fuse-angularjs-material-design-admin-template/12931855?ref=srcn"
target="_blank" md-button class="ml-8 ml-sm-24 md-accent-800-bg" fxFlex="0 0 auto" fxLayout="row" target="_blank" md-button class="md-pink-bg" fxFlex="0 0 auto" fxLayout="row"
fxLayoutAlign="start center"> fxLayoutAlign="start center">
<md-icon class="s-16 mr-sm-4">shopping_cart</md-icon> <md-icon class="s-16 mr-sm-4">shopping_cart</md-icon>
<span>Purchase Fuse template (Angular4+)</span> <span>Purchase FUSE (Angular4+)</span>
</a> </a>
<div fxLayout="row" fxLayoutAlign="start center" fxHide fxShow.gt-xs>
<a md-button href="http://fuse-angular-material-docs.withinpixels.com/" target="_blank">Documentation</a>
<span>&bull;</span>
<a md-button href="http://withinpixels.com/themes/fuse/changelog" target="_blank">Changelog</a>
</div>
</div> </div>
</md-toolbar> </md-toolbar>

View File

@ -12,19 +12,6 @@ fuse-main {
@include mat-elevation(8); @include mat-elevation(8);
} }
&.disable-perfect-scrollbar {
.ps {
-webkit-overflow-scrolling: touch !important;
overflow: auto !important;
}
.ps__scrollbar-x-rail,
.ps__scrollbar-y-rail {
display: none !important;
}
}
> .mat-sidenav-container { > .mat-sidenav-container {
display: flex; display: flex;
flex: 1; flex: 1;

View File

@ -1,6 +1,8 @@
import { Component, ElementRef, HostBinding, OnDestroy, OnInit, Renderer2, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, HostBinding, Inject, OnDestroy, OnInit, Renderer2, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { FuseConfigService } from '../core/services/config.service'; import { FuseConfigService } from '../core/services/config.service';
import { Platform } from '@angular/cdk/platform';
import { DOCUMENT } from '@angular/common';
@Component({ @Component({
selector : 'fuse-main', selector : 'fuse-main',
@ -12,13 +14,14 @@ export class FuseMainComponent implements OnInit, OnDestroy
{ {
onSettingsChanged: Subscription; onSettingsChanged: Subscription;
fuseSettings: any; fuseSettings: any;
@HostBinding('class.disable-perfect-scrollbar') disableCustomScrollbars;
@HostBinding('class.boxed') boxed; @HostBinding('class.boxed') boxed;
constructor( constructor(
private _renderer: Renderer2, private _renderer: Renderer2,
private _elementRef: ElementRef, private _elementRef: ElementRef,
private fuseConfig: FuseConfigService private fuseConfig: FuseConfigService,
private platform: Platform,
@Inject(DOCUMENT) private document: any
) )
{ {
this.onSettingsChanged = this.onSettingsChanged =
@ -26,10 +29,14 @@ export class FuseMainComponent implements OnInit, OnDestroy
.subscribe( .subscribe(
(newSettings) => { (newSettings) => {
this.fuseSettings = newSettings; this.fuseSettings = newSettings;
this.disableCustomScrollbars = !this.fuseSettings.customScrollbars;
this.boxed = this.fuseSettings.layout.mode === 'boxed'; this.boxed = this.fuseSettings.layout.mode === 'boxed';
} }
); );
if ( this.platform.ANDROID || this.platform.IOS )
{
this.document.body.className += ' is-mobile';
}
} }
ngOnInit() ngOnInit()

View File

@ -1,137 +1 @@
@import "../../../core/scss/fuse";
fuse-main {
&.fuse-nav-bar-folded {
.content-wrapper {
&:last-child {
padding-left: 64px !important;
}
&:first-child {
padding-right: 64px !important;
}
&:first-child:last-child {
padding-left: 0 !important;
padding-right: 0 !important;
}
}
}
}
fuse-navbar-vertical {
display: flex;
flex-direction: column;
width: 256px;
min-width: 256px;
max-width: 256px;
background-color: #FFFFFF;
overflow-y: auto;
overflow-x: hidden;
z-index: 3;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
transition: all .3s cubic-bezier(.55, 0, .55, .2), width .1s linear, min-width .1s linear, max-width .1s linear;
transform: translateX(0);
&.folded {
position: absolute;
top: 0;
bottom: 0;
&.left-navbar {
left: 0;
}
&.right-navbar {
right: 0;
}
&:not(.folded-open) {
width: 64px;
min-width: 64px;
max-width: 64px;
.navbar-header {
padding: 0 16px 0 16px;
}
}
&.folded-open {
}
}
&.close {
&.left-navbar {
transform: translateX(-100%) !important;
}
&.right-navbar {
transform: translateX(100%) !important;
}
box-shadow: none;
}
@include media-breakpoint('lt-lg') {
position: absolute;
top: 0;
bottom: 0;
&.left-navbar {
left: 0;
}
&.right-navbar {
right: 0;
}
&:not(.initialized) {
&.left-navbar {
transform: translateX(-100%);
}
&.right-navbar {
transform: translateX(100%);
}
}
}
.navbar-header {
padding: 0 16px 0 24px;
display: flex;
align-items: center;
height: 64px;
min-height: 64px;
justify-content: space-between;
transition: padding 200ms ease;
background-color: rgba(255, 255, 255, .05);
@include mat-elevation(1);
.logo {
display: flex;
align-items: center;
.logo-icon {
display: block;
background: #039BE5;
width: 32px;
min-width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 16px;
font-weight: 500;
color: #FFF;
border-radius: 2px;
}
.logo-text {
margin-left: 16px;
font-size: 16px;
}
}
}
.nav-bar-content {
flex: 1;
}
}

View File

@ -1,7 +1,7 @@
<div class="navbar-header"> <div class="navbar-header">
<div class="logo"> <div class="logo">
<span class="logo-icon">F</span> <img class="logo-icon" src="assets/images/logos/fuse.svg">
<span class="logo-text">FUSE</span> <span class="logo-text">FUSE</span>
</div> </div>
@ -15,6 +15,6 @@
</div> </div>
<div class="navbar-content" perfect-scrollbar> <div class="navbar-content" fusePerfectScrollbar>
<fuse-navigation layout="vertical"></fuse-navigation> <fuse-navigation layout="vertical"></fuse-navigation>
</div> </div>

View File

@ -32,7 +32,7 @@ fuse-navbar-vertical {
background-color: #FFFFFF; background-color: #FFFFFF;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
z-index: 3; z-index: 4;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12); box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
transition: all .3s cubic-bezier(.55, 0, .55, .2), width .1s linear, min-width .1s linear, max-width .1s linear; transition: all .3s cubic-bezier(.55, 0, .55, .2), width .1s linear, min-width .1s linear, max-width .1s linear;
transform: translateX(0); transform: translateX(0);
@ -45,6 +45,7 @@ fuse-navbar-vertical {
&.left-navbar { &.left-navbar {
left: 0; left: 0;
} }
&.right-navbar { &.right-navbar {
right: 0; right: 0;
} }
@ -55,40 +56,50 @@ fuse-navbar-vertical {
max-width: 64px; max-width: 64px;
.navbar-header { .navbar-header {
padding: 0 16px 0 16px; padding: 0 13px;
.logo {
.logo-text {
opacity: 0;
transition: opacity 200ms ease;
}
} }
} }
&.folded-open {
} }
} }
&.close { &.close {
box-shadow: none;
&.left-navbar { &.left-navbar {
transform: translateX(-100%) !important; transform: translateX(-100%) !important;
} }
&.right-navbar { &.right-navbar {
transform: translateX(100%) !important; transform: translateX(100%) !important;
} }
box-shadow: none;
} }
@include media-breakpoint('lt-lg') { @include media-breakpoint('lt-lg') {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
&.left-navbar { &.left-navbar {
left: 0; left: 0;
} }
&.right-navbar { &.right-navbar {
right: 0; right: 0;
} }
&:not(.initialized) { &:not(.initialized) {
&.left-navbar { &.left-navbar {
transform: translateX(-100%); transform: translateX(-100%);
} }
&.right-navbar { &.right-navbar {
transform: translateX(100%); transform: translateX(100%);
} }
@ -111,22 +122,14 @@ fuse-navbar-vertical {
align-items: center; align-items: center;
.logo-icon { .logo-icon {
display: block; width: 38px;
background: #039BE5;
width: 32px;
min-width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 16px;
font-weight: 500;
color: #FFF;
border-radius: 2px;
} }
.logo-text { .logo-text {
margin-left: 16px; margin-left: 8px;
font-size: 16px; font-size: 20px;
font-weight: 300;
letter-spacing: 0.4px;
} }
} }
} }
@ -135,3 +138,14 @@ fuse-navbar-vertical {
flex: 1; flex: 1;
} }
} }
.fuse-navbar-backdrop {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 3;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
}

View File

@ -1,12 +1,13 @@
import { Component, HostBinding, HostListener, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, HostBinding, HostListener, Input, OnDestroy, OnInit, Renderer2, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { FuseMatchMedia } from '../../../core/services/match-media.service'; import { FuseMatchMedia } from '../../../core/services/match-media.service';
import { FuseNavbarVerticalService } from './navbar-vertical.service'; import { FuseNavbarVerticalService } from './navbar-vertical.service';
import { ObservableMedia } from '@angular/flex-layout'; import { ObservableMedia } from '@angular/flex-layout';
import { FuseMainComponent } from '../../main.component'; import { FuseMainComponent } from '../../main.component';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
import { FuseNavigationService } from '../../../core/components/navigation/navigation.service'; import { FuseNavigationService } from '../../../core/components/navigation/navigation.service';
import { FusePerfectScrollbarDirective } from '../../../core/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
@Component({ @Component({
selector : 'fuse-navbar-vertical', selector : 'fuse-navbar-vertical',
@ -16,22 +17,28 @@ import { FuseNavigationService } from '../../../core/components/navigation/navig
}) })
export class FuseNavbarVerticalComponent implements OnInit, OnDestroy export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
{ {
private _backdropElement: HTMLElement | null = null;
@HostBinding('class.close') isClosed: boolean; @HostBinding('class.close') isClosed: boolean;
@HostBinding('class.folded') isFoldedActive: boolean; @HostBinding('class.folded') isFoldedActive: boolean;
@HostBinding('class.folded-open') isFoldedOpen: boolean; @HostBinding('class.folded-open') isFoldedOpen: boolean;
@HostBinding('class.initialized') initialized: boolean; @HostBinding('class.initialized') initialized: boolean;
@Input('folded') foldedByDefault = false; @Input('folded') foldedByDefault = false;
@ViewChild(PerfectScrollbarDirective) perfectScrollbarDirective; @ViewChild(FusePerfectScrollbarDirective) fusePerfectScrollbarDirective;
matchMediaWatcher: Subscription; matchMediaWatcher: Subscription;
player: AnimationPlayer;
constructor( constructor(
private fuseMainComponentEl: FuseMainComponent, private fuseMainComponent: FuseMainComponent,
private fuseMatchMedia: FuseMatchMedia, private fuseMatchMedia: FuseMatchMedia,
private fuseNavigationService: FuseNavigationService, private fuseNavigationService: FuseNavigationService,
private navBarService: FuseNavbarVerticalService, private navBarService: FuseNavbarVerticalService,
public media: ObservableMedia, public media: ObservableMedia,
private router: Router private router: Router,
private _renderer: Renderer2,
private _elementRef: ElementRef,
private animationBuilder: AnimationBuilder
) )
{ {
navBarService.setNavBar(this); navBarService.setNavBar(this);
@ -39,7 +46,7 @@ export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
this.fuseNavigationService.onNavCollapseToggled.subscribe(() => { this.fuseNavigationService.onNavCollapseToggled.subscribe(() => {
setTimeout(() => { setTimeout(() => {
this.perfectScrollbarDirective.update(); this.fusePerfectScrollbarDirective.update();
}, 310); }, 310);
}); });
@ -56,6 +63,7 @@ export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
else else
{ {
this.openBar(); this.openBar();
this._detachBackdrop();
} }
}); });
}); });
@ -109,12 +117,17 @@ export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
{ {
this.isClosed = false; this.isClosed = false;
this.updateCssClasses(); this.updateCssClasses();
if ( this.media.isActive('lt-lg') )
{
this._attachBackdrop();
}
} }
closeBar() closeBar()
{ {
this.isClosed = true; this.isClosed = true;
this.updateCssClasses(); this.updateCssClasses();
this._detachBackdrop();
} }
toggleBar() toggleBar()
@ -144,14 +157,14 @@ export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
activateFolded() activateFolded()
{ {
this.isFoldedActive = true; this.isFoldedActive = true;
this.fuseMainComponentEl.addClass('fuse-nav-bar-folded'); this.fuseMainComponent.addClass('fuse-nav-bar-folded');
this.isFoldedOpen = false; this.isFoldedOpen = false;
} }
deActivateFolded() deActivateFolded()
{ {
this.isFoldedActive = false; this.isFoldedActive = false;
this.fuseMainComponentEl.removeClass('fuse-nav-bar-folded'); this.fuseMainComponent.removeClass('fuse-nav-bar-folded');
this.isFoldedOpen = false; this.isFoldedOpen = false;
} }
@ -171,13 +184,56 @@ export class FuseNavbarVerticalComponent implements OnInit, OnDestroy
{ {
if ( this.isClosed ) if ( this.isClosed )
{ {
this.fuseMainComponentEl.addClass('fuse-nav-bar-opened'); this.fuseMainComponent.addClass('fuse-nav-bar-opened');
this.fuseMainComponentEl.removeClass('fuse-nav-bar-closed'); this.fuseMainComponent.removeClass('fuse-nav-bar-closed');
} }
else else
{ {
this.fuseMainComponentEl.addClass('fuse-nav-bar-closed'); this.fuseMainComponent.addClass('fuse-nav-bar-closed');
this.fuseMainComponentEl.removeClass('fuse-nav-bar-opened'); this.fuseMainComponent.removeClass('fuse-nav-bar-opened');
}
}
private _attachBackdrop()
{
this._backdropElement = this._renderer.createElement('div');
this._backdropElement.classList.add('fuse-navbar-backdrop');
this._renderer.appendChild(this._elementRef.nativeElement.parentElement, this._backdropElement);
this.player =
this.animationBuilder
.build([
animate('400ms ease', style({opacity: 1}))
]).create(this._backdropElement);
this.player.play();
this._backdropElement.addEventListener('click', () => {
this.closeBar();
}
);
}
private _detachBackdrop()
{
if ( this._backdropElement )
{
this.player =
this.animationBuilder
.build([
animate('400ms cubic-bezier(.25,.8,.25,1)', style({opacity: 0}))
]).create(this._backdropElement);
this.player.play();
this.player.onDone(() => {
if ( this._backdropElement )
{
this._backdropElement.parentNode.removeChild(this._backdropElement);
this._backdropElement = null;
}
});
} }
} }

View File

@ -1,6 +1,6 @@
<md-list class="date"> <md-list class="date" cdk-focus-region-start>
<h3 md-subheader> <h3 md-subheader cdk-focus-init>
<span>Today</span> <span>Today</span>
</h3> </h3>
@ -16,7 +16,7 @@
</div> </div>
</md-list> </md-list>
<md-divider></md-divider> <md-divider cdk-focus-region-end></md-divider>
<md-list> <md-list>
<h3 md-subheader> <h3 md-subheader>
@ -24,19 +24,22 @@
</h3> </h3>
<md-list-item> <md-list-item>
<md-slide-toggle fxFlex class="mat-primary" [(ngModel)]="settings.notify" aria-label="Notifications" labelPosition="before"> <md-slide-toggle fxFlex class="mat-primary" [(ngModel)]="settings.notify" aria-label="Notifications"
labelPosition="before">
<h3>Notifications</h3> <h3>Notifications</h3>
</md-slide-toggle> </md-slide-toggle>
</md-list-item> </md-list-item>
<md-list-item> <md-list-item>
<md-slide-toggle fxFlex class="mat-accent" [(ngModel)]="settings.cloud" aria-label="Cloud" labelPosition="before"> <md-slide-toggle fxFlex class="mat-accent" [(ngModel)]="settings.cloud" aria-label="Cloud"
labelPosition="before">
<h3>Cloud Sync</h3> <h3>Cloud Sync</h3>
</md-slide-toggle> </md-slide-toggle>
</md-list-item> </md-list-item>
<md-list-item> <md-list-item>
<md-slide-toggle fxFlex class="mat-warn" [(ngModel)]="settings.retro" aria-label="Retro Thrusters" labelPosition="before"> <md-slide-toggle fxFlex class="mat-warn" [(ngModel)]="settings.retro" aria-label="Retro Thrusters"
labelPosition="before">
<h3>Retro Thrusters</h3> <h3>Retro Thrusters</h3>
</md-slide-toggle> </md-slide-toggle>
</md-list-item> </md-list-item>

View File

@ -13,7 +13,7 @@
<div fxLayout="row" fxLayoutAlign="start center" *ngIf="horizontalNav"> <div fxLayout="row" fxLayoutAlign="start center" *ngIf="horizontalNav">
<div class="logo ml-16"> <div class="logo ml-16">
<span class="logo-icon">F</span> <img class="logo-icon" src="assets/images/logos/fuse.svg">
</div> </div>
</div> </div>

View File

@ -20,22 +20,7 @@
align-items: center; align-items: center;
.logo-icon { .logo-icon {
display: block; width: 38px;
background: #039BE5;
width: 32px;
min-width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
font-size: 16px;
font-weight: 500;
color: #FFF;
border-radius: 2px;
}
.logo-text {
margin-left: 16px;
font-size: 16px;
} }
} }

View File

@ -1,33 +1,13 @@
export class FuseNavigation export class NavigationModel
{ {
public verticalNavItems: any[]; public model: any[];
public horizontalNavItems: any[];
constructor() constructor()
{ {
this.verticalNavItems = [ this.model = [
{ {
'title': 'APPS', 'title': 'Applications',
'type' : 'subheader' 'type' : 'group',
},
{
'title': 'Sample',
'type' : 'nav-item',
'icon' : 'email',
'url' : '/sample',
'badge': {
'title': 25,
'bg' : '#F44336',
'fg' : '#FFFFFF'
}
}
];
this.horizontalNavItems = [
{
'title' : 'Apps',
'icon' : 'apps',
'type' : 'nav-collapse',
'children': [ 'children': [
{ {
'title': 'Sample', 'title': 'Sample',

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -0,0 +1,4 @@
export const environment = {
production: false,
hmr: true
};

View File

@ -1,3 +1,4 @@
export const environment = { export const environment = {
production: true production: true,
hmr: false
}; };

View File

@ -4,5 +4,6 @@
// The list of which env maps to which file can be found in `.angular-cli.json`. // The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = { export const environment = {
production: false production: false,
hmr: false
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

15
src/hmr.ts Normal file
View File

@ -0,0 +1,15 @@
import { NgModuleRef, ApplicationRef } from '@angular/core';
import { createNewHosts } from '@angularclass/hmr';
export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {
let ngModule: NgModuleRef<any>;
module.hot.accept();
bootstrap().then(mod => ngModule = mod);
module.hot.dispose(() => {
const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
const elements = appRef.components.map(c => c.location.nativeElement);
const makeVisible = createNewHosts(elements);
ngModule.destroy();
makeVisible();
});
};

View File

@ -10,7 +10,7 @@
<meta name="description" content="Material design admin template with pre-built apps and pages"> <meta name="description" content="Material design admin template with pre-built apps and pages">
<meta name="keywords" content="HTML,CSS,AngularJS,Angular,Angular 4,Angular 5,Angular 6, Material"> <meta name="keywords" content="HTML,CSS,AngularJS,Angular,Angular 4,Angular 5,Angular 6, Material">
<meta name="author" content="Withinpixels"> <meta name="author" content="Withinpixels">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
@ -40,17 +40,12 @@
} }
#fuse-splash-screen .logo { #fuse-splash-screen .logo {
width: 96px; width: 128px;
height: 96px;
line-height: 96px;
margin: 0 auto; margin: 0 auto;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif; }
font-size: 56px;
text-align: center; #fuse-splash-screen .logo img {
border-radius: 2px; filter: drop-shadow(0px 10px 6px rgba(0, 0, 0, 0.2))
background-color: #039BE5;
color: #FFFFFF;
box-shadow: 0 2px 14px 0 rgba(0, 0, 0, 0.22);
} }
#fuse-splash-screen .spinner-wrapper { #fuse-splash-screen .spinner-wrapper {
@ -194,7 +189,7 @@
<div class="center"> <div class="center">
<div class="logo"> <div class="logo">
<span>F</span> <img width="128" src="assets/images/logos/fuse.svg">
</div> </div>
<!-- Material Design Spinner --> <!-- Material Design Spinner -->

View File

@ -3,10 +3,28 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module'; import { AppModule } from './app/app.module';
import { environment } from './environments/environment'; import { environment } from './environments/environment';
import { hmrBootstrap } from './hmr';
if ( environment.production ) if ( environment.production )
{ {
enableProdMode(); enableProdMode();
} }
platformBrowserDynamic().bootstrapModule(AppModule); const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);
if ( environment.hmr )
{
if ( module['hot'] )
{
hmrBootstrap(module, bootstrap);
}
else
{
console.error('HMR is not enabled for webpack-dev-server!');
console.log('Are you using the --hmr flag for ng serve?');
}
}
else
{
bootstrap();
}