feat(charts): storyboard annotations on HealthChart

Add an additive annotations[] prop to <HealthChart> that paints a
vertical Recharts <ReferenceLine> per AI-narrated event on the
underlying timeline. The line + tooltip + comparison overlay remain
untouched — annotations sit between the cartesian grid and the data
lines so they read as orientation, never as data.

The /insights page wires advisor.payload.insights.storyboardAnnotations
into the 90-day BP chart, mapping the four canonical categories to
Dracula colours (medication=pink, event=cyan, milestone=green,
warning=orange).

Pure helper resolveAnnotationPositions() handles the date->pointIndex
mapping with a 7-day snap window (so annotations don't stack on
monthly buckets) and a 24-char truncation for the small-viewport
label. The unit suite pins exact-day pinning, near-day snapping,
out-of-window dropping, and label truncation.

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-10 17:17:45 +02:00
1 parent f1868453af
commit ff1e335c19
3 files changed
+279

No files matched your search

+28
View File
@@ -890,6 +890,33 @@ export default function InsightsPage() {
}
: undefined;
// v1.4.20 phase B4 — storyboard annotations for the 90-day BP chart.
// The advisor payload may carry up to 20 entries; we transform them
// into the {date, label, color} shape <HealthChart> consumes. The
// colour map mirrors the four canonical categories. Cached payloads
// from before PROMPT_VERSION 4.20.2 simply produce an empty array.
const STORYBOARD_COLOR_BY_CATEGORY: Record<string, string> = {
medication: "var(--dracula-pink)",
event: "var(--dracula-cyan)",
milestone: "var(--dracula-green)",
warning: "var(--dracula-orange)",
};
const rawStoryboard = (
advisor.payload?.insights as
| { storyboardAnnotations?: Array<{
date: string;
label: string;
category: string;
}> }
| undefined
)?.storyboardAnnotations;
const bpStoryboardAnnotations = (rawStoryboard ?? []).map((entry) => ({
date: entry.date,
label: entry.label,
color:
STORYBOARD_COLOR_BY_CATEGORY[entry.category] ?? "var(--dracula-purple)",
}));
return (
<div className="space-y-8">
<HeroStrip
@@ -997,6 +1024,7 @@ export default function InsightsPage() {
yAxisUnit="Hg"
targetZones={bpTargetZones}
compareBaseline={compareBaseline}
annotations={bpStoryboardAnnotations}
/>
<div className="grid gap-4 xl:grid-cols-2">