From 055f0011745d201b912a554945e864581839a453 Mon Sep 17 00:00:00 2001 From: Peter Meier Date: Thu, 21 May 2026 15:14:41 +0200 Subject: [PATCH] feat(page): inline topImage field, fallback to topFullwidthBanner Reads page.topImage first (new direct image field on the page schema); falls back to legacy topFullwidthBanner.image during transition. Same ResponsiveImage build, social-image transform and warm-up as before. Banner-object still passed through so existing rendering keeps working when headline/subheadline/variant are wanted; pure-image migration needs no further code changes. Schema + 21 pages migrated CMS-side in the same change set. Co-Authored-By: Claude Sonnet 4.6 --- src/routes/[...slug]/+page.server.ts | 34 ++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/routes/[...slug]/+page.server.ts b/src/routes/[...slug]/+page.server.ts index 99c574f..966d9da 100644 --- a/src/routes/[...slug]/+page.server.ts +++ b/src/routes/[...slug]/+page.server.ts @@ -67,22 +67,26 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead ]); sanitizeBlocks(page); - // Resolve top banner if present + // Top-Bild: bevorzugt neues inline-Feld `topImage`, sonst Legacy via + // topFullwidthBanner-Referenz. Banner-Bild ist auch Social-Image-Quelle. 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 ?? []) - : (bannerRaw as { image?: unknown }).image != null - ? [(bannerRaw as { image?: unknown }).image] - : []; - if (bannerImages.length > 0) { - const primary = extractCmsImageField(bannerImages[0]); + + const topImageRaw = (page as { topImage?: unknown }).topImage; + const bannerRaw = (page as { topFullwidthBanner?: unknown }).topFullwidthBanner; + const topImageSource: unknown = + topImageRaw ?? + (bannerRaw && typeof bannerRaw === 'object' && 'image' in bannerRaw + ? (bannerRaw as { image?: unknown }).image + : undefined); + + if (topImageSource) { + const imageArr = Array.isArray(topImageSource) ? topImageSource : [topImageSource]; + if (imageArr.length > 0) { + const primary = extractCmsImageField(imageArr[0]); if (primary?.url) { topBannerFocalCss = focalToCss(primary.focal); topBannerResponsive = await buildResponsiveImage(primary.url, { @@ -101,7 +105,7 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead ? `${siteBaseUrl}${socialRel}` : socialRel; } - topBannerResolvedImages = await resolveImageUrls(bannerImages as string[], { + topBannerResolvedImages = await resolveImageUrls(imageArr as string[], { width: 2000, height: 750, fit: 'cover', @@ -125,9 +129,11 @@ export const load: PageServerLoad = async ({ params, locals, fetch, url, setHead { href: '/', label: 'Start' }, { label: page.headline ?? page.linkName ?? page.slug ?? page._slug ?? slug }, ], - topBanner: bannerRaw + topBanner: topImageSource ? { - banner: bannerRaw as import('$lib/cms').FullwidthBannerEntry | null, + banner: + (bannerRaw as import('$lib/cms').FullwidthBannerEntry | null) ?? + null, resolvedImages: topBannerResolvedImages, responsive: topBannerResponsive, focalCss: topBannerFocalCss,