diff --git a/eslint-plugins/healthlog/__tests__/no-raw-palette-color.test.mjs b/eslint-plugins/healthlog/__tests__/no-raw-palette-color.test.mjs index b55629c45..5283c827a 100644 --- a/eslint-plugins/healthlog/__tests__/no-raw-palette-color.test.mjs +++ b/eslint-plugins/healthlog/__tests__/no-raw-palette-color.test.mjs @@ -159,3 +159,36 @@ ruleTester.run("no-raw-palette-color (dracula check)", rule, { }, ], }); + +ruleTester.run("no-raw-palette-color (dracula blind spots)", rule, { + valid: [ + // Semantic replacements for the directional + paren-var forms. + { + code: 'const c = "border-l-destructive/70 bg-success border-success";', + filename: APP_FILE, + options: [{ checks: ["dracula"] }], + }, + // Token references through var() stay legal. + { + code: 'const c = "shadow-[0_0_0_1px_color-mix(in_oklab,var(--success)_20%,transparent)]";', + filename: APP_FILE, + options: [{ checks: ["dracula"] }], + }, + ], + invalid: [ + // Directional border form. + { + code: 'const c = "border-l-dracula-red/70";', + filename: APP_FILE, + options: [{ checks: ["dracula"] }], + errors: [{ messageId: "draculaUtility" }], + }, + // Parenthesised CSS-var utility shorthand. + { + code: 'const c = "bg-(--dracula-green)";', + filename: APP_FILE, + options: [{ checks: ["dracula"] }], + errors: [{ messageId: "draculaUtility" }], + }, + ], +}); diff --git a/eslint-plugins/healthlog/index.js b/eslint-plugins/healthlog/index.js index fe97d8368..ca06edf90 100644 --- a/eslint-plugins/healthlog/index.js +++ b/eslint-plugins/healthlog/index.js @@ -25,9 +25,9 @@ module.exports = { "no-raw-palette-color": noRawPaletteColor, "spacing-scale": spacingScale, // Same module as `no-raw-palette-color`, registered under a second - // name so the flat config can run the `dracula` check at a different - // severity (warn) than the error-level checks. See the staged plan in - // the rule header. + // name so the flat config can run the `dracula` check as its own + // named rule (now error-level too; the staged warn phase ended with + // the semantic sweep). See the rule header. "no-dracula-utility": noRawPaletteColor, }, }; diff --git a/eslint-plugins/healthlog/no-raw-palette-color.js b/eslint-plugins/healthlog/no-raw-palette-color.js index 3dfcffc40..4550d7adb 100644 --- a/eslint-plugins/healthlog/no-raw-palette-color.js +++ b/eslint-plugins/healthlog/no-raw-palette-color.js @@ -28,14 +28,13 @@ * before any stylesheet loads, so it must stay a literal). * - `arbitrary-value` (error) — Tailwind arbitrary colour values * (`bg-[#…]`, `text-[oklch(…)]`). `…-[var(--token)]` never matches. - * - `dracula` (WARN, staged) — raw `*-dracula-*` utilities. ~250 - * legacy sites predate the token system; the light-theme overrides in - * `globals.css` defuse their AA failures, so the check ships as a - * warning first (registered separately as - * `healthlog/no-dracula-utility`). It moves to error once the - * semantic sweep (status meaning → `text-success/warning/info/ - * destructive`, brand use → `--brand-*` tokens) has retired the - * legacy sites. + * - `dracula` (error, registered separately as + * `healthlog/no-dracula-utility`) — raw `*-dracula-*` utilities. + * The semantic sweep retired every legacy site: status meaning → + * `text-success/warning/info/destructive`, purple → `primary`, + * pink → the `--brand-pink` token. `var(--dracula-*)` references in + * chart code are token references, not utilities, and never match — + * the light-theme overrides in `globals.css` keep them AA. * * The `checks` option selects which detectors run, so the flat config can * register the same module twice at different severities (see @@ -78,9 +77,12 @@ const RAW_PALETTE_RE = // Raw `dracula-*` utility: the pre-token palette accessed directly // (`text-dracula-green`, `bg-dracula-orange/15`). Same prefix set and -// modifier tolerance as the palette check. +// modifier tolerance as the palette check, plus the directional border +// forms (`border-l-dracula-red`) and the parenthesised CSS-var utility +// shorthand (`bg-(--dracula-green)`) — both bypassed the plain prefix +// match during the staged-warning phase. const DRACULA_RE = - /\b(?:text|bg|border|ring|stroke|fill|from|to|via)-dracula-[a-z]+\b/; + /\b(?:text|bg|border(?:-[lrtbxyse])?|ring|stroke|fill|from|to|via)-(?:dracula-[a-z]+\b|\(--dracula-[a-z]+\))/; // Tailwind arbitrary colour value: `bg-[#…]`, `text-[rgb(…)]`, // `border-[oklch(…)]`. Matching on the bracket-open plus a colour-literal diff --git a/eslint.config.mjs b/eslint.config.mjs index 2ef764ed1..992d0e885 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -59,11 +59,13 @@ const eslintConfig = defineConfig([ "error", { checks: ["palette", "color-props", "arbitrary-value"] }, ], - // Staged: raw `*-dracula-*` utilities warn for now — ~250 legacy - // sites predate the token system and the light-theme overrides in - // globals.css keep them readable. Moves to error once the semantic - // sweep has retired the legacy sites (see the rule header). - "healthlog/no-dracula-utility": ["warn", { checks: ["dracula"] }], + // The semantic sweep retired every raw `*-dracula-*` utility site + // (status meaning → success/warning/info/destructive, purple → + // primary, pink → the --brand-pink token), so the staged warning is + // now a hard error. `var(--dracula-*)` references in chart code are + // token references, not utilities, and stay legal — the light-theme + // overrides in globals.css keep them AA on both themes. + "healthlog/no-dracula-utility": ["error", { checks: ["dracula"] }], // The Card primitive is gap-based; pt-/pb- on CardHeader/CardContent // fights the gap and re-opens the sl-001 drift class. Density lives // on the Card itself (`gap-2 py-3 md:py-4`). See the rule header. diff --git a/src/app/coach/conversations/page.tsx b/src/app/coach/conversations/page.tsx index c2677c2d7..6110786cb 100644 --- a/src/app/coach/conversations/page.tsx +++ b/src/app/coach/conversations/page.tsx @@ -224,7 +224,7 @@ function CoachConversationsBody() { className={cn( "shrink-0", isConfirming && - "text-dracula-red hover:text-dracula-red", + "text-destructive hover:text-destructive", )} >