diff --git a/frontend/src/v2/__tests__/V2FeaturePageColors.test.ts b/frontend/src/v2/__tests__/V2FeaturePageColors.test.ts new file mode 100644 index 0000000000..90d8676125 --- /dev/null +++ b/frontend/src/v2/__tests__/V2FeaturePageColors.test.ts @@ -0,0 +1,47 @@ +import fs from 'fs'; +import path from 'path'; +import { V2_COLORS } from '../components/V2FeaturePage'; + +// TASK-681: V2FeaturePage's MUI theme cannot read var(), so its colours stay +// literal. This pins each literal to the light --v2-* token of the same role, so +// a token change fails here instead of drifting silently. Dark mode needs its own +// decision (UX Lead, TASK-681 ruling). +const css = fs.readFileSync(path.join(__dirname, '../v2.css'), 'utf8'); + +const TOKEN_FOR: Record = { + bg: 'bg-subtle', + surface: 'surface', + surfaceHover: 'surface-hover', + border: 'border', + borderSoft: 'border-soft', + borderStrong: 'border-strong', + textPrimary: 'text-primary', + textSecondary: 'text-secondary', + textMuted: 'text-muted', + accent: 'accent', + accentStrong: 'accent-strong', + accentSoft: 'accent-soft', + success: 'success', + warning: 'warning', + danger: 'danger', + info: 'info', + shadowSm: '', + shadow: '', + shadowLg: '', +}; + +// First declaration wins: the light block sits above any future dark scope. +const lightTokenValue = (name: string): string | null => { + const m = new RegExp(`--v2-${name}:\\s*(#[0-9a-fA-F]{6})\\s*;`).exec(css); + return m ? m[1].toLowerCase() : null; +}; + +describe('V2FeaturePage MUI palette matches the light --v2-* tokens', () => { + const colourKeys = (Object.keys(TOKEN_FOR) as Array) + .filter((k) => TOKEN_FOR[k] !== ''); + + test.each(colourKeys)('%s equals its light token', (key) => { + expect(lightTokenValue(TOKEN_FOR[key])).not.toBeNull(); + expect(V2_COLORS[key].toLowerCase()).toBe(lightTokenValue(TOKEN_FOR[key])); + }); +}); diff --git a/frontend/src/v2/components/V2FeaturePage.tsx b/frontend/src/v2/components/V2FeaturePage.tsx index 0b61a98712..31f904fd62 100644 --- a/frontend/src/v2/components/V2FeaturePage.tsx +++ b/frontend/src/v2/components/V2FeaturePage.tsx @@ -25,16 +25,18 @@ const withV2Prefix = (path: string): string => { return path.startsWith('/') ? `/v2${path}` : `/v2/${path}`; }; -const V2_COLORS = { - bg: '#f8f8fb', +// MUI's createTheme cannot read var(), so these stay literal. Each value is the +// light --v2-* token of the same role; V2FeaturePageColors.test pins them to v2.css. +export const V2_COLORS = { + bg: '#f9fafb', surface: '#ffffff', - surfaceHover: '#f1f2f5', - border: '#e5e7eb', - borderSoft: '#eef0f6', - borderStrong: '#d7dce7', - textPrimary: '#111827', - textSecondary: '#4b5563', - textMuted: '#6b7280', + surfaceHover: '#f2f4f7', + border: '#d0d5dd', + borderSoft: '#e4e7ec', + borderStrong: '#98a2b3', + textPrimary: '#101828', + textSecondary: '#475467', + textMuted: '#667085', accent: '#1d3fd1', accentStrong: '#1633a8', accentSoft: '#e9edfb',