Acceptance Criteria
- A link whose target is a drawer on the same page —
[x](#id), {% link href="#id" %} or an actions item — gets the drawer's anchor and data-target-type="drawer", and opens the drawer (D10) #drawer-<id> is accepted as well as #<id>; a drawer wins over a heading with the same id; a link to an id no drawer has is left unchangedref and file-ref triggers render as before- The drawer reference page documents triggering a drawer from a link, an
actions item and ref Actions declares contextModifiers: { bar: 'in-bar' }, and .rf-actions--in-bar appears in both copies of the structure contract (D11)- Lumina styles
.rf-actions--in-bar: compact (the badges' height), tonal rather than filled, no fill on a primary action, an icon before the label; the skeleton keeps the row structural; CSS coverage passes - An
actions region whose items are links with an icon in their text ranks the first as primary, asserted by a test - The intro data carries
sourceUrl, the file on GitHub, built from the site's repoUrl and repoBranch (D12) - The partial declares the Source drawer (
{% drawer id="rune-source" %} around {% snippet path=$row.source /%} and the GitHub link) — or, if snippet cannot take $row.path inside data, file-ref gains a drawer id and the resolution records why - The partial's right group is
{% actions %} with Install (plugin runes only) and Source, each an icon and a label; the WORK-706 pipeline test passes against it - Reviewed on a built page, light and dark, at 1280px and 390px: the actions read as actions, not prose links and not buttons, and match each other
Approach
- The link rewrite belongs where drawer ids are known for the page (
packages/runes/src/drawer-pipeline.ts collects hoisted drawers); a link to a declared drawer must be found the same way. actions already reads its size from --action-padding / --action-font-size, which marquee sets. The bar context sets them too, and the tonal look keys on .rf-actions--in-bar.- Links that are values inside bars (the plan plugin's) are out of scope and keep prose styling.
References
- SPEC-187: D3, D10, D11, D12.
- WORK-706: the partial this changes.
Resolution
Completed: 2026-11-04
Branch: claude/composition-usage-rune-pages-c87ar6 PR: refrakt-md/refrakt#771
What was done
packages/runes/src/drawer-pipeline.ts: bindDrawerLinks, called last in the core postProcess chain (config.ts). A link to a drawer on the page, by #id or #drawer-<id>, gets the drawer's anchor and data-target-type="drawer"; a drawer wins over a heading; unknown ids, off-page links and reference-rune triggers are untouched. Tests: packages/runes/test/drawer-links.test.ts.Actions gains contextModifiers: { bar: 'in-bar' } (both contract copies regenerated). Lumina actions.css: compact (20px, the badges' 19px), tonal, no primary fill, 1em icon; skeleton actions.css: stays a row on a phone.- Lumina
bar.css: a bar group's paragraph takes no block margin — its prose margin made one group taller and set the two groups at different heights. site/content/_partials/rune-intro.md: Install / Source as actions items with icons, linking to #rune-install / #rune-source; the Source drawer is declared around {% snippet path=$row.source /%} with a GitHub link.scripts/rune-intro.mjs: sourceUrl (from the main site's repoUrl / repoBranch) and a core flag.- Docs: drawer page "Triggering from a link"; actions page "In a bar";
_partials/README.md. packages/content/test/rune-intro.test.ts: triggers' hrefs and ranks for a plugin and a core rune; the snippet drawer holds the file.
Notes
snippet takes its path from $row inside data, so file-ref did not need an id attribute.refrakt format refuses to re-indent {% else /%} (it would change the parse), so the partial uses two if blocks; $row is not substituted inside a function's arguments, so not($row.plugin) was always true — hence the core flag.- Reviewed on a built site (hero, testimonial, hint; trial edits reverted), light and dark at 1280px and 390px; both drawers open from their actions.