import type { PageServerLoad } from './$types'; import { getPageBySlug } from '$lib/cms'; import { extractCmsImageField, resolveContentImages, resolveImageUrls, } from '$lib/rusty-image'; import { buildResponsiveImage, type ResponsiveImage } from '$lib/rusty-image.server'; import { resolvePostOverviewBlocks, resolveSearchableTextBlocks, resolveCalendarBlocks, } from '$lib/blog-utils'; import { PAGE_RESOLVE } from '$lib/constants'; import { error } from '@sveltejs/kit'; const BANNER_WIDTHS = [640, 960, 1280, 1600, 1920, 2400]; function focalToCss(focal: { x: number; y: number } | undefined): string | null { if (!focal) return null; return `${(focal.x * 100).toFixed(2)}% ${(focal.y * 100).toFixed(2)}%`; } export const load: PageServerLoad = async ({ params, locals }) => { const { slug } = params; const translations = locals.translations ?? {}; const page = await getPageBySlug(slug, { locale: 'de', resolve: PAGE_RESOLVE, }); if (!page) { error(404, 'Seite nicht gefunden'); } await resolveContentImages(page); const tagsMap = await resolvePostOverviewBlocks(page); await resolveSearchableTextBlocks(page, tagsMap); await resolveCalendarBlocks(page); // Resolve top banner if present let topBannerResolvedImages: string[] = []; let topBannerResponsive: ResponsiveImage | null = null; let topBannerFocalCss: string | null = null; const bannerRaw = (page as { topFullwidthBanner?: unknown }).topFullwidthBanner; 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]); if (primary?.url) { topBannerFocalCss = focalToCss(primary.focal); topBannerResponsive = await buildResponsiveImage(primary.url, { widths: BANNER_WIDTHS, fit: 'contain', formats: ['avif', 'webp', 'jpeg'], quality: 78, focal: primary.focal, }); } topBannerResolvedImages = await resolveImageUrls(bannerImages as string[], { width: 2000, height: 750, fit: 'cover', format: 'webp', }); } } return { page, translations, seoTitle: page.seoTitle ?? page.headline ?? page.linkName ?? slug, seoDescription: page.seoDescription ?? page.subheadline ?? '', breadcrumbItems: [ { href: '/', label: 'Start' }, { label: page.headline ?? page.linkName ?? page.slug ?? page._slug ?? slug }, ], topBanner: bannerRaw ? { banner: bannerRaw as import('$lib/cms').FullwidthBannerEntry | null, resolvedImages: topBannerResolvedImages, responsive: topBannerResponsive, focalCss: topBannerFocalCss, headline: page.headline ?? undefined, subheadline: page.subheadline ?? undefined, } : null, }; };