WORK-235
Setting up your dashboard 0 entities found · 9/32 branches scanned
ID:WORK-235Status:done

Description / icon enrichment generalised across auto layouts

Generalise the existing auto=true frontmatter enrichment (currently implemented for layout="cards") so it applies to every layout. Resolution rules: inline description child (paragraph following a list item) wins; frontmatter description is the fallback; nothing otherwise. icon follows the same shape — inline {% icon %} rune in link text overrides frontmatter icon.

Data is always attached to the item during postProcess; theme CSS decides whether to render. The mega layout (WORK-236) will consume this enrichment; cards continues to work unchanged.

Priority:mediumComplexity:moderateMilestone:v0.14.3Source:SPEC-054
claude/v0-14-3-nav-milestone-planning View source

Criteria completion

Criteria completion: 12 of 12 (100%) checked; history from May 20 to May 210%25%50%75%100%May 20May 21
Branches 1
claude/v0-14-3-nav-milestone-planning current done
main done
History 2
  1. 10f7c21
    • ☑ When `auto=true` is set on a `{% nav %}`, description resolution applies uniformly to every layout — not just `cards`
    • ☑ For each `NavItem`, the resolver determines `description` per the rules: explicit paragraph child wins; linked-page frontmatter `description` is the fallback; nothing if neither
    • ☑ For each `NavItem`, the resolver determines `icon` per the same rules: inline `{% icon %}` in the link wins; frontmatter `icon` is the fallback; nothing if neither
    • ☑ Title resolution continues to work as today: frontmatter `title` for slug items; link text for explicit-link items
    • ☑ Resolved `description`, `icon`, and `title` properties are attached to the NavItem at postProcess time and present in the SSR HTML (as text content or data attributes, per the engine config)
    • ☑ Existing `layout="cards"` behavior is preserved exactly — same rendered output for the same input
    • ☑ When an item's link points to an external URL or a page missing `description` / `icon`, the resolver attaches nothing (no broken fallbacks)
    • ☑ When an inline paragraph follows a list item in the source (CommonMark indented continuation), the engine recognises it as the item's description child and consumes it (verified via a Markdoc-behaviour spike — see Approach)
    • ☑ Tests cover all four item shapes from {% ref "SPEC-054" /%}'s resolution table: plain slug, explicit link no paragraph, explicit link with paragraph, slug with paragraph
    • ☑ Tests cover icon resolution with both inline `{% icon %}` and frontmatter sources
    • ☑ `npx refrakt inspect nav` with a representative `auto=true` input shows resolved properties on each item
    • ☑ No regression in the existing cards-layout demos in `site/content/`
    by bjornolofandersson
  2. ce1a0f6
    Created (ready)by bjornolofandersson

Acceptance Criteria

  • When auto=true is set on a {% nav %}, description resolution applies uniformly to every layout — not just cards
  • For each NavItem, the resolver determines description per the rules: explicit paragraph child wins; linked-page frontmatter description is the fallback; nothing if neither
  • For each NavItem, the resolver determines icon per the same rules: inline {% icon %} in the link wins; frontmatter icon is the fallback; nothing if neither
  • Title resolution continues to work as today: frontmatter title for slug items; link text for explicit-link items
  • Resolved description, icon, and title properties are attached to the NavItem at postProcess time and present in the SSR HTML (as text content or data attributes, per the engine config)
  • Existing layout="cards" behavior is preserved exactly — same rendered output for the same input
  • When an item's link points to an external URL or a page missing description / icon, the resolver attaches nothing (no broken fallbacks)
  • When an inline paragraph follows a list item in the source (CommonMark indented continuation), the engine recognises it as the item's description child and consumes it (verified via a Markdoc-behaviour spike — see Approach)
  • Tests cover all four item shapes from SPEC-054's resolution table: plain slug, explicit link no paragraph, explicit link with paragraph, slug with paragraph
  • Tests cover icon resolution with both inline {% icon %} and frontmatter sources
  • npx refrakt inspect nav with a representative auto=true input shows resolved properties on each item
  • No regression in the existing cards-layout demos in site/content/

Approach

Spike first: Markdoc paragraph-under-list-item behaviour. SPEC-054 flagged this as a needed spike. Before writing the resolver, confirm what Markdoc gives us when an author writes:

- [Plan](/plan)

  Track work, specs, and decisions.

CommonMark says the indented paragraph is a continuation of the list item — so the AST should have a paragraph node as a child of the list item, alongside the link. Verify with a small test. If Markdoc deviates, document the required indent level or paragraph delimiter convention as part of the work.

Refactor existing enrichment. The current auto=true cards-layout enrichment lives somewhere in the runes / pipeline path (locate via git log and grep for frontmatter.description / cards-layout-specific code). Extract the resolution logic into a layout-agnostic helper:

