fix(ui): close consistency-audit contrast and duplication findings

Today hero's top-signal delta used opacity-on-muted text, landing below
AA on the app's most prominent card; five mood charts and the sleep-
stage IN_BED fill painted raw --dracula-*/hardcoded-hex hues with no
(or an unused) light-theme counterpart. Route all of them through
existing semantic/chart tokens instead (destructive/warning/success,
chart-1..5, and a newly minted --chart-inbed with its own Alucard
override) so every hue is AA-tuned per theme.

Also collapses three duplicated primitives the audit flagged: the
click-Popover VitalsInfoTip and hover-Tooltip InfoHint merge into one
touch-first ui/info-popover; MedicationViewToggle and ModuleViewToggle
were verbatim copy-paste and now wrap one shared ui/view-toggle; the
triplicated sport-icon map (already drifted — mixedCardio rendered a
different glyph in the list vs the detail/dashboard views) moves to
lib/workouts/sport-icons.ts with HeartPulse as the settled icon.

Adds a no-restricted-imports lint rule banning direct recharts imports
outside the chart-runtime barrel, catching the bundle-duplication
mistake at local lint instead of PR-CI.
This commit is contained in:
Marc-André Bombeck committed 2026-07-18 01:23:37 +02:00
1 parent 1ff179178f
commit 247bc4f33c
25 files changed
+401 -400

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
import {
Activity,
Bike,
Dumbbell,
Footprints,
HeartPulse,
Mountain,
PersonStanding,
type LucideIcon,
} from "lucide-react";
/**
* Shared sport-type → icon map. Previously three private copies
* (`workout-list.tsx`, `workout-detail.tsx`, `recent-workouts-tile.tsx`)
* that had already drifted — `mixedCardio` rendered `Heart` in the list but
* `HeartPulse` in the detail view and the dashboard tile, so the same
* workout showed two different glyphs between the row and its detail page.
* `HeartPulse` won as the shared value (two of three sites already agreed).
*/
export const SPORT_TYPE_ICON: Record<string, LucideIcon> = {
walking: Footprints,
running: PersonStanding,
cycling: Bike,
hiking: Mountain,
swimming: Activity,
rowing: Activity,
elliptical: Activity,
stairClimber: Activity,
yoga: PersonStanding,
mindAndBody: PersonStanding,
strength: Dumbbell,
hiit: Activity,
dance: Activity,
golf: Activity,
tennis: Activity,
basketball: Activity,
soccer: Activity,
crossTraining: Activity,
mixedCardio: HeartPulse,
other: Activity,
};
export function iconForSport(sportType: string): LucideIcon {
return SPORT_TYPE_ICON[sportType] ?? Activity;
}