Theme support #54

Closed
opened 2026-10-13 21:23:14 +02:00 by SBDeveloper · 2 comments
Owner
No description provided.
Author
Owner

This was generated by AI during triage.

Agent Brief

Category: enhancement
Summary: Let the user choose a Theme (Scheme + Accent) in settings, and make the whole UI honour it.

Current behavior:
The UI is a single hard-coded dark palette defined as design tokens on :root with color-scheme: dark. There is no appearance setting and no handling of prefers-color-scheme. About 26 colours in components bypass the tokens (purple gradients, white hover tints, cover-art scrims, #fff), so they would look wrong under a light Scheme or a different Accent. The page theme-color meta is a fixed dark value.

Desired behavior:

  • A Theme is a Scheme (Dark / Light / System) plus an Accent (one of a fixed set of ~6 curated swatches, purple stays the default accent). Terms are defined in GLOSSARY.md.
  • Default Scheme is System: follows the OS prefers-color-scheme, including live changes while the app runs.
  • The choice is stored per device in UI localStorage (same approach as the sidebar layout), and applied before first paint so there is no flash of the wrong Theme. Storage being unavailable must degrade to the default without error.
  • A settings section (e.g. "Appearance") lets the user pick Scheme and Accent; the change applies immediately.
  • Every Accent swatch must meet readable contrast for text-on-accent and accent-as-text in both Dark and Light.
  • Hard-coded colours move behind tokens. Scrims over cover art stay dark in both Schemes, as named tokens.
  • Native chrome follows the Theme where cheap: the theme-color meta and the Tauri window theme. Nothing requiring new per-platform code.
  • Plugin views need no changes; they render with the host's components and inherit the tokens (ADR 0005).

Key interfaces:

  • Design token set: needs a Light variant and an Accent override mechanism (e.g. an attribute on the root element), plus new tokens replacing the hard-coded colours.
  • A theme preference module in the UI, mirroring the sidebar layout store: parse/serialize/validate with a safe fallback, reactive state, and a pure function for resolving System to Dark/Light that is unit-testable.
  • Settings section registry: register a new section for Appearance.

Acceptance criteria:

  • With no stored preference, the app follows the OS colour scheme, and switches when the OS setting changes.
  • Choosing Dark or Light overrides the OS and persists across restarts.
  • Choosing an Accent recolours buttons, focus rings, sliders, switches and active states in both Schemes; default remains the current purple.
  • A corrupt or unknown stored value falls back to System / default Accent.
  • No flash of the wrong Scheme on startup.
  • No hard-coded colour literals remain in components outside of intentionally Scheme-independent tokens (verified by grep).
  • All primary screens (library, queue, big player, settings, plugin views) are legible in Light; text contrast meets WCAG AA.
  • theme-color meta and Tauri window theme follow the resolved Scheme.
  • Unit tests cover the preference parse/serialize and System resolution; npm run check and npm test pass.

Out of scope:

  • Custom user-authored themes, named full-palette presets, and a free-form colour picker.
  • Accent derived from cover art.
  • Syncing the Theme between devices or storing it in core settings.
  • Plugin-contributed themes or any plugin API for reading the Theme.
  • New platform-specific native code for window chrome.
> *This was generated by AI during triage.* ## Agent Brief **Category:** enhancement **Summary:** Let the user choose a Theme (Scheme + Accent) in settings, and make the whole UI honour it. **Current behavior:** The UI is a single hard-coded dark palette defined as design tokens on `:root` with `color-scheme: dark`. There is no appearance setting and no handling of `prefers-color-scheme`. About 26 colours in components bypass the tokens (purple gradients, white hover tints, cover-art scrims, `#fff`), so they would look wrong under a light Scheme or a different Accent. The page `theme-color` meta is a fixed dark value. **Desired behavior:** - A **Theme** is a **Scheme** (Dark / Light / System) plus an **Accent** (one of a fixed set of ~6 curated swatches, purple stays the default accent). Terms are defined in `GLOSSARY.md`. - Default Scheme is **System**: follows the OS `prefers-color-scheme`, including live changes while the app runs. - The choice is stored per device in UI `localStorage` (same approach as the sidebar layout), and applied before first paint so there is no flash of the wrong Theme. Storage being unavailable must degrade to the default without error. - A settings section (e.g. "Appearance") lets the user pick Scheme and Accent; the change applies immediately. - Every Accent swatch must meet readable contrast for text-on-accent and accent-as-text in both Dark and Light. - Hard-coded colours move behind tokens. Scrims over cover art stay dark in both Schemes, as named tokens. - Native chrome follows the Theme where cheap: the `theme-color` meta and the Tauri window theme. Nothing requiring new per-platform code. - Plugin views need no changes; they render with the host's components and inherit the tokens (ADR 0005). **Key interfaces:** - Design token set: needs a Light variant and an Accent override mechanism (e.g. an attribute on the root element), plus new tokens replacing the hard-coded colours. - A theme preference module in the UI, mirroring the sidebar layout store: parse/serialize/validate with a safe fallback, reactive state, and a pure function for resolving System to Dark/Light that is unit-testable. - Settings section registry: register a new section for Appearance. **Acceptance criteria:** - [ ] With no stored preference, the app follows the OS colour scheme, and switches when the OS setting changes. - [ ] Choosing Dark or Light overrides the OS and persists across restarts. - [ ] Choosing an Accent recolours buttons, focus rings, sliders, switches and active states in both Schemes; default remains the current purple. - [ ] A corrupt or unknown stored value falls back to System / default Accent. - [ ] No flash of the wrong Scheme on startup. - [ ] No hard-coded colour literals remain in components outside of intentionally Scheme-independent tokens (verified by grep). - [ ] All primary screens (library, queue, big player, settings, plugin views) are legible in Light; text contrast meets WCAG AA. - [ ] `theme-color` meta and Tauri window theme follow the resolved Scheme. - [ ] Unit tests cover the preference parse/serialize and System resolution; `npm run check` and `npm test` pass. **Out of scope:** - Custom user-authored themes, named full-palette presets, and a free-form colour picker. - Accent derived from cover art. - Syncing the Theme between devices or storing it in core settings. - Plugin-contributed themes or any plugin API for reading the Theme. - New platform-specific native code for window chrome.
Author
Owner

Implemented in f56b026: Scheme (System/Dark/Light) + six Accents in Settings → Appearance, stored per device, applied before first paint, AA contrast tested against app.css. Known limits: on Linux, returning to System after an explicit choice keeps the last GTK theme until restart; the Big player backdrop wash follows the Scheme.

Implemented in f56b026: Scheme (System/Dark/Light) + six Accents in Settings → Appearance, stored per device, applied before first paint, AA contrast tested against app.css. Known limits: on Linux, returning to System after an explicit choice keeps the last GTK theme until restart; the Big player backdrop wash follows the Scheme.
Sign in to join this conversation.
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.

Dependencies

No dependencies set

Reference
SBDeveloper/medley#54
No description provided.