Skip to content

Authoring reports

Reports live in apps/site/src/content/reports/<slug>/v<version>.mdx. Each file is one version of one report; the newest version is served at /reports/<slug>/ and every version stays at /reports/<slug>/v<version>/.

title: "Atmospheric CO₂ at Mauna Loa"
subtitle: "A reference analysis …"
slug: atmospheric-co2-2026 # lower-case, hyphens; never changes
type: analysis # report | analysis | brief (reports get a PDF cover page, a contents page and back matter on its own page)
palette: goap # optional: default | landscape | goap — colour palette for this report (see /design/palette/)
status: published # draft | review | published | superseded (drafts build only in dev)
version: "1.0" # semver-ish; bump for a new file
date: 2026-08-17
updated: 2026-08-20 # optional
authors:
- name: Jane Doe
orcid: 0000-0002-1825-0097
affiliation: Centre for Sustainable Development Reform
role: Lead author
- name: CSDR Platform Team
type: organization
abstract: >- # used for <meta description>, JSON-LD and the reports list
keywords: [carbon dioxide, Mauna Loa]
licence: CC BY 4.0
doi: 10.5281/zenodo.0000000 # optional; when minted
funder: # optional
series: Scaffold reference reports # optional
data_bundles: [noaa-mlo-co2] # bundle ids used by the report
outputs: { pdf: true, html: true } # PDF + self-contained HTML written next to the page by pnpm build
changelog:
- { version: "1.0", date: 2026-08-17, note: First release }

The schema is reportSchema in src/content.config.ts; the build fails on invalid frontmatter.

Public or internal is decided by the folder, not by frontmatter (D11): src/content/reports/<slug>/ is on the public site; src/content/internal/<slug>/ is only on the sign-in internal site (pnpm dev:internal to preview). Setting visibility: internal on a file under reports/ fails pnpm check — move the directory instead. See Deploy → Audiences.

Plain Markdown does most of the work — Markdown tables are auto-wrapped in a scroll container, ![alt](src "caption") becomes a captioned figure. Beyond that, import from @csdr/editorial:

import { Figure, Table, Callout, Ref, KeyMessages, StatRow, StatTile, DataDownload, Definition } from '@csdr/editorial';
ComponentUse
<KeyMessages>Bulleted opening block; one number per bullet if you can
<StatRow><StatTile …/></StatRow>2–4 headline numbers with unit, delta, source
<Figure id caption source width webNote printNote>Numbered figure; put a chart, image or map inside. webNote (“Hover for values…”) is dropped from the PDF/print; printNote (“An interactive version is online.”) appears only there
<Table id caption units source landscape keep>Numbered table; put a Markdown table inside (blank lines around it). In the PDF, landscape gives a wide table its own landscape page and keep stops it splitting across pages (by default long tables run over with the header row repeated)
<Callout kind title>note · key-finding · method · warning · caution
<Ref to="fig-x" /> or {ref:fig-x}“Figure N” / “Table N”, resolved at build
[@key]Citation from src/content/bib/references.bib; end the report with ## References and [^ref]
[^1]GFM footnote
<DataDownload bundle="id" />Files, licence, provenance, citation of a bundle
<Definition term="SEEA">…</Definition>Inline definition

See the live catalogue at /design/ — every component with a render and copyable code.

Do not type numbers that the data can change. Put a small .astro “analysis cell” next to the report (see src/components/analyses/co2/) that loads the bundle with the data loaders, computes derived values once, and exposes charts and inline values (<Co2Value of="latestAnnual" />). The reference report is the worked example.

To publish a revision, copy v1.0.mdx to v1.1.mdx, bump version, add a changelog entry, and set the old file’s status: superseded. Both build; the old one shows a banner and canonicalises to the new one.

  • pnpm check and pnpm test pass
  • Every figure has caption, source and (for charts) an alt sentence
  • Key numbers come from an analysis cell, not the keyboard
  • References render under ## References
  • Preview at /reports/<slug>/ and print preview look right

Every build writes the PDF and the self-contained HTML export next to the page (see Deploy → Exports). What authors control:

  • The PDF is a print-native document, not the web page on paper: a 10 pt body on a 154 mm measure (20 mm left / 36 mm right), numbered sections (1, 2.1 — the screen stays unnumbered), figures at text width, no decorative rules. The same layer drives the HTML export, so the two files are one document in two containers.
  • type: report gets a title page (title block, authors, version/licence, the abstract and the key messages, which move up from the body for print), a contents page with page numbers (filled from a first render, then printed again) plus an imprint (recommended citation, versions, changelog, licence), and running headers from page 2; analysis and brief flow from page 1 — title block, key messages, headline numbers, first section — with the same running header/footer.
  • status: draft | review | superseded prints a watermark on every page and names the status in the running header. Drafts are not built in production at all.
  • outputs: { pdf: false } or { html: false } switches an export off for that report.
  • <Figure webNote="…" printNote="…"> keeps screen-only sentences (“hover for values”) out of the PDF and adds a print-only one; <Table landscape keep> controls how a wide or long table paginates.
  • Figures, callouts, key messages, stat rows and the data card never split across pages; tables may, with the header row repeated. Charts print at text width and at most 80 mm tall (90 mm for width="wide") — the default chart shape (720 × 320) is chosen for that. Open a section with a sentence, not a figure: a heading is kept with whatever follows it, so a heading + full-width figure that does not fit moves to the next page together and leaves a gap. If something still paginates badly, the fix belongs in packages/theme/src/print.css, not in the report.