mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-20] Sidenav - submenu support (#779)
* transform children data * update navigation schema for children * sidenav submenu * update style * disable extansion panel animation * child routerLinkActive template reference * getApplicationNavigation test * minimised submenu indicator * sort navigaton children
This commit is contained in:
parent
264597439b
commit
88678852e7
@ -173,7 +173,7 @@
|
||||
},
|
||||
"navBarLinkRef": {
|
||||
"type": "object",
|
||||
"required": ["id", "icon", "title", "route"],
|
||||
"required": ["id", "icon", "title"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Unique identifier",
|
||||
@ -199,6 +199,12 @@
|
||||
"description": "Element order",
|
||||
"type": "number"
|
||||
},
|
||||
"children": {
|
||||
"description": "Navigation children items",
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/navBarLinkRef" },
|
||||
"minItems": 1
|
||||
},
|
||||
"rules": {
|
||||
"description": "Element rules",
|
||||
"type": "object",
|
||||
@ -209,7 +215,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"required": ["route"],
|
||||
"not": {
|
||||
"required": ["children"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": ["children"],
|
||||
"not": {
|
||||
"required": ["route"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"navBarGroupRef": {
|
||||
"type": "object",
|
||||
|
@ -1,40 +1,148 @@
|
||||
<div class="sidenav">
|
||||
<div class="sidenav__section sidenav__section sidenav_action-menu">
|
||||
<app-create-menu [expanded]="showLabel"></app-create-menu>
|
||||
<app-create-menu [expanded]="showLabel"></app-create-menu>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let group of groups; trackBy: trackById"
|
||||
class="sidenav__section sidenav__section--menu" >
|
||||
<ul class="sidenav-menu">
|
||||
<li *ngFor="let item of group.items; trackBy: trackById"
|
||||
class="sidenav-menu__item"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
[attr.title]="item.description | translate">
|
||||
class="sidenav__section sidenav__section--menu">
|
||||
|
||||
<button
|
||||
[id]="item.id"
|
||||
mat-icon-button
|
||||
mat-ripple
|
||||
[routerLink]="item.url"
|
||||
[color]="rla.isActive ? 'accent': 'primary'"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
matRippleColor="primary"
|
||||
[matRippleTrigger]="rippleTrigger"
|
||||
[matRippleCentered]="true">
|
||||
<div class="sidenav-menu">
|
||||
<div *ngFor="let item of group.items; trackBy: trackById"
|
||||
routerLinkActive
|
||||
#routerLink="routerLinkActive">
|
||||
|
||||
<mat-icon>{{ item.icon }}</mat-icon>
|
||||
</button>
|
||||
<ng-container *ngIf="showLabel">
|
||||
<ng-container *ngIf="!item.children">
|
||||
<div class="sidenav-menu__item">
|
||||
<button [id]="item.id"
|
||||
mat-icon-button mat-ripple
|
||||
[routerLink]="item.url"
|
||||
[color]="routerLink.isActive ? 'accent': 'primary'"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
matRippleColor="primary"
|
||||
[matRippleTrigger]="rippleTrigger"
|
||||
[matRippleCentered]="true"
|
||||
[matRippleRadius]="20">
|
||||
|
||||
<span #rippleTrigger
|
||||
[routerLink]="item.url"
|
||||
class="menu__item--label"
|
||||
[hidden]="!showLabel"
|
||||
[ngClass]="{
|
||||
'menu__item--active': rla.isActive,
|
||||
'menu__item--default': !rla.isActive
|
||||
}">{{ item.title | translate }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<mat-icon>{{ item.icon }}</mat-icon>
|
||||
</button>
|
||||
|
||||
<span #rippleTrigger
|
||||
class="menu__item--label"
|
||||
[routerLink]="item.url"
|
||||
[attr.aria-label]="item.title | translate"
|
||||
[ngClass]="{
|
||||
'menu__item--active': routerLink.isActive,
|
||||
'menu__item--default': !routerLink.isActive
|
||||
}">
|
||||
{{ item.title | translate }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.children && item.children.length">
|
||||
<mat-expansion-panel [expanded]="routerLink.isActive" [@.disabled]="true">
|
||||
<mat-expansion-panel-header expandedHeight="48px" collapsedHeight="48px" [id]="item.id">
|
||||
<mat-panel-title>
|
||||
<mat-icon [color]="routerLink.isActive? 'accent': 'primary'">{{ item.icon }}</mat-icon>
|
||||
<span class="menu__item--label"
|
||||
[ngClass]="{
|
||||
'menu__item--active': routerLink.isActive,
|
||||
'menu__item--default': !routerLink.isActive
|
||||
}">
|
||||
{{ item.title | translate }}</span>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div *ngFor="let child of item.children; trackBy: trackById"
|
||||
routerLinkActive #childRouteActive="routerLinkActive"
|
||||
[attr.title]="child.description | translate">
|
||||
|
||||
<button [id]="child.id"
|
||||
mat-icon-button mat-ripple
|
||||
[routerLink]="child.url"
|
||||
[color]="childRouteActive.isActive ? 'accent': 'primary'"
|
||||
[attr.aria-label]="child.title | translate"
|
||||
matRippleColor="primary"
|
||||
[matRippleTrigger]="rippleTrigger"
|
||||
[matRippleCentered]="true"
|
||||
[matRippleRadius]="20">
|
||||
|
||||
<mat-icon>{{ child.icon }}</mat-icon>
|
||||
</button>
|
||||
|
||||
<span #rippleTrigger
|
||||
[routerLink]="child.url"
|
||||
class="menu__item--label"
|
||||
[ngClass]="{
|
||||
'menu__item--active': childRouteActive.isActive,
|
||||
'menu__item--default': !childRouteActive.isActive
|
||||
}">
|
||||
{{ child.title | translate }}</span>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!showLabel">
|
||||
<ng-container *ngIf="!item.children">
|
||||
<div class="sidenav-menu__item">
|
||||
<button [id]="item.id"
|
||||
mat-icon-button [routerLink]="item.url"
|
||||
[color]="routerLink.isActive ? 'accent': 'primary'"
|
||||
[attr.aria-label]="item.title | translate">
|
||||
|
||||
<mat-icon>{{ item.icon }}</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="item.children && item.children.length">
|
||||
<div class="sidenav-menu__item">
|
||||
<button [id]="item.id"
|
||||
color="accent"
|
||||
mat-mini-fab
|
||||
mat-icon-button
|
||||
disableRipple="true"
|
||||
matRipple
|
||||
[matRippleCentered]="true"
|
||||
matRippleColor="accent"
|
||||
[matRippleRadius]="24"
|
||||
#childMenu="matMenuTrigger"
|
||||
[matMenuTriggerFor]="menu">
|
||||
|
||||
<mat-icon
|
||||
[color]="routerLink.isActive|| childMenu.menuOpen? 'accent': 'primary'">
|
||||
{{ item.icon }}
|
||||
</mat-icon>
|
||||
|
||||
<mat-icon
|
||||
[color]="routerLink.isActive|| childMenu.menuOpen? 'accent': 'primary'">
|
||||
more_vert
|
||||
</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-menu #menu="matMenu"[overlapTrigger]="false">
|
||||
<button mat-menu-item
|
||||
*ngFor="let child of item.children; trackBy: trackById"
|
||||
routerLinkActive
|
||||
#menuRouterLink="routerLinkActive"
|
||||
[routerLink]="child.url"
|
||||
[id]="child.id">
|
||||
|
||||
<mat-icon [color]="menuRouterLink.isActive ? 'primary': null"
|
||||
[attr.color]="menuRouterLink.isActive ? 'primary': null">
|
||||
{{ child.icon }}
|
||||
</mat-icon>
|
||||
|
||||
<span class="mat-button" [ngClass]="{ 'mat-primary': menuRouterLink.isActive }">
|
||||
{{ child.title | translate }}
|
||||
</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -18,15 +18,13 @@
|
||||
|
||||
&__section {
|
||||
padding: 8px 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
&-menu__item {
|
||||
@ -48,4 +46,18 @@
|
||||
.menu__item--label:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header {
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-title span {
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,25 @@
|
||||
|
||||
background-color: mat-color($background, background);
|
||||
|
||||
.mat-expansion-panel {
|
||||
background-color: unset;
|
||||
color: mat-color($primary, 0.87) !important;
|
||||
}
|
||||
|
||||
.mat-expansion-panel {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.mat-expansion-panel:not(.mat-expanded)
|
||||
.mat-expansion-panel-header:not([aria-disabled='true']):hover {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.mat-mini-fab {
|
||||
box-shadow: unset !important;
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
.adf-sidebar-action-menu-button {
|
||||
background-color: mat-color($accent);
|
||||
}
|
||||
|
@ -618,4 +618,25 @@ describe('AppExtensionService', () => {
|
||||
expect(result[0].id).toBe('1');
|
||||
expect(result[1].id).toBe('3');
|
||||
});
|
||||
|
||||
describe('getApplicationNavigation', () => {
|
||||
it('should create navigation data', () => {
|
||||
const navigation = service.getApplicationNavigation([
|
||||
{ items: [{ route: 'route1' }, { route: 'route2' }] },
|
||||
{ items: [{ children: [{ route: 'route3' }] }] }
|
||||
]);
|
||||
|
||||
expect(navigation).toEqual([
|
||||
{
|
||||
items: [
|
||||
{ route: 'route1', url: '/route1' },
|
||||
{ route: 'route2', url: '/route2' }
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [{ children: [{ route: 'route3', url: '/route3' }] }]
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -185,11 +185,31 @@ export class AppExtensionService implements RuleContext {
|
||||
return {
|
||||
...group,
|
||||
items: (group.items || [])
|
||||
.filter(item => {
|
||||
return this.filterByRules(item);
|
||||
})
|
||||
.filter(item => this.filterByRules(item))
|
||||
.sort(sortByOrder)
|
||||
.map(item => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = item.children
|
||||
.filter(child => this.filterByRules(child))
|
||||
.sort(sortByOrder)
|
||||
.map(child => {
|
||||
const childRouteRef = this.extensions.getRouteById(
|
||||
child.route
|
||||
);
|
||||
const childUrl = `/${
|
||||
childRouteRef ? childRouteRef.path : child.route
|
||||
}`;
|
||||
return {
|
||||
...child,
|
||||
url: childUrl
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...item
|
||||
};
|
||||
}
|
||||
|
||||
const routeRef = this.extensions.getRouteById(item.route);
|
||||
const url = `/${routeRef ? routeRef.path : item.route}`;
|
||||
return {
|
||||
@ -197,6 +217,7 @@ export class AppExtensionService implements RuleContext {
|
||||
url
|
||||
};
|
||||
})
|
||||
.reduce(reduceEmptyMenus, [])
|
||||
};
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user