From 22edce91ab046abdd91f3b72031d0c07a04b1292 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 4 Mar 2026 23:32:33 +0100 Subject: [PATCH] feat: add responsive image support (#1283) * feat: create responsive-image helper * feat: new responsive-image helper * feat: Implement responsive image rendering in page content using a new partial and configure image processing widths. * feat: add `sizes` attribute for enhanced image responsiveness * feat: add responsive image to page header too * Check for `.Enabled` before processing image * style: remove wrong article-list--tile width and height * feat: add `helper/thumbnail-image` for responsive thumbnails * feat: enable content image processing and update responsive image `sizes` attributes for improved display. * fix: get src from the attributes so external image can work correctly * fix: add missing data-title-escaped * Update layouts/_partials/article/components/header.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: remove default `true` for thumbnail resize parameter. * Update layouts/_markup/render-image.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update layouts/_partials/helper/thumbnail-image.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * add original width and height to thumbnail pictures, for case that resize is not enabled * Update layouts/_partials/helper/thumbnail-image.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- assets/scss/partials/article.scss | 2 +- assets/scss/partials/layout/article.scss | 2 - assets/scss/partials/layout/list.scss | 2 - config/_default/params.toml | 10 +++-- layouts/_markup/render-image.html | 42 +++++++++++-------- layouts/_partials/article-list/compact.html | 15 ++++++- layouts/_partials/article-list/tile.html | 15 ++++++- .../_partials/article/components/header.html | 14 ++++++- .../_partials/helper/responsive-image.html | 33 +++++++++++++++ layouts/_partials/helper/thumbnail-image.html | 41 ++++++++++++++++++ 10 files changed, 143 insertions(+), 33 deletions(-) create mode 100644 layouts/_partials/helper/responsive-image.html create mode 100644 layouts/_partials/helper/thumbnail-image.html diff --git a/assets/scss/partials/article.scss b/assets/scss/partials/article.scss index 94c0177..2388ba8 100644 --- a/assets/scss/partials/article.scss +++ b/assets/scss/partials/article.scss @@ -207,8 +207,8 @@ border-radius: var(--card-border-radius); overflow: hidden; position: relative; - height: 350px; width: 250px; + height: 150px; box-shadow: var(--shadow-l1); transition: box-shadow 0.3s ease; background-color: var(--card-background); diff --git a/assets/scss/partials/layout/article.scss b/assets/scss/partials/layout/article.scss index b214a10..af038ad 100644 --- a/assets/scss/partials/layout/article.scss +++ b/assets/scss/partials/layout/article.scss @@ -242,8 +242,6 @@ margin-right: 15px; flex-shrink: 0; overflow: hidden; - width: 250px; - height: 150px; .article-title { font-size: 1.8rem; diff --git a/assets/scss/partials/layout/list.scss b/assets/scss/partials/layout/list.scss index b97e1d2..b29f230 100644 --- a/assets/scss/partials/layout/list.scss +++ b/assets/scss/partials/layout/list.scss @@ -56,8 +56,6 @@ width: max-content; article { - width: 250px; - height: 150px; margin-right: 20px; flex-shrink: 0; diff --git a/config/_default/params.toml b/config/_default/params.toml index 2583f61..f1baee3 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -75,11 +75,13 @@ SortBy = "default" toggle = true default = "auto" -[imageProcessing.cover] - enabled = true +[imageProcessing] + [imageProcessing.content] + widths = [800, 1600, 2400] + enabled = true -[imageProcessing.content] - enabled = true + [imageProcessing.thumbnail] + enabled = true # GDPR Cookie Consent Configuration # When enabled, analytics and functional cookies require user consent diff --git a/layouts/_markup/render-image.html b/layouts/_markup/render-image.html index f15d292..2d0ebc9 100644 --- a/layouts/_markup/render-image.html +++ b/layouts/_markup/render-image.html @@ -2,23 +2,29 @@ {{- $alt := .PlainText | safeHTML -}} {{- $title := .Title | markdownify -}} -{{/* SVG and external images won't work with gallery layout, because their width and height attributes are unknown */}} +{{/* There are some types of images that don't have width and height attributes, such as SVG */}} {{- $galleryImage := and $image.Height $image.Width -}} -{{ . }} \ No newline at end of file +{{- $attributes := dict -}} +{{- if $galleryImage -}} + {{- $attributes = (dict + "data-flex-grow" (div (mul $image.Width 100) $image.Height) + "data-flex-basis" (printf "%dpx" (div (mul $image.Width 240) $image.Height)) + ) -}} +{{- end -}} + +{{ partial "helper/responsive-image" (dict + "Resource" $image.Resource + "Widths" (cond .Page.Site.Params.ImageProcessing.Content.Enabled .Page.Site.Params.ImageProcessing.Content.Widths nil) + "Attributes" (merge $attributes (dict + "src" $image.Permalink + "width" $image.Width + "height" $image.Height + "alt" $alt + "title" $title + "data-title-escaped" ($title | htmlEscape) + "class" (cond $galleryImage "gallery-image" "") + "loading" "lazy" + "sizes" "(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" + )) +) }} \ No newline at end of file diff --git a/layouts/_partials/article-list/compact.html b/layouts/_partials/article-list/compact.html index 7a4185c..f110e90 100644 --- a/layouts/_partials/article-list/compact.html +++ b/layouts/_partials/article-list/compact.html @@ -14,8 +14,19 @@ {{- $image := partial "helper/image" (dict "Image" .Params.image "Resources" .Resources) -}} {{ if $image }}
- {{ .Title }} + {{ partial "helper/thumbnail-image" (dict + "Resource" $image.Resource + "Width" 60 + "Height" 60 + "Resize" .Site.Params.ImageProcessing.Thumbnail.Enabled + "Attributes" (dict + "src" $image.Permalink + "alt" .Title + "loading" "lazy" + "width" $image.Width + "height" $image.Height + ) + ) }}
{{ end }} diff --git a/layouts/_partials/article-list/tile.html b/layouts/_partials/article-list/tile.html index 3c819b2..0b367af 100644 --- a/layouts/_partials/article-list/tile.html +++ b/layouts/_partials/article-list/tile.html @@ -3,8 +3,19 @@ {{ if $image }}
- Featured image of post {{ .context.Title }} + {{ partial "helper/thumbnail-image" (dict + "Resource" $image.Resource + "Width" 250 + "Height" 150 + "Resize" .context.Site.Params.ImageProcessing.Thumbnail.Enabled + "Attributes" (dict + "src" $image.Permalink + "alt" (printf "Featured image of post %s" .context.Title) + "loading" "lazy" + "width" $image.Width + "height" $image.Height + ) + ) }}
{{ end }} diff --git a/layouts/_partials/article/components/header.html b/layouts/_partials/article/components/header.html index 301aa37..8c04d72 100644 --- a/layouts/_partials/article/components/header.html +++ b/layouts/_partials/article/components/header.html @@ -5,8 +5,18 @@ {{ if $image }}
- Featured image of post {{ $Page.Title }} + {{ partial "helper/responsive-image" (dict + "Resource" $image.Resource + "Widths" (cond $Page.Site.Params.ImageProcessing.Content.Enabled $Page.Site.Params.ImageProcessing.Content.Widths nil) + "Attributes" (dict + "src" $image.Permalink + "width" $image.Width + "height" $image.Height + "alt" (printf "Featured image of post %s" $Page.Title) + "loading" "lazy" + "sizes" "(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" + ) + ) }}
{{ end }} diff --git a/layouts/_partials/helper/responsive-image.html b/layouts/_partials/helper/responsive-image.html new file mode 100644 index 0000000..63cc2de --- /dev/null +++ b/layouts/_partials/helper/responsive-image.html @@ -0,0 +1,33 @@ +{{- /* +Params: + Resource: Hugo image resource object (Optional, for processing) + Widths: Slice of widths to generate for srcset + Attributes: Map of HTML attributes for the tag +*/ -}} + +{{- $resource := .Resource -}} +{{- $widths := .Widths -}} +{{- $attributes := .Attributes | default dict -}} + +{{/* Generate srcset if Resource and Widths are provided */}} +{{- if and $widths $resource (reflect.IsImageResourceProcessable $resource) -}} + {{- $srcset := slice -}} + {{- range $widths -}} + {{- if lt . $resource.Width -}} + {{- $resized := $resource.Resize (printf "%dx" .) -}} + {{- $srcset = $srcset | append (printf "%s %dw" $resized.RelPermalink .) -}} + {{- end -}} + {{- end -}} + + {{- if gt (len $srcset) 0 -}} + {{- $permalink := default $resource.RelPermalink (index $attributes "src") -}} + {{- $srcset = $srcset | append (printf "%s %dw" $permalink $resource.Width) -}} + {{- $attributes = merge $attributes (dict "srcset" (delimit $srcset ", ")) -}} + {{- end -}} +{{- end -}} + + \ No newline at end of file diff --git a/layouts/_partials/helper/thumbnail-image.html b/layouts/_partials/helper/thumbnail-image.html new file mode 100644 index 0000000..442371b --- /dev/null +++ b/layouts/_partials/helper/thumbnail-image.html @@ -0,0 +1,41 @@ +{{- /* +Params: + Resource: Hugo image resource object (Optional, for processing) + Width: Image width (Required) + Height: Image height (Required) + Resize: Whether to perform resize (Optional, default: false) + Attributes: Map of HTML attributes for the tag +*/ -}} + +{{- $resource := .Resource -}} +{{- $width := .Width -}} +{{- $height := .Height -}} +{{- $resize := .Resize -}} +{{- $attributes := .Attributes | default dict -}} + +{{- if and $resize $resource (reflect.IsImageResourceProcessable $resource) $width $height -}} + {{/* Create thumbnail with 1x/2x descriptors */}} + {{- $srcset := slice -}} + {{- range (slice 1 2) -}} + {{- $w := mul $width . -}} + {{- $h := mul $height . -}} + {{- if and (le $w $resource.Width) (le $h $resource.Height) -}} + {{- $resized := $resource.Fill (printf "%dx%d" $w $h) -}} + {{- $srcset = $srcset | append (printf "%s %dx" $resized.RelPermalink .) -}} + + {{- if eq . 1 -}} + {{- $attributes = merge $attributes (dict "src" $resized.RelPermalink) -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if gt (len $srcset) 0 -}} + {{- $attributes = merge $attributes (dict "width" $width "height" $height "srcset" (delimit $srcset ", ")) -}} + {{- end -}} +{{- end -}} + +