Responsive desktop table + mobile stacked-cards competitor comparison.
Supports category headings, boolean check/cross/partial and text cell
values, row striping, highlighted column with gradient border, and a
CTA row. Per-cell zebra striping opts out on the highlighted column to
avoid ring paint-order conflicts.
Replaces block.html with a Preact component featuring smooth CSS grid
0fr→1fr height animation, icon rotation, and multi-paragraph answer
support via renderRich(). Single-open accordion with question/title and
answer/text field aliases for backward compatibility.
Hugo v0.161's css.TailwindCSS reads node_modules/.bin/tailwindcss and
expects either a symlink or a Node-shebang script. pnpm's default
isolated linker creates shell wrappers (#!/bin/sh with NODE_PATH
manipulation), which Hugo rejects with "binary tailwindcss is not a
Node.js script". With node-linker=hoisted, pnpm flattens node_modules
and creates plain symlinks for Node-shebang bins — same shape npm
produces, which Hugo handles via its symlink branch in resolveNodeBin
(common/hexec/exec.go).
- Add .npmrc with node-linker=hoisted to all 9 templates and test/
- Verified end-to-end: academic-cv builds cleanly against published
modules/blox with Hugo v0.161.1
- Kit root and modules/blox keep pnpm's isolated linker for monorepo
The shipped per-template GitHub Actions build workflow still pinned
Node 20 and fell back to Hugo 0.154.5 on missing config - both
incompatible with Hugo v0.161's css.TailwindCSS Node permission sandbox
(Node >= 22, npm @tailwindcss/cli required). Sites upgraded via
`hugoblox upgrade` (which only touches go.mod) hit this immediately.
- Bump NODE_VERSION 20 -> 22 in all 9 templates' .github/workflows/build.yml
- Bump fallback DEFAULT_VERSION 0.154.5 -> 0.161.0 to match the framework's
new module.hugoVersion.min
- Add a "Verify Tailwind CSS dependency" step that fails fast with an
actionable ::error message if @tailwindcss/cli is not resolvable,
replacing Hugo's cryptic "binary tailwindcss is not a Node.js script"
Steps block:
- Three layouts: vertical (stacked with connector line), horizontal
(side-by-side, connector above), timeline (alternating cards on centre
line)
- Three marker styles: number (decimal/padded/roman/alpha), icon, dot
- Layout-aware marker sizing - bare 40px icon for horizontal, tinted
circle for vertical/timeline
- Staggered IntersectionObserver entrance animation
- Code span rendering in step body text
- Added to startup-landing-page template as a horizontal how-it-works
section
Replace legacy static Go HTML logos block with a Preact component. Adds three
layouts (row, grid, marquee), three filter styles (grayscale/color/white),
and three sizes (sm/md/lg). Fixed-width slots normalise visual weight across
SVG aspect ratios; per-item `scale` compensates for viewBox whitespace and
per-item `style` allows individual colour exceptions. Add logos block to startup-landing-page template.
Hugo v0.161 dropped the standalone tailwindcss binary; @tailwindcss/cli
npm package is now the only accepted transformer, invoked via
`node --permission` (Node >= 22 required).
- Bump module.hugoVersion.min to 0.161.0 in modules/blox/hugo.yaml;
add comment explaining why security.node.permissions is left to
Hugo's built-in defaults
- Bump hugo_version / HUGO_VERSION / devcontainer image tag to 0.161.0
across all 9 templates (hugoblox.yaml, netlify.toml, devcontainer.json)
- Bump devcontainer base image Node 20 → 22 and default Hugo version
- Add scripts/check-template-deps.mjs to assert every template declares
tailwindcss + @tailwindcss/cli; wire as pnpm check:template-deps
- Harden CI: new audit-template-deps job gates all build jobs; add
`require.resolve('@tailwindcss/cli/package.json')` check after each
pnpm install to catch the exact "binary is not a Node.js script" failure
Wire .hbb-section to var(--hb-spacing-section) instead of hardcoded 6rem,
enabling hugoblox.layout.spacing (compact/comfortable/spacious) to take effect.
- Default to "spacious" (6rem) to preserve existing visual layouts
- Per-section override via design.spacing.padding still works (inline > class)
- Remove dead design.spacing frontmatter field from all templates
- Set correct layout.spacing token in each template's params.yaml
Closes#3314
- Use design.spacing.padding to remove top padding on biography section
with banner image (previously caused a large 96px gap above the banner)
- Add proper vertical spacing (mt-4) between bio text and Download Résumé button
- Implement design.show_status option in both biography and biography-3 blocks
(config was accepted but never checked — status emoji always rendered)
Removes x-transition:leave directives from portfolio cards so hidden items
exit the grid flow immediately. This fixes two visual glitches when clicking
filter buttons: "ghost" cards briefly appearing during the overlap of enter
and leave animations, and cards snapping from their original grid position
to the start after a delayed reflow.
Fixes#3309
site_head.html, jsonld/article.html, jsonld/qapage.html, and
jsonld/event.html hardcode `(.Resources.ByType "image").GetMatch
"*featured*"` to find featured images. This ignores custom filenames
set via `.Params.image.filename` in front matter, causing og:image
and JSON-LD image to fall back to the site icon.
Replace the hardcoded pattern with the `get_featured_image` partial
(already used by jsonld/webpage.html), which properly searches for:
1. Files matching `*featured*` in the page directory
2. Custom filename from `.Params.image.filename` in the page directory
3. Custom filename in `assets/media/` directory
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add `actions/configure-pages` step to all template build workflows and
pass the detected base_url to `hugo --baseURL`, so sites deployed to
subdirectory paths (e.g. user.github.io/repo-name/) generate correct
asset URLs. Also fix leading-slash relURL calls in slides layout that
would ignore the baseURL path component.
Replace manual format detection (printf "%T", MediaType.SubType whitelists,
duck-typing) with Hugo's new reflect.IsResource, reflect.IsImageResource, and
reflect.IsImageResourceProcessable functions across 19 template files.
Key changes:
- process_responsive_image: collapse 15-line format whitelist into single
reflect.IsImageResourceProcessable call
- Unify three-way SVG/processable/GIF branches into two-way $canProcess guard
- Remove duplicate GIF passthrough branches in single.html, events/page.html
- Add missing SVG guard in research-areas block (was calling .Fill unprotected)
- Replace nil checks with reflect.IsResource in get_cover_image/get_featured_image
Design decision: GIFs are intentionally excluded from processing despite Hugo
supporting it — processing strips animation frames, so we preserve user-optimized
animated GIFs by checking (IsImageResourceProcessable AND not GIF).
Move block-specific CSS from centralized assets/css/blox/ to co-located
style.css files within each block directory. The css.html partial now
auto-discovers style.css files from bundled and community blocks and
concatenates them into the Tailwind entry via resources.Concat, enabling
full @apply support while avoiding VFS path resolution issues.
Shared biography styles (avatar, ruby) are extracted to blox/shared/css/
and auto-included before per-block styles. Navbar CSS moves to
components/ as it's a framework-level concern. The separate community
CSS pipeline in site_head.html is removed — all block CSS now flows
through a single Tailwind entry point.
Replace site.LanguageCode → site.Language.Locale and
.Language.LanguageCode → .Language.Locale in module layouts,
and languageCode → locale in all template language configs.