feat(admin): richer live preview — motion, focus ring, card, dark mode toggle, CSS export - #151
Conversation
…e toggle, CSS export LivePreview: - Replace static dark section with ☀/☾ Light/Dark toggle; all swatches, buttons and card instantly flip to the selected mode's color variants. - Extend inlineStyle to compute --preview-radius-* and --preview-shadow from the live radius_scale / shadow_strength tokens so the card updates when those tabs change. - Add a card component preview showing colors + typography + radius + shadow together (header accent strip, avatar, badges, action button). - Add Outline and Ghost button variants to the button row. MiscTab: - Add motion preview: 5 animated fill-bars (instant → slower) running at their computed duration (base ms × motionScale) so the effect of changing Motion Scale is immediately visible. - Add focus ring preview: a live focusable button that renders the exact outline-width, outline-offset and outline-style set in the fields above. SpacingPreview: - Add a container card below the scale bars showing padding (space-m) and gap (space-s) applied to a real card layout; values update with the viewport slider so fluid spacing is visible in context. ExportImportTab: - Add "Download CSS file" button alongside "Download token file (.json)" so the standalone @layer CSS can be grabbed directly from this tab (mirrors the Export CSS button already present in SaveBar). https://claude.ai/code/session_019MD9F8rrpYzCeDTmSTLA1K
ColorTab: add "Custom dark mode colors" toggle (stored as colors.dark_overrides_enabled). When OFF, the -dark color fields are hidden and no -dark declarations are emitted — the CSS framework's built-in relative-color-syntax auto-derivation takes over: oklch(from light clamp(0.65, 0.95−l·0.5, 0.88) c·0.9 h) Values are preserved in the DB so toggling back re-enables them. class-css-generator.php + export.js: skip brand_dark_* / status_dark_* declarations when dark_overrides_enabled === '0'. Default (key absent or '1') preserves existing behaviour. tests/color-semantic.spec.js: add 4 Playwright tests (Chromium — all pass) confirming the auto-derivation actually runs end-to-end: · primary is lighter in dark theme than light theme · all 6 brand colors obey the formula (base inverts, others brighten) · base inverts near-white → near-dark (luminance > 0.7 vs < 0.08) · explicit -dark override takes precedence over auto-derived fallback https://claude.ai/code/session_019MD9F8rrpYzCeDTmSTLA1K
…xt-aware naming
- Add `align-self: center` to `.rebemer-badge-host` so it no longer
stretches to the full row height in Bricks' flex structure panel.
The badge now sits as a small inline word rather than a tall block.
- Replace the CSS `[data-depth="1/2/3"]` margin rules (which capped
indentation at 3 levels) with a `--rebemer-row-depth` CSS custom
property. Row.svelte sets the property from `row.depth` directly —
any subtree depth now renders with the correct 12px-per-level indent.
- Add context-aware second pass in BemPanel `onMount` that refines
auto-suggested names before rows are rendered:
- Layout containers (section/container/block/div) now get names
inferred from their children: `actions`, `header`, `body`, `footer`,
`media`, `content`, `form`, `nav`, etc. instead of always `item`.
- Sole-child elements get semantic overrides: `heading` → `title`,
`button` → `action`, `text`/`text-basic` → `description`.
- Elements the user already labelled are never touched.
https://claude.ai/code/session_019MD9F8rrpYzCeDTmSTLA1K
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Warning Review limit reached
More reviews will be available in 36 minutes and 29 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 (8)
📝 WalkthroughWalkthroughThis PR introduces a toggleable dark-mode override system in the admin app, gates CSS generation in both JavaScript and PHP export pipelines by a new ChangesDark-Mode Overrides, Admin UI Enhancements, and BEM Naming
Possibly Related PRs
🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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: 3
🧹 Nitpick comments (2)
tests/color-semantic.spec.js (1)
252-327: ⚡ Quick winEnsure Playwright tests use rebuilt
distbundles
tests/fixture.htmlloads../dist/slashed.full.css.- CI runs
npm run buildbefore the Playwright test step, so the checks run against freshly generated CSS.- Local
npm testwon’t rebuilddist(nopretesthook;testis justplaywright test), so consider adding apreteststep or documentingnpm run buildas a prerequisite.🤖 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 `@tests/color-semantic.spec.js` around lines 252 - 327, The Playwright tests load ../dist/slashed.full.css from tests/fixture.html but local npm test doesn't rebuild dist, so CI passes because it runs npm run build beforehand; fix by adding an automatic build step before tests (e.g., add a pretest script that runs npm run build) or document that developers must run npm run build before running playwright test; update package.json's "test" lifecycle (add "pretest": "npm run build") or developer docs accordingly so tests in tests/color-semantic.spec.js run against the rebuilt dist artifact.integrations/bricks/editor-app/src/lib/element-types.js (1)
151-184: ⚡ Quick winAdd focused unit tests for
suggestContainerName(heuristic regression coverage)No current unit/spec coverage references
suggestContainerNameorlib/element-types.js; the helper is only defined inintegrations/bricks/editor-app/src/lib/element-types.js(lines 151-184) and consumed byintegrations/bricks/editor-app/src/components/BemPanel.svelte. Add table-driven tests covering every ordered return path (including theheading+text+buttoncase) and the positional fallback (header/footer/body/content).🤖 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 `@integrations/bricks/editor-app/src/lib/element-types.js` around lines 151 - 184, Add focused unit tests for the heuristic function suggestContainerName in integrations/bricks/editor-app/src/lib/element-types.js: create table-driven tests that exercise every distinct return path of suggestContainerName (cases: form, nav, actions (button-only), media (image-only), header (heading-only and heading+button and positional first sibling), body (text-only and positional middle sibling), content (heading+text, default single-sibling fallback), icon-group, list-wrap, and footer (positional last sibling)). For each row call suggestContainerName with appropriate childTypes arrays and positionAmongContainerSiblings/totalContainerSiblings values and assert the exact returned string, including the specific combined case heading+text+button to ensure it returns 'content'. Use the test framework already in the repo and keep tests table-driven to cover all ordered return paths.
🤖 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 `@integrations/bricks/admin-app/src/components/ExportImportTab.svelte`:
- Around line 10-22: The export button enables when there is generated CSS, not
merely any non-empty token flag: replace the current canExportCSS =
$derived(hasOverrides(tokens)) logic with a derived value based on
generateExportCSS(tokens) (e.g., compute css = generateExportCSS(tokens) and set
canExportCSS to Boolean(css.length)) so the button is disabled when
generateExportCSS would return an empty string; update downloadCSS to rely on
that same generated css (call generateExportCSS(tokens) once) and remove the
hasOverrides import if it becomes unused.
In `@integrations/bricks/admin-app/src/components/LivePreview.svelte`:
- Around line 67-69: The code computes ss with
parseFloat(shadows.shadow_strength ?? meta.defaults?.shadows?.shadow_strength ??
0.08) which lets an empty-string token become NaN; update the guard so empty
strings fall back too (e.g., use logical OR or an explicit empty-string check)
before calling parseFloat: read shadows.shadow_strength, fall back to
meta.defaults?.shadows?.shadow_strength, then to 0.08 if the value is
null/undefined/empty-string, and assign that sanitized value to ss (the variable
used in the pairs.push for --preview-shadow) so parseFloat never receives an
empty string.
In `@integrations/bricks/admin-app/src/components/MiscTab.svelte`:
- Around line 61-66: focusRingWidth and focusRingOffset call parseFloat directly
and use ?? fallbacks, so an empty-string token yields NaN; mirror the
empty-string guard used by durationMs: treat tokens.contrast?.focus_ring_width
and tokens.contrast?.focus_ring_offset as "unset" when they are '' before
parsing, then call parseFloat on the guarded value and fall back to
contrastDefaults (e.g. use the same conditional check durationMs uses to detect
'' and only parse when non-empty), keeping the derived stores named
focusRingWidth and focusRingOffset.
---
Nitpick comments:
In `@integrations/bricks/editor-app/src/lib/element-types.js`:
- Around line 151-184: Add focused unit tests for the heuristic function
suggestContainerName in integrations/bricks/editor-app/src/lib/element-types.js:
create table-driven tests that exercise every distinct return path of
suggestContainerName (cases: form, nav, actions (button-only), media
(image-only), header (heading-only and heading+button and positional first
sibling), body (text-only and positional middle sibling), content (heading+text,
default single-sibling fallback), icon-group, list-wrap, and footer (positional
last sibling)). For each row call suggestContainerName with appropriate
childTypes arrays and positionAmongContainerSiblings/totalContainerSiblings
values and assert the exact returned string, including the specific combined
case heading+text+button to ensure it returns 'content'. Use the test framework
already in the repo and keep tests table-driven to cover all ordered return
paths.
In `@tests/color-semantic.spec.js`:
- Around line 252-327: The Playwright tests load ../dist/slashed.full.css from
tests/fixture.html but local npm test doesn't rebuild dist, so CI passes because
it runs npm run build beforehand; fix by adding an automatic build step before
tests (e.g., add a pretest script that runs npm run build) or document that
developers must run npm run build before running playwright test; update
package.json's "test" lifecycle (add "pretest": "npm run build") or developer
docs accordingly so tests in tests/color-semantic.spec.js run against the
rebuilt dist artifact.
🪄 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: e4ca6929-37c3-444a-9fea-93e919a4cd54
📒 Files selected for processing (16)
integrations/bricks/admin-app/src/components/ColorTab.svelteintegrations/bricks/admin-app/src/components/ExportImportTab.svelteintegrations/bricks/admin-app/src/components/LivePreview.svelteintegrations/bricks/admin-app/src/components/MiscTab.svelteintegrations/bricks/admin-app/src/components/SpacingPreview.svelteintegrations/bricks/admin-app/src/lib/export.jsintegrations/bricks/assets/admin-app/app.cssintegrations/bricks/assets/admin-app/app.jsintegrations/bricks/assets/editor-app/app.cssintegrations/bricks/assets/editor-app/app.jsintegrations/bricks/editor-app/src/components/BemPanel.svelteintegrations/bricks/editor-app/src/components/Row.svelteintegrations/bricks/editor-app/src/lib/element-types.jsintegrations/bricks/editor-app/src/styles/panel.cssintegrations/bricks/includes/class-css-generator.phptests/color-semantic.spec.js
ExportImportTab: derive canExportCSS from generateExportCSS(tokens) directly so the button is disabled when the generated CSS string is empty (e.g. only the dark-toggle flag is stored, which hasOverrides() caught but generateExportCSS() skips). Removes the hasOverrides import. LivePreview: guard shadow_strength against empty-string tokens — `??` does not catch '', which made parseFloat produce NaN and broke the --preview-shadow custom property. MiscTab: apply the same empty-string guard to focusRingWidth and focusRingOffset via a shared numField() helper, matching the pattern already used by durationMs above them. element-types: swap the `heading+button` and `heading+text` rules in suggestContainerName so that a container holding heading+text+button returns 'content' (rich content area) rather than 'header' (nav-like). tests: add table-driven unit tests for suggestContainerName covering all 21 return paths (form, nav, actions, media, header, body, content, icon-group, list-wrap, positional header/body/footer, and the specific heading+text+button → content case). package.json: add pretest script that rebuilds dist and runs the new unit tests before Playwright, so local npm test always exercises fresh CSS bundles and catches element-types regressions automatically. https://claude.ai/code/session_019MD9F8rrpYzCeDTmSTLA1K
LivePreview:
buttons and card instantly flip to the selected mode's color variants.
from the live radius_scale / shadow_strength tokens so the card updates
when those tabs change.
shadow together (header accent strip, avatar, badges, action button).
MiscTab:
their computed duration (base ms × motionScale) so the effect of
changing Motion Scale is immediately visible.
outline-width, outline-offset and outline-style set in the fields above.
SpacingPreview:
gap (space-s) applied to a real card layout; values update with the
viewport slider so fluid spacing is visible in context.
ExportImportTab:
so the standalone @layer CSS can be grabbed directly from this tab
(mirrors the Export CSS button already present in SaveBar).
https://claude.ai/code/session_019MD9F8rrpYzCeDTmSTLA1K
Summary by CodeRabbit
Release Notes
New Features
Improvements