feat(page): use topFullwidthBanner as og:image source
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:
@@ -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: [
|
||||
|
||||
Reference in New Issue
Block a user