Conversation
Dark colors are generated at build time by a small PostCSS plugin (src/build/dark-theme.ts) instead of hand-written overrides for ~560 hard-coded colors. Every rule with color declarations gets a twin under :root[data-theme='dark'] that flips OKLab lightness while keeping hue, lifts mid-tones for AA contrast, keeps shadows dark, and preserves media queries and cascade order. Intentionally dark surfaces (the call view) are marked /* theme: fixed */. - public/theme.js applies the saved theme before first paint (an external file because the CSP disallows inline scripts), so there is no flash. - Settings has an Appearance control; System follows the device and updates live. The choice is stored per browser. - Measured in dark: secondary text 4.98:1, notes 4.83:1, headings 8.4:1. Light mode is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Workflow
Settings has a new Appearance control: System, Light or Dark. System follows the device and updates live. The choice is saved per browser, and the theme is applied before the first paint, so there's no white flash.
Approach: dark colors derived at build time
style.cssandeditor.csscontain about 560 hard-coded colors, most of them unique. Hand-writing dark overrides for all of them would be large and would drift with every style change. Instead, a small PostCSS plugin (src/build/dark-theme.ts, registered invite.config.ts) generates the dark theme::root[data-theme='dark']that contains only those color declarations, inside the same media query.#1b1b1b, black becomes#eeeeee), with a curve that lifts mid-tones so secondary text keeps AA contrast. Hue is preserved and chroma is softened slightly. Alpha is kept.url()values are left alone.background: noneorvar(--x). Without that, an earlier rule's dark twin could beat a later light rule that has no literal color./* theme: fixed */ … /* theme: end */.New styles get a dark variant automatically.
public/theme.jssetsdata-themebefore React loads. It's an external file because the CSP disallows inline scripts.src/client/theme.tshandles later changes and the system preference.postcssis now listed as a direct dev dependency; it was already installed through Vite.Verification
npm run check-format,lint,typecheck,test(171 passing, 7 new intests/dark-theme.test.ts) andbuildall pass.🤖 Generated with Claude Code