feat: manage skyline background media via payload
This commit is contained in:
@@ -11,6 +11,14 @@ export const SiteSettings: GlobalConfig = {
|
|||||||
group: 'Site Settings',
|
group: 'Site Settings',
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'skylineImage',
|
||||||
|
type: 'upload',
|
||||||
|
relationTo: 'media',
|
||||||
|
admin: {
|
||||||
|
description: `Current frontend fallback image: ${defaultSiteSettings.skylineImageUrl}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'genericPageKicker',
|
name: 'genericPageKicker',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export default async function Page({ params }: Args) {
|
|||||||
const [header, footer, siteSettings, route, preistraeger, events, posts] = await Promise.all([
|
const [header, footer, siteSettings, route, preistraeger, events, posts] = await Promise.all([
|
||||||
payload.findGlobal({ slug: 'header', depth: 1 }).catch(() => undefined),
|
payload.findGlobal({ slug: 'header', depth: 1 }).catch(() => undefined),
|
||||||
payload.findGlobal({ slug: 'footer', 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),
|
findRouteDoc(payload, pathname, draft),
|
||||||
findList(payload, 'preistraeger', draft).catch(() => []),
|
findList(payload, 'preistraeger', draft).catch(() => []),
|
||||||
findList(payload, 'events', draft).catch(() => []),
|
findList(payload, 'events', draft).catch(() => []),
|
||||||
|
|||||||
@@ -5894,6 +5894,10 @@ export interface Footer {
|
|||||||
*/
|
*/
|
||||||
export interface SiteSetting {
|
export interface SiteSetting {
|
||||||
id: number;
|
id: number;
|
||||||
|
/**
|
||||||
|
* Current frontend fallback image: /munich-skyline.jpg
|
||||||
|
*/
|
||||||
|
skylineImage?: (number | null) | Media;
|
||||||
genericPageKicker: string;
|
genericPageKicker: string;
|
||||||
genericPageTitle: string;
|
genericPageTitle: string;
|
||||||
genericPageDescription: string;
|
genericPageDescription: string;
|
||||||
@@ -6026,6 +6030,7 @@ export interface FooterSelect<T extends boolean = true> {
|
|||||||
* via the `definition` "site-settings_select".
|
* via the `definition` "site-settings_select".
|
||||||
*/
|
*/
|
||||||
export interface SiteSettingsSelect<T extends boolean = true> {
|
export interface SiteSettingsSelect<T extends boolean = true> {
|
||||||
|
skylineImage?: T;
|
||||||
genericPageKicker?: T;
|
genericPageKicker?: T;
|
||||||
genericPageTitle?: T;
|
genericPageTitle?: T;
|
||||||
genericPageDescription?: T;
|
genericPageDescription?: T;
|
||||||
|
|||||||
@@ -1,13 +1,23 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import { mediaUrl } from '@/spa/cmsMediaField';
|
||||||
|
import { useCmsRoute } from '@/spa/cmsRoute';
|
||||||
|
import { defaultSiteSettings } from '@/spa/siteSettings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MunichSkylineBg
|
* MunichSkylineBg
|
||||||
* Drop inside any light section (position: relative required on parent).
|
* Drop inside any light section (position: relative required on parent).
|
||||||
* Uses backgroundPositionY for parallax – no transform, no GPU compositing layer.
|
* Uses backgroundPositionY for parallax – no transform, no GPU compositing layer.
|
||||||
* No mixBlendMode to avoid Safari compositing bleed into sibling elements.
|
* 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<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const siteSettings = useCmsRoute()?.siteSettings || defaultSiteSettings;
|
||||||
|
const skylineImage = mediaUrl(siteSettings.skylineImage, siteSettings.skylineImageUrl);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = ref.current;
|
const el = ref.current;
|
||||||
@@ -32,17 +42,14 @@ const MunichSkylineBg: React.FC = () => {
|
|||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 0,
|
...(inset ? { inset: 0 } : { bottom: 0, left: 0, right: 0, height }),
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
height: '52%',
|
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
zIndex: 0,
|
zIndex: 0,
|
||||||
backgroundImage: 'url(/munich-skyline.jpg)',
|
backgroundImage: `url(${skylineImage})`,
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
backgroundPosition: 'bottom center',
|
backgroundPosition: 'bottom center',
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
opacity: 0.08,
|
opacity,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -537,9 +537,7 @@ const Netzwerk: React.FC = () => {
|
|||||||
{/* ── 3. JURY-INTRO (editorial 2-col split) ────────────────────────────── */}
|
{/* ── 3. JURY-INTRO (editorial 2-col split) ────────────────────────────── */}
|
||||||
<section style={{ display: isMobile ? 'block' : 'grid', gridTemplateColumns: isMobile ? undefined : '40% 60%', minHeight: isMobile ? 'auto' : 400, position: 'relative', overflow: 'hidden', isolation: 'isolate', background: isMobile ? NAVY : undefined }}>
|
<section style={{ display: isMobile ? 'block' : 'grid', gridTemplateColumns: isMobile ? undefined : '40% 60%', minHeight: isMobile ? 'auto' : 400, position: 'relative', overflow: 'hidden', isolation: 'isolate', background: isMobile ? NAVY : undefined }}>
|
||||||
{!isMobile && <MunichSkylineBg />}
|
{!isMobile && <MunichSkylineBg />}
|
||||||
{isMobile && (
|
{isMobile && <MunichSkylineBg inset opacity={0.07} />}
|
||||||
<div aria-hidden style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 0, backgroundImage: 'url(/munich-skyline.jpg)', backgroundRepeat: 'no-repeat', backgroundPosition: 'bottom center', backgroundSize: 'cover', opacity: 0.07 }} />
|
|
||||||
)}
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
/* Mobile: one cohesive navy module – copy + compact stat strip */
|
/* Mobile: one cohesive navy module – copy + compact stat strip */
|
||||||
<div style={{ padding: '48px 24px', position: 'relative', zIndex: 1 }}>
|
<div style={{ padding: '48px 24px', position: 'relative', zIndex: 1 }}>
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ export type SpaSiteSettingsData = {
|
|||||||
genericPageKicker: string
|
genericPageKicker: string
|
||||||
genericPageTitle: string
|
genericPageTitle: string
|
||||||
genericPageDescription: string
|
genericPageDescription: string
|
||||||
|
skylineImage?: unknown
|
||||||
|
skylineImageUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultSiteSettings: SpaSiteSettingsData = {
|
export const defaultSiteSettings: SpaSiteSettingsData = {
|
||||||
genericPageKicker: 'CMS',
|
genericPageKicker: 'CMS',
|
||||||
genericPageTitle: 'Seite',
|
genericPageTitle: 'Seite',
|
||||||
genericPageDescription: 'Diese Route wird aus Payload CMS geladen. Ergänze Inhalte im entsprechenden Collection-Dokument.',
|
genericPageDescription: 'Diese Route wird aus Payload CMS geladen. Ergänze Inhalte im entsprechenden Collection-Dokument.',
|
||||||
|
skylineImageUrl: '/munich-skyline.jpg',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeSiteSettings(settings?: Partial<SpaSiteSettingsData> | null): SpaSiteSettingsData {
|
export function normalizeSiteSettings(settings?: Partial<SpaSiteSettingsData> | null): SpaSiteSettingsData {
|
||||||
|
|||||||
Reference in New Issue
Block a user