Skip to content
pH7x Systems edited this page Jul 21, 2026 · 8 revisions

Themes

Sardine CMS is design-agnostic: themes are packages, discovered at runtime, and the builder never hardcodes HTML. The bundled ph7x-reference theme is one example, not the product.

How a theme is found

Themes register a Python entry point in the sardine.themes group:

# pyproject.toml of a theme package
[project.entry-points."sardine.themes"]
my-theme = "my_theme:MyTheme"

theme = "my-theme" in sardine.toml selects it. A theme provides two things: assets() (a mapping of relative paths → bytes, shipped verbatim with hashed URLs) and render(kind, context) for the page kinds page, article, listing, not_found. JinjaTheme is the batteries-included base: point it at a template directory and it renders <kind>.html.j2 with autoescape on.

Template contexts (the contract)

Every page receives head (canonical, hreflang cluster, OG, optional JSON-LD), nav (home_url, menu, languages — the language switcher keeps the reader on the current page wherever a translation exists), footer (text, menu, optional admin_url/admin_label) and asset_urls (hashed). Kind-specific context:

Kind Extra context
page page (title, description), sections (key, kind, data fields, images), latest articles
article article (title, body_html, date, category, tags, cover, reading time)
listing listing (entries, page/pages, prev/next, filters, search index URL, labels)
not_found localized head + not_found.home_url

UI strings come from the localized label system (cms_build.ui, overridable via [site.labels]) — templates never hardcode editorial text.

Section kinds

A section's kind names the template branch that renders it; unknown kinds get a graceful generic rendering (conformance-tested). The authoring contract is spec-based (ADR-0037): a SectionKindSpec declares flat fields, Markdown-capable fields (delivered to templates as safe HTML) and the columns of the unbounded section.rows items group — no template may cap repetition, and the conformance suite proves a ten-item FAQ renders in every theme. Pages expose page.body_html for long-form Markdown. The bundled gallery — the authoring contract SECTION_KIND_GALLERY in cms_build.themes, documented kind-by-kind in the repository's THEME_GUIDE — ships nine kinds implemented by both bundled themes: hero, story, expertise, latest-articles, quote (pull quote), faq (native <details>, no JavaScript), cta (per-language target URL), gallery (srcset-aware image grid) and contact. The admin section editor suggests exactly these fields and merges kinds advertised by activated extensions.

Comments (ADR-0031)

Article contexts may carry an optional comments object (label, thread_url, island_url) when the project configures a provider. Themes render a plain localized link (the no-JS surface) inside a <site-comments> element plus a module script for the same-origin island; ignoring the key keeps working.

Overrides

A project can override individual templates and assets of the active theme locally (layered lookup) without forking the package.

Stylesheet hygiene

The reference theme's stylesheets contain only rules its templates actually emit, documented in English; load-bearing decisions (the [hidden] first rule, the sticky-footer flex trap, build-time code highlighting) are commented in place.

Frontend rules (ADR-0010)

Native web platform only: no frameworks, no build step. Interactivity ships as small Web-Component islands (ES modules) and every page must be complete without JavaScript. The framework ships one island: <site-search> (per-language JSON index, same-origin fetch, aria-live results). Total JS budget for a theme: ≤ 20 KB, enforced by tests. The reference theme itself adds zero JavaScript — its effects (aurora, grain, reveals, constellation field, cards/list toggle) are modern CSS only.

Reference theme ground rules

Design tokens only, local fonts (Inter, Newsreader — OFL, subset), inline SVG, zero inline styles, images with dimensions, no horizontal scroll, editorial dark theme, WCAG 2.2 AA (enforced by the axe gate in CI), and flow-relative CSS only — logical properties, never -left/-right — so a pack-declared RTL language mirrors the whole layout (ADR-0034). Mechanical rules land as tests in the theme conformance suite; the flow-relative rule is one of them, so third-party themes inherit it.

Responsive images

With [build] image_widths = [480, 960] (and sardine-cms-build[images] installed), the builder generates deterministic resized variants and hands themes a ready srcset on every image context — both bundled themes render it out of the box.

Clone this wiki locally