Skip to content

Add base color palette and live semantic preview to ColorsPanel - #461

Merged
jackgranatowski merged 4 commits into
mainfrom
claude/base-color-control-panel-lu750c
Jun 30, 2026
Merged

jackgranatowski merged 4 commits into
mainfrom
claude/base-color-control-panel-lu750c

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends the ColorsPanel with support for the new base color system and adds a live semantic color preview section at the top of the panel. The base color now uses an absolute fixed-lightness OKLCH ramp (independent of the brand color mix curve), and all semantic roles are previewed in real-time with their paired on-color text for legibility checking.

Key changes

  • Base color palette system: Added BASE_RAMP constant with fixed lightness values for each step (50–950), mirroring the framework's absolute OKLCH ramp. Base colors now pin lightness and inherit chroma + hue from the source, unlike the brand colors which use the color-mix tint/shade curve.

  • Palette routing: Introduced paletteSwatch() function that routes each color to the correct palette system—base uses the fixed-L ramp, all others use the color-mix curve toward surface/text.

  • Live semantic preview: Added SEMANTIC_PREVIEW section at the top showing all semantic roles (brand, status, surfaces & text) rendered in both light and dark modes with their resolved on-color text. Each tile is painted from the live canvas, so it updates as you edit and serves as a real legibility check.

  • Expanded color tracking: Renamed BRAND_COLOR_KEYS usage to PALETTE_COLOR_KEYS (which includes base) and moved ALL_SOURCES to module scope for consistent access across auto-dark logic.

  • Auto/manual dark mode toggle for status colors: Status color pairs now have an explicit toggle button to switch between auto-derived and manual dark values, with visual feedback. Auto mode shows the derived value inline; manual mode reveals the editable dark input.

  • Improved dark value derivation: Status colors now properly use sourceTokenMap to resolve token values before deriving dark, ensuring consistency with brand colors. Auto-derived dark values are displayed as read-only previews when in auto mode.

  • Base color documentation: Added inline help text explaining that base uses an absolute lightness ramp, not the brand mix curve.

Implementation notes

  • The BASE_RAMP values are hardcoded to match core/tokens.css exactly, ensuring the panel preview matches the framework output.
  • computeBasePaletteSwatch() uses oklch(from <source> <L> c h) syntax to pin lightness while inheriting chroma and hue.
  • The semantic preview uses paintTheme() to resolve colors from the live canvas, so it reflects both overrides and the active theme in real-time.
  • Auto dark mode state is tracked per color key in autoDarkSet, with proper initialization from existing overrides.

https://claude.ai/code/session_01GDdMto9ikgPJJ5PbbwP4BA

Summary by CodeRabbit

  • New Features

    • Added a live semantic preview section showing resolved role tiles for light and dark themes.
    • Introduced a dedicated lightness ramp for the base color, improving palette generation consistency.
    • Enhanced status color controls with clearer guidance and improved auto/manual dark-mode previews.
  • Improvements

    • Updated palette swatches so base, brand, and status colors are handled more consistently.
    • Refined automatic dark-value selection and preview behavior for more accurate theme results.

claude added 3 commits June 30, 2026 16:58
Base color no longer rides the color-mix tint/shade curve used by the
five brand colors — it's an absolute fixed-lightness OKLCH ramp
(oklch(from <base> <L> c h)). Give it a matching preview in the control
panel:

- Add BASE_RAMP mirroring the L values in core/tokens.css and a
  computeBasePaletteSwatch() that reproduces the framework's ramp.
- Route palette strips through a paletteSwatch() helper so base uses its
  ramp while the brand colors keep the mix curve, and include base in the
  rendered light/dark strips with a short explanatory note.

Status colors now expose the same Auto/Manual dark toggle as the brand
colors, defaulting to Auto (matching the CSS light-dark fallback that
auto-derives the dark source). Seed autoDarkSet and toggleDarkMode from
the combined brand + status source list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDdMto9ikgPJJ5PbbwP4BA
Add an always-visible preview at the top of the Colors panel showing
every semantic role — brand, status, and surfaces/text — each tile
painted with the resolved background and its paired on-color text, so it
doubles as a quick legibility check. Resolved from the live canvas via
paint(), so it tracks overrides and the active theme in real time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDdMto9ikgPJJ5PbbwP4BA
Split the top-of-panel semantic preview into labelled L/D rows per group,
resolving each tile through paintTheme() for both light and dark instead
of only the canvas's active theme. Both modes update live as you edit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDdMto9ikgPJJ5PbbwP4BA
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jackgranatowski, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 384690d3-2ea2-4f94-838f-ee7f7a4bf47f

📥 Commits

Reviewing files that changed from the base of the PR and between 4de3826 and 6eb176d.

📒 Files selected for processing (1)
  • configurator/src/components/panels/ColorsPanel.svelte
📝 Walkthrough

Walkthrough

ColorsPanel.svelte adds a fixed-lightness BASE_RAMP for OKLCH-based base palette swatches, a unified ALL_SOURCES list, a paletteSwatch dispatcher routing base to the new ramp and other keys to existing mix logic, a "LIVE SEMANTIC PREVIEW" tile grid, and restructured status color auto/manual dark rendering.

