From cc396e2a113b7972873624b11b2191c4c6dd3851 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Wed, 12 Sep 2018 10:02:24 +0100 Subject: [PATCH] [ADF-3512] SidenavLayoutComponent option to show the sidebar on the right (#3768) * add sidebar end start property * add demo and test * fix test * fix failing test --- .../app-layout/app-layout.component.html | 57 ++++++++++++------- .../app-layout/app-layout.component.ts | 11 ++-- .../header-data/header-data.component.html | 22 +++++-- .../header-data/header-data.component.ts | 8 ++- .../header-data/header-data.service.ts | 57 ++++++++++--------- docs/core/header.component.md | 1 + docs/core/sidenav-layout.component.md | 1 + .../components/header/header.component.html | 11 +++- .../header/header.component.spec.ts | 22 ++++++- .../components/header/header.component.ts | 3 + .../layout-container.component.html | 3 +- .../layout-container.component.ts | 32 +++++++++-- .../sidenav-layout.component.html | 21 ++++--- .../sidenav-layout.component.spec.ts | 1 + .../sidenav-layout.component.ts | 3 + lib/core/layout/helpers/animations.ts | 12 +++- 16 files changed, 186 insertions(+), 79 deletions(-) diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.html b/demo-shell/src/app/components/app-layout/app-layout.component.html index c4265b5d79..24781cda59 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.html +++ b/demo-shell/src/app/components/app-layout/app-layout.component.html @@ -1,28 +1,39 @@ - + - - + -
+ - +
-
+ - +
- - - - - + + + + + + +
@@ -31,19 +42,23 @@ - + {{link.icon}}
{{link.title | translate }}
- + exit_to_app
Logout
+
- + diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts index 62d83089d3..d519f60c10 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts @@ -34,9 +34,9 @@ export class AppLayoutComponent implements OnInit { { href: '/home', icon: 'home', title: 'APP_LAYOUT.HOME' }, { href: '/files', icon: 'folder_open', title: 'APP_LAYOUT.CONTENT_SERVICES' }, { href: '/breadcrumb', icon: 'label', title: 'APP_LAYOUT.BREADCRUMB' }, - { href: '/notifications', icon: 'alarm', title: 'APP_LAYOUT.NOTIFICATIONS'}, - { href: '/card-view', icon: 'view_headline', title: 'APP_LAYOUT.CARD_VIEW'}, - { href: '/header-data', icon: 'edit', title: 'APP_LAYOUT.HEADER_DATA'}, + { href: '/notifications', icon: 'alarm', title: 'APP_LAYOUT.NOTIFICATIONS' }, + { href: '/card-view', icon: 'view_headline', title: 'APP_LAYOUT.CARD_VIEW' }, + { href: '/header-data', icon: 'edit', title: 'APP_LAYOUT.HEADER_DATA' }, { href: '/node-selector', icon: 'attachment', title: 'APP_LAYOUT.NODE-SELECTOR' }, { href: '/task-list', icon: 'assignment', title: 'APP_LAYOUT.TASK_LIST' }, { href: '/process-list', icon: 'assignment', title: 'APP_LAYOUT.PROCESS_LIST' }, @@ -61,6 +61,8 @@ export class AppLayoutComponent implements OnInit { expandedSidenav = false; + position = 'start'; + hideSidenav = false; showMenu = true; @@ -87,6 +89,7 @@ export class AppLayoutComponent implements OnInit { this.headerService.logo.subscribe(path => this.logo = path); this.headerService.redirectUrl.subscribe(redirectUrl => this.redirectUrl = redirectUrl); this.headerService.tooltip.subscribe(tooltip => this.tooltip = tooltip); + this.headerService.position.subscribe(position => this.position = position); } constructor( @@ -104,4 +107,4 @@ export class AppLayoutComponent implements OnInit { this.userpreference.set('expandedSidenav', state); } } - } +} diff --git a/demo-shell/src/app/components/header-data/header-data.component.html b/demo-shell/src/app/components/header-data/header-data.component.html index e6978a4fe1..01a8ec6541 100644 --- a/demo-shell/src/app/components/header-data/header-data.component.html +++ b/demo-shell/src/app/components/header-data/header-data.component.html @@ -13,34 +13,46 @@ OR - +

*Choose only one value at a time: either hex code or theme color.

*press enter for submitting new hex color

- +

*press enter for submitting new title

- +

*press enter for submitting new logo

- +

*Input JSON friendly array or explicit string. E.g. ["/test", 33, "user", 11] or "/test"

*press enter for submitting new link on logo

- +

*press enter for submitting new tooltip

+ +
+ + + + Start + End + +
+ diff --git a/demo-shell/src/app/components/header-data/header-data.component.ts b/demo-shell/src/app/components/header-data/header-data.component.ts index 51feb7ea62..9a2e16604c 100644 --- a/demo-shell/src/app/components/header-data/header-data.component.ts +++ b/demo-shell/src/app/components/header-data/header-data.component.ts @@ -24,8 +24,10 @@ import { HeaderDataService } from './header-data.service'; }) export class HeaderDataComponent { checkbox = true; + position = 'start'; - constructor(private headerService: HeaderDataService) {} + constructor(private headerService: HeaderDataService) { + } hideButton() { this.headerService.hideMenuButton(); @@ -59,4 +61,8 @@ export class HeaderDataComponent { this.headerService.changeTooltip(tooltip); } } + + changePosition() { + this.headerService.changePosition(this.position); + } } diff --git a/demo-shell/src/app/components/header-data/header-data.service.ts b/demo-shell/src/app/components/header-data/header-data.service.ts index d320e15c1b..929a23355d 100644 --- a/demo-shell/src/app/components/header-data/header-data.service.ts +++ b/demo-shell/src/app/components/header-data/header-data.service.ts @@ -20,38 +20,43 @@ import { Injectable, Output, EventEmitter } from '@angular/core'; @Injectable() export class HeaderDataService { - show = true; + show = true; - @Output() hideMenu: EventEmitter = new EventEmitter(); - @Output() color: EventEmitter = new EventEmitter(); - @Output() title: EventEmitter = new EventEmitter(); - @Output() logo: EventEmitter = new EventEmitter(); - @Output() redirectUrl: EventEmitter = new EventEmitter(); - @Output() tooltip: EventEmitter = new EventEmitter(); + @Output() hideMenu: EventEmitter = new EventEmitter(); + @Output() color: EventEmitter = new EventEmitter(); + @Output() title: EventEmitter = new EventEmitter(); + @Output() logo: EventEmitter = new EventEmitter(); + @Output() redirectUrl: EventEmitter = new EventEmitter(); + @Output() tooltip: EventEmitter = new EventEmitter(); + @Output() position: EventEmitter = new EventEmitter(); - hideMenuButton() { - this.show = !this.show; - this.hideMenu.emit(this.show); - } + hideMenuButton() { + this.show = !this.show; + this.hideMenu.emit(this.show); + } - changeColor(color: string) { - this.color.emit(color); - } + changeColor(color: string) { + this.color.emit(color); + } - changeTitle(title: string) { - this.title.emit(title); + changeTitle(title: string) { + this.title.emit(title); - } + } - changeLogo(logoPath: string) { - this.logo.emit(logoPath); - } + changeLogo(logoPath: string) { + this.logo.emit(logoPath); + } - changeRedirectUrl(redirectUrl: string | any[]) { - this.redirectUrl.emit(redirectUrl); - } + changeRedirectUrl(redirectUrl: string | any[]) { + this.redirectUrl.emit(redirectUrl); + } - changeTooltip(tooltip: string) { - this.tooltip.emit(tooltip); - } + changeTooltip(tooltip: string) { + this.tooltip.emit(tooltip); + } + + changePosition(position) { + this.position.emit(position); + } } diff --git a/docs/core/header.component.md b/docs/core/header.component.md index cfe63247fe..fcf6898f4f 100644 --- a/docs/core/header.component.md +++ b/docs/core/header.component.md @@ -44,6 +44,7 @@ body of the element: | tooltip | `string` | The tooltip text for the application logo. | color | `string` | Background color for the header. It can be any hex color code or the Material theme colors: 'primary', 'accent' or 'warn'. | showSidenavToggle | `boolean` | Signals if the sidenav button will be displayed in the header or not. By default is true. +| position | `string` | 'start' | The side that the drawer is attached to 'start' or 'end' page | ### Events diff --git a/docs/core/sidenav-layout.component.md b/docs/core/sidenav-layout.component.md index 69c0884b3c..a3475a22c1 100644 --- a/docs/core/sidenav-layout.component.md +++ b/docs/core/sidenav-layout.component.md @@ -73,6 +73,7 @@ sub-components (note the use of `` in the sub-components' body sect | sidenavMax | `number` | | Maximum size of the navigation region | | sidenavMin | `number` | | Minimum size of the navigation region | | stepOver | `number` | | Screen size at which display switches from small screen to large screen configuration | +| position | `string` | 'start' | The side that the drawer is attached to 'start' or 'end' page | ### Events diff --git a/lib/core/layout/components/header/header.component.html b/lib/core/layout/components/header/header.component.html index 1f45245519..373658addd 100644 --- a/lib/core/layout/components/header/header.component.html +++ b/lib/core/layout/components/header/header.component.html @@ -1,13 +1,20 @@ - - + {{title}} + + + diff --git a/lib/core/layout/components/header/header.component.spec.ts b/lib/core/layout/components/header/header.component.spec.ts index daf94bb3d0..3854d9c998 100644 --- a/lib/core/layout/components/header/header.component.spec.ts +++ b/lib/core/layout/components/header/header.component.spec.ts @@ -114,13 +114,33 @@ describe('HeaderLayoutComponent', () => { expect(button === null).toBeFalsy(); }); - it('if showSidenavToggle is false the button menu should not be displayed', () => { + it('if showSidenavToggle is false the button menu should not be displayed', () => { component.showSidenavToggle = false; fixture.detectChanges(); const button = fixture.nativeElement.querySelector('.adf-menu-icon'); expect(button === null).toBeTruthy(); }); + + it('if position is end the button menu should be at the end', () => { + component.position = 'end'; + fixture.detectChanges(); + + const buttonStart = fixture.nativeElement.querySelector('#adf-sidebar-toggle-start'); + const buttonEnd = fixture.nativeElement.querySelector('#adf-sidebar-toggle-end'); + expect(buttonStart === null).toBeTruthy(); + expect(buttonEnd === null).toBeFalsy(); + }); + + it('if position is start the button menu should be at the start', () => { + component.position = 'start'; + fixture.detectChanges(); + + const buttonStart = fixture.nativeElement.querySelector('#adf-sidebar-toggle-start'); + const buttonEnd = fixture.nativeElement.querySelector('#adf-sidebar-toggle-end'); + expect(buttonStart === null).toBeFalsy(); + expect(buttonEnd === null).toBeTruthy(); + }); }); describe('Template tranclusion', () => { diff --git a/lib/core/layout/components/header/header.component.ts b/lib/core/layout/components/header/header.component.ts index 32a9bd44c1..027e57aaf8 100644 --- a/lib/core/layout/components/header/header.component.ts +++ b/lib/core/layout/components/header/header.component.ts @@ -32,6 +32,9 @@ export class HeaderLayoutComponent implements OnInit { @Input() showSidenavToggle: boolean = true; @Output() clicked = new EventEmitter(); + /** The side that the drawer is attached to 'start' | 'end' page */ + @Input() position = 'start'; + toggleMenu() { this.clicked.emit(true); } diff --git a/lib/core/layout/components/layout-container/layout-container.component.html b/lib/core/layout/components/layout-container/layout-container.component.html index 51f2f2b939..be39742072 100644 --- a/lib/core/layout/components/layout-container/layout-container.component.html +++ b/lib/core/layout/components/layout-container/layout-container.component.html @@ -1,5 +1,6 @@
-
+
diff --git a/lib/core/layout/components/layout-container/layout-container.component.ts b/lib/core/layout/components/layout-container/layout-container.component.ts index bd7f019179..75310da523 100644 --- a/lib/core/layout/components/layout-container/layout-container.component.ts +++ b/lib/core/layout/components/layout-container/layout-container.component.ts @@ -17,14 +17,14 @@ import { Component, Input, ViewChild, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'; import { MatSidenav } from '@angular/material'; -import { sidenavAnimation, contentAnimation } from '../../helpers/animations'; +import { sidenavAnimation, contentAnimationLeft, contentAnimationRight } from '../../helpers/animations'; @Component({ selector: 'adf-layout-container', templateUrl: './layout-container.component.html', styleUrls: ['./layout-container.component.scss'], encapsulation: ViewEncapsulation.None, - animations: [ sidenavAnimation, contentAnimation ] + animations: [sidenavAnimation, contentAnimationLeft, contentAnimationRight] }) export class LayoutContainerComponent implements OnInit, OnDestroy { @Input() sidenavMin: number; @@ -36,6 +36,9 @@ export class LayoutContainerComponent implements OnInit, OnDestroy { @Input() hideSidenav = false; @Input() expandedSidenav = true; + /** The side that the drawer is attached to 'start' | 'end' page */ + @Input() position = 'start'; + @ViewChild(MatSidenav) sidenav: MatSidenav; sidenavAnimationState: any; @@ -51,11 +54,11 @@ export class LayoutContainerComponent implements OnInit, OnDestroy { ngOnInit() { this.SIDENAV_STATES.MOBILE = { value: 'expanded', params: { width: this.sidenavMax } }; this.SIDENAV_STATES.EXPANDED = { value: 'expanded', params: { width: this.sidenavMax } }; - this.SIDENAV_STATES.COMPACT = { value: 'compact', params: {width: this.sidenavMin } }; + this.SIDENAV_STATES.COMPACT = { value: 'compact', params: { width: this.sidenavMin } }; - this.CONTENT_STATES.MOBILE = { value: 'expanded', params: { marginLeft: 0 } }; - this.CONTENT_STATES.EXPANDED = { value: 'expanded', params: { marginLeft: this.sidenavMin } }; - this.CONTENT_STATES.COMPACT = { value: 'compact', params: { marginLeft: this.sidenavMax } }; + this.CONTENT_STATES.MOBILE = { value: 'expanded', params: { margin: 0 } }; + this.CONTENT_STATES.EXPANDED = { value: 'expanded', params: { margin: this.sidenavMin } }; + this.CONTENT_STATES.COMPACT = { value: 'compact', params: { margin: this.sidenavMax } }; this.mediaQueryList.addListener(this.onMediaQueryChange); @@ -110,4 +113,21 @@ export class LayoutContainerComponent implements OnInit, OnDestroy { this.sidenavAnimationState = this.SIDENAV_STATES.EXPANDED; this.contentAnimationState = this.toggledContentAnimation; } + + getContentAnimationStateLeft() { + if (this.position === 'start') { + return this.contentAnimationState; + } else { + return { value: 'compact', params: { width: this.sidenavMin } }; + } + } + + getContentAnimationStateRight() { + if (this.position === 'end') { + return this.contentAnimationState; + + } else { + return { value: 'compact', params: { width: this.sidenavMin } }; + } + } } diff --git a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.html b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.html index bec4ecc281..6b9b12b95c 100644 --- a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.html +++ b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.html @@ -1,18 +1,21 @@
- + + [position]="position" + [sidenavMin]="sidenavMin" + [sidenavMax]="sidenavMax" + [mediaQueryList]="mediaQueryList" + [hideSidenav]="hideSidenav" + [expandedSidenav]="expandedSidenav" + data-automation-id="adf-layout-container" + class="layout__content"> - + diff --git a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.spec.ts b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.spec.ts index 9e6781f290..3888b5724b 100644 --- a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.spec.ts +++ b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.spec.ts @@ -38,6 +38,7 @@ import { CommonModule } from '@angular/common'; export class DummyLayoutContainerComponent { @Input() sidenavMin: number; @Input() sidenavMax: number; + @Input() position: string; @Input() mediaQueryList: MediaQueryList; @Input() hideSidenav: boolean; @Input() expandedSidenav: boolean; diff --git a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.ts b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.ts index 993f90bfe6..ce24bde0fa 100644 --- a/lib/core/layout/components/sidenav-layout/sidenav-layout.component.ts +++ b/lib/core/layout/components/sidenav-layout/sidenav-layout.component.ts @@ -31,6 +31,9 @@ export class SidenavLayoutComponent implements OnInit, AfterViewInit, OnDestroy static STEP_OVER = 600; + /** The side that the drawer is attached to 'start' | 'end' page */ + @Input() position = 'start'; + @Input() sidenavMin: number; @Input() sidenavMax: number; @Input() stepOver: number; diff --git a/lib/core/layout/helpers/animations.ts b/lib/core/layout/helpers/animations.ts index a529222be8..ca4204d7e4 100644 --- a/lib/core/layout/helpers/animations.ts +++ b/lib/core/layout/helpers/animations.ts @@ -23,8 +23,14 @@ export const sidenavAnimation: AnimationTriggerMetadata = trigger('sidenavAnimat transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')) ]); -export const contentAnimation: AnimationTriggerMetadata = trigger('contentAnimation', [ - state('expanded', style({ 'margin-left': '{{ marginLeft }}px' }), { params : { marginLeft: 0 } }), - state('compact', style({'margin-left': '{{ marginLeft }}px' }), { params : { marginLeft: 0 } }), +export const contentAnimationLeft: AnimationTriggerMetadata = trigger('contentAnimationLeft', [ + state('expanded', style({ 'margin-left': '{{ margin }}px' }), { params : { margin: 0 } }), + state('compact', style({'margin-left': '{{ margin }}px' }), { params : { margin: 0 } }), + transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) +]); + +export const contentAnimationRight: AnimationTriggerMetadata = trigger('contentAnimationRight', [ + state('expanded', style({ 'margin-right': '{{ margin }}px' }), { params : { margin: 0 } }), + state('compact', style({'margin-right': '{{ margin }}px' }), { params : { margin: 0 } }), transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) ]);