Files
termi-blog/frontend/src/components/ui/ResponsiveImage.astro

93 lines
2.3 KiB
Plaintext

---
import {
buildOptimizedImageUrl,
buildOptimizedSrcSet,
canOptimizeImageSource,
getFallbackImageFormat,
getResponsiveWidths,
} from '../../lib/image';
interface Props {
src: string;
alt: string;
widths?: number[];
sizes?: string;
pictureClass?: string;
imgClass?: string;
loading?: 'lazy' | 'eager';
decoding?: 'async' | 'sync' | 'auto';
fetchpriority?: 'high' | 'low' | 'auto';
quality?: number;
lightbox?: boolean;
}
const {
src,
alt,
widths = [480, 768, 1024, 1440, 1920],
sizes = '100vw',
pictureClass = '',
imgClass = '',
loading = 'lazy',
decoding = 'async',
fetchpriority = 'auto',
quality = 72,
lightbox = false,
} = Astro.props;
const resolvedSrc = String(src || '').trim();
const normalizedWidths = getResponsiveWidths(widths);
const allowedHosts =
(import.meta.env.PUBLIC_IMAGE_ALLOWED_HOSTS as string | undefined) ||
process.env.PUBLIC_IMAGE_ALLOWED_HOSTS ||
'';
const optimize =
Boolean(resolvedSrc) &&
canOptimizeImageSource(resolvedSrc, Astro.url.origin, allowedHosts);
const fallbackFormat = getFallbackImageFormat(resolvedSrc);
const fallbackWidth = normalizedWidths[normalizedWidths.length - 1] ?? 1440;
const dataLightboxImage = lightbox ? 'true' : undefined;
---
{resolvedSrc ? (
optimize ? (
<picture class={pictureClass}>
<source
type="image/avif"
srcset={buildOptimizedSrcSet(resolvedSrc, normalizedWidths, 'avif', quality)}
sizes={sizes}
/>
<source
type="image/webp"
srcset={buildOptimizedSrcSet(resolvedSrc, normalizedWidths, 'webp', quality)}
sizes={sizes}
/>
<img
src={buildOptimizedImageUrl(resolvedSrc, {
width: fallbackWidth,
format: fallbackFormat,
quality,
})}
srcset={buildOptimizedSrcSet(resolvedSrc, normalizedWidths, fallbackFormat, quality)}
sizes={sizes}
alt={alt}
loading={loading}
decoding={decoding}
fetchpriority={fetchpriority}
data-lightbox-image={dataLightboxImage}
class={imgClass}
/>
</picture>
) : (
<img
src={resolvedSrc}
alt={alt}
loading={loading}
decoding={decoding}
fetchpriority={fetchpriority}
data-lightbox-image={dataLightboxImage}
class={imgClass}
/>
)
) : null}