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>