diff --git a/layouts/_default/_markup/render-image.html b/layouts/_default/_markup/render-image.html
index a9c07b1..5eb6d57 100644
--- a/layouts/_default/_markup/render-image.html
+++ b/layouts/_default/_markup/render-image.html
@@ -104,14 +104,14 @@
{{- /* Get image resource. */}}
{{- $r := "" }}
{{- if $u.IsAbs }}
- {{- with resources.GetRemote $u.String }}
+ {{- with try (resources.GetRemote $u.String) }}
{{- with .Err }}
{{- if eq $errorLevel "warning" }}
- {{- warnf "%s. See %s" . $contentPath }}
+ {{- warnf "%s. See %s" .Err $contentPath }}
{{- else if eq $errorLevel "error" }}
- {{- errorf "%s. See %s" . $contentPath }}
+ {{- errorf "%s. See %s" .Err $contentPath }}
{{- end }}
- {{- else }}
+ {{- else with .Value }}
{{- /* Destination is a remote resource. */}}
{{- $r = . }}
{{- end }}
diff --git a/layouts/partials/figure.html b/layouts/partials/figure.html
index 53c79f7..21c77bc 100644
--- a/layouts/partials/figure.html
+++ b/layouts/partials/figure.html
@@ -1,289 +1,289 @@
-{{- /* Based on https://www.veriphor.com/articles/link-and-image-render-hooks/#image-render-hook */}}
-
-{{- /* Last modified: 2023-09-05T11:48:34-07:00 */}}
-
-{{- /*
-Copyright 2023 Veriphor LLC
-
-Licensed under the Apache License, Version 2.0 (the "License"); you may not
-use this file except in compliance with the License. You may obtain a copy of
-the License at
-
-https://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-License for the specific language governing permissions and limitations under
-the License.
-*/}}
-
-{{- /*
-Renders an HTML figure element, in multiple formats and sizes.
-
-It resolves internal destinations by looking for a matching:
-
- 1. Page resource (an image in the current page bundle)
- 2. Section resource (an image in the current section)
- 3. Global resource (an image in the assets directory)
-
-It skips the section resource lookup if the current page is a leaf bundle, and
-captures external destinations as resources for local hosting. The build will
-fail if this partial is unable to resolve a destination.
-
-You must place global resources in the assets directory. If you have placed
-your resources in the static directory, and you are unable or unwilling to move
-them, you must mount the static directory to the assets directory by including
-both of these entries in your site configuration:
-
- [[module.mounts]]
- source = 'assets'
- target = 'assets'
-
- [[module.mounts]]
- source = 'static'
- target = 'assets'
-
-Add this CSS to your site to enable responsive image behavior:
-
- img {
- height: auto;
- max-width: 100%;
- }
-
-Add this CSS to your site to remove small gaps between adjacent elements:
-
- img, picture {
- font-size: 0;
- }
-
-@context {page} [page] The current page.
-@context {string} [src] The path to the base image: a page resource, a global resource, or a remote resource.
-@contect {int} [width] The display width of the image, in pixels, falling back to 100% of the viewport width.
-@context {string} [sizes] = "" # "100vw", "75vw", or "auto" for example
-@context {string slice} [formats] A slice of image formats, ordered by precedence, to use when creating images for the srcset attribute of each source element.
-@context {string} [process] = "" # "fill 1600x900" for example
-@context {string} [lqip] = "" # "16x webp q20" or "21x webp q20" for example
-@context {string} [decoding] The img element's decoding attribute.
-@context {string} [fetchpriority] The img element's fetchpriority attribute.
-@context {string} [loading] The img element's loading attribute.
-@context {string} [alt] The img element's alt attribute.
-@context {string} [title] The img element's title attribute.
-@context {string} [caption] The figure element's caption attribute.
-@context {string} [class] The img element's class attribute.
-
-@returns {template.HTML}
-
-@example (required args only)
-
- {{- partial "figure.html" (dict "page" . "src" "images/zion.jpg") }}
-
-@example (all args)
- {{- $opts := dict
- "page" .
- "src" "images/bryce-canyon-national-park.jpg"
- "width" 768
- "sizes" "auto"
- "formats" (slice "webp" "jpeg")
- "process" "fill 1600x900"
- "lqip" "16x webp q20"
- "decoding" "async"
- "fetchpriority" "auto"
- "loading" "eager"
- "alt" "Bryce Canyon National Park"
- "title" "A beautiful day in Bryce Canyon National Park"
- "caption" "Bryce Canyon National Park"
- "class" "foo"
- }}
- {{- partial "figure.html" $opts }}
-
-*/}}
-
-{{- /* Initialize. */}}
-{{- $partialName := "figure" }}
-
-{{- /* Verify minimum required version. */}}
-{{- $minHugoVersion := "0.118.0" }}
-{{- if lt hugo.Version $minHugoVersion }}
- {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }}
-{{- end }}
-
-{{- /* Validate page arg. */}}
-{{- if not .page }}
- {{- errorf "The %q partial requires a page argument." $partialName }}
-{{- end }}
-
-{{- /* Determine content path for warning and error messages. */}}
-{{- $contentPath := "" }}
-{{- with .page.File }}
- {{- $contentPath = .Path }}
-{{- else }}
- {{- $contentPath = .Path }}
-{{- end }}
-
-{{- /* Set defaults and get args. */}}
-{{- $alt := or .alt "" }}
-{{- $class := or .class "" }}
-{{- $formats := or .formats (slice "webp") }}
-{{- $decoding := or .decoding site.Params.thulite_images.defaults.decoding }}
-{{- $fetchPriority := or .fetchpriority site.Params.thulite_images.defaults.fetchpriority }}
-{{- $loading := or .loading site.Params.thulite_images.defaults.loading }}
-{{- $process := or .process site.Params.thulite_images.defaults.process }}
-{{- $lqip := or .lqip site.Params.thulite_images.defaults.lqip }}
-{{- $src := or .src "" }}
-{{- $title := or .title "" }}
-{{- $caption := or .caption "" }}
-{{- $width := or (int .width) 0 }}
-{{- $fallbackFormat := "jpeg" }}
-{{- $stdWidths := site.Params.thulite_images.defaults.widths }}
-{{- $stdSizes := or .sizes site.Params.thulite_images.defaults.sizes }}
-
-{{- /* Validate args. */}}
-{{- $validFormats := slice "gif" "jpg" "jpeg" "png" "webp"}}
-{{- if reflect.IsSlice $formats }}
- {{- $formats = apply $formats "strings.ToLower" "." }}
- {{- range $formats }}
- {{- if not (in $validFormats .) }}
- {{- errorf "The formats argument passed to the %q partial is invalid. Valid formats are %s. See %s" $partialName (delimit $validFormats ", " ", and ") $contentPath }}
- {{- end }}
- {{- end }}
-{{- else }}
- {{- errorf "The formats argument passed to the %q partial is not a slice. See %s" $partialName $contentPath }}
-{{- end }}
-
-{{- if not $src }}
- {{- errorf "The %q partial requires an image path, relative to the assets directory. See %s" $partialName $contentPath }}
-{{- end }}
-
-{{- /* Capture image as a resource. */}}
-{{- $r := "" }}
-{{- $ctx := dict
- "page" .page
- "path" $src
- "partialName" $partialName
- "contentPath" $contentPath
-}}
-{{- with partial "inline/capture-resource.html" $ctx }}
- {{- $r = . }}
-{{- end }}
-
-{{- /* Process image. */}}
-{{- with $process }}
- {{- $r = $r.Process $process }}
-{{- end }}
-
-{{- /* Process LQIP. */}}
-{{- $l := "" }}
-{{- with $lqip }}
- {{- $l = $r.Resize . }}
-{{- end }}
-
-{{- /* Determine widths for srcset generation. */}}
-{{- $widths := slice }}
-{{- if $width }}
- {{- /* The width was specified; generate 1x, 2x, 3x, and 4x images. */}}
- {{- $widths = slice $r.Width }}
- {{- range seq 4 }}
- {{- with mul . $width }}
- {{- if and (le . $r.Width) (le . (math.Max $stdWidths)) }}
- {{- /* Do not enlarge, and do not exceed maximum of $stdWidths. */}}
- {{- $widths = $widths | append . }}
- {{- end }}
- {{- end }}
- {{- end }}
-{{- else }}
- {{- /* The width was not speficied, will be using $stdWidths. */}}
- {{- $stdWidths = $stdWidths | append $r.Width | sort }}
- {{- range $stdWidths }}
- {{- /* Do not enlarge. */}}
- {{- if (le . $r.Width) }}
- {{- $widths = $widths | append . }}
- {{- end }}
- {{- end }}
-{{- end }}
-{{- $widths = $widths | uniq | sort}}
-
-{{- /* Create fallback image (fi) with the smallest of widths. */}}
-{{- $fi := $r.Resize (printf "%dx %s" (math.Min $widths | int) $fallbackFormat) }}
-
-{{- /* Create the image map. */}}
-{{- $im := dict }}
-{{- range $format := $formats }}
- {{- $sizes := slice }}
- {{- range sort $widths }}
- {{- $sizes = $sizes | append ($r.Resize (printf "%dx %s" . $format)) }}
- {{- end }}
- {{- $im = merge $im (dict $format $sizes) }}
-{{- end }}
-
-{{- /* Render. */}}
-
-
- {{- with $caption }}{{ . }}{{- end }}
-
-
-{{- define "partials/inline/capture-resource.html" }}
- {{- /* Parse destination. */}}
- {{- $u := urls.Parse .path }}
-
- {{- /* Set common message. */}}
- {{- $msg := printf "The %q partial was unable to get %q in %s" .partialName $u.String .contentPath }}
-
- {{- /* Get image resource. */}}
- {{- $r := "" }}
- {{- if $u.IsAbs }}
- {{- with resources.GetRemote $u.String }}
- {{- with .Err }}
- {{- errorf "%s. See %s" . $.contentPath }}
- {{- else }}
- {{- /* Destination is a remote resource. */}}
- {{- $r = . }}
- {{- end }}
- {{- else }}
- {{- errorf $msg }}
- {{- end }}
- {{- else }}
- {{- with .page.Resources.Get (strings.TrimPrefix "./" $u.Path) }}
- {{- /* Destination is a page resource. */}}
- {{- $r = . }}
- {{- else }}
- {{- with (and (ne .page.BundleType "leaf") (.page.CurrentSection.Resources.Get (strings.TrimPrefix "./" $u.Path)) ) }}
- {{- /* Destination is a section resource, and current page is not a leaf bundle. */}}
- {{- $r = . }}
- {{- else }}
- {{- with resources.Get $u.Path }}
- {{- /* Destination is a global resource. */}}
- {{- $r = . }}
- {{- else }}
- {{- errorf $msg }}
- {{- end }}
- {{- end }}
- {{- end }}
- {{- end }}
- {{- return $r }}
-{{- end -}}
+{{- /* Based on https://www.veriphor.com/articles/link-and-image-render-hooks/#image-render-hook */}}
+
+{{- /* Last modified: 2023-09-05T11:48:34-07:00 */}}
+
+{{- /*
+Copyright 2023 Veriphor LLC
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+*/}}
+
+{{- /*
+Renders an HTML figure element, in multiple formats and sizes.
+
+It resolves internal destinations by looking for a matching:
+
+ 1. Page resource (an image in the current page bundle)
+ 2. Section resource (an image in the current section)
+ 3. Global resource (an image in the assets directory)
+
+It skips the section resource lookup if the current page is a leaf bundle, and
+captures external destinations as resources for local hosting. The build will
+fail if this partial is unable to resolve a destination.
+
+You must place global resources in the assets directory. If you have placed
+your resources in the static directory, and you are unable or unwilling to move
+them, you must mount the static directory to the assets directory by including
+both of these entries in your site configuration:
+
+ [[module.mounts]]
+ source = 'assets'
+ target = 'assets'
+
+ [[module.mounts]]
+ source = 'static'
+ target = 'assets'
+
+Add this CSS to your site to enable responsive image behavior:
+
+ img {
+ height: auto;
+ max-width: 100%;
+ }
+
+Add this CSS to your site to remove small gaps between adjacent elements:
+
+ img, picture {
+ font-size: 0;
+ }
+
+@context {page} [page] The current page.
+@context {string} [src] The path to the base image: a page resource, a global resource, or a remote resource.
+@contect {int} [width] The display width of the image, in pixels, falling back to 100% of the viewport width.
+@context {string} [sizes] = "" # "100vw", "75vw", or "auto" for example
+@context {string slice} [formats] A slice of image formats, ordered by precedence, to use when creating images for the srcset attribute of each source element.
+@context {string} [process] = "" # "fill 1600x900" for example
+@context {string} [lqip] = "" # "16x webp q20" or "21x webp q20" for example
+@context {string} [decoding] The img element's decoding attribute.
+@context {string} [fetchpriority] The img element's fetchpriority attribute.
+@context {string} [loading] The img element's loading attribute.
+@context {string} [alt] The img element's alt attribute.
+@context {string} [title] The img element's title attribute.
+@context {string} [caption] The figure element's caption attribute.
+@context {string} [class] The img element's class attribute.
+
+@returns {template.HTML}
+
+@example (required args only)
+
+ {{- partial "figure.html" (dict "page" . "src" "images/zion.jpg") }}
+
+@example (all args)
+ {{- $opts := dict
+ "page" .
+ "src" "images/bryce-canyon-national-park.jpg"
+ "width" 768
+ "sizes" "auto"
+ "formats" (slice "webp" "jpeg")
+ "process" "fill 1600x900"
+ "lqip" "16x webp q20"
+ "decoding" "async"
+ "fetchpriority" "auto"
+ "loading" "eager"
+ "alt" "Bryce Canyon National Park"
+ "title" "A beautiful day in Bryce Canyon National Park"
+ "caption" "Bryce Canyon National Park"
+ "class" "foo"
+ }}
+ {{- partial "figure.html" $opts }}
+
+*/}}
+
+{{- /* Initialize. */}}
+{{- $partialName := "figure" }}
+
+{{- /* Verify minimum required version. */}}
+{{- $minHugoVersion := "0.118.0" }}
+{{- if lt hugo.Version $minHugoVersion }}
+ {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }}
+{{- end }}
+
+{{- /* Validate page arg. */}}
+{{- if not .page }}
+ {{- errorf "The %q partial requires a page argument." $partialName }}
+{{- end }}
+
+{{- /* Determine content path for warning and error messages. */}}
+{{- $contentPath := "" }}
+{{- with .page.File }}
+ {{- $contentPath = .Path }}
+{{- else }}
+ {{- $contentPath = .Path }}
+{{- end }}
+
+{{- /* Set defaults and get args. */}}
+{{- $alt := or .alt "" }}
+{{- $class := or .class "" }}
+{{- $formats := or .formats (slice "webp") }}
+{{- $decoding := or .decoding site.Params.thulite_images.defaults.decoding }}
+{{- $fetchPriority := or .fetchpriority site.Params.thulite_images.defaults.fetchpriority }}
+{{- $loading := or .loading site.Params.thulite_images.defaults.loading }}
+{{- $process := or .process site.Params.thulite_images.defaults.process }}
+{{- $lqip := or .lqip site.Params.thulite_images.defaults.lqip }}
+{{- $src := or .src "" }}
+{{- $title := or .title "" }}
+{{- $caption := or .caption "" }}
+{{- $width := or (int .width) 0 }}
+{{- $fallbackFormat := "jpeg" }}
+{{- $stdWidths := site.Params.thulite_images.defaults.widths }}
+{{- $stdSizes := or .sizes site.Params.thulite_images.defaults.sizes }}
+
+{{- /* Validate args. */}}
+{{- $validFormats := slice "gif" "jpg" "jpeg" "png" "webp"}}
+{{- if reflect.IsSlice $formats }}
+ {{- $formats = apply $formats "strings.ToLower" "." }}
+ {{- range $formats }}
+ {{- if not (in $validFormats .) }}
+ {{- errorf "The formats argument passed to the %q partial is invalid. Valid formats are %s. See %s" $partialName (delimit $validFormats ", " ", and ") $contentPath }}
+ {{- end }}
+ {{- end }}
+{{- else }}
+ {{- errorf "The formats argument passed to the %q partial is not a slice. See %s" $partialName $contentPath }}
+{{- end }}
+
+{{- if not $src }}
+ {{- errorf "The %q partial requires an image path, relative to the assets directory. See %s" $partialName $contentPath }}
+{{- end }}
+
+{{- /* Capture image as a resource. */}}
+{{- $r := "" }}
+{{- $ctx := dict
+ "page" .page
+ "path" $src
+ "partialName" $partialName
+ "contentPath" $contentPath
+}}
+{{- with partial "inline/capture-resource.html" $ctx }}
+ {{- $r = . }}
+{{- end }}
+
+{{- /* Process image. */}}
+{{- with $process }}
+ {{- $r = $r.Process $process }}
+{{- end }}
+
+{{- /* Process LQIP. */}}
+{{- $l := "" }}
+{{- with $lqip }}
+ {{- $l = $r.Resize . }}
+{{- end }}
+
+{{- /* Determine widths for srcset generation. */}}
+{{- $widths := slice }}
+{{- if $width }}
+ {{- /* The width was specified; generate 1x, 2x, 3x, and 4x images. */}}
+ {{- $widths = slice $r.Width }}
+ {{- range seq 4 }}
+ {{- with mul . $width }}
+ {{- if and (le . $r.Width) (le . (math.Max $stdWidths)) }}
+ {{- /* Do not enlarge, and do not exceed maximum of $stdWidths. */}}
+ {{- $widths = $widths | append . }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- else }}
+ {{- /* The width was not speficied, will be using $stdWidths. */}}
+ {{- $stdWidths = $stdWidths | append $r.Width | sort }}
+ {{- range $stdWidths }}
+ {{- /* Do not enlarge. */}}
+ {{- if (le . $r.Width) }}
+ {{- $widths = $widths | append . }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- $widths = $widths | uniq | sort}}
+
+{{- /* Create fallback image (fi) with the smallest of widths. */}}
+{{- $fi := $r.Resize (printf "%dx %s" (math.Min $widths | int) $fallbackFormat) }}
+
+{{- /* Create the image map. */}}
+{{- $im := dict }}
+{{- range $format := $formats }}
+ {{- $sizes := slice }}
+ {{- range sort $widths }}
+ {{- $sizes = $sizes | append ($r.Resize (printf "%dx %s" . $format)) }}
+ {{- end }}
+ {{- $im = merge $im (dict $format $sizes) }}
+{{- end }}
+
+{{- /* Render. */}}
+
+
+ {{- with $caption }}{{ . }}{{- end }}
+
+
+{{- define "partials/inline/capture-resource.html" }}
+ {{- /* Parse destination. */}}
+ {{- $u := urls.Parse .path }}
+
+ {{- /* Set common message. */}}
+ {{- $msg := printf "The %q partial was unable to get %q in %s" .partialName $u.String .contentPath }}
+
+ {{- /* Get image resource. */}}
+ {{- $r := "" }}
+ {{- if $u.IsAbs }}
+ {{- with try (resources.GetRemote $u.String) }}
+ {{- with .Err }}
+ {{- errorf "%s. See %s" .Err $.contentPath }}
+ {{- else with .Value }}
+ {{- /* Destination is a remote resource. */}}
+ {{- $r = . }}
+ {{- end }}
+ {{- else }}
+ {{- errorf $msg }}
+ {{- end }}
+ {{- else }}
+ {{- with .page.Resources.Get (strings.TrimPrefix "./" $u.Path) }}
+ {{- /* Destination is a page resource. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- with (and (ne .page.BundleType "leaf") (.page.CurrentSection.Resources.Get (strings.TrimPrefix "./" $u.Path)) ) }}
+ {{- /* Destination is a section resource, and current page is not a leaf bundle. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- with resources.Get $u.Path }}
+ {{- /* Destination is a global resource. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- errorf $msg }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- return $r }}
+{{- end -}}
diff --git a/layouts/partials/img.html b/layouts/partials/img.html
index 20c76d5..757b3d6 100644
--- a/layouts/partials/img.html
+++ b/layouts/partials/img.html
@@ -1,283 +1,283 @@
-{{- /* Based on https://www.veriphor.com/articles/link-and-image-render-hooks/#image-render-hook */}}
-
-{{- /* Last modified: 2023-09-05T11:48:34-07:00 */}}
-
-{{- /*
-Copyright 2023 Veriphor LLC
-
-Licensed under the Apache License, Version 2.0 (the "License"); you may not
-use this file except in compliance with the License. You may obtain a copy of
-the License at
-
-https://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-License for the specific language governing permissions and limitations under
-the License.
-*/}}
-
-{{- /*
-Renders an HTML img element, in multiple formats and sizes.
-
-It resolves internal destinations by looking for a matching:
-
- 1. Page resource (an image in the current page bundle)
- 2. Section resource (an image in the current section)
- 3. Global resource (an image in the assets directory)
-
-It skips the section resource lookup if the current page is a leaf bundle, and
-captures external destinations as resources for local hosting. The build will
-fail if this partial is unable to resolve a destination.
-
-You must place global resources in the assets directory. If you have placed
-your resources in the static directory, and you are unable or unwilling to move
-them, you must mount the static directory to the assets directory by including
-both of these entries in your site configuration:
-
- [[module.mounts]]
- source = 'assets'
- target = 'assets'
-
- [[module.mounts]]
- source = 'static'
- target = 'assets'
-
-Add this CSS to your site to enable responsive image behavior:
-
- img {
- height: auto;
- max-width: 100%;
- }
-
-Add this CSS to your site to remove small gaps between adjacent elements:
-
- img, picture {
- font-size: 0;
- }
-
-@context {page} [page] The current page.
-@context {string} [src] The path to the base image: a page resource, a global resource, or a remote resource.
-@contect {int} [width] The display width of the image, in pixels, falling back to 100% of the viewport width.
-@context {string} [sizes] = "" # "100vw", "75vw", or "auto" for example
-@context {string slice} [formats] A slice of image formats, ordered by precedence, to use when creating images for the srcset attribute of each source element.
-@context {string} [process] = "" # "fill 1600x900" for example
-@context {string} [lqip] = "" # "16x webp q20" or "21x webp q20" for example
-@context {string} [decoding] The img element's decoding attribute.
-@context {string} [fetchpriority] The img element's fetchpriority attribute.
-@context {string} [loading] The img element's loading attribute.
-@context {string} [alt] The img element's alt attribute.
-@context {string} [title] The img element's title attribute.
-@context {string} [class] The img element's class attribute.
-
-@returns {template.HTML}
-
-@example (required args only)
-
- {{- partial "img.html" (dict "page" . "src" "images/zion.jpg") }}
-
-@example (all args)
- {{- $opts := dict
- "page" .
- "src" "images/bryce-canyon-national-park.jpg"
- "width" 768
- "sizes" "auto"
- "formats" (slice "webp" "jpeg")
- "process" "fill 1600x900"
- "lqip" "16x webp q20"
- "decoding" "async"
- "fetchpriority" "auto"
- "loading" "eager"
- "alt" "Bryce Canyon National Park"
- "title" "A beautiful day in Bryce Canyon National Park"
- "class" "foo"
- }}
- {{- partial "img.html" $opts }}
-
-*/}}
-
-{{- /* Initialize. */}}
-{{- $partialName := "img" }}
-
-{{- /* Verify minimum required version. */}}
-{{- $minHugoVersion := "0.118.0" }}
-{{- if lt hugo.Version $minHugoVersion }}
- {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }}
-{{- end }}
-
-{{- /* Validate page arg. */}}
-{{- if not .page }}
- {{- errorf "The %q partial requires a page argument." $partialName }}
-{{- end }}
-
-{{- /* Determine content path for warning and error messages. */}}
-{{- $contentPath := "" }}
-{{- with .page.File }}
- {{- $contentPath = .Path }}
-{{- else }}
- {{- $contentPath = .Path }}
-{{- end }}
-
-{{- /* Set defaults and get args. */}}
-{{- $alt := or .alt "" }}
-{{- $class := or .class "" }}
-{{- $formats := or .formats (slice "webp") }}
-{{- $decoding := or .decoding site.Params.thulite_images.defaults.decoding }}
-{{- $fetchPriority := or .fetchpriority site.Params.thulite_images.defaults.fetchpriority }}
-{{- $loading := or .loading site.Params.thulite_images.defaults.loading }}
-{{- $process := or .process site.Params.thulite_images.defaults.process }}
-{{- $lqip := or .lqip site.Params.thulite_images.defaults.lqip }}
-{{- $src := or .src "" }}
-{{- $title := or .title "" }}
-{{- $width := or (int .width) 0 }}
-{{- $fallbackFormat := "jpeg" }}
-{{- $stdWidths := site.Params.thulite_images.defaults.widths }}
-{{- $stdSizes := or .sizes site.Params.thulite_images.defaults.sizes }}
-
-{{- /* Validate args. */}}
-{{- $validFormats := slice "gif" "jpg" "jpeg" "png" "webp"}}
-{{- if reflect.IsSlice $formats }}
- {{- $formats = apply $formats "strings.ToLower" "." }}
- {{- range $formats }}
- {{- if not (in $validFormats .) }}
- {{- errorf "The formats argument passed to the %q partial is invalid. Valid formats are %s. See %s" $partialName (delimit $validFormats ", " ", and ") $contentPath }}
- {{- end }}
- {{- end }}
-{{- else }}
- {{- errorf "The formats argument passed to the %q partial is not a slice. See %s" $partialName $contentPath }}
-{{- end }}
-
-{{- if not $src }}
- {{- errorf "The %q partial requires an image path, relative to the assets directory. See %s" $partialName $contentPath }}
-{{- end }}
-
-{{- /* Capture image as a resource. */}}
-{{- $r := "" }}
-{{- $ctx := dict
- "page" .page
- "path" $src
- "partialName" $partialName
- "contentPath" $contentPath
-}}
-{{- with partial "inline/capture-resource.html" $ctx }}
- {{- $r = . }}
-{{- end }}
-
-{{- /* Process image. */}}
-{{- with $process }}
- {{- $r = $r.Process $process }}
-{{- end }}
-
-{{- /* Process LQIP. */}}
-{{- $l := "" }}
-{{- with $lqip }}
- {{- $l = $r.Resize . }}
-{{- end }}
-
-{{- /* Determine widths for srcset generation. */}}
-{{- $widths := slice }}
-{{- if $width }}
- {{- /* The width was specified; generate 1x, 2x, 3x, and 4x images. */}}
- {{- $widths = slice $r.Width }}
- {{- range seq 4 }}
- {{- with mul . $width }}
- {{- if and (le . $r.Width) (le . (math.Max $stdWidths)) }}
- {{- /* Do not enlarge, and do not exceed maximum of $stdWidths. */}}
- {{- $widths = $widths | append . }}
- {{- end }}
- {{- end }}
- {{- end }}
-{{- else }}
- {{- /* The width was not speficied, will be using $stdWidths. */}}
- {{- $stdWidths = $stdWidths | append $r.Width | sort }}
- {{- range $stdWidths }}
- {{- /* Do not enlarge. */}}
- {{- if (le . $r.Width) }}
- {{- $widths = $widths | append . }}
- {{- end }}
- {{- end }}
-{{- end }}
-{{- $widths = $widths | uniq | sort}}
-
-{{- /* Create fallback image (fi) with the smallest of widths. */}}
-{{- $fi := $r.Resize (printf "%dx %s" (math.Min $widths | int) $fallbackFormat) }}
-
-{{- /* Create the image map. */}}
-{{- $im := dict }}
-{{- range $format := $formats }}
- {{- $sizes := slice }}
- {{- range sort $widths }}
- {{- $sizes = $sizes | append ($r.Resize (printf "%dx %s" . $format)) }}
- {{- end }}
- {{- $im = merge $im (dict $format $sizes) }}
-{{- end }}
-
-{{- /* Render. */}}
-
-
-{{- define "partials/inline/capture-resource.html" }}
- {{- /* Parse destination. */}}
- {{- $u := urls.Parse .path }}
-
- {{- /* Set common message. */}}
- {{- $msg := printf "The %q partial was unable to get %q in %s" .partialName $u.String .contentPath }}
-
- {{- /* Get image resource. */}}
- {{- $r := "" }}
- {{- if $u.IsAbs }}
- {{- with resources.GetRemote $u.String }}
- {{- with .Err }}
- {{- errorf "%s. See %s" . $.contentPath }}
- {{- else }}
- {{- /* Destination is a remote resource. */}}
- {{- $r = . }}
- {{- end }}
- {{- else }}
- {{- errorf $msg }}
- {{- end }}
- {{- else }}
- {{- with .page.Resources.Get (strings.TrimPrefix "./" $u.Path) }}
- {{- /* Destination is a page resource. */}}
- {{- $r = . }}
- {{- else }}
- {{- with (and (ne .page.BundleType "leaf") (.page.CurrentSection.Resources.Get (strings.TrimPrefix "./" $u.Path)) ) }}
- {{- /* Destination is a section resource, and current page is not a leaf bundle. */}}
- {{- $r = . }}
- {{- else }}
- {{- with resources.Get $u.Path }}
- {{- /* Destination is a global resource. */}}
- {{- $r = . }}
- {{- else }}
- {{- errorf $msg }}
- {{- end }}
- {{- end }}
- {{- end }}
- {{- end }}
- {{- return $r }}
-{{- end -}}
+{{- /* Based on https://www.veriphor.com/articles/link-and-image-render-hooks/#image-render-hook */}}
+
+{{- /* Last modified: 2023-09-05T11:48:34-07:00 */}}
+
+{{- /*
+Copyright 2023 Veriphor LLC
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+*/}}
+
+{{- /*
+Renders an HTML img element, in multiple formats and sizes.
+
+It resolves internal destinations by looking for a matching:
+
+ 1. Page resource (an image in the current page bundle)
+ 2. Section resource (an image in the current section)
+ 3. Global resource (an image in the assets directory)
+
+It skips the section resource lookup if the current page is a leaf bundle, and
+captures external destinations as resources for local hosting. The build will
+fail if this partial is unable to resolve a destination.
+
+You must place global resources in the assets directory. If you have placed
+your resources in the static directory, and you are unable or unwilling to move
+them, you must mount the static directory to the assets directory by including
+both of these entries in your site configuration:
+
+ [[module.mounts]]
+ source = 'assets'
+ target = 'assets'
+
+ [[module.mounts]]
+ source = 'static'
+ target = 'assets'
+
+Add this CSS to your site to enable responsive image behavior:
+
+ img {
+ height: auto;
+ max-width: 100%;
+ }
+
+Add this CSS to your site to remove small gaps between adjacent elements:
+
+ img, picture {
+ font-size: 0;
+ }
+
+@context {page} [page] The current page.
+@context {string} [src] The path to the base image: a page resource, a global resource, or a remote resource.
+@contect {int} [width] The display width of the image, in pixels, falling back to 100% of the viewport width.
+@context {string} [sizes] = "" # "100vw", "75vw", or "auto" for example
+@context {string slice} [formats] A slice of image formats, ordered by precedence, to use when creating images for the srcset attribute of each source element.
+@context {string} [process] = "" # "fill 1600x900" for example
+@context {string} [lqip] = "" # "16x webp q20" or "21x webp q20" for example
+@context {string} [decoding] The img element's decoding attribute.
+@context {string} [fetchpriority] The img element's fetchpriority attribute.
+@context {string} [loading] The img element's loading attribute.
+@context {string} [alt] The img element's alt attribute.
+@context {string} [title] The img element's title attribute.
+@context {string} [class] The img element's class attribute.
+
+@returns {template.HTML}
+
+@example (required args only)
+
+ {{- partial "img.html" (dict "page" . "src" "images/zion.jpg") }}
+
+@example (all args)
+ {{- $opts := dict
+ "page" .
+ "src" "images/bryce-canyon-national-park.jpg"
+ "width" 768
+ "sizes" "auto"
+ "formats" (slice "webp" "jpeg")
+ "process" "fill 1600x900"
+ "lqip" "16x webp q20"
+ "decoding" "async"
+ "fetchpriority" "auto"
+ "loading" "eager"
+ "alt" "Bryce Canyon National Park"
+ "title" "A beautiful day in Bryce Canyon National Park"
+ "class" "foo"
+ }}
+ {{- partial "img.html" $opts }}
+
+*/}}
+
+{{- /* Initialize. */}}
+{{- $partialName := "img" }}
+
+{{- /* Verify minimum required version. */}}
+{{- $minHugoVersion := "0.118.0" }}
+{{- if lt hugo.Version $minHugoVersion }}
+ {{- errorf "The %q partial requires Hugo v%s or later." $partialName $minHugoVersion }}
+{{- end }}
+
+{{- /* Validate page arg. */}}
+{{- if not .page }}
+ {{- errorf "The %q partial requires a page argument." $partialName }}
+{{- end }}
+
+{{- /* Determine content path for warning and error messages. */}}
+{{- $contentPath := "" }}
+{{- with .page.File }}
+ {{- $contentPath = .Path }}
+{{- else }}
+ {{- $contentPath = .Path }}
+{{- end }}
+
+{{- /* Set defaults and get args. */}}
+{{- $alt := or .alt "" }}
+{{- $class := or .class "" }}
+{{- $formats := or .formats (slice "webp") }}
+{{- $decoding := or .decoding site.Params.thulite_images.defaults.decoding }}
+{{- $fetchPriority := or .fetchpriority site.Params.thulite_images.defaults.fetchpriority }}
+{{- $loading := or .loading site.Params.thulite_images.defaults.loading }}
+{{- $process := or .process site.Params.thulite_images.defaults.process }}
+{{- $lqip := or .lqip site.Params.thulite_images.defaults.lqip }}
+{{- $src := or .src "" }}
+{{- $title := or .title "" }}
+{{- $width := or (int .width) 0 }}
+{{- $fallbackFormat := "jpeg" }}
+{{- $stdWidths := site.Params.thulite_images.defaults.widths }}
+{{- $stdSizes := or .sizes site.Params.thulite_images.defaults.sizes }}
+
+{{- /* Validate args. */}}
+{{- $validFormats := slice "gif" "jpg" "jpeg" "png" "webp"}}
+{{- if reflect.IsSlice $formats }}
+ {{- $formats = apply $formats "strings.ToLower" "." }}
+ {{- range $formats }}
+ {{- if not (in $validFormats .) }}
+ {{- errorf "The formats argument passed to the %q partial is invalid. Valid formats are %s. See %s" $partialName (delimit $validFormats ", " ", and ") $contentPath }}
+ {{- end }}
+ {{- end }}
+{{- else }}
+ {{- errorf "The formats argument passed to the %q partial is not a slice. See %s" $partialName $contentPath }}
+{{- end }}
+
+{{- if not $src }}
+ {{- errorf "The %q partial requires an image path, relative to the assets directory. See %s" $partialName $contentPath }}
+{{- end }}
+
+{{- /* Capture image as a resource. */}}
+{{- $r := "" }}
+{{- $ctx := dict
+ "page" .page
+ "path" $src
+ "partialName" $partialName
+ "contentPath" $contentPath
+}}
+{{- with partial "inline/capture-resource.html" $ctx }}
+ {{- $r = . }}
+{{- end }}
+
+{{- /* Process image. */}}
+{{- with $process }}
+ {{- $r = $r.Process $process }}
+{{- end }}
+
+{{- /* Process LQIP. */}}
+{{- $l := "" }}
+{{- with $lqip }}
+ {{- $l = $r.Resize . }}
+{{- end }}
+
+{{- /* Determine widths for srcset generation. */}}
+{{- $widths := slice }}
+{{- if $width }}
+ {{- /* The width was specified; generate 1x, 2x, 3x, and 4x images. */}}
+ {{- $widths = slice $r.Width }}
+ {{- range seq 4 }}
+ {{- with mul . $width }}
+ {{- if and (le . $r.Width) (le . (math.Max $stdWidths)) }}
+ {{- /* Do not enlarge, and do not exceed maximum of $stdWidths. */}}
+ {{- $widths = $widths | append . }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- else }}
+ {{- /* The width was not speficied, will be using $stdWidths. */}}
+ {{- $stdWidths = $stdWidths | append $r.Width | sort }}
+ {{- range $stdWidths }}
+ {{- /* Do not enlarge. */}}
+ {{- if (le . $r.Width) }}
+ {{- $widths = $widths | append . }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- $widths = $widths | uniq | sort}}
+
+{{- /* Create fallback image (fi) with the smallest of widths. */}}
+{{- $fi := $r.Resize (printf "%dx %s" (math.Min $widths | int) $fallbackFormat) }}
+
+{{- /* Create the image map. */}}
+{{- $im := dict }}
+{{- range $format := $formats }}
+ {{- $sizes := slice }}
+ {{- range sort $widths }}
+ {{- $sizes = $sizes | append ($r.Resize (printf "%dx %s" . $format)) }}
+ {{- end }}
+ {{- $im = merge $im (dict $format $sizes) }}
+{{- end }}
+
+{{- /* Render. */}}
+
+
+{{- define "partials/inline/capture-resource.html" }}
+ {{- /* Parse destination. */}}
+ {{- $u := urls.Parse .path }}
+
+ {{- /* Set common message. */}}
+ {{- $msg := printf "The %q partial was unable to get %q in %s" .partialName $u.String .contentPath }}
+
+ {{- /* Get image resource. */}}
+ {{- $r := "" }}
+ {{- if $u.IsAbs }}
+ {{- with try (resources.GetRemote $u.String) }}
+ {{- with .Err }}
+ {{- errorf "%s. See %s" .Err $.contentPath }}
+ {{- else with .Value }}
+ {{- /* Destination is a remote resource. */}}
+ {{- $r = .Value }}
+ {{- end }}
+ {{- else }}
+ {{- errorf $msg }}
+ {{- end }}
+ {{- else }}
+ {{- with .page.Resources.Get (strings.TrimPrefix "./" $u.Path) }}
+ {{- /* Destination is a page resource. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- with (and (ne .page.BundleType "leaf") (.page.CurrentSection.Resources.Get (strings.TrimPrefix "./" $u.Path)) ) }}
+ {{- /* Destination is a section resource, and current page is not a leaf bundle. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- with resources.Get $u.Path }}
+ {{- /* Destination is a global resource. */}}
+ {{- $r = . }}
+ {{- else }}
+ {{- errorf $msg }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- return $r }}
+{{- end -}}
diff --git a/layouts/partials/picture.html b/layouts/partials/picture.html
index e1175c3..b16f0fe 100644
--- a/layouts/partials/picture.html
+++ b/layouts/partials/picture.html
@@ -253,10 +253,10 @@
{{- /* Get image resource. */}}
{{- $r := "" }}
{{- if $u.IsAbs }}
- {{- with resources.GetRemote $u.String }}
+ {{- with try (resources.GetRemote $u.String) }}
{{- with .Err }}
- {{- errorf "%s. See %s" . $.contentPath }}
- {{- else }}
+ {{- errorf "%s. See %s" .Err $.contentPath }}
+ {{- else with .Value }}
{{- /* Destination is a remote resource. */}}
{{- $r = . }}
{{- end }}