Adds analytics-loader for GA4 event tracking on link clicks. Implements
UTM parameter injection for campaign attribution on share actions.
Enables detailed conversion and traffic source tracking.
Adds share button, QR code block, and Schema.org WebSite markup for
enhanced link sharing. Introduces vCard contact export and PWA manifest
generation for mobile compatibility.
Expands profile distribution and integration capabilities.
Introduces multi-section bio cards and link groups for content organization.
Link buttons now support dict-shape with image, featured, scheduled, rel,
and note attributes. Schema Person flattens sections for SEO. RSS and
single.html templates updated to use new link dict shape.
Enables linktree-style content structuring.
Adds canonical, og:url, robots, and theme-color meta tags for Lighthouse
validation. Hardens avatar with width/height/fetchpriority/decoding and
<picture> pipeline. Adds skip-link and tap-target CSS enhancements.
Improves Core Web Vitals and accessibility scores.
Date the Unreleased v0.4 entries to 2026-05-10. Reset Unreleased to
list deferred-to-v0.5 items only (#7 OG auto-gen, #9 multi-section bio).
v0.4.0 ships:
#11 gallery CSS extraction
#10 +10 icons (35 -> 45)
#8 optional RSS feed
plus the 17-item a11y + polish pass shipped in PR #15.
Plan tracking files updated alongside (phase 7 marked in-progress
during release prep; will flip to completed post-tag).
Closes#8.
Opt-in via `params.rss = true` (off by default). When enabled:
- layouts/index.rss.xml renders an RSS 2.0 feed of [[params.links]]
at /index.xml — one <item> per link, pubDate = build time
- head.html emits <link rel="alternate" type="application/rss+xml">
- Users must remove "RSS" from their disableKinds to let Hugo emit it
Channel populated from params.{name,tagline,bio} and site.BaseURL.
Item shape: <title> = link title, <link> = link URL,
<guid isPermaLink="false"> = bonsai-link-{url}, optional <description>.
XML declaration uses safeHTML+printf to defeat Hugo's default escape
(otherwise '<?xml ... ?>' becomes '<?xml ... ?>' and breaks parsers).
exampleSite enables rss=true to demo the feature; verified output
parses as valid XML via Python ElementTree.
Closes#11.
Move .themes-gallery__* + .variants-gallery__* selectors out of
static/css/bonsai.css into static/css/gallery.css. The demo pages
/themes/ and /variants/ load the new stylesheet via a head_extra
block defined in layouts/_default/baseof.html; the home page and
/icons/ keep getting only bonsai.css.
End-user sites stop shipping ~1.9 KB raw / ~200 B gzipped of demo-only
CSS. README "< 3 KB gzipped" claim restored to true.
Sizes (minified):
bonsai.css 12,394 -> 10,470 raw (-1,924)
3,113 -> 2,910 gzip (-203)
gallery.css 2,252 raw / 626 gzip (loaded only on demo pages)
Verified rendered HTML at /, /themes/, /variants/, /icons/ via curl;
demo pages carry both stylesheets, others carry only bonsai.css.
Consolidates dependabot PRs #1-#5 into one atomic change to avoid sequential rebase churn (all 5 dependabot PRs touched the same 2 workflow files).
- actions/checkout: v4 → v6
- actions/configure-pages: v5 → v6
- actions/upload-artifact: v4 → v7
- actions/upload-pages-artifact: v3 → v5
- actions/deploy-pages: v4 → v5
Each individual bump's CI was green on dependabot's PR. Dependabot will auto-close PRs #1-#5 when this lands on main.
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.
- Code merged via PR #6, retro captured in docs/journals/2026-05-03-v0-3-release.md.
- Mark plan status: completed; record shipped_via + journal links + release-admin items still pending (screenshot regen + v0.3.0 tag).
- Phase files preserved under plans/archive/ for design-rationale retrospection.
- params.ogImageUrl: explicit 1200×630 social-preview image; auto-upgrades twitter:card to summary_large_image.
- params.ogImage = false: suppresses all og:image / twitter:image tags.
- Avatar still serves as the og:image fallback when neither override is set (twitter:card stays summary, since avatars are square).
- Auto-generation deferred to v0.4 — vendoring a TTF + 4 base PNGs (~150 KB) conflicted with the theme's minimalist binary footprint.
- Move every theme-rendered string (nav aria-label, theme-toggle labels, default footer template) to i18n/{lang}.toml.
- Ship en (default) + vi bundles. Adding a language is a single-file change.
- Hugo selects bundle via defaultContentLanguage (not languageCode); documented in README.
- All i18n calls have | default fallbacks so missing keys never break rendering.
- Validate against allowlist in bio-card.html, warnf + fall back to stack on unknown values.
- Variant CSS scoped under .bio__links--{variant} to avoid v0.2-style specificity collisions.
- Inline variant visually-hides .link__title via clip-path; titles stay in DOM for screen readers.
- Grid collapses to 1-col under 480px.
- New /variants/ gallery page renders all three side by side.
- exampleSite switches to layout = "grid" so the live demo shows the new feature.
- .theme-toggle svg { display: block } was beating per-class hide rules
due to higher specificity. Scope the per-class rules under
.theme-toggle .theme-toggle__sun/moon so they win.
- Remove avatar from exampleSite so the initials fallback renders, which
inherits the active palette's accent color (sakura -> pink). The static
avatar.svg was hardcoded vermilion and looked off in non-bonsai
palettes.
- README: add new params (colorTheme, themeToggle button details, schema,
jobTitle/location/email, avatarInitials/Bg) to config table; new
'Color themes' section with live gallery link
- CHANGELOG: 0.2.0 entry under Added/Changed; placeholder for v0.3
- exampleSite/hugo.toml: colorTheme = sakura for distinctive screenshot
+ jobTitle to populate Person.jobTitle in JSON-LD
Bundle of four small additions for the v0.2 release. All strictly
additive — no breaking changes; v0.1 sites upgrade without edits.
Phase 1 — Color theme presets
- Refactor static/css/bonsai.css: palette vars now scoped per
[data-bonsai-theme]; layout vars (radius/gap/pad/fonts) stay in :root
- Four palettes: bonsai (default, vermilion+washi), sakura (cherry
blossom), sumi (monochrome ink), koi (orange+cream). Light + dark
variants each, both prefers-color-scheme and manual data-theme override
- New params.colorTheme (default 'bonsai'); applied via baseof
- Themes gallery at exampleSite /themes/ shows all 4 side-by-side
Phase 2 — schema.org Person markup
- New layouts/partials/schema-person.html emits JSON-LD ProfilePage
containing a Person (built from name/bio/avatar/links + optional
jobTitle/location/email)
- mailto: and tel: links excluded from sameAs
- Suppress with params.schema = false
- Wired into head.html
Phase 3 — Theme toggle UI button
- New layouts/partials/theme-toggle-button.html (sun/moon SVGs)
- Rendered in footer when params.themeToggle = true
- aria-pressed reflects current state; updated theme-toggle.js to
sync on click and on first paint
- Sun shown in dark mode, moon in light (button shows target state)
- exampleSite enables the toggle by default for demo
Phase 4 — Avatar initials fallback
- New layouts/partials/avatar.html: img if params.avatar set,
inline SVG circle with initials otherwise
- Initials auto-derived from params.name (first letter of up to 2
words, uppercased); override with params.avatarInitials
- Background overrideable with params.avatarBg; defaults to accent
- bio-card.html simplified to delegate to the partial
Headless renderers and many systems lack Japanese fonts to render the
kanji glyph used previously. T is universally available and reads as
a Tien-Nguyen demo monogram.
Hugo's relURL/absURL on a leading-slash path treats it as root-absolute
and skips the baseURL subpath. Strip the prefix first so user-supplied
paths like '/images/avatar.svg' resolve correctly under
https://*.github.io/<repo>/.
relURL leaves leading-slash paths untouched, breaking sites served
from a subpath like https://*.github.io/bonsai/. absURL prepends the
full baseURL (including subpath) and works in both root and subpath
deployments. Affects: avatar img, favicon link, css link, theme-toggle
script.
avatar.svg: vermilion circle with kanji 盆 (bon, from 盆栽) in
washi-paper text. exampleSite/hugo.toml updated to reference it.
images/screenshot.png and images/tn.png recaptured against the demo
now showing all 6 working brand+ui icons.
Simple Icons ships SVGs with viewBox only — no explicit width/height —
so inline SVG rendered at 0x0 inside the link button flex container.
Add `.link__icon svg { width:20px; height:20px; fill:currentColor }` to
size all icons consistently. Lucide stroke-only icons opt out of the
fill via attribute selector.
- README: add badges (build/license/Hugo), live-demo callouts, full
configuration parameter table, expanded features list
- CONTRIBUTING.md: dev setup, icon-add workflow, PR/style guidelines
- CHANGELOG.md: Keep-a-Changelog format with v0.1.0 + v0.0.1 entries
- theme.toml: point demosite at live GitHub Pages URL
- build.yml: hugo extended 0.154.0, runs on PR + main push, uploads
exampleSite artifact for inspection
- deploy.yml: deploys exampleSite to GitHub Pages on main push using
actions/configure-pages + actions/deploy-pages (modern flow, no
gh-pages branch)
- dependabot.yml: weekly action version updates
One-time manual: enable Pages in repo settings (Source = GitHub Actions)
before deploy.yml will succeed.
Minimalist Hugo theme for link-in-bio pages, inspired by Linktree
and Japanese bonsai aesthetics.
- Single-page bio with avatar, tagline, bio, and links
- Data-driven via [params] in hugo.toml — no content files needed
- Light/dark mode via prefers-color-scheme + optional toggle
- Inline SVG icon set (github, globe, mail, twitter, linkedin, etc)
- Zero JS by default; opt-in theme toggle script
- exampleSite for local development
Replace the custom Node.js builder with Hugo and the bonsai theme
(added as a submodule at themes/bonsai). Site content moves from
config.yaml into [params] in hugo.toml. CI switched to Hugo Extended
0.154.0 build; daily cron dropped (no API decoration to refresh).
Avatar imported from miti99 project.
The deploy workflow now self-enables Pages via configure-pages@v5
with enablement: true, so the manual Settings -> Pages flip is no
longer required. Mention the workflow-permissions prerequisite
instead.
First-run failed because the repository had no Pages site yet and
configure-pages@v5 defaults to enablement: false. Setting it to true
lets the action create the Pages site on first deploy and removes the
manual Settings -> Pages UI step.
Captures the analysis behind the linkyee-inspired implementation: source
anatomy, dependency matrix, decision matrix (stack, plugins, theme, icons,
deploy), and four phase files used to drive the build.
Single-page link-in-bio site at config.yaml -> build.js -> _site/index.html.
Links flagged with `repo: owner/name` get live star count and last-commit
age decoration from the GitHub REST API at build time.
Stack: vanilla HTML/CSS output, Node 20 build script (sole dep: js-yaml).
Deploy: GitHub Actions Pages artifact, daily cron + push triggers.
Architecture inspired by linkyee (MIT); no source code copied. See NOTICE.