Only hero images for CTA carousels, honour reduced motion

This commit is contained in:
encie22 committed 2026-10-16 09:17:58 +10:30
1 parent 70af555189
commit af8f99feb0
2 files changed
+48 -37

No files matched your search

+36 -27
View File
@@ -20,6 +20,7 @@ interface Props {
quality?: number; quality?: number;
height?: number; height?: number;
shuffle?: boolean; shuffle?: boolean;
eagerCount?: number;
} }
const { const {
@@ -37,7 +38,8 @@ const {
foregroundOpacity = "opacity-50", foregroundOpacity = "opacity-50",
quality = "80", quality = "80",
height, height,
shuffle = false shuffle = false,
eagerCount = 2
} = Astro.props as Props; } = Astro.props as Props;
const imagesArray = shuffle ? shuffleArray(images) : images; const imagesArray = shuffle ? shuffleArray(images) : images;
@@ -64,7 +66,7 @@ const imagesArray = shuffle ? shuffleArray(images) : images;
alt={ alt={
typeof altText === "function" ? altText(index) : (altText ?? "") typeof altText === "function" ? altText(index) : (altText ?? "")
} }
loading={index < 2 ? "eager" : "lazy"} loading={index < eagerCount ? "eager" : "lazy"}
aria-hidden={index === 0 ? "false" : "true"} aria-hidden={index === 0 ? "false" : "true"}
layout="full-width" layout="full-width"
fit="cover" fit="cover"
@@ -91,34 +93,41 @@ const imagesArray = shuffle ? shuffleArray(images) : images;
> >
let currentIndex = 0; let currentIndex = 0;
setInterval(() => { // Honour reduced-motion: leave the first image showing, no rotation.
const current = document.querySelectorAll( const reduceMotion = window.matchMedia(
`[data-id="${carouselId}-${currentIndex}"]` "(prefers-reduced-motion: reduce)"
)[0]; ).matches;
const nextIndex = (currentIndex + 1) % imageCount;
const next = document.querySelectorAll(
`[data-id="${carouselId}-${nextIndex}"]`
)[0];
if (!current || !next) return; if (!reduceMotion) {
setInterval(() => {
const current = document.querySelectorAll(
`[data-id="${carouselId}-${currentIndex}"]`
)[0];
const nextIndex = (currentIndex + 1) % imageCount;
const next = document.querySelectorAll(
`[data-id="${carouselId}-${nextIndex}"]`
)[0];
// Fade out current, fade in next if (!current || !next) return;
current.classList.add("opacity-0");
current.setAttribute("aria-hidden", "true");
next.classList.remove("opacity-0", "hidden"); // Fade out current, fade in next
next.setAttribute("aria-hidden", "false"); current.classList.add("opacity-0");
current.setAttribute("aria-hidden", "true");
const preloadIndex = (nextIndex + 1) % imageCount; next.classList.remove("opacity-0", "hidden");
const preloadImage = document.querySelectorAll( next.setAttribute("aria-hidden", "false");
`[data-id="${carouselId}-${preloadIndex}"]`
)[0];
if (preloadImage) {
preloadImage.classList.add("opacity-0");
preloadImage.classList.remove("hidden");
preloadImage.setAttribute("aria-hidden", "true");
}
currentIndex = nextIndex; const preloadIndex = (nextIndex + 1) % imageCount;
}, interval); const preloadImage = document.querySelectorAll(
`[data-id="${carouselId}-${preloadIndex}"]`
)[0];
if (preloadImage) {
preloadImage.classList.add("opacity-0");
preloadImage.classList.remove("hidden");
preloadImage.setAttribute("aria-hidden", "true");
}
currentIndex = nextIndex;
}, interval);
}
</script> </script>
+12 -10
View File
@@ -17,28 +17,28 @@ import { Image } from "astro:assets";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { convertEagerImagesImportGlobToArray } from "@lib/utils"; import {
convertEagerImagesImportGlobToArray,
getProjectHero
} from "@lib/utils";
const heroImages = import.meta.glob<{ default: ImageMetadata; eager: true }>( const heroImages = import.meta.glob<{ default: ImageMetadata; eager: true }>(
"../assets/img/hero/*" "../assets/img/hero/*"
); );
const heroImagesArray = await convertEagerImagesImportGlobToArray(heroImages); const heroImagesArray = await convertEagerImagesImportGlobToArray(heroImages);
const imagesForCTA = import.meta.glob<{ default: ImageMetadata; eager: true }>([
"../assets/img/hero/*",
"../assets/img/project-heros/*",
"../assets/img/projects/**"
]);
const imagesForCTAArray =
await convertEagerImagesImportGlobToArray(imagesForCTA);
const projects = ( const projects = (
await getCollection("projects", ({ data }) => data.frontPage) await getCollection("projects", ({ data }) => data.frontPage)
).sort( ).sort(
(a, b) => (a.data.frontPage?.order || 0) - (b.data.frontPage?.order || 1) (a, b) => (a.data.frontPage?.order || 0) - (b.data.frontPage?.order || 1)
); );
// Curated carousel set: site heroes + heroes of featured projects only, instead of every image in the repo. Shared by both CTA carousels.
const imagesForCTAArray = [
...heroImagesArray,
...projects.map((project) => getProjectHero(project))
];
const awards = (await getCollection("awards")).sort( const awards = (await getCollection("awards")).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf() (a, b) => b.data.date.valueOf() - a.data.date.valueOf()
); );
@@ -120,6 +120,7 @@ const tracks = (
quality={5} quality={5}
height={192} height={192}
shuffle={true} shuffle={true}
eagerCount={0}
><div class="flex h-full w-full items-center"> ><div class="flex h-full w-full items-center">
<a <a
href="/contact/" href="/contact/"
@@ -207,6 +208,7 @@ const tracks = (
quality={5} quality={5}
height={384} height={384}
shuffle={true} shuffle={true}
eagerCount={0}
/> />
</div> </div>
</section> </section>