feat(page): inline topImage field, fallback to topFullwidthBanner
Deploy / verify (push) Successful in 1m3s
Deploy / deploy (push) Successful in 1m4s

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 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-05-21 15:14:41 +02:00
parent c329658992
commit 055f001174
+20 -14
View File
@@ -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,