Files
buzz/desktop-new/package.json
morgmart cef97be05b desktop-new: add a palette layer beneath the colour families
The colour system had three layers, and the middle one held two different kinds
of thing under one name. --neutral-1..12 is a real scale; --accent-2 and
--danger-9 are five specific jobs (tint, tint-hover, border, fill, text) wearing
ramp-style numbering. So --accent-2 read as 'a light purple' when it meant 'the
surface an accent tint sits on'.

Underneath it was 114 hand-picked hex values with nothing enforcing that two
tokens doing the same job agreed. They drifted: --accent-2 and --tint-purple were
the same purple in light mode and two different purples in dark. I introduced
that yesterday and did not notice.

Four layers now:
  0 palette    --palette-purple-3   every hue, 12 steps, authored per mode
  1 families   --accent-tint        the five jobs a hue does, named not numbered
  2 roles      --bg-accent-tint     what a thing is in the interface
  3 components bg-accent-tint       Tailwind utilities

Dark stops being freehand. A family points at a palette step and .dark redefines
the whole palette, so 50 hand-picked dark values are simply gone.

This also answers a concrete trap. Tailwind's purple gets MORE saturated as it
descends (950 is 87% saturation), so a dark tint drawn from its bottom end reads
as oversaturated, and the only way to reach a muted deep purple was to write
purple-950/50 in a component. That value is correct — it composites to within a
few percent of the palette step now in use — but as an expression it has no name,
no light/dark pair, and nothing the contrast guard can measure. The palette's
dark ramps are authored for dark surfaces, so it is a step you pick.

New scripts/check-color.mjs enforces it: rejects opacity modifiers on colour
utilities, color-mix() and alpha rgb()/hsl() in component code, components
reaching past the role layer, and the layering itself — palette steps must be
literals, family steps must reference the palette, two tokens doing one job must
resolve to one step, and dark must not restate families. Falsified by
reintroducing the original drift and each other failure mode in turn.

Values are Radix Colors (MIT), transcribed rather than depended on; Radix is not
on Block's Tech Radar so this is a values-only copy with no package. Its
twelve-step contract is the one this system already described in comments, step
for step. Two documented divergences, both found by the contrast guard: family
text takes step 12 rather than the 11 Radix names 'low-contrast text' (Radix
sizes 11 for WCAG 4.5:1; every hue's 11 measured Lc 55-61 against our Lc 60
target), and dark neutral surfaces stay hand-authored because they were sized
against the real panel stack.

The colour page now renders the palette, so picking a step is visual.

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-09-06 19:12:35 -07:00

49 lines
1.6 KiB
JSON

{
"name": "buzz-desktop-new",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"typecheck": "tsc --noEmit",
"preview": "vite preview",
"lint": "biome lint .",
"check": "biome check . && node scripts/check-type.mjs && node scripts/check-contrast.mjs && node scripts/check-color.mjs",
"format": "biome format --write .",
"check:type": "node scripts/check-type.mjs",
"check:contrast": "node scripts/check-contrast.mjs",
"test": "vitest run src",
"test:e2e": "playwright test",
"tauri:dev": "node ../desktop/scripts/tauri-command.mjs dev --config ../desktop-new/tauri.conf.json --config ../desktop/src-tauri/tauri.dev.conf.json",
"check:color": "node scripts/check-color.mjs"
},
"dependencies": {
"@base-ui/react": "1.7.0",
"@fontsource-variable/inter": "^5.2.8",
"@fontsource/jetbrains-mono": "^5.3.0",
"@tabler/icons-react": "^3.46.0",
"@tanstack/react-router": "^1.168.10",
"@tauri-apps/api": "~2.11.1",
"@tiptap/core": "^3.22.3",
"@tiptap/pm": "^3.22.3",
"@tiptap/react": "^3.22.3",
"@tiptap/starter-kit": "^3.22.3",
"dockview-react": "8.2.0",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4.3.0",
"@tanstack/router-plugin": "^1.167.12",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^6.0.0",
"tailwindcss": "^4.3.0",
"typescript": "~6.0.0",
"vite": "^8.0.0",
"vitest": "^4.1.11"
}
}