renderreportv0.7.0renderreport.casoon.de

Template packs

Bundle templates, components, themes and assets in a folder and select them per request.

A pack is a folder with a pack.toml manifest. A request with pack_id uses everything the pack brings: its components, the template selected by template_id, its themes and its assets.

Bundled packs

standard

Templates default and minimal, themes light, dark and print.

seo-audit

Template seo-report (cover page, table of contents) and the components lighthouse-scores and core-web-vitals.

Folder layout

pack-name/
├── pack.toml           # Manifest
├── templates/          # Report templates
│   └── *.typ
├── components/         # Custom components
│   └── *.typ
├── themes/             # Theme definitions
│   └── *.toml
└── assets/             # Fonts, images, etc.

Creating a pack

1. Create pack.toml

[pack]
name = "my-pack"
version = "0.1.0"
description = "My custom report pack"
authors = ["Your Name <email@example.com>"]
license = "MIT"

[compatibility]
min_engine_version = "0.1.0"

[templates.my-report]
file = "my_report.typ"
description = "My custom report template"
default_theme = "default"

[themes.default]
file = "default.toml"
default = true

[components.my-widget]
file = "my_widget.typ"
description = "Custom widget component"

2. Create Theme (themes/default.toml)

id = "default"
name = "Default Theme"

[tokens]
"color.primary" = "#2563eb"
"color.text" = "#1e293b"
# ... more tokens

Every file the manifest lists must exist, or loading the pack fails.

3. Create Component (components/my_widget.typ)

The manifest key is the component id. The file must define #let <id>(data). A key that equals a built-in component id replaces that component (for image, define report-image). overrides in the manifest is not evaluated.

#let my-widget(data) = {
  box(
    fill: color-surface,
    inset: spacing-4,
    radius: 4pt,
  )[
    #text(weight: "bold")[#data.title]
    #v(spacing-2)
    #data.content
  ]
}

4. Create Template (templates/my_report.typ)

A template defines #let report(meta, body). The engine wraps the report content with #show: body => report(meta, body); meta holds title, subtitle and every metadata entry of the request. The template renders its own title page; the built-in one is skipped.

#let report(meta, body) = {
  let title = meta.at("title", default: none)
  if title != none {
    align(center)[
      #text(size: font-size-2xl, weight: "bold")[#title]
    ]
    v(spacing-6)
  }
  body
}

5. Assets (optional)

Files under assets/ are added to the Typst file system by their path inside assets/, e.g. assets/logo.svg is image("/logo.svg", alt: "Logo").

Using a pack

use renderreport::Engine;

let mut engine = Engine::new()?;
engine.load_pack("my-pack")?;

let report = engine
    .report("my-report")
    .pack("my-pack")
    .title("Report Title")
    // ... add components, e.g. "my-widget"
    .build();

From the CLI: renderreport render request.json --pack-path ./my-packs, with pack_id and template_id set in the request JSON.

Manifest fields

Field Required Purpose
pack.name, pack.version yes Pack name and semver version
pack.description, pack.authors, pack.license, pack.repository, pack.keywords, pack.capabilities no Metadata
compatibility.min_engine_version, max_engine_version, typst_version no Recorded, not checked yet
templates.<name>.file yes File in templates/; <name> is the template_id
templates.<name>.default_theme no A theme of this pack, merged when the template is used
themes.<name>.file, themes.<name>.default yes / no File in themes/; default = true marks the pack’s default theme
components.<id>.file yes File in components/ defining #let <id>(data)

Use kebab-case for ids and template names.

Edit this page on GitHub · Docs for v0.7.0