Feature/pdf export - #268
Merged
Merged
Conversation
Catches the branch up on three months of main, including the Zensical migration, which rewrote every file this branch touches. Conflict resolutions: - pyproject.toml, poetry.lock: take main's Zensical stack, keep mkdocs-print-site-plugin. Add beautifulsoup4 explicitly: build_pdf.py imports it and used to get it transitively from mkdocs-swagger-ui-tag, which the migration dropped. Lock regenerated rather than hand-merged. - mkdocs.yml: take main's plugin list, reinstate the print-site block in the same documented-as-inert style main uses for `social` and `git-revision-date-localized`. - Taskfile.yml: take main's `zensical serve`; keep the `pdf` target, rewired from `mkdocs build` onto `task build`. Drop the Insiders switching tasks, which main removed along with the MATERIAL_* vars they read. - docs/assets/extra.css: keep both - the print-media consent rules and main's .md-clear-highlight button style are independent. `task check` passes. `task pdf` does not: Zensical does not run MkDocs plugins, so /print_page/ is never generated and build_pdf.py stops on its own guard. Porting the PDF pipeline off mkdocs-print-site-plugin is outstanding work, noted in mkdocs.yml and the task summary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The PDF export was built on mkdocs-print-site-plugin, which supplied the /print_page/ skeleton. Zensical does not run MkDocs plugins, so that page stopped being generated and `task pdf` had been dead since the migration. nav.yml replaces it as the page order. It is generated from the .pages files and gated by `check:navigation`, so the PDF can no longer drift from the sidebar, and it carries nav depth explicitly - which the heading demotion previously had to reconstruct from URL slugs. build_pdf.py now assembles the document itself: it walks nav.yml, splices each page's rendered <article> out of site/, namespaces per-page element ids so 656 pages can share one document, resolves cross-page links into in-PDF anchors, absolutizes assets, and demotes headings by nav depth so the PDF outline mirrors the navigation tree. The link rewriting, cover stamping and headless-Chrome printing are the branch's original code. Drops mkdocs-print-site-plugin from mkdocs.yml and pyproject.toml. Declares beautifulsoup4 and pyyaml, which the script imports directly - bs4 used to arrive transitively via mkdocs-swagger-ui-tag, dropped in the migration. Scope: the 656 pages in nav.yml. The homepage, tags.md, testing.md and the deliberately off-nav Getting Started tutorial are not included. Verified: 656 pages merged, 0 missing, 1420 PDF pages, 5799 outline entries, 659 images all resolving, 17136 internal anchors with no tool-introduced dangling links. `task check` passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Links the merged document could not resolve inside itself were left root-absolute, so Chrome baked the address of the throwaway print server into the PDF: 697 links to http://127.0.0.1:<port>/, plus the logo on the cover. - resolve downloadable resources, full-size screenshots and pages outside the navigation against the published site under the built version, or under latest for a dev build - leave image sources root-absolute, they are embedded while printing
The @page block styled footers that mkdocs-print-site-plugin generated. The plugin is gone, build_pdf.py prints with --no-pdf-header-footer, and Chrome implements no CSS margin boxes, so the rules did nothing. The cover comment explained its height with an @page margin that print-site-material.css no longer sets. In Chrome 100vh resolves to the page area, but the cover starts below it, under the print header and the main wrapper padding - measured on Letter, 15mm of slack still breaks the copyright line onto a second page and 20mm fits. - remove the @page footer block from docs/assets/extra.css - record the real reason for the 50mm on the cover height
rpietzsch
marked this pull request as draft
September 11, 2026 13:21
Test Results0 tests 0 ✅ 0s ⏱️ Results for commit ac4db32. ♻️ This comment has been updated with latest results. |
rpietzsch
marked this pull request as ready for review
September 11, 2026 13:31
tools/ is the dec-tool package: every script in it is a subcommand and none is meant to be called directly. build_pdf.py was the exception - it was invoked as `python tools/build_pdf.py` and took its settings from the environment only. - turn main() into the click command `build-pdf` with --chrome, --build-version, --output-file and --port, each keeping its environment variable as a fallback - raise click.ClickException instead of printing to stderr and returning an exit code - register the command, call it from `task pdf`, list it in tools/README.md
seebi
reviewed
Sep 11, 2026
seebi
left a comment
Member
There was a problem hiding this comment.
some comments:
- is the PDF served with the website?
- Can we add a TOC
- We have a document template (created by the policy group) - should we re-use this?
The Chrome print of the merged site could not carry the eccenca house style, and admonitions, tabs and code printed with their web look. - merge site/ along nav.yml, normalize the HTML, convert it with pandoc and a Lua filter, typeset it with Typst (tools/pdf/) - house style from the policy template: title page, contents on their own pages, chapter breaks, running chapter footer, size-base variable - vendor Roboto, Roboto Mono, Noto Color Emoji and DejaVu fonts with their full licence texts, listed in the README - add headings for nav sections without an index page (Release Notes) - shrink terminal tables to fit, keep cards whole - drop the Chrome cover template and its print CSS - embed the package lifecycle diagram as PNG; its SVG labels are foreignObject elements, which Typst renders empty
Contributor
Author
|
seebi
reviewed
Sep 14, 2026
seebi
left a comment
Member
There was a problem hiding this comment.
-
the TOC is already long but a little bit useless at the same time, because too less levels are shown
- I suggest to add another level (for build it does not make sense but most other of the parts have a useful second level
-- OR we introduce Parts-Structuring so that each part has its own TOC
- I suggest to add another level (for build it does not make sense but most other of the parts have a useful second level
-
I would also like to see the commit hash in the "version ID"
- Generated 2026-09-14 -> Generated 2026-09-14 (31b5663)
-
The footer should show more the just the Part Name (e.g Automate) but the next TOC level
-
not all external links are market as external links (e.g. the Red Hat Universal Base Image 10 Minimal)
-
The icons should be stripped from the TOC (similar to inline PDF TOC)
-
Important Question for the TOC: Should we introduce Numbering?
Reviewer feedback: the contents were too shallow, the stamp did not name a commit, the footer showed only the part, and external links looked like jumps within the book. - letter the parts (A-I), number their pages from 1, down to A.1.1 - open each part with a cover page and its own contents, and keep only the parts in the front contents - stamp the commit next to the build date, marked -dirty when tracked files have uncommitted changes - show part and page in the footer, e.g. A Build > A.1 Introduction - mark links that leave the PDF with an arrow - drop icons from headings - build the PDF on every push to main (.github/workflows/pdf.yml) - nest the 20.03 and 20.10 cmemc and migration notes under their release
Operators in the task and operator reference and the component notes of each release had no contents entry.
seebi
enabled auto-merge
September 14, 2026 15:29
seebi
approved these changes
Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
add a single-file PDF export of the whole documentation
💪 What
dec-tool build-pdf, wired totask pdf: builds the site, assembles one linearized HTML document,serves it and prints it with headless Chrome to
dist/documentation-eccenca-com-<version>.pdf.tools/build_pdf.pywalksnav.yml, splices each page's rendered<article>out ofsite/, namespacesper-page element ids so 657 pages can share one document, resolves cross-page links into in-PDF anchors,
absolutizes assets, and demotes headings by nav depth so the PDF outline mirrors the navigation tree.
overrides/print_cover.html, the cover page stamped with the build version, the generation date andthe copyright line.
pages outside the navigation — at the published site under the built version, or under
latestfor a devbuild.
beautifulsoup4andpyyamlinpyproject.toml:tools/build_pdf.pyimports both directly, andbs4 used to arrive transitively via
mkdocs-swagger-ui-tag, which the zensical migration dropped.🤔 Why
mkdocs-print-site-plugin, which supplied the/print_page/skeleton. Zensicaldoes not run MkDocs plugins, so that page stopped being generated and
task pdfhad been dead since themigration.
nav.ymlreplaces the plugin as the page order. It is generated from the.pagesfiles and gated bycheck:navigation, so the PDF cannot drift from the sidebar, and it carries nav depth explicitly — whichthe heading demotion previously had to reconstruct from URL slugs.
PDF: 697 links to
http://127.0.0.1:<port>/, plus the logo on the cover.python tools/build_pdf.py, against whattools/README.mdsays about the directory — every script there is adec-toolsubcommand and none is meantto be called directly. It is now a
clickcommand like the others: four options with environment-variablefallbacks instead of env-only tunables,
click.ClickExceptioninstead ofprint-to-stderr plus a returncode, and a row in the command table.
@pageblock that styled page footers the plugin used togenerate — dead now that the export prints with
--no-pdf-header-footer, and never honoured anyway sinceChrome implements no CSS margin boxes.
👩🔬 How to validate
Needs a Chromium-family browser. The default is macOS Google Chrome; override with
--chromeorCHROME=.copyright line. Page 2 starts the first content page.
screenshot — it opens documentation.eccenca.com under the built version.
Started tutorial are not included.