Skip to content

Design-system bar charts for blog posts; use one in the graded prediction post - #1231

Merged
MaxGhenis merged 1 commit into
mainfrom
max/graded-post-design-system
Sep 29, 2026
Merged

MaxGhenis merged 1 commit into
mainfrom
max/graded-post-design-system

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Blog posts can now carry charts that match the app's. The graded 2025 prediction post uses one in place of its matplotlib PNG.

What changes

  • website/src/components/blog/BlogChart.tsx renders a ```chart block. The block holds a JSON spec: title, subtitle, x key, series with a chart color token name, data, a number format, and a source line. The component draws a Recharts bar chart with the ui-kit chart defaults the app's charts use:

    • AXIS_STYLE, GRID_STYLE, TOOLTIP_STYLE and LEGEND_STYLE
    • the --chart-* color tokens
    • Inter
    • the PolicyEngineWatermark

    Values above zero are labeled above their bar and values below zero beneath it. Axis ticks land on round steps, and the unit appears on the axis rather than on each label.

  • MarkdownFormatter (website) routes language-chart to BlogChart and renders it without the code-block frame. The drift check passes, since no top-level declarations changed.

  • recharts ^3.7.0 is added to the website, the same version as the app and within ui-kit's peer range.

  • The post swaps the static image for a bar chart of the graded quantity: the 2024-to-2025 change, Census against the registered prediction, by group. The unreferenced prediction-chart.png is removed.

The title, subtitle and label styles use token CSS variables inline. ui-kit's components use unprefixed Tailwind classes, and the website's Tailwind build uses the tw: prefix, so those classes never reach the website's CSS. ChartContainer and the watermark's alignment therefore rendered unstyled.

The legacy app/ website router still has a blog route, and its MarkdownFormatter does not know chart blocks. policyengine.org renders posts from website/.

The post's cover image is still the old chart; a photographic cover follows in a separate change.

Checks

  • tsc --noEmit and ESLint are clean for the website. Prettier is clean. The markdown drift check passes.
  • 165 website tests pass, including 8 new ones in blog-chart.test.tsx:
    • formatting of signs, zero and suffix
    • a sweep checking that the printed sign and magnitude always agree with the value
    • spec validation
    • rendering, and the formatter rendering chart fences without the code frame
  • The post was checked in the local Next.js dev server at desktop and mobile widths.

🤖 Generated with Claude Code

…n post

Adds a ```chart block to the website's blog renderer. The block holds a
JSON spec (series, data, number format) and BlogChart renders it with
Recharts and the ui-kit chart defaults the app's charts use: axis, grid,
tooltip and legend styles, the --chart-* color tokens, Inter, and the
PolicyEngine watermark. Header and label styles use token CSS variables
inline because the website's Tailwind build uses a prefix that ui-kit's
utility classes lack.

The graded prediction post replaces its matplotlib PNG with a bar chart of
the graded quantity: the 2024-to-2025 change, Census against the
registered prediction, by group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
policyengine-calculator-next Ready Ready Preview Sep 29, 2026 3:46pm UTC
policyengine-website Ready Ready Preview Sep 29, 2026 3:46pm UTC

Request Review

MaxGhenis added a commit that referenced this pull request Sep 29, 2026
…hrow

Fixes from the independent review of #1231 and #1232:

- Reading time counted chart JSON as words, moving the 2025 SPM post from
  "10 min read" to "14 min read". A chart block now counts as the prose a
  reader reads in it (title, subtitle, note, source), which keeps the SPM
  post at 10 minutes and the graded prediction post at 13, as on main.
- MarkdownFormatter imported BlogChart eagerly, so every research article
  shipped Recharts. It now goes through LazyBlogChart (next/dynamic, still
  server-rendered); articles without a chart block load none of it.
- Specs that parsed could still throw during render (format.decimals outside
  0 to 100, non-string title or legend, null or string bar values). The
  parsers now reject them, and formatChartValue clamps decimals.
- The bar chart body is now rendered in tests (labels either side of zero,
  ticks, legend), alongside tests for the new rejections, reading-time
  parity, and pinned values from the published SPM figures.
- Smaller: "positive" (an undefined --success on the website) falls back to
  the series color; the waterfall legend keeps LEGEND_STYLE's top padding;
  figures take their accessible name from the title; map tooltips near
  either edge anchor to it, and a tapped tooltip closes on a tap outside the
  map; the prediction chart's source says Table 5 publishes rates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis merged commit 59d3509 into main Sep 29, 2026
12 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Landed via #1232, which carries this PR's commit 59d35092 and was merged with a merge commit at e675f80d. The fixes for this PR's review findings are part of that merge:

  • BlogChart is now loaded lazily, so chart-free articles don't ship Recharts.
  • The bar chart body now has rendering tests.
  • The parsers reject specs that would throw during render.
  • The source line now reads "Table 5 (rates to two decimals; changes are their differences)".

The independent Opus reviews approved this PR on the condition that it lands together with #1232. Details are in the audit comment on #1232.

This branch was successfully deployed

2 active deployments
Preview – policyengine-calculator-next — 59d35092 Deployed Sep 29, 2026 by vercel[bot]
Preview – policyengine-website — 59d35092 Deployed Sep 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant