feat: ship blog platform admin and deploy stack
This commit is contained in:
92
frontend/src/components/ui/ResponsiveImage.astro
Normal file
92
frontend/src/components/ui/ResponsiveImage.astro
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
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}
|
||||
Reference in New Issue
Block a user