diff --git a/CLAUDE.md b/CLAUDE.md index afa575c..1021ccd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -740,6 +740,21 @@ meant to stay split; add new features as new files, not inside the shells: as a second door. Before adding a global-looking "open X" button, check where X is mounted. +29. **A Tailwind class whose token is undeclared fails in total silence.** + `frontend/tailwind.config.js` is a v3-style config and Tailwind v4 never + loads it — there is no `@config` in `src/index.css`. Every + `primary-` class the app wrote therefore generated no CSS at all: + 568 of them across 60 files, including 38 buttons carrying `text-white` on + a `bg-primary-600` that painted nothing, and the + `focus-visible:ring-primary-500` this file prescribes for accessibility. + No build error, no lint warning, no visual difference from a typo. The + scale now lives in the `@theme` block of `index.css`, which is the only + place v4 reads; `src/theme.test.ts` compiles the real stylesheet and fails + if a step stops resolving. **`--color-primary` and `--color-primary-500` + are different tokens** — `bg-primary` (213 uses) comes from the first and + must keep working. Everything else the config declares — `font-sans`, + `shadow-glow`, `animate-shimmer` — is still inert. + 28. **Two vocabularies name the same act, and they disagree on case.** `constants/actTypes.ts` spells it `Regolamento UE`; the backend resolver answers `regolamento ue`. A `===` between the two silently produced an act diff --git a/docs/deployment.md b/docs/deployment.md index 749ba91..bbe4f9a 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -95,7 +95,7 @@ cd backend && npm test cd frontend && npm run build && npx vitest run ``` -Expected today: 400 Python (1 deselected — the `live` marker), 35 backend, 192 frontend. +Expected today: 400 Python (1 deselected — the `live` marker), 35 backend, 194 frontend. The backend suite needs `backend/.env.test` pointing at a **separate** database (`visualex_test`, not `visualex_platform`) — it runs `prisma migrate reset` on diff --git a/frontend/src/index.css b/frontend/src/index.css index 2c8719c..e786585 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -43,6 +43,25 @@ --color-warning: hsl(var(--warning)); --color-warning-foreground: hsl(var(--warning-foreground)); + /* Primary scale — Blue. + These lived in tailwind.config.js, which is a v3-style config: Tailwind v4 + never loads it without an `@config` directive, so every `primary-` + class in the app generated nothing at all. Declared here instead, where v4 + actually reads them. Values are Tailwind's own blue, unchanged from the + config. `--color-primary` above is a different token and stays as it is: + `bg-primary` and `primary-500` are not the same thing. */ + --color-primary-50: #eff6ff; + --color-primary-100: #dbeafe; + --color-primary-200: #bfdbfe; + --color-primary-300: #93c5fd; + --color-primary-400: #60a5fa; + --color-primary-500: #3b82f6; + --color-primary-600: #2563eb; + --color-primary-700: #1d4ed8; + --color-primary-800: #1e40af; + --color-primary-900: #1e3a8a; + --color-primary-950: #172554; + /* Radius */ --radius-lg: var(--radius); --radius-md: calc(var(--radius) - 2px); diff --git a/frontend/src/theme.test.ts b/frontend/src/theme.test.ts new file mode 100644 index 0000000..ccce61f --- /dev/null +++ b/frontend/src/theme.test.ts @@ -0,0 +1,41 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import postcss from 'postcss'; +import tailwind from '@tailwindcss/postcss'; + +/** + * Tailwind failures are silent: a class whose token the theme never declares + * generates no CSS, and nothing — not the build, not the linter — says so. That + * is how `primary-` came to be written 568 times while drawing nothing + * (tailwind.config.js is a v3-style config, and v4 never loads it without an + * `@config` directive). These tests compile the real stylesheet and assert the + * tokens the app spends its classes on actually resolve. + */ +// vitest runs with the frontend package as its root. +const CSS_PATH = resolve(process.cwd(), 'src/index.css'); + +async function compile(candidates: string[]): Promise { + const source = `${readFileSync(CSS_PATH, 'utf8')}\n@source inline("${candidates.join(' ')}");\n`; + const { css } = await postcss([tailwind()]).process(source, { from: CSS_PATH }); + return css; +} + +describe('the primary colour scale', () => { + it('gives every step used by the app a real colour', async () => { + const steps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; + const css = await compile(steps.map((s) => `bg-primary-${s}`)); + + for (const step of steps) { + expect(css, `bg-primary-${step} generated no rule`).toContain(`.bg-primary-${step}`); + } + }, 30000); + + it('still resolves the unnumbered primary token, which 213 classes rely on', async () => { + const css = await compile(['bg-primary', 'ring-ring', 'bg-background']); + + expect(css).toContain('.bg-primary'); + expect(css).toContain('.ring-ring'); + expect(css).toContain('.bg-background'); + }, 30000); +}); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index ddacc3d..2cadd08 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,3 +1,16 @@ +/** + * NOT LOADED. This is a Tailwind v3-style config; the project runs Tailwind v4 + * (`@import "tailwindcss"` + `@theme` in src/index.css) and v4 only reads a JS + * config when the stylesheet asks for it with `@config`. Nothing here reaches + * the build: editing a value in this file changes nothing you can see. + * + * The `primary` scale below is live only because it was copied into the + * `@theme` block in src/index.css — edit it there. `fontFamily`, `boxShadow` + * (`shadow-glow`, `shadow-glass-lg`) and the keyframes/animations are still + * inert, and the fonts named here are never fetched anyway. + * + * Kept for the record until we decide whether to wire it up or delete it. + */ /** @type {import('tailwindcss').Config} */ export default { content: [