Nested Menus (#1554)
* added initial submenu * added submenu - needs a bit of more work * removed admin and nonadmin action split * the whole menu is build under the resetactions function * removed download from seriesAction * changed submenu layout changed submenu toggle icon fix for the hovering of submenu toggle * moved the cdMarkForCheck in the subscribe block
This commit is contained in:
parent
dec6802f88
commit
3cdf8df1db
7 changed files with 310 additions and 185 deletions
|
|
@ -130,7 +130,7 @@ export class CardDetailDrawerComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.chapterActions = this.actionFactoryService.getChapterActions(this.handleChapterActionCallback.bind(this))
|
||||
.filter(item => item.action !== Action.Edit);
|
||||
this.chapterActions.push({title: 'Read', action: Action.Read, callback: this.handleChapterActionCallback.bind(this), requiresAdmin: false});
|
||||
this.chapterActions.push({title: 'Read', action: Action.Read, callback: this.handleChapterActionCallback.bind(this), requiresAdmin: false, children: []});
|
||||
|
||||
this.libraryService.getLibraryType(this.libraryId).subscribe(type => {
|
||||
this.libraryType = type;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,22 @@
|
|||
<div ngbDropdown container="body" class="d-inline-block">
|
||||
<button [disabled]="disabled" class="btn {{btnClass}}" id="actions-{{labelBy}}" ngbDropdownToggle (click)="preventClick($event)"><i class="fa {{iconClass}}" aria-hidden="true"></i></button>
|
||||
<div ngbDropdownMenu attr.aria-labelledby="actions-{{labelBy}}">
|
||||
<button ngbDropdownItem *ngFor="let action of nonAdminActions" (click)="performAction($event, action)">{{action.title}}</button>
|
||||
<div class="dropdown-divider" *ngIf="nonAdminActions.length > 1 && adminActions.length > 1"></div>
|
||||
<button ngbDropdownItem *ngFor="let action of adminActions" (click)="performAction($event, action)">{{action.title}}</button>
|
||||
<ng-container *ngTemplateOutlet="submenu; context: { list: actions }"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<!-- IDEA: If we are not on desktop, then let's open a bottom drawer instead-->
|
||||
<ng-template #submenu let-list="list">
|
||||
<ng-container *ngFor="let action of list">
|
||||
<ng-container *ngIf="action.children === undefined || action?.children?.length === 0 else submenuDropdown">
|
||||
<button ngbDropdownItem *ngIf="willRenderAction(action)" (click)="performAction($event, action)">{{action.title}}</button>
|
||||
</ng-container>
|
||||
<ng-template #submenuDropdown>
|
||||
<div ngbDropdown #subMenuHover="ngbDropdown" placement="right" (mouseover)="preventClick($event); openSubmenu(action.title, subMenuHover)" (mouseleave)="preventClick($event)">
|
||||
<button id="actions-{{action.title}}" class="submenu-toggle" ngbDropdownToggle>{{action.title}} <i class="fa-solid fa-angle-right submenu-icon"></i></button>
|
||||
<div ngbDropdownMenu attr.aria-labelledby="actions-{{action.title}}">
|
||||
<ng-container *ngTemplateOutlet="submenu; context: { list: action.children }"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
|
@ -1,3 +1,28 @@
|
|||
.dropdown-toggle:after {
|
||||
content: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.submenu-toggle {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);
|
||||
font-weight: 400;
|
||||
text-align: inherit;
|
||||
border: 0;
|
||||
color: var(--dropdown-item-text-color);
|
||||
background-color: var(--dropdown-item-bg-color);
|
||||
&:hover {
|
||||
color: var(--dropdown-item-text-color);
|
||||
background-color: var(--dropdown-item-hover-bg-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
&:focus-visible {
|
||||
color: var(--dropdown-item-text-color);
|
||||
background-color: var(--dropdown-item-hover-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
.submenu-icon {
|
||||
float: right;
|
||||
padding: var(--bs-dropdown-item-padding-y) 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ActionItem } from 'src/app/_services/action-factory.service';
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { take } from 'rxjs';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
import { Action, ActionItem } from 'src/app/_services/action-factory.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-card-actionables',
|
||||
|
|
@ -16,16 +19,19 @@ export class CardActionablesComponent implements OnInit {
|
|||
@Input() disabled: boolean = false;
|
||||
@Output() actionHandler = new EventEmitter<ActionItem<any>>();
|
||||
|
||||
adminActions: ActionItem<any>[] = [];
|
||||
nonAdminActions: ActionItem<any>[] = [];
|
||||
isAdmin: boolean = false;
|
||||
canDownload: boolean = false;
|
||||
submenu: {[key: string]: NgbDropdown} = {};
|
||||
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef) { }
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, private accountService: AccountService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.nonAdminActions = this.actions.filter(item => !item.requiresAdmin);
|
||||
this.adminActions = this.actions.filter(item => item.requiresAdmin);
|
||||
this.cdRef.markForCheck();
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user) => {
|
||||
if (!user) return;
|
||||
this.isAdmin = this.accountService.hasAdminRole(user);
|
||||
this.canDownload = this.accountService.hasDownloadRole(user);
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
preventClick(event: any) {
|
||||
|
|
@ -41,4 +47,23 @@ export class CardActionablesComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
willRenderAction(action: ActionItem<any>): boolean {
|
||||
return (action.requiresAdmin && this.isAdmin)
|
||||
|| (action.action === Action.Download && (this.canDownload || this.isAdmin))
|
||||
|| (!action.requiresAdmin && action.action !== Action.Download)
|
||||
}
|
||||
|
||||
openSubmenu(actionTitle: string, subMenu: NgbDropdown) {
|
||||
// We keep track when we open and when we get a request to open, if we have other keys, we close them and clear their keys
|
||||
if (Object.keys(this.submenu).length > 0) {
|
||||
const keys = Object.keys(this.submenu).filter(k => k !== actionTitle);
|
||||
keys.forEach(key => {
|
||||
this.submenu[key].close();
|
||||
delete this.submenu[key];
|
||||
});
|
||||
}
|
||||
this.submenu[actionTitle] = subMenu;
|
||||
subMenu.open();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue