Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 6 additions & 20 deletions src/assets/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,13 @@ h3 { font-size: clamp(1.2rem, 2vw, 1.55rem); }
.page-head { max-width: 62rem; margin-bottom: 3rem; }
.page-head h1 { font-size: clamp(2.5rem, 6vw, 5rem); }
.index-list { display: grid; gap: .7rem; padding: 0; list-style: none; }
.index-list > li > a { display: grid; grid-template-columns: 7rem 1fr auto; gap: 1rem; align-items: baseline; padding: .9rem 1rem; border: 1px solid var(--line); border-radius: .75rem; background: rgba(16,24,42,.75); color: inherit; text-decoration: none; }
.index-list > li > a:hover { border-color: var(--violet); }
.index-list a { display: grid; grid-template-columns: 7rem 1fr auto; gap: 1rem; align-items: baseline; padding: .9rem 1rem; border: 1px solid var(--line); border-radius: .75rem; background: rgba(16,24,42,.75); color: inherit; text-decoration: none; }
.index-list a:hover { border-color: var(--violet); }
.index-list small { color: var(--silver); }
.canon-outline .canon-unit { margin: 0; padding: 0; overflow: hidden; background: rgba(16,24,42,.75); }
.canon-unit-summary { position: relative; display: grid; grid-template-columns: 7rem 1fr auto; gap: 1rem; align-items: baseline; padding: .9rem 1rem; list-style: none; }
.canon-unit-summary::-webkit-details-marker { display: none; }
.canon-unit-summary::before { content: "+"; position: absolute; transform: translate(-.55rem, -.05rem); color: var(--cyan); font: 800 1rem/1 ui-monospace, monospace; }
.canon-unit[open] .canon-unit-summary::before { content: "−"; }
.canon-unit-summary { padding: .9rem 1rem; }
.canon-unit-summary:hover { background: rgba(22,33,58,.72); }
.canon-unit-summary strong { padding-left: .35rem; }
.canon-unit .disclosure-open { display: none; }
.canon-unit[open] .disclosure-closed { display: none; }
.canon-unit[open] .disclosure-open { display: inline-flex; }
.canon-unit-text { padding: 0 1rem 1rem; border-top: 1px solid var(--line); }
.canon-unit-text .source-block { max-height: 28rem; overflow: auto; margin: 1rem 0; }
.canon-unit-text .actions { margin-top: 1rem; }
.canon-unit-text .actions a { display: inline-flex; padding: .7rem 1rem; }
.canon-unit > .source-block { margin: 0; border-right: 0; border-bottom: 0; border-left: 0; border-radius: 0; }
.canon-outline .unit-level-3 { margin-left: clamp(1rem, 3vw, 2.5rem); }
.canon-outline .unit-level-4 { margin-left: clamp(2rem, 6vw, 5rem); }
.canon-outline .unit-level-3 .canon-unit { border-left: .25rem solid var(--violet); }
Expand Down Expand Up @@ -166,12 +156,8 @@ summary { cursor: pointer; font-weight: 800; }
.primary-nav a { padding: .7rem; border: 1px solid var(--line); }
.hero { grid-template-columns: 1fr; min-height: auto; }
.hero-field { max-width: 22rem; width: 78%; margin: 1rem auto; }
.index-list > li > a { grid-template-columns: 1fr; gap: .15rem; }
.canon-unit-summary { grid-template-columns: 1fr auto; gap: .2rem .6rem; padding-left: 1.35rem; }
.canon-unit-summary small { grid-column: 1 / -1; }
.canon-unit-summary strong { padding-left: 0; }
.canon-unit-text { padding: 0 .7rem .7rem; }
.canon-unit-text .actions .button { flex: 1 1 100%; }
.index-list a { grid-template-columns: 1fr; gap: .15rem; }
.canon-unit-summary { padding: .9rem .75rem; }
.canon-outline .unit-level-3 { margin-left: .65rem; }
.canon-outline .unit-level-4 { margin-left: 1.3rem; }
.textbook-chapter { padding: 1rem; }
Expand Down
8 changes: 3 additions & 5 deletions src/way/index.njk
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
---
layout: layouts/base.njk
title: Explore The Way
description: A sectioned and nested companion map of The Interdependent Way, with exact source available one deliberate layer deeper.
description: An expandable map of The Interdependent Way.
---
<header class="page-head"><p class="eyebrow">Canon-derived map</p><h1>Explore The Way</h1><p class="lede">This layer identifies the shape and relations of the source. Major sections, subheadings, and nested headings remain visibly distinct. Tap any unit to reveal its exact bounded text here; the Unit, Lab, and Source links preserve the deeper paths.</p></header>
{% for section in generated.canon.sections %}
<section class="category"><p class="eyebrow">{{ section.id }}</p><h2>{{ section.title }}</h2><ul class="index-list canon-outline">{% for unit in generated.canon.units %}{% if unit.section == section.id %}<li class="unit-level-{{ unit.level }}" data-parent-id="{{ unit.parentId or '' }}"><details class="canon-unit" id="{{ unit.routeSlug }}"><summary class="canon-unit-summary"><small>lines {{ unit.startLine }}–{{ unit.endLine }} · {% if unit.level <= 2 %}section{% elif unit.level == 3 %}subheading{% else %}nested heading{% endif %}</small><strong>{{ unit.title }}</strong><span class="status status-canon disclosure-closed">tap to read</span><span class="status status-canon disclosure-open">text open</span></summary><div class="canon-unit-text"><pre class="source-block">{{ unit.content }}</pre><div class="actions"><a class="button" href="/way/{{ unit.routeSlug }}/">Open unit page</a><a class="button secondary" href="/lab/{{ unit.routeSlug }}/">Enter Lab</a><a class="button secondary" href="/source/{{ unit.routeSlug }}/">Source and provenance</a></div></div></details></li>{% endif %}{% endfor %}</ul></section>
{% endfor %}
<header class="page-head"><p class="eyebrow">Canon-derived map</p><h1>Explore The Way</h1><p class="lede">Select a title to display that canon unit's exact text.</p></header>
<ul class="index-list canon-outline">{% for unit in generated.canon.units %}<li class="unit-level-{{ unit.level }}" data-parent-id="{{ unit.parentId or '' }}"><details class="canon-unit" id="{{ unit.routeSlug }}"><summary class="canon-unit-summary"><strong>{{ unit.title }}</strong></summary><pre class="source-block">{{ unit.content }}</pre></details></li>{% endfor %}</ul>
8 changes: 4 additions & 4 deletions tests/generated-site.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ test('distributed textbook displays all eight exact chapter sources', async () =

test('Way map renders Human consciousness beneath Interdefinables and before Preamble', async () => {
const way = await readFile('_site/way/index.html', 'utf8');
const interdefinablesSection = way.indexOf('<h2>The Interdefinables</h2>');
const interdefinablesSection = way.indexOf('<strong>The Interdefinables</strong>');
const humanHeading = way.indexOf('Human consciousness emerges from');
const binaryHeading = way.indexOf('Binary essences meaningfully');
const preambleSection = way.indexOf('<h2>Preamble</h2>');
const preambleSection = way.indexOf('<strong>Preamble</strong>');

assert.ok(interdefinablesSection >= 0, 'Interdefinables section missing');
assert.ok(humanHeading > interdefinablesSection, 'Human consciousness must appear inside Interdefinables');
Expand All @@ -105,8 +105,8 @@ test('Way map renders Human consciousness beneath Interdefinables and before Pre
assert.doesNotMatch(way, /<h2>Human consciousness emerges from:?<\/h2>/);
assert.match(way, /<details class="canon-unit"/);
assert.match(way, /<summary class="canon-unit-summary">/);
assert.match(way, /Tap any unit to reveal its exact bounded text here/);
assert.match(way, /Human consciousness emerges from[\s\S]*?Source and provenance/);
assert.match(way, /Select a title to display that canon unit's exact text/);
assert.doesNotMatch(way, /Open unit page|Enter Lab|Source and provenance|tap to read|text open/);
});

test('generated deployment artifact contains all rights article vertical slices with research attachment', async () => {
Expand Down
8 changes: 3 additions & 5 deletions tests/site-contract.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ test('base layout remains readable without javascript and exposes the textbook a
assert.doesNotMatch(layout, /fetch\(/);
});

test('Way map uses native disclosure and keeps deeper routes separate', async () => {
test('Way map disclosures contain only a title and exact canon text', async () => {
const way = await readFile('src/way/index.njk', 'utf8');
assert.match(way, /<details class="canon-unit"/);
assert.match(way, /<summary class="canon-unit-summary">/);
assert.match(way, /<summary class="canon-unit-summary"><strong>{{ unit\.title }}<\/strong><\/summary>/);
assert.match(way, /<pre class="source-block">{{ unit\.content }}<\/pre>/);
assert.match(way, /href="\/way\/{{ unit\.routeSlug }}\/"/);
assert.match(way, /href="\/lab\/{{ unit\.routeSlug }}\/"/);
assert.match(way, /href="\/source\/{{ unit\.routeSlug }}\/"/);
assert.doesNotMatch(way, /Open unit page|Enter Lab|Source and provenance|tap to read|text open/);
assert.doesNotMatch(way, /<script/i);
});

Expand Down
12 changes: 6 additions & 6 deletions tests/site.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,17 @@ test('all eight rights articles are reachable from the article index', async ({
});

test('clicking a Way row reveals its bounded canon text without leaving the tree', async ({ page }) => {
const articleFiveUnit = canon.units.find(unit => unit.title === 'Article Five');
expect(articleFiveUnit, 'Article Five canon unit should exist').toBeTruthy();
await page.goto('/way/');
const articleFive = page.locator('details.canon-unit', { has: page.locator('summary', { hasText: 'Article Five' }) }).first();
const sourceBlock = articleFive.locator('.source-block');
await expect(articleFive).not.toHaveAttribute('open', '');
await expect(sourceBlock).not.toBeVisible();
await articleFive.locator('summary').click();
await expect(articleFive).toHaveAttribute('open', '');
await expect(articleFive.locator('.source-block')).toHaveText(articleFiveUnit.content);
await expect(articleFive.locator('a', { hasText: 'Open unit page' })).toBeVisible();
await expect(articleFive.locator('a', { hasText: 'Enter Lab' })).toBeVisible();
await expect(articleFive.locator('a', { hasText: 'Source and provenance' })).toBeVisible();
await expect(sourceBlock).toBeVisible();
await expect(sourceBlock).toContainText('Article Five');
expect((await sourceBlock.textContent())?.trim().length).toBeGreaterThan(100);
await expect(articleFive.locator('a')).toHaveCount(0);
await expect(page).toHaveURL(/\/way\/$/);
});

Expand Down
Loading