Skip to content

feat(home): render social icon row from [[menu.social]] - #55

Merged
hakula139 merged 26 commits into
mainfrom
feat/profile-socials
May 10, 2026
Merged

feat(home): render social icon row from [[menu.social]]#55
hakula139 merged 26 commits into
mainfrom
feat/profile-socials

Conversation

@hakula139

@hakula139 hakula139 commented May 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Render an icon row under the home profile subtitle from [[menu.social]], mirroring the legacy LoveIt social-link row but driven by kiln's typed menu groups (no social.yml preset list, no shorthand syntax — themes treat the group as opaque MenuItem records).
  • Each entry becomes an <a> with an icon, aria-label and title from t(item.name) (so site authors can write either an i18n key or a literal label), and rel="me noopener noreferrer" target="_blank" when external = true. rel="me" follows the IndieAuth / verified-profile convention for outbound social links.
  • Icons resolve through a dispatcher macro (_partials/macros/icon.html) that accepts either a Font Awesome class string ("fab fa-github") or "svg:<slug>", inlining a theme-bundled SVG from _partials/icons/<slug>.svg. SVGs may originate from Simple Icons, project repositories (NeoDB ships fediverse.svg, MetaBrainz ships listenbrainz_logo_icon.svg), or hand-authored sources — the prefix names what the macro does, not the source.
  • Theme ships an initial registry: bilibili, douban, fediverse, github, linkedin, listenbrainz, mastodon, qq, steam, telegram, zhihu. The <title> and role="img" markers are stripped — the parent <a> carries the aria-label, so the SVG is aria-hidden. Bangumi is intentionally not bundled (no usable SVG available upstream that reduces to a clean monochrome glyph); sites that want it ship a hand-authored SVG at the same path.
  • Shared CSS sizing keeps the two icon sources interchangeable: <i> and inline <svg> children of .header-link / .header-mobile-link get a 1.25em footprint (the FA fa-fw equivalent), and .profile-social svg matches surrounding glyphs at 1em with fill=currentColor — so a row mixing FA and inline SVGs aligns and recolors uniformly.
  • Profile social row tightened: 4px gap, 32px container, 24px glyphs (was 12px / 36px / 18px) so the row reads as a single unit rather than scattered badges. Hover state matches the header-icon circular tinted background via a shared @utility icon-tap-hover (50% bg in light mode, 10% white in dark).
  • fa-brands-400.woff2 joins the head preload list. The brand face was loading lazily via all.min.css, leaving brand glyphs in fallback (visibly thinner) on first paint.
  • New .profile-socials / .profile-social Tailwind v4 utilities under the existing ── Profile ── block in home-card.css. Compiled style.css regenerated via pnpm build.
  • min_kiln_version bumps to 0.3.0-rc.1 — the kiln release that ships feat!: named menu groups + literal-friendly t() kiln#59. Merge gating: kiln must release 0.3.0-rc.1 before this PR merges.

Theme cleanup folded into this PR

