tiennm99 d92a9c820b docs(journal): v0.2 release retro
Captures CSS specificity gotcha, Hugo jsonify-in-script trap, hardcoded SVG fill issue, and the modular-commit safety net learned from the same-day v0.1 → v0.2 cadence.
2026-05-03 12:43:21 +07:00
2026-05-01 10:04:59 +07:00
2026-05-01 10:04:59 +07:00

Bonsai

build license Hugo

A minimalist Hugo theme for link-in-bio pages, inspired by Linktree and the Japanese art of bonsaismall, curated, intentional.

Live demo · Icon gallery · Layout variants · Color themes

盆栽 (bonsai): "tray planting" — the art of growing miniature trees through patient, deliberate cultivation. Every branch placed with care.

Bonsai treats your bio page the same way: a quiet, well-pruned page that surfaces only what matters — your name, who you are, and where people can find you.

Features

  • Single-page bio — name, avatar, tagline, links. Nothing else.
  • Data-driven links — defined in [[params.links]]; no content files required.
  • 35 icons out of the box — 25 brand (GitHub, Mastodon, Bluesky, X, Threads, LinkedIn, Instagram…) + 10 utility (mail, globe, rss…). Vendored from Simple Icons and Lucide.
  • Light & dark mode — respects prefers-color-scheme; optional toggle.
  • Zero JavaScript by default — pure HTML + CSS; opt-in JS for theme toggle only.
  • Fast — < 3 KB gzipped CSS, no web fonts (system stack), no runtime fetches.
  • Accessible — semantic HTML, focus-visible outlines, prefers-reduced-motion.
  • Responsive — mobile-first, looks right at every viewport.

Quick Start

As a Git submodule (simplest)

git submodule add https://github.com/tiennm99/bonsai.git themes/bonsai

Add to hugo.toml:

theme = "bonsai"

As a Hugo Module

hugo mod init github.com/<you>/<your-site>
hugo mod get github.com/tiennm99/bonsai

Add to hugo.toml:

[module]
  [[module.imports]]
    path = "github.com/tiennm99/bonsai"

Configuration

Minimal hugo.toml:

baseURL = "https://example.com/"
title   = "Your Name"
theme   = "bonsai"

# Single-page bio — disable everything Hugo doesn't need.
disableKinds = ["taxonomy", "term", "RSS", "sitemap", "404"]

[params]
  name    = "Your Name"
  tagline = "Tending my little corner of the internet"
  bio     = "Short bio. One sentence is plenty."
  avatar  = "/images/avatar.jpg"

  [[params.links]]
    title = "GitHub"
    url   = "https://github.com/yourname"
    icon  = "github"

  [[params.links]]
    title = "Email"
    url   = "mailto:you@example.com"
    icon  = "mail"

All parameters

Param Type Default Description
name string site title Display name shown as <h1>.
tagline string One-liner under the name.
bio string (markdown) Short bio paragraph. Markdown supported.
avatar string (URL) Avatar image path. If unset, theme renders an SVG circle with auto-derived initials.
avatarInitials string first letters of name Override the initials when no avatar is set.
avatarBg string (CSS color) var(--bonsai-accent) Background color of the initials circle.
favicon string (URL) /favicon.ico Favicon path.
colorTheme string bonsai Palette: bonsai, sakura, sumi, or koi. See Color themes.
layout string stack Link arrangement: stack, grid, or inline. See Layout variants.
themeToggle bool false Render a sun/moon button in the footer + load the toggle script.
ogImage bool true Set false to suppress all og:image / twitter:image tags.
ogImageUrl string (URL) Explicit OG preview image (1200×630 recommended). Overrides the avatar fallback and upgrades Twitter card to summary_large_image.
schema bool true Emit schema.org Person JSON-LD in <head>. Set false if you provide your own.
jobTitle string Optional Person.jobTitle field for JSON-LD.
location string Optional Person.address field for JSON-LD.
email string Optional Person.email field for JSON-LD.
footer bool true Show the footer.
footerText string (HTML) © {year} {name} Override footer text. HTML allowed.
links array Bio links. See below.

