mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-18 08:20:13 +01:00
sidebar refactoring
This commit is contained in:
parent
38e1c6cfa3
commit
515684f424
4 changed files with 168 additions and 158 deletions
121
src/app/app.menu.ts
Normal file
121
src/app/app.menu.ts
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
export const menuItems = [
|
||||||
|
{
|
||||||
|
title: 'Dashboard',
|
||||||
|
component: 'Dashboard',
|
||||||
|
icon: 'ion-android-home',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
order: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'UI Features',
|
||||||
|
component: 'Ui',
|
||||||
|
icon: 'ion-android-laptop',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
order: 200,
|
||||||
|
subMenu: [
|
||||||
|
{
|
||||||
|
title: 'Typography',
|
||||||
|
component: 'Typography',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Buttons',
|
||||||
|
component: 'Buttons',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Icons',
|
||||||
|
component: 'Icons',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Grid',
|
||||||
|
component: 'Grid',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Maps',
|
||||||
|
component: 'Maps',
|
||||||
|
icon: 'ion-ios-location-outline',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
order: 300,
|
||||||
|
subMenu: [
|
||||||
|
{
|
||||||
|
title: 'Google Maps',
|
||||||
|
component: 'GoogleMaps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Leaflet Maps',
|
||||||
|
component: 'LeafletMaps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Bubble Maps',
|
||||||
|
component: 'BubbleMaps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Line Maps',
|
||||||
|
component: 'LineMaps',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Charts',
|
||||||
|
component: 'Charts',
|
||||||
|
icon: 'ion-stats-bars',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
order: 400,
|
||||||
|
subMenu: [
|
||||||
|
// {
|
||||||
|
// title: 'Chart Js',
|
||||||
|
// component: 'ChartJs',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: 'ChartistJs',
|
||||||
|
component: 'ChartistJs',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Form Elements',
|
||||||
|
component: 'Forms',
|
||||||
|
icon: 'ion-compose',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
order: 500,
|
||||||
|
subMenu: [
|
||||||
|
{
|
||||||
|
title: 'Form Inputs',
|
||||||
|
component: 'Inputs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Form Layouts',
|
||||||
|
component: 'Layouts',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Menu Level 1',
|
||||||
|
icon: 'ion-ios-more',
|
||||||
|
selected: false,
|
||||||
|
expanded: false,
|
||||||
|
subMenu: [
|
||||||
|
{
|
||||||
|
title: 'Menu Level 1.1',
|
||||||
|
disabled: true,
|
||||||
|
selected: false,
|
||||||
|
expanded: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Menu Level 1.2',
|
||||||
|
subMenu: [{
|
||||||
|
title: 'Menu Level 1.2.1',
|
||||||
|
disabled: true,
|
||||||
|
selected: false,
|
||||||
|
expanded: false
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
@ -5,9 +5,6 @@ import {AppState} from '../../../app.state';
|
||||||
import {layoutSizes} from '../../../theme';
|
import {layoutSizes} from '../../../theme';
|
||||||
import {SidebarService} from './sidebar.service';
|
import {SidebarService} from './sidebar.service';
|
||||||
|
|
||||||
// TODO: separate menu and sidebar
|
|
||||||
// TODO: move some functionality to decorators
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'sidebar',
|
selector: 'sidebar',
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
|
@ -36,15 +33,10 @@ export class Sidebar {
|
||||||
private _sidebarService:SidebarService,
|
private _sidebarService:SidebarService,
|
||||||
private _state:AppState) {
|
private _state:AppState) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.menuItems = this._sidebarService.getMenuItems();
|
this.menuItems = this._sidebarService.getMenuItems();
|
||||||
this.selectMenuItem();
|
this._router.root.subscribe((path) => this._selectMenuItem(path));
|
||||||
this._router.root.subscribe(() => this.selectMenuItem());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is it really the best event for this kind of things?
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.updateSidebarHeight();
|
this.updateSidebarHeight();
|
||||||
}
|
}
|
||||||
|
|
@ -102,28 +94,9 @@ export class Sidebar {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: there is a bug in the router thus all child routers are considered as active
|
private _selectMenuItem(currentPath = null) {
|
||||||
private selectMenuItem() {
|
|
||||||
let currentMenu;
|
|
||||||
|
|
||||||
let isCurrent = (instructions) => (instructions.filter(i => typeof i !== 'undefined').length > 0 ? this._router.isRouteActive(this._router.generate(instructions)) : false);
|
let currentMenu = this._sidebarService.selectMenuItem(this._router, this.menuItems, currentPath);
|
||||||
let assignCurrent = (menu) => (menu.selected ? currentMenu = menu : null);
|
|
||||||
|
|
||||||
this.menuItems.forEach(function (menu: any) {
|
|
||||||
|
|
||||||
menu.selected = isCurrent([menu.name]);
|
|
||||||
menu.expanded = menu.expanded || menu.selected;
|
|
||||||
assignCurrent(menu);
|
|
||||||
|
|
||||||
if (menu.subMenu) {
|
|
||||||
menu.subMenu.forEach(function (subMenu) {
|
|
||||||
subMenu.selected = isCurrent([menu.name, subMenu.name]) && !subMenu.disabled;
|
|
||||||
assignCurrent(menu);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// notifies all subscribers
|
|
||||||
this._state.notifyDataChanged('menu.activeLink', currentMenu);
|
this._state.notifyDataChanged('menu.activeLink', currentMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<aside class="al-sidebar" (mouseleave)="hoverElemTop=outOfArea">
|
<aside class="al-sidebar" (mouseleave)="hoverElemTop=outOfArea" sidebarResize>
|
||||||
<ul class="al-sidebar-list">
|
<ul class="al-sidebar-list">
|
||||||
<li *ngFor="let item of menuItems" class="al-sidebar-list-item"
|
<li *ngFor="let item of menuItems" class="al-sidebar-list-item"
|
||||||
[ngClass]="{'selected': item.selected, 'with-sub-menu': item.subMenu}">
|
[ngClass]="{'selected': item.selected, 'with-sub-menu': item.subMenu}">
|
||||||
|
|
||||||
<a *ngIf="!item.subMenu" [routerLink]="[item.name]" class="al-sidebar-list-link">
|
<a *ngIf="!item.subMenu" [routerLink]="[item.component]" class="al-sidebar-list-link">
|
||||||
<i class="{{ item.icon }}"></i><span>{{ item.title }}</span>
|
<i class="{{ item.icon }}"></i><span>{{ item.title }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
@ -27,11 +27,11 @@
|
||||||
[ngClass]="{expanded: subitem.expanded, 'slide-right': subitem.slideRight}">
|
[ngClass]="{expanded: subitem.expanded, 'slide-right': subitem.slideRight}">
|
||||||
<li *ngFor="let subSubitem of subitem.subMenu" (mouseenter)="hoverItem($event, item)"
|
<li *ngFor="let subSubitem of subitem.subMenu" (mouseenter)="hoverItem($event, item)"
|
||||||
[ngClass]="{selected: subitem.selected}">
|
[ngClass]="{selected: subitem.selected}">
|
||||||
<a (mouseenter)="hoverItem($event, item)" [routerLink]="[item.name, subitem.name, subSubitem.name]">
|
<a (mouseenter)="hoverItem($event, item)" [routerLink]="[item.component, subitem.component, subSubitem.component]">
|
||||||
{{ subSubitem.title }}</a>
|
{{ subSubitem.title }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<a *ngIf="!subitem.subMenu" [routerLink]="[item.name, subitem.name]"
|
<a *ngIf="!subitem.subMenu" [routerLink]="[item.component, subitem.component]"
|
||||||
(mouseenter)="hoverItem($event, item)" target="{{subitem.blank ? '_blank' : '_self'}}">
|
(mouseenter)="hoverItem($event, item)" target="{{subitem.blank ? '_blank' : '_self'}}">
|
||||||
{{ subitem.title}}
|
{{ subitem.title}}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -1,133 +1,49 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
import {menuItems} from '../../../app.menu';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SidebarService {
|
export class SidebarService {
|
||||||
|
|
||||||
staticMenuItems = [
|
|
||||||
{
|
|
||||||
title: 'Dashboard',
|
|
||||||
name: 'Dashboard',
|
|
||||||
icon: 'ion-android-home',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
order: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'UI Features',
|
|
||||||
name: 'Ui',
|
|
||||||
icon: 'ion-android-laptop',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
order: 200,
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
title: 'Typography',
|
|
||||||
name: 'Typography',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Buttons',
|
|
||||||
name: 'Buttons',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Icons',
|
|
||||||
name: 'Icons',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Grid',
|
|
||||||
name: 'Grid',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Maps',
|
|
||||||
name: 'Maps',
|
|
||||||
icon: 'ion-ios-location-outline',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
order: 300,
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
title: 'Google Maps',
|
|
||||||
name: 'GoogleMaps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Leaflet Maps',
|
|
||||||
name: 'LeafletMaps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Bubble Maps',
|
|
||||||
name: 'BubbleMaps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Line Maps',
|
|
||||||
name: 'LineMaps',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Charts',
|
|
||||||
name: 'Charts',
|
|
||||||
icon: 'ion-stats-bars',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
order: 400,
|
|
||||||
subMenu: [
|
|
||||||
// {
|
|
||||||
// title: 'Chart Js',
|
|
||||||
// name: 'ChartJs',
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
title: 'ChartistJs',
|
|
||||||
name: 'ChartistJs',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Form Elements',
|
|
||||||
name: 'Forms',
|
|
||||||
icon: 'ion-compose',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
order: 500,
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
title: 'Form Inputs',
|
|
||||||
name: 'Inputs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Form Layouts',
|
|
||||||
name: 'Layouts',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Menu Level 1',
|
|
||||||
icon: 'ion-ios-more',
|
|
||||||
selected: false,
|
|
||||||
expanded: false,
|
|
||||||
subMenu: [
|
|
||||||
{
|
|
||||||
title: 'Menu Level 1.1',
|
|
||||||
disabled: true,
|
|
||||||
selected: false,
|
|
||||||
expanded: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Menu Level 1.2',
|
|
||||||
subMenu: [{
|
|
||||||
title: 'Menu Level 1.2.1',
|
|
||||||
disabled: true,
|
|
||||||
selected: false,
|
|
||||||
expanded: false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
getMenuItems() {
|
getMenuItems() {
|
||||||
return this.staticMenuItems;
|
return menuItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectMenuItem(router, items:Array<any>, currentPath:string) {
|
||||||
|
let currentMenu;
|
||||||
|
|
||||||
|
let assignCurrent = (menu) => (menu.selected ? currentMenu = menu : null);
|
||||||
|
|
||||||
|
items.forEach((menu: any) => {
|
||||||
|
|
||||||
|
menu.selected = this._isCurrent(router, this._generateRoute(router, [menu.component]));
|
||||||
|
menu.expanded = menu.expanded || menu.selected;
|
||||||
|
assignCurrent(menu);
|
||||||
|
|
||||||
|
if (menu.subMenu) {
|
||||||
|
menu.subMenu.forEach((subMenu) => {
|
||||||
|
let route = this._generateRoute(router, [menu.component, subMenu.component]);
|
||||||
|
subMenu.selected = !subMenu.disabled && this._isCurrent(router, route) && this._resolvePath(route, '') == currentPath;
|
||||||
|
assignCurrent(menu);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return currentMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _isCurrent(router, route) {
|
||||||
|
return route ? router.isRouteActive(route) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _generateRoute(router, instructions) {
|
||||||
|
return instructions.filter(i => typeof i !== 'undefined').length > 0 ? router.generate(instructions) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _resolvePath(instruction, collected) {
|
||||||
|
if (instruction !== null) {
|
||||||
|
collected += instruction.urlPath + '/';
|
||||||
|
return this._resolvePath(instruction.child, collected)
|
||||||
|
} else {
|
||||||
|
return collected.slice(0, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue