libs/core/frame/src/frame-parts/global-sidebar/global-sidebar.component.ts

Metadata

Relationships

Used by

Depends on

Index

Properties
Methods

Methods

isSelected
isSelected(index: number)
Parameters :
Name Type Optional
index number No
Returns : boolean
onTabKeydown
onTabKeydown(event: KeyboardEvent, index: number)
Parameters :
Name Type Optional
event KeyboardEvent No
index number No
Returns : void
panelId
panelId(index: number)
Parameters :
Name Type Optional
index number No
Returns : string
selectTab
selectTab(index: number)
Parameters :
Name Type Optional
index number No
Returns : void
tabId
tabId(index: number)
Parameters :
Name Type Optional
index number No
Returns : string
toggle
toggle()
Returns : void

Properties

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.component.scss

$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
Component
Html element with directive

results matching ""

    No results matching ""