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
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ sections that affect its template. Version numbers follow the
this path against a theme installed from the local checkout; its
`docs/theme/` tree is generated, not committed.
- `extra_css` now points at `theme/`.
- `pdf/styles.scss` no longer forces a page break before every subsection
and no longer pads one out to a full page. A nav section whose children
are separate pages becomes a single article of stacked `section`
elements, and the forced break dropped everything after each one's first
paragraph from the PDF, so a chapter's tables, lists, and admonitions
went missing without a warning. Top-level chapters still start on a new
page.
- A long table, list, code block, or block quote now splits across pages
instead of moving whole and leaving the page it came from half empty.
Admonitions and content tabs still move whole, because splitting a
bordered box leaves it open at the page edge. A split never strands a
lone list item or table row on either side of the break, and a heading
or a bold-only label stays with the block it introduces.
- `styles/pdf.css` now agrees with `pdf/styles.scss` on how a block
fragments. The two disagreed, so browser print and PDF export broke a
page at different points.

### api-reference

Expand All @@ -44,6 +60,22 @@ sections that affect its template. Version numbers follow the
this path against a theme installed from the local checkout; its
`docs/theme/` tree is generated, not committed.
- `extra_css` now points at `theme/` and includes `api.css`.
- `pdf/styles.scss` no longer forces a page break before every subsection
and no longer pads one out to a full page. A nav section whose children
are separate pages becomes a single article of stacked `section`
elements, and the forced break dropped everything after each one's first
paragraph from the PDF, so a chapter's tables, lists, and admonitions
went missing without a warning. Top-level chapters still start on a new
page.
- A long table, list, code block, or block quote now splits across pages
instead of moving whole and leaving the page it came from half empty.
Admonitions and content tabs still move whole, because splitting a
bordered box leaves it open at the page edge. A split never strands a
lone list item or table row on either side of the break, and a heading
or a bold-only label stays with the block it introduces.
- `styles/pdf.css` now agrees with `pdf/styles.scss` on how a block
fragments. The two disagreed, so browser print and PDF export broke a
page at different points.

### shared

Expand Down Expand Up @@ -86,6 +118,11 @@ sections that affect its template. Version numbers follow the
`extra.cover_tagline` no longer renders when `extra.pdf.cover_tagline`
is unset for the locale being built.
- Removed the root `VERSION` file. The git tag is the version.
- `pdf-test.sh` builds a nav-grouped fixture and reads the rendered pages
back with `pdftotext`, so the chapter content, the chapter page break,
the label kept with its list, and the two-row minimum on a split table
are each asserted. A PDF build that exits 0 was not evidence the chapter
was in the PDF, which is how the dropped content went unnoticed.

## [0.1.0] - 2026-03-30

Expand Down
53 changes: 53 additions & 0 deletions templates/api-reference/pdf/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,56 @@ article#doc-toc li>a {
display: inline-block;
line-height: 0.5;
}

// Chapters (articles) still start on a new page; subsections flow.
article:not(#doc-cover):not(#doc-toc) section + section {
break-before: auto;
page-break-before: auto;
min-height: auto;
}

article:not(#doc-cover):not(#doc-toc) :is(h1, h2, h3, h4, h5, h6) {
break-after: avoid;
page-break-after: avoid;
}

// Only break-inside is relaxed. The inherited break-before: avoid keeps a
// block attached to the sentence or label that introduces it.
article:not(#doc-cover):not(#doc-toc) :is(table, pre, blockquote, ul, ol, div.highlight) {
break-inside: auto;
page-break-inside: auto;
}

