diff --git a/.eleventy.js b/.eleventy.js index 2e39dce..b9553ec 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -22,6 +22,21 @@ export default function configureEleventy(eleventyConfig) { eleventyConfig.addFilter('where', (items, key, value) => (items || []).filter(item => item?.[key] === value)); eleventyConfig.addFilter('statusClass', value => `status-${String(value || 'hmmm').toLowerCase().replace(/[^a-z0-9]+/g, '-')}`); eleventyConfig.addFilter('markdown', value => md.render(String(value || ''))); + // Exact canonical body lines of a unit: skip the heading line, stop before + // footnote lines, notes blocks, separators, and sub-headings. Mirrors the + // body extraction in scripts/verify-article-canon.mjs; keep the two in step. + eleventyConfig.addFilter('canonUnitBody', content => { + const lines = String(content || '').split(/\r?\n/).slice(1); + const body = []; + for (const line of lines) { + if (/^\s*>?\s*(?:\[[^\]]+\]|[⁰¹²³⁴⁵⁶⁷⁸⁹]+|\d+)\s+/.test(line)) break; + if (/^\s*\*\*\[Notes/.test(line)) break; + if (/^\s*---\s*$/.test(line)) break; + if (/^\s*#{2,}\s/.test(line)) break; + if (line.trim()) body.push(line.trim()); + } + return body; + }); return { dir: { input: 'src', output: '_site', includes: '_includes', data: '_data' }, diff --git a/src/lab/unit.njk b/src/lab/unit.njk index 539a07b..c84137c 100644 --- a/src/lab/unit.njk +++ b/src/lab/unit.njk @@ -18,7 +18,9 @@ title: "Lab: {{ unit.title }}"

Conversation

-
Speaker A · main text

The exact canonical unit is one interaction away so this interpretive layer cannot quietly replace it.

Open exact source and provenance

+
Speaker A · main text +
{% for line in unit.content | canonUnitBody %}

{{ line }}

{% endfor %}
+

Open exact source and provenance

{% if unit.notes.length %} {% for note in unit.notes %}
Speaker B · note {{ note.marker }}

{{ note.text }}

{% endfor %} {% else %}