Each [[params.links]] entry:

Field Type Required Description
title string yes Link label.
url string yes Link target. mailto: and tel: are rendered without target=_blank.
icon string no Icon name from the available set (see below). Unknown names render a generic external-link glyph.

Color themes

Four built-in palettes, each with light + dark variants. Set colorTheme in [params]:

Name Vibe Accent
bonsai (default) washi paper + vermilion seal #8b3a2b
sakura cherry blossom pink #d4456a
sumi monochrome ink #1a1a1a
koi orange + cream #c8521e

Live preview: tiennm99.github.io/bonsai/themes/.

Layout variants

Three arrangements for [[params.links]]. Pick one via layout in [params]:

Value Look Best for
stack (default) Full-width vertical buttons ≤ 6 link bios; the classic Linktree shape.
grid Two-column responsive grid (collapses to one column under 480 px) 612 links; balances density and tap-target size.
inline Icon-only horizontal row Lots of accounts, short page; titles stay in DOM for screen readers.

Live preview: tiennm99.github.io/bonsai/variants/.

i18n

Theme-rendered strings (nav landmark, theme-toggle labels, default footer) live in i18n/{lang}.toml. Bundles for en and vi ship with the theme.

To use another language, set Hugo's defaultContentLanguage and add a matching i18n/{lang}.toml:

defaultContentLanguage = "fr"
# i18n/fr.toml
[nav_links_label]
other = "Liens"
[theme_toggle_label]
other = "Basculer le thème clair / sombre"
[theme_toggle_title]
other = "Basculer le thème"
[footer_default]
other = "© {{ .year }} {{ .name }}"

Missing keys fall back to en. User content (name, tagline, bio, link titles, footerText) is never auto-translated — it stays user-owned.

Available Icons

Brand / Social (25)
Name Source
github Simple Icons
gitlab Simple Icons
mastodon Simple Icons
bsky Simple Icons
x Simple Icons
threads Simple Icons
linkedin Simple Icons
instagram Simple Icons
facebook Simple Icons
tiktok Simple Icons
youtube Simple Icons
twitch Simple Icons
discord Simple Icons
telegram Simple Icons
signal Simple Icons
whatsapp Simple Icons
reddit Simple Icons
medium Simple Icons
devto Simple Icons
substack Simple Icons
hashnode Simple Icons
kofi Simple Icons
patreon Simple Icons
buymeacoffee Simple Icons
paypal Simple Icons
UI / Utility (10)
Name Source
mail Lucide
globe Lucide
link Lucide
rss Lucide
calendar Lucide
phone Lucide
mappin Lucide
filetext Lucide
extlink Lucide
share Lucide

Icons are vendored at build time — no CDN fetch at runtime. Live gallery: tiennm99.github.io/bonsai/icons/.

To refresh or add icons, edit scripts/sync-icons.sh and data/icons.yaml, then re-run the script. See CONTRIBUTING.md.

Development

git clone https://github.com/tiennm99/bonsai.git
cd bonsai/exampleSite
hugo server --themesDir ../.. --bind 0.0.0.0

Build for inspection:

cd exampleSite && hugo --themesDir ../.. --gc --minify

Contributing

PRs welcome. See CONTRIBUTING.md for dev setup, the icon-add workflow, and PR guidelines.

License

Apache-2.0 © tiennm99. See LICENSE and NOTICE for third-party attributions (Simple Icons CC0, Lucide ISC).

S
Description
A minimalist Hugo theme for link-in-bio pages, inspired by Linktree and Japanese bonsai aesthetics — small, curated, intentional.
Readme Apache-2.0 883 KiB
Languages
HTML 54.1%
CSS 32.2%
Shell 8.9%
JavaScript 4.8%