mirror of
https://github.com/olehomelchenko/chart-sins.git
synced 2026-08-08 02:22:43 +00:00
a3ab9f8a79
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
47 lines
1.8 KiB
TypeScript
47 lines
1.8 KiB
TypeScript
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 1–5 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];
|
||
}
|