From ec586ba75c95f912a767a67cd426c80b20365377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 5 Jul 2026 22:11:26 +0200 Subject: [PATCH] fix(dashboard): paint the dose ring in the medication hue, not green MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'Doses today' ring pinned the ring system's green arc — a colour that vocabulary reserves for band semantics. Every medication surface in Insights paints --primary (the compliance progress bars, the compliance trend line, the drug-level and dose-strength curves), so the ring now rides a new constant 'meds' hue on that token: flat by design (both gradient stops on --primary), never a band gradient over pending morning doses. Contrast, computed: dark #bd93f9 — 6.78:1 card / 5.90:1 bg; light #644ac9 — 6.00:1 card / 5.60:1 bg; both clear the 3:1 graphics floor with room. The guard now windows the assertion to the dose ring's own SVG and pins primary present, ring-green absent. --- .../hero/__tests__/dashboard-hero.test.tsx | 14 ++++++++--- .../dashboard/hero/dashboard-hero.tsx | 24 ++++++++++++------- src/components/insights/derived/ring-hues.ts | 19 +++++++++++++-- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/components/dashboard/hero/__tests__/dashboard-hero.test.tsx b/src/components/dashboard/hero/__tests__/dashboard-hero.test.tsx index e093e3a8f..81cc88758 100644 --- a/src/components/dashboard/hero/__tests__/dashboard-hero.test.tsx +++ b/src/components/dashboard/hero/__tests__/dashboard-hero.test.tsx @@ -395,12 +395,20 @@ describe(" — ring row (v1.27.7)", () => { expect(rings).toHaveLength(3); // Labels (de locale): the derived ring reuses its wellness-strip // title; the dose ring names today's tally and shows it as - // taken/scheduled over the constant green arc — never the band - // gradient (a pending morning dose is not an alert state). + // taken/scheduled over the constant med-family arc (`--primary`, + // the hue the medication surfaces in Insights paint) — never the + // band gradient (a pending morning dose is not an alert state) and + // never the ring system's green (reserved for band semantics). expect(html).toContain("Bereitschaft"); expect(html).toContain("Dosen heute"); expect(html).toContain(">1/3<"); - expect(html).toContain("var(--ring-green-from)"); + // Window the assertion to the dose ring's own SVG (its gradient defs + // close with the svg) so the trailing health-score ring's band-green + // gradient can't mask a regression. + const medIdx = html.indexOf('data-ring="MED_COMPLIANCE"'); + const doseRing = html.slice(medIdx, html.indexOf("", medIdx)); + expect(doseRing).toContain("var(--primary)"); + expect(doseRing).not.toContain("var(--ring-green-from)"); expect(html).not.toContain("var(--ring-yellow-from)"); }); diff --git a/src/components/dashboard/hero/dashboard-hero.tsx b/src/components/dashboard/hero/dashboard-hero.tsx index 08133cb84..7845ef737 100644 --- a/src/components/dashboard/hero/dashboard-hero.tsx +++ b/src/components/dashboard/hero/dashboard-hero.tsx @@ -101,16 +101,18 @@ const CTA_LABEL_KEY: Partial> = { /** * Per-ring hue for the selected score rings — the wellness-strip * vocabulary, so every hero ring paints EXACTLY the hue its insights - * sibling paints. MED_COMPLIANCE carries no per-metric hue entry: the - * dose ring pins the ring system's green arc (`band="green"`, constant) - * — the same green family the medication compliance surfaces in - * Insights paint for a taken dose — instead of a band gradient that - * would flash yellow/red over pending morning doses. + * sibling paints. MED_COMPLIANCE rides the `meds` hue: the medication + * family in Insights paints `--primary` on every surface (compliance + * bars, compliance trend line, drug-level / dose-strength curves), so + * the dose ring holds that one constant tone — never a band gradient + * that would flash yellow/red over pending morning doses, and not the + * green arc the ring system reserves for band semantics. */ const RING_HUE_BY_ID: Partial> = { READINESS: "readiness", RECOVERY_SCORE: "recovery", SLEEP_SCORE: "sleep", + MED_COMPLIANCE: "meds", }; /** Per-ring label key — reuses the existing score labels; the dose ring @@ -328,13 +330,19 @@ export function DashboardHero({ className="flex shrink-0 items-center" > {/* Dose ring — today's tally ("1/3") over the constant - green arc; the arc still sweeps on the 0..100 - progress `score`. Falls through to the score render - when a cached pre-doses snapshot carries no tally. */} + med-family arc (`hue="meds"` = --primary, the tone + every medication surface in Insights paints); the arc + still sweeps on the 0..100 progress `score`. + `band="green"` stays as the stable data-band anchor — + a pending morning dose is not an alert state — while + the hue owns the paint. Falls through to the score + render when a cached pre-doses snapshot carries no + tally. */} {ring.id === "MED_COMPLIANCE" && ring.doses ? ( `. */ -export type RingHue = "readiness" | "sleep" | "recovery" | "stress" | "strain"; +/** The per-metric hue keys the wellness strip passes to ``. + * `meds` is the dashboard dose ring: the medication family in Insights + * paints `--primary` everywhere (the compliance Progress bars, the + * compliance trend line, the drug-level and dose-strength curves), so + * the ring rides the same token — constant, never a band gradient. + * Contrast (computed): dark #bd93f9 — 6.78:1 card / 5.90:1 bg; light + * #644ac9 — 6.00:1 card / 5.60:1 bg — far above the 3:1 graphics + * floor in both themes, and a future `--primary` retune carries the + * ring along. */ +export type RingHue = + "readiness" | "sleep" | "recovery" | "stress" | "strain" | "meds"; /** * Near-flat single-hue arc `[from, to]` per metric, plus a band fallback for @@ -38,6 +47,9 @@ export const RING_GRADIENT: Record = { sleep: ["var(--ring-sleep-from)", "var(--ring-sleep-to)"], stress: ["var(--ring-stress-from)", "var(--ring-stress-to)"], strain: ["var(--ring-strain-from)", "var(--ring-strain-to)"], + // Perfectly flat by design (both stops on the one token) — the med + // family's `--primary`, not a hand-tuned from/to pair. + meds: ["var(--primary)", "var(--primary)"], // Band fallback for the anatomy detail view (no per-metric hue passed): green: ["var(--ring-green-from)", "var(--ring-green-to)"], yellow: ["var(--ring-yellow-from)", "var(--ring-yellow-to)"], @@ -54,4 +66,7 @@ export const TILE_HUE: Record = { recovery: "var(--tile-recovery)", stress: "var(--tile-stress)", strain: "var(--tile-strain)", + // No wellness tile carries the meds hue; the dose ring lives on the + // dashboard hero only. Primary keeps the record total. + meds: "var(--primary)", };