Tell the browser which colour scheme the page is in

The parts of a form control the browser draws itself -- a number input's
stepper, a date field's calendar button and popup, a select's dropdown,
scrollbars, the autofill tint -- were painted in the light appearance on
every theme. Bambuddy switches theme by swapping CSS variables under a
`dark` class, which the browser cannot see, so it assumed the page was
light and matched the steppers to a white background that was not there.

Declaring color-scheme alongside the variables fixes all of them at once,
in both directions. It goes on `.dark` rather than the per-palette
classes because the kiosk sets `dark` on the root element directly.

Three date and time fields had been pinned to dark by hand to work
around this and no longer need to be; being pinned, they were wrong
under the light theme anyway.
This commit is contained in:
maziggy
2026-08-11 12:16:31 +02:00
parent 0229d61cea
commit 4a65abe228
7 changed files with 26 additions and 8 deletions
@@ -1270,7 +1270,7 @@ export function GitHubBackupSettings() {
<input
type="time"
value={localBackupStatus?.time ?? '03:00'}
className="w-full h-10 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none [color-scheme:dark]"
className="w-full h-10 px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none"
onChange={async (e) => {
try {
await api.updateSettings({ local_backup_time: e.target.value });
+17
View File
@@ -101,6 +101,17 @@ html {
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
--glow-color: transparent;
/* Tell the browser which appearance the page is in, so the parts of a form
control it draws itself follow the theme. Bambuddy themes by
swapping CSS variables under a `.dark` class, which the browser cannot
see: without this declaration it assumes light and paints every native
widget internal that way -- number-input steppers, the date picker's
calendar button and its popup, `<select>` dropdowns, scrollbars, the
autofill highlight. That is why the quantity steppers in the print
dialog were pale grey chips inside a dark field. Only the widget
internals are affected; anything we set ourselves still wins. */
color-scheme: light;
font-family: 'Inter', system-ui, sans-serif;
line-height: 1.5;
font-weight: 400;
@@ -112,6 +123,12 @@ html {
/* Dark mode base */
.dark {
/* Pairs with `color-scheme: light` on :root -- see the note there. This
sits on `.dark` rather than on each `.dark.bg-*` palette because the
kiosk adds `dark` to <html> on its own (SpoolBuddyLayout), and every
palette is a dark one regardless of which background it picks. */
color-scheme: dark;
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--bg-tertiary: #3d3d3d;
+2 -2
View File
@@ -1370,7 +1370,7 @@ export function StatsPage() {
value={timeframe.dateFrom || ''}
max={timeframe.dateTo || new Date().toISOString().split('T')[0]}
onChange={(e) => setTimeframe(prev => ({ ...prev, dateFrom: e.target.value || undefined }))}
className="w-full bg-bambu-dark border border-bambu-dark-tertiary rounded-md px-3 py-1.5 text-sm text-white [color-scheme:dark]"
className="w-full bg-bambu-dark border border-bambu-dark-tertiary rounded-md px-3 py-1.5 text-sm text-white"
/>
</div>
<div>
@@ -1381,7 +1381,7 @@ export function StatsPage() {
min={timeframe.dateFrom}
max={new Date().toISOString().split('T')[0]}
onChange={(e) => setTimeframe(prev => ({ ...prev, dateTo: e.target.value || undefined }))}
className="w-full bg-bambu-dark border border-bambu-dark-tertiary rounded-md px-3 py-1.5 text-sm text-white [color-scheme:dark]"
className="w-full bg-bambu-dark border border-bambu-dark-tertiary rounded-md px-3 py-1.5 text-sm text-white"
/>
</div>
<Button