Theming — BCC is dark-only; add a light theme and system-following #75

Open
opened 2026-07-20 12:07:29 -04:00 by the_og · 0 comments
Owner

Correction to the original filing

I first wrote this up as "BCC renders as a bright white window on a dark desktop." That's backwards, and I should have read the constants before filing. BCC is already darkBG = "#1b1d23", PANEL = "#23262e", TEXT = "#e7e9ee", applied through a single module-level STYLESHEET in bcc.py.

The actual gap: the theme is hardcoded dark with no light option and no awareness of the OS appearance. A user on a light desktop gets a dark window that matches nothing else on their screen, with no way to change it.

What exists

  • A complete dark palette as module-level constants (ACCENT, BG, PANEL, PANEL_2, TEXT, MUTED, BORDER, GOOD, BAD, WARN).
  • One f-string STYLESHEET built from them, applied globally.
  • ~20 per-widget setStyleSheet(f"color: {MUTED}")-style calls scattered through bcc.py, plus STATUS_COLORS / HEALTH_COLORS lookup tables.

So the colour vocabulary is already factored — it's just bound to one palette at import time.

Scope

  • A Palette value type plus DARK (byte-identical to today's colours — this must not be a redesign) and a new LIGHT.
  • Theme setting with three states: System (default), Light, Dark; persisted in QSettings next to the existing splitter geometry and update/autoCheck.
  • Pure resolve_theme(setting, system_is_dark) -> "light" | "dark" in bcc_core so the decision logic is testable without a Qt app.
  • STYLESHEET becomes build_stylesheet(palette).
  • Toggle in the existing menu, near the About action.

The hard part

The ~20 inline setStyleSheet calls read module-level constants at call time. Switching theme live means those either re-run or go stale, showing dark-theme colours on a light window. Options: re-apply global QSS and refresh the affected panes on switch, or accept a "restart to apply" for inline-styled bits. Prefer live if it's clean; don't ship a half-updated window.

Constraints

  • No -apple-system or any web font stack in the QSS. Removed deliberately; the comment above STYLESHEET explains why (forces a costly font-alias scan). Native system fonts only.
  • GOOD (#4ade80) and WARN (#fbbf24) were picked against a dark background and will not carry to white — the health column and status dots need light-palette variants that actually meet contrast.
  • Several hardcoded near-black values are baked into the QSS (#1a1205 as on-accent text, #202229 for the disabled table, #16181d for the diagnostics pane). These need palette slots, not literals.
  • The masked-secret rendering must stay visually distinct from real values in both palettes.

Tests

resolve_theme across all three settings × both OS appearances; palette completeness (every slot the stylesheet references exists in both palettes, so a missing key fails a test rather than rendering a broken window).

## Correction to the original filing I first wrote this up as "BCC renders as a bright white window on a dark desktop." That's backwards, and I should have read the constants before filing. BCC is **already dark** — `BG = "#1b1d23"`, `PANEL = "#23262e"`, `TEXT = "#e7e9ee"`, applied through a single module-level `STYLESHEET` in `bcc.py`. The actual gap: the theme is **hardcoded dark with no light option and no awareness of the OS appearance**. A user on a light desktop gets a dark window that matches nothing else on their screen, with no way to change it. ## What exists - A complete dark palette as module-level constants (`ACCENT`, `BG`, `PANEL`, `PANEL_2`, `TEXT`, `MUTED`, `BORDER`, `GOOD`, `BAD`, `WARN`). - One f-string `STYLESHEET` built from them, applied globally. - ~20 per-widget `setStyleSheet(f"color: {MUTED}")`-style calls scattered through `bcc.py`, plus `STATUS_COLORS` / `HEALTH_COLORS` lookup tables. So the colour vocabulary is already factored — it's just bound to one palette at import time. ## Scope - A `Palette` value type plus `DARK` (byte-identical to today's colours — this must not be a redesign) and a new `LIGHT`. - Theme setting with three states: **System** (default), **Light**, **Dark**; persisted in `QSettings` next to the existing splitter geometry and `update/autoCheck`. - Pure `resolve_theme(setting, system_is_dark) -> "light" | "dark"` in `bcc_core` so the decision logic is testable without a Qt app. - `STYLESHEET` becomes `build_stylesheet(palette)`. - Toggle in the existing menu, near the About action. ## The hard part The ~20 inline `setStyleSheet` calls read module-level constants at call time. Switching theme live means those either re-run or go stale, showing dark-theme colours on a light window. Options: re-apply global QSS and refresh the affected panes on switch, or accept a "restart to apply" for inline-styled bits. Prefer live if it's clean; don't ship a half-updated window. ## Constraints - **No `-apple-system` or any web font stack in the QSS.** Removed deliberately; the comment above `STYLESHEET` explains why (forces a costly font-alias scan). Native system fonts only. - `GOOD` (`#4ade80`) and `WARN` (`#fbbf24`) were picked against a dark background and will not carry to white — the health column and status dots need light-palette variants that actually meet contrast. - Several hardcoded near-black values are baked into the QSS (`#1a1205` as on-accent text, `#202229` for the disabled table, `#16181d` for the diagnostics pane). These need palette slots, not literals. - The masked-secret rendering must stay visually distinct from real values in both palettes. ## Tests `resolve_theme` across all three settings × both OS appearances; palette completeness (every slot the stylesheet references exists in both palettes, so a missing key fails a test rather than rendering a broken window).
the_og added the P2 label 2026-07-20 12:07:29 -04:00
the_og changed title from Dark mode / theming — light/dark toggle with persistence to Theming — BCC is dark-only; add a light theme and system-following 2026-07-20 12:13:03 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: the_og/better-claude-config#75