// Navigation copy-paste examples.
export /**
*
*/
const NAV_BREADCRUMB = `// You own the items array — breadcrumb won't walk the route tree for you.
// Link every ancestor; leave routerLink off the last crumb (current page).
import { Component, computed, inject, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { NavigationEnd, Router } from '@angular/router';
import { BreadcrumbComponent, type AfricaniesNavItem } from '@africanies/africanies-ui';
import { filter, map, startWith } from 'rxjs';
@Component({
selector: 'app-shipment-detail-chrome',
standalone: true,
imports: [BreadcrumbComponent],
template: \`
\`,
})
export class ShipmentDetailChromeComponent {
private readonly router = inject(Router);
private readonly url = toSignal(
this.router.events.pipe(
filter((e): e is NavigationEnd => e instanceof NavigationEnd),
map(() => this.router.url),
startWith(this.router.url),
),
{ initialValue: this.router.url },
);
protected readonly shipmentRef = signal('SFN-1042');
protected readonly crumbs = computed((): AfricaniesNavItem[] => {
const ref = this.shipmentRef();
const path = this.url().split('?')[0] ?? '';
const section = path.includes('/documents')
? 'Documents'
: path.includes('/events')
? 'Events'
: 'Overview';
return [
{ id: 'home', label: 'Home', routerLink: '/overview', icon: 'home' },
{ id: 'shipments', label: 'Shipments', routerLink: '/shipments' },
{ id: 'detail', label: ref, routerLink: '/shipments/' + ref + '/overview' },
{ id: 'section', label: section }, // current page — no routerLink
];
});
}
`;
export /**
*
*/
const NAV_ROUTED_TABS = `// URL-driven tabs + child routes. Active tab follows Router.isActive (survives refresh).
// Put routerLink on each item, render below. Don't mix with africaniesTabDef.
// keepScroll defaults to true — navigates with { scroll: 'manual' } so the page does not jump to the top.
// Pass [keepScroll]="false" if you want the app's normal scrollPositionRestoration behaviour.
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { TabsComponent, type AfricaniesNavItem } from '@africanies/africanies-ui';
@Component({
selector: 'app-shipment-detail-tabs',
standalone: true,
imports: [TabsComponent, RouterOutlet],
template: \`
\`,
})
export class ShipmentDetailTabsComponent {
protected readonly routeTabId = signal(null);
protected readonly routeTabs: AfricaniesNavItem[] = [
{
id: 'overview',
label: 'Overview',
icon: 'inbox',
routerLink: '/shipments/SFN-1042/overview',
},
{
id: 'documents',
label: 'Documents',
icon: 'file-add',
routerLink: '/shipments/SFN-1042/documents',
},
{
id: 'events',
label: 'Events',
icon: 'alarm',
routerLink: '/shipments/SFN-1042/events',
},
];
}
// Example child route config (app.routes.ts excerpt):
//
// {
// path: 'shipments/:ref',
// component: ShipmentDetailTabsComponent,
// children: [
// { path: 'overview', loadComponent: () => import('./overview').then(m => m.OverviewPage) },
// { path: 'documents', loadComponent: () => import('./documents').then(m => m.DocumentsPage) },
// { path: 'events', loadComponent: () => import('./events').then(m => m.EventsPage) },
// { path: '', pathMatch: 'full', redirectTo: 'overview' },
// ],
// }
`;
export /**
*
*/
const NAV_SEGMENT = `// Pill switcher on one path — same routerLink, different queryParams per segment.
// Active pill matches the query on cold load.
// keepScroll defaults to true — no jump to top when the query changes (same as routed tabs).
import { Component, inject, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';
import { SegmentComponent, type AfricaniesNavItem } from '@africanies/africanies-ui';
import { map } from 'rxjs';
@Component({
selector: 'app-shipment-list-density',
standalone: true,
imports: [SegmentComponent],
template: \`
Active density from URL:
{{ densityId() ?? '—' }}
\`,
})
export class ShipmentListDensityComponent {
private readonly route = inject(ActivatedRoute);
protected readonly densityFromUrl = toSignal(
this.route.queryParamMap.pipe(map((p) => p.get('density') ?? 'comfortable')),
{ initialValue: 'comfortable' },
);
protected readonly densityId = signal(null);
protected readonly densitySegments: AfricaniesNavItem[] = [
{
id: 'comfortable',
label: 'Comfortable',
routerLink: '/shipments',
queryParams: { density: 'comfortable' },
},
{
id: 'compact',
label: 'Compact',
routerLink: '/shipments',
queryParams: { density: 'compact' },
},
{
id: 'dense',
label: 'Dense',
routerLink: '/shipments',
queryParams: { density: 'dense' },
},
];
}
`;
export /**
*
*/
const NAV_LOCAL_TABS = `// In-page tabs — no router. Selection is [(activeId)] only; panels live in africaniesTabDef.
// Match template ids to AfricaniesNavItem.id. Want bookmarkable tabs? Use routed tabs instead.
import { Component, signal } from '@angular/core';
import { TabDefDirective, TabsComponent, type AfricaniesNavItem } from '@africanies/africanies-ui';
@Component({
selector: 'app-shipment-editor-local-tabs',
standalone: true,
imports: [TabsComponent, TabDefDirective],
template: \`
General fields — not tied to the URL.
Shipper and consignee — local panel only.
Charges and duties — local panel only.
\`,
})
export class ShipmentEditorLocalTabsComponent {
protected readonly localTabId = signal('general');
protected readonly localTabs: AfricaniesNavItem[] = [
{ id: 'general', label: 'General', icon: 'edit' },
{ id: 'parties', label: 'Parties', icon: 'user' },
{ id: 'charges', label: 'Charges', icon: 'wallet' },
];
}
`;
export /**
*
*/
const NAV_SIDE = `// Ink-spine side nav — icons, nested children, collapse to icon rail.
// Soft active highlight; collapsed: hover an icon for a label blade.
// Collapse all sits above the list (top right) when any section is open.
import { Component, signal } from '@angular/core';
import {
SideNavComponent,
type AfricaniesSideNavItem,
} from '@africanies/africanies-ui';
@Component({
selector: 'app-shell-nav',
standalone: true,
imports: [SideNavComponent],
template: \`
\`,
})
export class ShellNavComponent {
protected readonly collapsed = signal(false);
protected readonly activeId = signal('shipments');
protected readonly nav: AfricaniesSideNavItem[] = [
{ id: 'home', label: 'Home', icon: 'home' },
{
id: 'shipments',
label: 'Shipments',
icon: 'truck',
badge: true,
children: [
{ id: 'track', label: 'Track', icon: 'map-marker', badge: true },
{ id: 'create', label: 'Create', icon: 'plus' },
],
},
{ id: 'warehouse', label: 'Warehouse', icon: 'warehouse' },
{ id: 'settings', label: 'Settings', icon: 'cog' },
];
}
`;
export /**
*
*/
const NAV_APP_SHELL = `// Dedicated app shell — breadcrumbs + Back in the content column;
// header holds clock, notifications, and avatar.
// Needs provideAfricaniesUiOverlays() for the notification drawer.
// Back is built into africanies-app-shell — nest child routes under a parent and it appears.
// Log out: confirm → UserService.logoutFromAllSessions() → AuthTokenService.clear().
import { Component, inject, signal } from '@angular/core';
import { finalize } from 'rxjs';
import { AuthTokenService, UserService } from '@africanies/africanies-core';
import {
AppShellComponent,
ConfirmService,
SideNavComponent,
type AfricaniesMenuItem,
type AfricaniesNavItem,
type AfricaniesNotification,
type AfricaniesSideNavItem,
} from '@africanies/africanies-ui';
@Component({
selector: 'app-product-shell',
standalone: true,
imports: [AppShellComponent, SideNavComponent],
template: \`
\`,
})
export class ProductShellComponent {
private readonly confirm = inject(ConfirmService);
private readonly users = inject(UserService);
private readonly auth = inject(AuthTokenService);
protected readonly collapsed = signal(false);
protected readonly activeId = signal('home');
protected readonly pageTitle = 'STN-1042';
protected readonly crumbs: AfricaniesNavItem[] = [
{ id: 'home', label: 'Home', icon: 'home' },
{ id: 'shipments', label: 'Shipments' },
{ id: 'track', label: 'STN-1042' },
];
protected readonly accountMenu: AfricaniesMenuItem[] = [
{ label: 'Profile', icon: 'user', onClick: () => {} },
{ label: 'Settings', icon: 'cog', onClick: () => {} },
{
label: 'Log out',
icon: 'sign-out',
danger: true,
dividerBefore: true,
onClick: () => this.confirmLogout(),
},
];
protected readonly notifications: AfricaniesNotification[] = [
{
id: 'n1',
title: 'Shipment delivered',
timestamp: new Date().toISOString(),
},
];
protected readonly nav: AfricaniesSideNavItem[] = [
{ id: 'home', label: 'Home', icon: 'home' },
{ id: 'shipments', label: 'Shipments', icon: 'truck' },
];
protected confirmLogout(): void {
this.confirm
.confirm({
title: 'Log out?',
message:
'This signs you out of this device and every other session.',
confirmLabel: 'Log out',
danger: true,
})
.subscribe((ok) => {
if (!ok) {
return;
}
this.users
.logoutFromAllSessions()
.pipe(finalize(() => this.auth.clear()))
.subscribe();
});
}
}
`;