Files
chart-sins/src/lib/charts.ts
T
Claude a3ab9f8a79 Restyle on the Carbon Design System
Adopt Carbon at the design-token level (the component libraries ship JS and
target app UIs; this is a static content site):

- IBM Plex Sans/Mono, self-hosted via @fontsource (no external requests)
- Carbon color tokens + layered White / Gray 100 themes
- 8px spacing scale, productive/expressive type, motion tokens, square
  geometry, 2px focus ring
- UI-shell header, tile grid, Carbon tags, geometric severity meter,
  breadcrumb, colophon crediting Carbon
- Charts themed with IBM Plex + Carbon's data-visualization palette
  (validated colorblind-safe/contrast) on a fixed light canvas so the
  build-time SVG stays legible in both themes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPEvmMbac2fCvKXpQcovj8
2026-08-05 12:41:00 +00:00

47 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
/** A 15 severity as five booleans, for the Carbon-style severity meter. */
export function severityUnits(severity: number): boolean[] {
return Array.from({ length: 5 }, (_, i) => i < severity);
}
// Stable category -> Carbon tag color. Known categories get a hand-picked hue;
// anything new hashes to a stable colour so the palette never churns.
const TAG_COLORS = ['purple', 'teal', 'red', 'blue', 'magenta'] as const;
const CATEGORY_TAG: Record<string, (typeof TAG_COLORS)[number]> = {
'Misleading Scales': 'blue',
'False Relationships': 'magenta',
'Chart-Type Abuse': 'purple',
};
/** Map a category label to a Carbon tag colour modifier. */
export function tagModifier(category: string): (typeof TAG_COLORS)[number] {
if (CATEGORY_TAG[category]) return CATEGORY_TAG[category];
let hash = 0;
for (let i = 0; i < category.length; i++) hash = (hash * 31 + category.charCodeAt(i)) >>> 0;
return TAG_COLORS[hash % TAG_COLORS.length];
}