Site building
Pages and layouts
Pages are json-render specs with data queries, merged into a layout and resolved by path.
The built-in pages collection holds routable pages: title, path (unique; /, /about, /docs/:slug), description, layout (a relation to layouts), data (named queries), spec, and css. Pages have drafts, so they publish like any document.
Specs
A spec is a flat json-render tree. Only components from the host's catalog are allowed.
{
"root": "main",
"elements": {
"main": { "type": "Section", "props": {}, "children": ["title", "body"] },
"title": { "type": "Heading", "props": { "text": { "$state": "/data/post/title" }, "level": 1 } },
"body": { "type": "RichText", "props": { "json": { "$state": "/data/post/body" } } }
}
}Data queries
{
"posts": { "collection": "posts", "sort": "-publishedAt", "limit": 10 },
"post": { "collection": "posts", "one": true, "filter": { "slug": ":slug" } }
}Each query runs with public access before rendering. :param in a filter value takes the path parameter, and one: true turns a missing document into a 404.
State
Components read state with { "$state": "/path" }: /data/<name>, /params/<name>, /menus/<name>, /site, /globals/<slug>, and /page. A document in state has its fields plus system values prefixed with _ (_id, _publishedAt, _locale).
Layouts
A document in layouts has a name, a spec with exactly one Outlet element, and css. The page's root replaces the Outlet; element keys are prefixed layout: and page: so they never collide. A page without a layout uses the one named default.
Resolving a page
engine.resolvePage(user, { path, preview }) matches published pages (static paths first, then fewer parameters), runs the queries, merges the layout, and returns { page, params, spec, state, css, theme, warnings }, or null for a 404. Over HTTP it is GET /_public/_pages?path= (&preview=1 shows working copies to users who may read pages), and POST /_cms/pages/_preview resolves an unsaved page for the editor.
In the reference app, void.config.ts falls back from any unclaimed URL to /site/:splat, whose loader calls resolvePage and renders the spec with the json-render Renderer.