feat(colors): give LumLocker a separate dark-mode lightness - #635
Conversation
LumLocker pinned both themes to one shared --sf-lumlocker L, so a lock tuned for a light surface read poorly on a dark one. Add --sf-lumlocker-dark, defaulting to the light L mirrored around the light/dark background midpoint — clamp(0.5, calc(1.18 - L), 0.92) — which holds contrast against the surface in both themes. Dark theme's lock rule now reads the dark token; light is unchanged. The configurator LumLocker panel gains an "L · dark" slider and resolves the D preview rows against the dark L. New PUBLIC-ADVANCED token: docs, annotations, registry, api-index and the llm-guide token count regenerated; minor version bump to 0.8.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BRVgKfEYocPCHz9KU96FN
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds ChangesLumLocker dark-mode support
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
The token-coverage gate requires every token in docs/api-index.json to appear in demo/index.html and the embedded #cov-data token list to match the live API set exactly. Add the new --sf-lumlocker-dark cov-token row and list entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BRVgKfEYocPCHz9KU96FN
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge — the change is purely additive, all existing light-mode behavior is preserved, and the dark-mode overrides are consistently applied across every affected selector site. The midpoint math (1.18 = 2 × 0.59, already used by the base-color dark-source formula in the same file) is correct. The CSS cascade order in themes.css is sound: light-dark() handles OS-level scheme, and [data-theme] selectors correctly shadow it. The Svelte $derived.by() mirrors the CSS formula exactly, so the configurator preview matches real output. All generated artifacts, counts, and version references are consistently updated. The only note is a minor semantic tension in how --sf-lumlocker-dark is typed in the token taxonomy. No files require special attention. The token taxonomy documentation (docs/token-index.md and mirrored files) has a minor role-classification nuance worth revisiting, but it does not affect runtime behavior. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["User sets --sf-lumlocker (default 0.65)"] --> B["--sf-lumlocker-dark default\nclamp(0.5, 1.18 - L, 0.92)"]
A --> C["User may override --sf-lumlocker-dark\n(breaks the mirror)"]
C --> D["--sf-lumlocker-dark = explicit value"]
B --> E{"Color scheme?"}
D --> E
E -->|"light-dark() light branch or [data-theme=light]"| F["oklch(from source var(--sf-lumlocker) c h)"]
E -->|"light-dark() dark branch or [data-theme=dark]"| G["oklch(from source var(--sf-lumlocker-dark) c h)"]
F --> H["--sf-color-primary / secondary / tertiary / action"]
G --> H
H --> I["Rendered under :root[data-lumlocker]"]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["User sets --sf-lumlocker (default 0.65)"] --> B["--sf-lumlocker-dark default\nclamp(0.5, 1.18 - L, 0.92)"]
A --> C["User may override --sf-lumlocker-dark\n(breaks the mirror)"]
C --> D["--sf-lumlocker-dark = explicit value"]
B --> E{"Color scheme?"}
D --> E
E -->|"light-dark() light branch or [data-theme=light]"| F["oklch(from source var(--sf-lumlocker) c h)"]
E -->|"light-dark() dark branch or [data-theme=dark]"| G["oklch(from source var(--sf-lumlocker-dark) c h)"]
F --> H["--sf-color-primary / secondary / tertiary / action"]
G --> H
H --> I["Rendered under :root[data-lumlocker]"]
|
There was a problem hiding this comment.
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 `@scripts/token-tiers.js`:
- Around line 41-42: Add --sf-lumlocker-dark to the FORCED_KNOB set in
scripts/token-tiers.js, while preserving its existing ADVANCED classification,
so generated API and documentation output treats it as a knob instead of
consumption.
🪄 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: 1c5e7cac-6df8-40d3-966d-98a19d06fb74
⛔ Files ignored due to path filters (5)
configurator/package-lock.jsonis excluded by!**/package-lock.jsonconfigurator/src/data/api-index.generated.jsonis excluded by!**/*.generated.*configurator/src/data/token-registry.generated.jsonis excluded by!**/*.generated.*dist/css-custom-data.jsonis excluded by!**/dist/**package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (19)
CHANGELOG.mdREADME.mdbadges/badge-optimal.jsonconfigurator/package.jsonconfigurator/src/components/panels/ColorsPanel.sveltecore/themes.csscore/tokens.cssdocs/api-index.jsondocs/api-index.mddocs/llm-guide.mddocs/registry.jsondocs/roadmap.mddocs/token-annotations.jsondocs/token-index.jsondocs/token-index.mddocs/tokens.mdpackage.jsonscripts/token-tiers.jstoken-registry.json
Its default references var(--sf-lumlocker), so the value-shape heuristic in roleOf() mislabeled it as a consumption (read-only) token. It is a user-settable input whose default merely happens to be a derived mirror — exactly the case FORCED_KNOB exists for (cf. --sf-shadow-strength). Add it there so the generated API/docs advertise it as a knob users can set. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BRVgKfEYocPCHz9KU96FN
The locked token-surface snapshot (tests/token-api.spec.js, e2e suite) must record intentional public-token additions. Add the new token; the CHANGELOG already carries its ### Features entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BRVgKfEYocPCHz9KU96FN
Summary
LumLocker pinned both themes to a single
--sf-lumlockerL, so a lock tuned for a light surface read poorly in dark mode (the dark brand colors weren't suitable for a dark background). This adds a separate dark-mode target.--sf-lumlocker-dark(PUBLIC-ADVANCED). Defaultclamp(0.5, calc(1.18 - var(--sf-lumlocker)), 0.92)— the light L mirrored around 0.59, the midpoint between the light (~0.96) and dark (~0.22) page backgrounds. Mirroring around the background midpoint (not 0.5) is what keeps the lock's contrast against the surface equal in both themes; a naive1 - Lwould leave the dark lock too dark to read (L≈0.35, contrast ≈0.13 on a dark surface). Override it to break the mirror.core/themes.css— the dark lock rules (light-dark()dark branch +[data-theme=dark]) now read--sf-lumlocker-dark; the light rules are unchanged.Verified in-browser: with light lock 0.65, light primary resolves to L=0.65 and dark primary to L=0.53 — both carrying contrast 0.31 against their respective surfaces.
Type
Checklist
npm run lint:csspasses (stylelint)npm run buildrebuildsdist/(bundles git-ignored; CI rebuilds/stamps)npm run check:version— 0.8.0, minor bump for the new public token)npm run check:llm-guide— token count 747)check:macros,check:registry,audit:check,check:doc-refs,check:release-add,check:layer-order)CHANGELOG.mdupdated under## UnreleasedNotes
--sf-lumlockerkeeps its meaning and default (0.65) as the light-mode target; only dark mode's lightness source changed. Existing configs that only set--sf-lumlockernow get a better-contrasting dark lock automatically; those wanting the old behaviour can set--sf-lumlocker-darkto the same value as--sf-lumlocker.Configurator
svelte-checkandcheck:curationboth pass.🤖 Generated with Claude Code
Generated by Claude Code
Summary by CodeRabbit
New Features
--sf-lumlocker-darktoken with automatic mirrored defaults and override support.Documentation