refactor(tokens): migrate dark mode to light-dark() hybrid architecture - #19
Conversation
Eliminates the 80-line duplicate dark mode block in base.css by moving all theme logic into tokens.css using the CSS light-dark() function. Source tokens renamed to explicit -light/-dark pairs (@Property registered). Resolved tokens (--sf-color-primary etc.) auto-switch via light-dark() — component API unchanged. Direction-dependent formulas (text, borders, status text) reference source tokens directly inside light-dark() so both formula and source value are correct per mode. --sf-is-dark (0/1) drives non-color dark overrides (shadow-strength). base.css dark mode section: ~100 lines → 5 lines.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR restructures CSS theming into explicit light/dark source tokens with semantic tokens resolved via light-dark(), adds an integer ChangesTheme Architecture Refactor
Tooling, CI, and Docs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 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)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/demo.html (2)
546-546:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate description to reflect new token naming.
The text mentions
--sf-color-*for light mode, but inputs now write to--sf-color-*-lightsource tokens.📝 Suggested text update
- Pick a color for any brand or status token in light or dark mode. Changes are applied live to <code>:root</code> via <code>--sf-color-*</code> and <code>--sf-color-*-dark</code>. Toggle dark mode in the header to preview the dark palette in context. + Pick a color for any brand or status token in light or dark mode. Changes are applied live to <code>:root</code> via <code>--sf-color-*-light</code> and <code>--sf-color-*-dark</code>. Toggle dark mode in the header to preview the dark palette in context.🤖 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 `@docs/demo.html` at line 546, Update the descriptive text to reflect the new token names: change the mention of light-mode tokens from "--sf-color-*" to the new "--sf-color-*-light" naming while keeping the dark-mode mention of "--sf-color-*-dark" and the note that changes are applied to :root; also keep the instruction about toggling dark mode in the header to preview the dark palette so the sentence references "--sf-color-*-light" and "--sf-color-*-dark" explicitly.
1573-1574:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winRandomize function sets wrong token names for light mode.
The randomize function sets
--sf-color-{key}(resolved tokens), but light mode inputs now bind to--sf-color-{key}-light(source tokens). This breaks the randomize feature—light mode inputs won't reflect the randomized values since the re-sync reads from the wrong tokens.🐛 Proposed fix
- applyToken('--sf-color-' + key, light); + applyToken('--sf-color-' + key + '-light', light); applyToken('--sf-color-' + key + '-dark', dark);🤖 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 `@docs/demo.html` around lines 1573 - 1574, The randomize function is writing the light value to the resolved token name '--sf-color-{key}' instead of the source token used by light-mode inputs; update the calls in randomize (where applyToken is invoked) to set '--sf-color-' + key + '-light' for the light value and keep '--sf-color-' + key + '-dark' for the dark value so the light-mode inputs (which bind to the '-light' source tokens) will reflect randomized values.
🤖 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.
Outside diff comments:
In `@docs/demo.html`:
- Line 546: Update the descriptive text to reflect the new token names: change
the mention of light-mode tokens from "--sf-color-*" to the new
"--sf-color-*-light" naming while keeping the dark-mode mention of
"--sf-color-*-dark" and the note that changes are applied to :root; also keep
the instruction about toggling dark mode in the header to preview the dark
palette so the sentence references "--sf-color-*-light" and "--sf-color-*-dark"
explicitly.
- Around line 1573-1574: The randomize function is writing the light value to
the resolved token name '--sf-color-{key}' instead of the source token used by
light-mode inputs; update the calls in randomize (where applyToken is invoked)
to set '--sf-color-' + key + '-light' for the light value and keep '--sf-color-'
+ key + '-dark' for the dark value so the light-mode inputs (which bind to the
'-light' source tokens) will reflect randomized values.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 1368e81e-d087-45bb-b7f1-06ec79308bcc
📒 Files selected for processing (3)
core/base.csscore/tokens.cssdocs/demo.html
- stylelint 17 + stylelint-config-standard; zero errors on full codebase - release-it + @release-it/conventional-changelog: `npm run release` bumps version in package.json, writes CHANGELOG.md, creates annotated tag, pushes - commitlint enforces Conventional Commits via .githooks/commit-msg - pre-commit hook: lint staged CSS files then rebuild dist bundle - GitHub Actions: ci.yml (lint + build on push/PR), release.yml (publishes GitHub Release with dist artifact when a v* tag is pushed) - dist bundle header now includes version from package.json - README: version/CI/license badges (always current from GitHub), token customisation examples, dark mode usage, dev commands
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 @.github/workflows/release.yml:
- Around line 27-31: The awk pattern uses ${VERSION} as a regex which treats
dots and other metacharacters specially; fix by escaping VERSION before using it
in awk. Create an escaped variable (e.g. ESC_VERSION=$(printf '%s' "$VERSION" |
sed -e 's/[][^$.*/\\]/\\&/g') or similar) and then use ESC_VERSION in the awk
invocation that sets NOTES so the pattern matches the literal version string
(referencing VERSION, ESC_VERSION, and the NOTES/awk line).
- Around line 15-33: The workflow uses mutable major-version tags for three
actions—actions/checkout@v4, actions/setup-node@v4, and
softprops/action-gh-release@v2—so replace each tag with the corresponding
immutable full commit SHA for that action (e.g., actions/checkout@<full-sha>,
actions/setup-node@<full-sha>, softprops/action-gh-release@<full-sha>) to pin
behavior; locate the three occurrences in the release.yml step list and update
the version strings to the full SHAs (you can fetch the exact SHAs from each
action's GitHub repository releases/tags) and rotate them periodically when you
intentionally update the workflow.
🪄 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: 77007d4b-d066-4229-90ce-3d1f1542611f
⛔ Files ignored due to path filters (2)
dist/slashed.essential.cssis excluded by!**/dist/**package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (11)
.githooks/commit-msg.githooks/pre-commit.github/workflows/ci.yml.github/workflows/release.yml.release-it.json.stylelintrc.jsonCHANGELOG.mdREADME.mdcommitlint.config.jspackage.jsonscripts/bundle.js
✅ Files skipped from review due to trivial changes (5)
- CHANGELOG.md
- .githooks/commit-msg
- commitlint.config.js
- .githooks/pre-commit
- README.md
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: npm | ||
| - run: npm ci | ||
| - run: npm run build | ||
| - name: Extract changelog for this version | ||
| id: changelog | ||
| run: | | ||
| VERSION="${GITHUB_REF_NAME#v}" | ||
| NOTES=$(awk "/^## \[?${VERSION}\]?/{found=1; next} found && /^## /{exit} found{print}" CHANGELOG.md) | ||
| echo "notes<<EOF" >> "$GITHUB_OUTPUT" | ||
| echo "$NOTES" >> "$GITHUB_OUTPUT" | ||
| echo "EOF" >> "$GITHUB_OUTPUT" | ||
| - uses: softprops/action-gh-release@v2 | ||
| with: |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify workflow action refs are immutable SHAs.
# Expected after fix: no output.
rg -nP '^\s*-\s*uses:\s*[^@\s]+@(?![0-9a-f]{40}\b)[^\s]+' .github/workflows/*.ymlRepository: codeslash-dev/SLASHED
Length of output: 600
Pin workflow actions to immutable commit SHAs.
Three actions in this file use mutable major version tags (@v4, @v2) instead of full commit SHAs (lines 15, 18, 32). Mutable tags allow upstream changes to alter your release pipeline without code review. Pin to commit SHAs and rotate them periodically:
actions/checkout@v4→actions/checkout@<full-sha>actions/setup-node@v4→actions/setup-node@<full-sha>softprops/action-gh-release@v2→softprops/action-gh-release@<full-sha>
🤖 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 @.github/workflows/release.yml around lines 15 - 33, The workflow uses
mutable major-version tags for three actions—actions/checkout@v4,
actions/setup-node@v4, and softprops/action-gh-release@v2—so replace each tag
with the corresponding immutable full commit SHA for that action (e.g.,
actions/checkout@<full-sha>, actions/setup-node@<full-sha>,
softprops/action-gh-release@<full-sha>) to pin behavior; locate the three
occurrences in the release.yml step list and update the version strings to the
full SHAs (you can fetch the exact SHAs from each action's GitHub repository
releases/tags) and rotate them periodically when you intentionally update the
workflow.
- demo.html: randomize() wrote to resolved --sf-color-{key} instead of
source --sf-color-{key}-light; light-mode inputs now reflect randomized values
- demo.html: update customizer description to reference --sf-color-*-light
- release.yml: replace regex awk with awk -v target for exact version matching;
add warning when CHANGELOG section is missing (dots/brackets no longer
treated as regex metacharacters)
- version: 1.0.0 → 0.1.0 - release-it: increment defaults to patch, ignoreRecommendedBump: true (feat: and BREAKING CHANGE commits no longer silently bump minor/major) - added release:minor and release:major scripts for intentional bumps
Eliminates the 80-line duplicate dark mode block in base.css by moving
all theme logic into tokens.css using the CSS light-dark() function.
Source tokens renamed to explicit -light/-dark pairs (@Property registered).
Resolved tokens (--sf-color-primary etc.) auto-switch via light-dark() —
component API unchanged. Direction-dependent formulas (text, borders,
status text) reference source tokens directly inside light-dark() so
both formula and source value are correct per mode.
--sf-is-dark (0/1) drives non-color dark overrides (shadow-strength).
base.css dark mode section: ~100 lines → 5 lines.
Summary by CodeRabbit
Refactor
Documentation
Style
Chores