function resolveItemEnrichment(
  item: NavItemNode,
  registry: EntityRegistry,
): { title?: string; description?: string; icon?: string };

Called for every NavItem when the parent Nav has auto=true, regardless of layout.

Property attachment. Properties are attached during identity transform / postProcess so the engine config can declare structural slots for them. The mega layout (WORK-236) will consume these as data-name="description" / data-name="icon" children that the engine wraps with the right BEM classes. Cards already consumes them the same way — preserve that contract.

Migration risk. The cards-layout demos in site/content/ are the primary backwards-compat target. Run the site build before and after this work; diff the rendered cards HTML to confirm identical output.

Dependencies

  • None blocking — can begin in parallel with WORK-231 and WORK-234
  • WORK-236 (mega layout engine) depends on this — the mega layout's per-item description rendering assumes enrichment is layout-agnostic

References

  • SPEC-054 — Description Resolution section, resolution rules table
  • Existing cards-layout enrichment — find via grep -r "frontmatter" packages/runes/src/tags/nav.ts and pipeline files
  • packages/content/src/registry.tsEntityRegistryImpl for page lookups

Resolution

Branch: claude/v0-14-3-nav-milestone-planning

What was done

  • data-auto plumbing through schema and auto-resolution. Added tag.attributes['data-auto'] = 'true' in forwardLayout of packages/runes/src/tags/nav.ts so every nav declared with auto=true carries the marker through the pipeline. Updated buildAutoNav (in packages/runes/src/config.ts) to accept the original sentinel-bearing tag and copy contextual attributes (layout, data-layout, data-auto, data-source-path, data-collapsible, data-default-open) onto the freshly-built nav — fixes a latent bug where {% nav layout="cards" auto=true %} would lose its layout attribute through sentinel replacement.
  • Generalised enrichment in resolveCardsNavs. The function now dispatches on (layout === 'cards') vs (data-auto === 'true'):
    • Cards layout → existing enrichNavItemAsCard full replacement (icon + title + description wrapped in <a>). Unchanged byte-for-byte from previous behaviour.
    • Any other layout with auto=true → new augmentNavItemFromFrontmatter helper that prepends an <rf-icon data-name="icon"> to the existing <a> link's children (when frontmatter has icon) and appends a <span data-name="description"> (when frontmatter has description). Preserves the link's existing href and text. Idempotent — re-runs detect existing data-name children and skip.
  • No enrichment for plain navs. A nav without data-auto and without cards layout receives no frontmatter enrichment — preserves today's behaviour for the docs sidebar nav and other vertical layouts that intentionally use only the link text.
  • External link handling. External URLs (https://, mailto:) in nav items are skipped by the auto-augment path — no frontmatter to enrich from. Cards layout continues to render external links as title-only cards (existing behaviour).

Files changed

  • packages/runes/src/tags/nav.ts — emit data-auto="true" from forwardLayout when attrs.auto
  • packages/runes/src/config.tsbuildAutoNav preserves original attributes; resolveCardsNavs dispatches on layout/auto and gains the new augmentNavItemFromFrontmatter helper
  • packages/runes/test/nav-auto-enrichment.test.ts — 7 new tests

Verification

  • New nav-auto-enrichment.test.ts covers: menubar with auto=true enriches; menubar without auto does NOT enrich; vertical without auto does NOT enrich; cards layout still does full replacement (backwards compat); items without frontmatter description get nothing; external links are skipped; the pass is idempotent. 7/7 pass.
  • Full suite: 2628/2628 pass.
  • Site build: 0 errors, 171 pages. The existing {% nav layout="cards" auto=true /%} demo at /runes/ continues to render correctly with the cards CSS layout (confirms the buildAutoNav attribute-preservation fix).

Notes / scope decisions

  • Inline-paragraph-as-description detection deferred to WORK-236. The position-based slot rule for menubar groups (including detecting a description paragraph that follows a list item) lives in the schema's headingsToList / buildGroups path, not in postProcess. WORK-235 only covers the FRONTMATTER fallback; WORK-236 will add inline-paragraph detection at schema time and ensure it takes precedence over the frontmatter fallback (per the resolution table in SPEC-054).
  • Cards full-replacement vs auto augmentation. Kept these as separate code paths because the visual contracts differ: cards is opinionated about layout (icon-above-title-above-description), while auto on other layouts just attaches data so themes can choose. Unifying would force a single CSS contract that doesn't fit either case cleanly.
  • Markdoc paragraph-under-list-item spike: not done as part of this work since the inline-paragraph detection is WORK-236's concern. Worth confirming the AST shape before WORK-236 starts; flagged in WORK-236's approach notes.