master
1---
2import { buildConfig } from '@/config';
3import { getCachedRemoteImageSize } from '@/utils/image-size-cache';
4import type { ImageMetadata } from 'astro';
5import { Image } from 'astro:assets';
6import path from 'path';
7
8interface Props {
9 id?: string;
10 src: ImageMetadata | string;
11 class?: string;
12 alt?: string;
13 position?: string;
14 basePath?: string;
15}
16
17const { id, src, alt, position = 'center', basePath = '/' } = Astro.props;
18const className = Astro.props.class;
19
20const isLocal =
21 typeof src !== 'string' ||
22 !(
23 src.startsWith('/') ||
24 src.startsWith('http') ||
25 src.startsWith('https') ||
26 src.startsWith('data:')
27 );
28const isPublic = typeof src === 'string' && src.startsWith('/');
29const isRemote = !isLocal && !isPublic;
30
31let img: ImageMetadata | undefined;
32if (isLocal) {
33 if (typeof src === 'string') {
34 const files = import.meta.glob<ImageMetadata>(
35 '../../**/*.{png,jpg,jpeg,tiff,webp,gif,svg,avif,jfif,pjpeg,pjp,ico}',
36 {
37 import: 'default',
38 }
39 );
40 let normalizedPath = path.normalize(path.join('../../', basePath, src)).replace(/\\/g, '/');
41 const file = files[normalizedPath];
42 if (!file) {
43 console.error(
44 `\n[ERROR] Image file not found: ${normalizedPath.replace('../../', 'src/')}`
45 );
46 }
47 img = await file();
48 } else {
49 img = src;
50 }
51}
52
53let w, h;
54if (isRemote && buildConfig.inferRemoteImageSize.enable) {
55 const dimensions = await getCachedRemoteImageSize(src);
56 if (dimensions) {
57 w = dimensions.width;
58 h = dimensions.height;
59 } else {
60 w = buildConfig.inferRemoteImageSize.defaultSize.width;
61 h = buildConfig.inferRemoteImageSize.defaultSize.height;
62 }
63} else {
64 w = buildConfig.inferRemoteImageSize.defaultSize.width;
65 h = buildConfig.inferRemoteImageSize.defaultSize.height;
66}
67
68const imageClass = 'w-full h-full object-cover';
69const imageStyle = `object-position: ${position}`;
70---
71
72<div id={id} class:list={[className, 'relative overflow-hidden']}>
73 {isLocal && img && <Image src={img} alt={alt || ''} class={imageClass} style={imageStyle} />}
74 {
75 isRemote && (
76 <Image
77 src={src as string}
78 alt={alt || ''}
79 class={imageClass}
80 style={imageStyle}
81 width={w}
82 height={h}
83 />
84 )
85 }
86 {
87 !isLocal && isPublic && (
88 <img
89 src={new URL(src, Astro.site) as unknown as string}
90 alt={alt || ''}
91 class={imageClass}
92 style={imageStyle}
93 width={w}
94 height={h}
95 loading="lazy"
96 decoding="async"
97 />
98 )
99 }
100</div>