File size: 3,141 Bytes
96dd062 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | ---
import { Image, Picture } from "astro:assets";
import * as path from "node:path";
import type { ImageMetadata } from "astro";
import type { ImageFormat, ResponsiveImageLayout } from "@/types/config";
import {
getFallbackFormat,
getImageFormats,
getImageQuality,
} from "@/utils/image-utils";
import { url } from "@/utils/url-utils";
interface Props {
id?: string;
src: string;
class?: string;
alt?: string;
position?: string;
basePath?: string;
loading?: "lazy" | "eager";
fetchpriority?: "high" | "low" | "auto";
// 响应式图像属性
layout?: ResponsiveImageLayout;
usePicture?: boolean;
formats?: ImageFormat[];
widths?: number[];
sizes?: string;
quality?: number;
}
const {
id,
src,
alt,
position = "center",
basePath = "/",
loading = "lazy",
fetchpriority = "auto",
layout = "constrained",
usePicture = true,
formats = getImageFormats(),
widths,
sizes,
quality = getImageQuality(),
} = Astro.props;
const fallbackFormat = getFallbackFormat();
const className = Astro.props.class;
const isLocal = !(
src.startsWith("/") ||
src.startsWith("http") ||
src.startsWith("https") ||
src.startsWith("data:")
);
const isPublic = src.startsWith("/");
// TODO temporary workaround for images dynamic import
// https://github.com/withastro/astro/issues/3373
let img: ImageMetadata | null = null;
if (isLocal) {
const files = import.meta.glob<ImageMetadata>(
"../../**/*.{png,jpg,jpeg,webp,avif}",
{
import: "default",
},
);
let normalizedPath = path
.normalize(path.join("../../", basePath, src))
.replace(/\\/g, "/");
const file = files[normalizedPath];
if (!file) {
console.error(
`\n[ERROR] Image file not found: ${normalizedPath.replace("../../", "src/")}`,
);
} else {
img = await file();
}
}
const imageClass = "w-full h-full object-cover";
const imageStyle = `object-position: ${position}`;
// 构建响应式图像属性
const responsiveProps = {
...(layout && { layout }),
...(widths && { widths }),
...(sizes && { sizes }),
...(quality && { quality }),
};
---
<div id={id} class:list={[className, 'overflow-hidden relative']}>
<div class="transition absolute inset-0 dark:bg-black/10 pointer-events-none"></div>
{isLocal && img && usePicture && (
<Picture
src={img}
alt={alt || ""}
class={imageClass}
style={imageStyle}
loading={loading}
fetchpriority={fetchpriority}
formats={formats}
fallbackFormat={fallbackFormat}
{...responsiveProps}
/>
)}
{isLocal && img && !usePicture && (
<Image
src={img}
alt={alt || ""}
class={imageClass}
style={imageStyle}
loading={loading}
fetchpriority={fetchpriority}
{...responsiveProps}
/>
)}
{!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle} loading={loading} fetchpriority={fetchpriority} />}
</div>
|