Methods
|
isSelected
|
isSelected(index: number)
|
|
|
Parameters :
| Name |
Type |
Optional |
| index |
number
|
No
|
|
|
onTabKeydown
|
onTabKeydown(event: KeyboardEvent, index: number)
|
|
|
Parameters :
| Name |
Type |
Optional |
| event |
KeyboardEvent
|
No
|
| index |
number
|
No
|
|
|
panelId
|
panelId(index: number)
|
|
|
Parameters :
| Name |
Type |
Optional |
| index |
number
|
No
|
|
|
selectTab
|
selectTab(index: number)
|
|
|
Parameters :
| Name |
Type |
Optional |
| index |
number
|
No
|
|
|
tabId
|
tabId(index: number)
|
|
|
Parameters :
| Name |
Type |
Optional |
| index |
number
|
No
|
|
|
Readonly
collapseToggleLabel
|
Type : unknown
|
Default value : $localize`:@@frame.global-sidebar.toggle.collapse:Collapse global sidebar`
|
|
|
|
expanded
|
Type : unknown
|
Default value : this.sidebarService.expanded
|
|
|
|
Readonly
expandToggleLabel
|
Type : unknown
|
Default value : $localize`:@@frame.global-sidebar.toggle.expand:Expand global sidebar`
|
|
|
|
selectedIndex
|
Type : unknown
|
Default value : this.sidebarService.selectedTabIndex
|
|
|
|
selectedTab
|
Type : unknown
|
Default value : computed<GlobalSidebarTab | undefined>(
() => this.visibleTabs()[this.selectedIndex()]
)
|
|
|
|
visibleTabs
|
Type : unknown
|
Default value : this.sidebarService.visibleTabs
|
|
|
import { ChangeDetectionStrategy, Component, computed, ElementRef, inject } from '@angular/core';
import type { LocalizeFn } from '@angular/localize/init';
import { NxActionModule } from '@allianz/ng-aquila/action';
import { NxIconModule } from '@allianz/ng-aquila/icon';
import { NxPlainButtonComponent } from '@allianz/ng-aquila/button';
import { GlobalSidebarTab } from '@allianz/taly-core/schemas';
import { NxHeadlineComponent } from '@allianz/ng-aquila/headline';
import { TalyFrameGlobalSidebarService } from './global-sidebar.service';
import { AclModule } from '@allianz/taly-acl/angular';
declare let $localize: LocalizeFn;
@Component({
selector: 'frame-global-sidebar',
styleUrls: ['global-sidebar.component.scss'],
templateUrl: 'global-sidebar.component.html',
imports: [NxActionModule, NxIconModule, NxPlainButtonComponent, NxHeadlineComponent, AclModule],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class GlobalSidebarComponent {
private sidebarService = inject(TalyFrameGlobalSidebarService);
visibleTabs = this.sidebarService.visibleTabs;
selectedIndex = this.sidebarService.selectedTabIndex;
selectedTab = computed<GlobalSidebarTab | undefined>(
() => this.visibleTabs()[this.selectedIndex()]
);
expanded = this.sidebarService.expanded;
readonly collapseToggleLabel = $localize`:@@frame.global-sidebar.toggle.collapse:Collapse global sidebar`;
readonly expandToggleLabel = $localize`:@@frame.global-sidebar.toggle.expand:Expand global sidebar`;
private hostElement = inject<ElementRef<HTMLElement>>(ElementRef);
selectTab(index: number): void {
this.selectedIndex.set(index);
this.sidebarService.expanded.set(true);
}
toggle(): void {
this.sidebarService.expanded.update((value) => !value);
}
isSelected(index: number): boolean {
return this.selectedIndex() === index;
}
tabId(index: number): string {
return `taly-frame-global-sidebar-tab-${index}`;
}
panelId(index: number): string {
return `taly-frame-global-sidebar-panel-${index}`;
}
onTabKeydown(event: KeyboardEvent, index: number): void {
const tabCount = this.visibleTabs().length;
if (!tabCount) return;
let target: number | undefined;
switch (event.key) {
case 'ArrowDown':
case 'ArrowRight':
target = (index + 1) % tabCount;
break;
case 'ArrowUp':
case 'ArrowLeft':
target = (index - 1 + tabCount) % tabCount;
break;
case 'Home':
target = 0;
break;
case 'End':
target = tabCount - 1;
break;
default:
return;
}
event.preventDefault();
const targetButton = this.hostElement.nativeElement.querySelector<HTMLButtonElement>(
`#${this.tabId(target)}`
);
targetButton?.focus();
}
}
@if (visibleTabs().length) {
<div class="global-sidebar" data-testid="global-sidebar" *aclTag="'taly-frame-global-sidebar'">
<div
class="global-sidebar__tabs"
role="tablist"
aria-orientation="vertical"
aria-label="Global sidebar navigation"
i18n-aria-label="@@frame.global-sidebar.navigation.label"
>
@for (tab of visibleTabs(); track $index; let i = $index) {
<button
nxAction
type="button"
class="global-sidebar__tab"
role="tab"
[id]="tabId(i)"
[attr.aria-controls]="panelId(i)"
[attr.aria-selected]="isSelected(i)"
[attr.tabindex]="isSelected(i) ? 0 : -1"
[selected]="isSelected(i)"
[attr.aria-label]="tab.header || tab.icon"
(click)="selectTab(i)"
(keydown)="onTabKeydown($event, i)"
>
<nx-icon nxActionIcon [name]="tab.icon"></nx-icon>
</button>
}
</div>
@if (selectedTab(); as tab) {
<section
class="global-sidebar__panel"
data-testid="global-sidebar-panel"
role="tabpanel"
[attr.tabindex]="expanded() ? 0 : -1"
[id]="panelId(selectedIndex())"
[attr.aria-labelledby]="tabId(selectedIndex())"
[class.global-sidebar__panel--collapsed]="!expanded()"
>
<div class="global-sidebar__panel-inner">
@if (tab.header) {
<header class="global-sidebar__panel-header">
<h3 nxHeadline size="m" class="nx-font-weight-bold nx-margin-0">{{ tab.header }}</h3>
</header>
}
<div class="global-sidebar__panel-content">
<ng-content select="[talyGlobalSidebarContent]"></ng-content>
</div>
</div>
</section>
}
<button
nxPlainButton
type="button"
class="global-sidebar__toggle"
[attr.aria-label]="expanded() ? collapseToggleLabel : expandToggleLabel"
[attr.aria-expanded]="expanded()"
(click)="toggle()"
>
<nx-icon [name]="expanded() ? 'sidebar-right' : 'sidebar-left'"></nx-icon>
</button>
</div>
}
$global-sidebar-panel-width: 320px;
:host {
display: flex;
position: sticky;
top: var(--frame-header-height);
height: calc(100vh - var(--frame-header-height));
background-color: var(--action-background-color);
}
.global-sidebar {
display: flex;
border-left: 1px solid var(--header-border-color, #e6e6e6);
}
.global-sidebar__tabs {
padding-top: 8px;
border-right: 1px solid var(--header-border-color, #e6e6e6);
}
.global-sidebar__tab {
padding: 8px 14px !important;
margin-bottom: 0 !important;
border-radius: 0 !important;
::ng-deep {
.nx-action-icon__container {
padding-right: 0;
}
.nx-action__wrapper::before {
min-width: 0;
}
}
}
.global-sidebar__panel {
width: $global-sidebar-panel-width;
overflow: hidden;
transition: width 240ms cubic-bezier(0.4, 0, 0.2, 1), opacity 180ms ease-in-out;
}
.global-sidebar__panel-inner {
width: $global-sidebar-panel-width;
padding: 16px;
height: 100%;
overflow-y: auto;
}
.global-sidebar__panel--collapsed {
width: 0;
opacity: 0;
}
.global-sidebar__panel-header {
padding-bottom: 16px;
border-bottom: 1px solid var(--header-border-color, #e6e6e6);
}
.global-sidebar__panel-content {
padding-top: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
.global-sidebar__toggle {
position: absolute;
bottom: 14px;
left: 14px;
}
Legend
Html element with directive