feat(page): use topFullwidthBanner as og:image source
Deploy / verify (push) Successful in 55s
Deploy / deploy (push) Successful in 1m4s

Pages now expose `socialImage` from the topFullwidthBanner field —
same 1200×630 cover transform with focal-aware crop that posts already
use. Layout meta-tag pipeline picks it up automatically; pages without
a banner still fall back to the global default social image.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-05-21 15:06:48 +02:00
parent 6a1069f908
commit c329658992
+15 -1
View File
@@ -2,6 +2,7 @@ import type { PageServerLoad } from './$types';
import { getPageBySlug } from '$lib/cms';
import {
extractCmsImageField,
ensureTransformedImage,
resolveContentImages,
resolveImageUrls,
} from '$lib/rusty-image';
@@ -12,7 +13,8 @@ import {
resolveCalendarBlocks,
resolveDeadlineBannerBlocks,
} from '$lib/blog-utils';
import { PAGE_RESOLVE } from '$lib/constants';
import { PAGE_RESOLVE, POST_SOCIAL_IMAGE_TRANSFORM } from '$lib/constants';
import { env } from '$env/dynamic/public';
import { error } from '@sveltejs/kit';
import { sanitizeBlocks } from '$lib/sanitize-blocks.server';
@@ -69,7 +71,10 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead
let topBannerResolvedImages: string[] = [];
let topBannerResponsive: ResponsiveImage | null = null;
let topBannerFocalCss: string | null = null;
// Banner-Bild ist auch unsere Social-Image-Quelle (1200×630 cover, mit Focal).
let pageSocialImageAbs: string | null = null;
const bannerRaw = (page as { topFullwidthBanner?: unknown }).topFullwidthBanner;
const siteBaseUrl = (env.PUBLIC_SITE_URL || '').replace(/\/$/, '');
if (bannerRaw && typeof bannerRaw === 'object' && 'image' in bannerRaw) {
const bannerImages = Array.isArray((bannerRaw as { image?: unknown }).image)
? ((bannerRaw as { image?: unknown[] }).image ?? [])
@@ -87,6 +92,14 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead
quality: 72,
focal: primary.focal,
});
const socialRel = ensureTransformedImage(primary.url, {
...POST_SOCIAL_IMAGE_TRANSFORM,
focalX: primary.focal?.x,
focalY: primary.focal?.y,
});
pageSocialImageAbs = socialRel.startsWith('/')
? `${siteBaseUrl}${socialRel}`
: socialRel;
}
topBannerResolvedImages = await resolveImageUrls(bannerImages as string[], {
width: 2000,
@@ -105,6 +118,7 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead
previewDraft: !!previewDraft,
seoTitle: page.seoTitle ?? page.headline ?? page.linkName ?? slug,
seoDescription: page.seoDescription ?? page.subheadline ?? '',
socialImage: pageSocialImageAbs ?? undefined,
robots: (page as { seoMetaRobots?: string }).seoMetaRobots ?? undefined,
keywords: (page as { seoKeywords?: string }).seoKeywords ?? undefined,
breadcrumbItems: [