ADR-002 — Design-system: UI/UX-refresh gennem MUI 6-themet¶
Status: GODKENDT 2026-06-11 — med tillæg (se nederst): ambitionsniveauet er hævet fra token-konvertering til egentlig modernisering pr. view. Dato: 2026-06-11 Forudsætning: MUI 6 er etableret; refreshet sker GENNEM theme-systemet (palette, typography, shape, komponent-overrides i ét centralt theme) — IKKE et nyt UI-bibliotek.
Baggrund og problem¶
Der findes allerede et centralt theme (frontend/src/utils/theme.ts:
mint-grøn primærfarve #7be6c9, Inter, pill-knapper) — men det bliver
undermineret i praksis:
| Måling (main, 2026-06-11) | Antal |
|---|---|
| Filer med hardcodede hex-farver | 26 |
Inline linear-gradient(...)-forekomster |
76 |
| Lokale farve-arrays (AVATAR_COLORS, CLASS_COLORS, SUBJECT_COLORS) | 4+ kopier |
Ekstra ad-hoc-theme (maintenanceTheme i App.tsx) |
1 dublet |
Konsekvenser: dark mode er generisk (#121212) selvom kortene har deres
egen mørkegrønne identitet (#0d1f1a-familien); samme CTA-gradient er
copy-pastet 30+ steder med småvariationer; workroom'en (fuldskærm uden
for MainLayout) hardcoder sin baggrund (#f5f5f5) og styles uden tokens;
og flere views (login, admin) ligner standard-MUI-skabeloner.
Beslutning 1 — Tokens: én sandhed i utils/theme.ts¶
Den eksisterende visuelle identitet kodificeres (vi opfinder ikke et nyt udtryk — vi gør det konsistent og tilgængeligt via theme).
Palette¶
// Brand (uændret identitet, defineret ét sted)
mint: #7be6c9 // primary.main (CTA, aktive tilstande)
mintDark: #5ac3a7 // primary.dark
teal: #0d9488 // secondary.main (avatars, accenter — findes allerede)
inkLight: #2d3748 / #718096 // text primary/secondary (lys)
// Dark mode: den mørkegrønne identitet fra kortene gøres global
darkBg: #0b1512 // background.default (i dag generisk #121212)
darkPaper: #11201b // background.paper (afledt af kortenes #0d1f1a)
mintOnDark: #7be6c9 // primær på mørk — kontrast AA mod darkPaper
Semantiske farver fastlåses (success/warning/error/info = MUI-baseline,
men altid via theme.palette.* — aldrig hex).
Custom theme-felter (module augmentation)¶
Alt det, der i dag tvinger folk til hex, bliver theme-tokens:
declare module '@mui/material/styles' {
interface Palette {
gradients: { brand: string; brandHover: string; accent: string; accentHover: string };
subjects: string[]; // 10-farvers kategorisk skala (én kilde — i dag 4 kopier)
surface: { sunken: string; raised: string; overlay: string };
}
}
gradients.brand= mint-CTA'en (#7be6c9 → #6bd4b8),accent= chat-lilla (#667eea → #764ba2). De 76 inline-gradients erstattes af disse to + hover-varianter.subjects= den kategoriske 10-farveskala fra StudentAssignment — bruges af fag-chips, mapper, avatars og grafer.
Typography, shape og spacing¶
- Inter (allerede valgt). Skala strammes: h1 2.25rem/800 → caption
0.75rem;
buttonuden uppercase (som i dag); tal i tabeller/statistik fårfontVariantNumeric: tabular-nums. - Radius-tokens: 12 px (inputs/knapper/små chips), 16 px (kort/paper),
24 px (pill-CTA).
shape.borderRadius = 12som base. - Spacing: 8 px-grid (MUI-default) håndhæves — ingen
px-magi i sx.
Beslutning 2 — Komponent-overrides (det anti-skabelon-agtige lag)¶
Ét sted i getThemeOptions, så hver view slipper for sx-rod:
| Komponent | Override |
|---|---|
MuiButton |
Pill-radius; ny variant gradient (brand-CTA — erstatter alle inline-gradient-knapper); size="small" strammere |
MuiCard/MuiPaper |
16 px radius; lys: hårfin kant + ingen skygge; mørk: darkPaper + subtil mint-kant ved hover; venstre accent-kant via ny prop-variant accent (gruppe-/dokumentkort) |
MuiChip |
Status-varianter som theme-variants: status-draft, status-submitted, status-locked, status-planned, status-help — i dag håndbygges de i 6+ filer |
MuiDialog |
16 px radius, ensartet padding, titel-typografi |
MuiTextField/MuiSelect |
12 px radius, ens label/helper-stil — fjerner inputBgSx-hacket i wizard'en |
MuiAlert |
Radius + ikon-farver via semantik (help-flag/finish-bannere) |
MuiSkeleton, MuiTooltip, MuiTableCell, MuiTab(s), MuiStepper |
Ensretning (mint-indikator, head-celler, wave-skeletons) |
MuiCssBaseline |
Global scrollbar-styling + selection-farve (små detaljer, stor "ikke-skabelon"-effekt) |
Regel (håndhæves i review + CI-grep): komponenter må ikke indeholde
hex-farver eller linear-gradient — kun theme.palette.*-referencer.
sx er til layout (flex/grid/spacing), ikke til farver/typografi.
CI får et grep-step der fejler på nye #[0-9a-f]{6}/linear-gradient i
frontend/src (med en kort allowlist for SVG-assets).
Beslutning 3 — Fælles state-komponenter¶
Nyt frontend/src/components/feedback/:
EmptyState(ikon + titel + undertekst + valgfri CTA) — bruges i alle lister/mapper/tabeller (i dag: blandede ad-hoc-Papers og rå tekst)ErrorState(besked + "Prøv igen"-retry-callback)LoadingState(eksisterende skeletons genbruges; ny generisk side-skeleton til admin-siderne der mangler)
Standard: hvert view har eksplicit loading- (skeleton), empty- og error-state. Ingen view må rendere "tomt hvidt" eller en rå fejlstreng.
Beslutning 4 — Responsivitet (tablet + desktop)¶
Mål: iPad portræt (768) og landskab (1024) + desktop. Mobil holdes fungerende (eksisterende isMobile-greb beholdes), men optimeres ikke.
- Breakpoint-konvention:
md= tablet,lg+= desktop. - Dashboard-/oversigtsgrids: 1 kolonne < md, 2 ved md, 3 ved lg.
- Wizard:
Steppervandret ≥ md, kompakt (kun aktiv label) < md; fordelings-boardet wrapper kolonner ved md. - Workroom: dokumentgrid 2 kolonner på md (i dag spring fra 1 til 4); topbar-knapper kollapser til ikon-knapper < lg.
- Tabeller (admin/klassepaneler): vandret scroll-container ved < lg i stedet for klemte kolonner.
Beslutning 5 — Udrulning view-for-view (én MR pr. view-gruppe)¶
| MR | Omfang | Nøglepunkter |
|---|---|---|
| A1 — Fundament + login + skal | utils/theme.ts (tokens/overrides/augmentation), fjern maintenanceTheme-dubletten, components/feedback/*, login-siden, MainLayout/TopBar/SideNav |
Login er førstehåndsindtrykket — væk fra skabelon-look: brand-panel + formular, gradient-CTA, fejl-states |
| A2 — Dashboards | Lærer-dashboard (overblik, help-flags, kommende frister), elev-forside | Help-flag-sektionen som tydelig prioritet; "kommende frister"-liste (data findes via assignments); stat-kort på tokens |
| A3 — Grupper & forløb | TeacherGroups (lukkede mapper), StudentGroups, GroupCard, GroupDetails, ClassDetails-paneler | Mappe-hierarkiet (hold→fag→forløb) får ens ikonografi/indrykning; status-chips via theme-varianter |
| A4 — Oprettelses-wizard | views/CreateGroup + creation/* | Fjern inputBgSx-hacket; trin-layout på grid; GroupBuilder-boardet på tokens; sekventiel picker poleres |
| A5 — Workroom & dokumenter | WorkRoomFolderView, OnlyOfficeWorkspace, WorkRoomChat | Kører fuldskærm UDEN FOR MainLayout — al styling skal via theme (i dag hardcodet #f5f5f5-baggrund, gradient-knapper, chat-lilla); editor-topbar og chat-overlay på tokens |
| A6 — Admin + aktivitetslog | Reports, UserManagement, Tenant*, SubjectManagement, ActivityTimeline/Feed, UserProfileView | Mest "rå MUI" i dag — tabeller, tomme states og skeletons mangler flere steder |
Hver MR: (1) erstat hardcodede farver/gradients med tokens i de berørte filer, (2) tilføj manglende loading/empty/error-states, (3) verificér md/lg-breakpoints, (4) visuel røgtest i begge roller + begge themes på review-appen. CI-grep-checket (Beslutning 2) aktiveres i sidste MR (A6), når alle filer er konverteret.
Forkastede alternativer¶
- Nyt UI-bibliotek / Tailwind: eksplicit udelukket af opgaven, og unødvendigt — identiteten findes, den skal bare samles.
- CSS-variabler ved siden af MUI: to kilder til sandhed; MUI 6's theme + module augmentation dækker behovet typed.
- Big-bang-omskrivning i én MR: urevidérbart; view-for-view giver testbare, små diffs og en review-app pr. trin.
Konsekvenser¶
- ✅ Én kilde til farver/typografi/radius; dark mode bliver en ægte identitet i stedet for gråt standard-MUI.
- ✅ Status-chips, gradient-CTA'er og fag-farver bliver konsistente og genbrugelige via theme — nye views kan ikke "komme til" at afvige.
- ⚠️
variant="gradient"på Button og chip-varianterne kræver TS-module- augmentation — defineres i A1 og er derefter typed. - ⚠️ Visuelle regressioner er muligt — afbødes af view-for-view-MR'er med røgtest pr. rolle/theme på review-apps, og af at INGEN funktionel kode ændres (kun styling/states).
Dokumentation¶
docs/design-system.md oprettes i A1 og vedligeholdes pr. MR: tokens,
komponent-varianter, state-standarder, responsive konventioner og
"sådan style du et nyt view"-guide.
Tillæg (godkendt 2026-06-11): Modernisering, ikke kun konvertering¶
Token-disciplinen, MR-opdelingen (A1–A6) og "ingen funktionel kode ændres" fastholdes — men hvert view skal MODERNISERES. Designretning for alle MR'er:
- Login (A1) redesignes fra bunden: split-layout med brand-panel (mørkegrøn flade med subtilt mønster/gradient i mint, produktnavn, én sætning om produktet) + ren formular-side. Store inputs, gradient-CTA, inline-validering med tydelige fejl-states, loading-state på knappen. Benchmark: moderne SaaS-logins (Linear/Notion-klassen) — ikke MUI-demo.
- Rum og hierarki: mere whitespace, større sektionsoverskrifter,
færre rammer — adskil med spacing og baggrundsnuancer
(
surface.sunken/raised) frem for borders overalt. Maks. én primær CTA pr. view. - Dybde og bevægelse: subtile hover-løft på kort (transform + skygge
via theme), bløde transitions (150–200 ms) på interaktive elementer,
Fade/Grow på dialoger og lister. Ingen tunge animationsbiblioteker —
MUI's transitions rækker. Respektér
prefers-reduced-motion. - Dashboards (A2): moderne app-forside — hilsen + dato, stat-kort med ikon og trend, help-flags som prioriteret sektion øverst, "kommende frister" som tidslinje frem for tabel. Tomme dashboards skal se designede ud (EmptyState med illustration/ikon, ikke bare tekst).
- Lister og kort (A3): tydeligt visuelt hierarki: fag-farve-accent, status-chip, deadline med relativ tid ("om 3 dage", rød < 24 t), medlems-avatars som stack. Mapper (lukkede som default) med smooth expand/collapse.
- Wizard (A4): trin-fremdrift tydelig, ét spørgsmål i fokus ad gangen, opsummerings-trin til sidst før oprettelse.
- Workroom (A5): editor-topbar slankes (ikon-knapper med tooltips), chat-overlay moderniseres (bobler, avatars, timestamps grupperet), tydelig LOCKED/SUBMITTED-banner-tilstand.
- Admin (A6): tabeller med sticky header, zebra via surface-nuance, row-hover, og filtre samlet i én toolbar.
Anti-mål: ingen glassmorphism/neon/dribbble-effekter, ingen nye farver uden for paletten, ingen dekorative animationer der ikke kommunikerer tilstand. Moderne = roligt, rummeligt, hurtigt — ikke pyntet. Alt skal bestå CI-grep'et og AA-kontrast i begge themes.
Proces: pr. MR vises screenshot (review-app, lys + mørk) af det vigtigste view FØR merge.