From 2afe32492b0d4f0d8b7547d5a9a986f799bfd909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 2 Jul 2026 00:00:37 +0200 Subject: [PATCH] refactor(insights): route metric-page and chart colors through theme tokens The per-metric reference bands, chart palettes, and status tints across the insights pages and shared charts carried hardcoded hex that glared on the light theme. Route them through the semantic and chart CSS variables; dark rendering stays byte-identical, light gets the muted set. --- src/app/insights/active-energy/page.tsx | 2 +- src/app/insights/audio-events/page.tsx | 2 +- src/app/insights/blood-glucose/page.tsx | 2 +- src/app/insights/blood-pressure/page.tsx | 10 ++++----- src/app/insights/bmi/page.tsx | 12 +++++----- src/app/insights/body-temperature/page.tsx | 2 +- src/app/insights/body-water/page.tsx | 2 +- src/app/insights/bone-mass/page.tsx | 2 +- .../insights/breathing-disturbances/page.tsx | 2 +- src/app/insights/cardio-fitness/page.tsx | 2 +- src/app/insights/cardio-recovery/page.tsx | 2 +- src/app/insights/daylight/page.tsx | 2 +- src/app/insights/double-support-time/page.tsx | 2 +- src/app/insights/environmental-audio/page.tsx | 2 +- src/app/insights/falls/page.tsx | 2 +- src/app/insights/fat-free-mass/page.tsx | 2 +- src/app/insights/fat-mass/page.tsx | 2 +- src/app/insights/flights-climbed/page.tsx | 2 +- src/app/insights/headphone-audio/page.tsx | 2 +- src/app/insights/hrv/page.tsx | 2 +- src/app/insights/lean-body-mass/page.tsx | 2 +- src/app/insights/muscle-mass/page.tsx | 2 +- src/app/insights/oxygen/page.tsx | 8 +++---- src/app/insights/pulse-wave-velocity/page.tsx | 2 +- src/app/insights/pulse/page.tsx | 22 ++++++++++++++----- src/app/insights/respiratory-rate/page.tsx | 2 +- src/app/insights/resting-pulse/page.tsx | 2 +- src/app/insights/six-minute-walk/page.tsx | 2 +- src/app/insights/skin-temperature/page.tsx | 4 ++-- src/app/insights/stair-ascent-speed/page.tsx | 2 +- src/app/insights/stair-descent-speed/page.tsx | 2 +- src/app/insights/step-length/page.tsx | 2 +- src/app/insights/steps/page.tsx | 2 +- src/app/insights/vascular-age/page.tsx | 2 +- src/app/insights/visceral-fat/page.tsx | 2 +- src/app/insights/walking-asymmetry/page.tsx | 2 +- src/app/insights/walking-distance/page.tsx | 2 +- src/app/insights/walking-heart-rate/page.tsx | 2 +- src/app/insights/walking-speed/page.tsx | 2 +- src/app/insights/walking-steadiness/page.tsx | 2 +- src/app/insights/weight/page.tsx | 2 +- src/app/insights/wrist-temperature/page.tsx | 2 +- .../health-chart-vertical-markers.test.ts | 4 ++-- src/components/charts/health-chart.tsx | 6 ++--- .../insights/glucose/glucose-tir-bar.tsx | 10 ++++----- .../insights/recovery/recovery-section.tsx | 14 ++++++------ .../insights/sleep-duration-chart.tsx | 2 +- .../insights/sleep-stage-stacked-bar.tsx | 10 ++++----- .../insights/sleep/sleep-quality-section.tsx | 12 +++++----- 49 files changed, 99 insertions(+), 89 deletions(-) diff --git a/src/app/insights/active-energy/page.tsx b/src/app/insights/active-energy/page.tsx index b5b126fe8..933931442 100644 --- a/src/app/insights/active-energy/page.tsx +++ b/src/app/insights/active-energy/page.tsx @@ -22,7 +22,7 @@ export default function InsightsActiveEnergyPage() { chartKey="activeEnergy" i18nPrefix="insights.activeEnergy" explainerMetric="activeEnergy" - color="#ffb86c" + color="var(--warning)" unit="kcal" yAxisUnit="kcal" emptyStateIcon={} diff --git a/src/app/insights/audio-events/page.tsx b/src/app/insights/audio-events/page.tsx index 570b879d3..29dfeb833 100644 --- a/src/app/insights/audio-events/page.tsx +++ b/src/app/insights/audio-events/page.tsx @@ -21,7 +21,7 @@ export default function InsightsLaermereignissePage() { chartKey="audioExposureEvent" i18nPrefix="insights.audioExposureEvent" explainerMetric="audioEvents" - color="#ff79c6" + color="var(--chart-3)" unit="" yAxisUnit="" emptyStateIcon={} diff --git a/src/app/insights/blood-glucose/page.tsx b/src/app/insights/blood-glucose/page.tsx index 22b2c3a9b..7860b40fa 100644 --- a/src/app/insights/blood-glucose/page.tsx +++ b/src/app/insights/blood-glucose/page.tsx @@ -51,7 +51,7 @@ export default function InsightsBlutzuckerPage() { chartKey="bloodGlucose" i18nPrefix="insights.bloodGlucose" explainerMetric="bloodGlucose" - color="#ff79c6" + color="var(--chart-3)" unit={glucoseUnit} yAxisUnit={glucoseUnit} // mmol/L = mg/dL ÷ 18.0182; the chart's valueScale multiplies, so pass diff --git a/src/app/insights/blood-pressure/page.tsx b/src/app/insights/blood-pressure/page.tsx index 09e49a51d..252395a67 100644 --- a/src/app/insights/blood-pressure/page.tsx +++ b/src/app/insights/blood-pressure/page.tsx @@ -88,19 +88,19 @@ export default function InsightsBlutdruckPage() { { min: bpTargets.sysLow, max: bpTargets.sysHigh, - color: "#ff79c6", + color: "var(--chart-3)", opacity: 0.21, label: t("charts.systolic"), - textColor: "#ff79c6", + textColor: "var(--chart-3)", lineOpacity: 0.24, }, { min: bpTargets.diaLow, max: bpTargets.diaHigh, - color: "#8be9fd", + color: "var(--info)", opacity: 0.21, label: t("charts.diastolic"), - textColor: "#8be9fd", + textColor: "var(--info)", lineOpacity: 0.24, }, ] @@ -164,7 +164,7 @@ export default function InsightsBlutdruckPage() { types={["BLOOD_PRESSURE_SYS", "BLOOD_PRESSURE_DIA"]} title={t("charts.bloodPressure")} titleIcon={HeartPulse} - colors={["#ff79c6", "#8be9fd"]} + colors={["var(--chart-3)", "var(--info)"]} unit="mmHg" yAxisUnit="mmHg" targetZones={bpTargetZones} diff --git a/src/app/insights/bmi/page.tsx b/src/app/insights/bmi/page.tsx index d15bad292..dced35190 100644 --- a/src/app/insights/bmi/page.tsx +++ b/src/app/insights/bmi/page.tsx @@ -31,11 +31,11 @@ import { SubPageShell } from "@/components/insights/sub-page-shell"; * the CTA targets `/settings/account`, not the measurement onboarding. */ const BMI_BANDS = [ - { min: 0, max: 17, color: "#ff5555", opacity: 0.16 }, - { min: 17, max: 18.5, color: "#ffb86c", opacity: 0.18 }, - { min: 18.5, max: 24.9, color: "#50fa7b", opacity: 0.2 }, - { min: 24.9, max: 29.9, color: "#ffb86c", opacity: 0.18 }, - { min: 29.9, max: 120, color: "#ff5555", opacity: 0.16 }, + { min: 0, max: 17, color: "var(--destructive)", opacity: 0.16 }, + { min: 17, max: 18.5, color: "var(--warning)", opacity: 0.18 }, + { min: 18.5, max: 24.9, color: "var(--success)", opacity: 0.2 }, + { min: 24.9, max: 29.9, color: "var(--warning)", opacity: 0.18 }, + { min: 29.9, max: 120, color: "var(--destructive)", opacity: 0.16 }, ]; export default function InsightsBmiPage() { @@ -117,7 +117,7 @@ export default function InsightsBmiPage() { chartKey="bmi" types={["WEIGHT"]} title={t("targets.bmi")} - colors={["#f1fa8c"]} + colors={["var(--dracula-yellow)"]} unit="kg/m²" valueMode="bmi" valueBands={BMI_BANDS} diff --git a/src/app/insights/body-temperature/page.tsx b/src/app/insights/body-temperature/page.tsx index b1ee0cf9f..db572f899 100644 --- a/src/app/insights/body-temperature/page.tsx +++ b/src/app/insights/body-temperature/page.tsx @@ -21,7 +21,7 @@ export default function InsightsBodyTemperaturePage() { chartKey="bodyTemperature" i18nPrefix="insights.bodyTemperature" explainerMetric="bodyTemperature" - color="#ff79c6" + color="var(--chart-3)" unit="°C" yAxisUnit="°C" emptyStateIcon={} diff --git a/src/app/insights/body-water/page.tsx b/src/app/insights/body-water/page.tsx index 3b7d359b4..854877bca 100644 --- a/src/app/insights/body-water/page.tsx +++ b/src/app/insights/body-water/page.tsx @@ -21,7 +21,7 @@ export default function InsightsKoerperwasserPage() { chartKey="totalBodyWater" i18nPrefix="insights.totalBodyWater" explainerMetric="bodyWater" - color="#8be9fd" + color="var(--info)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/bone-mass/page.tsx b/src/app/insights/bone-mass/page.tsx index 0fbcd7c2f..db944b5bd 100644 --- a/src/app/insights/bone-mass/page.tsx +++ b/src/app/insights/bone-mass/page.tsx @@ -21,7 +21,7 @@ export default function InsightsKnochenmassePage() { chartKey="boneMass" i18nPrefix="insights.boneMass" explainerMetric="boneMass" - color="#ffb86c" + color="var(--warning)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/breathing-disturbances/page.tsx b/src/app/insights/breathing-disturbances/page.tsx index a692ae338..51324fe2a 100644 --- a/src/app/insights/breathing-disturbances/page.tsx +++ b/src/app/insights/breathing-disturbances/page.tsx @@ -20,7 +20,7 @@ export default function InsightsBreathingDisturbancesPage() { chartKey="breathingDisturbances" i18nPrefix="insights.breathingDisturbances" explainerMetric="breathingDisturbances" - color="#8be9fd" + color="var(--info)" unit="count" yAxisUnit="count" emptyStateIcon={} diff --git a/src/app/insights/cardio-fitness/page.tsx b/src/app/insights/cardio-fitness/page.tsx index 010b7e66c..6de5d9b29 100644 --- a/src/app/insights/cardio-fitness/page.tsx +++ b/src/app/insights/cardio-fitness/page.tsx @@ -21,7 +21,7 @@ export default function InsightsCardioFitnessPage() { chartKey="vo2Max" i18nPrefix="insights.cardioFitness" explainerMetric="cardioFitness" - color="#bd93f9" + color="var(--chart-1)" unit="mL/(kg·min)" yAxisUnit="mL/(kg·min)" statIcon={Gauge} diff --git a/src/app/insights/cardio-recovery/page.tsx b/src/app/insights/cardio-recovery/page.tsx index e859c4558..16cc1fdf0 100644 --- a/src/app/insights/cardio-recovery/page.tsx +++ b/src/app/insights/cardio-recovery/page.tsx @@ -21,7 +21,7 @@ export default function InsightsCardioRecoveryPage() { chartKey="cardioRecovery" i18nPrefix="insights.cardioRecovery" explainerMetric="cardioRecovery" - color="#ff79c6" + color="var(--chart-3)" unit="bpm" yAxisUnit="bpm" emptyStateIcon={} diff --git a/src/app/insights/daylight/page.tsx b/src/app/insights/daylight/page.tsx index 3e94db7cd..5cecb4509 100644 --- a/src/app/insights/daylight/page.tsx +++ b/src/app/insights/daylight/page.tsx @@ -21,7 +21,7 @@ export default function InsightsTageslichtPage() { chartKey="timeInDaylight" i18nPrefix="insights.timeInDaylight" explainerMetric="daylight" - color="#50fa7b" + color="var(--success)" unit="min" yAxisUnit="min" emptyStateIcon={} diff --git a/src/app/insights/double-support-time/page.tsx b/src/app/insights/double-support-time/page.tsx index 0fe424711..9b7112851 100644 --- a/src/app/insights/double-support-time/page.tsx +++ b/src/app/insights/double-support-time/page.tsx @@ -21,7 +21,7 @@ export default function InsightsDoppelstandphasePage() { chartKey="walkingDoubleSupport" i18nPrefix="insights.walkingDoubleSupport" explainerMetric="doubleSupportTime" - color="#50fa7b" + color="var(--success)" unit="%" yAxisUnit="%" emptyStateIcon={} diff --git a/src/app/insights/environmental-audio/page.tsx b/src/app/insights/environmental-audio/page.tsx index 957930481..1259a1536 100644 --- a/src/app/insights/environmental-audio/page.tsx +++ b/src/app/insights/environmental-audio/page.tsx @@ -21,7 +21,7 @@ export default function InsightsLaermbelastungPage() { chartKey="audioExposureEnv" i18nPrefix="insights.audioExposureEnv" explainerMetric="environmentalAudio" - color="#ff79c6" + color="var(--chart-3)" unit="dBA" yAxisUnit="dBA" emptyStateIcon={} diff --git a/src/app/insights/falls/page.tsx b/src/app/insights/falls/page.tsx index 34c32ad46..9cd6ff193 100644 --- a/src/app/insights/falls/page.tsx +++ b/src/app/insights/falls/page.tsx @@ -19,7 +19,7 @@ export default function InsightsFallsPage() { chartKey="fallCount" i18nPrefix="insights.falls" explainerMetric="falls" - color="#ff5555" + color="var(--destructive)" unit="falls" yAxisUnit="falls" emptyStateIcon={} diff --git a/src/app/insights/fat-free-mass/page.tsx b/src/app/insights/fat-free-mass/page.tsx index 50f3008e2..54875212f 100644 --- a/src/app/insights/fat-free-mass/page.tsx +++ b/src/app/insights/fat-free-mass/page.tsx @@ -21,7 +21,7 @@ export default function InsightsFettfreieMassePage() { chartKey="fatFreeMass" i18nPrefix="insights.fatFreeMass" explainerMetric="fatFreeMass" - color="#bd93f9" + color="var(--chart-1)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/fat-mass/page.tsx b/src/app/insights/fat-mass/page.tsx index adfde941c..fa27ad08e 100644 --- a/src/app/insights/fat-mass/page.tsx +++ b/src/app/insights/fat-mass/page.tsx @@ -21,7 +21,7 @@ export default function InsightsFettmassePage() { chartKey="fatMass" i18nPrefix="insights.fatMass" explainerMetric="fatMass" - color="#ffb86c" + color="var(--warning)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/flights-climbed/page.tsx b/src/app/insights/flights-climbed/page.tsx index 34d4d35ec..8486cfbf3 100644 --- a/src/app/insights/flights-climbed/page.tsx +++ b/src/app/insights/flights-climbed/page.tsx @@ -21,7 +21,7 @@ export default function InsightsStockwerkePage() { chartKey="flightsClimbed" i18nPrefix="insights.flightsClimbed" explainerMetric="flightsClimbed" - color="#50fa7b" + color="var(--success)" unit="flights" yAxisUnit="flights" emptyStateIcon={} diff --git a/src/app/insights/headphone-audio/page.tsx b/src/app/insights/headphone-audio/page.tsx index 3670be637..ac0e7c2ed 100644 --- a/src/app/insights/headphone-audio/page.tsx +++ b/src/app/insights/headphone-audio/page.tsx @@ -21,7 +21,7 @@ export default function InsightsKopfhoererpegelPage() { chartKey="audioExposureHeadphone" i18nPrefix="insights.audioExposureHeadphone" explainerMetric="headphoneAudio" - color="#ff79c6" + color="var(--chart-3)" unit="dBA" yAxisUnit="dBA" emptyStateIcon={} diff --git a/src/app/insights/hrv/page.tsx b/src/app/insights/hrv/page.tsx index 74f1c5c2d..353d8804f 100644 --- a/src/app/insights/hrv/page.tsx +++ b/src/app/insights/hrv/page.tsx @@ -27,7 +27,7 @@ export default function InsightsHrvPage() { chartKey="hrv" i18nPrefix="insights.hrv" explainerMetric="hrv" - color="#bd93f9" + color="var(--chart-1)" unit="ms" yAxisUnit="ms" emptyStateIcon={} diff --git a/src/app/insights/lean-body-mass/page.tsx b/src/app/insights/lean-body-mass/page.tsx index 126c39bbe..e055eeb9c 100644 --- a/src/app/insights/lean-body-mass/page.tsx +++ b/src/app/insights/lean-body-mass/page.tsx @@ -21,7 +21,7 @@ export default function InsightsMagermassePage() { chartKey="leanBodyMass" i18nPrefix="insights.leanBodyMass" explainerMetric="leanBodyMass" - color="#bd93f9" + color="var(--chart-1)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/muscle-mass/page.tsx b/src/app/insights/muscle-mass/page.tsx index 0c4f770f5..bf6fb6500 100644 --- a/src/app/insights/muscle-mass/page.tsx +++ b/src/app/insights/muscle-mass/page.tsx @@ -21,7 +21,7 @@ export default function InsightsMuskelmassePage() { chartKey="muscleMass" i18nPrefix="insights.muscleMass" explainerMetric="muscleMass" - color="#bd93f9" + color="var(--chart-1)" unit="kg" yAxisUnit="kg" emptyStateIcon={} diff --git a/src/app/insights/oxygen/page.tsx b/src/app/insights/oxygen/page.tsx index def6a478f..9d10b81ed 100644 --- a/src/app/insights/oxygen/page.tsx +++ b/src/app/insights/oxygen/page.tsx @@ -23,16 +23,16 @@ export default function InsightsOxygenSaturationPage() { chartKey="oxygenSaturation" i18nPrefix="insights.oxygenSaturation" explainerMetric="oxygenSaturation" - color="#8be9fd" + color="var(--info)" unit="%" yAxisUnit="%" valueBands={[ // < 90 % — clinical hypoxia floor, paint the danger band. - { min: 80, max: 90, color: "#ff5555", opacity: 0.18 }, + { min: 80, max: 90, color: "var(--destructive)", opacity: 0.18 }, // 90 .. 95 % — watch zone. - { min: 90, max: 95, color: "#ffb86c", opacity: 0.18 }, + { min: 90, max: 95, color: "var(--warning)", opacity: 0.18 }, // 95 .. 100 % — clinical normal. - { min: 95, max: 100, color: "#50fa7b", opacity: 0.18 }, + { min: 95, max: 100, color: "var(--success)", opacity: 0.18 }, ]} emptyStateIcon={} emptyStateCtaType={null} diff --git a/src/app/insights/pulse-wave-velocity/page.tsx b/src/app/insights/pulse-wave-velocity/page.tsx index e6666e845..e3460aeb7 100644 --- a/src/app/insights/pulse-wave-velocity/page.tsx +++ b/src/app/insights/pulse-wave-velocity/page.tsx @@ -21,7 +21,7 @@ export default function InsightsPulswellengeschwindigkeitPage() { chartKey="pulseWaveVelocity" i18nPrefix="insights.pulseWaveVelocity" explainerMetric="pulseWaveVelocity" - color="#ff5555" + color="var(--destructive)" unit="m/s" yAxisUnit="m/s" emptyStateIcon={} diff --git a/src/app/insights/pulse/page.tsx b/src/app/insights/pulse/page.tsx index fe9701269..cb3963e16 100644 --- a/src/app/insights/pulse/page.tsx +++ b/src/app/insights/pulse/page.tsx @@ -98,26 +98,36 @@ export default function InsightsPulsPage() { (user?.gender as "MALE" | "FEMALE" | null | undefined) ?? null, ); const pulseBands = [ - { min: 30, max: pulseTarget.orangeMin, color: "#ff5555", opacity: 0.16 }, + { + min: 30, + max: pulseTarget.orangeMin, + color: "var(--destructive)", + opacity: 0.16, + }, { min: pulseTarget.orangeMin, max: pulseTarget.greenMin, - color: "#ffb86c", + color: "var(--warning)", opacity: 0.18, }, { min: pulseTarget.greenMin, max: pulseTarget.greenMax, - color: "#50fa7b", + color: "var(--success)", opacity: 0.2, }, { min: pulseTarget.greenMax, max: pulseTarget.orangeMax, - color: "#ffb86c", + color: "var(--warning)", opacity: 0.18, }, - { min: pulseTarget.orangeMax, max: 220, color: "#ff5555", opacity: 0.16 }, + { + min: pulseTarget.orangeMax, + max: 220, + color: "var(--destructive)", + opacity: 0.16, + }, ].filter((band) => band.max > band.min); return ( @@ -156,7 +166,7 @@ export default function InsightsPulsPage() { types={hasRestingHr ? ["RESTING_HEART_RATE"] : ["PULSE"]} title={t("charts.pulse")} titleIcon={Heart} - colors={["#50fa7b"]} + colors={["var(--success)"]} unit="bpm" valueBands={hasRestingHr ? pulseBands : undefined} compareBaseline={compareBaseline} diff --git a/src/app/insights/respiratory-rate/page.tsx b/src/app/insights/respiratory-rate/page.tsx index a9292e46a..726f6a216 100644 --- a/src/app/insights/respiratory-rate/page.tsx +++ b/src/app/insights/respiratory-rate/page.tsx @@ -21,7 +21,7 @@ export default function InsightsAtemfrequenzPage() { chartKey="respiratoryRate" i18nPrefix="insights.respiratoryRate" explainerMetric="respiratoryRate" - color="#8be9fd" + color="var(--info)" unit="breaths/min" yAxisUnit="breaths/min" emptyStateIcon={} diff --git a/src/app/insights/resting-pulse/page.tsx b/src/app/insights/resting-pulse/page.tsx index 95a16af3a..f78e24699 100644 --- a/src/app/insights/resting-pulse/page.tsx +++ b/src/app/insights/resting-pulse/page.tsx @@ -24,7 +24,7 @@ export default function InsightsRestingHrPage() { chartKey="restingHr" i18nPrefix="insights.restingHr" explainerMetric="restingHr" - color="#ff5555" + color="var(--destructive)" unit="bpm" yAxisUnit="bpm" emptyStateIcon={} diff --git a/src/app/insights/six-minute-walk/page.tsx b/src/app/insights/six-minute-walk/page.tsx index 991e453c5..9c0e52e84 100644 --- a/src/app/insights/six-minute-walk/page.tsx +++ b/src/app/insights/six-minute-walk/page.tsx @@ -20,7 +20,7 @@ export default function InsightsSixMinuteWalkPage() { chartKey="sixMinuteWalkDistance" i18nPrefix="insights.sixMinuteWalk" explainerMetric="sixMinuteWalk" - color="#50fa7b" + color="var(--success)" unit="m" yAxisUnit="m" emptyStateIcon={} diff --git a/src/app/insights/skin-temperature/page.tsx b/src/app/insights/skin-temperature/page.tsx index 87c506e2f..e04a3bcad 100644 --- a/src/app/insights/skin-temperature/page.tsx +++ b/src/app/insights/skin-temperature/page.tsx @@ -29,7 +29,7 @@ export default function InsightsHauttemperaturPage() { chartKey="skinTemperature" i18nPrefix="insights.skinTemperature" explainerMetric="skinTemperature" - color="#ffb86c" + color="var(--warning)" unit="°C" yAxisUnit="°C" emptyStateIcon={} @@ -40,7 +40,7 @@ export default function InsightsHauttemperaturPage() { type="BODY_TEMPERATURE_DEVIATION" title={t("measurements.typeBodyTemperatureDeviation")} icon={ThermometerSnowflake} - color="#8be9fd" + color="var(--info)" unit="°C" fractionDigits={2} sectionTitle={t("insights.bodyTempDeviation.title")} diff --git a/src/app/insights/stair-ascent-speed/page.tsx b/src/app/insights/stair-ascent-speed/page.tsx index 18ec8d6aa..a91043428 100644 --- a/src/app/insights/stair-ascent-speed/page.tsx +++ b/src/app/insights/stair-ascent-speed/page.tsx @@ -20,7 +20,7 @@ export default function InsightsStairAscentSpeedPage() { chartKey="stairAscentSpeed" i18nPrefix="insights.stairAscentSpeed" explainerMetric="stairAscentSpeed" - color="#50fa7b" + color="var(--success)" unit="m/s" yAxisUnit="m/s" emptyStateIcon={} diff --git a/src/app/insights/stair-descent-speed/page.tsx b/src/app/insights/stair-descent-speed/page.tsx index d7066413c..3dc31f478 100644 --- a/src/app/insights/stair-descent-speed/page.tsx +++ b/src/app/insights/stair-descent-speed/page.tsx @@ -20,7 +20,7 @@ export default function InsightsStairDescentSpeedPage() { chartKey="stairDescentSpeed" i18nPrefix="insights.stairDescentSpeed" explainerMetric="stairDescentSpeed" - color="#50fa7b" + color="var(--success)" unit="m/s" yAxisUnit="m/s" emptyStateIcon={} diff --git a/src/app/insights/step-length/page.tsx b/src/app/insights/step-length/page.tsx index 56c3a62d0..d373f0f80 100644 --- a/src/app/insights/step-length/page.tsx +++ b/src/app/insights/step-length/page.tsx @@ -21,7 +21,7 @@ export default function InsightsSchrittlaengePage() { chartKey="walkingStepLength" i18nPrefix="insights.walkingStepLength" explainerMetric="stepLength" - color="#50fa7b" + color="var(--success)" unit="m" yAxisUnit="m" emptyStateIcon={} diff --git a/src/app/insights/steps/page.tsx b/src/app/insights/steps/page.tsx index 0a4a7b401..13f7c26dc 100644 --- a/src/app/insights/steps/page.tsx +++ b/src/app/insights/steps/page.tsx @@ -26,7 +26,7 @@ export default function InsightsStepsPage() { i18nPrefix="insights.steps" explainerMetric="steps" statIcon={Footprints} - color="#50fa7b" + color="var(--success)" unit="steps" yAxisUnit="steps" emptyStateIcon={} diff --git a/src/app/insights/vascular-age/page.tsx b/src/app/insights/vascular-age/page.tsx index cd695db74..dfc04b043 100644 --- a/src/app/insights/vascular-age/page.tsx +++ b/src/app/insights/vascular-age/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGefaessalterPage() { chartKey="vascularAge" i18nPrefix="insights.vascularAge" explainerMetric="vascularAge" - color="#ff79c6" + color="var(--chart-3)" unit="years" yAxisUnit="years" emptyStateIcon={} diff --git a/src/app/insights/visceral-fat/page.tsx b/src/app/insights/visceral-fat/page.tsx index c168d1996..fcefd0522 100644 --- a/src/app/insights/visceral-fat/page.tsx +++ b/src/app/insights/visceral-fat/page.tsx @@ -21,7 +21,7 @@ export default function InsightsViszeralfettPage() { chartKey="visceralFat" i18nPrefix="insights.visceralFat" explainerMetric="visceralFat" - color="#ffb86c" + color="var(--warning)" unit="" yAxisUnit="" emptyStateIcon={} diff --git a/src/app/insights/walking-asymmetry/page.tsx b/src/app/insights/walking-asymmetry/page.tsx index 4c81864e7..cc870dc61 100644 --- a/src/app/insights/walking-asymmetry/page.tsx +++ b/src/app/insights/walking-asymmetry/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGangasymmetriePage() { chartKey="walkingAsymmetry" i18nPrefix="insights.walkingAsymmetry" explainerMetric="walkingAsymmetry" - color="#50fa7b" + color="var(--success)" unit="%" yAxisUnit="%" emptyStateIcon={} diff --git a/src/app/insights/walking-distance/page.tsx b/src/app/insights/walking-distance/page.tsx index fe51dceb9..0872c7890 100644 --- a/src/app/insights/walking-distance/page.tsx +++ b/src/app/insights/walking-distance/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGehstreckePage() { chartKey="walkingRunningDistance" i18nPrefix="insights.walkingRunningDistance" explainerMetric="walkingDistance" - color="#50fa7b" + color="var(--success)" unit="km" yAxisUnit="km" // Stored in metres; display daily totals in km (1 m = 0.001 km). diff --git a/src/app/insights/walking-heart-rate/page.tsx b/src/app/insights/walking-heart-rate/page.tsx index 10e0002a5..0340bfdd8 100644 --- a/src/app/insights/walking-heart-rate/page.tsx +++ b/src/app/insights/walking-heart-rate/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGehpulsPage() { chartKey="walkingHeartRateAverage" i18nPrefix="insights.walkingHeartRateAverage" explainerMetric="walkingHeartRate" - color="#ff5555" + color="var(--destructive)" unit="bpm" yAxisUnit="bpm" emptyStateIcon={} diff --git a/src/app/insights/walking-speed/page.tsx b/src/app/insights/walking-speed/page.tsx index 15b87d531..8223c557e 100644 --- a/src/app/insights/walking-speed/page.tsx +++ b/src/app/insights/walking-speed/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGehgeschwindigkeitPage() { chartKey="walkingSpeed" i18nPrefix="insights.walkingSpeed" explainerMetric="walkingSpeed" - color="#50fa7b" + color="var(--success)" unit="km/h" yAxisUnit="km/h" valueScale={3.6} diff --git a/src/app/insights/walking-steadiness/page.tsx b/src/app/insights/walking-steadiness/page.tsx index e9fb5696f..91bfa01ce 100644 --- a/src/app/insights/walking-steadiness/page.tsx +++ b/src/app/insights/walking-steadiness/page.tsx @@ -21,7 +21,7 @@ export default function InsightsGangstabilitaetPage() { chartKey="walkingSteadiness" i18nPrefix="insights.walkingSteadiness" explainerMetric="walkingSteadiness" - color="#50fa7b" + color="var(--success)" unit="%" yAxisUnit="%" emptyStateIcon={} diff --git a/src/app/insights/weight/page.tsx b/src/app/insights/weight/page.tsx index 453a2e3e4..a43287bf8 100644 --- a/src/app/insights/weight/page.tsx +++ b/src/app/insights/weight/page.tsx @@ -104,7 +104,7 @@ export default function InsightsGewichtPage() { types={["WEIGHT"]} title={t("charts.weight")} titleIcon={Scale} - colors={["#bd93f9"]} + colors={["var(--chart-1)"]} unit="kg" valueBands={weightBands} compareBaseline={compareBaseline} diff --git a/src/app/insights/wrist-temperature/page.tsx b/src/app/insights/wrist-temperature/page.tsx index 7376b6457..eedb62695 100644 --- a/src/app/insights/wrist-temperature/page.tsx +++ b/src/app/insights/wrist-temperature/page.tsx @@ -21,7 +21,7 @@ export default function InsightsWristTemperaturePage() { chartKey="wristTemperature" i18nPrefix="insights.wristTemperature" explainerMetric="wristTemperature" - color="#ffb86c" + color="var(--warning)" unit="°C" yAxisUnit="°C" emptyStateIcon={} diff --git a/src/components/charts/__tests__/health-chart-vertical-markers.test.ts b/src/components/charts/__tests__/health-chart-vertical-markers.test.ts index 6babb1ac2..427d2813b 100644 --- a/src/components/charts/__tests__/health-chart-vertical-markers.test.ts +++ b/src/components/charts/__tests__/health-chart-vertical-markers.test.ts @@ -46,7 +46,7 @@ describe("resolveVerticalMarkerPositions", () => { ); expect(positions).toHaveLength(1); expect(positions[0].pointIndex).toBe(0); - expect(positions[0].color).toBe("#50fa7b"); + expect(positions[0].color).toBe("var(--success)"); expect(positions[0].label).toBeUndefined(); }); @@ -69,7 +69,7 @@ describe("resolveVerticalMarkerPositions", () => { expect(positions[0].color).toBe("#ff79c6"); expect(positions[0].label).toBe("Mounjaro 7.5"); // Default color preserved for the second marker. - expect(positions[1].color).toBe("#50fa7b"); + expect(positions[1].color).toBe("var(--success)"); expect(positions[1].label).toBeUndefined(); }); diff --git a/src/components/charts/health-chart.tsx b/src/components/charts/health-chart.tsx index 7d667dc6b..a6541e8ac 100644 --- a/src/components/charts/health-chart.tsx +++ b/src/components/charts/health-chart.tsx @@ -190,7 +190,7 @@ interface HealthChartProps { * 2. A small filled dot sits at the x-axis intersection (mood- * chart style emoji-on-axis pattern repurposed) so a row of * green dots reads as "injection cadence" at a glance. - * 3. Default green (`#50fa7b`) to match the strip-tile palette + * 3. Default green (`var(--success)`) to match the strip-tile palette * for active medications; callers can override per marker. * * Off-window markers silently drop via `ifOverflow="discard"`, @@ -485,7 +485,7 @@ export function resolveVerticalMarkerPositions( if (idx === undefined) continue; out.push({ pointIndex: idx, - color: marker.color ?? "#50fa7b", + color: marker.color ?? "var(--success)", label: marker.label, }); } @@ -570,7 +570,7 @@ function buildTrendSeriesByTime(data: Array<{ date: Date; value: number }>): { export function HealthChart({ types, title, - colors = ["#bd93f9", "#ff79c6", "#8be9fd"], + colors = ["var(--chart-1)", "var(--chart-3)", "var(--chart-4)"], unit, yAxisUnit, valueMode = "raw", diff --git a/src/components/insights/glucose/glucose-tir-bar.tsx b/src/components/insights/glucose/glucose-tir-bar.tsx index 704a7eefd..745cc701d 100644 --- a/src/components/insights/glucose/glucose-tir-bar.tsx +++ b/src/components/insights/glucose/glucose-tir-bar.tsx @@ -16,11 +16,11 @@ import type { TimeInRangeDistribution } from "@/lib/analytics/glucose-metrics"; */ const BAND_COLORS = { - veryLow: "#ff5555", // dracula-red — urgent low - low: "#ffb86c", // dracula-orange — low - inRange: "#50fa7b", // dracula-green — target - high: "#f1fa8c", // dracula-yellow — high - veryHigh: "#ff79c6", // dracula-pink — urgent high + veryLow: "var(--destructive)", // dracula-red — urgent low + low: "var(--warning)", // dracula-orange — low + inRange: "var(--success)", // dracula-green — target + high: "var(--dracula-yellow)", // dracula-yellow — high + veryHigh: "var(--chart-3)", // dracula-pink — urgent high } as const; type BandKey = keyof typeof BAND_COLORS; diff --git a/src/components/insights/recovery/recovery-section.tsx b/src/components/insights/recovery/recovery-section.tsx index 908d96795..084af1270 100644 --- a/src/components/insights/recovery/recovery-section.tsx +++ b/src/components/insights/recovery/recovery-section.tsx @@ -89,7 +89,7 @@ export function RecoverySection() { title: t("measurements.typeAnsCharge"), explainer: t("insights.recovery.block.ansChargeExplainer"), icon: Battery, - color: "#50fa7b", + color: "var(--success)", unit: unitScore, fractionDigits: 1, }, @@ -105,7 +105,7 @@ export function RecoverySection() { title: t("measurements.typeDayStrain"), explainer: t("insights.recovery.block.dayStrainExplainer"), icon: Gauge, - color: "#ffb86c", + color: "var(--warning)", unit: unitScore, fractionDigits: 1, }, @@ -116,7 +116,7 @@ export function RecoverySection() { title: t("measurements.typeWorkoutStrain"), explainer: t("insights.recovery.block.workoutStrainExplainer"), icon: Activity, - color: "#ff79c6", + color: "var(--chart-3)", unit: unitScore, fractionDigits: 1, }, @@ -127,7 +127,7 @@ export function RecoverySection() { title: t("measurements.typeCardioLoad"), explainer: t("insights.recovery.block.cardioLoadExplainer"), icon: TrendingUp, - color: "#bd93f9", + color: "var(--chart-1)", unit: unitScore, }, ], @@ -142,7 +142,7 @@ export function RecoverySection() { title: t("measurements.typeAverageHeartRate"), explainer: t("insights.recovery.block.averageHeartRateExplainer"), icon: Heart, - color: "#8be9fd", + color: "var(--info)", unit: unitBpm, }, { @@ -152,7 +152,7 @@ export function RecoverySection() { title: t("measurements.typeMaxHeartRate"), explainer: t("insights.recovery.block.maxHeartRateExplainer"), icon: HeartPulse, - color: "#ff5555", + color: "var(--destructive)", unit: unitBpm, }, { @@ -162,7 +162,7 @@ export function RecoverySection() { title: t("measurements.typeEnergyExpenditureKj"), explainer: t("insights.recovery.block.energyExpenditureKjExplainer"), icon: Flame, - color: "#f1fa8c", + color: "var(--dracula-yellow)", unit: unitKj, }, ], diff --git a/src/components/insights/sleep-duration-chart.tsx b/src/components/insights/sleep-duration-chart.tsx index 9d5a20a07..47b5a75bc 100644 --- a/src/components/insights/sleep-duration-chart.tsx +++ b/src/components/insights/sleep-duration-chart.tsx @@ -42,7 +42,7 @@ export function SleepDurationChart({ chartKey="sleep" types={["SLEEP_DURATION"]} title={t("charts.sleep")} - colors={["#8be9fd"]} + colors={["var(--info)"]} unit="h" yAxisUnit="h" compareBaseline={compareBaseline} diff --git a/src/components/insights/sleep-stage-stacked-bar.tsx b/src/components/insights/sleep-stage-stacked-bar.tsx index f31507094..f79bce378 100644 --- a/src/components/insights/sleep-stage-stacked-bar.tsx +++ b/src/components/insights/sleep-stage-stacked-bar.tsx @@ -89,11 +89,11 @@ export const STAGE_ORDER = ["DEEP", "REM", "CORE", "ASLEEP", "AWAKE"] as const; * charts-visual-identity rule, no token reshuffle. */ export const STAGE_COLORS: Record = { - DEEP: "#bd93f9", // dracula-purple — deepest, most restorative - REM: "#ff79c6", // dracula-pink — dream phase - CORE: "#8be9fd", // dracula-cyan — bulk of sleep - ASLEEP: "#50fa7b", // dracula-green — legacy iOS 15- unspecified - AWAKE: "#f1fa8c", // dracula-yellow — wake bouts + DEEP: "var(--chart-1)", // dracula-purple — deepest, most restorative + REM: "var(--chart-3)", // dracula-pink — dream phase + CORE: "var(--info)", // dracula-cyan — bulk of sleep + ASLEEP: "var(--success)", // dracula-green — legacy iOS 15- unspecified + AWAKE: "var(--dracula-yellow)", // dracula-yellow — wake bouts IN_BED: "#6272a4", // dracula-comment — pre-asleep }; diff --git a/src/components/insights/sleep/sleep-quality-section.tsx b/src/components/insights/sleep/sleep-quality-section.tsx index b471c092f..593e7dd4b 100644 --- a/src/components/insights/sleep/sleep-quality-section.tsx +++ b/src/components/insights/sleep/sleep-quality-section.tsx @@ -57,42 +57,42 @@ export function SleepQualitySection({ enabled }: { enabled: boolean }) { type: "SLEEP_SCORE", title: t("measurements.typeSleepScore"), icon: Moon, - color: "#bd93f9", + color: "var(--chart-1)", unit: t("insights.deviceScore.unitScore"), }, { type: "SLEEP_PERFORMANCE", title: t("measurements.typeSleepPerformance"), icon: Target, - color: "#8be9fd", + color: "var(--info)", unit: "%", }, { type: "SLEEP_EFFICIENCY", title: t("measurements.typeSleepEfficiency"), icon: Gauge, - color: "#50fa7b", + color: "var(--success)", unit: "%", }, { type: "SLEEP_CONSISTENCY", title: t("measurements.typeSleepConsistency"), icon: Repeat, - color: "#f1fa8c", + color: "var(--dracula-yellow)", unit: "%", }, { type: "SLEEP_NEED", title: t("measurements.typeSleepNeed"), icon: Waves, - color: "#ffb86c", + color: "var(--warning)", unit: t("insights.deviceScore.unitMinutes"), }, { type: "SLEEP_DISTURBANCE_COUNT", title: t("measurements.typeSleepDisturbanceCount"), icon: Activity, - color: "#ff79c6", + color: "var(--chart-3)", }, ];