ColorsPanel enhancements

Layer / File(s) Summary
BASE_RAMP, PALETTE_COLOR_KEYS, ALL_SOURCES, SEMANTIC_PREVIEW constants
configurator/src/components/panels/ColorsPanel.svelte
Defines BASE_RAMP fixed lightness values, expands palette key routing to include "base" via PALETTE_COLOR_KEYS, merges brand and status sources into ALL_SOURCES, updates auto-dark initialization to use ALL_SOURCES, and declares SEMANTIC_PREVIEW tile data.
computeBasePaletteSwatch and paletteSwatch routing
configurator/src/components/panels/ColorsPanel.svelte
Adds computeBasePaletteSwatch generating oklch(from <source> <fixed-L> c h) swatches from BASE_RAMP, and paletteSwatch dispatcher routing base to the fixed ramp and all other keys to the existing computePaletteSwatch. Updates both light and dark strip renders and adds explanatory text for "base" key.
LIVE SEMANTIC PREVIEW UI
configurator/src/components/panels/ColorsPanel.svelte
New panel section iterates SEMANTIC_PREVIEW and renders light/dark theme tiles with backgrounds and foreground text resolved from the live preview.
Status color auto/manual dark rendering
configurator/src/components/panels/ColorsPanel.svelte
Adds a description paragraph to the Status section, integrates auto/manual dark toggle into per-color headers, restricts manual dark desk to non-auto mode, and in auto mode shows a derived-dark preview with deriveDarkFromLight(...) as the dark swatch source.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • codeslash-dev/SLASHED#423: Directly overlapping edits to ColorsPanel.svelte palette/routing logic for base and auto dark-mode handling.
  • codeslash-dev/SLASHED#428: Overlapping changes to auto dark derivation and base vs non-base dark token computation in ColorsPanel.svelte.
  • codeslash-dev/SLASHED#369: Both wire up live semantic role color preview UI and palette-resolution logic in the Colors panel.

Suggested labels

codex

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: base palette support and a live semantic preview in ColorsPanel.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/base-color-control-panel-lu750c

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add base color ramp + live semantic preview to ColorsPanel

✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Add a fixed-lightness OKLCH base ramp and route “base” swatches through it.
• Add a live semantic color preview grid (light/dark) for quick legibility checking.
• Extend auto/manual dark-mode controls and token resolution for status color pairs.
Diagram

