Files
vue-journal-layer/app/components/Journal/FeaturedImage.vue
Jakub Zych 1080a3f0c4 feat: WebP and srcset for featured images
- JournalFeaturedImage renders <picture> from featured_images[].variants:
  a WebP source and the original format as srcset fallback, the
  original's width and height, alt; lazy in cards, eager with
  fetchpriority high on the post page; unchanged without variants
- app/utils/srcset.ts (imageSrcsets) with node tests
- acme fixtures and SSR expectations for both cases
2026-11-04 17:10:30 +01:00

38 lines
1.5 KiB
Vue

<script setup lang="ts">
// A post's featured image. With the API's variants (D-85) it renders a
// <picture>: a WebP <source> and the <img> in the original format, both
// with srcset and sizes; without them, the single <img> as before. The
// intrinsic width/height reserve space before the image loads; the
// rendered size and crop come from --journal-image-ratio. eager is the
// post's main image: loaded at once, with fetchpriority high when the
// variants are there; cards load lazily.
import type { JournalFeaturedImage } from '../../utils/types.ts'
import { imageSrcsets } from '../../utils/srcset.ts'
const props = withDefaults(
defineProps<{ src: string | null | undefined; alt: string; eager?: boolean; image?: JournalFeaturedImage | null; sizes?: string }>(),
{ eager: false, image: null, sizes: '100vw' },
)
const sets = computed(() => (props.src ? imageSrcsets(props.image?.variants, props.src) : null))
</script>
<template>
<figure v-if="src" class="journal-featured-image">
<picture v-if="sets">
<source type="image/webp" :srcset="sets.webp" :sizes="sizes" />
<img
:src="src"
:srcset="sets.original"
:sizes="sizes"
:width="sets.width"
:height="sets.height"
:alt="alt"
:loading="eager ? 'eager' : 'lazy'"
:fetchpriority="eager ? 'high' : undefined"
decoding="async"
/>
</picture>
<img v-else :src="src" :alt="alt" width="1200" height="630" :loading="eager ? 'eager' : 'lazy'" decoding="async" />
</figure>
</template>