From 448c70968dff31b38a93f08da63251feb3b5b8ef Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Tue, 18 Aug 2026 23:30:26 +0200 Subject: [PATCH] feat: add the light palette, and the module that resolves a theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dark tokens re-struck under `[data-theme="light"]`. Nothing sets that attribute yet, so the app still renders exactly as it did. Two things could not be tokens. Game hues are data — ours and the reader's — and every one was picked against a near-black ground, so `readableHue` darkens them along the same hue until they read on paper, and returns dark untouched by construction. And the attribute has to be on the root before React can mount, or a reader who chose light gets a dark flash on every load, so the shell reads the preference itself. That leaves the ground colour written in three files that cannot import each other, which is what the test pins together. Co-Authored-By: Claude Opus 5 (1M context) --- index.html | 54 +++++-- src/client/components/CustomForms.tsx | 14 +- src/client/components/EventDetail.tsx | 4 +- src/client/components/Welcome.tsx | 2 +- src/client/state/theme.ts | 212 ++++++++++++++++++++++++++ src/client/styles.css | 66 +++++++- test/theme.test.ts | 152 ++++++++++++++++++ 7 files changed, 487 insertions(+), 17 deletions(-) create mode 100644 src/client/state/theme.ts create mode 100644 test/theme.test.ts diff --git a/index.html b/index.html index 5ee61ab..85e42ca 100644 --- a/index.html +++ b/index.html @@ -12,20 +12,56 @@ + + + void; }) { const [name, setName] = useState(initial?.name ?? ""); - const [hue, setHue] = useState(initial?.hue ?? HUES[0]!); + const [hue, setHue] = useState(initial?.hue ?? CUSTOM_HUES[0]!); const valid = name.trim().length > 0 && name.trim().length <= 40; return ( @@ -77,7 +83,7 @@ export function GameForm({

Lane colour

- {HUES.map((h) => ( + {CUSTOM_HUES.map((h) => (