Scaffold Chart Sins site with Astro + build-time Vega-Lite

Set up the static-site tech stack: Astro 5 with Markdown content
collections, Vega-Lite specs rendered to static SVG at build time
(zero client JS), plain scoped CSS, and a GitHub Pages deploy workflow.

Includes three sample sins (truncated y-axis, dual-axis deception,
pie chart overload), each with a bad and fixed chart spec, plus a
gallery index and per-sin detail pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPEvmMbac2fCvKXpQcovj8
This commit is contained in:
Claude
2026-08-05 11:57:52 +00:00
commit 2e17f8fa59
23 changed files with 978 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
import type { TopLevelSpec } from 'vega-lite';
// Eagerly load every Vega-Lite spec in src/charts/ at build time so pages can
// look one up by its basename (e.g. "dual-axis-bad").
const modules = import.meta.glob<{ default: TopLevelSpec }>('../charts/*.json', {
eager: true,
});
const specsByName = new Map<string, TopLevelSpec>();
for (const [path, mod] of Object.entries(modules)) {
const name = path.split('/').pop()!.replace(/\.json$/, '');
specsByName.set(name, mod.default);
}
/** Look up a Vega-Lite spec by basename; throws at build time if missing. */
export function getChartSpec(name: string): TopLevelSpec {
const spec = specsByName.get(name);
if (!spec) {
throw new Error(
`Chart spec "${name}" not found in src/charts/. Available: ${[...specsByName.keys()].join(', ')}`,
);
}
return spec;
}
/** Render a 15 severity as flame glyphs for display. */
export function severityFlames(severity: number): string {
return '🔥'.repeat(severity) + '·'.repeat(Math.max(0, 5 - severity));
}