Files
marketplaces/src/app/features/admin/shell/admin-layout.component.html
sdarbinyan 35b1c7ed27
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
feat: wire order watcher into admin topbar bell (badge + panel)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:59:23 +04:00

191 lines
7.9 KiB
HTML

<a class="admin-layout__skip-link" href="#admin-content">{{ 'adminShell.skipToContent' | translate }}</a>
<div class="admin-layout" [class.admin-layout--drawer-open]="mobileDrawerOpen()">
@if (mobileDrawerOpen()) {
<div class="admin-layout__backdrop" (click)="closeMobileDrawer()"></div>
}
<nav
#drawer
class="admin-layout__sidebar"
[attr.aria-label]="'adminShell.sidebarLabel' | translate"
>
<a class="admin-layout__brand" [routerLink]="['/', currentLang(), 'backoffice', 'dashboard']">
<span class="admin-layout__brand-mark" aria-hidden="true">M</span>
<span class="admin-layout__brand-name">Marketplace</span>
</a>
<ul class="admin-layout__nav-list">
@for (entry of navPrimary; track (entry.type === 'group' ? entry.labelKey : entry.id)) {
@if (entry.type === 'group') {
<li class="admin-layout__nav-group" role="presentation">{{ entry.labelKey | translate }}</li>
} @else if (entry.type === 'link' && !entry.comingSoon) {
<li>
<a
class="admin-layout__nav-link"
[routerLink]="adminLinkFor(entry)"
routerLinkActive="admin-layout__nav-link--active"
[routerLinkActiveOptions]="{ exact: false }"
>
<app-icon [name]="entry.icon" [size]="18" />
<span class="admin-layout__nav-label">{{ entry.labelKey | translate }}</span>
</a>
</li>
} @else if (entry.type === 'link' && entry.comingSoon) {
<li>
<button type="button" class="admin-layout__nav-link admin-layout__nav-link--disabled" disabled>
<app-icon [name]="entry.icon" [size]="18" />
<span class="admin-layout__nav-label">{{ entry.labelKey | translate }}</span>
<span class="admin-layout__soon-badge">{{ 'adminShell.nav.comingSoonBadge' | translate }}</span>
</button>
</li>
}
}
</ul>
<ul class="admin-layout__nav-list admin-layout__nav-list--bottom">
@for (entry of navBottom(); track $index) {
@if (entry.type === 'link' && entry.externalHref) {
<li>
<a
class="admin-layout__nav-link"
[href]="entry.externalHref"
[attr.target]="entry.externalHref.startsWith('mailto:') ? null : '_blank'"
[attr.rel]="entry.externalHref.startsWith('mailto:') ? null : 'noopener'"
>
<app-icon [name]="entry.icon" [size]="18" />
<span class="admin-layout__nav-label">{{ entry.labelKey | translate }}</span>
</a>
</li>
} @else if (entry.type === 'link' && entry.comingSoon) {
<li>
<button type="button" class="admin-layout__nav-link admin-layout__nav-link--disabled" disabled>
<app-icon [name]="entry.icon" [size]="18" />
<span class="admin-layout__nav-label">{{ entry.labelKey | translate }}</span>
<span class="admin-layout__soon-badge">{{ 'adminShell.nav.comingSoonBadge' | translate }}</span>
</button>
</li>
} @else if (entry.type === 'action') {
<li>
<button type="button" class="admin-layout__nav-link" (click)="logout()">
<app-icon [name]="entry.icon" [size]="18" />
<span class="admin-layout__nav-label">{{ entry.labelKey | translate }}</span>
</button>
</li>
}
}
</ul>
</nav>
<header class="admin-layout__topbar">
<button
#menuToggle
type="button"
class="admin-layout__menu-toggle"
[attr.aria-expanded]="mobileDrawerOpen()"
[attr.aria-label]="(mobileDrawerOpen() ? 'adminShell.closeSidebar' : 'adminShell.openSidebar') | translate"
(click)="toggleMobileDrawer()"
>
<app-icon name="menu" [size]="20" />
</button>
<div class="admin-layout__heading">
<nav class="admin-layout__breadcrumb" [attr.aria-label]="'adminShell.breadcrumbHome' | translate">
<ol>
<li>
<a [routerLink]="['/', currentLang(), 'backoffice', 'dashboard']">{{ 'adminShell.breadcrumbHome' | translate }}</a>
</li>
@for (crumb of breadcrumb(); track crumb.labelKey; let last = $last) {
<li>
<span class="admin-layout__breadcrumb-sep" aria-hidden="true">/</span>
@if (!last) {
<a [routerLink]="breadcrumbLink(crumb)">{{ crumb.labelKey | translate }}</a>
} @else {
<span aria-current="page">{{ crumb.labelKey | translate }}</span>
}
</li>
}
</ol>
</nav>
<h1 class="admin-layout__title">{{ pageTitleKey() | translate }}</h1>
<p class="admin-layout__description">{{ pageDescriptionKey() | translate }}</p>
</div>
<div class="admin-layout__topbar-actions">
<label class="admin-layout__search">
<span class="visually-hidden">{{ 'adminShell.topbar.searchLabel' | translate }}</span>
<app-icon name="search" [size]="16" class="admin-layout__search-icon" />
<input type="search" [placeholder]="'adminShell.topbar.searchPlaceholder' | translate" />
</label>
<button
type="button"
class="admin-layout__icon-button"
disabled
[title]="'adminShell.topbar.quickPublishComingSoon' | translate"
>
<app-icon name="upload" [size]="18" />
<span class="visually-hidden">{{ 'adminShell.topbar.quickPublish' | translate }}</span>
</button>
<button
type="button"
class="admin-layout__icon-button"
disabled
[title]="'adminShell.topbar.tenantSelectorComingSoon' | translate"
>
<app-icon name="building" [size]="18" />
<span class="visually-hidden">{{ 'adminShell.topbar.tenantSelector' | translate }}</span>
</button>
<div class="admin-layout__notifications">
<button
type="button"
class="admin-layout__icon-button"
aria-haspopup="true"
[attr.aria-expanded]="notificationsOpen()"
[attr.aria-label]="'adminShell.topbar.notifications' | translate"
(click)="toggleNotifications()"
>
<app-icon name="bell" [size]="18" />
@if (unreadCount() > 0) {
<span class="admin-layout__notifications-badge">{{ unreadCount() }}</span>
}
</button>
@if (notificationsOpen()) {
<div class="admin-layout__notifications-panel" role="menu">
@if (recentOrders().length === 0) {
<p>{{ 'adminShell.topbar.notificationsEmpty' | translate }}</p>
} @else {
@for (order of recentOrders(); track order.id) {
<button
type="button"
class="admin-layout__notification-item"
role="menuitem"
(click)="goToOrder(order.id)"
>
<span class="admin-layout__notification-order">#{{ order.orderNumber }}</span>
<span class="admin-layout__notification-customer">{{ order.customer.name }}</span>
<span class="admin-layout__notification-amount">{{ order.total }} {{ order.currency }}</span>
</button>
}
}
</div>
}
</div>
<div class="admin-layout__account" [attr.aria-label]="'adminShell.topbar.account' | translate">
<span class="admin-layout__avatar" aria-hidden="true">{{ initials() }}</span>
<span class="admin-layout__account-name">{{ displayName() }}</span>
</div>
</div>
</header>
<main id="admin-content" class="admin-layout__content" [class.admin-density-compact]="density() === 'compact'" tabindex="-1">
<router-outlet></router-outlet>
</main>
<!-- Reserved for a future contextual inspector panel; intentionally empty. -->
<aside class="admin-layout__inspector" aria-hidden="true"></aside>
</div>