6.1 KiB
Pagefind + Zola (Open Free Books)
Reference for static search in this repo. Pagefind runs after Zola builds HTML to public/ — it does not use Zola’s build_search_index.
Read Pagefind Component UI for upstream API details. Use Component UI (pagefind-component-ui.js) only — not legacy pagefind-ui.js / PagefindUI.
How it fits together
bun run build:js → themes/openfreebooks/static/js/bundle.js
zola build → public/**/*.html
pagefind --site public → public/pagefind/ (index + WASM + UI assets)
| Environment | Index output | Served from |
|---|---|---|
Production (bun run build) |
public/pagefind/ |
Deployed with Wrangler |
Dev (zola serve) |
static/pagefind/ (copy) |
Zola copies static/ to site root |
static/pagefind/ is gitignored. Run bun run index:search after zola build so zola serve can load /pagefind/*.
Commands
bun run build:js # if frontend changed
zola build # required before indexing
bun run index:search # pagefind on public/ → copy to static/pagefind/
zola serve # http://127.0.0.1:1111
Production (includes index + copy):
bun run build # build:js + zola build + index:search
package.json devDependency: pagefind (^1.5). CLI: pagefind --site public.
What gets indexed
Live chapter pages only. Once any page uses data-pagefind-body, Pagefind skips all pages without it.
| Source | Indexed? |
|---|---|
templates/chapter.html → <article data-pagefind-body> |
Yes |
Home, about, catalog, credits, contributing, /search/ |
No |
| Catalog chapter cards (Solid + JSON) | No |
Planned chapters (no content/ page) |
No |
New subject chapter templates must include data-pagefind-body on the main lesson container.
Per-chapter markup
themes/openfreebooks/templates/chapter.html:
<article class="book-chapter" data-pagefind-body data-chapter="math/quadratic-equations">
…
<div id="copy-page-button" … data-pagefind-ignore></div>
<div id="quadratic-explorer" … data-pagefind-ignore></div>
</article>
data-pagefind-body— title, lead, and HTML partial prose.data-pagefind-ignore— chrome and interactive widgets (not lesson text).
Breadcrumb nav stays outside the article so it is not indexed.
UI integration
Global (every page)
themes/openfreebooks/templates/base.html:
<head>:pagefind/pagefind-component-ui.css+.jsviaget_url()- Before
</body>:<pagefind-modal reset-on-close> #site-configincludessearchUrlfromzola.toml[extra] search_url
Header (Solid)
frontend/src/components/site-header.tsx:
<pagefind-modal-trigger compact placeholder="Search" />
frontend/src/main.tsx: nav link Search → config.searchUrl.
Types: frontend/src/types/pagefind-components.d.ts.
Dedicated page
| File | Role |
|---|---|
content/search.md |
template = "search.html" |
templates/search.html |
pagefind-input, pagefind-summary, pagefind-results, pagefind-keyboard-hints |
sass/_search.scss |
Layout + map --pf-* to site tokens (:root, [data-theme="dark"]) |
URL: /search/. Modal and page share the default Pagefind instance (⌘K / Ctrl+K).
Theming
Pagefind hosts use all: initial — site CSS does not cascade in. Theme via --pf-* variables in _search.scss (see Pagefind CSS variables).
Load order in base.html: pagefind-component-ui.css first, then main.css so site --pf-* overrides Pagefind defaults (white button, blue focus ring).
Site theme uses data-theme and data-pf-theme on <html> (theme.ts); tokens map under [data-theme="dark"] and prefers-color-scheme. Header trigger scoped in .site-header__search to match .theme-toggle.
Zola config
build_search_index = false # Zola search unused; Pagefind handles search
search_url = "/search/"
<html lang="en"> in base.html — required for Pagefind language detection.
Stale static HTML (common bug)
Never copy public/ into themes/openfreebooks/static/. Committed themes/openfreebooks/static/**/*.html overrides Zola output and breaks:
data-pagefind-bodyon chapters- Pagefind assets in
base.html - Any template change
If search indexes 8 pages instead of 1, delete stale themes/openfreebooks/static/**/*.html, then zola build and bun run index:search.
Allowed under theme static/: built JS (js/bundle.js, hashed chunks), fonts, etc. — not generated HTML.
Verify
bun run build:js && zola build && bun run index:search
Expect Pagefind output similar to:
Indexed 1 page
Indexed … words
Check:
public/math/<slug>/index.htmlcontainsdata-pagefind-bodypublic/pagefind/pagefind-component-ui.jsexistsstatic/pagefind/exists afterindex:search(for dev)/search/and header ⌘K return chapter hits only
Adding a new live chapter
- Publish chapter per CONTRIBUTING.md (
content/, partial,chapter.htmlbranch). - Ensure content lives inside
<article data-pagefind-body>. zola build && bun run index:search(or fullbun run build).- Confirm indexed page count increased.
Do not
- Commit
public/pagefind/orstatic/pagefind/. - Use
pagefind-ui.js/new PagefindUI(). - Add
data-pagefind-bodytobase.htmlor marketing pages unless you intend to index them. - Expect catalog JSON titles in search without a static HTML index block (future enhancement).
Related
- SKILL.md — Zola layout and commands
- zola-solid.md — header mount,
searchUrlin site config - ofb/SKILL.md — product rules, chapter workflow