Skip to content

darwin67/er

Repository files navigation

Hugo - Er theme

Forked from https://github.com/lingxz/er.

A configurable blog theme for Hugo, with elements inspired by this blog.

Checkout the demo.

Features

  • 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) or nord (arctic) color palette
  • Mermaid diagrams in Markdown and Org content
  • Tag cloud on big screens
  • Hugo multilingual sites
  • Optional Pagefind search
  • Styled with TailwindCSS

Installation

Git submodule

git submodule add [email protected]:darwin67/er.git themes/er
git submodule update

Hugo module

hugo mod get github.com/darwin67/er

Configurations

Projects

The 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: true

It 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/.

Color palette

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: nord

If unset, the site uses clay.

Mermaid diagrams

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: 12

The 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.mjs

Favicon

You 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.

Markdown TOC

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 = false

Tag cloud

Tag 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.

Multilingual sites

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: 2

The 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: Later

Site-level i18n files take precedence over the theme defaults. Override only the keys you want to phrase differently.

Search

Search is disabled by default. To enable the search UI, set search = true under [params]:

[params]
search = true

Search 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 public

Deploy 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.

Development

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 dev

This 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:

  1. Run make dev from the repo root
  2. Run make css-watch from 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.

Releases

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 release
  • fix and most other included types: patch release
  • breaking changes marked with ! or BREAKING 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.