Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 4x 101x 101x 101x 4x 336x 1x 11x 1519x 87x 41x 41x 41x 19x 21x 21x 21x 21x 21x 21x 21x 21x 20x 35x 20x 20x 18x 13x 13x 33x 33x 13x | /**
* Navigation utilities.
*
* All navigation is driven by content/navigation.md — a plain markdown list.
* Edit that file to add, remove, reorder, or nest pages and categories.
*/
import { parseNavigationMd, type NavCategory, type NavGroup, type NavPage, type NavTab } from './parse-navigation-md';
export type { NavCategory, NavGroup, NavPage, NavTab };
let _cached: NavCategory[] | null = null;
function load(): NavCategory[] {
const isDev = process.env.NODE_ENV === 'development';
if (isDev || !_cached) _cached = parseNavigationMd();
return _cached;
}
export function getNavigation(): NavCategory[] {
return load();
}
export function getAllPages(): NavPage[] {
return load().flatMap((c) => c.children);
}
export function getAllNavCategories(): NavCategory[] {
return load();
}
export function getPageBySlug(slug: string): NavPage | undefined {
return getAllPages().find((p) => p.slug === slug);
}
export function getPagesByCategory(category: string): NavPage[] {
return getAllPages().filter((p) => p.category === category);
}
export function getCategoryBySlug(slug: string): NavCategory | undefined {
return load().find((c) => c.slug === slug);
}
/**
* The nav page a route URL renders: the page itself, or the page that lists it
* as a tab. Matching on the URL (not the bare slug) keeps same-named pages in
* different categories apart (`/components/icons` vs `/icons/usage`).
* A tab file missing from the nav falls back to its parent page (`/cat/page--tab` → `/cat/page`).
*/
export function getPageByUrl(url: string): NavPage | undefined {
const pages = getAllPages();
const parentUrl = url.split('--')[0];
return (
pages.find((p) => p.url === url) ??
pages.find((p) => p.tabs?.some((t) => t.url === url)) ??
pages.find((p) => p.url === parentUrl)
);
}
/** Category › Group › Page. A label group has no page, so its crumb has no URL. */
export function getBreadcrumbs(page: NavPage): { name: string; url?: string }[] {
const crumbs: { name: string; url?: string }[] = [];
Eif (page.category) {
const category = getCategoryBySlug(page.category);
Eif (category) crumbs.push({ name: category.name, url: `/${category.slug}` });
}
if (page.group) crumbs.push({ name: page.group.name, url: page.group.url });
crumbs.push({ name: page.name, url: page.url });
return crumbs;
}
export function getAdjacentPages(page: NavPage): { prev: NavPage | null; next: NavPage | null } {
if (!page.category) return { prev: null, next: null };
const categoryPages = getPagesByCategory(page.category);
const idx = categoryPages.findIndex((p) => p.url === page.url);
Iif (idx === -1) return { prev: null, next: null };
return {
prev: idx > 0 ? categoryPages[idx - 1] : null,
next: idx < categoryPages.length - 1 ? categoryPages[idx + 1] : null,
};
}
/**
* Given a page and the URL being rendered, return the page's tab list with the
* active tab marked. The first tab links to the parent URL so
* `/components/badge` and `/components/badge--usage` share a tab.
*/
export function getTabContext(
parent: NavPage,
url: string,
): {
parent: NavPage;
tabs: { name: string; url: string; active: boolean }[];
} | null {
if (!parent.tabs || parent.tabs.length === 0) return null;
const isOnParent = url === parent.url;
const tabs = parent.tabs.map((t, i) => {
const isFirst = i === 0;
return {
name: t.name,
url: isFirst ? parent.url : t.url,
active: isFirst ? isOnParent || t.url === url : t.url === url,
};
});
return { parent, tabs };
}
|