Frontend dark mode: popup primitives + page-size select still hardcode light colors; missing theme-color/color-scheme meta #68

Closed
opened 2026-06-09 21:26:21 +00:00 by logaritmisk · 1 comment
Owner

Dark mode shipped in #59, but the popup-layer primitives in src/components/ui/ (exempt from check:colors, so the guard never caught them) and one raw <select> in app code still hardcode light-theme colors. In dark mode these render as white boxes with light-gray text.

Findings

web/src/components/ui/tooltip.tsx:25TooltipPopup uses bg-white and inherits no foreground token:

"rounded border bg-white px-2 py-1 text-sm shadow-md"

bg-popover text-popover-foreground.

web/src/components/ui/toast.tsx:17-19, 31, 37 — toast root uses bg-white, border-red-300 / border-green-300, description text-neutral-700, close button text-neutral-400 hover:text-neutral-700:
bg-popover text-popover-foreground, border-destructive / border-success, text-muted-foreground hover:text-foreground. While in there: the close button renders a literal × glyph — swap to the lucide <X className="size-4" aria-hidden /> icon used by detail-drawer.tsx for visual consistency (the aria-label is already correct).

web/src/components/ui/combobox.tsx:34, 46, 59, 84, 106ComboboxClear (text-neutral-400 hover:text-neutral-700), ComboboxTrigger (text-neutral-500), ComboboxPopup (bg-white), ComboboxItem highlight (data-[highlighted]:bg-indigo-50), ComboboxEmpty (text-neutral-500):
text-muted-foreground hover:text-foreground, bg-popover, data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground, text-muted-foreground.

web/src/objects/objects-table.tsx:290 — the page-size <select> in the table footer uses bg-white in app code. check:colors doesn't flag it because its regex only matches palette-shade pairs (white has no shade). → bg-background (or replace with the ui Select, cf. #51).

web/index.html — head has the theme preload script but no browser-chrome integration:

  • add <meta name="color-scheme" content="light dark"> so native form controls/scrollbars follow the theme,
  • add <meta name="theme-color"> with light + dark media variants.

Suggested follow-up guard

Consider extending scripts/check-no-raw-colors.mjs to also match bg-white/text-black-style literals outside src/components/ui/, so the objects-table case can't recur.

All tokens needed (--color-popover, --color-accent, --color-destructive, --color-success) already exist in src/index.css @theme inline — this is purely a class swap.

Dark mode shipped in #59, but the popup-layer primitives in `src/components/ui/` (exempt from `check:colors`, so the guard never caught them) and one raw `<select>` in app code still hardcode light-theme colors. In dark mode these render as white boxes with light-gray text. ## Findings **`web/src/components/ui/tooltip.tsx:25`** — `TooltipPopup` uses `bg-white` and inherits no foreground token: ``` "rounded border bg-white px-2 py-1 text-sm shadow-md" ``` → `bg-popover text-popover-foreground`. **`web/src/components/ui/toast.tsx:17-19, 31, 37`** — toast root uses `bg-white`, `border-red-300` / `border-green-300`, description `text-neutral-700`, close button `text-neutral-400 hover:text-neutral-700`: → `bg-popover text-popover-foreground`, `border-destructive` / `border-success`, `text-muted-foreground hover:text-foreground`. While in there: the close button renders a literal `×` glyph — swap to the lucide `<X className="size-4" aria-hidden />` icon used by `detail-drawer.tsx` for visual consistency (the `aria-label` is already correct). **`web/src/components/ui/combobox.tsx:34, 46, 59, 84, 106`** — `ComboboxClear` (`text-neutral-400 hover:text-neutral-700`), `ComboboxTrigger` (`text-neutral-500`), `ComboboxPopup` (`bg-white`), `ComboboxItem` highlight (`data-[highlighted]:bg-indigo-50`), `ComboboxEmpty` (`text-neutral-500`): → `text-muted-foreground hover:text-foreground`, `bg-popover`, `data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground`, `text-muted-foreground`. **`web/src/objects/objects-table.tsx:290`** — the page-size `<select>` in the table footer uses `bg-white` in *app* code. `check:colors` doesn't flag it because its regex only matches `palette-shade` pairs (`white` has no shade). → `bg-background` (or replace with the ui `Select`, cf. #51). **`web/index.html`** — head has the theme preload script but no browser-chrome integration: - add `<meta name="color-scheme" content="light dark">` so native form controls/scrollbars follow the theme, - add `<meta name="theme-color">` with light + dark `media` variants. ## Suggested follow-up guard Consider extending `scripts/check-no-raw-colors.mjs` to also match `bg-white`/`text-black`-style literals outside `src/components/ui/`, so the objects-table case can't recur. All tokens needed (`--color-popover`, `--color-accent`, `--color-destructive`, `--color-success`) already exist in `src/index.css` `@theme inline` — this is purely a class swap.
Author
Owner

Fixed in 79a6567 (merged as 1d19ddf).

As specified: tooltip/toast/combobox swapped to popover/accent/muted/destructive/success tokens, page-size select → bg-background, toast × → lucide X, and check-no-raw-colors now also flags shadeless white/black outside components/ui/.

One deviation: instead of static media-variant theme-color metas (which would desync from the in-app toggle), there's a single theme-color meta kept in sync by the index.html preload script and applyTheme() (#ffffff/#0a0a0a, matching --background), with a unit test. color-scheme is set via CSS on :root/.dark — it takes precedence over the light dark meta, so native controls follow the resolved theme rather than the OS preference.

Fixed in 79a6567 (merged as 1d19ddf). As specified: tooltip/toast/combobox swapped to `popover`/`accent`/`muted`/`destructive`/`success` tokens, page-size select → `bg-background`, toast `×` → lucide `X`, and `check-no-raw-colors` now also flags shadeless `white`/`black` outside `components/ui/`. One deviation: instead of static `media`-variant `theme-color` metas (which would desync from the in-app toggle), there's a **single** `theme-color` meta kept in sync by the `index.html` preload script and `applyTheme()` (`#ffffff`/`#0a0a0a`, matching `--background`), with a unit test. `color-scheme` is set via CSS on `:root`/`.dark` — it takes precedence over the `light dark` meta, so native controls follow the resolved theme rather than the OS preference.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logaritmisk/biggus-dickus#68