Rodeo: https://rodeo.club/post/7365224645898760192
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
Rodeo: https://rodeo.club/post/7365224645898760192
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
Rodeo: https://rodeo.club/post/7364945270112481280
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
Ever wanted your Hugo site’s blog list to look like those beautiful Gatsby blogs—displaying 12 cards per page in a three-column grid, each card showing a featured image, tags (as links), an excerpt, author, read time, publish date, and last modified date? That’s exactly what I set out to do—here’s my practical walkthrough with code, tips, and gotchas!
Home page (index.html
):
Define a .blog-grid
container for your grid, and loop over paginated blog posts.
text{{ define "main" }}
<div class="container" role="main">
{{ $pages := where .Site.RegularPages "Draft" false }}
{{ $paginator := .Paginate (sort $pages "Lastmod" "desc") 12 }}
<div class="blog-grid">
{{ range $page := $paginator.Pages }}
<article class="blog-card">
<!-- Featured image -->
{{ with resources.Get (printf "images/%s" $page.Params.image) }}
{{ with .Resize (printf "%dx%d webp" .Width .Height) }}
<img src="{{ .RelPermalink }}" alt="{{ $page.Title }}" class="u-photo blog-card-image" style="width:100%;height:170px;object-fit:cover;">
{{ end }}
{{ end }}
<!-- Tag links (see below for correct “/tags/” path!) -->
{{ if $page.Params.tags }}
<div class="blog-card-tags">
{{ range $page.Params.tags }}
<a href="{{ (print "/tags/" (. | urlize) "/") | relLangURL }}" class="tag p-category">{{ . }}</a>
{{ end }}
</div>
{{ end }}
<!-- Title -->
<h2 class="blog-card-title">
<a href="{{ $page.Permalink }}">{{ $page.Title }}</a>
</h2>
<!-- Meta info (see section 4) -->
<div class="blog-card-meta">
{{ partial "post_meta.html" $page }}
</div>
<!-- Excerpt -->
<div class="blog-card-excerpt">
{{ if $page.Params.excerpt }}
{{ $page.Params.excerpt | plainify | truncate 80 }}
{{ else }}
{{ $page.Summary | plainify | truncate 80 }}
{{ end }}
</div>
<!-- Read more -->
<a href="{{ $page.Permalink }}" class="blog-card-readmore">Read more →</a>
</article>
{{ end }}
</div>
<!-- ...pagination, profile box, etc, as needed -->
</div>
{{ end }}
Add this CSS (as a file or inline):
css.blog-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2em;
}
@media (max-width: 900px) { .blog-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 600px) { .blog-grid { grid-template-columns: 1fr; } }
.blog-card {
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,.05);
border-radius: 10px;
padding: 1em;
color: #222;
display: flex;
flex-direction: column;
}
.blog-card-image img { object-fit: cover; width: 100%; height: 170px; border-radius: 8px 8px 0 0; }
.blog-card-tags a.tag { background: #f3f3f3; border-radius: 12px; font-size: 0.9em; margin-right: 0.4em; padding: 1px 0.8em; text-decoration: none; color: #555; }
.blog-card-title { font-size: 1.22em; margin: 0.2em 0 0.12em 0; }
.blog-card-excerpt { margin-bottom: auto; margin-top: 0.7em; }
.blog-card-readmore { color: #ff8300; font-weight: bold; text-decoration: none; }
/* Dark mode */
@media (prefers-color-scheme: dark), body.night-mode {
.blog-card { background: #1a1a1a; color: #f9f9f9; }
.blog-card-title a { color: #ffa134; }
.blog-card-tags a.tag { background: #292929; color: #ffa134; }
}
Centralize your meta display using a Hugo partial, e.g. post_meta.html
:
text<span class="post-meta">
<!-- Publish date -->
<time class="dt-published" datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">{{ .Date.Format "2006-01-02" }}</time>
{{ $lastmodstr := .Lastmod.Format "2006-01-02" }}
{{ $datestr := .Date.Format "2006-01-02" }}
{{ if ne $datestr $lastmodstr }}
| Last updated {{ $lastmodstr }}
{{ end }}
<!-- Reading time (auto, in minutes) -->
| <i class="fas fa-clock"></i> {{ .ReadingTime }} min
<!-- Author (from front matter or global config) -->
{{ if .Params.author }}
| <i class="fas fa-user"></i> <span class="p-author h-card">{{ .Params.author | safeHTML }}</span>
{{ else }}
| <i class="fas fa-user"></i> <span class="p-author h-card">{{ .Site.Params.author.name | safeHTML }}</span>
{{ end }}
</span>
And in your card:
text<div class="blog-card-meta">
{{ partial "post_meta.html" $page }}
</div>
author = "Your Name"
to the post’s front matter.[params.author] name = "Your Name"
in config.toml
..ReadingTime
as estimated minutes..row
/.col-
and use your own grid for full control.resources.Get
and .Resize
for images—no change needed from your original.post_meta.html
) and call it from both list and single templates.prefers-color-scheme
or a body class.content/blog/my-post.md
:
texttitle = "My Hugo Gatsby-Style Cards Example"
date = 2025-09-07T19:00:00+09:00
lastmod = 2025-09-08T09:00:00+09:00
tags = ["Japanese beat selling site", "AI music"]
author = "Genx"
excerpt = "How to build Gatsby-style card layouts in Hugo, step by step, including pitfalls and professional tweaks."
image = "sample-thumb.jpg"
config.toml
:
text[params.author]
name = "Genx"
By customizing your Hugo index.html
with a CSS Grid, improving card structure, using Hugo’s natural .ReadingTime
and partial-powered meta display, and being careful with tag URLs, you can perfectly mimic those modern Gatsby/Next.js blog UIs—in Hugo, your way!
These methods work for multilingual Hugo sites, are flexible with any base theme, and let you easily achieve that highly-polished card grid you see everywhere.
Joining the IndieWeb Webring is a great way to connect your personal Hugo site to the broader IndieWeb community. Here’s how to get started:
Add rel=”me” Links
In your Hugo site’s layouts (usually in the head partial template), add links to your existing verified social profiles with rel=”me”. For example:
<a href="https://github.com/yourusername" rel="me">GitHub</a> <a href="https://mastodon.social/@yourusername" rel="me">Mastodon</a>
Make sure your social profiles link back to your website as well (for bidirectional verification).
Sign In on the Webring Site
Click the “Sign in” button at https://xn--sr8hvo.ws/.
Enter your personal website URL. The service will look for your social rel=”me” links and use those to authenticate you through RelMeAuth.
Complete the authentication process by authorizing through your social profile (usually GitHub or Mastodon).
Once authenticated and added to the webring, you’ll be instructed (or allowed) to add navigation links to your website.
Edit your Hugo footer partial ( commonly layouts/partials/footer.html ).
Add the following HTML snippet for the navigation links:
<a href="https://xn--sr8hvo.ws/previous">←</a> An <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a> 🕸💍 <a href="https://xn--sr8hvo.ws/next">→</a>
This enables seamless navigation to the previous and next sites in the ring.
Optional Enhancements
That’s it.
You’re now part of a decentralized community-powered webring, using web standards and your own web identity.
Rodeo: https://rodeo.club/post/7364463023047536640
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
Rodeo: https://rodeo.club/post/7364103594993217536
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
If you want your Hugo-powered glossary (用語集) section to have its own navigation bar or layout while keeping your codebase lean, read on! Here’s what really matters, and the “aha!” moments you need to know.
Just put your glossary Markdown files under content/en/glossary/ and content/ja/glossary/.
You don’t need anything extra for Hugo to treat them as a unique section.
Directory example:
content/
en/
glossary/
apple.md
bitcoin.md
ja/
glossary/
apple.md
bitcoin.md
Want your glossary pages to have a custom menu? Just create:
layouts/partials/glossary/nav.html
Put your glossary-specific navigation HTML here.
This can be a glossary term list, an index, or whatever special menu you want.
Here’s a Hugo superpower: you can use a “base template” just for the glossary section (with its own nav, etc.) by making:
layouts/glossary/baseof.html
Example:
<!DOCTYPE html>
<html lang="{{ .Lang }}">
<head>
{{ partial "head.html" . }}
</head>
<body>
{{ partial "glossary/nav.html" . }}
{{ block "main" . }}{{ end }}
{{ partial "footer.html" . }}
</body>
</html>
This ensures every glossary page uses your specific glossary nav and layout!
At first, you might think you need to copy single.html into layouts/glossary/single.html to get the layout working.
But you often don’t!
As long as your glossary content files have the correct front matter, Hugo will use your layouts/glossary/baseof.html.
If your glossary .md files have
type = "post"
Hugo will never use your glossary layouts, even if you made layouts/glossary/baseof.html!
Solution:
For each .md file in your glossary folders:
That’s it! Once you do this, Hugo will apply your section-specific layouts and partials—no need to duplicate single.html or fight with conditionals.
layouts/
glossary/
baseof.html # Glossary exclusive base layout!
partials/
nav.html # General nav
glossary/
nav.html # Glossary-exclusive nav bar!
_default/
baseof.html # Fallback for other sections
Remember:
Controlling Hugo’s template application is about content organization and front matter—not copying template files or writing complex conditionals!
This workflow will keep your Hugo theme simple, DRY, and powerful.
No more struggling with broken layouts or unnecessary template duplication for your custom sections. Happy Hugo theming! 🎉
Rodeo: https://rodeo.club/post/7363750345530372096
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
Rodeo: https://rodeo.club/post/7363373034729598976
Follow me:
X: https://x.com/genxnotes
Bluesky: https://bsky.app/profile/genxnotes.com
Pixiv: https://www.pixiv.net/users/90286455
Subscribe: If you enjoy my art, please follow me for more updates!
1. Genx Beats & djfunnycat – Smooth – 01 Smooth
2. Genx Beats & djfunnycat – Smooth – 02 Spec
3. Genx Beats & djfunnycat – Smooth – 03 We Do This
4. Genx Beats & djfunnycat – Smooth – 04 Changing
5. Genx Beats & djfunnycat – Smooth – 05 Running
6. Genx Beats & djfunnycat – Smooth – 06 Black