Skip to content

Architecture

Rod Christiansen edited this page Oct 8, 2026 · 3 revisions

Architecture

How the site is put together. This is a static site: there is no server, no runtime rendering, and no data fetching at request time.

Build model

astro.config.mjs is the whole configuration:

Setting Value Effect
site https://reportmate.app Base for canonical URLs and the absolute Open Graph image URL built in Layout.astro
output static Every route is prerendered to HTML at build time
integrations tailwind() The @astrojs/tailwind integration, which wires Tailwind into the build with no separate PostCSS config

tsconfig.json extends astro/tsconfigs/strict. Component props are declared with a TypeScript interface Props in each component's frontmatter.

Directory layout

Directory Role
src/pages/ One file per route, file-based routing
src/layouts/ Layout.astro, the single page shell
src/components/ Reusable pieces used by more than one page or section
src/components/dataviz/ Three decorative SVG marks
src/data/ modules.js, plain JavaScript shared by two pages
public/ Copied verbatim to the site root

The layout shell

src/layouts/Layout.astro wraps every page. It takes three props:

Prop Required Default
title yes —
description no A site-wide default sentence
hideFooter no false

It renders the <head> metadata (canonical link, theme color, favicons, Open Graph and Twitter tags), the sticky nav, a <slot /> for the page body, the footer, and the lightbox.

The nav marks the current link active by comparing Astro.url.pathname, with trailing slashes stripped, against each entry's href. Because that comparison is exact, a new nested route will not light up its parent nav item.

Lightbox

The layout also emits a hidden lightbox overlay and a small inline script. The script collects every img[data-lightbox] on the page, and on click opens the overlay showing that image. It supports previous and next across all matched images, closes on the close button, on a click outside the image, and on Escape, and moves with the arrow keys. If a page has no data-lightbox images, the script returns immediately.

The script is is:inline, so Astro emits it as-is rather than bundling it.

Components

Component Purpose
FeatureBlock.astro Two-column marketing block. Props: badge, title, tone (dark or light), reverse. Body copy goes in the default slot; the image or figure goes in the visual named slot. reverse swaps the column order at the lg breakpoint
Mermaid.astro Renders a Mermaid diagram from a code string with an optional caption
dataviz/BarsMark.astro Four-bar mini chart in a 24x24 viewBox
dataviz/DonutMark.astro Five-segment donut, arcs computed from a segments array using stroke-dasharray
dataviz/Sparkline.astro Eight-point polyline with an end dot, in a 64x24 viewBox

The three data-viz marks are decorative by default: they render aria-hidden unless you pass a label, in which case they take role="img" and that label. Each accepts a class prop to override its size; Sparkline also takes a color (default #0074c7).

Mermaid rendering

Mermaid.astro puts the diagram source in a <pre class="mermaid"> and loads Mermaid 11.15.0 as an ES module from the jsDelivr CDN inside an inline module script. It guards on a window.__rmMermaidInit flag so the library is imported and initialized once per page even if several diagrams are present, then calls mermaid.run() over every .mermaid element.

Initialization sets startOnLoad: false, securityLevel: 'loose', a base theme with brand-colored theme variables, and flowchart.htmlLabels: true so node labels can contain markup.

Two consequences follow from the CDN import: the diagram renders client-side, not at build time, and it will not render for a visitor who cannot reach jsDelivr.

API reference page

/docs is a thin host for a third-party web component:

  1. An inline script seeds localStorage key mosaic-theme to {"mode":"system"} so Stoplight Elements follows the operating-system color scheme instead of defaulting to light, and mirrors the resolved scheme onto <html data-theme> so the site chrome has the right theme on the first paint. It subscribes to prefers-color-scheme changes.
  2. Page-scoped CSS under [data-theme='dark'] restyles the shared nav for dark mode. Only this page ever sets data-theme, so those rules do not leak.
  3. An <elements-api> element points at /openapi.json with router="hash" and layout="sidebar", sized to calc(100vh - 4rem) to sit under the 4rem nav.
  4. The Stoplight stylesheet and script are loaded from jsDelivr at a pinned version (@stoplight/elements@8.4.4) with Subresource Integrity hashes and crossorigin="anonymous".

Layout is invoked with hideFooter={true} here.

The spec at public/openapi.json is the API's OpenAPI 3.1 document, exported from the reportmate-api source by its scripts/export_openapi.py and committed here by the openapi-sync workflow every day (see Deployment). It is a static file — the docs page never contacts a live API.

What this site does not do

  • No client-side framework. The only JavaScript shipped is the lightbox script, the Mermaid loader, and the Stoplight bundle on /docs.
  • No API calls, no authentication, no cookies, no analytics script in the repo.
  • No content collections, no Markdown, no CMS.