Cookbook
A Blogin site is customized in six places. This page is the index: what each one reaches, and where the detail lives.
| Where | What it changes |
|---|---|
blogin.json |
Site-wide behaviour. Feeds, pagination, taxonomies, assets, languages. |
| Front matter | One post. Its URL, its ordering, its summary, its redirects. |
layouts/ |
The markup of every page, per section if you want. |
assets/ and static/ |
Stylesheets, scripts, images, and files served verbatim. |
data/ and shortcodes/ |
Values a layout reads, and markup a post can call. |
themes/ |
A whole layout and asset set, reused across sites. |
Change what a page looks like#
Edit layouts/. base.haml is the shell, show.haml a post, and index.haml
a listing. A missing one of those three is a build error naming it.
Give one section its own markup by putting a layout in a matching directory.
A post in content/essays/ renders through layouts/essays/show.haml when that
file exists, falling back to layouts/show.haml:
layouts/
show.haml every post
essays/show.haml posts under content/essays/
Or name a layout in the config instead of using a directory:
"sections": {
"essays": { "layout": "essay" }
}
See Layouts for the full set of files and how they resolve, and Template Data for every value a layout can read.
Change what a post does#
Front matter. title is the only required key:
---
title: My Post
slug: a-different-url
order: 2
toc: true
draft: true
summary: What listings and feeds show instead of the opening paragraph.
aliases: [/the-old-url]
---
slug picks the URL, order places a post ahead of date ordering, toc turns
on the table of contents, draft holds it back from a normal build, and
aliases writes a redirecting page at each old URL. Any key Blogin does not
recognise is still available to the layout under its own name, so
series: Advanced in front matter reads as series in show.haml.
See Writing Posts.
Change the site's behaviour#
blogin.json. Every key is optional, an unknown key is a warning naming the
closest real one, and a key with the wrong type stops the build.
Common ones:
| Want | Key |
|---|---|
| Extensionless URLs | clean-urls |
| Posts per listing page | page-size, or per section |
| More than tags | taxonomies |
| RSS or JSON alongside Atom | feed-formats |
| Syntax highlighting | highlight |
| Smaller CSS and JS | minify |
| Cache-safe asset names | fingerprint |
| Responsive images | image-widths |
| More than one language | languages |
See Configuration for all of them with types and defaults.
Change the navigation#
The nav is built from the content tree, so a new directory under content/
becomes a new nav entry. Adjust it per section:
"sections": {
"notes": { "label": "Field Notes", "order": 1 },
"drafts": { "nav": false }
}
label renames it, order places it ahead of alphabetical, and nav: false
keeps it out. A layout renders the tree itself from nav-nodes, with
nav-current(node) marking the current section, so the markup is yours. See
Template Data.
Nothing links /tags automatically. Add it to a layout when you want it.
Change the styling#
Three separate levers, and they combine.
A CSS framework. Set css-framework to none, bootstrap5, pico, or
bulma and Blogin classes the HTML it writes to match. See
CSS Frameworks.
Your own CSS. Anything under assets/css is copied to public/assets/css,
minified and fingerprinted if you asked for it. Link it from base.haml.
The generated stylesheet. public/assets/css/blogin.css carries the syntax
highlighting colors, code block styling, and the light and dark toggle. Override
any rule in your own stylesheet rather than editing it, since a build rewrites
it.
For a light and dark toggle, put theme-script in the <head> and
theme-toggle in the navbar. See Layouts.
Change the pagination#
page-size sets how many posts a listing page holds, and a section can override
it. pagination-html renders a ready-made bar, and pagination-links gives the
pages as data for a bar you write yourself. See Pagination.
Add values a layout can read#
data/. Every .json, .yaml, and .yml file under it loads into data,
keyed by filename:
data/
authors.json -> data<authors>
site/links.yaml -> data<site><links>
A _data.json inside a content directory applies to the pages beneath it and
overrides the site-wide tree key by key. See Data files
and Data File YAML for what a YAML file may hold.
Add markup a post can call#
shortcodes/. Put an HTML template there named for the shortcode, and a post
calls it with key="value" arguments:
<!-- shortcodes/note.html -->
<aside class="note">{{ text }}</aside>
{{< note text="Heads up" >}}
youtube and figure are built in, and a file of the same name overrides one.
See Writing Posts.
Reuse a whole design#
themes/. A theme is a directory of layouts/, assets/, and static/ that
fills in behind your own file by file, so you can override one layout and keep
the rest:
"theme": "acme"
See Themes.
Speed up a big site#
Wrap chrome that renders the same on every page in cache-fragment:
!= cache-fragment('sidebar', { render(:partial<sidebar>) })
Reuse is decided by the values the fragment read, so it cannot serve one page's markup to another. See Layouts.
blogin build --counters prints the work a build did, which is what says
whether a change made it do more. See
Previewing and Building.
What cannot be customized#
Know these before you go looking for a setting.
- No plugin system. Everything a site needs is in the binary.
- No template logic beyond the expression language. It reads, compares, iterates, and calls what the view offers. No assignment, no user-defined functions, no calling into a host language. See Template Expressions.
- No per-taxonomy page size. Term pages use the site's
page-size. - The
page/2URL shape is fixed. See Pagination. - Feeds carry every post in scope, with no length key.