feat(masthead): navigation built from the documentation manifests - #112
Open
oto-macenauer-absa wants to merge 1 commit into
Open
oto-macenauer-absa wants to merge 1 commit into
oto-macenauer-absa wants to merge 1 commit into
Conversation
oto-macenauer-absa
force-pushed
the
feat/masthead-nav
branch
2 times, most recently
from
September 30, 2026 09:54
4deada2 to
2c06445
Compare
The masthead's navigation is scoped to the app being viewed: Library, the app's name, then that app's own entries from its kb-docs.json `pages` — a page without a `section` as a link, a section as a dropdown of its pages, placed where its first page falls in `order`. A publisher adds a page to the menu without a knowledge base change, and the bar does not grow with the number of apps: the catalog is the way between them. The model is built once per resolved registry (src/utils/navigation.js) and shares route derivation with apps.js, so every menu link resolves to a built page. Tablet first: below 1024px a compact bar (Library, current app, and a Menu button for an app with manifest pages) opens a popover sheet of the app's pages; from 1024px a wrapping bar with <details> dropdowns. Both work without script; masthead-nav.js adds Escape, outside-click and edge-flip to the dropdowns, taking the real window from event.view because reframed reports its iframe's document as the masthead's ownerDocument. The current page carries aria-current="page", the app and section holding it aria-current="true". The brand wordmark on app pages moves out of flow into the left gutter, shown from 90rem where the gutter holds it: as a flex item it took its width out of the centred column and moved every link away from where it sits on the catalog. The vendored docs-example fixture gains a third app, `handbook`, with a two-section manifest, so the app-scoped menu and exclusive dropdowns are exercised and visible in a local build. Closes #111 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
oto-macenauer-absa
force-pushed
the
feat/masthead-nav
branch
from
September 30, 2026 11:12
2c06445 to
d347606
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #111
What
The masthead navigation is scoped to the app being viewed, built from its
kb-docs.jsonpages:sectionis a link of its own; asectionis one dropdown of its pages, placed where its first page falls inorder. Adding a page to a manifest adds it to the menu; no knowledge base change.pagesmanifest (crawled, single-page, iframe) shows just its name.<details name>(exclusive).aria-current="page", the app and section holding itaria-current="true"; visible focus ring; everything keyboard-operable. No-JS core:<details>and the Popover API bring toggling, Escape and light dismiss.src/scripts/masthead-nav.jsadds Escape / outside click / tab-out / right-edge flip for the bar dropdowns.How
src/utils/navigation.js— nav model built once per resolved registry (navigationFor, memoised), never passed throughgetStaticPathsprops (keeps the Performance: sub-app assets are copied twice and the whole registry is duplicated into every page's props #51 memory fix). Each app carriesitems:pageandsectionentries in manifest order.pageRelDir()/routeHref()shared withapps.js, so a menu link cannot point where no route was built.Masthead.astro+NavPages.astro— both renderings of the current app's entries; CSS switches at 1024px.Brand wordmark
On app pages the "Knowledge base" wordmark was a flex item beside the centred 72rem column, which took its width out of the column and moved every link (Library at x=508 instead of the catalog's 424 at 1920px). It is now out of flow in the left gutter, shown from 90rem where the gutter holds it, so the links sit exactly where they do on the catalog at every width.
Fixture
tests/fixtures/docs-example.kb-docs.tar.gzgains a third app,handbook(same page tree asguide-mirror), with a two-section manifest —Showcase | Getting started ▾ | Authoring ▾— so exclusive dropdowns are exercised and the feature is visible innpm run build:local && npm run preview.user-guidestays crawled andguide-mirrorunchanged. Repacked withactions/lib/pack.js(deterministic); 4.2 → 5.7 MB.Found along the way
<script>in place, which put it between the masthead and the sub-app content and broke the "next sibling is the app" contract (css-isolation failures). The script now sits inside the masthead.ownerDocumentandgetRootNode(), so an outside-click listener there never saw host clicks. The script takes the real window from the opening click'sevent.view.Behaviour changes
build-integrity.spec.jsrewritten accordingly. Three standalone tests that clicked "the first internal link" (now Library) target a catalog card.contract/ARTIFACT.mddocumentssectionas "one masthead dropdown".Tests
tests/navigation.spec.js(new) — ordering, section entries and interleaving, omitted entry point, iframe entries, memoisation.build-integrity.spec.js— catalog shows Library alone; handbook's two dropdowns and their pages; an app page shows only its own entries in manifest order; section dropdown contents; apps without a manifest show nothing after their name; every menu link resolves to a built page;aria-currentper page type; compact sheet contents.standalone.spec.js— 320–1920px: right rendering, zero horizontal overflow or clipped control; Library at the catalog's x on app pages, brand never covering it; exclusive section dropdowns (handbook); sheet contents, close/Escape; entries follow the app across navigation; keyboard operation, focus ring, outside click, tab-out, navigation.web-fragment.spec.js— section dropdown and sheet inside the fragment, before and after router swaps (app → Library → app), both embeddings (plain + pierced).css-isolation.spec.js— runs at 1600px so the brand is part of the compared masthead.Local:
npm test446 passed;playwright.config.ci.js38 passed.test:containernot run (Docker).🤖 Generated with Claude Code