Mark · Theme

Preview stages

A specimen is a component boxed in a documentation column. A stage is the same component with a real page around it, in its own document. Some components can only be judged — or even rendered — the second way.


Why a whole page, and not a bordered div

Because some components leave the flow, and a div cannot contain that. A fixed navbar pins itself to the viewport: dropped among the specimens it would float over the documentation you are reading. An overlay navbar is transparent and positioned over what follows it — inline, it has nothing to sit on and looks broken rather than intentional.

In an iframe the viewport is the stage, so both behave exactly as they will on a real page. No containment tricks, and no CSS crossing in either direction.

Full page, for free

Every example already has one. The Full page ↗ link beside a specimen's name opens that example as a document at:

/__stage/<layer>/<partial-id>/<example-index>

Nothing is declared to get it and no file is written. The URL is derived from the partial's own path and the example's position, so adding an example adds its stage. The __ prefix follows /__preview and /__reload: a real URL that is not a page.

Staged examples

Generated stages put the component on a plain page. When the backdrop is the demonstration — an overlay bar needs a hero to float on — write the page and point the example at it:

# partials/chrome/navbar.ejs
examples:
  - name: Overlay — transparent, over a hero
    stage: /__stage/navbar-overlay   # a page under pages/__stage/
    height: 460                      # the frame; the docs cannot measure inside it
    props: { overlay: true }         # shown as demo data, not rendered inline

An example with stage: is embedded as a lazy iframe instead of rendered among the specimens, and links out to the page itself and to the preview harness. Hand-written stages live at pages/__stage/*.ejs — two path segments, so they never collide with the three-segment generated ones.

The wrapper

Both kinds render through templates/preview-stage.ejs: a full document with the head, the component, and optional filler.

<%- require('/templates/preview-stage.ejs')({
  meta_title: 'Navbar — overlay | stage',
  filler: 3,        // paragraphs of page underneath; 0 for none
  content: navbar({ overlay: true, /* … */ }) + hero({ /* … */ }),
  above: '',        // markup before the subject (content above a footer)
  below: '',        // markup after it
}) %>

Filler is deliberately plain — the component is the subject, and anything characterful there competes with it. Generated stages pick an amount by layer: chrome gets more, because a bar needs something to pass over.

Rules worth knowing

  • Stages are noindex. They are fixtures, not content, and should never rank against a real page.
  • They ship with the static site. The export writes every generated stage, so Full page ↗ works on the deployed docs exactly as it does in dev.
  • Any stage opens in the harness. Append it to /__preview?path= for viewport and palette switching.
  • Editing dev/ needs a restart. The watcher covers partials/, templates/, pages/ and assets/ — a new route in dev/server.mjs will 404 until the server is bounced.