feat: add responsive image support#1283
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
hugo-theme-stack | 6b37520 | Commit Preview URL Branch Preview URL |
Mar 04 2026, 10:05 PM |
…w partial and configure image processing widths.
…zes` attributes for improved display.
There was a problem hiding this comment.
Pull request overview
This PR introduces two new reusable Hugo partial helpers — helper/responsive-image (for width-based srcset) and helper/thumbnail-image (for 1x/2x DPR-based srcset) — and wires them up across article header, article list tiles, compact article lists, and the Markdown image render hook. It also restructures the imageProcessing config to add a new thumbnail sub-section (and removes the old cover sub-section), removes hard-coded width/height CSS from tile article containers, and fixes the tile article to use the correct 150px height value.
Changes:
- Two new image helper partials (
helper/responsive-imageandhelper/thumbnail-image) that generate<img>elements withsrcsetfor responsive images - Existing templates (
render-image.html,header.html,tile.html,compact.html) migrated to use the new helpers config/_default/params.tomlrestructured to addimageProcessing.thumbnailsub-section (removingimageProcessing.cover) and addwidthstoimageProcessing.content
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
layouts/_partials/helper/responsive-image.html |
New helper: generates <img> with width-descriptor srcset |
layouts/_partials/helper/thumbnail-image.html |
New helper: generates <img> with 1x/2x pixel-density srcset |
layouts/_partials/article/components/header.html |
Uses responsive-image for article header image |
layouts/_partials/article-list/tile.html |
Uses thumbnail-image for tile list article images |
layouts/_partials/article-list/compact.html |
Uses thumbnail-image for compact list article images |
layouts/_markup/render-image.html |
Uses responsive-image for Markdown-rendered images |
config/_default/params.toml |
Adds imageProcessing.thumbnail section, content.widths, removes cover |
assets/scss/partials/article.scss |
Corrects tile article height from 350px to 150px |
assets/scss/partials/layout/article.scss |
Removes hard-coded width/height from related-content article |
assets/scss/partials/layout/list.scss |
Removes hard-coded width/height from subsection tile article |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "Attributes" (merge $attributes (dict | ||
| "src" $image.Permalink | ||
| "width" $image.Width | ||
| "height" $image.Height | ||
| "alt" $alt | ||
| "title" $title | ||
| "class" (cond $galleryImage "gallery-image" "") | ||
| "loading" "lazy" | ||
| "sizes" "(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" | ||
| )) |
There was a problem hiding this comment.
The data-title-escaped attribute is no longer rendered on gallery images in the new responsive-image helper, but gallery.ts still reads this attribute (lines 77–78) to populate figcaptions via innerHTML. Without it, the gallery caption falls back to the alt attribute text instead of the (possibly markdown-formatted) image title.
In the old code, the data-title-escaped attribute held the HTML-entity-escaped version of the markdownified title, which was required for safe assignment to innerHTML in JS. Now that neither data-title-escaped nor any equivalent attribute is emitted, any image with a title in Markdown (e.g. ) will silently lose its gallery caption.
The fix would be to include a "data-title-escaped" key in the attributes dict passed to responsive-image, set to the HTML-escaped form of $title when $title is non-empty.
| {{- $resource := .Resource -}} | ||
| {{- $width := .Width -}} | ||
| {{- $height := .Height -}} | ||
| {{- $resize := .Resize | default true -}} |
There was a problem hiding this comment.
In thumbnail-image.html, the Resize parameter is defaulted using | default true. In Hugo's template engine, default treats any falsy value (including the boolean false) as "missing" and substitutes the default. This means that when a caller explicitly passes "Resize" false (e.g. when imageProcessing.thumbnail.enabled = false in the config), the condition will still evaluate to true, making image processing run unconditionally regardless of the user's configuration.
The correct pattern used elsewhere in this codebase (e.g. mermaid.html line 30) is (not (eq (.Resize | default true) false)), or more directly, to check for nil explicitly (e.g., {{ $resize := .Resize }}{{ if eq $resize nil }}{{ $resize = true }}{{ end }}).
| {{- $resize := .Resize | default true -}} | |
| {{- $resize := .Resize -}} | |
| {{- if eq $resize nil }}{{ $resize = true }}{{ end -}} |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…size is not enabled
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {{- end -}} | ||
|
|
||
| {{- if gt (len $srcset) 0 -}} | ||
| {{- $permalink := default $resource.RelPermalink (index $attributes "src") -}} |
There was a problem hiding this comment.
The srcset entries from resized images use RelPermalink (relative paths), but the final "full resolution" entry at line 24 uses $permalink, which comes from (index $attributes "src"). When the caller passes an absolute URL as src (e.g., for a remote image), this results in a srcset that mixes relative paths for the resized variants with an absolute URL for the full-resolution entry. While modern browsers can handle this, the inconsistency can cause unexpected behavior. The $permalink could be normalized to $resource.RelPermalink when the resource exists and has been processed from a remote URL (i.e., the locally cached version's relative path), or at least kept consistent in type with the other entries.
| {{- $permalink := default $resource.RelPermalink (index $attributes "src") -}} | |
| {{- $permalink := $resource.RelPermalink -}} |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This reverts commit 22edce9.
No description provided.