The bounded set and the centered set each get their own page again, at print size
A second look: the bounded set on one page and the centered set on another. Each chart keeps everything the redesign gave it — its heading, the cross at the centre, the nine numbered target bands with dots spread through them, the full ring legend — as one large square panel (960px) centred on its page, instead of two 660px panels sharing one. The centered set's page carries the legend; both carry the pair's heading so they read as one spread. Also the profile row's photo URL is escaped (esc(src)), the identical hunk regions landed in 1aeafead0, so the two merge cleanly: a quote in an API image_url closed the attribute and injected markup into the printed document. check:packet-a1-structure and check:packet-variants assert the two-page order and the derived lightweight delta (four back pages dropped).
This commit is contained in:
parent
ce0417efc6
commit
88f747cf5c
3 changed files with 28 additions and 19 deletions
|
|
@ -70,7 +70,8 @@ function sequence(html) {
|
|||
: /funnel-title/.test(seg) ? 'triangle'
|
||||
: /sheet-life/.test(cls) ? 'life'
|
||||
: /sheet-christian/.test(cls) ? 'christian'
|
||||
: /sheet-sets\b/.test(cls) ? 'sets'
|
||||
: /sheet-sets-bounded/.test(cls) ? 'bounded'
|
||||
: /sheet-sets-centered/.test(cls) ? 'centered'
|
||||
: /sheet-worksheet/.test(cls) ? 'worksheet'
|
||||
: /wheel-title/.test(seg) ? 'wheel'
|
||||
: /class="card"/.test(seg) ? 'profiles'
|
||||
|
|
@ -84,7 +85,7 @@ function sequence(html) {
|
|||
const liftedMap = R.liftMap(MAP_ONLY_SHEET)
|
||||
const full = R.buildPacket(zone, groups, new Map(), liftedMap, withK, christian, 'full', sets)
|
||||
const light = R.buildPacket(zone, groups, new Map(), liftedMap, withK, christian, 'lightweight', sets)
|
||||
const FULL = 'map · triangle · life · christian · profiles · sets · wheel · points'
|
||||
const FULL = 'map · triangle · life · christian · profiles · bounded · centered · wheel · points'
|
||||
const LIGHT = 'map · triangle · worksheet · wheel · points'
|
||||
ok(sequence(full) === FULL, `full-detail order is\n ${sequence(full)}\n expected\n ${FULL}`, `full detail: ${FULL}`)
|
||||
ok(sequence(light) === LIGHT, `lightweight order is\n ${sequence(light)}\n expected\n ${LIGHT}`, `lightweight: ${LIGHT}`)
|
||||
|
|
|
|||
|
|
@ -85,19 +85,19 @@ ok(count(light, /sheet-christian/g) === 0, 'lightweight still carries the %-evan
|
|||
ok(count(light, /funnel-title/g) === count(full, /funnel-title/g), 'lightweight lost the funnel (the narrowing triangle)')
|
||||
// …and the SETS page, which is back matter a reader sits with rather than carries — the same
|
||||
// reason the life calendar and the %-evangelical grid are dropped.
|
||||
// ★ ONE SETS PAGE CARRYING BOTH CHARTS (2026-09-29: two square panels side by side), asserted
|
||||
// by each chart's own class, so losing EITHER chart fails by name rather than inside a total.
|
||||
ok(count(full, /<div class="sheet [^"]*sheet-sets\b/g) === 1, 'the full packet should have exactly ONE sets page')
|
||||
// ★ ONE PAGE PER CHART (2026-09-29: the bounded set on one page, the centered set on another),
|
||||
// asserted by each page's own class, so losing EITHER chart fails by name rather than inside a total.
|
||||
ok(count(full, /<div class="sheet [^"]*sheet-sets\b/g) === 2, 'the full packet should have TWO sets pages, one per chart')
|
||||
ok(count(full, /sheet-sets-bounded/g) === 1, 'the full packet has no bounded-set chart')
|
||||
ok(count(full, /sheet-sets-centered/g) === 1, 'the full packet has no centered-set chart')
|
||||
ok(count(full, /class="set-cross"/g) === 2, 'both set charts must carry the cross at their centre')
|
||||
ok(count(light, /sheet-sets-(bounded|centered)/g) === 0, 'lightweight still carries a sets page')
|
||||
// ⚠ THE DELTA IS DERIVED, never relaxed into a range: lightweight drops three back pages (life, %
|
||||
// grid, sets) AND lists the same people as a worksheet, whose pages hold more rows than profile pages.
|
||||
// ⚠ THE DELTA IS DERIVED, never relaxed into a range: lightweight drops four back pages (life, % grid,
|
||||
// bounded, centered) AND lists the same people as a worksheet, whose pages hold more rows than profiles.
|
||||
{
|
||||
const profilePages = Math.ceil(45 / R.PER_PAGE)
|
||||
const worksheetPages = count(light, /<div class="sheet sheet-worksheet/g)
|
||||
const want = 3 + profilePages - worksheetPages
|
||||
const want = 4 + profilePages - worksheetPages
|
||||
ok(worksheetPages >= 1 && count(light, /class="ws-row"/g) === 45, `the lightweight worksheet should list all 45 groups, got ${count(light, /class="ws-row"/g)}`)
|
||||
ok(count(full, /<div class="sheet/g) - count(light, /<div class="sheet/g) === want,
|
||||
`lightweight should be exactly ${want} sheets shorter, got ${count(full, /<div class="sheet/g)} vs ${count(light, /<div class="sheet/g)}`)
|
||||
|
|
@ -268,4 +268,4 @@ if (fails.length) {
|
|||
for (const f of fails) console.error(` ✗ ${f}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('PACKET-VARIANTS: PASS — both packets print every group, lightweight drops exactly the three back-matter sheets (life calendar, % grid, sets) and lists everyone as a worksheet, an unknown variant falls back to full, the Prayer List prints the PACKET and not the columnar list, the Cards button and its size row are unchanged, and one ref means one open tape.')
|
||||
console.log('PACKET-VARIANTS: PASS — both packets print every group, lightweight drops exactly the four back-matter sheets (life calendar, % grid, bounded set, centered set) and lists everyone as a worksheet, an unknown variant falls back to full, the Prayer List prints the PACKET and not the columnar list, the Cards button and its size row are unchanged, and one ref means one open tape.')
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
// the description without the labels wrapping in the longest locale we ship.
|
||||
const PRAY_CELL = 84;
|
||||
const SET_PANEL = 660; // one square sets panel: two + a 40px gap fit 1380px
|
||||
const SET_SOLO = 960; // one chart per page: a large square, centred
|
||||
const PRAY_W = PRAY_CELL * PRAY_COLS.length; // 252px
|
||||
// What is left is the description — the widest column on the page, and the point of the table.
|
||||
// For comparison an ENTIRE card in the old 2x10 grid was 683px wide; the description alone is 50%
|
||||
|
|
@ -254,7 +255,8 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
.set-cap{margin:10px 0 0;font:400 16px Georgia,serif;color:#413d35}
|
||||
/* The legend names EVERY ring, numbered as the figure numbers them, so a reader can read the scale
|
||||
from the same dialect outward to the language family — including rings this list leaves empty. */
|
||||
.set-legend{margin:26px auto 0;max-width:${2 * SET_PANEL + 40}px}
|
||||
.set-row-solo .set-panel{width:${SET_SOLO}px}
|
||||
.set-legend{margin:26px auto 0;max-width:${SET_SOLO}px}
|
||||
.set-legend-h{font:700 17px Georgia,serif;color:#1b1a17;margin:0 0 8px}
|
||||
.set-rings{margin:0;padding:0;list-style:none;display:grid;grid-template-columns:1fr 1fr;column-gap:40px;
|
||||
row-gap:6px;font:400 16px Georgia,serif;color:#413d35}
|
||||
|
|
@ -1033,8 +1035,12 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
const i = start + k;
|
||||
const top = M + HEAD + k * (CH + GUT);
|
||||
const src = photos.get(g.slug);
|
||||
// esc() on the URL too, not just on the name below it. src is photos.get(slug), and
|
||||
// usePosterPrints builds that Map straight from the API's image_url — so a quote in a
|
||||
// photo URL would close the attribute and inject the rest as markup, in a document the
|
||||
// reader is about to print. Same omission this file makes nowhere else.
|
||||
const img = src
|
||||
? `<img src="${src}" alt="">`
|
||||
? `<img src="${esc(src)}" alt="">`
|
||||
: `<div class="nophoto">${esc(t('no_photo'))}</div>`;
|
||||
return `<div class="card" style="left:${M}px;top:${top.toFixed(0)}px;
|
||||
width:${CW.toFixed(0)}px;height:${CH.toFixed(0)}px">${img}
|
||||
|
|
@ -1288,16 +1294,18 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
if (rows) legend = `<div class="set-legend"><div class="set-legend-h">${esc(t('sets_rings_head'))}</div>${rows}</div>`;
|
||||
}
|
||||
|
||||
// ★ ONE PAGE (2026-09-29), superseding the one-chart-per-page split: the two figures are a
|
||||
// PAIR and read as one, square panels side by side in the middle of the page, the legend under both.
|
||||
// The page key stays 'sets', so the lightweight variant still drops it whole.
|
||||
return sheet(`
|
||||
// ★ ONE CHART PER PAGE (2026-09-29, second look: the bounded set on one page and the centered set on
|
||||
// another), each a large square panel centred on its page with its heading — the Module 1 panel,
|
||||
// at a size a printed page can carry. The centered set's page carries the ring legend beneath it.
|
||||
// Both pages share the pair's heading so they read as one spread; the first carries the lede.
|
||||
// The page key stays 'sets', so the lightweight variant still drops both together.
|
||||
return panels.map((p, i) => sheet(`
|
||||
<div class="pg-head pg-head-c"><div class="pg-kicker">${esc(t('sets_kicker'))}</div>
|
||||
<h1 class="pg-h1">${esc(t('sets_title'))}</h1></div>
|
||||
<p class="pg-lede pg-lede-c">${esc(t('sets_lede'))}</p>
|
||||
<div class="set-row">${panels.map((p) => p.html).join('')}</div>
|
||||
${legend}
|
||||
`, `sheet-sets sheet-flow ${panels.map((p) => `sheet-sets-${p.kind}`).join(' ')}`);
|
||||
${i === 0 ? `<p class="pg-lede pg-lede-c">${esc(t('sets_lede'))}</p>` : ''}
|
||||
<div class="set-row set-row-solo">${p.html}</div>
|
||||
${p.kind === 'centered' ? legend : ''}
|
||||
`, `sheet-sets sheet-flow sheet-sets-${p.kind}`)).join('');
|
||||
}
|
||||
|
||||
// ── PAGE n+2: the prayer wheel ──────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Reference in a new issue