Report: sparkline charts on numeric history + stage-grouped date timeline

Two visual additions to the read-only activity report.

Sparkline: when the user expands earlier-entries on a numeric field
(number/currency/percent) with two or more numeric points, the
expansion now leads with a 240x56 inline SVG trend chart — chronological
polyline, faint area fill, small dots at every measurement, a slightly
larger emphasized dot on the most recent point. Min and max captions
sit beneath in tabular-nums, formatted in the field's native style
(currency uses Intl, percent appends %, etc.). Non-numeric fields are
unchanged.

DateTimeline: a new card between the context header and the section
accordions. Walks every date-type field in stage sections 1-5 (Stage 0
omitted as it isn't a stage in the journey sense), pulls each field's
most-recent entered date, and lays the events out in five horizontal
swim lanes — one per stage rank, labeled at the left. Time axis
spans from the earliest event to max(latest event, Date_Opened).
Stage 5's Date_Opened is rendered as a larger clay-700 dot with a
heavier ring so it reads as the journey's anchor at the right end.
A faint clay-300 dashed vertical line marks 'today' if it falls
within the range. Color scale across stages is leaf-300 / leaf-500
/ leaf-600 / leaf-700 / clay-700 — a sprout-to-fruit gradient that
matches the existing palette. Empty stage rows still draw their lane
line at half opacity so the structure stays readable. SR-only event
list provides screen-reader access to all plotted dates with their
labels.

Stub payload enriched with four cross-stage date entries so the
timeline has content in dev preview.
This commit is contained in:
Joel Brock
2026-05-19 16:16:57 -07:00
parent 9209d6dc02
commit 814b560363
2 changed files with 319 additions and 15 deletions
+18
View File
@@ -41,6 +41,10 @@ const STUB_PAYLOAD: ReportPayload = (() => {
const today = new Date();
const daysAgo = (n: number) =>
new Date(today.getTime() - n * 24 * 3600 * 1000).toISOString();
const ymd = (n: number) => {
const d = new Date(today.getTime() - n * 24 * 3600 * 1000);
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
};
return {
orgName: "Sample Co-op (stub)",
currentStage: "Organizing",
@@ -69,6 +73,20 @@ const STUB_PAYLOAD: ReportPayload = (() => {
{ activityId: 9012, date: daysAgo(3), value: "Strong" },
{ activityId: 8995, date: daysAgo(95), value: "Moderate" },
],
// Stage-spanning dates so the timeline strip has events across the
// whole journey in dev preview.
Preliminary_Market_Assessment: [
{ activityId: 8995, date: daysAgo(95), value: ymd(180) },
],
Market_Study_Date: [
{ activityId: 9008, date: daysAgo(34), value: ymd(60) },
],
Projected_Opening_Date: [
{ activityId: 9012, date: daysAgo(3), value: ymd(-365) },
],
Date_Opened: [
{ activityId: 9012, date: daysAgo(3), value: ymd(-450) },
],
},
options: {
140: [{ value: "Yes", label: "Yes" }, { value: "No", label: "No" }, { value: "Considering", label: "Considering" }],