Theming
A theme is a package like any other: it contributes layouts and assets.
How a page gets its look
A collection says which function renders its pages:
Collection.create "docs" decoder
|> Collection.layout (fun context -> (* markup *) )
That function receives a PageContext<'FrontMatter> - the page, its decoded front matter, the site, every other page, and the rendered content - and returns markup. Everything else a theme does (stylesheets, scripts, web components) it contributes as a plugin:
registry
|> Registry.asset (WriteText(css, RelativePath.create "assets/theme.css"))
|> Registry.extra (Stylesheet "assets/theme.css")
So "using a theme" is two lines: register the package, and use its layout.
Site.create "My library"
|> Theme.register theme // its assets
|> Site.collection (Theme.docs theme "content") // its layout and front matter
The default theme
Nacara.Theme.Default is the one this site uses, and what dotnet new nacara-docs starts you with: navbar, sidebar, table of contents, dark mode, and the components for tabs, callouts and code frames. It is documented with the other packages:
- Default theme - what you get, and how to add it
- Customising - colours, spacing, fonts, your own CSS
- Navbar - sections, dropdowns, and the frame
- Menu - where a sidebar comes from, and writing your own
- Front matter - what a page says about itself
- Components - composing a layout of your own
Three ways to make it yours
Override the tokens. Colours, spacing and the measure are custom properties, and your own stylesheet is loaded after the theme's, so yours wins.
Compose the pieces. The navbar, sidebar, table of contents and page navigation are exported functions. Your own layout can use them and arrange the middle differently - a landing page, a reference page with two columns.
Write a theme. A layout function, a stylesheet, and register; nothing else is required. Publish it and it is an ordinary NuGet package, like the default one.
What the engine owns
Some things stay with the engine whichever theme you use:
| The engine decides | The theme decides |
|---|---|
| Which pages exist, and their routes | What a page looks like |
| That front matter is typed, and fails the build when it is not | Which fields it reads |
| What a URL is - base path, locale, version prefix | Which links a page shows |
| Which locale a page belongs to, and which one stands in for it | How that is said to a reader |
| What a code block contains - its title, marked lines, folded ranges | The markup that draws it |
| That a page carries its headings, whichever plugin read them out of it | Whether a table of contents is shown, and where |
| That an asset is written once, and only when its bytes changed | Which stylesheets and scripts a page carries |
So swapping themes does not change your content, and a plugin can ship a widget - a search box, a version switcher - without knowing which theme draws it.