From 569300eaca7b22cbbbe3097a2cc7c4e0fefaad67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 9 May 2026 17:18:56 +0200 Subject: [PATCH] style(ui): use semantic tokens for mood and feedback indicators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the v1.4.6 deferred polish item — feedback / mood / medication status indicators now ask for *meaning* (success / warning / info) instead of hard-coding `text-dracula-green` / `bg-dracula-orange/15`. Adds three CSS aliases to `globals.css`: --success → dracula-green (positive outcome) --warning → dracula-orange (caution / attention) --info → dracula-cyan (neutral informational) Dark mode (Dracula): each alias resolves to the same hex as before, so the visual is pixel-identical to v1.4.6 — what changes is the *intent* of the class. Light mode (Alucard): the raw Dracula greens and oranges fail AA contrast on a white card. The new tokens get higher-contrast counterparts (#14720a, #a34d14, #036a96) that match the existing `--destructive` / `--chart-*` light-mode swap. Migrated callers: - `src/components/admin/feedback-inbox-section.tsx`: - BUG category badge → `destructive` (semantic — bug *is* broken) - "published to GitHub" badge → `success` - `src/components/medications/medication-card.tsx`: - in-window status → `success` - very-overdue status → `warning` - "late" intermediate stays on `dracula-yellow` (yellow doesn't map to either semantic bucket — it's mid-warning) - `src/components/settings/ai-section.tsx`: - "ChatGPT connected" badge + success toast → `success` - "Connection expired" badge + raw-data warning → `warning` Charts (`src/components/charts/**`) untouched per `feedback_charts_visual_identity.md`. Other dracula-token callsites in settings/* (telegram, ntfy, web-push, account, about, test-connection) are deferred to v1.5.1 — broader sweep, not in tonight's scope. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/globals.css | 32 +++++++++++++++++++ .../admin/feedback-inbox-section.tsx | 8 +++-- .../medications/medication-card.tsx | 4 +-- src/components/settings/ai-section.tsx | 12 +++---- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index a3c70f988..3c594012b 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -55,6 +55,20 @@ --color-dracula-red: var(--dracula-red); --color-dracula-yellow: var(--dracula-yellow); --color-dracula-lavender: var(--dracula-lavender); + + /* + * Semantic feedback tokens — aliases over the Dracula palette so badges, + * banners, and status pills can stop hard-coding `text-dracula-green` / + * `bg-dracula-orange/15` and ask for the *meaning* instead. Each is a + * straight alias of the existing colour at the time of introduction so + * the visual stays pixel-identical to v1.4.6 — what changes is intent. + * - success → dracula-green (positive outcome, e.g. published) + * - warning → dracula-orange (caution / non-blocking attention) + * - info → dracula-cyan (neutral informational note) + */ + --color-success: var(--success); + --color-warning: var(--warning); + --color-info: var(--info); } /* @@ -78,6 +92,16 @@ --dracula-yellow: #f1fa8c; --dracula-lavender: #d6acff; + /* + * Semantic feedback tokens (see @theme `--color-success` / `--color-warning` + * / `--color-info` re-exports). Aliased over the Dracula palette so existing + * dark-mode visuals stay identical; light mode (Alucard) below provides the + * higher-contrast counterpart so AA contrast lands on the white card. + */ + --success: var(--dracula-green); + --warning: var(--dracula-orange); + --info: var(--dracula-cyan); + --radius: 0.625rem; } @@ -135,6 +159,14 @@ --accent: #dcdeef; --accent-foreground: #1f1f1f; --destructive: #cb3a2a; + /* + * Alucard light-mode overrides for the semantic tokens — straight Dracula + * green/orange/cyan would fail AA contrast on a white card. These match the + * darker palette already used for `--destructive`/`--chart-*` in light mode. + */ + --success: #14720a; + --warning: #a34d14; + --info: #036a96; --border: #cfcfde; --input: #cfcfde; --ring: #644ac9; diff --git a/src/components/admin/feedback-inbox-section.tsx b/src/components/admin/feedback-inbox-section.tsx index b187189b1..d1b86e116 100644 --- a/src/components/admin/feedback-inbox-section.tsx +++ b/src/components/admin/feedback-inbox-section.tsx @@ -206,7 +206,11 @@ function FeedbackCategoryBadge({ > = { BUG: { label: t("admin.feedback.categoryBug"), - className: "bg-dracula-red/15 text-dracula-red border-dracula-red/30", + // Bug = something that's broken → semantic `destructive` token instead + // of raw `dracula-red`. Visually identical in dark mode (both resolve + // to #ff5555); light mode now picks up the AA-contrast `#cb3a2a`. + className: + "bg-destructive/15 text-destructive border-destructive/30", }, FEATURE_REQUEST: { label: t("admin.feedback.categoryFeature"), @@ -500,7 +504,7 @@ function FeedbackDetailDialog({ )} {issueUrl && ( - + {t("admin.feedback.publishedToGithub")} )} diff --git a/src/components/medications/medication-card.tsx b/src/components/medications/medication-card.tsx index 974b6efe6..2e4ef50f8 100644 --- a/src/components/medications/medication-card.tsx +++ b/src/components/medications/medication-card.tsx @@ -416,10 +416,10 @@ export function MedicationCard({ medication, onEdit }: MedicationCardProps) { {currentWindowStatus.status === "in_window" diff --git a/src/components/settings/ai-section.tsx b/src/components/settings/ai-section.tsx index 043e4afb5..e38ded9d0 100644 --- a/src/components/settings/ai-section.tsx +++ b/src/components/settings/ai-section.tsx @@ -334,7 +334,7 @@ function InsightsSettingsCard({
{settings?.codexStatus === "connected" && ( - + {t("settings.ai.chatgptConnectedBadge")} )} @@ -344,7 +344,7 @@ function InsightsSettingsCard({ )} {settings?.codexStatus === "expired" && ( - + {t("settings.ai.connectionExpiredBadge")} )} @@ -493,7 +493,7 @@ function InsightsSettingsCard({ {msg && (

{msg}

@@ -518,7 +518,7 @@ function InsightsSettingsCard({
{settings?.privacyMode === "raw" && ( -
+
{t("settings.rawDataWarning")}
)} @@ -958,7 +958,7 @@ function UserAIProviderSubsection() { {saveMsg && (

{saveMsg} @@ -967,7 +967,7 @@ function UserAIProviderSubsection() { {testMsg && (

{testMsg}