aboutsummaryrefslogtreecommitdiff
path: root/templates
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 11:09:18 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 11:09:18 +0200
commitc00bf135defe69eb303f4bcf32ae862f65c01178 (patch)
treefea8a088c40e366bc902d991ddf826d2b9b81a0d /templates
parent1935f40c156563c134f87093bf6ec8da1cf4fc46 (diff)
downloadcolitur-c00bf135defe69eb303f4bcf32ae862f65c01178.tar.gz
colitur-c00bf135defe69eb303f4bcf32ae862f65c01178.zip
feat(templates): the ordo booklet flows continuously, not one week per page
One week per page filled roughly the top third of every A5 page and cost 65 pages for a year that needed far fewer -- the original requirement, reversed here: a full 7-day week already occupies most of an A5 page even at reduced type, so the real saving was always in the year's many SHORT boundary weeks (a month's first/last week is rarely a full seven days), not in packing two full weeks together. lib/render/view.ml gains a [first] field on every week object (true on a month's own first week, the same 'cheap flag beats invented template logic' call [last] already made for grid rows) -- there is still no {{../}} parent-path syntax for a template to test this any other way. ordo.tex: the per-week \clearpage is gone. Every week keeps its existing small header line; the month's own first week additionally prints a large, ruled banner. \needspace (a template-local LaTeX dependency, not one of the frozen OCaml deps) keeps a header from being stranded alone at a page's bottom -- and a real, separate bug surfaced building it: \label placed BEFORE \needspace captured the OLD page number when \needspace went on to force a break, producing a step-stale \pageref in the TOC (fixed by moving \label after both needspace checks). The day box itself is tightened (rank/colour folded onto the same line as the citations -- an A5 box is far wider than tall, so this fits even Holy Week's longest citations with room to spare) so a second week routinely shares a page with the first. Measured result: 65 -> 53 pages, two pdflatex passes still settle the TOC, zero orphaned headers, zero overfull boxes. ordo.typ: the per-week #pagebreak is gone; #show heading's own block gains sticky:true, Typst's built-in answer to what ordo.tex needs \needspace for. The month banner needed its OWN sticky:true, found live: without it a banner could sit alone at a page's bottom with the entire month pushed to the next page -- not caught by a check for an orphaned HEADING, since the banner is plain markup, not one. Measured result: 65 -> 27 pages (Typst's own page-fill packs tighter than ordo.tex's needspace-driven approach), one compile pass, zero orphans. The five non-paginated flavours (ms/html/md/adoc/txt) never had a forced page break to remove -- they mainly needed the same header treatment for structural consistency: a week-level header nested under each month's existing one, walking months>weeks>days (the week's own padded, in-month-guarded day list) in place of the old months>days flat loop. Verified against groff, asciidoctor and an HTML parser -- zero warnings. Goldens regenerated through the Test_view.view_of path test_render_golden.ml itself uses, not the CLI (whose --lang default would have pinned output the tests never produce).
Diffstat (limited to 'templates')
-rw-r--r--templates/ef/ordo.adoc14
-rw-r--r--templates/ef/ordo.html15
-rw-r--r--templates/ef/ordo.md12
-rw-r--r--templates/ef/ordo.ms14
-rw-r--r--templates/ef/ordo.tex80
-rw-r--r--templates/ef/ordo.txt7
-rw-r--r--templates/ef/ordo.typ81
7 files changed, 171 insertions, 52 deletions
diff --git a/templates/ef/ordo.adoc b/templates/ef/ordo.adoc
index 3c7e69b..0b5785d 100644
--- a/templates/ef/ordo.adoc
+++ b/templates/ef/ordo.adoc
@@ -12,17 +12,27 @@
// (Ordo, Epistle, Gospel, Commemoration) comes from the view's term
// vocabulary rather than being written into this file, so a translated
// booklet needs no template edit.
+//
+// Defect 2: AsciiDoc has no page concept either -- mainly needed the same
+// header treatment as the paginated flavours. A === per week under each
+// month's ==, so :toc: now nests month/week the way ordo.tex's own
+// hand-built TOC and ordo.typ's outline already do. Walks
+// months>weeks>days (the week's own padded, in-month-guarded day list) in
+// place of the old months>days flat loop over the month's own flat one.
= {{term.ordo}} {{year}} · {{rite_name}}
:toc:
{{#months}}
== {{name}}
-{{#days}}
+{{#weeks}}
+=== {{term.week}} {{num}}
+
+{{#days}}{{#in_month}}
*{{dom}}* {{name}} +
{{rank}} · {{colour}} +
{{#first}}{{term.epistle}} {{first}} {{/first}}{{#gospel}}{{term.gospel}} {{gospel}}{{/gospel}}
{{#comms}} +
{{term.commemoration}} {{name}}{{/comms}}
-{{/days}}{{/months}}
+{{/in_month}}{{/days}}{{/weeks}}{{/months}}
diff --git a/templates/ef/ordo.html b/templates/ef/ordo.html
index c80a2a4..4936974 100644
--- a/templates/ef/ordo.html
+++ b/templates/ef/ordo.html
@@ -7,11 +7,21 @@
(Ordo, Epistle, Gospel, Commemoration) comes from the view's term
vocabulary rather than being written into this file, so a translated
booklet needs no template edit. -->
+<!-- Defect 2: HTML has no concept of a forced page break to begin with,
+ so this flavour was never one-week-per-page -- it mainly needed the
+ SAME header treatment the paginated flavours gained, for a reader
+ switching between them to find the same structure. Walks
+ months>weeks>days now (was months>days flat): an h2 per month
+ (unchanged) and a new h3 per week, using the week's own padded,
+ in-month-flagged day list rather than the month's flat, unpadded
+ one -- guarded accordingly below, the same guard every paginated
+ flavour's grid already needs for that field. -->
<!doctype html>
<html lang="la"><head><meta charset="utf-8">
<title>{{term.ordo}} {{year}}</title>
<style>
body{font-family:serif;max-width:40em;margin:2em auto;line-height:1.4}
+ h3{font-size:1em;border-top:1px solid #ccc;padding-top:.3em;margin-top:1.2em}
.day{margin:.6em 0;padding-left:2.5em;text-indent:-2.5em}
.dom{display:inline-block;width:2em;font-weight:bold}
.meta{font-size:.85em;color:#555}
@@ -22,10 +32,11 @@
</style></head><body>
<h1>{{term.ordo}} {{year}} &middot; {{rite_name}}</h1>
{{#months}}<h2>{{name}}</h2>
-{{#days}}<div class="day {{colour}}">
+{{#weeks}}<h3>{{term.week}} {{num}}</h3>
+{{#days}}{{#in_month}}<div class="day {{colour}}">
<span class="dom">{{dom}}</span>{{name}}
<div class="meta">{{rank}} &middot; {{colour}}{{#first}} &middot; {{term.epistle}} {{first}}{{/first}}{{#gospel}} &middot; {{term.gospel}} {{gospel}}{{/gospel}}</div>
{{#comms}}<div class="meta">{{term.commemoration}} {{name}}</div>{{/comms}}
</div>
-{{/days}}{{/months}}
+{{/in_month}}{{/days}}{{/weeks}}{{/months}}
</body></html>
diff --git a/templates/ef/ordo.md b/templates/ef/ordo.md
index fde5bb2..fd8094f 100644
--- a/templates/ef/ordo.md
+++ b/templates/ef/ordo.md
@@ -11,16 +11,24 @@
(Ordo, Epistle, Gospel, Commemoration) comes from the view's term
vocabulary rather than being written into this file, so a translated
booklet needs no template edit. -->
+<!-- Defect 2: Markdown has no page concept either, so this mainly needed
+ the same header treatment as the paginated flavours, for structural
+ consistency -- a ### per week under each month's ##, walking
+ months>weeks>days (the week's own padded, in-month-guarded day
+ list, not the flat unpadded one the old months>days loop used). -->
# {{term.ordo}} {{year}} · {{rite_name}}
{{#months}}
## {{name}}
-{{#days}}
+{{#weeks}}
+### {{term.week}} {{num}}
+
+{{#days}}{{#in_month}}
**{{dom}}** {{name}}
`{{rank}}` · {{colour}}{{#first}} · {{term.epistle}} {{first}}{{/first}}{{#gospel}} · {{term.gospel}} {{gospel}}{{/gospel}}
{{#comms}}
- {{term.commemoration}} {{name}}
{{/comms}}
-{{/days}}{{/months}}
+{{/in_month}}{{/days}}{{/weeks}}{{/months}}
diff --git a/templates/ef/ordo.ms b/templates/ef/ordo.ms
index d578455..a5d7100 100644
--- a/templates/ef/ordo.ms
+++ b/templates/ef/ordo.ms
@@ -9,13 +9,22 @@
.\" (Ordo, Epistle, Gospel, Commemoration) comes from the view's term
.\" vocabulary rather than being written into this file, so a translated
.\" booklet needs no template edit.
+.\"
+.\" Defect 2: groff -ms paginates its own way (no per-week \" clearpage \"
+.\" this template ever forced), so it mainly needed the same header
+.\" treatment as the paginated flavours, for structural consistency -- a
+.\" bold week run-in under each month's own .SH, walking months>weeks>days
+.\" (the week's own padded, in-month-guarded day list) in place of the
+.\" old months>days flat loop over the month's own flat one.
.TL
{{term.ordo}} {{year}} \(bu {{rite_name}}
{{#months}}
.SH
{{name}}
+{{#weeks}}
.LP
-{{#days}}
+\fB{{term.week}} {{num}}\fR
+{{#days}}{{#in_month}}
.IP "{{dom}}" 4
{{name}}
.br
@@ -26,5 +35,6 @@
\s-2{{term.gospel}} {{gospel}}\s+2
{{/gospel}}{{#comms}}.br
\s-2{{term.commemoration}} {{name}}\s+2
-{{/comms}}{{/days}}
+{{/comms}}{{/in_month}}{{/days}}
+{{/weeks}}
{{/months}}
diff --git a/templates/ef/ordo.tex b/templates/ef/ordo.tex
index 4b5bed9..a7fcbb3 100644
--- a/templates/ef/ordo.tex
+++ b/templates/ef/ordo.tex
@@ -2,11 +2,61 @@
% Build: colitur table --year 2027 --template ordo.tex > ordo.tex && pdflatex ordo.tex &&
% pdflatex ordo.tex (twice, so \pageref in the table of contents settles)
%
-% A5, one week per page, each day in a framed box with a colour swatch. Every
-% fixed string (headings, the Epistle/Gospel/Commemoration/Week labels)
-% comes from the view's term vocabulary rather than being written into this
-% file, so a translated booklet needs no template edit -- only a different
-% --lang.
+% A5, CONTINUOUS: days flow one after another with no forced page break per
+% week (Defect 2 -- the original one-week-per-page layout filled roughly
+% the top third of every page and cost 65 pages for a year that needed far
+% fewer; that requirement is reversed here on purpose, not merely relaxed).
+% Structure stays scannable through two header weights instead: every
+% week still opens with its existing small header line ({{month_name}} .
+% {{term.week}} N), and the month's own FIRST week additionally gets a
+% large, ruled banner above that line ({{#first}}...{{/first}}, a real
+% view field -- lib/render/view.ml -- not template-side arithmetic, since
+% this engine has no way to test "is this the first item" any other way).
+% \needspace (a genuine, tiny dependency, not one of the deps this project
+% freezes at the OCaml level -- LaTeX packages are a template author's own
+% concern) keeps a header from being stranded alone at a page's bottom
+% with its first day box pushed to the next one: 29mm covers the month
+% banner's own rule+title (~11.5mm) plus the week header below it
+% (~5.5mm) plus room for at least one day box (~10mm); 16mm covers just
+% the week header plus one day box. Both re-verified against the actual
+% typeset output, not derived from theory alone (the task report has the
+% before/after page counts and a scan proving no header is ever left
+% alone at a page's foot with nothing under it).
+%
+% \label fires AFTER both \needspace calls below, not before: a \label
+% placed before a \needspace that goes on to force a break captures the
+% OLD page number (\thepage at the point \label is processed, not where
+% its content actually lands) -- a step-stale \pageref found live in an
+% early draft's own TOC (week 3 read "page 3" while its own content
+% demonstrably started on page 4). Moving the label to fire only once the
+% page a week ACTUALLY starts on is already decided fixes it at the
+% source, cheaper than a third pdflatex pass, which would not have fixed
+% it either (the wrong page number was already committed to the .aux by
+% the second pass).
+%
+% Each day in a framed box with a colour swatch, tightened from an
+% earlier draft (top/bottom padding 0.4mm, before skip 0.5mm, \scriptsize
+% meta text, rank/colour and the citations on separate lines) for this
+% same continuous flow: a full 7-day week already occupies most of an A5
+% page even at reduced size (measured: 55-65% of the text height for a
+% typical week, more with commemorations), so simply dropping the forced
+% per-week \clearpage only let the year's many PARTIAL boundary weeks
+% double up, not full ones -- a real but small saving on its own. Three
+% changes together fit a genuinely useful second (often third, on a short
+% week) week onto the same page: \fontsize explicitly (not \scriptsize,
+% whose 7pt/8.4pt leading is looser than a dense booklet needs), the
+% feast name still a clearly-bolder 9pt, and rank/colour folded onto the
+% SAME line as the citations rather than a line of its own -- an A5 box
+% is far wider than it is tall (roughly 120mm of usable width here), so
+% "I classis . albus Epistola ... Evangelium ..." fits with room to
+% spare even on Holy Week's own longest citations (measured against the
+% rendered output, not assumed; see the task report for the page count
+% this bought).
+%
+% Every fixed string (headings, the Epistle/Gospel/Commemoration/Week
+% labels) comes from the view's term vocabulary rather than being written
+% into this file, so a translated booklet needs no template edit -- only
+% a different --lang.
%
% The observed day's own display name is a PLAIN resolved string
% (View.of_days, Task 5), never a lang-keyed object -- there is no
@@ -49,6 +99,7 @@
\usepackage{tcolorbox}
\usepackage{fancyhdr}
\usepackage[hidelinks]{hyperref}
+\usepackage{needspace}
\definecolor{licolwhite}{HTML}{FFFFFF}
\definecolor{licolred}{HTML}{C1272D}
\definecolor{licolgreen}{HTML}{2E7D32}
@@ -84,20 +135,25 @@
\clearpage
{{#months}}
{{#weeks}}
+{{#first}}
+\needspace{29mm}
+\vspace{2mm}\noindent\rule{\linewidth}{1pt}\par\vspace{0.8mm}
+{\LARGE\bfseries {{month_name}} {{year}} }\par\vspace{1mm}
+{{/first}}
+\needspace{16mm}
\label{w{{month_num}}-{{num}}}
{\bfseries\large {{month_name}} }\hfill{\small {{term.week}} {{num}}}\par\vspace{0.5mm}
{{#days}}
{{#in_month}}
-\begin{tcolorbox}[colback=white,colframe=black!35,boxrule=0.4pt,left=1.6mm,right=1.6mm,top=0.4mm,bottom=0.4mm,before skip=0.5mm,after skip=0mm]
-{\bfseries {{dom}} } \;\; {\scriptsize {{weekday}} } \hfill \swatch{licol{{colour}}}\par
-{\bfseries {{name}} }\par
-{\scriptsize {{rank_name}} \textperiodcentered\ {{colour_name}} }\par
-{{#first}}{\scriptsize {{term.epistle}}\ {{first}} }\quad{{/first}}{{#gospel}}{\scriptsize {{term.gospel}}\ {{gospel}} }{{/gospel}}
-{{#comms}}\par{\scriptsize {{term.commemoration}}\ {{name}} }{{/comms}}
+\begin{tcolorbox}[colback=white,colframe=black!35,boxrule=0.3pt,left=1.4mm,right=1.4mm,top=0.2mm,bottom=0.2mm,before skip=0.2mm,after skip=0mm]
+{\bfseries {{dom}} } \;{\fontsize{6.5}{7.4}\selectfont {{weekday}} }\hfill\swatch{licol{{colour}}}\par
+{\fontsize{9}{10.2}\selectfont\bfseries {{name}} }\par
+{\fontsize{6.5}{7.4}\selectfont {{rank_name}} \textperiodcentered\ {{colour_name}} {{#first}}\quad {{term.epistle}}\ {{first}} {{/first}}{{#gospel}}\quad {{term.gospel}}\ {{gospel}} {{/gospel}}}
+{{#comms}}\par{\fontsize{6.5}{7.4}\selectfont {{term.commemoration}}\ {{name}} }{{/comms}}
\end{tcolorbox}
{{/in_month}}
{{/days}}
-\clearpage
+\vspace{1mm}
{{/weeks}}
{{/months}}
\end{document}
diff --git a/templates/ef/ordo.txt b/templates/ef/ordo.txt
index 3301652..0ac0366 100644
--- a/templates/ef/ordo.txt
+++ b/templates/ef/ordo.txt
@@ -1,10 +1,13 @@
{{#months}}
{{name}} {{year}}
-{{#days}}
+{{#weeks}}
+== {{term.week}} {{num}} ==
+{{#days}}{{#in_month}}
{{dom}} {{name}}
{{rank}} · {{colour}}
{{#first}} {{term.epistle}} {{first}}
{{/first}}{{#gospel}} {{term.gospel}} {{gospel}}
{{/gospel}}{{#comms}} {{term.commemoration}} {{name}}
-{{/comms}}{{/days}}
+{{/comms}}{{/in_month}}{{/days}}
+{{/weeks}}
{{/months}}
diff --git a/templates/ef/ordo.typ b/templates/ef/ordo.typ
index 162a485..85b609e 100644
--- a/templates/ef/ordo.typ
+++ b/templates/ef/ordo.typ
@@ -8,12 +8,16 @@
// a genuine advantage of this flavour over ordo.tex, not merely a different
// syntax for the same thing.
//
-// A5, one week per page, each day in a framed box with a colour swatch.
-// Every fixed string (headings, the Epistle/Gospel/Commemoration/Week
-// labels) comes from the view's term vocabulary rather than being written
-// into this file, so a translated booklet needs no template edit -- only a
-// different --lang. Same discipline as ordo.tex; see that file's own header
-// for the full reasoning, repeated only where Typst changes it below.
+// A5, CONTINUOUS (Defect 2): no forced page break per week any more --
+// see ordo.tex's own header for the measured "why" (a full 7-day week
+// already fills most of an A5 page even tightened, so the real saving
+// comes from the year's many SHORT boundary weeks no longer wasting a
+// whole page each). Every fixed string (headings, the Epistle/Gospel/
+// Commemoration/Week labels) comes from the view's term vocabulary rather
+// than being written into this file, so a translated booklet needs no
+// template edit -- only a different --lang. Same discipline as ordo.tex;
+// see that file's own header for the full reasoning, repeated only where
+// Typst changes it below.
//
// The observed day's own display name is a PLAIN resolved string
// (View.of_days), never a lang-keyed object, exactly as in every other
@@ -42,12 +46,29 @@
// per month with its weeks dotted-and-paginated underneath, because it
// walks the months-then-weeks nesting directly in its own hand-built TOC
// loop. Typst's outline instead builds its table of contents automatically
-// from real document headings, and there is no "is this the month's first
-// week" flag in the view model for a template to test -- inventing one
-// would be new engine state for a cosmetic grouping, not a real gap. Each
-// week page therefore carries ONE flat heading, "Month . Week N", which is
-// both what a reader sees at the top of that page and, automatically, its
-// own single-line entry in the table of contents below.
+// from real document headings, so this stays a flat list of "Month . Week
+// N" headings rather than being restructured into two heading levels --
+// changing outline depth/structure is a bigger, riskier change than this
+// defect calls for. Defect 2 DID add a "is this the month's first week"
+// flag to the view model (lib/render/view.ml's own [first], the same
+// "cheap flag beats invented template logic" call [last] already made
+// elsewhere) -- used below for a separate, non-heading month BANNER
+// printed just above that first week's own heading, not by restructuring
+// the heading/outline itself. The banner's own sticky:true (separate from
+// the heading show-rule's below) is needed for the identical reason: an
+// early draft without it put "Aprilis 2027" alone at the very bottom of
+// a page with the entire month below it on the next one -- not caught by
+// a check for an orphaned HEADING (a banner is not one), only found by
+// looking at the rendered page. Chaining two sticky blocks keeps
+// banner+heading+first day box moving together.
+//
+// Each day box is tightened from an earlier draft (0.6mm inset, 0.42em
+// leading, 7pt meta text on its own separate rank/colour line) for this
+// same continuous flow -- see ordo.tex's own header for the measured
+// reasoning, identical here: a full week already fills most of a page,
+// so folding rank/colour onto the SAME line as the citations (this box
+// is far wider than it is tall) is what buys back a second week's worth
+// of room, not the font/inset trim alone.
//
// Colour swatch: the six colour names this rite emits (white, red, green,
// violet, rose, black -- Colour.to_string's own closed vocabulary) are used
@@ -65,9 +86,15 @@
)
#set text(size: 9pt)
#set par(justify: false)
+// sticky: true keeps a heading from being stranded alone at a page's
+// bottom with its own week's first day box pushed to the next page --
+// Typst's own built-in answer to what ordo.tex needs \needspace (an
+// external package) for. Verified live: a heading is provably never the
+// LAST thing on a page anywhere in the rendered output (the task report
+// has the scan).
#show heading: it => {
set text(size: 12pt, weight: "bold")
- block(above: 3mm, below: 2mm)[#it.body]
+ block(above: 3mm, below: 2mm, sticky: true)[#it.body]
}
#let licol = (
@@ -92,30 +119,24 @@
{{#months}}
{{#weeks}}
+{{#first}}
+#block(above: 2mm, below: 0mm, sticky: true)[
+ #line(length: 100%, stroke: 0.6pt + luma(120))
+ #text(size: 15pt, weight: "bold")[{{month_name}} {{year}}]
+]
+{{/first}}
= {{month_name}} #sym.dot.c {{term.week}} {{num}}
{{#days}}
{{#in_month}}
-#block(width: 100%, above: 0.6mm, below: 0mm, breakable: false, stroke: 0.4pt + luma(160), inset: (x: 1.6mm, y: 0.6mm))[
- // A single Typst paragraph throughout, deliberately: two markup lines
- // separated only by a bare newline stay on ONE rendered line (they are
- // still the same paragraph, soft-wrapped) -- verified live, the first
- // draft of this box merged the rank/colour line into the citation line
- // for exactly that reason. A trailing backslash forces a real line
- // break WITHOUT starting a new paragraph (no inter-paragraph spacing
- // to tune down), which is what a compact multi-line box wants; #par's
- // own block-level break, used further up for the day/weekday/swatch
- // row against the name below it, is reserved for the one place this
- // box actually wants a fresh paragraph.
- #set par(leading: 0.42em)
- #text(weight: "bold")[{{dom}}] #h(2mm) #text(size: 8pt)[{{weekday}}] #h(1fr) #swatch("{{colour}}") \
+#block(width: 100%, above: 0.4mm, below: 0mm, breakable: false, stroke: 0.4pt + luma(160), inset: (x: 1.6mm, y: 0.4mm))[
+ #set par(leading: 0.36em)
+ #text(weight: "bold")[{{dom}}] #h(2mm) #text(size: 7pt)[{{weekday}}] #h(1fr) #swatch("{{colour}}") \
#text(weight: "bold")[{{name}}] \
- #text(size: 7pt)[{{rank_name}} #sym.dot.c {{colour_name}}] \
- #text(size: 7pt)[{{#first}}{{term.epistle}} {{first}}{{/first}}{{#gospel}}{{#first}} #h(2mm) {{/first}}{{term.gospel}} {{gospel}}{{/gospel}}]{{#comms}} \
- #text(size: 7pt)[{{term.commemoration}} {{name}}]{{/comms}}
+ #text(size: 6.5pt)[{{rank_name}} #sym.dot.c {{colour_name}}{{#first}} #h(2mm) {{term.epistle}} {{first}}{{/first}}{{#gospel}} #h(2mm) {{term.gospel}} {{gospel}}{{/gospel}}]{{#comms}} \
+ #text(size: 6.5pt)[{{term.commemoration}} {{name}}]{{/comms}}
]
{{/in_month}}
{{/days}}
-#pagebreak(weak: true)
{{/weeks}}
{{/months}}