UI: dark mode following system preference #6

Closed
opened 2026-09-10 03:37:43 +00:00 by agent-pi · 3 comments
Collaborator

Problem

The UI is light-theme only. Reading in the evening means a glaring white page, and there is no way to darken it.

Goal

A dark theme that activates automatically by following the OS/browser preference (prefers-color-scheme), with no manual toggle required for the common case.

## Problem The UI is light-theme only. Reading in the evening means a glaring white page, and there is no way to darken it. ## Goal A dark theme that activates automatically by following the OS/browser preference (`prefers-color-scheme`), with no manual toggle required for the common case.
Author
Collaborator

Findings

  • src/yunjin/web/static/style.css (567 lines) is already fully variable-driven — colours live in a :root block as --color-* custom properties (blue/orange/yellow accent palette, chosen for deuteranopia safety).
  • No prefers-color-scheme media query anywhere.
  • This means dark mode needs zero JavaScript: one @media (prefers-color-scheme: dark) block redefining the custom properties, consistent with the project's minimal-JS rule.
  • Constraint carried over from project conventions: the dark palette must also be deuteranopia-safe — accents must remain pairwise distinguishable and contrast-checked against the dark backgrounds, not just inverted.
  • Any remaining hardcoded hex values in the stylesheet get swept into variables as part of the change.

Plan of attack

  1. Add @media (prefers-color-scheme: dark) redefining all --color-* variables (backgrounds, surfaces, text, accents, alerts).
  2. Sweep hardcoded colour values into variables.
  3. Contrast/distinctness check of the dark palette for deuteranopia.
  4. Screenshots (light + dark) in the PR for Marvin8's eyeball review.
## Findings - `src/yunjin/web/static/style.css` (567 lines) is **already fully variable-driven** — colours live in a `:root` block as `--color-*` custom properties (blue/orange/yellow accent palette, chosen for deuteranopia safety). - No `prefers-color-scheme` media query anywhere. - This means dark mode needs **zero JavaScript**: one `@media (prefers-color-scheme: dark)` block redefining the custom properties, consistent with the project's minimal-JS rule. - Constraint carried over from project conventions: the dark palette must *also* be deuteranopia-safe — accents must remain pairwise distinguishable and contrast-checked against the dark backgrounds, not just inverted. - Any remaining hardcoded hex values in the stylesheet get swept into variables as part of the change. ## Plan of attack 1. Add `@media (prefers-color-scheme: dark)` redefining all `--color-*` variables (backgrounds, surfaces, text, accents, alerts). 2. Sweep hardcoded colour values into variables. 3. Contrast/distinctness check of the dark palette for deuteranopia. 4. Screenshots (light + dark) in the PR for Marvin8's eyeball review.
Author
Collaborator

Scope update (Marvin8)

Dark mode will ship together with #8 (settings infrastructure) in one branch/PR, and gains a third mode: the theme is user-settable — system / light / dark — with an explicit user choice overriding the system preference. Default remains "follow system". Implementation will use a data-theme attribute on <html> combined with a prefers-color-scheme media query, all server-rendered (no JS), persisted via the new settings store.

## Scope update (Marvin8) Dark mode will ship together with #8 (settings infrastructure) in one branch/PR, and gains a third mode: the theme is **user-settable — system / light / dark** — with an explicit user choice overriding the system preference. Default remains "follow system". Implementation will use a `data-theme` attribute on `<html>` combined with a `prefers-color-scheme` media query, all server-rendered (no JS), persisted via the new settings store.
Author
Collaborator

Resolved by PR #27 (merged): dark theme with three modes — Follow system (default), Light, Dark (user choice overrides the OS preference). Pure CSS via prefers-color-scheme + data-theme attribute; all colour literals swept into variables with dark variants and contrast-checked on-accent text colours, guarded by static stylesheet tests.

Resolved by PR #27 (merged): dark theme with three modes — Follow system (default), Light, Dark (user choice overrides the OS preference). Pure CSS via prefers-color-scheme + data-theme attribute; all colour literals swept into variables with dark variants and contrast-checked on-accent text colours, guarded by static stylesheet tests.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/yunjin#6
No description provided.