Once the icon dispatcher landed, an audit pass surfaced unrelated CSS hygiene wins worth shipping in the same merge unit:

  • 404 page bug fix: bg-card-bg referenced a non-existent token (--color-cardbg-card); the back-to-home button silently rendered with no surface fill. The 404 panel also got asymmetric vertical padding (pt-16 pb-8 sm:pt-24 sm:pb-12) so it sits visually centered below the header instead of crowding it.
  • @utility fa-icon: extracted the Font Awesome 6 Free family + weight + shrink-0 setup repeated in three pseudo-element rules (.callout-title::before, the chevron pseudos in collapse.css, .toc-trigger::before).
  • glass-surface utility folds the border: the border: 1px solid var(--surface-glass-border) declaration paired with glass-surface in five places (.glass-panel, .header-mobile, .skip-link:focus, .OwO-body, .pf-modal). Coupling the border with the surface matches the same argument that justified glass-surface itself; consumers that don't want the border (.header-nav, .header-mobile) explicitly override.
  • Dead tokens dropped: --radius-sm, --shadow-sm, --shadow-lg had zero consumers in CSS or templates.
  • Convention nits: theme-transition block folded into @layer base; @variant dark nested inside .glass-glow rule (vs. sibling form); @apply ordering in .highlight reordered to match the rest of the codebase; comments.css unlayered status now has a rationale comment matching the precedent in prose.css and mermaid.css.
  • Docs: User-facing reference split out of README.md and CLAUDE.md into docs/{customization,parameters,i18n}.md (mirroring kiln's docs layout). Token tables refreshed to match the post-cleanup token set; CSS file tree updated to include the new components/shared/ directory.

Test plan

  • pnpm build (Tailwind v4 compile)
  • pnpm format
  • pnpm lint (markdownlint + ESLint)
  • pnpm spellcheck
  • Visual smoke on hakula.xyz-kiln: icon row appears centered under subtitle, hover transitions to the same circular tinted background as .header-icon / .header-link, keyboard tab order walks through links in weight order, aria-label matches resolved i18n strings (知乎, 豆瓣, ...), external links open in a new tab with rel="me noopener noreferrer", local QQ entry opens the embedded image.
  • Visual smoke for the dispatcher: every svg:<slug> entry inlines its SVG at the same visual weight / color as the FA glyphs alongside it; FA brand row paints solid on first load (no fallback flash).
  • 404 page: button surface fill renders correctly; panel sits with adequate breathing room above.

Pairs with hakula139/kiln#59.

Mirrors the legacy LoveIt social-link row, but driven by kiln's typed
menu groups (no `social.yml` preset, no shorthand syntax). The theme
treats `[[menu.social]]` entries as opaque MenuItem records: each one
becomes an `<a>` with an icon, accessible label from `t(item.name)`,
and `rel="me noopener noreferrer" target="_blank"` when external.

`rel="me"` follows the IndieAuth / verified-profile microformats
convention for outbound social links.

`min_kiln_version` bumps to `0.3.0-rc.1` (the kiln release that ships
named menu groups + literal-friendly `t()`).
@hakula139
hakula139 force-pushed the feat/profile-socials branch from ec4bb24 to aeac853 Compare May 9, 2026 15:46
Brand glyphs (fab fa-*) live in fa-brands-400.woff2, which the preload
list was missing. The font still loaded via @font-face in all.min.css,
but only after stylesheet parse, leaving brand icons in fallback (or
visibly thinner) on first paint. Adding the preload puts brands on the
same critical path as solid and regular faces.
@hakula139
hakula139 force-pushed the feat/profile-socials branch 4 times, most recently from 0de01ae to 7589369 Compare May 10, 2026 07:40
hakula139 added 2 commits May 10, 2026 16:52
… SVGs

The icon string in [[menu.*]] entries used to be a Font Awesome class
string rendered inline as <i class="...">. The dispatcher accepts a
second form, "svg:<slug>", which inlines a theme-bundled SVG from
_partials/icons/<slug>.svg. SVGs may originate from Simple Icons
(brand-only set, used for most entries here), other project
repositories (NeoDB ships fediverse.svg, MetaBrainz ships
listenbrainz_logo_icon.svg), or hand-authored sources. Falls back to
the existing FA path for everything else, so existing fab/fas/far
configs keep working.

A shared CSS rule sizes both <i> and inline <svg> children of
.header-link / .header-mobile-link to the fa-fw 1.25em footprint, and
.profile-social svg matches the surrounding glyph at 1em with
fill=currentColor — so a row mixing FA and inline SVGs aligns and
recolors uniformly.
Default Tailwind defaults left the row visually loose: 12px x-gap, 18px
glyphs, 36px-wide centering boxes. Drops the gap to 4px, shrinks the
container to 32px, and bumps glyphs to 24px so the row matches the
visual weight of a typical social-icon strip rather than scattering
into separate badges.
@hakula139
hakula139 force-pushed the feat/profile-socials branch from 7589369 to 4a7a885 Compare May 10, 2026 08:53
hakula139 added 4 commits May 10, 2026 17:06
Use :is(i, svg) to consolidate the menu-icon selector across header-link
and header-mobile-link, switch align-[-0.125em] to align-middle (FA's
literal magic number was tuned for FA font metrics; align-middle keys
off x-height and is robust to font-size changes), and replace
h-[1em] w-[1em] on .profile-social svg with the v4 size-[1em] shorthand.

No visual change to FA-only menu rows. Inline SVG glyphs sit fractionally
lower against the text baseline in the menu, matching x-height middle
rather than FA's pre-rendered offset.
The bundled icon registry is now upstream-only: Simple Icons brands
(bilibili, douban, github, linkedin, mastodon, qq, steam, telegram,
zhihu) plus two project-repo SVGs (fediverse from neodb-social/neodb,
listenbrainz from MetaBrainz). Bangumi was the only hand-authored
glyph and is fundamentally site-flavor — sites that link to Bangumi
profiles should ship their own SVG under templates/_partials/icons/
and reference it as svg:bangumi (the dispatcher resolves through the
site's template directory before falling back to the theme).

Sites consuming this commit must add a bangumi.svg locally if their
[[menu.social]] previously relied on the theme-bundled one.
…urfaces

Three call sites now share one source of truth for the tappable icon
hover treatment (background tint, link color, dark-mode swap):
.header-link, .header-icon, and .profile-social. The matching surface
also lands on .profile-social for the first time, fixing a regression
against the legacy site row where each icon got an individual roundel
on hover.

Header desktop nav and icon buttons collapse the 95% duplicate base
into a comma-listed shared rule with per-variant deltas (border-b-0
to kill anchor underline; cursor-pointer because <button> doesn't
inherit it). All CSS-tokens live in a new _src/components/shared/
directory imported once near the top of main.css.
Add a docs/ directory mirroring kiln's audience-organized layout:
docs/customization.md (how-to guide for visual tokens, template
overrides, social icons, comments providers, fonts, static assets),
docs/parameters.md ([params] schema reference with defaults and
rendering context), and docs/i18n.md (translatable-key reference
with override pattern).

README sheds the verbose per-section [params] examples in favor of
a single Quick Start config and a Documentation table linking to
docs/. The detailed examples for [params.background], [params.comments],
[params.footer], etc. now live exclusively in docs/parameters.md.

CLAUDE.md trims three sections that were duplicating user-facing
material: the design-token namespace list (now points at customization.md),
the i18n override-pattern paragraph (now points at i18n.md), and the
body-background user config (now points at parameters.md). The file
stays contributor-focused — file-tree map, build pipeline, SRI flow,
coding conventions — with a top-of-file pointer making the divide
explicit.

The svg:<slug> icon dispatcher (added in this branch's earlier
commits) is documented in docs/customization.md with the bundled
registry table and the site-override pattern.

cspell dictionary picks up bangumi, bilibili, fediverse, listenbrainz,
metabrainz, and neodb to cover docs/customization.md examples.
@hakula139 hakula139 added the documentation Improvements or additions to documentation label May 10, 2026
hakula139 added 12 commits May 10, 2026 17:50
The token is --color-card, so the Tailwind utility is bg-card; bg-card-bg
silently no-ops, leaving the back-to-home button without its surface fill.
Every other rule in the codebase puts @apply first, then raw
declarations; .highlight was the lone outlier.
Sibling-rule form duplicated the :where() selector and contradicted
the nested-inside convention used in apple-music.css and icon-button.css.
Bump top padding so the panel sits visually centered below the header
instead of crowding it; modest extra below to balance.
Matches the rationale comment convention established by prose.css and
mermaid.css for intentional layer bypasses.
Trailing-! important keeps it winning during the toggle window, so the
out-of-layer placement was unnecessary; co-locating with the other
prefers-reduced-motion: no-preference rule keeps related concerns together.
--radius-sm, --shadow-sm, and --shadow-lg have no consumers in CSS or
templates; their auto-generated rounded-sm / shadow-sm / shadow-lg
utilities aren't used anywhere either.
Three sites (callout-title, code/callout/toc chevrons, toc list icon)
all repeated the same shrink-0 + Font Awesome family + weight setup
before applying their content / size deltas. Folding into a shared
utility couples the family + weight (which must agree) and lets each
site keep its own content / sizing as the natural seam.
The border:1px var(--surface-glass-border) declaration was paired with
glass-surface in five places (.glass-panel, .header-mobile, .skip-link
focus, .OwO-body, .pf-modal). Coupling the border with the surface
matches the same argument that justified glass-surface itself.

.header-mobile keeps its bottom-only border via border-x-0 border-t-0;
.header-nav was already overriding via border-0 border-b. The Pagefind
modal keeps its !important border-color override since raw declarations
inside @Utility blocks don't inherit the @apply ! modifier.
Replaces the raw border-color !important declaration with the equivalent
border-(color:--surface-glass-border)! utility, keeping all overrides in
the @apply chain.
The free-floating comment under the section divider read as orphaned;
moving it next to .apple-music-light makes its scope explicit.
hakula139 added 6 commits May 10, 2026 18:02
glass-surface! now propagates !important to its border-color raw
declaration, so the explicit border-(color:...)! addition added zero
new information.
The token table in docs/customization.md still listed --radius-sm and
left shadow scales unenumerated; refresh to match the post-cleanup set
(radii: md/lg/xl/card; shadows: md/card + drop-shadow-text).

CLAUDE.md's CSS file tree was missing components/shared/, which now
holds fa-icon.css and icon-button.css.
The previous attempt bumped the wrapper padding, which pushed the whole
panel down. The right shape is to keep the panel anchored near the top
(y-6 like other layouts) and bump the panel's *inner* padding so the
404 content sits visually centered within the surface.

The back-home link also dropped its filled bg-card surface and now
matches the icon-button language used by .header-link / .profile-social
(transparent until hover, where it picks up the shared icon-tap-hover
tinted background).
The previous attempt bumped wrapper padding, pushing the whole panel
down. Right shape is to keep the panel anchored near top (py-6 like
other layouts) and bump the panel's *inner* padding so the 404 content
sits visually centered within the surface.

The back-home link drops its filled bg-card surface and now matches the
icon-button language used by .header-link / .profile-social — extracted
as .back-home-link in a new layout/error-page.css since the chain
exceeded the inline-utility threshold.
Previously h-8 w-8 with text-2xl gave a 24/32 = 75% icon-to-container
ratio, leaving only 4px around the glyph and the hover circle barely
visible. Switch to aspect-square + p-2 (matching the .header-link
idiom) so the container scales with the icon and the tinted hover area
reads as a deliberate surface. Bump gap from 1 to 2 for the same
reason — buttons no longer touch.
@hakula139
hakula139 merged commit c9465da into main May 10, 2026
1 check passed
@hakula139
hakula139 deleted the feat/profile-socials branch May 10, 2026 10:38
hakula139 added a commit to hakula139/hakula.xyz-kiln that referenced this pull request May 10, 2026
## Summary

- Port the legacy hakula.xyz social-link row to kiln. 12
`[[menu.social]]` entries with `weight` ordering, surfacing
higher-priority contact channels (QQ, Telegram, email) above passive
discovery links (GitHub, LinkedIn, Bilibili, Bangumi, Zhihu, NeoDB,
Steam, ListenBrainz) and trailing the row with RSS.
- `i18n/zh-Hans.toml` adds the `menu_social_*` block. Labels resolve via
`t(item.name)` in IgnIt's home template, so `aria-label` / `title`
render in zh-Hans (`知乎`, `豆瓣`, `邮箱`, ...).
- QQ icon points at `/images/social/qq.webp` (the QR-code image, copied
over from the legacy site at `static/images/social/qq.webp`); other
external entries open in a new tab via the theme's `rel="me noopener
noreferrer"` handling.
- Email omits `external = true` so `mailto:` stays in the same tab.
- All brand entries use IgnIt's `svg:<slug>` dispatcher to inline a
theme-bundled SVG (Simple Icons for most; NeoDB renders the `fediverse`
glyph since the official NeoDB logo doesn't reduce cleanly to
monochrome). Non-brand entries (Email = `fas fa-envelope`, RSS = `fas
fa-rss`) stay on Font Awesome — they're protocols, not brands.
- **Bangumi icon owned by the site**: the theme intentionally doesn't
bundle a bangumi glyph (no usable upstream SVG that reduces to a clean
monochrome silhouette). This site ships a hand-authored
`templates/_partials/icons/bangumi.svg` (a stylized retro TV) which
IgnIt's icon dispatcher resolves through kiln's path loader (site
shadows theme). Sites that want bangumi own their own glyph; sites that
don't reference `svg:bangumi` are unaffected.
- IgnIt submodule bumped to the icon-dispatcher tip from
hakula139/IgnIt#55, including the theme-side cleanup folded into that PR
(404 fix, `glass-surface` border fold, `@utility fa-icon`, dead-token
cleanup, doc split).
- `cspell` dictionary picks up `bangumi`, `bilibili`, `fediverse`,
`listenbrainz`, `metabrainz`, `neodb`.
- `CLAUDE.md` documents the `templates/_partials/icons/<slug>.svg`
site-side override path so future contributors know where to land new
bundled glyphs.

## Test plan

- [x] `kiln build` succeeds against the bumped IgnIt submodule
- [x] `pnpm build` (regenerated `static/css/style.css` to pick up the
theme's new `@utility icon-tap-hover` and `@utility fa-icon`
definitions)
- [x] `pnpm format`, `pnpm lint`, `pnpm spellcheck` clean
- [x] Visual smoke: home page shows the social icon row in `weight`
order; tooltips and `aria-label`s resolve to the zh-Hans labels;
external links open in a new tab with `rel="me noopener noreferrer"`; QQ
link opens the QR image; mailto link opens in the same tab; bangumi
renders the site-bundled SVG; brand glyphs render at the same visual
weight as the FA placeholders alongside them; hover state matches
`.header-icon` circular tinted background.

Pairs with hakula139/IgnIt#55 and hakula139/kiln#59.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant