site-chrome-navigation
The chrome around every page on sahin.io/angel-investments — static header and mega menu, React NavBar, SiteSidebar, MobileSectionNav, footer, breadcrumbs — and the YAML that drives them (navigation.yaml, chrome.yaml, page-crumbs.yaml). Use when building, rebuilding or changing the menu, a menu page's label/title/description, the sidebar, the mobile tabs, the footer or breadcrumbs.
- Source file
.claude/skills/site-chrome-navigation/SKILL.md
Site chrome and navigation
What it is
Two copies of the same chrome, fed by the same YAML:
- Static (
server/publicChrome.ts): written into every pre-rendered document byrenderDocument()inserver/seoRouteManifest.ts—renderSiteHeader()(brand +<details class="site-mega-menu">built fromPUBLIC_NAVIGATION_SECTIONS),renderBreadcrumbNav()(<nav class="crumb">),renderSiteFooter()(Category and Sub-Category chips fromfacts.derived, firstFOOTER_SUBCATEGORY_PREVIEW= 18 sub-categories then a show-all toggle, social links, editorial links).siteNavigationLinks()adds About and the deck CTA (the/aboutand/pitchroutes when they exist, else the person URL and a mailto). - React (
client/src/components/):NavBar.tsx(header,ThemeSwitcher,GlobalSearch, and it mountsSiteSidebar.tsx+MobileSectionNav.tsx),Footer.tsx(SPA hub only), shared helpers insiteNavigation.ts(NAV_SECTIONS,MENU_COPY,SECTION_ICONSby section id,EXTRA_LINKS,isCurrent,sectionForPath,usePagePath).
On a React page, server/publicReactDocument.ts drops the static header, keeps the static
breadcrumb and footer HTML and hands them to PublicReactPageView as ServerChrome
(data-server-crumb, data-server-footer divs), so crumbs and footer are identical on both
paths. App.tsx pads content by var(--app-sidebar-width); the sidebar collapsed state is in
localStorage key sidebar-collapsed (SIDEBAR_STORAGE_KEY).
Files
| File | Role |
|---|---|
content/shared/navigation.yaml |
hub (Portfolio entry), sections (id, label, ordered pages paths; / is the hub), pages (every menu page: path, label, title, description), compactLinks |
content/shared/chrome.yaml |
brand, menu, sidebar, breadcrumb, head, footer, search copy; placeholders {name}, {handle}, {section}, {query}, ... |
content/pages/page-crumbs.yaml |
breadcrumb names of React SINGLE_PAGES outside the menu, by path (pageCrumbCopy() in server/staticPageCopy.ts) |
client/src/generated/copy/shared/navigation.ts, chrome.ts |
generated by node scripts/sync-site-copy-module.mjs; never edit by hand |
shared/publicNavigation.ts |
LEGACY_MENU_PAGES, PUBLIC_NAVIGATION_SECTIONS, PUBLIC_NAVIGATION_ITEMS, EXPLORE_PATH |
server/publicChrome.ts |
static header/menu/crumb/footer, PUBLIC_PAGE_CSS, headSpec, renderHead |
client/src/lib/themeVars.ts |
tv() / tvMix() colours used by all React chrome (see theme-system) |
How it works
- Sections:
explore,insights,stories,research,specs(ids are stable keys for icons and element ids; change labels, never ids). Each menu page belongs to exactly one section. - A section may add
links(label + path, e.g./skills-and-agents#sna-agentsanchors) after its pages; they render in every menu but are not routes.specsholds/skills-and-agentsplus anchors to its Foundation, Pages, Quality & Ship and Agents groups;sectionForPath()also matches detail pages under an item's path (/skills-and-agents/{name}→ Specs). - Every
pagesentry becomes alegacyFeatureroute increateSeoRouteManifest()(LEGACY_MENU_PAGES→route(page.routePath, "legacyFeature", page.title)), unless a reviewed editorial singleton owns the path (e.g./thesis). Itstitleis the<title>; itsdescriptionis the meta description for paths inMENU_DESCRIPTION_FEATURES, else the recovery-surface intro (RECOVERY_SURFACE_BY_PATH,content/pages/recovery-surfaces.yaml). - Breadcrumbs: hub crumb (
hubCrumb()) then the page. React shell pages use the spec'scrumb(SINGLE_PAGES from page-crumbs.yaml; FAMILIES derive it from their title). Company crumbs add the primary Category. The JSON-LDBreadcrumbListuses the same list (seeseo-head-and-schema). scripts/generate-static.tsfails the build if any page lacks anhreffromNAVIGATION_HREFS(every section link), so the menu stays crawlable on React pages.
How to change
- Add a menu page: add
path/label/title/descriptionunderpagesand the path under one section innavigation.yaml; runnode scripts/sync-site-copy-module.mjs; build the page (new-react-page, or a staticlegacyFeaturebody); give it a URL perpublic-url-conventions. - Rename/reorder: edit labels or order in YAML only. Code matches pages by path, never by label.
- Add a non-menu React page crumb: add
/path: Nametopage-crumbs.yaml(itsSinglePage.pathtype iskeyof ReturnType<typeof pageCrumbCopy>, so a missing crumb is a type error). - Footer/header wording:
chrome.yamlonly (page-content-yaml).
Rebuild from scratch
- Write
navigation.yaml,chrome.yaml,page-crumbs.yaml; run the copy sync. shared/publicNavigation.tsmaps YAML into sections/items with/angel-investmentshrefs.- Static chrome in
server/publicChrome.ts;renderDocument()composes header,<main class="shell">, crumb, body, footer. - React chrome:
NavBar+SiteSidebar+MobileSectionNavusingsiteNavigation.tsandtv()colours;App.tsxlayout. PublicReactPageViewrenders server crumb/footer HTML around React pages.deploy-gate→ui-before-after(desktop and mobile; sidebar and mobile tabs) →ship-to-production.
Tests
server/shared-content.test.ts (menu, sections, placeholders; static header/menu/footer/crumb
copy), server/seo-route-manifest.test.ts, server/public-react-document.test.ts (server
crumb/footer inside React pages), server/public-schema.test.ts (BreadcrumbList),
server/content-in-yaml.test.ts.