Layouts
The site from Getting started has a home page and an about page, both wrapped in page.html. Keep those files as we add shared navigation, styling, and a place for posts.
Navigation belongs to the site, not each document
We could paste links into every Markdown file, but then every navigation change would mean editing every page. A fragment lets the scheme own that shared content: it is rendered once into a named layout slot. Create .falz/schemes/nav.md:
[Home](/) · [About](/about.html)
Add {{nav}} to .falz/schemes/page.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tiny site</title>
<link rel="stylesheet" href="/site.css">
</head>
<body>
<nav>{{nav}}</nav>
<main>{{body}}</main>
<script src="/falz-hotreload.js"></script>
</body>
</html>
Declare the fragment in layout.xml:
<Layout src="page.html">
<Fragment name="nav" src="nav.md" pipe="md"/>
<Content name="body" src="*.md" pipe="md" to="{FILENAME}.html"/>
</Layout>
The md pipe turns nav.md into HTML before the layout is compiled.
A component-rendering pipe can instead use <Fragment name="nav" pipe="shell"/> with no src. It receives the fragment's name as this.name and an empty input buffer, so no placeholder source file is necessary. Like normal pipes, it receives this.globals, this.vars, this.entry, and this.debug. Content <Var> values are in this.vars and remain available directly on its context for compatibility, except where they collide with context fields. See the Fragment reference.
Give the shared pages a stylesheet
Create .falz/schemes/site.css:
body { max-width: 48rem; margin: 2rem auto; font: 18px system-ui; }
nav { margin-bottom: 2rem; }
Add a top-level asset:
<Layout src="page.html">
<Fragment name="nav" src="nav.md" pipe="md"/>
<Content name="body" src="*.md" pipe="md" to="{FILENAME}.html"/>
<Asset name="css" src="site.css" to="site.css"/>
</Layout>
The result is copied to dist/site.css. Assets are transformed by their pipe, if any, but are not inserted into the page template.
Build again and open / and /about.html: both now have navigation and styling. The Markdown-site checkpoint contains the project at this point.
Let posts have their own presentation
The home and about pages can share a layout, but posts will have their own article template and directory-style URLs.
Create posts/hello.md with this content:
# Hello
This is my first post.
Mirror that directory in the scheme:
posts/hello.md
.falz/schemes/posts/layout.xml
.falz/schemes/posts/post.html
.falz/schemes/posts/layout.xml:
<Layout src="post.html">
<Fragment name="nav" src="nav.md" pipe="md"/>
<Content name="article" src="*.md" pipe="md" to="{FILENAME}/index.html"/>
</Layout>
Output templates can place a filename placeholder in a directory segment. For posts/hello.md, {FILENAME}/index.html expands to hello/index.html; with the source base posts/, the final path is dist/posts/hello/index.html. Falz creates posts/hello/ as part of writing the result.
.falz/schemes/posts/post.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tiny site — posts</title>
<link rel="stylesheet" href="/site.css">
</head>
<body>
<nav>{{nav}}</nav>
<article>{{article}}</article>
<script src="/falz-hotreload.js"></script>
</body>
</html>
posts/hello.md now becomes dist/posts/hello/index.html. nav.md is found by walking up the scheme tree, so the root fragment is reused. Add .falz/schemes/posts/nav.md to override it only for posts.
The nearest layout wins: root pages still use the root layout, while posts/hello.md and any deeper posts use the posts layout. Matching happens in each source directory, so src="*.md" does not need a recursive glob.
Keep images with the writing
A shared stylesheet belongs to the scheme. A post's image belongs beside the post in the source tree. To copy those images without wrapping them in HTML, replace the posts content rule with:
<Content name="article" src="*.md" pipe="md" to="{FILENAME}/index.html">
<Asset name="images" src="*.{png,jpg,jpeg,webp}" to="images/{BASENAME}"/>
</Content>
With posts/cover.png in the source, this writes dist/posts/images/cover.png. Reference it from the post as : the page lives at /posts/hello/, so the relative URL resolves to that image.
The source directory remains the output base; to is appended below it. Falz creates destination directories as needed. Use top-level assets for scheme-owned files and nested assets for source-owned files.
The posts-layout checkpoint includes the complete site and an image.
A fixed value can belong to a rule
<Var> makes a string available while compiling a layout and to the content pipe as this.vars:
<Content name="article" src="*.md" pipe="md" to="{FILENAME}/index.html">
<Var name="section" value="Journal"/>
</Content>
The template may now contain {{section}}. A custom pipe reads it as this.vars.section. Variables are strings and belong to that <Content> rule.
For project-wide structured values and secrets, use configuration variables.
Matching just the files you want
As the site grows, you might keep a draft beside published posts. Change src="*.md" to src="*.md !draft.md" to leave it out. The full pattern rules are in the layout reference.
Posts now have their own presentation, but their URLs still come from filenames. In Pipes, we will let a post supply its own slug.