graph TD
  A["ColorsPanel.svelte"] --> B{Auto vs Manual dark?} --> C["autoDarkSet state"]
  A --> D["Palette swatch routing"] --> E["Base: fixed-L OKLCH ramp"]
  D --> F["Brand/status: mix-curve swatches"]
  A --> G["Live semantic preview"] --> H["paintTheme()/paint() canvas resolver"]
  A --> I["tokens + overrides"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Single source of truth for BASE_RAMP (import/generate from tokens)
  • ➕ Avoids drift if core/tokens.css ramp changes
  • ➕ Keeps configurator and framework ramp values aligned automatically
  • ➖ Requires build-time extraction step or shared package boundary
  • ➖ Slightly more tooling complexity than a local constant
2. Render swatches purely via CSS variables (less JS resolving)
  • ➕ Moves color evaluation to the browser CSS engine
  • ➕ Potentially reduces canvas/resolveColor coupling
  • ➖ Harder to show “resolved” concrete values in tooltips/previews
  • ➖ More complex CSS generation for light/dark + derived values
3. Make semantic preview collapsible or configurable
  • ➕ Reduces panel height/visual noise for users who don’t need it
  • ➕ Can improve performance if paintTheme calls are heavy
  • ➖ Adds UI state and persistence concerns
  • ➖ Always-visible preview is valuable for quick legibility checks

Recommendation: Current approach is solid for correctness and UX: hardcoding BASE_RAMP ensures an exact match to the framework today, and using paintTheme() guarantees the semantic preview reflects real resolved output. The main follow-up worth considering is centralizing BASE_RAMP to prevent future drift (shared constant or build-time generation from tokens.css).

Files changed (1) +140 / -11

Enhancement (1) +140 / -11
ColorsPanel.svelteAdd base OKLCH ramp, semantic preview, and status auto/manual dark controls +140/-11

Add base OKLCH ramp, semantic preview, and status auto/manual dark controls

• Introduces a fixed-lightness OKLCH BASE_RAMP and routes “base” palette swatches through a dedicated ramp computation while keeping existing mix-curve behavior for other palettes. Adds an always-visible semantic preview grid rendering resolved semantic backgrounds with their on-color text in both light and dark modes via the live canvas. Expands auto-dark handling to include status colors with an Auto/Manual toggle, read-only derived-dark display, and improved derivation inputs via sourceTokenMap.

configurator/src/components/panels/ColorsPanel.svelte

@coderabbitai coderabbitai Bot added the codex label Jun 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@configurator/src/components/panels/ColorsPanel.svelte`:
- Around line 402-403: The dark-value derivation in ColorsPanel.svelte is using
the fallback default source instead of the loaded token source, which can
produce a mismatched manual dark override and preview. Update the dark
derivation paths in the relevant colors panel helpers (the ones currently
calling deriveDarkFromLight from the light token selection) to read the source
value through sourceTokenMap consistently, matching the logic already used in
the later auto-preview code. Keep the same symbols involved in this flow,
including ALL_SOURCES, sourceTokenMap, deriveDarkFromLight, and the dark/manual
toggle handlers, so the derived dark value always comes from the actual loaded
token value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 15cea607-4a57-4447-beca-552e5adcb550

📥 Commits

Reviewing files that changed from the base of the PR and between f55e468 and 4de3826.

📒 Files selected for processing (1)
  • configurator/src/components/panels/ColorsPanel.svelte

Comment thread configurator/src/components/panels/ColorsPanel.svelte Outdated
@qodo-code-review

qodo-code-review Bot commented Jun 30, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 6 rules

Grey Divider


Remediation recommended

1. Toggle seeds wrong dark ✓ Resolved 🐞 Bug ≡ Correctness
Description
When switching Auto→Manual in toggleDarkMode and when rendering the read-only “Dark: auto-derived”
preview, the code seeds/derives from overrides[lightName] ?? default instead of the resolved light
token value, ignoring sourceTokenMap. This can cause the derived/manual dark value shown or
persisted to diverge from what the user is actually editing/viewing whenever the current light token
differs from the hardcoded default.
Code

configurator/src/components/panels/ColorsPanel.svelte[R399-404]

    const effectivelyAuto = autoDarkSet.has(colorKey) && !darkOverridden;
    if (effectivelyAuto) {
      // Switch to manual — populate dark with the derived value as a starting point
-      const lightVal = overrides[lightName] ?? BRAND_SOURCES.find(s => s.name === lightName)?.default ?? "";
+      const lightVal = overrides[lightName] ?? ALL_SOURCES.find(s => s.name === lightName)?.default ?? "";
      if (dark) onSet(dark.name, deriveDarkFromLight(lightVal, colorKey));
      autoDarkSet = new Set([...autoDarkSet].filter(k => k !== colorKey));
Relevance

⭐⭐⭐ High

Team previously accepted fixes ensuring Auto-dark/preview uses resolved token values for consistency
(PR #428; swatch accuracy PR #434).

PR-#428
PR-#434

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The finding is supported by the fact that both the mode-switch seed path in toggleDarkMode and the
inline auto-derived preview compute their light input from overrides[...] ?? ...default (e.g.,
ALL_SOURCES...default / light.default), while elsewhere in the panel the “current” light value
is resolved through sourceTokenMap[... ]?.value when no override exists; this means the UI
(swatches/inputs/palette computations) can be based on the resolved token value, but the
auto-derived preview and the Auto→Manual seeding path can still use a different light value, making
the derived dark inconsistent and potentially persisting that inconsistency as an override.

configurator/src/components/panels/ColorsPanel.svelte[397-404]
configurator/src/components/panels/ColorsPanel.svelte[498-505]
configurator/src/components/panels/ColorsPanel.svelte[669-676]
configurator/src/components/panels/ColorsPanel.svelte[498-511]
configurator/src/components/panels/ColorsPanel.svelte[559-568]
configurator/src/components/panels/ColorsPanel.svelte[669-704]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ColorsPanel.svelte` derives/seeds auto-dark values from `overrides[lightName] ?? default` in two places: (1) when switching Auto→Manual in `toggleDarkMode()`, and (2) in the inline read-only “Dark: auto-derived” preview. Both paths ignore the resolved light token value from `sourceTokenMap[lightName]?.value`, which can cause the derived/manual dark value to differ from the value implied by the current light token the user is actually viewing/editing.

## Issue Context
Elsewhere in the panel (inputs and palette computations), the effective light value is already resolved using the precedence `overrides ?? sourceTokenMap?.value ?? default`. The Auto→Manual seed and the auto-derived preview should use the same resolved light value to avoid inconsistencies when the light source token’s current value differs from the hardcoded defaults.

## Fix Focus Areas
- configurator/src/components/panels/ColorsPanel.svelte[397-404]
- configurator/src/components/panels/ColorsPanel.svelte[559-568]
- configurator/src/components/panels/ColorsPanel.svelte[686-695]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread configurator/src/components/panels/ColorsPanel.svelte
…ault

The Auto→Manual seed in toggleDarkMode and the read-only "auto-derived"
dark previews derived from `overrides[light] ?? hardcoded default`,
skipping the loaded token value in sourceTokenMap that the swatch strips
and inputs already use. When a light source token's current value
differed from the hardcoded default, the seeded manual override and the
inline preview could disagree with the rest of the panel.

Add a sourceValue() helper applying the panel-wide precedence
(override → loaded token value → default) and route every source-value
read through it, so derivation, seeding, swatches, and inputs stay
consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GDdMto9ikgPJJ5PbbwP4BA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants