From 34ef0e1f22e71134600d33bfb29ce470f5ce43fb Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Mon, 22 Jun 2026 13:02:47 +0200 Subject: [PATCH] feat: manage skyline background media via payload --- src/SiteSettings/config.ts | 8 ++++++++ src/app/(frontend)/[[...slug]]/page.tsx | 2 +- src/payload-types.ts | 5 +++++ src/spa/components/ui/munich-skyline-bg.tsx | 21 ++++++++++++++------- src/spa/pages/Netzwerk.tsx | 4 +--- src/spa/siteSettings.ts | 3 +++ 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/SiteSettings/config.ts b/src/SiteSettings/config.ts index c66288f..1e9fb0d 100644 --- a/src/SiteSettings/config.ts +++ b/src/SiteSettings/config.ts @@ -11,6 +11,14 @@ export const SiteSettings: GlobalConfig = { group: 'Site Settings', }, fields: [ + { + name: 'skylineImage', + type: 'upload', + relationTo: 'media', + admin: { + description: `Current frontend fallback image: ${defaultSiteSettings.skylineImageUrl}`, + }, + }, { name: 'genericPageKicker', type: 'text', diff --git a/src/app/(frontend)/[[...slug]]/page.tsx b/src/app/(frontend)/[[...slug]]/page.tsx index b573701..e78f9f4 100644 --- a/src/app/(frontend)/[[...slug]]/page.tsx +++ b/src/app/(frontend)/[[...slug]]/page.tsx @@ -77,7 +77,7 @@ export default async function Page({ params }: Args) { const [header, footer, siteSettings, route, preistraeger, events, posts] = await Promise.all([ payload.findGlobal({ slug: 'header', depth: 1 }).catch(() => undefined), payload.findGlobal({ slug: 'footer', depth: 1 }).catch(() => undefined), - payload.findGlobal({ slug: 'site-settings', depth: 0 }).catch(() => undefined), + payload.findGlobal({ slug: 'site-settings', depth: 1 }).catch(() => undefined), findRouteDoc(payload, pathname, draft), findList(payload, 'preistraeger', draft).catch(() => []), findList(payload, 'events', draft).catch(() => []), diff --git a/src/payload-types.ts b/src/payload-types.ts index ccacc78..f1f46a0 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -5894,6 +5894,10 @@ export interface Footer { */ export interface SiteSetting { id: number; + /** + * Current frontend fallback image: /munich-skyline.jpg + */ + skylineImage?: (number | null) | Media; genericPageKicker: string; genericPageTitle: string; genericPageDescription: string; @@ -6026,6 +6030,7 @@ export interface FooterSelect { * via the `definition` "site-settings_select". */ export interface SiteSettingsSelect { + skylineImage?: T; genericPageKicker?: T; genericPageTitle?: T; genericPageDescription?: T; diff --git a/src/spa/components/ui/munich-skyline-bg.tsx b/src/spa/components/ui/munich-skyline-bg.tsx index bd19919..0f21e81 100644 --- a/src/spa/components/ui/munich-skyline-bg.tsx +++ b/src/spa/components/ui/munich-skyline-bg.tsx @@ -1,13 +1,23 @@ import React, { useEffect, useRef } from 'react'; +import { mediaUrl } from '@/spa/cmsMediaField'; +import { useCmsRoute } from '@/spa/cmsRoute'; +import { defaultSiteSettings } from '@/spa/siteSettings'; + /** * MunichSkylineBg * Drop inside any light section (position: relative required on parent). * Uses backgroundPositionY for parallax – no transform, no GPU compositing layer. * No mixBlendMode to avoid Safari compositing bleed into sibling elements. */ -const MunichSkylineBg: React.FC = () => { +const MunichSkylineBg: React.FC<{ height?: string | number; inset?: boolean; opacity?: number }> = ({ + height = '52%', + inset = false, + opacity = 0.08, +}) => { const ref = useRef(null); + const siteSettings = useCmsRoute()?.siteSettings || defaultSiteSettings; + const skylineImage = mediaUrl(siteSettings.skylineImage, siteSettings.skylineImageUrl); useEffect(() => { const el = ref.current; @@ -32,17 +42,14 @@ const MunichSkylineBg: React.FC = () => { aria-hidden="true" style={{ position: 'absolute', - bottom: 0, - left: 0, - right: 0, - height: '52%', + ...(inset ? { inset: 0 } : { bottom: 0, left: 0, right: 0, height }), pointerEvents: 'none', zIndex: 0, - backgroundImage: 'url(/munich-skyline.jpg)', + backgroundImage: `url(${skylineImage})`, backgroundRepeat: 'no-repeat', backgroundPosition: 'bottom center', backgroundSize: 'cover', - opacity: 0.08, + opacity, }} /> ); diff --git a/src/spa/pages/Netzwerk.tsx b/src/spa/pages/Netzwerk.tsx index 1fad51f..3681178 100644 --- a/src/spa/pages/Netzwerk.tsx +++ b/src/spa/pages/Netzwerk.tsx @@ -537,9 +537,7 @@ const Netzwerk: React.FC = () => { {/* ── 3. JURY-INTRO (editorial 2-col split) ────────────────────────────── */}
{!isMobile && } - {isMobile && ( -
- )} + {isMobile && } {isMobile ? ( /* Mobile: one cohesive navy module – copy + compact stat strip */
diff --git a/src/spa/siteSettings.ts b/src/spa/siteSettings.ts index 0ee94a2..4019dbc 100644 --- a/src/spa/siteSettings.ts +++ b/src/spa/siteSettings.ts @@ -2,12 +2,15 @@ export type SpaSiteSettingsData = { genericPageKicker: string genericPageTitle: string genericPageDescription: string + skylineImage?: unknown + skylineImageUrl: string } export const defaultSiteSettings: SpaSiteSettingsData = { genericPageKicker: 'CMS', genericPageTitle: 'Seite', genericPageDescription: 'Diese Route wird aus Payload CMS geladen. Ergänze Inhalte im entsprechenden Collection-Dokument.', + skylineImageUrl: '/munich-skyline.jpg', } export function normalizeSiteSettings(settings?: Partial | null): SpaSiteSettingsData {