Menubar enrichment, column flow, and strip layout — engine + CSS + behavior
Implement the three coordinated nav changes from SPEC-054 end-to-end:
Implement the three coordinated nav changes from SPEC-054 end-to-end:
5586b0d12288ac4fdcd57ce1a0f6nav rune layout attribute accepts strip in addition to existing values (vertical, menubar, columns, cards); no mega value added.rf-nav--strip modifier class and data-layout="strip"## groups accept arbitrary block content: lists, paragraphs, blockquotes, images, nested {% nav %} runes. No content type is rejected at the schema level## group renders into data-name="intro" (class .rf-nav-group__intro)## group renders into data-name="footer" (class .rf-nav-group__footer)columns layout: <hr> between ## sections at the nav's top level opens a new .rf-nav-group__column — each column stacks one or more ## sectionscolumns layout (headingless mode): when the nav has no ## sections, <hr> between flat items splits items into columnscolumns layout (backwards compat): a nav with ## sections and no <hr>s renders one column per section (today's footer behaviour, unchanged)strip layout: renders a flat row of items, no top-level container, no groupsstrip layout: rejects ## headings via ctx.warn and degrades gracefully (heading treated as plain text)strip layout: supports standard nav features (slug resolution, active state, frontmatter enrichment, inline badges).rf-nav-item__description (works in any layout){% badge %} appears inside or after a nav item's link text, the engine attaches it as a badge property on the item (rendered adjacent to the title).rf-nav--columns updated for both the multi-section-column-flow rule and the headingless mode.rf-nav--strip (compact horizontal row, smaller text, muted base styling, mobile-friendly wrap).rf-nav-item__description styled (smaller text, muted colour, line-height tightened).rf-nav--strip, .rf-nav-group__intro, .rf-nav-group__column, .rf-nav-group__footer, .rf-nav-item__description## group becomes a tappable accordion sectioncolumns inside an open menubar panel: items render in a single stacked column (Linear-style flat scroll)columns collapsible=true with ## sub-sections inside an open menubar panel: each sub-section becomes an accordion toggle (Vercel-style structured collapse)## group whose nav items match (or prefix) the current page URL auto-expands; mirrors the existing collapsible vertical-layout behaviour@refrakt-md/behaviors nav-menubar module extended to handle the drawer + accordion toggles for the richer panel structure — no new behaviour modulevertical, cards) render identically — no regressions<hr>s) render identically — same HTML, same CSS treatmentnpx refrakt inspect nav --layout=menubar shows expected HTML output with intro / footer slots populated for a representative rich-content inputnpx refrakt inspect nav --layout=columns shows expected HTML output for both multi-section-column-flow and headingless modesnpx refrakt inspect nav --layout=strip shows expected HTML output<hr>), columns headingless mode (between-item <hr>), strip layout rejecting ## groups, badge attachment on a nav itemSchema work first. Extend packages/runes/src/tags/nav.ts — specifically headingsToList and buildGroups.
Menubar group content detection:
headingsToList produces the group's content array (heading + following children), walk the children in source order.<ul>/<ol>): paragraphs, blockquotes, images, nested Tag runes (including nested {% nav %} outputs).intro property on the group.footer property on the group.Columns layout column-flow detection:
<hr> into segments.column entry on the Nav.## sections (each a sub-block), or a flat list of items in headingless mode.Strip layout:
buildGroups entirely; produce a flat <ul> of items.## heading: ctx.warn('Strip nav at <source> contains heading "<X>" — strip is flat; the heading will render as plain text') and proceed.Badge attachment:
navItem transform, walk the item's link text and trailing content.{% badge %} rune output is found (tag with data-rune="badge"), consume it and attach as a badge property on the item.Engine config (packages/runes/src/config.ts). Add structure entries:
NavGroup: add intro, footer slot entries.NavItem: add description, badge slot entries.Use existing structure and properties patterns as the template.
Lumina CSS (packages/lumina/styles/runes/nav.css). Add new sections:
/* Menubar panel: auto-size to content */ .rf-nav--menubar .rf-nav-group[data-state="open"] > /* panel content */ { width: max-content; max-width: 80vw; } .rf-nav-group__intro { margin-bottom: var(--rf-space-md); } .rf-nav-group__intro p { font-size: 0.875em; color: var(--rf-color-muted); } .rf-nav-group__intro blockquote { /* featured hero: larger, accent border */ } .rf-nav-group__footer { margin-top: var(--rf-space-md); padding-top: var(--rf-space-md); border-top: 1px solid var(--rf-color-border); } .rf-nav-item__description { font-size: 0.875em; color: var(--rf-color-muted); } /* Columns: multi-section per column */ .rf-nav--columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: var(--rf-space-md); } .rf-nav--columns .rf-nav-group__column { /* one column, may contain multiple ## sections */ } /* Strip: compact horizontal row */ .rf-nav--strip { display: flex; gap: var(--rf-space-md); padding: var(--rf-space-sm) 0; font-size: 0.875em; } .rf-nav--strip .rf-nav-item__link { color: var(--rf-color-muted); } /* Mobile collapse */ @media (max-width: ...) { /* Drawer opens, columns stack, strip wraps */ }
Behaviors (packages/behaviors/src/). Extend the existing nav-menubar module. The DOM contract is the same (trigger button + panel container). On mobile, the drawer opens and accordion toggling proceeds as today; the richer panel content just renders inside the open section. No new behaviour module needed.
Backwards-compat verification. Build the site before and after; diff the HTML for every existing nav. Should be byte-identical except for the migrations and enrichment changes from WORK-233 and WORK-235.
{% badge %} rune must exist before menubar items can recognise and attach badgespackages/runes/src/tags/nav.ts — Existing nav schema; extension targetpackages/runes/src/config.ts — Engine config; new slots land herepackages/lumina/styles/runes/nav.css — Reference CSS; menubar / columns / strip sections added or extendedpackages/behaviors/src/ — nav-menubar behavior; extension targetBranch: claude/v0-14-3-nav-milestone-planning
packages/runes/src/tags/nav.ts). The transform now produces a ParsedGroup | ColumnBreak sequence from the transformed children, preserving every non-list block inside each ## group. Added:parseNavStructure: walks the children, tracks top-level items, opens groups on <h*>, treats top-level <hr> as a column-break marker, collects everything else into the current group's children array.partitionGroupChildren: classifies a group's children into intro / body / footer per SPEC-054's position rule. First non-list block → intro; last non-list block (only if it differs from intro) → footer; everything else renders in source order as the body.buildGroupTag: renders a group with <div data-name="intro">… and <div data-name="footer">… wrappers around the slot content.bucketColumns: buckets the parsed sequence into columns separated by column-break markers (used by the columns layout).parseNavStructure entirely and produces a flat list of items. Sets data-layout="strip" and emits no top-level container.<hr> between ## sections at the top level, groups are bucketed into <div data-name="column"> wrappers — each column stacks one or more <section data-rune="nav-group">s. Backwards-compatible: a columns nav with no <hr> still renders one group per column without the wrapper (existing CSS keeps working).## sections and uses <hr> between items, the schema splits the flat items into <div data-name="column"> wrappers each containing a <ul> of items. Used inside menubar panels for unlabeled columns.navItem transform. A paragraph following a list item in source (CommonMark indented continuation) gets attached as <p data-name="description"> under the item, alongside the link. Works for both slug-based and explicit-link items.navItem transform. When a {% badge %} rune appears in or after a list item's link text, the engine sets data-name="badge" on it and keeps it as a child of the nav-item alongside the link and description.packages/runes/src/config.ts). No structural slot additions needed — the schema emits <div data-name="intro">, <div data-name="footer">, <div data-name="column">, <p data-name="description">, <span data-name="badge"> directly, and the engine's applyBemClasses translates each data-name to its .rf-{block}__{name} class automatically.packages/lumina/styles/runes/nav.css). Added new sections at the end:.rf-nav-item__description — universal description styling (smaller, muted, tightened line-height).:has()) when intro/footer/nested-nav present; intro blockquote → card-shaped hero with accent border; intro paragraph-only → uppercase eyebrow; footer → top-border divider with muted paragraph..rf-nav__column / .rf-nav-group__column flex-stack vertically; outer .rf-nav--columns:has(> div[data-name="column"]) switches to grid layout for the column wrappers.site/content/_layout.md footer region to use the new column-flow rule — added --- between "Documentation" and "Resources / Project" so the footer now renders as two columns (Documentation alone in column 1; Resources + Project stacked in column 2).site/content/docs/authoring/rich-menubar-panels.md with 11 live {% preview source=true %} examples covering every pattern: simple menubar, nested columns, blockquote hero, eyebrow paragraph, footer slot, per-item descriptions, inline badges, multi-section columns flow, headingless columns, strip layout, Linear vs Vercel mobile patterns.nav rune reference updated. site/content/runes/nav.md gained a strip layout section and a pointer to the rich-menubar-panels authoring page.authoring/rich-menubar-panels added to the Authoring group in site/content/docs/_layout.md.packages/runes/src/tags/nav.ts — schema refactor (~150 lines added)packages/lumina/styles/runes/nav.css — new CSS sections (~140 lines added)packages/runes/test/nav-richer-dropdowns.test.ts — 12 new testssite/content/_layout.md — footer multi-section column demosite/content/docs/_layout.md — docs sidebar nav entrysite/content/docs/authoring/rich-menubar-panels.md — new authoring pagesite/content/runes/nav.md — reference updatesnav-richer-dropdowns.test.ts cover: menubar slot detection (none / intro-only / blockquote intro / footer / single-content / standalone), columns multi-section flow (none / 3-column split / headingless 2-column), strip layout, nested columns in menubar group, per-item descriptions. All pass./index.html shows 2 <div data-name="column"> wrappers)./runes/rune-catalog/ still enriches items (18 each of .rf-nav-item__icon / __title / __description — unchanged from before this work)./docs/authoring/rich-menubar-panels renders 6 intros, 3 footers, 7 column wrappers, and 4 strip-layout instances across its 11 preview blocks./docs/themes/overview/ still renders 7 groups (Guide / CLI / Theme authoring / Adapters / Authoring / Packages / MCP Server) with collapsible accordions intact.nav-menubar and nav-collapsible behaviour modules handle the menubar drawer + accordion toggles. Lumina CSS adjusts the mobile reflow for the new slots (intro/footer stack vertically, columns collapse to single column). No new JS behaviour modules required.collapsible vertical layout has URL-aware auto-expand. Replicating that for menubar mobile drawer is a follow-up — the data is there (resolved hrefs + current URL), but threading it requires a behaviour module change.## headings — the schema currently renders headings as plain content rather than warning. The ctx context isn't available at schema time. A future enhancement could emit a sentinel meta that a postProcess hook turns into a ctx.warn. Low priority — strip is opt-in and authors will quickly notice headings disappearing visually.:has() browser support — the auto-widening of menubar panels for rich content uses CSS :has(). Supported in all modern browsers (Chrome 105+, Safari 15.4+, Firefox 121+); themes that need older support can use a data-rich-panel attribute approach instead, but Lumina targets modern browsers.