feat(frontend): sprint 4 — dark mode + matrix overhaul + tactic selection + done read-only + UI polish

US-17: fix duplicate "Create engagement" button, icon conventions (Save/RotateCcw/Grid2x2), UsersAdminPage form baseline alignment
US-18: done status fully read-only + Reopen button (done → review_required) for all roles
US-19: invalidate engagement queries on simulation PATCH/transition for auto-status propagation
US-20: MitreMatrixModal rewritten — CSS grid 12-column layout, no horizontal scroll, attack.mitre.org compact look
US-21: tactic header clickable in matrix, tactic chips (MitreTacticTag) in field, single atomic PATCH with technique_ids + tactic_ids
US-22: MitreTechniquesField chips-only area + inline search input + matrix icon button; chips show ID-only (name in title=)
US-23: useTheme hook — 3-state light/dark/system, CSS variables, Tailwind darkMode class, localStorage persistence

92/92 tests passing, typecheck and lint clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-27 20:06:01 +02:00
parent d5ab1fd26f
commit f5ea9d16af
21 changed files with 721 additions and 337 deletions

View File

@@ -3,36 +3,38 @@ import type { Config } from 'tailwindcss';
/**
* Tokens mirror DESIGN.md.
* Forma DJR Micro substitut: Inter (bundled locally via @fontsource-variable/inter).
* Dark mode: class-based, toggled by adding 'dark' to <html>.
*/
const config: Config = {
content: ['./index.html', './src/**/*.{ts,tsx}'],
darkMode: 'class',
theme: {
extend: {
colors: {
// Brand & Accent
// Brand & Accent — primary stays fixed (HP Electric Blue never inverts)
primary: {
DEFAULT: '#024ad8',
bright: '#296ef9',
deep: '#0e3191',
soft: '#c9e0fc',
},
// Surface
canvas: '#ffffff',
paper: '#ffffff',
cloud: '#f7f7f7',
fog: '#e8e8e8',
steel: '#c2c2c2',
hairline: '#e8e8e8',
// Text
// Surface — backed by CSS vars so dark mode works via .dark class
canvas: 'var(--color-canvas)',
paper: 'var(--color-paper)',
cloud: 'var(--color-cloud)',
fog: 'var(--color-fog)',
steel: 'var(--color-steel)',
hairline: 'var(--color-hairline)',
// Text — also CSS vars
ink: {
DEFAULT: '#1a1a1a',
deep: '#000000',
soft: '#292929',
on: '#ffffff',
DEFAULT: 'var(--color-ink)',
deep: 'var(--color-ink-deep)',
soft: 'var(--color-ink-soft)',
on: 'var(--color-ink-on)',
},
charcoal: '#3d3d3d',
graphite: '#636363',
// Semantic / decorative
charcoal: 'var(--color-charcoal)',
graphite: 'var(--color-graphite)',
// Semantic / decorative — fixed (not themeable)
bloom: {
coral: '#ff5050',
rose: '#f9d4d2',