feat: layout variants — params.layout = stack/grid/inline

- 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.
This commit is contained in:
tiennm99 committed 2026-05-03 12:19:16 +07:00
1 parent eff11d99d8
commit 949d73c141
5 files changed
+123 -1

No files matched your search

@@ -0,0 +1,4 @@
---
title: "Layout variants"
type: variants
---
+2
View File
@@ -13,9 +13,11 @@ disableKinds = ["taxonomy", "term", "RSS", "sitemap", "404"]
# avatar omitted intentionally so the demo showcases the initials fallback
# (the SVG circle uses the active palette's accent color)
colorTheme = "sakura" # try "bonsai" (default), "sakura", "sumi", "koi"
layout = "grid" # try "stack" (default), "grid", "inline"
themeToggle = true
jobTitle = "Software Engineer"
footerText = "© 2026 · made with bonsai"
# ogImageUrl = "/og.png" # optional 1200×630 image for social previews
[[params.links]]
title = "GitHub"
+7 -1
View File
@@ -2,6 +2,12 @@
{{- $tagline := site.Params.tagline -}}
{{- $bio := site.Params.bio -}}
{{- $links := site.Params.links -}}
{{- $layout := site.Params.layout | default "stack" -}}
{{- $validLayouts := slice "stack" "grid" "inline" -}}
{{- if not (in $validLayouts $layout) -}}
{{- warnf "bonsai: unknown params.layout %q (expected stack|grid|inline), falling back to 'stack'" $layout -}}
{{- $layout = "stack" -}}
{{- end -}}
<article class="bio">
{{ partial "avatar.html" . }}
@@ -17,7 +23,7 @@
{{- end }}
{{- if $links }}
<nav class="bio__links" aria-label="Links">
<nav class="bio__links bio__links--{{ $layout }}" aria-label="{{ i18n "nav_links_label" | default "Links" }}">
{{- range $links }}
{{- partial "link-button.html" . -}}
{{- end }}
@@ -0,0 +1,36 @@
{{ define "main" }}
<article style="text-align:center;">
<h1 style="font-family:var(--bonsai-font-display);">Layout variants</h1>
<p style="color:var(--bonsai-muted);max-width:32rem;margin:0 auto 2rem;">
Set <code>layout = "stack"</code> (default), <code>"grid"</code>, or <code>"inline"</code> in your <code>hugo.toml</code> <code>[params]</code> block.
</p>
</article>
{{- $sample := slice
(dict "title" "GitHub" "url" "#" "icon" "github")
(dict "title" "LinkedIn" "url" "#" "icon" "linkedin")
(dict "title" "Email" "url" "#" "icon" "mail")
(dict "title" "Mastodon" "url" "#" "icon" "mastodon")
-}}
{{- $variants := slice
(dict "name" "stack" "label" "Stack (default)" "desc" "Full-width vertical buttons. Best for ≤ 6 links.")
(dict "name" "grid" "label" "Grid" "desc" "Two-column responsive grid; collapses to one column under 480 px.")
(dict "name" "inline" "label" "Inline" "desc" "Icon-only horizontal row. Titles stay in DOM for screen readers.")
-}}
<div class="variants-gallery">
{{- range $variants }}
<section class="variants-gallery__card">
<h3 class="variants-gallery__name">{{ .label }}</h3>
<p class="variants-gallery__desc">{{ .desc }}</p>
<code class="variants-gallery__code">layout = "{{ .name }}"</code>
<nav class="bio__links bio__links--{{ .name }}" aria-label="{{ .label }} sample">
{{- range $sample }}
{{- partial "link-button.html" . -}}
{{- end }}
</nav>
</section>
{{- end }}
</div>
{{ end }}
+74
View File
@@ -221,6 +221,40 @@ body {
margin-top: 1.5rem;
}
/* === layout variants ===
* All variant rules scope under .bio__links--{name} to avoid CSS specificity
* collisions with the default .link rules (see v0.2 journal for the lesson).
*/
.bio__links--grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
@media (max-width: 480px) {
.bio__links--grid { grid-template-columns: 1fr; }
}
.bio__links--inline {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.bio__links--inline .link {
padding: .75rem;
gap: 0;
}
/* Visually hide the title in inline mode but keep it for screen readers. */
.bio__links--inline .link__title {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.link {
display: flex;
align-items: center;
@@ -376,6 +410,46 @@ body {
border-color: var(--bonsai-accent);
}
/* ============================================================
Variants gallery (exampleSite/variants/) — 3 sample bio cards
============================================================ */
.variants-gallery {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
max-width: 36rem;
margin: 2rem auto;
}
.variants-gallery__card {
background: var(--bonsai-surface);
border: 1px solid var(--bonsai-border);
border-radius: var(--bonsai-radius);
padding: 1.5rem;
}
.variants-gallery__name {
font-family: var(--bonsai-font-display);
font-size: 1.1rem;
margin: 0 0 .25rem;
color: var(--bonsai-text);
}
.variants-gallery__desc {
color: var(--bonsai-muted);
font-size: .85rem;
margin: 0 0 .5rem;
}
.variants-gallery__code {
display: inline-block;
margin-bottom: 1rem;
font-family: ui-monospace, monospace;
font-size: .75rem;
color: var(--bonsai-muted);
}
@media (prefers-reduced-motion: reduce) {
.link, .link:hover { transition: none; transform: none; }
}