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

Renderer integration + pre-paint script

Wire the cascade-resolved (tint, tintMode, locked) tuple into SSR — emit data-theme, data-tint, data-tint-lock on <html>, plus a matching <meta name="color-scheme">. Add the inline pre-paint script that applies saved user preference on unlocked pages and no-ops on locked pages, so there's no flash of incorrect theme on dark-locked marketing.

Priority:highComplexity:mediumMilestone:v0.14.0Source:SPEC-052
claude/spec-053-tint-authoring-notes View source

Criteria completion

Criteria completion: 0 of 11 (0%) checked; tracking started on May 18, no incremental history yet0%25%50%75%100%May 18Jun 15

Tracking started May 18 — check back for trends.

Branches 3
History 1
  1. 8df92a3
    Created (ready)by bjornolofandersson

Acceptance Criteria

  • The renderer (likely @refrakt-md/svelte ThemeShell or equivalent in other adapters) emits:
    • data-theme="dark" (or "light") on <html> when the page's resolved tintMode is dark or light
    • No data-theme attribute when resolved tintMode is auto (lets the pre-paint script + system pref decide)
    • data-tint="<name>" when a named tint is resolved
    • data-tint-lock="true" when resolved locked is true (omit or set "false" otherwise)
    • <meta name="color-scheme" content="dark"> (or light) when locked; content="light dark" when unlocked
  • Inline pre-paint script (the small <script> that runs before first paint) reads data-tint-lock; if locked, does nothing; if unlocked, applies saved preference from localStorage, falls back to prefers-color-scheme
  • The pre-paint script lives in <head> before any styles so it runs before paint
  • No flash of incorrect theme on a dark-locked marketing page — verified by a Lighthouse trace or manual frame-by-frame on a slow connection
  • The pre-paint script is small and inline (not a separate file request) — sub-1KB
  • Unit tests verify the rendered HTML output for each combination of (tint, tintMode, locked)

Approach

Most of this is straightforward — pass the resolved tuple from WORK-212 into the layout/renderer and produce the right HTML.

The pre-paint script is the most subtle piece. The contract from WORK-211's toggle:

<script>
  (function() {
    if (document.documentElement.dataset.tintLock === 'true') return;
    var saved = localStorage.getItem('rf-theme');
    var resolved = saved && saved !== 'auto'
      ? saved
      : (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    document.documentElement.setAttribute('data-theme', resolved);
  })();
</script>

This script and WORK-211's toggle need to use the same localStorage key (rf-theme here, but pick the canonical name during implementation and use it consistently).

For other adapters (Astro, Next, Eleventy, plain HTML) — the same <html> attributes and the same pre-paint script need to be emitted by their respective render pipelines. Likely a single shared utility in @refrakt-md/content that all adapters call.

Dependencies

  • WORK-212 — cascade resolution produces the tuple this consumes.
  • WORK-213 — frontmatter schema must accept the fields.
  • WORK-189theme.colorScheme field already exists at site level (this work generalises its emit to per-page).

References

  • SPEC-052 — "SSR & Rendering" section
  • WORK-211 — toggle that pairs with this pre-paint script