@masmarino/gabarit 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masmarino-gabarit-docs.mjs","names":[],"sources":["../../../projects/gabarit/docs/src/lib/docs-config.ts","../../../projects/gabarit/docs/src/lib/docs-labels.ts","../../../projects/gabarit/docs/src/lib/docs.service.ts","../../../projects/gabarit/docs/src/lib/markdown-view/markdown-view.ts","../../../projects/gabarit/docs/src/lib/docs-search.service.ts","../../../projects/gabarit/docs/src/lib/docs.routes.ts","../../../projects/gabarit/docs/src/lib/docs-search/docs-search.ts","../../../projects/gabarit/docs/src/lib/docs-search/docs-search.html","../../../projects/gabarit/docs/src/lib/docs-nav/docs-nav.ts","../../../projects/gabarit/docs/src/lib/docs-nav/docs-nav.html","../../../projects/gabarit/docs/src/lib/markdown-outline/markdown-outline.ts","../../../projects/gabarit/docs/src/lib/markdown-outline/markdown-outline.html","../../../projects/gabarit/docs/src/lib/docs-page/docs-page.ts","../../../projects/gabarit/docs/src/lib/docs-page/docs-page.html"],"sourcesContent":["import { InjectionToken, type Provider } from '@angular/core'\n\nexport interface DocsConfig {\n /**\n * Where the pages are, both as files and as the reader's routes: `<root>/index.json`, `<root>/<section>/<page>.md`,\n * and the page `<root>/<section>/<page>`. `/docs` by default.\n */\n root: string\n /**\n * The quotes that become callouts: a quote whose first word, in bold, is one of these keys (`> **Note** …`), drawn\n * in the tone it maps to. Case does not matter.\n */\n callouts: Readonly<Record<string, 'note' | 'warning'>>\n}\n\nexport const DEFAULT_DOCS_CONFIG: Readonly<DocsConfig> = Object.freeze<DocsConfig>({\n root: '/docs',\n callouts: { note: 'note', warning: 'warning' },\n})\n\nexport const DOCS_CONFIG = new InjectionToken<DocsConfig>('DOCS_CONFIG', {\n factory: () => DEFAULT_DOCS_CONFIG,\n})\n\n/**\n * Where the shown page's title goes, for an app that names its pages somewhere of its own (a header, a breadcrumb):\n * called with the page's title, \"not found\" or the reader's name while loading. Without it the reader leaves the\n * title alone.\n */\nexport const DOCS_TITLE = new InjectionToken<(title: string) => void>('DOCS_TITLE')\n\nexport function provideDocs(config: Partial<DocsConfig> = {}): Provider {\n return { provide: DOCS_CONFIG, useValue: { ...DEFAULT_DOCS_CONFIG, ...config } }\n}\n","import { InjectionToken, type Provider, type Signal, computed, inject } from '@angular/core'\n\n/** Every string the documentation reader shows or announces. English by default. */\nexport interface DocsLabels {\n /** The reader's name: the navigation's heading, its landmark and the breadcrumb's first step. */\n documentation: string\n showContents: string\n hideContents: string\n searchLabel: string\n searchPlaceholder: string\n searching: string\n noResults: string\n searchFailed: string\n results: (count: number) => string\n onThisPage: string\n breadcrumb: string\n neighbours: string\n previous: string\n next: string\n notFoundHeading: string\n notFoundMessage: string\n toStart: string\n loadFailed: string\n retry: string\n loading: string\n /** The accessible names given to a code block and a table, which scroll sideways and so take the focus. */\n codeBlock: string\n table: string\n}\n\nexport const DEFAULT_DOCS_LABELS: Readonly<DocsLabels> = Object.freeze<DocsLabels>({\n documentation: 'Documentation',\n showContents: 'Show the contents',\n hideContents: 'Hide the contents',\n searchLabel: 'Search the documentation',\n searchPlaceholder: 'Search…',\n searching: 'Searching…',\n noResults: 'No page matches.',\n searchFailed: 'The documentation could not be loaded.',\n results: (count) => (count === 0 ? 'No results' : count === 1 ? '1 result' : `${count} results`),\n onThisPage: 'On this page',\n breadcrumb: 'Breadcrumb',\n neighbours: 'Neighbouring pages',\n previous: 'Previous',\n next: 'Next',\n notFoundHeading: 'Page not found',\n notFoundMessage:\n 'This page does not exist in the documentation. Check the address, or start again from the beginning.',\n toStart: 'Go to the start of the documentation',\n loadFailed: 'The documentation could not be loaded.',\n retry: 'Retry',\n loading: 'Loading the page…',\n codeBlock: 'Code block',\n table: 'Table',\n})\n\nexport const DOCS_LABELS = new InjectionToken<Partial<DocsLabels>>('DOCS_LABELS')\n\n/** The reader's strings, over the English defaults; the ones left out keep theirs. */\nexport function provideDocsLabels(labels: Partial<DocsLabels>): Provider {\n return { provide: DOCS_LABELS, useValue: labels }\n}\n\nexport function docsLabels(): Signal<DocsLabels> {\n const provided = inject(DOCS_LABELS, { optional: true }) ?? {}\n const defined = Object.fromEntries(\n Object.entries(provided).filter(([, value]) => value !== undefined),\n ) as Partial<DocsLabels>\n return computed(() => ({ ...DEFAULT_DOCS_LABELS, ...defined }))\n}\n","import { HttpClient, HttpErrorResponse } from '@angular/common/http'\nimport { Injectable, inject } from '@angular/core'\nimport { type Observable, map, of, shareReplay, tap } from 'rxjs'\nimport { DOCS_CONFIG } from './docs-config'\n\nexport interface DocsPageEntry {\n slug: string\n title: string\n description: string\n}\n\nexport interface DocsSection {\n slug: string\n title: string\n pages: DocsPageEntry[]\n}\n\n/** `<root>/index.json`: the sections and their pages, in reading order. */\nexport interface DocsIndex {\n sections: DocsSection[]\n}\n\nexport interface DocsLink {\n sectionTitle: string\n title: string\n commands: string[]\n}\n\n/** A page with its neighbours in reading order, across sections. */\nexport interface DocsLocation {\n section: DocsSection\n page: DocsPageEntry\n previous: DocsLink | null\n next: DocsLink | null\n}\n\nexport function docsPageCommands(root: string, section: string, page: string): string[] {\n return [root, section, page]\n}\n\n/** Every page in reading order, each with its section. */\nexport function docsReadingOrder(\n index: DocsIndex,\n): { section: DocsSection; page: DocsPageEntry }[] {\n return index.sections.flatMap((section) => section.pages.map((page) => ({ section, page })))\n}\n\n/** Where `<root>` leads: the first page of the first section, or `null` for an empty index. */\nexport function firstDocsPage(root: string, index: DocsIndex): string[] | null {\n const first = docsReadingOrder(index)[0]\n return first ? docsPageCommands(root, first.section.slug, first.page.slug) : null\n}\n\nexport function locateDocsPage(\n root: string,\n index: DocsIndex,\n section: string | null,\n page: string | null,\n): DocsLocation | null {\n const order = docsReadingOrder(index)\n const at = order.findIndex((entry) => entry.section.slug === section && entry.page.slug === page)\n if (at < 0) {\n return null\n }\n const link = (entry: (typeof order)[number] | undefined): DocsLink | null =>\n entry\n ? {\n sectionTitle: entry.section.title,\n title: entry.page.title,\n commands: docsPageCommands(root, entry.section.slug, entry.page.slug),\n }\n : null\n return { ...order[at], previous: link(order[at - 1]), next: link(order[at + 1]) }\n}\n\n// An SPA's fallback answers an unknown path with its index.html, which isn't a Markdown page.\nconst looksLikeHtml = (text: string) => /^\\s*<!doctype html|^\\s*<html[\\s>]/i.test(text)\n\n/**\n * The documentation, shipped as static files under the configured root. The index and each page are fetched once\n * and kept, since they only change with a new version of the app. A failure isn't kept, so it gets retried.\n */\n@Injectable({ providedIn: 'root' })\nexport class DocsService {\n private readonly http = inject(HttpClient)\n readonly root = inject(DOCS_CONFIG).root\n private index$: Observable<DocsIndex> | null = null\n private readonly pages = new Map<string, string>()\n\n index(): Observable<DocsIndex> {\n this.index$ ??= this.http\n .get<DocsIndex>(`${this.root}/index.json`)\n .pipe(tap({ error: () => (this.index$ = null) }), shareReplay(1))\n return this.index$\n }\n\n /** The page's Markdown. A missing file fails with a 404, including when the server answers with the app shell. */\n page(section: string, page: string): Observable<string> {\n const key = `${section}/${page}`\n const known = this.pages.get(key)\n if (known !== undefined) {\n return of(known)\n }\n return this.http.get(`${this.root}/${key}.md`, { responseType: 'text' }).pipe(\n map((text) => {\n if (looksLikeHtml(text)) {\n throw new HttpErrorResponse({\n status: 404,\n statusText: 'Not Found',\n url: `${this.root}/${key}.md`,\n })\n }\n return text\n }),\n tap((text) => this.pages.set(key, text)),\n )\n }\n}\n\nexport const isNotFound = (error: unknown) =>\n error instanceof HttpErrorResponse && error.status === 404\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n afterRenderEffect,\n computed,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core'\nimport { DomSanitizer, type SafeHtml } from '@angular/platform-browser'\nimport { Router } from '@angular/router'\nimport { marked, type Token } from 'marked'\nimport DOMPurify, { type Config, type DOMPurify as Purifier } from 'dompurify'\nimport { docsLabels } from '../docs-labels'\n\n// Markdown may come from anyone who can write a page, so it is sanitised harder than DOMPurify's default: no\n// restyling the page (<style>, style=\"…\"), no fake UI (forms, buttons, dialogs), no colliding ids. A dedicated\n// instance keeps these hooks off the global DOMPurify the app may use elsewhere. Made on first use, in a browser only.\nlet purifier: Purifier | null = null\n\nfunction purify(): Purifier | null {\n if (purifier || typeof window === 'undefined') {\n return purifier\n }\n purifier = DOMPurify(window)\n\n // Only GFM task-list checkboxes survive; any other <input> (password, text, hidden…) goes.\n purifier.addHook('uponSanitizeElement', (node, data) => {\n if (\n data.tagName === 'input' &&\n (node as Element).getAttribute('type')?.toLowerCase() !== 'checkbox'\n ) {\n node.parentNode?.removeChild(node)\n }\n })\n\n purifier.addHook('afterSanitizeAttributes', (node) => {\n // A task-list checkbox is a mark, not a control.\n if (node.nodeName === 'INPUT') {\n node.setAttribute('disabled', '')\n }\n // Remote images are fine (badges, screenshots) but must not leak the page's URL to their host or load before\n // they are scrolled into view.\n if (node.nodeName === 'IMG') {\n node.setAttribute('referrerpolicy', 'no-referrer')\n node.setAttribute('loading', 'lazy')\n }\n })\n\n // Authors can't borrow the app's global classes (sr-only, skip links, tooltips…) to spoof its UI. Only the\n // `language-*` classes of fenced code blocks survive, for syntax highlighting.\n purifier.addHook('uponSanitizeAttribute', (_node, data) => {\n if (data.attrName === 'class') {\n const kept = data.attrValue.split(/\\s+/).filter((c) => /^language-[\\w+#.-]+$/.test(c))\n if (kept.length) {\n data.attrValue = kept.join(' ')\n } else {\n data.keepAttr = false\n }\n }\n })\n return purifier\n}\n\nconst SANITIZE_CONFIG: Config = {\n FORBID_TAGS: [\n 'style',\n 'form',\n 'button',\n 'textarea',\n 'select',\n 'option',\n 'optgroup',\n 'fieldset',\n 'dialog',\n ],\n // `for` and aria IDREFs could point at the page's own controls (a <label for> toggling a real switch), and tabindex\n // could hijack the tab order.\n FORBID_ATTR: [\n 'style',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'for',\n 'tabindex',\n 'aria-owns',\n 'aria-controls',\n 'aria-labelledby',\n 'aria-describedby',\n ],\n // `id` and `name` become \"user-content-…\" so the Markdown can't clobber the page's ids.\n SANITIZE_NAMED_PROPS: true,\n}\n\n/** One heading of the rendered content, for an \"On this page\" outline. */\nexport interface MarkdownOutlineEntry {\n /** The level as rendered, after `headingOffset`: 2, 3 or 4. */\n level: number\n text: string\n id: string\n}\n\nconst ID_PREFIX = 'user-content-'\n\n/** GitHub-like slug, accents kept. `section` when nothing is left, e.g. a title made only of emoji. */\nexport function headingSlug(text: string): string {\n const slug = text\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\s_-]/gu, '')\n .trim()\n .replace(/[\\s-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug || 'section'\n}\n\n/**\n * Gives every rendered h1–h4 a stable `user-content-<slug>` id and returns the h2–h4 outline. Runs after sanitising so\n * ids are never the author's: an author id that would duplicate a heading id is removed. Headings in a quote or\n * `<details>` get an id but no outline entry.\n */\nfunction applyHeadingIds(root: HTMLElement): MarkdownOutlineEntry[] {\n const headings = Array.from(root.querySelectorAll<HTMLHeadingElement>('h1, h2, h3, h4'))\n const used = new Set<string>()\n const outline: MarkdownOutlineEntry[] = []\n for (const heading of headings) {\n const text = (heading.textContent ?? '').replace(/\\s+/g, ' ').trim()\n const base = ID_PREFIX + headingSlug(text)\n let id = base\n for (let n = 2; used.has(id); n++) {\n id = `${base}-${n}`\n }\n used.add(id)\n heading.id = id\n const level = Number(heading.tagName[1])\n if (level >= 2 && !heading.parentElement?.closest('blockquote, details')) {\n outline.push({ level, text, id })\n }\n }\n for (const node of Array.from(root.querySelectorAll('[id]'))) {\n if (used.has(node.id) && !headings.includes(node as HTMLHeadingElement)) {\n node.removeAttribute('id')\n }\n }\n return outline\n}\n\nexport function decodeFragment(rawFragment: string): string {\n try {\n return decodeURIComponent(rawFragment)\n } catch {\n return rawFragment\n }\n}\n\n/** The element a `#fragment` points at: the plain `id`, else the `user-content-` id or `<a name>` the sanitiser made. */\nexport function findAnchorTarget(root: HTMLElement, rawFragment: string): HTMLElement | null {\n const fragment = decodeFragment(rawFragment)\n if (!fragment) {\n return null\n }\n for (const wanted of [fragment, ID_PREFIX + fragment]) {\n for (const node of Array.from(root.querySelectorAll<HTMLElement>('[id], a[name]'))) {\n if (node.id === wanted || (node.tagName === 'A' && node.getAttribute('name') === wanted)) {\n return node\n }\n }\n }\n return null\n}\n\n/**\n * A long code block or a wide table scrolls sideways, which a keyboard can only do once it takes the focus (WCAG\n * 2.1.1): each one becomes a named stop in the tab order. A table keeps its own role and gets only the stop and the\n * name.\n */\nexport function makeScrollableBlocksFocusable(\n container: HTMLElement,\n names: { codeBlock: string; table: string },\n): void {\n for (const pre of Array.from(container.querySelectorAll('pre'))) {\n pre.setAttribute('tabindex', '0')\n pre.setAttribute('role', 'region')\n pre.setAttribute('aria-label', names.codeBlock)\n }\n for (const table of Array.from(container.querySelectorAll('table'))) {\n table.setAttribute('tabindex', '0')\n table.setAttribute('aria-label', names.table)\n }\n}\n\n/**\n * A task-list checkbox is named by its item's text, so a screen reader says what is done or still to do.\n */\nexport function nameTaskCheckboxes(container: HTMLElement): void {\n for (const box of Array.from(\n container.querySelectorAll<HTMLInputElement>(\n 'li > input[type=\"checkbox\"], li > p:first-child > input[type=\"checkbox\"]',\n ),\n )) {\n const item = box.closest('li')!\n box.setAttribute('aria-label', (item.textContent ?? '').replace(/\\s+/g, ' ').trim())\n }\n}\n\n/**\n * Markdown rendered to sanitised HTML, with the reading styles of the design system: headings, lists, code, tables,\n * quotes. Every heading gets a stable id, and the h2–h4 outline is emitted after each render.\n */\n@Component({\n selector: 'gbt-markdown-view',\n standalone: true,\n // The click is delegated from the links inside, which take the focus and the keyboard themselves.\n template: `<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"gbt-markdown-view\"\n #container\n [innerHTML]=\"renderedHtml()\"\n (click)=\"onClick($event)\"\n ></div>`,\n styleUrl: './markdown-view.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownView {\n content = input.required<string>()\n /** Levels added to every heading (up to h6), so a `# Title` under the page's own headings keeps the outline. */\n headingOffset = input(0)\n /**\n * Links under this prefix (`/docs` → `/docs/install/configuration#variables`) go through the router instead of\n * reloading the app. Off by default: a link in a README is left to the browser.\n */\n routedLinkPrefix = input<string | null>(null)\n /** The h2–h4 headings, emitted after each render once their ids are in the DOM. */\n outline = output<MarkdownOutlineEntry[]>()\n\n private readonly sanitizer = inject(DomSanitizer)\n private readonly router = inject(Router, { optional: true })\n private readonly labels = docsLabels()\n private readonly container = viewChild.required<ElementRef<HTMLElement>>('container')\n\n constructor() {\n afterRenderEffect({\n write: () => {\n this.renderedHtml()\n const container = this.container().nativeElement\n makeScrollableBlocksFocusable(container, this.labels())\n nameTaskCheckboxes(container)\n this.outline.emit(applyHeadingIds(container))\n },\n })\n }\n\n /**\n * In-content `#anchor` links would resolve against `<base href=\"/\">` and load the home page, so a plain left click\n * scrolls to the target inside this view and focuses it. Modified and middle clicks are left to the browser.\n */\n protected onClick(event: MouseEvent): void {\n if (\n event.defaultPrevented ||\n event.button !== 0 ||\n event.ctrlKey ||\n event.metaKey ||\n event.shiftKey ||\n event.altKey\n ) {\n return\n }\n const container = this.container().nativeElement\n const routed = this.routedHref(event.target)\n if (routed !== null) {\n event.preventDefault()\n void this.router!.navigateByUrl(routed)\n return\n }\n const link = event.target instanceof Element ? event.target.closest('a[href^=\"#\"]') : null\n if (!link || !container.contains(link)) {\n return\n }\n event.preventDefault()\n const target = findAnchorTarget(container, link.getAttribute('href')!.slice(1))\n if (!target) {\n return\n }\n const reduceMotion =\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches\n target.scrollIntoView?.({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' })\n // Headings aren't focusable; -1 lets the next Tab carry on from the section just reached.\n if (target.tabIndex < 0) {\n target.setAttribute('tabindex', '-1')\n }\n target.focus({ preventScroll: true })\n }\n\n /** The `href` of a clicked in-content link under `routedLinkPrefix`, or `null` when the browser should follow it. */\n private routedHref(target: EventTarget | null): string | null {\n const prefix = this.routedLinkPrefix()\n const link =\n prefix && this.router && target instanceof Element ? target.closest('a[href]') : null\n if (!link || !this.container().nativeElement.contains(link) || link.hasAttribute('target')) {\n return null\n }\n const href = link.getAttribute('href')!\n const rest = href.startsWith(prefix!) ? href.slice(prefix!.length) : null\n return rest !== null && (rest === '' || /^[/#?]/.test(rest)) ? href : null\n }\n\n // marked.parse is synchronous unless an async extension is registered (none is), so the cast is safe. A\n // `walkTokens` passed per call only applies to that call.\n protected readonly renderedHtml = computed<SafeHtml>(() => {\n const offset = this.headingOffset()\n const walkTokens =\n offset > 0\n ? (token: Token) => {\n if (token.type === 'heading') {\n token.depth = Math.min(6, token.depth + offset)\n }\n }\n : null\n const sanitizer = purify()\n if (!sanitizer) {\n return ''\n }\n const rawHtml = marked.parse(this.content(), { async: false, walkTokens }) as string\n return this.sanitizer.bypassSecurityTrustHtml(sanitizer.sanitize(rawHtml, SANITIZE_CONFIG))\n })\n}\n","import { inject, Injectable } from '@angular/core'\nimport { catchError, firstValueFrom, forkJoin, map, of, switchMap } from 'rxjs'\nimport { headingSlug } from './markdown-view/markdown-view'\nimport { DocsService, docsPageCommands, docsReadingOrder } from './docs.service'\n\nexport const DOCS_SEARCH_LIMIT = 8\n\nexport interface DocsSearchHit {\n sectionTitle: string\n pageTitle: string\n commands: string[]\n /** Id of the best matching heading (`user-content-…`), so the result lands on it. */\n fragment: string | null\n heading: string | null\n /** Body text around the first match, or the page's description when only the title or headings match. */\n excerpt: { before: string; match: string; after: string }\n}\n\ninterface Field {\n text: string\n /** Lower-cased, accents removed. */\n folded: string\n /** Where each character of `folded` sits in `text`. */\n origin: number[]\n}\n\ninterface Heading {\n id: string\n field: Field\n}\n\ninterface Document {\n order: number\n sectionTitle: string\n description: string\n commands: string[]\n title: Field\n section: Field\n headings: Heading[]\n body: Field\n}\n\n/** Lower case without accents, character by character, keeping track of where each one came from. */\nfunction fold(text: string): Field {\n let folded = ''\n const origin: number[] = []\n let at = 0\n for (const char of text) {\n const plain = char.normalize('NFD').replace(/\\p{M}/gu, '').toLowerCase()\n folded += plain\n for (let i = 0; i < plain.length; i++) {\n origin.push(at)\n }\n at += char.length\n }\n return { text, folded, origin }\n}\n\nexport function searchTokens(query: string): string[] {\n return [\n ...new Set(\n fold(query)\n .folded.split(/[^\\p{L}\\p{N}]+/u)\n .filter(Boolean),\n ),\n ]\n}\n\n/** Inline Markdown down to its text: links and images keep their label, emphasis and code marks are dropped. */\nfunction inlineText(line: string): string {\n return line\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/`+/g, '')\n .replace(/(\\*\\*|__|\\*|~~)/g, '')\n .replace(/(^|\\s)_(\\S)/g, '$1$2')\n .replace(/(\\S)_(\\s|$)/g, '$1$2')\n}\n\n/**\n * Title, headings and body text of one page. Heading ids follow `gbt-markdown-view`: `user-content-<slug>` on every\n * h1–h4, and `-2`, `-3`… on a repeated slug in document order.\n */\nexport function parseDocsPage(markdown: string): {\n headings: { id: string; text: string }[]\n body: string\n} {\n const headings: { id: string; text: string }[] = []\n const used = new Set<string>()\n const body: string[] = []\n let fence: string | null = null\n for (const line of markdown.split(/\\r?\\n/)) {\n const fenceMark = /^\\s*(`{3,}|~{3,})/.exec(line)?.[1]\n if (fence !== null) {\n if (fenceMark && fenceMark[0] === fence[0] && fenceMark.length >= fence.length) {\n fence = null\n } else {\n body.push(line)\n }\n continue\n }\n if (fenceMark) {\n fence = fenceMark\n continue\n }\n const heading = /^(#{1,6})\\s+(.*?)\\s*#*\\s*$/.exec(line)\n if (heading) {\n const level = heading[1].length\n const text = inlineText(heading[2]).replace(/\\s+/g, ' ').trim()\n if (level <= 4) {\n const base = `user-content-${headingSlug(text)}`\n let id = base\n for (let n = 2; used.has(id); n++) {\n id = `${base}-${n}`\n }\n used.add(id)\n if (level >= 2) {\n headings.push({ id, text })\n }\n }\n continue\n }\n if (/^\\s*\\|?\\s*:?-{3,}/.test(line)) {\n continue // table separator row\n }\n body.push(\n inlineText(\n line\n .replace(/^\\s*(>\\s*)+/, '')\n .replace(/^\\s*([-*+]|\\d+[.)])\\s+/, '')\n .replace(/\\|/g, ' '),\n ),\n )\n }\n return { headings, body: body.join(' ').replace(/\\s+/g, ' ').trim() }\n}\n\nconst isWordStart = (folded: string, at: number) =>\n at === 0 || !/[\\p{L}\\p{N}]/u.test(folded[at - 1])\n\nfunction count(field: Field, token: string): number {\n let found = 0\n for (\n let at = field.folded.indexOf(token);\n at >= 0 && found < 5;\n at = field.folded.indexOf(token, at + token.length)\n ) {\n found++\n }\n return found\n}\n\nfunction weight(field: Field, token: string, base: number): number {\n const at = field.folded.indexOf(token)\n if (at < 0) {\n return 0\n }\n return isWordStart(field.folded, at) ? base * 1.5 : base\n}\n\nconst EXCERPT_BEFORE = 40\nconst EXCERPT_LENGTH = 140\n\nfunction excerptAround(field: Field, token: string): DocsSearchHit['excerpt'] | null {\n const at = field.folded.indexOf(token)\n if (at < 0) {\n return null\n }\n const start = field.origin[at]\n const end =\n at + token.length < field.origin.length ? field.origin[at + token.length] : field.text.length\n let from = Math.max(0, start - EXCERPT_BEFORE)\n let to = Math.min(field.text.length, from + EXCERPT_LENGTH)\n // Cut on word boundaries at both ends.\n if (from > 0) {\n const space = field.text.indexOf(' ', from)\n from = space >= 0 && space < start ? space + 1 : from\n }\n if (to < field.text.length) {\n const space = field.text.lastIndexOf(' ', to)\n to = space > end ? space : to\n }\n return {\n before: (from > 0 ? '…' : '') + field.text.slice(from, start),\n match: field.text.slice(start, end),\n after: field.text.slice(end, to) + (to < field.text.length ? '…' : ''),\n }\n}\n\n/**\n * Search over the whole documentation, in the browser. Nothing is fetched until the first search (or `prepare()`),\n * then every page once, kept by `DocsService`. Every word of the query must appear in the page; a word in the title\n * ranks higher than one in a heading, and a heading higher than the text.\n */\n@Injectable({ providedIn: 'root' })\nexport class DocsSearchService {\n private docs = inject(DocsService)\n private documents: Promise<Document[]> | null = null\n\n /** Starts loading the pages before the first search; the field calls it on focus. */\n prepare(): void {\n this.load().catch(() => {})\n }\n\n private load(): Promise<Document[]> {\n this.documents ??= firstValueFrom(\n this.docs.index().pipe(\n switchMap((index) => {\n const order = docsReadingOrder(index)\n if (order.length === 0) {\n return of([])\n }\n // A page that fails to load drops out of the results instead of failing the whole search.\n return forkJoin(\n order.map(({ section, page }, position) =>\n this.docs.page(section.slug, page.slug).pipe(\n map((markdown): Document => {\n const parsed = parseDocsPage(markdown)\n return {\n order: position,\n sectionTitle: section.title,\n description: page.description,\n commands: docsPageCommands(this.docs.root, section.slug, page.slug),\n title: fold(page.title),\n section: fold(section.title),\n headings: parsed.headings.map((heading) => ({\n id: heading.id,\n field: fold(heading.text),\n })),\n body: fold(parsed.body),\n }\n }),\n catchError(() => of(null)),\n ),\n ),\n ).pipe(\n map((documents) =>\n documents.filter((document): document is Document => document !== null),\n ),\n )\n }),\n ),\n ).catch((error: unknown) => {\n this.documents = null\n throw error\n })\n return this.documents\n }\n\n async search(query: string): Promise<DocsSearchHit[]> {\n const tokens = searchTokens(query)\n if (tokens.length === 0) {\n return []\n }\n const documents = await this.load()\n const scored: { score: number; order: number; hit: DocsSearchHit }[] = []\n for (const document of documents) {\n let score = 0\n let complete = true\n for (const token of tokens) {\n const inTitle = weight(document.title, token, 12)\n const inSection = weight(document.section, token, 3)\n const inHeading = Math.max(\n 0,\n ...document.headings.map((heading) => weight(heading.field, token, 5)),\n )\n const inBody = count(document.body, token)\n if (inTitle + inSection + inHeading + inBody === 0) {\n complete = false\n break\n }\n score += inTitle + inSection + inHeading + inBody\n }\n if (!complete) {\n continue\n }\n // The heading with the most query words, the first one on a tie.\n let heading: Heading | null = null\n let headingMatches = 0\n for (const candidate of document.headings) {\n const matches = tokens.filter((token) => candidate.field.folded.includes(token)).length\n if (matches > headingMatches) {\n heading = candidate\n headingMatches = matches\n }\n }\n const longest = [...tokens].sort((a, b) => b.length - a.length)\n const excerpt = longest\n .map((token) => excerptAround(document.body, token))\n .find((found) => found !== null) ?? {\n before: document.description,\n match: '',\n after: '',\n }\n scored.push({\n score,\n order: document.order,\n hit: {\n sectionTitle: document.sectionTitle,\n pageTitle: document.title.text,\n commands: document.commands,\n fragment: heading?.id ?? null,\n heading: heading?.field.text ?? null,\n excerpt,\n },\n })\n }\n return scored\n .sort((a, b) => b.score - a.score || a.order - b.order)\n .slice(0, DOCS_SEARCH_LIMIT)\n .map((entry) => entry.hit)\n }\n}\n","import { inject } from '@angular/core'\nimport { type CanActivateFn, Router, type Routes } from '@angular/router'\nimport { catchError, map, of } from 'rxjs'\nimport { DocsService, firstDocsPage } from './docs.service'\n\n/**\n * The root opens the first page of the index. If the index can't be read or is empty, the reader shows that itself,\n * inside its own layout.\n */\nexport const docsHomeGuard: CanActivateFn = () => {\n const router = inject(Router)\n const docs = inject(DocsService)\n return docs.index().pipe(\n map((index) => {\n const first = firstDocsPage(docs.root, index)\n return first ? router.createUrlTree(first) : true\n }),\n catchError(() => of(true)),\n )\n}\n\n/**\n * The reader's routes, to mount at the configured root: the root (to the first page), `<section>/<page>`, and any\n * other depth, which gets the reader's own \"not found\". `page` is the routed component that shows the reader (often\n * the app's own, wrapping `gbt-docs-page` in its layout).\n */\nexport function docsRoutes(page: () => Promise<unknown>): Routes {\n const loadComponent = page as Routes[number]['loadComponent']\n return [\n { path: '', pathMatch: 'full', canActivate: [docsHomeGuard], loadComponent },\n { path: ':section/:page', loadComponent },\n { path: '**', loadComponent },\n ]\n}\n","import { ChangeDetectionStrategy, Component, inject, output, viewChild } from '@angular/core'\nimport { Router } from '@angular/router'\nimport { Autocomplete, type AutocompleteSearchFn } from '@masmarino/gabarit'\nimport { docsLabels } from '../docs-labels'\nimport { type DocsSearchHit, DocsSearchService } from '../docs-search.service'\n\n/** The search field above the documentation's navigation. Pages load on first focus, since most visits never search. */\n@Component({\n selector: 'gbt-docs-search',\n standalone: true,\n imports: [Autocomplete],\n templateUrl: './docs-search.html',\n styleUrl: './docs-search.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DocsSearch {\n /** Emitted once a result is opened, so a folded navigation can close. */\n opened = output<DocsSearchHit>()\n\n private readonly searchService = inject(DocsSearchService)\n private readonly router = inject(Router)\n private readonly field = viewChild.required(Autocomplete)\n protected readonly labels = docsLabels()\n\n protected readonly search: AutocompleteSearchFn<DocsSearchHit> = (query) =>\n this.searchService.search(query)\n protected readonly label = (hit: DocsSearchHit) => hit.pageTitle\n protected readonly announce = (count: number) => this.labels().results(count)\n\n protected prepare(): void {\n this.searchService.prepare()\n }\n\n protected open(hit: DocsSearchHit): void {\n // Empty the field, or it keeps the chosen title.\n this.field().writeValue(null)\n void this.router.navigate(hit.commands, { fragment: hit.fragment ?? undefined })\n this.opened.emit(hit)\n }\n}\n","<gbt-autocomplete\n class=\"gbt-docs-search\"\n [label]=\"labels().searchLabel\"\n [placeholder]=\"labels().searchPlaceholder\"\n [search]=\"search\"\n [displayFn]=\"label\"\n [itemTemplate]=\"result\"\n [debounceMs]=\"150\"\n [minLength]=\"2\"\n [loadingMessage]=\"labels().searching\"\n [noResultsMessage]=\"labels().noResults\"\n [searchErrorMessage]=\"labels().searchFailed\"\n [resultsAnnouncement]=\"announce\"\n (focusin)=\"prepare()\"\n (itemSelected)=\"open($event)\"\n/>\n\n<ng-template #result let-hit>\n <span class=\"gbt-docs-search__result\">\n <span class=\"gbt-docs-search__where\">{{ hit.sectionTitle }}</span>\n <span class=\"gbt-docs-search__title\">\n {{ hit.pageTitle }}\n @if (hit.heading) {\n <span class=\"gbt-docs-search__heading\">› {{ hit.heading }}</span>\n }\n </span>\n @if (hit.excerpt.before || hit.excerpt.match) {\n <span class=\"gbt-docs-search__excerpt\"\n >{{ hit.excerpt.before }}<mark>{{ hit.excerpt.match }}</mark\n >{{ hit.excerpt.after }}</span\n >\n }\n </span>\n</ng-template>\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n input,\n linkedSignal,\n signal,\n} from '@angular/core'\nimport { RouterLink } from '@angular/router'\nimport { Button, Disclosure, NavTab, NavTabs } from '@masmarino/gabarit'\nimport { docsLabels } from '../docs-labels'\nimport { DocsSearch } from '../docs-search/docs-search'\nimport { type DocsIndex, DocsService, docsPageCommands } from '../docs.service'\n\nlet nextNavId = 0\n\n/**\n * The documentation's left column: the search field, then every section with its pages. Only the current section\n * starts open. On a narrow layout the sections fold behind a toggle and the search stays.\n */\n@Component({\n selector: 'gbt-docs-nav',\n standalone: true,\n imports: [RouterLink, Button, Disclosure, NavTab, NavTabs, DocsSearch],\n templateUrl: './docs-nav.html',\n styleUrl: './docs-nav.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DocsNav {\n index = input.required<DocsIndex>()\n section = input<string | null>(null)\n page = input<string | null>(null)\n\n private readonly root = inject(DocsService).root\n protected readonly labels = docsLabels()\n protected readonly bodyId = `gbt-docs-nav-${++nextNavId}`\n protected readonly navOpen = signal(false)\n\n // What the reader opened or closed by hand; forgotten on moving to another section.\n private readonly toggled = linkedSignal<string | null, Record<string, boolean>>({\n source: this.section,\n computation: () => ({}),\n })\n\n protected readonly sections = computed(() =>\n this.index().sections.map((section) => {\n const current = section.slug === this.section()\n return {\n slug: section.slug,\n title: section.title,\n open: this.toggled()[section.slug] ?? current,\n pages: section.pages.map((page) => ({\n slug: page.slug,\n title: page.title,\n commands: docsPageCommands(this.root, section.slug, page.slug),\n current: current && page.slug === this.page(),\n })),\n }\n }),\n )\n\n protected setOpen(slug: string, open: boolean): void {\n this.toggled.update((toggled) => ({ ...toggled, [slug]: open }))\n }\n\n protected close(): void {\n this.navOpen.set(false)\n }\n}\n","<div class=\"gbt-docs-nav\" [class.gbt-docs-nav--open]=\"navOpen()\">\n <div class=\"gbt-docs-nav__header\">\n <h2 class=\"gbt-docs-nav__heading\">{{ labels().documentation }}</h2>\n <gbt-button\n class=\"gbt-docs-nav__toggle\"\n variant=\"secondary\"\n size=\"small\"\n iconName=\"list\"\n [text]=\"navOpen() ? labels().hideContents : labels().showContents\"\n [ariaExpanded]=\"navOpen()\"\n [ariaControls]=\"bodyId\"\n (clicked)=\"navOpen.set(!navOpen())\"\n />\n </div>\n\n <gbt-docs-search class=\"gbt-docs-nav__search\" (opened)=\"close()\" />\n\n <div class=\"gbt-docs-nav__body\" [id]=\"bodyId\">\n @for (section of sections(); track section.slug) {\n <gbt-disclosure\n class=\"gbt-docs-nav__section\"\n appearance=\"plain\"\n [headingLevel]=\"3\"\n [label]=\"section.title\"\n [open]=\"section.open\"\n (openChange)=\"setOpen(section.slug, $event)\"\n >\n <gbt-nav-tabs orientation=\"vertical\" [landmark]=\"false\">\n @for (page of section.pages; track page.slug) {\n <a gbtNavTab [routerLink]=\"page.commands\" [active]=\"page.current\" (click)=\"close()\">{{\n page.title\n }}</a>\n }\n </gbt-nav-tabs>\n </gbt-disclosure>\n }\n </div>\n</div>\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core'\nimport { RouterLink } from '@angular/router'\nimport { Panel, type PanelHeadingLevel } from '@masmarino/gabarit'\nimport { docsLabels } from '../docs-labels'\nimport type { MarkdownOutlineEntry } from '../markdown-view/markdown-view'\n\n/** An outline is worth a panel from two headings on: one heading is no table of contents. */\nexport function hasOutline(entries: readonly MarkdownOutlineEntry[]): boolean {\n return entries.length >= 2\n}\n\n/**\n * The \"On this page\" panel beside rendered Markdown. Each entry links to `#user-content-…` on the current URL; the\n * router does no anchor scrolling, so the click scrolls to the heading and focuses it itself.\n */\n@Component({\n selector: 'gbt-markdown-outline',\n standalone: true,\n imports: [RouterLink, Panel],\n templateUrl: './markdown-outline.html',\n styleUrl: './markdown-outline.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownOutline {\n entries = input.required<MarkdownOutlineEntry[]>()\n headingLevel = input<PanelHeadingLevel>(2)\n\n protected readonly labels = docsLabels()\n protected readonly here: readonly string[] = []\n\n protected goTo(id: string): void {\n const heading = document.getElementById(id)\n if (!heading) {\n return\n }\n const reduceMotion =\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches\n heading.scrollIntoView?.({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' })\n // Headings aren't focusable: -1 lets the next Tab continue from the section just reached.\n heading.setAttribute('tabindex', '-1')\n heading.focus({ preventScroll: true })\n }\n}\n","<gbt-panel [heading]=\"labels().onThisPage\" [headingLevel]=\"headingLevel()\">\n <ul class=\"gbt-markdown-outline__list\">\n @for (entry of entries(); track entry.id) {\n <li class=\"gbt-markdown-outline__item\" [attr.data-level]=\"entry.level\">\n <a\n class=\"gbt-markdown-outline__link\"\n [routerLink]=\"here\"\n [fragment]=\"entry.id\"\n [title]=\"entry.text\"\n (click)=\"goTo(entry.id)\"\n >{{ entry.text }}</a\n >\n </li>\n }\n </ul>\n</gbt-panel>\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core'\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'\nimport { ActivatedRoute, type ParamMap, RouterLink } from '@angular/router'\nimport {\n BehaviorSubject,\n type Observable,\n catchError,\n combineLatest,\n debounceTime,\n map,\n of,\n startWith,\n switchMap,\n tap,\n} from 'rxjs'\nimport {\n Alert,\n Breadcrumb,\n Button,\n Card,\n CardLink,\n EmptyState,\n PageLayout,\n Skeleton,\n} from '@masmarino/gabarit'\nimport { DOCS_CONFIG, DOCS_TITLE } from '../docs-config'\nimport { docsLabels } from '../docs-labels'\nimport { DocsNav } from '../docs-nav/docs-nav'\nimport {\n type DocsIndex,\n type DocsLocation,\n DocsService,\n docsPageCommands,\n firstDocsPage,\n isNotFound,\n locateDocsPage,\n} from '../docs.service'\nimport { MarkdownOutline, hasOutline } from '../markdown-outline/markdown-outline'\nimport {\n type MarkdownOutlineEntry,\n MarkdownView,\n findAnchorTarget,\n} from '../markdown-view/markdown-view'\n\ntype DocsView =\n | { kind: 'loading' }\n | { kind: 'failed' }\n | { kind: 'not-found'; firstPage: string[] | null }\n | { kind: 'page'; location: DocsLocation; content: string }\n\nconst keyOf = (section: string | null, page: string | null) => `${section}/${page}`\n\n/**\n * One documentation page (`<root>/<section>/<page>`, read from the route): the navigation, the page with its\n * breadcrumb and neighbours, and on a wide screen the outline beside it. An unknown address gets a \"not found\" in the\n * same frame.\n */\n@Component({\n selector: 'gbt-docs-page',\n standalone: true,\n imports: [\n RouterLink,\n Alert,\n Breadcrumb,\n Button,\n Card,\n CardLink,\n EmptyState,\n PageLayout,\n Skeleton,\n MarkdownView,\n MarkdownOutline,\n DocsNav,\n ],\n templateUrl: './docs-page.html',\n styleUrl: './docs-page.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DocsPage {\n private readonly docs = inject(DocsService)\n private readonly route = inject(ActivatedRoute)\n private readonly setTitle = inject(DOCS_TITLE, { optional: true })\n private readonly callouts = inject(DOCS_CONFIG).callouts\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef)\n\n protected readonly labels = docsLabels()\n protected readonly root = this.docs.root\n protected readonly skeletonRows = ['38%', '92%', '84%', '96%', '60%']\n\n private readonly reload$ = new BehaviorSubject<void>(undefined)\n protected readonly index = signal<DocsIndex | null>(null)\n private readonly params = toSignal(this.route.paramMap, { requireSync: true })\n protected readonly sectionSlug = computed(() => this.params().get('section'))\n protected readonly pageSlug = computed(() => this.params().get('page'))\n\n protected readonly view = toSignal(\n combineLatest([this.route.paramMap, this.reload$]).pipe(\n switchMap(([params]) => this.load(params)),\n ),\n { initialValue: { kind: 'loading' } as DocsView },\n )\n\n protected readonly page = computed(() => {\n const view = this.view()\n return view.kind === 'page' ? view : null\n })\n protected readonly notFound = computed(() => {\n const view = this.view()\n return view.kind === 'not-found' ? view : null\n })\n\n protected readonly outline = signal<MarkdownOutlineEntry[]>([])\n protected readonly showOutline = computed(\n () => this.view().kind === 'page' && hasOutline(this.outline()),\n )\n\n // What the reader navigated to (page and `#fragment`), handled once the page is on screen.\n private wanted: { key: string; fragment: string | null; moveFocus: boolean } | null = null\n private renderedKey: string | null = null\n\n constructor() {\n effect(() => {\n const view = this.view()\n const labels = this.labels()\n this.setTitle?.(\n view.kind === 'page'\n ? view.location.page.title\n : view.kind === 'not-found'\n ? labels.notFoundHeading\n : labels.documentation,\n )\n })\n\n // Params and fragment change one after the other within a navigation, so wait for both. The first visit leaves\n // the focus alone; later ones move it, as a new page would.\n let first = true\n combineLatest([this.route.paramMap, this.route.fragment])\n .pipe(debounceTime(0), takeUntilDestroyed(inject(DestroyRef)))\n .subscribe(([params, fragment]) => {\n this.wanted = {\n key: keyOf(params.get('section'), params.get('page')),\n fragment,\n moveFocus: !first,\n }\n first = false\n this.settle()\n })\n }\n\n private load(params: ParamMap): Observable<DocsView> {\n const section = params.get('section')\n const page = params.get('page')\n return this.docs.index().pipe(\n tap((index) => this.index.set(index)),\n switchMap((index): Observable<DocsView> => {\n const location = locateDocsPage(this.root, index, section, page)\n const notFound: DocsView = { kind: 'not-found', firstPage: firstDocsPage(this.root, index) }\n if (!location) {\n return of(notFound)\n }\n return this.docs.page(location.section.slug, location.page.slug).pipe(\n map((content): DocsView => ({ kind: 'page', location, content })),\n catchError((error: unknown) =>\n of<DocsView>(isNotFound(error) ? notFound : { kind: 'failed' }),\n ),\n )\n }),\n catchError(() => of<DocsView>({ kind: 'failed' })),\n startWith<DocsView>({ kind: 'loading' }),\n )\n }\n\n protected retry(): void {\n this.reload$.next()\n }\n\n protected sectionLink(location: DocsLocation): string[] {\n return docsPageCommands(this.root, location.section.slug, location.section.pages[0].slug)\n }\n\n /** After each render: the outline, the callouts, then the pending navigation. */\n protected onRendered(entries: MarkdownOutlineEntry[]): void {\n this.outline.set(entries)\n const content = this.content()\n if (!content) {\n return\n }\n for (const quote of Array.from(content.querySelectorAll('blockquote'))) {\n const lead =\n quote.firstElementChild?.tagName === 'P' ? quote.firstElementChild.firstChild : null\n const word =\n lead instanceof HTMLElement && lead.tagName === 'STRONG'\n ? (lead.textContent ?? '').trim().toLowerCase()\n : ''\n const kind = Object.hasOwn(this.callouts, word) ? this.callouts[word] : undefined\n if (kind) {\n quote.setAttribute('data-callout', kind)\n quote.setAttribute('role', 'note')\n }\n }\n const view = this.view()\n this.renderedKey =\n view.kind === 'page' ? keyOf(view.location.section.slug, view.location.page.slug) : null\n this.settle()\n }\n\n private content(): HTMLElement | null {\n return this.host.nativeElement.querySelector<HTMLElement>('.gbt-docs-page__content')\n }\n\n /** Scrolls to the `#fragment` (an outline `user-content-…` id or the bare slug from a link), or to the top of a new page. */\n private settle(): void {\n const wanted = this.wanted\n const content = this.content()\n if (!wanted || wanted.key !== this.renderedKey || !content) {\n return\n }\n this.wanted = null\n const reduceMotion =\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches\n const target = wanted.fragment ? findAnchorTarget(content, wanted.fragment) : null\n if (target) {\n target.scrollIntoView?.({\n behavior: wanted.moveFocus && !reduceMotion ? 'smooth' : 'auto',\n block: 'start',\n })\n if (wanted.moveFocus) {\n this.focus(target)\n }\n return\n }\n if (wanted.moveFocus) {\n const heading = content.querySelector<HTMLElement>('h1')\n if (heading) {\n this.focus(heading)\n }\n this.host.nativeElement.ownerDocument.defaultView?.scrollTo?.({ top: 0 })\n }\n }\n\n // Headings aren't focusable; -1 lets the next Tab carry on from there.\n private focus(element: HTMLElement): void {\n if (element.tabIndex < 0) {\n element.setAttribute('tabindex', '-1')\n }\n element.focus({ preventScroll: true })\n }\n}\n","<gbt-page-layout\n width=\"wide\"\n asideWidth=\"sm\"\n [navLabel]=\"labels().documentation\"\n [asideLabel]=\"labels().onThisPage\"\n stickyNav\n>\n <!-- One root per projected block: a control-flow block only gets projected into a named slot that way. -->\n @if (index(); as index) {\n <gbt-docs-nav page-nav [index]=\"index\" [section]=\"sectionSlug()\" [page]=\"pageSlug()\" />\n }\n\n <div class=\"gbt-docs-page\">\n @if (page(); as page) {\n <gbt-breadcrumb class=\"gbt-docs-page__breadcrumb\" [ariaLabel]=\"labels().breadcrumb\">\n <li breadcrumb-ancestor>\n <a class=\"gbt-breadcrumb__item\" [routerLink]=\"root\">{{ labels().documentation }}</a>\n </li>\n <li breadcrumb-ancestor>\n <a class=\"gbt-breadcrumb__item\" [routerLink]=\"sectionLink(page.location)\">{{\n page.location.section.title\n }}</a>\n </li>\n {{ page.location.page.title }}\n </gbt-breadcrumb>\n\n <article class=\"gbt-docs-page__article\">\n <gbt-card variant=\"outlined\" [flush]=\"true\">\n <div class=\"gbt-docs-page__body\">\n <gbt-markdown-view\n class=\"gbt-docs-page__content\"\n [content]=\"page.content\"\n [routedLinkPrefix]=\"root\"\n (outline)=\"onRendered($event)\"\n />\n </div>\n </gbt-card>\n </article>\n\n @if (page.location.previous || page.location.next) {\n <nav class=\"gbt-docs-page__pager\" [attr.aria-label]=\"labels().neighbours\">\n @if (page.location.previous; as previous) {\n <gbt-card class=\"gbt-docs-page__neighbour\" variant=\"outlined\" hoverable>\n <span class=\"gbt-docs-page__neighbour-label\"\n >{{ labels().previous }} · {{ previous.sectionTitle }}</span\n >\n <a\n gbtCardLink\n class=\"gbt-docs-page__neighbour-link\"\n [routerLink]=\"previous.commands\"\n >{{ previous.title }}</a\n >\n </gbt-card>\n }\n @if (page.location.next; as next) {\n <gbt-card\n class=\"gbt-docs-page__neighbour gbt-docs-page__neighbour--next\"\n variant=\"outlined\"\n hoverable\n >\n <span class=\"gbt-docs-page__neighbour-label\"\n >{{ labels().next }} · {{ next.sectionTitle }}</span\n >\n <a gbtCardLink class=\"gbt-docs-page__neighbour-link\" [routerLink]=\"next.commands\">{{\n next.title\n }}</a>\n </gbt-card>\n }\n </nav>\n }\n } @else if (notFound(); as notFound) {\n <gbt-card class=\"gbt-docs-page__not-found\" variant=\"outlined\">\n <gbt-empty-state\n illustration=\"book\"\n [headingLevel]=\"1\"\n [heading]=\"labels().notFoundHeading\"\n [message]=\"labels().notFoundMessage\"\n >\n @if (notFound.firstPage; as firstPage) {\n <a gbtButton variant=\"primary\" [routerLink]=\"firstPage\">{{ labels().toStart }}</a>\n }\n </gbt-empty-state>\n </gbt-card>\n } @else if (view().kind === 'failed') {\n <gbt-alert class=\"gbt-docs-page__failed\" variant=\"error\" appearance=\"subtle\">\n {{ labels().loadFailed }}\n <gbt-button\n alert-actions\n variant=\"secondary\"\n size=\"small\"\n iconName=\"refresh-cw\"\n [text]=\"labels().retry\"\n (clicked)=\"retry()\"\n />\n </gbt-alert>\n } @else {\n <div class=\"gbt-docs-page__loading\" aria-busy=\"true\">\n <span class=\"gbt-docs-page__status\" role=\"status\">{{ labels().loading }}</span>\n <gbt-card variant=\"outlined\" [flush]=\"true\" aria-hidden=\"true\">\n <div class=\"gbt-docs-page__loading-card\">\n @for (width of skeletonRows; track $index) {\n <gbt-skeleton [width]=\"width\" [height]=\"$first ? '1.75rem' : '0.875rem'\" />\n }\n </div>\n </gbt-card>\n </div>\n }\n </div>\n\n @if (showOutline()) {\n <div page-aside class=\"gbt-docs-page__aside\">\n <gbt-markdown-outline [entries]=\"outline()\" />\n </div>\n }\n</gbt-page-layout>\n"],"mappings":"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"}