Files
chart-sins/src/pages/sins/[...slug].astro
T
Claude cd18862115 Reframe the reference list; cite far more widely
"Canon" was leaking onto the public site — a nav item, a footer block, a
page title, a set of CSS class names. It was also driving content
decisions it had no business driving: the backlog was ordered around
which references were still unused, which is curation dressed up as
planning.

The page is now /references/, the list is documented as a bibliography
to grow rather than a canon to curate, and the backlog says plainly that
a sin earns a slot by being worth a page — sources are found to support
it, never the reverse.

Adds six sources (Cairo's Truthful Art, Few's Show Me the Numbers, the
Economist's audit of its own charts, Kosara's eagereyes, WTF
Visualizations, Datawrapper's dual-axis piece) and roughly doubles the
citations on the five published sins, to 5-7 each. Two of the new notes
point at sources that complicate our own position rather than back it.

The Economist essay ships without a URL rather than a guessed one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ULE5RRxdQE1ebwefEd2eCM
2026-08-05 17:10:04 +00:00

77 lines
2.7 KiB
Plaintext

---
import { getCollection, render } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import VegaChart from '../../components/VegaChart.astro';
import Citations from '../../components/Citations.astro';
import ShareLink from '../../components/ShareLink.astro';
import { getChartSpec, severityUnits, tagModifier } from '../../lib/charts';
import { href } from '../../lib/url';
export async function getStaticPaths() {
const sins = await getCollection('sins', ({ data }) => !data.draft);
return sins.map((sin) => ({
params: { slug: sin.id },
props: { sin },
}));
}
const { sin } = Astro.props;
const { Content } = await render(sin);
const badSpec = getChartSpec(sin.data.badChart);
const fixedSpec = getChartSpec(sin.data.fixedChart);
// Canonical, shareable URL for this sin — the thing you paste into a thread.
const pageUrl = new URL(href(`sins/${sin.id}/`), Astro.site).toString();
const ogImage = new URL(href(`og/${sin.id}.png`), Astro.site).toString();
---
<BaseLayout title={`${sin.data.title} — Chart Sins`} description={sin.data.poke} image={ogImage}>
<article class="wrap sin">
<nav class="breadcrumb"><a href={href()}>All sins</a> / {sin.data.title}</nav>
<header class="sin__head">
<div class="sin__meta">
<span class={`tag tag--${tagModifier(sin.data.category)}`}>{sin.data.category}</span>
<span class="severity" aria-label={`Severity ${sin.data.severity} of 5`}>
<span class="severity__meter" aria-hidden="true">
{severityUnits(sin.data.severity).map((on) => (
<span class={`severity__unit${on ? ' severity__unit--on' : ''}`} />
))}
</span>
Severity {sin.data.severity}/5
</span>
</div>
<h1 class="sin__title expressive-heading">{sin.data.title}</h1>
<p class="sin__poke">{sin.data.poke}</p>
<div class="sin__tags">
{sin.data.tags.map((t) => <span class="tag">{t}</span>)}
</div>
</header>
<div class="compare">
<div class="panel panel--bad">
<p class="panel__label">The Sin</p>
<VegaChart spec={badSpec} title={`Misleading chart: ${sin.data.title}`} />
</div>
<div class="panel panel--good">
<p class="panel__label">The Fix</p>
<VegaChart spec={fixedSpec} title={`Honest chart: ${sin.data.title}`} />
</div>
</div>
<p class="compare__note">Same numbers, both charts. Only the design changed.</p>
<div class="prose">
<Content />
</div>
<Citations citations={sin.data.citations} />
<ShareLink url={pageUrl} />
<p class="more-refs">
Building a case? See <a href={href('references/')}>every source we cite →</a>
</p>
</article>
</BaseLayout>