feat(design): the scheme set, the colour contract and the token utilities (E28 S3a)

Four schemes (Midnight; Forest cyan, Slate fuchsia, Matrix lime), YouTube
and Starship retired with no data migration: normalizeTheme maps a stored
retired scheme to Midnight. A vitest contract measures every scheme x mode
(text 4.5:1, control edge 3:1, status text, the accent's 30-degree hue gap);
it caught light-mode danger at 4.43:1, now red-700. The state layers, the
strong edge, the touch target and the fades are index.css tokens and
utilities the lab now reads. Backdrops recoloured to the new accents, with
a grey overlay grain that actually breaks the banding (longest flat run
15-26px -> 4-8px). The glass tuner is retired.
This commit is contained in:
2026-09-24 04:33:13 +02:00
parent 9c4a999e54
commit ad136c3fe8
26 changed files with 326 additions and 851 deletions
+30
View File
@@ -0,0 +1,30 @@
import { expect, it } from "vitest";
import { DEFAULT_THEME, normalizeTheme } from "./theme";
// YouTube and Starship were retired in E28 with no data migration (owner, 2026-09-24): an account or
// a browser that still stores one must land on the default scheme, not on an html[data-scheme] that no
// CSS block styles (an unstyled page), and the retired tuner flag must not ride along into the next save.
it("maps a retired scheme to the default and keeps only the known keys", () => {
const t = normalizeTheme({
mode: "light",
scheme: "youtube",
fontScale: 1.1,
bgImage: false,
bgFade: 35,
...{ showTuner: true },
});
expect(t).toEqual({
mode: "light",
scheme: "midnight",
fontScale: 1.1,
bgImage: false,
bgFade: 35,
});
});
it("keeps a live scheme and fills what is missing or malformed from the defaults", () => {
expect(normalizeTheme({ scheme: "matrix", mode: "sepia", fontScale: Number.NaN })).toEqual({
...DEFAULT_THEME,
scheme: "matrix",
});
});