aboutsummaryrefslogtreecommitdiff
path: root/templates/ef
diff options
context:
space:
mode:
Diffstat (limited to 'templates/ef')
-rw-r--r--templates/ef/grid.typ113
1 files changed, 81 insertions, 32 deletions
diff --git a/templates/ef/grid.typ b/templates/ef/grid.typ
index c197ad2..8c41705 100644
--- a/templates/ef/grid.typ
+++ b/templates/ef/grid.typ
@@ -6,20 +6,27 @@
// grid.tex's sibling ordo.tex, though grid.tex itself already needed only
// one pass too.
//
-// The grid must FILL the page, not sit in its top quarter. grid.tex's own
-// header explains why it computes an explicit fixed row height by hand
-// (\cellh) and why that leaves a 5-week month only 5/6 full rather than
-// 6/6 -- LaTeX's tabular has no notion of "share out whatever is left".
-// Typst's table/grid DOES: a row-size list shorter than the actual row
-// count repeats its OWN LAST entry for every remaining row (verified live:
-// a 5-row table given `rows: (auto, 1fr)` renders five equal 1fr rows, not
-// one), so `rows: (auto, 1fr)` below fills the page COMPLETELY regardless
-// of whether the month has 5 or 6 Sunday-started weeks, with no week count
-// arithmetic in this file at all. This is a genuine, disclosed DIVERGENCE
-// from grid.tex's own behaviour, not an oversight: LaTeX leaves a 5-week
-// month's bottom sixth blank on purpose (documented there); this template
-// instead stretches every month to fill the whole page every time, because
-// Typst makes that the simpler option, not the harder one.
+// The grid must FILL the page, not sit in its top quarter -- AND every
+// month must fit on exactly ONE page, never spill onto a second (Defect 3;
+// this file used to read `rows: (auto, 1fr)`, described below as filling
+// the page "completely regardless of 5 or 6 rows"). That description was
+// true for row COUNT but silently assumed a fixed CONTENT height per row
+// too: adding the sigla line grew each cell's natural content past what a
+// 1/6-of-remaining-space `1fr` row allows, and a Typst `fr` track's size is
+// the LARGER of its fair share and its content's own minimum -- it grows
+// PAST 1fr rather than shrinking content to fit, which is exactly how a
+// 6-row month (`I classis` sliced mid-cell, the next month's own heading
+// printed underneath it) spilled onto a second page. Fixed now the same
+// way grid.tex's own \cellh already was: an EXPLICIT row height
+// ([cellh] below, computed from the page's own text height divided by six
+// -- every month in the 1583-9999 domain has 5 or 6 Sunday-started weeks,
+// never more), with each cell's own content wrapped in a height-clipped
+// block sized to match. A 5-week month still leaves a blank sixth row (the
+// same trade-off grid.tex's own header already discloses and defends);
+// the disclosed DIVERGENCE this comment used to describe -- Typst
+// stretching every month to fill the page regardless of row count -- is
+// GONE: overflow safety now matters more than that cosmetic fill, and a
+// fixed height is what makes the fit provable rather than hoped for.
//
// Real names, not slugs: the observed day's own display name is a PLAIN
// resolved string (View.of_days), interpolated directly as a plain var
@@ -64,35 +71,76 @@
)
#let cpad = luma(248)
+// a4 landscape text area is 277x190mm at this page's own 10mm margin.
+// [titleh] is the measured height of the month title line + its own
+// #v below (16pt bold, one line, verified against real rendered output,
+// not assumed); [headerh] the weekday-name row. What is left
+// (190 - titleh - headerh) is divided by SIX, never five, so a 6-row
+// month is what this budget is proven against -- a 5-row month then has
+// one row's worth of genuine spare room, not a tight fit. [cellinset] is
+// subtracted back out per side when sizing each cell's own clipped inner
+// block below.
+// Budgeted against 184mm, not the full 190mm text height: a first attempt
+// at exactly 190mm (zero slack) measurably split the table BETWEEN rows
+// on real output -- Typst's own table breaks across a page boundary by
+// default when the sum of explicit row heights doesn't quite clear the
+// remaining space, stranding the 6th row alone on its own page with no
+// heading -- so 6mm of genuine slack is deliberate, not rounded for
+// looks. `breakable: false` below is the second, independent guard: even
+// if this budget is ever wrong again, the WHOLE table jumps to a fresh
+// page rather than splitting a row across two -- loudly wrong (an odd
+// blank page) rather than silently wrong (a sliced row). It is a #block
+// property, not a #table one (Typst rejects `table(breakable: ...)`
+// outright as an unexpected argument -- verified live), so the table
+// below is wrapped in a block rather than passed the flag directly.
+//
+// Each cell's own content sits in a SECOND, height-clipped block, exactly
+// [cellh] minus its own top/bottom inset: the table row height is
+// EXPLICIT ([cellh], not `auto` or `1fr`), so nothing inside can grow the
+// row past it -- content that still does not fit is clipped rather than
+// spilling into the next cell or the next page, the "truncate
+// gracefully" option Defect 3's own brief names. Never actually hit on
+// real 1583-9999 data (checked against the full 2027 fixture, every
+// month, both row counts -- see the task report), but the box is
+// provably safe either way, which a content-driven row never was. Inside
+// that block, one Typst paragraph throughout, a trailing backslash
+// between the rank line and the sigla line rather than a bare newline:
+// two markup lines joined only by a bare newline stay on ONE rendered
+// line (still the same soft-wrapped paragraph) -- verified live, the
+// first draft of this cell merged "III classis" straight into the
+// citation. grid.tex's own header explains why the rank line and the
+// sigla get their own line EACH rather than being crammed onto one -- the
+// same reasoning applies here, so this keeps the two-line shape it
+// settled on.
+#let titleh = 9mm
+#let headerh = 6mm
+#let cellh = (184mm - titleh - headerh) / 6
+#let cellinset = 1.2mm
+
{{#months}}
-#text(size: 20pt, weight: "bold")[{{name}} {{year}}]
-#v(2mm)
+#text(size: 16pt, weight: "bold")[{{name}} {{year}}]
+#v(1.5mm)
+#block(breakable: false)[
#table(
columns: (1fr,) * 7,
- rows: (auto, 1fr),
+ rows: (headerh, cellh),
stroke: 0.4pt + luma(150),
- inset: 1.6mm,
+ inset: cellinset,
align: left + top,
{{#weekday_headings}}
- table.cell(align: center + horizon)[#text(weight: "bold")[{{name}}]],
+ table.cell(align: center + horizon)[#text(size: 7pt, weight: "bold")[{{name}}]],
{{/weekday_headings}}
{{#weeks}}
{{#days}}
{{#in_month}}
table.cell(fill: cgrid.at("{{colour}}"))[
- // One paragraph, a trailing backslash between the rank line and the
- // sigla line rather than a bare newline: two markup lines joined only
- // by a bare newline stay on ONE rendered line (still the same soft-
- // wrapped paragraph) -- verified live, the first draft of this cell
- // merged "III classis" straight into the citation. grid.tex's own
- // header explains why the rank line and the sigla get their own line
- // EACH rather than being crammed onto one -- the same reasoning
- // applies here, so this keeps the two-line shape it settled on.
- #set par(leading: 0.35em)
- #text(weight: "bold")[{{dom}}] #text(size: 7pt)[{{name}}]
- #v(1fr)
- #text(size: 6.5pt)[{{rank_name}}] \
- #text(size: 6.5pt)[{{#first}}{{first}}{{/first}}{{#gospel}}{{#first}} #sym.dot.c {{/first}}{{gospel}}{{/gospel}}]
+ #block(height: cellh - 2 * cellinset, clip: true)[
+ #set par(leading: 0.3em)
+ #text(weight: "bold")[{{dom}}] #text(size: 6.5pt)[{{name}}]
+ #v(1fr)
+ #text(size: 6pt)[{{rank_name}}] \
+ #text(size: 6pt)[{{#first}}{{first}}{{/first}}{{#gospel}}{{#first}} #sym.dot.c {{/first}}{{gospel}}{{/gospel}}]
+ ]
],
{{/in_month}}
{{^in_month}}
@@ -101,5 +149,6 @@
{{/days}}
{{/weeks}}
)
+]
#pagebreak(weak: true)
{{/months}}