This is a demo announcement, dismissible and configured in site.json.

Print and handbook

One-click printable handbook plus PDF export via any HTML-to-PDF tool in CI.

The printable handbook is a plain, self-contained HTML page at a predictable URL:

text
docs/<version>/<lang>/handbook.html

No app chrome, no JavaScript. Just the cover, a linked table of contents and every page in order, styled for print. That makes it ideal input for any HTML-to-PDF tool run in your CI. The theme ships no PDF toolchain of its own, so you keep full control over the renderer and its output.

Why generate the PDF yourself

The handbook’s in-browser print uses the browser’s print dialog, which cannot compute page numbers. That is why its table of contents has no page numbers. A dedicated HTML-to-PDF engine can: it lays the document out into real pages and back-fills numbers and leader dots. If you want a true page-numbered PDF, render the handbook with one of the tools below.

With WeasyPrint (no browser)

WeasyPrint renders HTML and CSS to PDF with its own engine. No headless browser is required, so it is light in CI (Python plus a few system libraries).

bash
# after hugo has built the site into ./public
weasyprint public/docs/v1_0_0/en/handbook.html handbook-v1.0.0-en.pdf

With Paged.js CLI (headless Chrome)

pagedjs-cli drives headless Chromium, so the PDF matches Chrome exactly. Heavier (Node plus Chromium) but pixel-faithful.

bash
npx pagedjs-cli public/docs/v1_0_0/en/handbook.html -o handbook-v1.0.0-en.pdf

Prince, wkhtmltopdf or your own headless-Chrome script work the same way: point them at handbook.html.

Page numbers and a leader-dot TOC

To get the classic Chapter …………… 12 table of contents, add a small print stylesheet that your engine understands (WeasyPrint and Paged.js both support CSS Generated Content for Paged Media):

pdf.csscss
/* number the pages */
@page { @bottom-center { content: counter(page); } }

/* fill the handbook TOC leaders with the target page number */
.handbook-toc__link::after {
  content: leader('.') target-counter(attr(href), page);
}

Pass it to the tool (e.g. weasyprint -s pdf.css …). Because the handbook’s TOC links already point at each page’s anchor, target-counter resolves the real page numbers for you.

In a CI job

A minimal GitLab CI example that produces a downloadable PDF alongside the site:

.gitlab-ci.ymlyaml
pdf:
  stage: deploy
  image: python:3.12-slim
  rules: [{ if: $CI_COMMIT_TAG }]
  script:
    - pip install weasyprint
    - sh ci/scripts/build-docs.sh ci/config.json "$PAGES_PATH"
    - hugo --source exampleSite --environment production --baseURL "${CI_PAGES_URL}/"
    - weasyprint exampleSite/public/docs/<version>/en/handbook.html public/handbook.pdf
  artifacts: { paths: [public] }

The result is a real, page-numbered PDF, generated by the engine you chose, with no PDF dependency baked into the theme.

Tip

Looking for the shortcode that embeds a PDF viewer on a page? See PDF embed.