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 behavior. 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. show.haml and index.haml are required once there are posts and
listings to render. base.haml is optional.
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. No key is required, and a post with no title takes one from its
filename:
---
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 other key is read only
when taxonomies in blogin.json names it, and then it groups posts the way
tags does.
See Writing Posts.
Change the site's behavior#
blogin.json. Every key is optional, an unknown key is a warning that suggests
a real key within three edits of it, 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 sets its position, and nav: false keeps it out.
Sections sort by order ascending, then by name, and a section without one
counts as 0, so a negative order moves a section to the front. 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.