Files
ink-website/src/components/Screenshot.astro
T
Your Name 9e6804c1ab
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Initial commit
2026-10-11 18:09:42 +02:00

77 lines
2.7 KiB
Plaintext

---
import { getImage } from 'astro:assets';
import type { ImageMetadata } from 'astro';
import { screens, type ScreenName } from '../lib/screens';
interface Props {
name: ScreenName;
/** Above the fold: load immediately with high priority. */
priority?: boolean;
sizes?: string;
/** Override the default alt text. */
alt?: string;
class?: string;
}
const { name, priority = false, sizes = '(min-width: 1160px) 1120px, 100vw', alt, class: className } = Astro.props;
const spec = screens[name];
const files = import.meta.glob<{ default: ImageMetadata }>('/src/assets/screens/*.{png,jpg,jpeg,webp,svg}', { eager: true });
const raster = ['png', 'webp', 'jpg', 'jpeg'];
/** Real captures (png/webp/jpg) beat placeholder SVGs; `<name>-<theme>` beats a bare `<name>`. */
function pick(theme: 'dark' | 'light'): ImageMetadata {
const tries = [
...raster.map((e) => `${name}-${theme}.${e}`),
...raster.map((e) => `${name}.${e}`),
`${name}-${theme}.svg`,
`${name}.svg`,
];
for (const t of tries) {
const hit = files[`/src/assets/screens/${t}`];
if (hit) return hit.default;
}
throw new Error(`No screenshot found for "${name}" (${theme}) in src/assets/screens/`);
}
/** Optimised webp srcset for real captures; SVG placeholders pass through untouched. */
async function sources(img: ImageMetadata) {
if (img.format === 'svg') return { src: img.src, srcset: img.src };
const widths = [720, 1200, 1600, 2400].filter((w) => w < img.width).concat(img.width);
const out = await getImage({ src: img, widths, format: 'webp' });
return { src: out.src, srcset: out.srcSet.attribute };
}
const darkImg = pick('dark');
const dark = await sources(darkImg);
const light = await sources(pick('light'));
---
<figure class:list={['shot', className]}>
<div class="view">
<!-- The theme follows the system, so the browser fetches only the matching variant. -->
<picture>
<source media="(prefers-color-scheme: light)" srcset={light.srcset} sizes={sizes} />
<img
src={dark.src}
srcset={dark.srcset}
sizes={sizes}
width={darkImg.width}
height={darkImg.height}
alt={alt ?? spec.alt}
loading={priority ? 'eager' : 'lazy'}
fetchpriority={priority ? 'high' : undefined}
decoding={priority ? 'sync' : 'async'}
/>
</picture>
</div>
</figure>
<style>
.shot {
margin: 0; border-radius: 14px; overflow: hidden; background: var(--surface);
border: 1px solid var(--line-2); box-shadow: var(--shadow);
}
.view { aspect-ratio: 16 / 10; background: var(--bg); }
.view picture { display: block; width: 100%; height: 100%; }
.view img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 520px) {
.shot { border-radius: 10px; }
}
</style>