// A block may split, but never so that one item is stranded on either side.
// Scoped to top-level lists: chaining the guard through nested lists
// over-constrains the break and pushes whole blocks to the next page.
article:not(#doc-cover):not(#doc-toc) :not(li) > :is(ul, ol) > li:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

article:not(#doc-cover):not(#doc-toc) :not(li) > :is(ul, ol) > li:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

article:not(#doc-cover):not(#doc-toc) tbody > tr:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

article:not(#doc-cover):not(#doc-toc) tbody > tr:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

// Bordered containers stay whole; splitting them leaves an open box.
article:not(#doc-cover):not(#doc-toc) :is(div.admonition, div.tabbed-content--wrap) {
break-inside: avoid;
page-break-inside: avoid;
}

article:not(#doc-cover):not(#doc-toc) :is(p, li, pre) {
orphans: 2;
widows: 2;
}
44 changes: 41 additions & 3 deletions templates/api-reference/styles/pdf.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,56 @@
/* Print guardrails for the browser. The PDF export layers
* pdf/styles.scss on top of these rules, so the two must agree on how a
* block fragments; a block forbidden to split here and allowed to split
* there produces a different page break in each output.
*/

@media print {
h1,
h2,
h3 {
h3,
h4,
h5,
h6 {
break-after: avoid;
page-break-after: avoid;
}

/* Splitting a long block beats pushing it whole to the next page and
* leaving the current one half empty.
*/
table,
pre,
blockquote,
ul,
ol {
break-inside: avoid;
page-break-inside: avoid;
break-inside: auto;
page-break-inside: auto;
}

/* ...but never so that a single item is stranded on either side of the
* break. Scoped to top-level lists: chaining the guard through nested
* lists over-constrains the break and pushes whole blocks to the next
* page.
*/
:not(li) > ul > li:nth-child(-n+2),
:not(li) > ol > li:nth-child(-n+2),
tbody > tr:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

:not(li) > ul > li:nth-last-child(-n+2),
:not(li) > ol > li:nth-last-child(-n+2),
tbody > tr:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

p,
li,
pre {
orphans: 2;
widows: 2;
}

img {
Expand Down
53 changes: 53 additions & 0 deletions templates/manual/pdf/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,56 @@ article#doc-toc li>a {
display: inline-block;
line-height: 0.5;
}

// Chapters (articles) still start on a new page; subsections flow.
article:not(#doc-cover):not(#doc-toc) section + section {
break-before: auto;
page-break-before: auto;
min-height: auto;
}

article:not(#doc-cover):not(#doc-toc) :is(h1, h2, h3, h4, h5, h6) {
break-after: avoid;
page-break-after: avoid;
}

// Only break-inside is relaxed. The inherited break-before: avoid keeps a
// block attached to the sentence or label that introduces it.
article:not(#doc-cover):not(#doc-toc) :is(table, pre, blockquote, ul, ol, div.highlight) {
break-inside: auto;
page-break-inside: auto;
}

// A block may split, but never so that one item is stranded on either side.
// Scoped to top-level lists: chaining the guard through nested lists
// over-constrains the break and pushes whole blocks to the next page.
article:not(#doc-cover):not(#doc-toc) :not(li) > :is(ul, ol) > li:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

article:not(#doc-cover):not(#doc-toc) :not(li) > :is(ul, ol) > li:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

article:not(#doc-cover):not(#doc-toc) tbody > tr:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

article:not(#doc-cover):not(#doc-toc) tbody > tr:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

// Bordered containers stay whole; splitting them leaves an open box.
article:not(#doc-cover):not(#doc-toc) :is(div.admonition, div.tabbed-content--wrap) {
break-inside: avoid;
page-break-inside: avoid;
}

article:not(#doc-cover):not(#doc-toc) :is(p, li, pre) {
orphans: 2;
widows: 2;
}
44 changes: 41 additions & 3 deletions templates/manual/styles/pdf.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,56 @@
/* Print guardrails for the browser. The PDF export layers
* pdf/styles.scss on top of these rules, so the two must agree on how a
* block fragments; a block forbidden to split here and allowed to split
* there produces a different page break in each output.
*/

@media print {
h1,
h2,
h3 {
h3,
h4,
h5,
h6 {
break-after: avoid;
page-break-after: avoid;
}

/* Splitting a long block beats pushing it whole to the next page and
* leaving the current one half empty.
*/
table,
pre,
blockquote,
ul,
ol {
break-inside: avoid;
page-break-inside: avoid;
break-inside: auto;
page-break-inside: auto;
}

/* ...but never so that a single item is stranded on either side of the
* break. Scoped to top-level lists: chaining the guard through nested
* lists over-constrains the break and pushes whole blocks to the next
* page.
*/
:not(li) > ul > li:nth-child(-n+2),
:not(li) > ol > li:nth-child(-n+2),
tbody > tr:nth-child(-n+2) {
break-after: avoid;
page-break-after: avoid;
}

:not(li) > ul > li:nth-last-child(-n+2),
:not(li) > ol > li:nth-last-child(-n+2),
tbody > tr:nth-last-child(-n+2) {
break-before: avoid;
page-break-before: avoid;
}

p,
li,
pre {
orphans: 2;
widows: 2;
}

img {
Expand Down
Loading