custom content animation (#240)

This commit is contained in:
Cilibiu Bogdan
2018-03-17 08:01:08 +00:00
committed by Denys Vuika
parent 4eed0e9eb2
commit 50d6147e81
4 changed files with 47 additions and 26 deletions
+7 -1
View File
@@ -25,8 +25,14 @@
import { trigger, transition, animate, style, state } from '@angular/animations'; import { trigger, transition, animate, style, state } from '@angular/animations';
export const miniSidenavAnimation = trigger('miniSidenavAnimation', [ export const sidenavAnimation = trigger('sidenavAnimation', [
state('expanded', style({ width: '{{ width }}px' }), { params : { width: 0 } }), state('expanded', style({ width: '{{ width }}px' }), { params : { width: 0 } }),
state('compact', style({ width: '{{ width }}px' }), { params : { width: 0 } }), state('compact', style({ width: '{{ width }}px' }), { params : { width: 0 } }),
transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')) transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)'))
]); ]);
export const contentAnimation = trigger('contentAnimation', [
state('expanded', style({ 'margin-left': '{{ marginLeft }}px' }), { params : { marginLeft: 0 } }),
state('compact', style({'margin-left': '{{ marginLeft }}px' }), { params : { marginLeft: 0 } }),
transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
]);
@@ -1,13 +1,13 @@
<mat-sidenav-container> <mat-sidenav-container>
<mat-sidenav <mat-sidenav
[ngClass]="{ 'sidenav--hide': hideSidenav }" [ngClass]="{ 'sidenav--hidden': hideSidenav }"
[@miniSidenavAnimation]="sidenavAnimationState" [@sidenavAnimation]="sidenavAnimationState"
[opened]="!mobileQuery.matches" [opened]="!mobileQuery.matches"
[mode]="mobileQuery.matches ? 'over' : 'side'"> [mode]="mobileQuery.matches ? 'over' : 'side'">
<ng-content sidenav select="[app-layout-navigation]"></ng-content> <ng-content sidenav select="[app-layout-navigation]"></ng-content>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content [style.marginLeft.px]="sidenavAnimationState.params.width"> <mat-sidenav-content [@contentAnimation]="contentAnimationState">
<ng-content select="[app-layout-content]"></ng-content> <ng-content select="[app-layout-content]"></ng-content>
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container> </mat-sidenav-container>
@@ -1,9 +1,3 @@
@mixin transition($property) {
transition-property: $property !important;
transition-duration: 0.4s !important;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
}
:host { :host {
display: block; display: block;
width: 100%; width: 100%;
@@ -18,8 +12,11 @@ ng-content {
overflow: hidden; overflow: hidden;
} }
.sidenav--hide { .sidenav--hidden {
visibility: hidden !important; visibility: hidden !important;
width: 0 !important;
transform: unset !important;
opacity: 0 !important;
} }
.mat-sidenav-container { .mat-sidenav-container {
@@ -33,10 +30,10 @@ ng-content {
overflow: hidden; overflow: hidden;
} }
.mat-sidenav-content { .mat-sidenav-content,
@include transition('margin-left');
}
.mat-drawer-transition .mat-drawer-content { .mat-drawer-transition .mat-drawer-content {
@include transition('margin-left'); transform: unset !important;
transition-property: unset !important;
transition-duration: unset !important;
transition-timing-function: unset !important;
} }
@@ -26,14 +26,13 @@
import { Component, Input, ViewChild, OnInit, OnDestroy } from '@angular/core'; import { Component, Input, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { MatSidenav } from '@angular/material'; import { MatSidenav } from '@angular/material';
import {MediaMatcher} from '@angular/cdk/layout'; import {MediaMatcher} from '@angular/cdk/layout';
import { sidenavAnimation, contentAnimation } from './animations';
import { miniSidenavAnimation } from './animations';
@Component({ @Component({
selector: 'app-layout-container', selector: 'app-layout-container',
templateUrl: './layout-container.component.html', templateUrl: './layout-container.component.html',
styleUrls: ['./layout-container.component.scss'], styleUrls: ['./layout-container.component.scss'],
animations: [ miniSidenavAnimation ] animations: [ sidenavAnimation, contentAnimation ]
}) })
export class LayoutContainerComponent implements OnInit, OnDestroy { export class LayoutContainerComponent implements OnInit, OnDestroy {
static STEP_OVER = 600; static STEP_OVER = 600;
@@ -46,6 +45,7 @@ export class LayoutContainerComponent implements OnInit, OnDestroy {
@ViewChild(MatSidenav) sidenav: MatSidenav; @ViewChild(MatSidenav) sidenav: MatSidenav;
sidenavAnimationState: any; sidenavAnimationState: any;
contentAnimationState: any;
isMenuMinimized = false; isMenuMinimized = false;
mobileQuery: MediaQueryList; mobileQuery: MediaQueryList;
@@ -55,9 +55,11 @@ export class LayoutContainerComponent implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
const stepOver = this.stepOver || LayoutContainerComponent.STEP_OVER; const stepOver = this.stepOver || LayoutContainerComponent.STEP_OVER;
this.mobileQuery = this.mediaMatcher.matchMedia(`(max-width: ${stepOver}px)`); this.mobileQuery = this.mediaMatcher.matchMedia(`(max-width: ${stepOver}px)`);
this.mobileQuery.addListener(this.mobileQueryListener); this.mobileQuery.addListener(this.mobileQueryListener);
this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } }; this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } };
this.contentAnimationState = { value: 'compact', params: {marginLeft: this.sidenavMax } };
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@@ -65,23 +67,39 @@ export class LayoutContainerComponent implements OnInit, OnDestroy {
} }
toggleMenu(): void { toggleMenu(): void {
if (!this.mobileQuery.matches) { if (!this.mobileQuery.matches) {
this.isMenuMinimized = !this.isMenuMinimized; this.isMenuMinimized = !this.isMenuMinimized;
this.sidenavAnimationState = this.sidenavAnimation();
this.sidenavAnimationState = this.contentAnimationState = this.contentAnimation();
this.sidenavAnimationState.value === 'expanded'
? { value: 'compact', params: {width: this.sidenavMin } }
: { value: 'expanded', params: { width: this.sidenavMax } };
} else { } else {
this.isMenuMinimized = false; this.isMenuMinimized = false;
this.sidenav.toggle(); this.sidenav.toggle();
} }
} }
sidenavAnimation() {
return this.sidenavAnimationState.value === 'expanded'
? { value: 'compact', params: {width: this.sidenavMin } }
: { value: 'expanded', params: { width: this.sidenavMax } };
}
contentAnimation() {
if (this.mobileQuery.matches) {
return { value: 'expanded', params: { marginLeft: 0 } };
}
if (this.sidenavAnimationState.value === 'expanded') {
return { value: 'compact', params: { marginLeft: this.sidenavMax } };
}
if (this.sidenavAnimationState.value === 'compact') {
return { value: 'expanded', params: { marginLeft: this.sidenavMin } };
}
}
private mobileQueryListener() { private mobileQueryListener() {
this.isMenuMinimized = false; this.isMenuMinimized = false;
this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } }; this.sidenavAnimationState = { value: 'expanded', params: { width: this.sidenavMax } };
this.contentAnimationState = this.contentAnimation();
} }
} }