Files
max-richter.dev/src/components/Image.astro
2025-10-25 17:02:05 +02:00

97 lines
2.1 KiB
Plaintext

---
import type { ImageMetadata } from "astro";
import { Picture as AstroImage } from "astro:assets";
import { inferRemoteSize } from "astro/assets/utils";
import { getProcessedImage } from "@helpers/image";
interface Props {
src: ImageMetadata & { fsPath?: string; src?: string };
alt: string;
pictureClass?: string;
class?: string;
caption?: string;
hash?: boolean;
loader?: boolean;
maxWidth?: number;
thumbnail?: boolean;
}
async function checkImage(image: ImageMetadata) {
const src = typeof image === "string" ? image : image.src;
if (!src) return false;
try {
if (src.startsWith("/@fs") || src.startsWith("/_astro")) return true;
const res = await inferRemoteSize(src);
if (res.format) {
image.format = res.format;
return true;
} else {
console.log("Failed to load: ", src);
}
return false;
} catch (err) {
console.log("\n");
console.log("Failed to fetch: ", src);
return false;
}
}
const {
src: image,
loader = true,
pictureClass = "",
hash = true,
alt,
maxWidth,
thumbnail = false,
} = Astro.props;
const imageOk = await checkImage(image);
const { thumbhash, exif } = imageOk
? await getProcessedImage(image)
: { thumbhash: undefined, exif: undefined };
const definedSizes = [
{
width: 240,
media: "(max-width: 360px)",
},
{
width: 540,
media: "(max-width: 720px)",
},
{
width: 720,
media: "(max-width: 1600px)",
},
{
width: image.width,
},
];
const sizes = thumbnail
? [definedSizes[0]]
: definedSizes.filter((size) => !maxWidth || size.width <= maxWidth);
---
{
imageOk ? (
<AstroImage
src={image}
alt={alt}
data-thumbhash={thumbhash}
data-exif={JSON.stringify(exif)}
inferSize={true}
pictureAttributes={{
class: `${hash ? "block h-full relative" : ""} ${loader ? "thumb" : ""} ${pictureClass}`,
}}
class={`${Astro.props.class} h-full w-full`}
widths={sizes.map((size) => size.width)}
sizes={sizes
.map((size) => `${size.media || "100vw"} ${size.width}px`)
.join(", ")}>
<slot />
</AstroImage>
) : undefined
}