[Dashboard]: Reworked sidebar menu auto expanding
[src/xds/xds-agent.git] / webapp / src / app / @theme / layouts / xds / xds.layout.ts
1 import { Component, OnDestroy, EventEmitter } from '@angular/core';
2 import {
3   NbMediaBreakpoint,
4   NbMediaBreakpointsService,
5   NbMenuItem,
6   NbMenuService,
7   NbSidebarService,
8   NbThemeService,
9 } from '@nebular/theme';
10
11 import { StateService } from '../../../@core/data/state.service';
12
13 import { Subscription } from 'rxjs/Subscription';
14 import { Observable } from 'rxjs/Observable';
15 import 'rxjs/add/operator/withLatestFrom';
16 import 'rxjs/add/operator/delay';
17 import 'rxjs/add/observable/of';
18 import 'rxjs/add/operator/takeUntil';
19
20 // TODO: move layouts into the framework
21 @Component({
22   selector: 'ngx-xds-layout',
23   styleUrls: ['./xds.layout.scss'],
24   templateUrl: './xds.layout.html',
25 })
26
27 export class XdsLayoutComponent implements OnDestroy {
28
29   subMenu: NbMenuItem[] = [];
30   layout: any = {};
31   sidebar: any = {};
32   sidebarPinned = false;
33   sidebarCompact = true;
34
35   protected layoutState$: Subscription;
36   protected sidebarState$: Subscription;
37   protected menuClick$: Subscription;
38
39   private _mouseEnterStream: EventEmitter<any> = new EventEmitter();
40   private _mouseLeaveStream: EventEmitter<any> = new EventEmitter();
41
42   constructor(protected stateService: StateService,
43     protected menuService: NbMenuService,
44     protected themeService: NbThemeService,
45     protected bpService: NbMediaBreakpointsService,
46     protected sidebarService: NbSidebarService) {
47
48     this.layoutState$ = this.stateService.onLayoutState()
49       .subscribe((layout: string) => this.layout = layout);
50
51     this.sidebarState$ = this.stateService.onSidebarState()
52       .subscribe((sidebar: string) => {
53         this.sidebar = sidebar;
54       });
55
56     const isBp = this.bpService.getByName('is');
57
58     this.menuClick$ = this.menuService.onItemSelect()
59       .withLatestFrom(this.themeService.onMediaQueryChange())
60       .delay(20)
61       .subscribe(([item, [bpFrom, bpTo]]: [any, [NbMediaBreakpoint, NbMediaBreakpoint]]) => {
62         /*
63         this.sidebarCompact = false;
64         */
65         // automatically collapse sidebar for narrow screen / mobile
66         if (bpTo.width <= isBp.width) {
67           this.sidebarService.collapse('menu-sidebar');
68         }
69       });
70
71     // Set sidebarCompact according to sidebar state changes
72     this.sidebarService.onToggle().subscribe(s => {
73       if (s.tag === 'menu-sidebar') {
74         this.sidebarPinned = false;
75         this.sidebarCompact = !this.sidebarCompact;
76       }
77     });
78
79     this.sidebarService.onCollapse().subscribe(s => s.tag === 'menu-sidebar' && (this.sidebarCompact = true));
80     this.sidebarService.onExpand().subscribe(s => s.tag === 'menu-sidebar' && (this.sidebarCompact = false));
81     this.menuService.onSubmenuToggle().subscribe(i => i.item && i.item.expanded && (this.sidebarCompact = false));
82
83     // Automatically expand sidebar on mouse over
84     this._mouseEnterStream.flatMap(e => {
85       return Observable
86         .of(e)
87         .delay(100)
88         .takeUntil(this._mouseLeaveStream);
89     })
90       .subscribe(e => {
91         if (this.sidebarPinned || !this.sidebarCompact) {
92           return;
93         }
94         // this._mouseLeaveStream.emit(null);
95         this.sidebarService.toggle(false, 'menu-sidebar');
96       });
97
98     // Automatically collapse sidebar on mouse leave
99     this._mouseLeaveStream.flatMap(e => {
100       return Observable
101         .of(e)
102         .delay(100)
103         .takeUntil(this._mouseEnterStream);
104     })
105       .subscribe(e => {
106         if (this.sidebarPinned || this.sidebarCompact) {
107           return;
108         }
109         // this._mouseEnterStream.emit(null);
110         this.sidebarService.toggle(true, 'menu-sidebar');
111       });
112   }
113
114   ngOnDestroy() {
115     this.layoutState$.unsubscribe();
116     this.sidebarState$.unsubscribe();
117     this.menuClick$.unsubscribe();
118   }
119
120   onMouseEnter($event) {
121     this._mouseEnterStream.emit($event);
122   }
123
124   onMouseLeave($event) {
125     this._mouseLeaveStream.emit($event);
126   }
127
128   pinSidebar() {
129     this.sidebarPinned = !this.sidebarPinned;
130   }
131 }