feat(bricks): add in-builder Color System panel with light/dark preview - #193
Conversation
A floating Color System panel for the Bricks builder, launched from a corner pill. Browses every --sf-color-* token grouped by brand/status family (shades & tints, transparent steps, semantic aliases) plus a combined Semantic group. Leans into SLASHED's adaptive light-dark() model: each swatch previews BOTH variants at once (diagonal split in "Both" mode), and the Light/Dark toggle drives the live canvas [data-theme] so real elements adapt while browsing. Picking a swatch copies its var(--sf-color-*) reference and applies it to the selected element's chosen target (background / text / border) — always the variable, never a baked hex, so elements stay theme- and dark-mode-aware. Degrades to copy-only with no selection. - color-resolver: add resolve_dark() deriving dark sources + semantic tokens via the framework's own dark formulas; share the family-scale builder between modes. - inventory: add get_color_hex_map_dark() (cached, override-aware). - rebemer-enqueue: localise the ordered token list + light/dark hex maps behind a new slashed_bricks/show_color_panel filter. - editor-app: pure, unit-tested color-model.js (grouping/filter/value helpers) + ColorApp/ColorPanel/ColorSwatch/ColorLauncher Svelte UI; bricks-api gains active-element detection and color application. - tests/color-model.test.js wired into the pretest suite. https://claude.ai/code/session_01HPTgyrXeZBfqrwFpa78d3F
…panel
Addresses two gaps in the Color System panel:
1. Custom dark variants were ignored. resolve_dark() always auto-derived
the dark value from the light source, so a user's explicit dark
override (admin Dark-mode overrides, theme, or hand-written CSS) was
not reflected. derive_dark_sources() now honours an explicit
--sf-color-{family}-dark exactly like the framework's CSS fallback
chain — var(--sf-color-X-dark, <derived>) — and the whole dark scale
(shades/tints/alpha/aliases/semantics) follows the override. The
inventory's admin-override reader now also surfaces brand_dark_* /
status_dark_* (gated by the same dark_overrides_enabled flag the CSS
generator uses), so the preview matches the emitted CSS.
2. Organized, guided grouping. Each family group now carries a role
tagline ("Interactive & links") and a when-to-use hint, shown in the
group header, so users know which colour is which and when to reach
for it. The catch-all Semantic group is split into purpose-based
labelled subsections (Text on color, Text, Interactive states,
Surfaces, Borders, Links, Selection & marks, Code) instead of one
flat list — against the real inventory every token lands in a named
section with nothing left over.
color-model.js gains FAMILY_INFO + semantic subgrouping (pure, covered
by new unit tests).
https://claude.ai/code/session_01HPTgyrXeZBfqrwFpa78d3F
|
Warning Review limit reached
More reviews will be available in 47 minutes and 40 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughA new in-builder Color System panel displays ChangesColor System Panel Feature
Sequence DiagramssequenceDiagram
participant Editor as Bricks Editor
participant Server as PHP Backend
participant ColorApp as ColorApp
participant Panel as ColorPanel
participant Swatch as ColorSwatch
Editor->>Server: Request editor config (color variables, light/dark hex maps)
Server->>Server: resolve_dark() light/dark colors
Server->>Server: get_color_hex_map_dark() cached result
Server-->>Editor: colorPanel { variables, light, dark }
Editor->>ColorApp: Mount with source data
ColorApp->>Panel: Render with model data
Panel->>Swatch: Render grouped swatches
Swatch-->>Panel: Click swatch → onPick()
Panel->>Panel: Copy var(--sf-color-*) to clipboard
Panel->>Panel: Apply color to active element (if selected)
Panel-->>Editor: Toast feedback (success/error/info)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/bricks-api.js (1)
296-309: 💤 Low valueClarify comment about "leaving sibling fields untouched".
Line 270 states "leaving any sibling hex/hsl/rgb fields untouched", but line 307 replaces the entire color control object with
{ raw: rawValue }, which would clear existing sibling fields rather than preserve them. The code is functionally correct for the use case—var(--sf-color-*)references can't be resolved to hex/hsl/rgb at edit time, so having onlyrawis appropriate. The comment could be clearer that we're deliberately creating a minimal object rather than preserving existing structure.📝 Proposed comment revision
* These are the standard Bricks "_" style controls; a colour control stores * an object whose `raw` field carries the literal CSS value (so a - * `var(--sf-color-*)` reference round-trips intact). We only ever write - * `raw`, leaving any sibling hex/hsl/rgb fields untouched. + * `var(--sf-color-*)` reference round-trips intact). We set only the `raw` + * field (Bricks can't resolve CSS variables to hex/hsl/rgb at edit time).🤖 Prompt for 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. In `@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/bricks-api.js` around lines 296 - 309, The comment about "leaving any sibling hex/hsl/rgb fields untouched" is misleading because setElementColor (function setElementColor) intentionally replaces the color control object with a minimal { raw: rawValue } (see where el.settings[group][key] is assigned), which clears any sibling fields; update the comment near that code to explicitly state we deliberately create a minimal color object containing only raw for var(...) values and do not preserve hex/hsl/rgb siblings, so future readers understand this is intentional rather than a bug.plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/color-model.js (2)
226-238: 💤 Low valueAdd alphabetical tiebreaker for unrecognized aliases.
When both aliases are absent from
ALIAS_ORDER, they receive rank999and the comparator returns0, leaving their relative order non-deterministic. ThecompareSemanticfunction (line 249) includes an alphabetical tiebreaker; consider the same here for consistent, reproducible sorting.📋 Proposed tiebreaker
if (a.info.kind === 'alias') { const ai = ALIAS_ORDER.indexOf(a.info.step); const bi = ALIAS_ORDER.indexOf(b.info.step); - return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi); + const ar = ai === -1 ? 999 : ai; + const br = bi === -1 ? 999 : bi; + if (ar !== br) return ar - br; + return String(a.info.step).localeCompare(String(b.info.step)); }🤖 Prompt for 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. In `@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/color-model.js` around lines 226 - 238, The compareInFamily comparator can return 0 when both alias steps are missing from ALIAS_ORDER, causing non-deterministic order; update the alias branch in compareInFamily to, after computing ai/bi and falling back to 999, if ai === -1 && bi === -1 (or both mapped to the 999 fallback) use a lexical tiebreaker comparing a.info.step and b.info.step (same approach as compareSemantic) to return a deterministic alphabetical order (case-insensitive if compareSemantic does that).
28-34: ⚖️ Poor tradeoffFamily list duplication across language boundaries.
The brand and status family lists are independently defined here (lines 31, 34), in
class-color-resolver.php(line 37–49 as$default_sourceskeys), and inclass-inventory.php(lines 245–246). If a new family is added or one is renamed, all three locations must be updated in sync. Consider documenting this constraint in each location or centralizing the list in a shared data file that both JS and PHP can consume (e.g., a JSON schema or generated constants).🤖 Prompt for 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. In `@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/color-model.js` around lines 28 - 34, BRAND_FAMILIES and STATUS_FAMILIES are duplicated across JS and PHP (BRAND_FAMILIES, STATUS_FAMILIES in color-model.js vs $default_sources in class-color-resolver.php and lists in class-inventory.php); centralize these lists by extracting them to a shared JSON (e.g., colors-families.json) and update color-model.js to import/require that JSON and update class-color-resolver.php and class-inventory.php to read/parse the same JSON, or alternately add a clear TODO comment in each location referencing the canonical source and documenting the need to update all locations when changing families; ensure the shared symbol names (BRAND_FAMILIES / STATUS_FAMILIES) are preserved so existing code paths (color-model.js functions) continue to work.
🤖 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
`@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/components/ColorPanel.svelte`:
- Around line 127-147: When pick(...) detects an active element id but
api.setElementColor(id, target, value) returns false, don't fall through to the
generic copy-only toast; instead set a specific toast explaining the color
couldn't be applied to that element (use targetLabel and the element name from
api.getElementLabel(id) or 'element'). If copying succeeded, include that the
value was copied as a secondary note (e.g., "Copied X — paste into any Bricks
colour field; this element doesn't support {targetLabel}"), otherwise show a
clear error/warning about unsupported color application; update the pick
function's applied check to set that specific toast before returning.
---
Nitpick comments:
In `@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/bricks-api.js`:
- Around line 296-309: The comment about "leaving any sibling hex/hsl/rgb fields
untouched" is misleading because setElementColor (function setElementColor)
intentionally replaces the color control object with a minimal { raw: rawValue }
(see where el.settings[group][key] is assigned), which clears any sibling
fields; update the comment near that code to explicitly state we deliberately
create a minimal color object containing only raw for var(...) values and do not
preserve hex/hsl/rgb siblings, so future readers understand this is intentional
rather than a bug.
In
`@plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/color-model.js`:
- Around line 226-238: The compareInFamily comparator can return 0 when both
alias steps are missing from ALIAS_ORDER, causing non-deterministic order;
update the alias branch in compareInFamily to, after computing ai/bi and falling
back to 999, if ai === -1 && bi === -1 (or both mapped to the 999 fallback) use
a lexical tiebreaker comparing a.info.step and b.info.step (same approach as
compareSemantic) to return a deterministic alphabetical order (case-insensitive
if compareSemantic does that).
- Around line 28-34: BRAND_FAMILIES and STATUS_FAMILIES are duplicated across JS
and PHP (BRAND_FAMILIES, STATUS_FAMILIES in color-model.js vs $default_sources
in class-color-resolver.php and lists in class-inventory.php); centralize these
lists by extracting them to a shared JSON (e.g., colors-families.json) and
update color-model.js to import/require that JSON and update
class-color-resolver.php and class-inventory.php to read/parse the same JSON, or
alternately add a clear TODO comment in each location referencing the canonical
source and documenting the need to update all locations when changing families;
ensure the shared symbol names (BRAND_FAMILIES / STATUS_FAMILIES) are preserved
so existing code paths (color-model.js functions) continue to work.
🪄 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: 2ac24631-81a3-4711-871b-2c39481a5d2f
📒 Files selected for processing (16)
package.jsonplugins/SLASHED-for-WP/integrations/bricks/README.mdplugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.cssplugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.jsplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/components/ColorApp.svelteplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/components/ColorLauncher.svelteplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/components/ColorPanel.svelteplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/components/ColorSwatch.svelteplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/bricks-api.jsplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/lib/color-model.jsplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/main.jsplugins/SLASHED-for-WP/integrations/bricks/editor-app/src/styles/panel.cssplugins/SLASHED-for-WP/integrations/bricks/includes/class-color-resolver.phpplugins/SLASHED-for-WP/integrations/bricks/includes/class-inventory.phpplugins/SLASHED-for-WP/integrations/bricks/includes/class-rebemer-enqueue.phptests/color-model.test.js
- color-model: drop the unused SCALE_STEPS constant (CodeQL dead-code);
add a deterministic lexical tiebreaker for unranked aliases; note the
JS/PHP family-list mirror so the three definitions stay in sync.
- bricks-api: clarify that setElementColor intentionally writes a minimal
{ raw } object (Bricks can't resolve a CSS var to hex/hsl/rgb at edit
time), rather than implying it preserves sibling fields.
- ColorPanel: when an element is selected but apply fails (e.g. a stale
id from the DOM fallback), say so instead of the generic copy-only
toast.
https://claude.ai/code/session_01HPTgyrXeZBfqrwFpa78d3F
A floating Color System panel for the Bricks builder, launched from a
corner pill. Browses every --sf-color-* token grouped by brand/status
family (shades & tints, transparent steps, semantic aliases) plus a
combined Semantic group.
Leans into SLASHED's adaptive light-dark() model: each swatch previews
BOTH variants at once (diagonal split in "Both" mode), and the
Light/Dark toggle drives the live canvas [data-theme] so real elements
adapt while browsing. Picking a swatch copies its var(--sf-color-*)
reference and applies it to the selected element's chosen target
(background / text / border) — always the variable, never a baked hex,
so elements stay theme- and dark-mode-aware. Degrades to copy-only with
no selection.
tokens via the framework's own dark formulas; share the family-scale
builder between modes.
behind a new slashed_bricks/show_color_panel filter.
helpers) + ColorApp/ColorPanel/ColorSwatch/ColorLauncher Svelte UI;
bricks-api gains active-element detection and color application.
https://claude.ai/code/session_01HPTgyrXeZBfqrwFpa78d3F
Summary by CodeRabbit
New Features
Documentation
Tests