Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
474193e
feat(charts)!: draw charts like a report's, with heatmaps, units, and…
onmax Nov 11, 2026
50e6a6b
fix(charts): keep plots at 520px and end-of-line names 20px apart, so…
onmax Nov 11, 2026
66985ed
fix(charts): drop a chart's hairline right under a heading, and fit s…
onmax Nov 11, 2026
ec1facd
fix(charts): validate log scales and align report labels
vite-hub[bot] Nov 11, 2026
13d7a9f
feat(charts)!: span the column like a dashboard, with slim bars and n…
onmax Nov 11, 2026
5548820
fix(charts): type a checked log scale's axis, and test waterfall unit…
onmax Nov 11, 2026
9bbb227
fix(charts): preserve plot space and fit waterfall values
vite-hub[bot] Nov 11, 2026
e45e81a
style(charts): format the waterfall and long-name regression tests
onmax Nov 11, 2026
9c301d4
fix(charts): print a stack's total past its end, and keep each series…
onmax Nov 11, 2026
1b79d4a
fix(charts): check each value label against the others with the same …
onmax Nov 11, 2026
dd1c2a0
fix(charts): preserve label identity and total rendered stacks
vite-hub[bot] Nov 11, 2026
ffc21af
fix(charts): align annotation bounds with rendered padding
vite-hub[bot] Nov 11, 2026
faf4da0
fix(charts): use normalized Vega padding contract
vite-hub[bot] Nov 11, 2026
c358ee8
fix(charts): resolve main merge preserving descriptions and stable ids
vite-hub[bot] Nov 11, 2026
0a55513
Merge branch 'main' into feat/charts-report-style
vite-hub[bot] Nov 12, 2026
7647c96
Merge branch 'main' into feat/charts-report-style
vite-hub[bot] Nov 12, 2026
68333f4
Merge branch 'main' into feat/charts-report-style
vite-hub[bot] Nov 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/pages/doctor/charts/invalid-better.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
`better` colors a heatmap's cells from red through amber to green when its numbers rate something: `better="higher"` when a high number is good, such as a score, and `better="lower"` when a low one is, such as an error rate. Other charts have no cells to color.

::incorrect
```md
::chart{type="heatmap" better="more" title="Score per section"}
| agent | features | auth |
| --- | --: | --: |
| first | 10 | 6.2 |
| second | 9 | 4.6 |
::
```
::

::correct
```md
::chart{type="heatmap" better="higher" title="Score per section"}
| agent | features | auth |
| --- | --: | --: |
| first | 10 | 6.2 |
| second | 9 | 4.6 |
::
```
::
23 changes: 23 additions & 0 deletions docs/pages/doctor/charts/invalid-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
`log` puts numbers that span orders of magnitude on a log scale: alone for the numbers' axis, `log="x"` for the x column of a line or a scatter plot over numbers, or `log="both"`. Lines, scatter plots, and bar charts take it. A log scale has no zero, so stacks, areas, and pies, whose parts add up from zero, can't use one, and every number on a log axis must be above 0.

::incorrect
```md
::chart{type="line" log title="Time to first reply (h)"}
| week | median |
| --- | --: |
| 2026-09-07 | 1.2 |
| 2026-09-14 | 0 |
::
```
::

::correct
```md
::chart{type="line" log title="Time to first reply (h)"}
| week | median |
| --- | --: |
| 2026-09-07 | 1.2 |
| 2026-09-14 | 0.6 |
::
```
::
23 changes: 23 additions & 0 deletions docs/pages/doctor/charts/invalid-unit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
`unit` prints a chart's numbers with their unit on its bars and its value axis. A gantt prints how long each bar lasts, and a sankey each node's amount, so neither takes `unit`. Put the unit in the amount's header instead.

::incorrect
```md
::chart{type="sankey" unit="$" title="Where the snack budget went"}
| from | to | amount |
| --- | --- | --: |
| budget | coffee | 410 |
| budget | biscuits | 160 |
::
```
::

::correct
```md
::chart{type="sankey" title="Where the snack budget went"}
| from | to | amount ($) |
| --- | --- | --: |
| budget | coffee | 410 |
| budget | biscuits | 160 |
::
```
::
13 changes: 7 additions & 6 deletions e2e/charts.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ test("hundreds of worst-case charts draw with no text colliding, clipped, or pas
expect(problems).toEqual([]);
});

test("a chart beside a link keeps its own card, light and dark", async ({ page }) => {
test("a chart beside a link keeps its own hairline, light and dark", async ({ page }) => {
const render = createHtmlRenderer({
plugins: [charts(), chips({ download: false })],
components: { ...components, ...chipsComponents },
Expand All @@ -314,13 +314,14 @@ test("a chart beside a link keeps its own card, light and dark", async ({ page }
await page.goto("/fixture/", { waitUntil: "domcontentloaded" });
const figure = page.locator("figure.cch");
await expect(page.locator("main a").first()).toHaveCSS("border-top-left-radius", "6px");
for (const [scheme, background] of [
["light", "rgb(255, 255, 255)"],
["dark", "rgb(10, 10, 10)"],
for (const [scheme, border] of [
["light", "rgb(229, 229, 229)"],
["dark", "rgba(255, 255, 255, 0.1)"],
] as const) {
await page.emulateMedia({ colorScheme: scheme });
await expect(figure).toHaveCSS("background-color", background);
await expect(figure).toHaveCSS("border-top-left-radius", "10px");
await expect(figure).toHaveCSS("border-top-color", border);
await expect(figure).toHaveCSS("border-left-width", "0px");
await expect(figure).toHaveCSS("background-color", "rgba(0, 0, 0, 0)");
}
});

Expand Down
179 changes: 155 additions & 24 deletions packages/charts/docs/index.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/charts/docs/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The playground opens the editor right away, so it stays slow.

:::example{label="Target line"}
```md
::chart{labels title="Minutes to the first review comment"}
::chart{title="Minutes to the first review comment"}
| team | minutes |
| --- | --: |
| frontend | 38 |
Expand Down
29 changes: 15 additions & 14 deletions packages/charts/src/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ export const INK = {
grid: "#ececec",
background: "#ffffff",
} as const;
// Tailwind's 500 shades, bar a brown for the tenth, read on white and on black, so the defaults work in both themes.
// Past the palette, Flint would merge series into a gray "Others", so there are enough for any table a review holds.
// Muted tones at one lightness in OKLCH (0.66), so no series shouts over another: each reads at 3:1 on white and 6:1 on
// black, so the defaults work in both themes. Past the palette, Flint would merge series into a gray "Others", so
// there are enough for any table a review holds.
export const SERIES = [
"#3b82f6",
"#f97316",
"#10b981",
"#a855f7",
"#f43f5e",
"#eab308",
"#06b6d4",
"#ec4899",
"#84cc16",
"#a8774a",
"#14b8a6",
"#f59e0b",
"#4d97de",
"#bb8558",
"#3ca694",
"#a37ecd",
"#da6a76",
"#b8892d",
"#419fc0",
"#69a45c",
"#c673a3",
"#8693a5",
"#90994e",
"#8489da",
] as const;
Loading
Loading