Public: anyone can read this; the crew can change it.
The sparkline helper draws a day with no data as a gap, not a zero #3244
Check · Review · Land · Live done — Landed and live in production.
`src/web/studio/kpi_row.ts` now exports `daySpark(days: readonly (number | null)[], label: string): Html | null`. A `null` day breaks the line instead of being drawn as a zero. Each run of numbers is its own `<polyline>` inside one `<svg class="kpi-spark">`, and a run of one day is a `<circle r="1.5" fill="currentColor">`. All the runs share one y-scale, which tops out at the largest known value.…
shipped production is serving it deploy e36361f
src/web/studio/kpi_row.ts now exports daySpark(days: readonly (number | null)[], label: string): Html | null. A null day breaks the line instead of being drawn as a zero. Each run of numbers is its own <polyline> inside one <svg class="kpi-spark">, and a run of one day is a <circle r="1.5" fill="currentColor">. All the runs share one y-scale, which tops out at the largest known value. A series that is empty or all null returns null, so no svg is drawn. Non-finite values also count as missing. The label is escaped with escapeHtml.
- Existing sparklines unchanged: the point math and the
<svg>wrapper moved into two small helpers,atandsvg, thatsparkanddaySparkboth use. A new test pins the full markup ofvisitorsSparkandsparkline, and theW/Hbox is untouched. - Design system: no class, colour literal or
style=was added, anddocs/design/baseline.jsonis not edited.test/design-lint.test.tspasses, along withhome-kpi-row,home-kpisand the type check. - Where the issue contradicts itself: it asks for
[1, null, 3, 4]to give two polylines, but also says a run of one day is a dot. I kept the dot rule, so[1, null, 3, 4]gives one dot and one polyline, and the test says so.[1, 2, null, 3, 4]gives the two polylines. Both tests check the expected points, worked by hand in the test file, and that nothing is drawn at the zero line. - Return type: the issue gives the type as
Html, but it also says an all-nullseries returns nothing, so the type isHtml | null. A tile'sextraslot already takesnull. - Not done: no caller uses
daySparkyet. Switching the visitors tile over is the other half of #3202.
test/kpi-spark.test.ts fails without the change (it can't import daySpark) and passes with it. Try it with bun test test/kpi-spark.test.ts.
🤖 Generated with Claude Code
Matches #3238 as scoped: daySpark breaks the line at null or non-finite days, draws a lone day as a dot, returns null for no data, escapes the label, and reuses .kpi-spark, currentColor and attributes only (no class, colour, style, or baseline edit). The shared at/svg helpers leave visitorsSpark and sparkline byte-identical, and a test pins that. The dot rule over the issue contradictory [1,null,3,4] example is the right call and is explained. No page or script is touched, so there is no JS-off, keyboard or 360px concern; the svg keeps role=img and an aria-label. Two things next: 1) switch the visitors tile to daySpark (the other half of #3202) so it is reachable on the page, since it has no caller today; 2) spark still interpolates its label unescaped; pass it through escapeHtml too or have svg do it once.
src/web/studio/kpi_row.tsnow exportsdaySpark(days: readonly (number | null)[], label: string): Html | null. Anullday breaks the line instead of being drawn as a zero. Each run of numbers is its own<polyline>inside one<svg class="kpi-spark">, and a run of one day is a<circle r="1.5" fill="currentColor">. All the runs share one y-scale, which tops out at the largest known value. A series that is empty or allnullreturnsnull, so no svg is drawn. Non-finite values also count as missing. The label is escaped withescapeHtml.<svg>wrapper moved into two small helpers,atandsvg, thatsparkanddaySparkboth use. A new test pins the full markup ofvisitorsSparkandsparkline, and theW/Hbox is untouched.style=was added, anddocs/design/baseline.jsonis not edited.test/design-lint.test.tspasses, along withhome-kpi-row,home-kpisand the type check.[1, null, 3, 4]to give two polylines, but also says a run of one day is a dot. I kept the dot rule, so[1, null, 3, 4]gives one dot and one polyline, and the test says so.[1, 2, null, 3, 4]gives the two polylines. Both tests check the expected points, worked by hand in the test file, and that nothing is drawn at the zero line.Html, but it also says an all-nullseries returns nothing, so the type isHtml | null. A tile'sextraslot already takesnull.daySparkyet. Switching the visitors tile over is the other half of #3202.test/kpi-spark.test.tsfails without the change (it can't importdaySpark) and passes with it. Try it withbun test test/kpi-spark.test.ts.🤖 Generated with Claude Code
Closes #3238