feat(ui,sdk): unify data colours into one canonical source, pastel by default (OB-378)#105
Merged
eliotlim merged 3 commits intoJul 5, 2026
Conversation
Finish wiring every data-colour consumer onto the single canonical source (`@book.dev/sdk` dataColors), replacing the five legacy hard-coded lists. The scheme is fixed to Pastel (the signed-off default); the scheme param is plumbed for the "Data colours" appearance control (OB-379). - Runtime: `applyDataColors` emits the palette as CSS vars (chip bg/fg flip by `.dark`), wired from ThemeProvider. Chips, swatch dots, timeline bars and card tints read the vars via `dataColorVars` helpers (with default-scheme fallbacks for provider-less viewer mounts). - Charts + map: SVG presentation attributes / Leaflet can't resolve `var()`, so kit `PALETTE`, db `chartColor` and map pins resolve to concrete canonical hex; kit + db charts now share one `SERIES_ORDER` (blue-first, 12 series). - Status lights: index.css + the toHtml duplicate both take the pastel status fills, a 25%-alpha ring and the pastel/muted light-mode hairline (§1.2). - Export self-containment: tags inline the pastel chip colours; the kit chart runtime prepends `KIT_PALETTE` from `SERIES_ORDER` (one source, no drift). - Legacy lists gone: SWATCH_HEX, db CHART_PALETTE, COLOR_CLASSES, kit PALETTE literal, the baked KIT_PALETTE, and the index.css/toHtml status hexes. Tests: sdk dataColors unit test; export palette-parity assertions (status CSS, drawn chart fills, prepended runtime palette, db tag chip colours). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
…e, palette guard
- CalendarView event pill: `${accent}24` (hex-alpha concat) is invalid once
`accent` is a `var(--data-…)` string, silently dropping the bg tint. Swap
for `color-mix(in srgb, ${accent} 14%, transparent)`, which composes with
var(). (Quinn, only such concat in the tree.)
- Viewer bundle is provider-less, so `--data-stroke` was undefined and the
`.obe-kit-light` literal fallback baked a light-mode rgba hairline into dark
hosts. Call `applyDataColors()` at viewer load so the var is defined
(:root rgba, .dark transparent) — no reliance on the literal. (Devon.)
- dataColors.test.ts now re-derives all 180 values (36 fills + 144 chips) by
porting the ob-375-palette-audit.mjs colour math (browser-safe, no node
builtins) and diffing against the module — a real drift guard, not a
spot-check. (both reviewers.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Jul 5, 2026
eliotlim
added a commit
that referenced
this pull request
Jul 6, 2026
…data colours (integration) (#107) * docs(design): OB-375 colour-consistency manifest — unified data palette + sidebar full-accent spec Spike deliverable: canonical 12-token data palette (Pastel/Vivid/Muted x fill/chip roles) unifying SELECT_COLORS, SWATCH_HEX, CHART_PALETTE, kit PALETTE and the status trio; sidebar full-intensity accent sheet model with per-theme contrast overrides, veil hover/active/press treatment, interfaceIntensity 0-3 mapping and neutral --desk token; complete computed WCAG audit (68/68 sheet pairs, 102/102 wash states, all chip pairs >=4.5:1) with the generator script committed alongside; storage/ API sketch for AppearanceOptions.dataColors + sdk dataColors module. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * feat(ui): full-intensity accent sidebar by default (OB-377) (#104) * feat(ui): full-accent sidebar sheets — §2 derivation, veil hovers, neutral desk (OB-377) composeAppearance now derives sheet-1/2 from each theme's primary per the colour-consistency manifest §2.1–2.4: light = primary verbatim with the audited per-theme sheet-darken (default 49→44, forest 38→31, teal 38→30) and ink-flip (sunset + three pastels) escape hatches; dark = a deep accent shade (clamp(0.7·S,12,60), L 24/28.5) with a 0 0% 93% foreground. Sheet foregrounds stop tracking --foreground and a --sheet-veil overlay pole is composed per theme. Adds a neutral --desk token, repoints .ob-desk and the present backdrop onto it, and reworks sidebarStyles hover/active/press to veil washes. Full accent lands at interfaceIntensity ≥ 2 (the existing default) so the rollout needs no migration; levels 0/1 keep the flat/soft panel. index.css first-paint tokens track the composed default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * feat(ui): read every sidebar-chrome consumer on the accent surface (OB-377) The full-accent sheets broke the sidebar's neutral text/icon/hover tokens. Adds a scoped .ob-accent-chrome remap (muted/accent foreground → the full sheet foreground per manifest §2.2 'de-emphasis via size/weight only'; hover/active → --sheet-veil washes) on the three accent-chrome surfaces: the sidebar Drawer, the settings nav rail, and the titlebar (--foreground left intact so the active titlebar tab's light chip keeps its ink). Body rows/labels drop their alpha tiers (which fail 4.5:1 on the saturated sheet) onto the full sheet foreground — Tree primitive, Favorites, flat page rows, section labels — and the Tree drop indicators repaint with the sheet foreground so they read on the accent. Content surfaces that only borrowed --sheet-1 as a subtle raised card move to the neutral bg-muted (AgentPanel, ImportDialog drop zones/options, review comment/suggestion cards); the floating workspace switcher reverts to the neutral popover default. Portaled menus/dialogs sit outside the remapped subtrees, so they stay neutral. Tests: encodes the §2.2 audited table for the archetypes + a WCAG sweep asserting fg-on-sheet ≥ 4.5:1 for all 17 themes × 2 sheets × 2 schemes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * fix(ui): review nits on the full-accent sidebar (OB-377) - Tree row icons/chevron: fg@70% → 75% on the sheet (manifest §2.2 sanctions 75% for non-text icons; rose row icons were ~2.86:1 < 3:1, now ~3.12). - Unify dark-scheme sidebar hover: .ob-accent-chrome now sets the audited 8/13 % veil alphas in dark (matching SIDEBAR_*), so the page tree's shared bg-hover/bg-hover-strong washes read at the same strength as favorites. - OnboardingNudge sign-in CTA → secondary variant: a primary-blue fill barely separated from the full-accent sidebar sheet; a light neutral chip reads. - Note the now-unconsumed --sheet-2 painted token (kept, not dead-stripped). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * fix(ui): default the sidebar to tinted; make the full-accent option legible (OB-377) Owner re-scope: the pale accent *tint* is the DEFAULT again; the OB-377 full accent is an opt-in. Adds `sidebar: 'tinted' | 'accent'` to AppearanceOptions (default 'tinted'; normalizeAppearance keeps existing users tinted, drops an invalid value) + a Segmented 'Sidebar' control in Appearance settings. composeAppearance's 'tinted' branch reproduces the pre-OB-377 sheet computation (interfaceIntensity drives its saturation again); 'accent' is the audited full surface. applyAppearance writes `data-sidebar` on <html> to gate the CSS. Fixes the real contrast bug: `.ob-accent-chrome` remapped the base tokens (`--muted-foreground`), but `text-muted-foreground`/`bg-hover` resolve the Tailwind `--color-*` intermediates, which are declared at :root and substitute their nested var() there — so the subtree override never reached them, leaving the top nav / section headers / nudge body in a low-contrast muted hue. Now the gated `[data-sidebar='accent'] .ob-accent-chrome` overrides the `--color-*` tokens, so every de-emphasised sidebar element resolves to the light sheet foreground. sidebarStyles route through `bg-hover`/`bg-hover-strong` (primary tint when tinted, veil wash when accent). OnboardingNudge CTA is mode-aware (primary on the pale tint, secondary chip on the accent sheet). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * test(web): real-DOM contrast guard for the accent sidebar (OB-377) Verifies the OPT-IN full-accent sidebar on the real DOM (getComputedStyle colour composited over its effective background → WCAG contrast), not idealized token math. Audits every visible sidebar text/icon — top nav, section headers, favourites, page tree + chevrons/icons, the OnboardingNudge card, workspace switcher — across default / ocean / graphite accents in light AND dark; asserts text >= 4.5:1, icons >= 3:1. The aria-hidden account monogram (a decorative identity badge with its own hue background) is excluded. Measured worst cases: text 4.58 (default light) .. 7.23, icon 4.58 .. 10.4 — all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * feat(ui,sdk): unify data colours into one canonical source, pastel by default (OB-378) (#105) * wip(ob-378): partial data-colour unify — dead-worker snapshot, NOT reviewed * feat(ui,sdk): unify all data colours onto the canonical palette (OB-378) Finish wiring every data-colour consumer onto the single canonical source (`@book.dev/sdk` dataColors), replacing the five legacy hard-coded lists. The scheme is fixed to Pastel (the signed-off default); the scheme param is plumbed for the "Data colours" appearance control (OB-379). - Runtime: `applyDataColors` emits the palette as CSS vars (chip bg/fg flip by `.dark`), wired from ThemeProvider. Chips, swatch dots, timeline bars and card tints read the vars via `dataColorVars` helpers (with default-scheme fallbacks for provider-less viewer mounts). - Charts + map: SVG presentation attributes / Leaflet can't resolve `var()`, so kit `PALETTE`, db `chartColor` and map pins resolve to concrete canonical hex; kit + db charts now share one `SERIES_ORDER` (blue-first, 12 series). - Status lights: index.css + the toHtml duplicate both take the pastel status fills, a 25%-alpha ring and the pastel/muted light-mode hairline (§1.2). - Export self-containment: tags inline the pastel chip colours; the kit chart runtime prepends `KIT_PALETTE` from `SERIES_ORDER` (one source, no drift). - Legacy lists gone: SWATCH_HEX, db CHART_PALETTE, COLOR_CLASSES, kit PALETTE literal, the baked KIT_PALETTE, and the index.css/toHtml status hexes. Tests: sdk dataColors unit test; export palette-parity assertions (status CSS, drawn chart fills, prepended runtime palette, db tag chip colours). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG * fix(ui,sdk): address OB-378 review nits — calendar tint, viewer stroke, palette guard - CalendarView event pill: `${accent}24` (hex-alpha concat) is invalid once `accent` is a `var(--data-…)` string, silently dropping the bg tint. Swap for `color-mix(in srgb, ${accent} 14%, transparent)`, which composes with var(). (Quinn, only such concat in the tree.) - Viewer bundle is provider-less, so `--data-stroke` was undefined and the `.obe-kit-light` literal fallback baked a light-mode rgba hairline into dark hosts. Call `applyDataColors()` at viewer load so the var is defined (:root rgba, .dark transparent) — no reliance on the literal. (Devon.) - dataColors.test.ts now re-derives all 180 values (36 fills + 144 chips) by porting the ob-375-palette-audit.mjs colour math (browser-safe, no node builtins) and diffing against the module — a real drift guard, not a spot-check. (both reviewers.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * feat(sdk,ui): swap default Pastel scheme to the owner-selected soft pastel Replace the Pastel scheme values (only) with the softer, lighter set the owner picked from rendered candidates. Vivid/Muted are untouched (they render with the appearance control, OB-379). Everything else from the reviewed work stays: the var/hex split, export self-containment, the CalendarView color-mix fix, the viewer applyDataColors, and the derivation-based palette guard. - New per-token pastel: owner light fill/chipBg/chipFg + a distinct dark dot/series fill (`fillDark`); DataColor gains `fillDark` (equals `fill` for the mode-invariant vivid/muted + pastel extension tokens). `--data-<token>` now flips to `fillDark` in `.dark`, so dots/swatches/status honour the dark fill. - SERIES_ORDER is the 9 select tokens (blue-first); teal/cyan/indigo drop out of the rendered cycle (kept as unrendered extension tokens for type completeness). - Status trio → green / yellow / red: at these low saturations orange and red are near-identical, so warn maps to yellow for a glanceable traffic light. - Dark chips are derived (deep muted on-hue bg + light on-hue fg, all ≥4.5:1); the guard re-derives them + the owner light table + the ob-375 vivid/muted, and asserts chipFg contrast (light+dark) and status hue-distinctness. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Problem
Data colours lived in 5 divergent hardcoded lists (tags: pastel chips but saturated dots; kit-chart ≠ db-chart palettes; status hexes duplicated app+export), none tied to Appearance, all defaulting to saturated. Board: OB-378 (Epic OB-374).
Solution
Collapse all five into one canonical source (
packages/sdk/src/dataColors.ts, + UI emitterdataColorVars.ts), rendered as a refined soft pastel by default (owner-selected after reviewing rendered candidates). One blue-firstSERIES_ORDERdrives both chart systems; status lamps use a distinct green / yellow / red trio (warn→yellow so it stays distinct from bad at low saturation) + ring + hairline; exports inline concrete values (self-contained, var-free). Architecture: DOM inline-styles use livevar(); SVG/Leaflet/canvas use concrete hex. The Pastel/Vivid/Muted switch is OB-379; this PR fixes the scheme to the soft pastel. New deps: none.Reviews — Quinn (code) + Devon (design), both CLEAR-WITH-NITS, all nits addressed (CalendarView
color-mix; provider-less-viewer stroke; palette test hardened to re-derive every value + assert status distinctness).Before / After
soft, blue-first series
soft chips + dots
vivid green/orange/red
soft green/yellow/red (warn→yellow, stays distinct)
Test procedure
pnpm verifygreen: sdk 165 (incl. a palette guard re-deriving every value + a status-distinctness assertion) · ui 849 · server 586 · e2e 251+39.#9fdf9f/#dac495/#deaea6, chartfill, tag chip#dbeddb/#1e761e).Operational notes
index.cssregions).dataColors.tsis the canonical source).chore/artifacts(pr-assets/ob-378/), off this branch.Footer: verify green (sdk 165 · ui 849 · server 586 · mcp 39);
design(Devon) +code(Quinn) gates cleared; palette values are the owner-selected soft pastel (visually approved).🤖 Generated with Claude Code
https://claude.ai/code/session_01X78XTAemKrFw1uJpDpCEaG