style(ui): use semantic tokens for mood and feedback indicators

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) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 17:18:56 +02:00
1 parent 788c8ad335
commit 569300eaca
4 files changed
+46 -10

No files matched your search

+32
View File
@@ -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;
@@ -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({
</Button>
)}
{issueUrl && (
<Badge className="border-dracula-green/30 bg-dracula-green/15 text-dracula-green ml-auto">
<Badge className="border-success/30 bg-success/15 text-success ml-auto">
{t("admin.feedback.publishedToGithub")}
</Badge>
)}
@@ -416,10 +416,10 @@ export function MedicationCard({ medication, onEdit }: MedicationCardProps) {
<span
className={
currentWindowStatus.status === "in_window"
? "text-dracula-green font-medium"
? "text-success font-medium"
: currentWindowStatus.status === "late"
? "text-dracula-yellow font-medium"
: "text-dracula-orange font-medium"
: "text-warning font-medium"
}
>
{currentWindowStatus.status === "in_window"
+6 -6
View File
@@ -334,7 +334,7 @@ function InsightsSettingsCard({
</div>
<div className="flex flex-wrap items-center gap-2">
{settings?.codexStatus === "connected" && (
<Badge className="border-dracula-green/30 bg-dracula-green/15 text-dracula-green">
<Badge className="border-success/30 bg-success/15 text-success">
{t("settings.ai.chatgptConnectedBadge")}
</Badge>
)}
@@ -344,7 +344,7 @@ function InsightsSettingsCard({
</Badge>
)}
{settings?.codexStatus === "expired" && (
<Badge className="border-dracula-orange/30 bg-dracula-orange/15 text-dracula-orange">
<Badge className="border-warning/30 bg-warning/15 text-warning">
{t("settings.ai.connectionExpiredBadge")}
</Badge>
)}
@@ -493,7 +493,7 @@ function InsightsSettingsCard({
{msg && (
<p
role="alert"
className={`text-sm ${msgType === "success" ? "text-dracula-green" : "text-destructive"}`}
className={`text-sm ${msgType === "success" ? "text-success" : "text-destructive"}`}
>
{msg}
</p>
@@ -518,7 +518,7 @@ function InsightsSettingsCard({
</div>
</div>
{settings?.privacyMode === "raw" && (
<div className="bg-dracula-orange/15 text-dracula-orange mt-2 rounded-lg p-2 text-xs">
<div className="bg-warning/15 text-warning mt-2 rounded-lg p-2 text-xs">
{t("settings.rawDataWarning")}
</div>
)}
@@ -958,7 +958,7 @@ function UserAIProviderSubsection() {
{saveMsg && (
<p
className={`mt-2 text-xs ${
saveOk ? "text-dracula-green" : "text-destructive"
saveOk ? "text-success" : "text-destructive"
}`}
>
{saveMsg}
@@ -967,7 +967,7 @@ function UserAIProviderSubsection() {
{testMsg && (
<p
className={`mt-2 text-xs ${
testOk ? "text-dracula-green" : "text-destructive"
testOk ? "text-success" : "text-destructive"
}`}
>
{testMsg}