- <SeoBreadcrumbs> (UI-SPEC L1): the resolve answer's trail as nav > ol with server-rendered links and the last item as aria-current text; nothing with fewer than two items, with page meta seo.breadcrumbs false or with the option seo.breadcrumbs false; props items, label, hideCurrent, locale - one trail per page: the first rendered instance claims it (seoClaimBreadcrumbs, kept per path) - seoSitePath: same-origin CMS URLs become paths, non-http(s) URLs are never links; useSeoLabels takes an optional locale - L1 default styles with CSS-generated separators
28 lines
1.2 KiB
TypeScript
28 lines
1.2 KiB
TypeScript
// One visible breadcrumb trail per page (UI-SPEC L1): an app may place
|
|
// <SeoBreadcrumbs> in its layout while a layer's page renders one too; the
|
|
// first instance that renders in a request claims the page and later ones
|
|
// render nothing. The claim is kept per path, so a client navigation hands
|
|
// it out again (the layout instance, set up first, claims first). Pure, so
|
|
// `node --test` drives it; names start with `seo` (app/utils is
|
|
// auto-imported).
|
|
|
|
export interface SeoBreadcrumbClaim {
|
|
path: string
|
|
id: string
|
|
}
|
|
|
|
/**
|
|
* Whether instance `id` owns the trail of `path`, and the claim to keep:
|
|
* no claim or one for another path is taken over; the claim of this path
|
|
* belongs to the instance that made it.
|
|
*/
|
|
export function seoClaimBreadcrumbs(state: SeoBreadcrumbClaim | null | undefined, path: string, id: string): { state: SeoBreadcrumbClaim; owns: boolean } {
|
|
if (!state || state.path !== path) return { state: { path, id }, owns: true }
|
|
return { state, owns: state.id === id }
|
|
}
|
|
|
|
/** Releases the claim of `id` (an instance that stops rendering its trail). */
|
|
export function seoReleaseBreadcrumbs(state: SeoBreadcrumbClaim | null | undefined, id: string): SeoBreadcrumbClaim | null {
|
|
return state && state.id === id ? null : (state ?? null)
|
|
}
|