Initial design based off original website, some things still to do

This commit is contained in:
2025-08-08 17:48:11 +09:30
parent d38c8fc694
commit ae3c38be17
185 changed files with 6799 additions and 1877 deletions

View File

@@ -0,0 +1,126 @@
---
import { Image } from "astro:assets";
import type { ImageMetadata } from "astro";
import { shuffleArray } from "@lib/utils";
interface Props {
images: Array<ImageMetadata>;
className: string;
altText?: string | ((index: number) => string);
interval?: number;
backgroundColour?: string;
backgroundOpacity?: string;
transitionStyle?: string;
transitionDuration?: string;
foreground?: boolean;
foregroundColour?: string;
foregroundOpacity?: string;
quality?: number;
height?: number;
shuffle?: boolean;
}
const {
images,
className,
altText = null,
interval = 5000,
backgroundColour = "bg-black",
backgroundOpacity = "opacity-100",
transitionStyle = "ease-in-out",
transitionDuration = "duration-2000",
foreground = false,
foregroundColour = "bg-black",
foregroundOpacity = "opacity-50",
quality = "80",
height,
shuffle = false
} = Astro.props as Props;
const IDs: string[] = [];
const imagesArray = shuffle ? shuffleArray(images) : images;
---
<div class:list={[className]}>
<div class="relative h-full w-full">
<div class:list={[backgroundColour, backgroundOpacity, "absolute inset-0"]}>
</div>
{
imagesArray.map((image, index) => {
const ID = `image-carousel-${Math.random().toString(36)}`;
IDs.push(ID);
return (
<Image
data-id={`${ID}`}
class:list={[
"absolute h-full w-full object-cover object-center transition-opacity",
transitionStyle,
transitionDuration,
index > 0 ? "opacity-0" : "",
index < 2 ? "" : "hidden"
]}
src={image}
alt={
typeof altText === "function" ? altText(index) : (altText ?? "")
}
loading={index < 2 ? "eager" : "lazy"}
aria-hidden={index === 0 ? "false" : "true"}
layout="full-width"
fit="cover"
style="height: 100% !important;"
quality={quality}
height={height === undefined ? undefined : height}
/>
);
})
}
{
foreground && (
<div
class:list={[foregroundColour, foregroundOpacity, "absolute inset-0"]}
/>
)
}
<slot />
</div>
</div>
<script define:vars={{ imagesArray, interval, IDs }}>
let currentIndex = 0;
setInterval(() => {
const total = imagesArray.length;
const current = document.querySelectorAll(
`[data-id="${IDs[currentIndex]}"]`
)[0];
const nextIndex = (currentIndex + 1) % total;
const next = document.querySelectorAll(`[data-id="${IDs[nextIndex]}"]`)[0];
if (!current || !next) return;
// Fade out current, fade in next
current.classList.add("opacity-0");
current.setAttribute("aria-hidden", "true");
next.classList.remove("opacity-0", "hidden");
next.setAttribute("aria-hidden", "false");
const preloadIndex = (nextIndex + 1) % total;
const preloadImage = document.querySelectorAll(
`[data-id="${IDs[preloadIndex]}"]`
)[0];
if (preloadImage) {
preloadImage.classList.add("opacity-0");
preloadImage.classList.remove("hidden");
preloadImage.setAttribute("aria-hidden", "true");
}
currentIndex = nextIndex;
}, interval);
</script>