Forked from https://github.com/lingxz/er.
A configurable blog theme for Hugo, with elements inspired by this blog.
Checkout the demo.
- Open graph tags
- Tag and category pages
- Collapsible table of contents at the top of each post (built from Hugo's native
.TableOfContents) - Light and dark mode with a
clay(warm-earth) ornord(arctic) color palette - Mermaid diagrams in Markdown and Org content
- Tag cloud on big screens
- Hugo multilingual sites
- Optional Pagefind search
- Styled with TailwindCSS
git submodule add [email protected]:darwin67/er.git themes/er
git submodule updatehugo mod get github.com/darwin67/erThe theme ships a projects content type for case studies / portfolio
work, with a dedicated single-page layout, a grid list, and an optional
"Featured work" block on the homepage. Drop projects under
content/projects/ (either single markdown files or page bundles when
you have a cover image + gallery).
The homepage featured block is opt-in:
params:
showFeaturedProjects: trueIt surfaces up to 3 projects whose frontmatter sets featured: true,
and renders nothing if none match — so flipping the param on without
any featured content is also safe.
To add intro text to top-level list pages such as /projects/, /posts/, or
/tags/, create that page's _index.md; for the home page, use
content/_index.md. Use description for a short lead line and the page body
for longer markdown:
---
title: "Projects"
description: "Selected work across infrastructure, tools, and product systems."
---
Short intro copy can live here with normal Markdown formatting.Frontmatter schema (all fields optional except title and date):
---
title: "Acme rebuild"
date: 2025-03-12
role: "Lead engineer"
client: "Acme Co" # omit for personal work
period: "2024 – 2025"
tags: [go, postgres, terraform]
repo: "https://github.com/you/acme"
live_url: "https://acme.example"
status: "shipped" # shipped | active | wip | archived | closed
cover: "cover.jpg" # relative to the page bundle
summary: "Rebuilt the order pipeline; cut p99 latency by 38%."
featured: true # surface on the homepage
---Helpful shortcodes inside a project page:
{{< gallery >}}— responsive image grid with lightbox.{{< results >}} ... {{< /results >}}— metric strip at the top of a case study.
Project stack pills use Hugo's default tags taxonomy, so terms like
go and postgres link to /tags/go/ and /tags/postgres/.
The theme ships with two color palettes. Both support a light and dark mode
(the visitor's choice is respected via the moon/sun toggle and persisted in
localStorage).
| Palette | Vibe |
|---|---|
clay |
Warm-earth terracotta + sage. Default. |
nord |
Arctic Snow Storm (light) / Polar Night (dark). |
Pick one in your site config:
params:
palette: nordIf unset, the site uses clay.
Use a fenced mermaid code block in Markdown:
```mermaid
flowchart LR
Write --> Build --> Publish
```In Org content, use a Mermaid source block:
#+BEGIN_SRC mermaid
flowchart LR
Write --> Build --> Publish
#+END_SRC
Mermaid is loaded only on pages that contain a diagram. Diagrams follow the active color palette and are re-rendered after a light or dark mode change.
The default look is classic. Set mermaidLook to handDrawn for an
Excalidraw-like appearance, or to neo for Mermaid's modern style. When using
handDrawn, the fixed drawing seed keeps lines stable across re-renders; change
it to produce a different variation:
params:
mermaidLook: handDrawn
mermaidHandDrawnSeed: 12The theme uses Mermaid 11.15.0 from jsDelivr by default. To self-host it or pin another compatible build, set the ESM module URL:
params:
mermaidURL: /js/mermaid.esm.min.mjsYou can put your favicon at static/favicon.ico, the theme will automatically look for it there. If you want to choose a different path, please set the favicon parameter in [params] in the config.
Table of contents is activated by default, if it detects markdown headings. To turn it off, just add toc = false in the frontmatter. Alternatively, you can turn off contents page for the whole site by setting showtoc = false under the [params] section of config.toml, like this:
[params]
showtoc = falseTag cloud is shown by default. To disable, add showTagCloud = false under the [params] section, similar to showtoc. You can also configure the maximum number of tags you want to show in your tag cloud, using the maxTags key under [params]. This number is 50 by default.
The theme supports Hugo multilingual sites. Define languages in the importing site config, not in the theme:
defaultContentLanguage: en
languages:
en:
locale: en-US
label: English
weight: 1
ja:
locale: ja-JP
label: 日本語
weight: 2The theme uses each rendered page's language for <html lang>,
language-aware navigation URLs, taxonomy links, and the language switcher. The
language switcher is shown when Hugo renders more than one language site, which
the theme detects with len hugo.Sites > 1.
Add translated fixed UI strings by overriding the theme's i18n/*.yaml keys in
your site.
For example, to change the default English search label, create
i18n/en.yaml in your site:
search:
other: Find
searchPlaceholder:
other: Find something...
olderPosts:
other: Earlier
newerPosts:
other: LaterSite-level i18n files take precedence over the theme defaults. Override only the keys you want to phrase differently.
Search is disabled by default. To enable the search UI, set search = true
under [params]:
[params]
search = trueSearch uses Pagefind, so enabling the UI also requires your site build to generate and deploy a Pagefind index. Run Pagefind after Hugo renders the site:
hugo --minify
pagefind --site publicDeploy public/pagefind/ with the rest of public/. If search = true is set
but public/pagefind/ is missing, the search assets or index files will 404.
For multilingual sites, do not pass --force-language; Pagefind reads the
rendered <html lang> values and creates language-specific indexes.
The preferred development shell is nix develop; it provides Hugo, Pagefind,
Watchexec, Tailwind, Go, and release tooling.
To run the demo site from the repository root:
make devThis builds the demo into demo/public/, rebuilds its Pagefind index, and then
starts Hugo's live-reload server at http://127.0.0.1:1414/. While the server
runs, a file watcher refreshes demo/public/pagefind/ after content, template,
asset, or config changes.
To modify the theme styles:
- Run
make devfrom the repo root - Run
make css-watchfrom the repo root to rebuild CSS live as the demo templates change
At the theme root, make build runs pagefind --site public after Hugo and
writes public/pagefind/ for the root fixture.
Pull request titles must use Conventional Commits. The release workflow uses git-cliff to derive the next semver tag from conventional commit history:
feat: minor releasefixand most other included types: patch release- breaking changes marked with
!orBREAKING CHANGE: major release
Merges to main create or update a release/next pull request with a generated
CHANGELOG.md entry. Merging that release PR creates a vX.Y.Z tag and
publishes a GitHub release.
The release workflows require a private GitHub App installed on this repository
with Contents: write and Pull requests: write permissions. Store its app ID
and private key as repository secrets named RELEASE_APP_ID and
RELEASE_APP_PRIVATE_KEY. The release PR workflow intentionally does not use
the default GITHUB_TOKEN for release branch pushes because events created with
that token do not trigger normal downstream workflow runs.