feat: connect header and footer to cms as globals
This commit is contained in:
198
src/spa/cmsNavigation.ts
Normal file
198
src/spa/cmsNavigation.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import type { Media } from '@/payload-types'
|
||||
|
||||
export type SpaIconName = 'instagram' | 'linkedin' | 'facebook'
|
||||
export type SpaLink = { label: string; path: string }
|
||||
export type SpaSocialLink = { label: string; href: string; icon: SpaIconName }
|
||||
export type SpaCtaLink = SpaLink & { variant?: 'primary' | 'secondary' | 'subtle' | 'upload' }
|
||||
export type SpaMedia = { url?: string; alt?: string }
|
||||
|
||||
export type SpaHeaderNavItem = SpaLink & {
|
||||
key: string
|
||||
subLabel?: string
|
||||
sub?: SpaLink[]
|
||||
}
|
||||
|
||||
export type SpaHeaderData = {
|
||||
logo?: SpaMedia
|
||||
overlayKicker: string
|
||||
overlayHeadline: string
|
||||
overlayLogoAlt: string
|
||||
mobileWatermark: string
|
||||
menuLabel: string
|
||||
openLabel: string
|
||||
closeLabel: string
|
||||
overviewLabel: string
|
||||
navItems: SpaHeaderNavItem[]
|
||||
secondaryLinks: SpaLink[]
|
||||
socialLinks: SpaSocialLink[]
|
||||
ctas: SpaCtaLink[]
|
||||
languages: string[]
|
||||
}
|
||||
|
||||
export type SpaFooterLinkColumn = { label: string; links: SpaLink[] }
|
||||
export type SpaPartnerLogo = { image?: SpaMedia; alt: string }
|
||||
|
||||
export type SpaFooterData = {
|
||||
logo?: SpaMedia
|
||||
logoAlt: string
|
||||
headlinePrefix: string
|
||||
headlineAccent: string
|
||||
headlineSuffix: string
|
||||
sinceLabel: string
|
||||
year: string
|
||||
description: string
|
||||
ctas: SpaCtaLink[]
|
||||
linkColumns: SpaFooterLinkColumn[]
|
||||
partnerLabel: string
|
||||
partnerLogos: SpaPartnerLogo[]
|
||||
copyright: string
|
||||
socialLinks: SpaSocialLink[]
|
||||
}
|
||||
|
||||
export const defaultSocialLinks: SpaSocialLink[] = [
|
||||
{ href: 'https://instagram.com', icon: 'instagram', label: 'Instagram' },
|
||||
{ href: 'https://linkedin.com', icon: 'linkedin', label: 'LinkedIn' },
|
||||
{ href: 'https://facebook.com', icon: 'facebook', label: 'Facebook' },
|
||||
]
|
||||
|
||||
export const defaultHeaderData: SpaHeaderData = {
|
||||
logo: { url: '/bmp-logo.png', alt: 'Der Bayerische Mittelstandspreis 2026' },
|
||||
overlayKicker: 'Bayerischer Mittelstandspreis',
|
||||
overlayHeadline: 'EXZELLENZ HAT\nEINEN NAMEN.',
|
||||
overlayLogoAlt: 'BMP Logo',
|
||||
mobileWatermark: 'Exzellenz\nseit 2005',
|
||||
menuLabel: 'Menü',
|
||||
openLabel: 'Navigation öffnen',
|
||||
closeLabel: 'Menü schließen',
|
||||
overviewLabel: 'Überblick',
|
||||
languages: ['DE', 'EN'],
|
||||
socialLinks: defaultSocialLinks,
|
||||
navItems: [
|
||||
{
|
||||
key: 'preistraeger', label: 'Preisträger:innen', path: '/preistraeger', subLabel: 'PREISTRÄGER:INNEN',
|
||||
sub: [
|
||||
{ label: 'Alle Preisträger:innen', path: '/preistraeger' },
|
||||
{ label: 'Sieger & Aufsteiger 2025', path: '/preistraeger' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'teilnahme', label: 'Ihr Weg zum Preis', path: '/teilnahme', subLabel: 'IHR WEG ZUM PREIS',
|
||||
sub: [
|
||||
{ label: 'Teilnahmevoraussetzungen', path: '/teilnahme#voraussetzungen' },
|
||||
{ label: 'Kriterien & Bewertung', path: '/teilnahme#kriterien' },
|
||||
{ label: 'Fristen & Termine', path: '/teilnahme#fristen' },
|
||||
{ label: 'Bewerbungsformular', path: '/teilnahme#bewerben' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'bmp', label: 'Der BMP', path: '/der-bmp', subLabel: 'DER BMP',
|
||||
sub: [
|
||||
{ label: 'Was ist der Preis?', path: '/der-bmp#was-ist' },
|
||||
{ label: 'Geschichte & Werte', path: '/der-bmp#geschichte' },
|
||||
{ label: 'Vorteile der Auszeichnung', path: '/der-bmp#vorteile' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'netzwerk', label: 'Netzwerk', path: '/netzwerk', subLabel: 'NETZWERK',
|
||||
sub: [
|
||||
{ label: 'Jury-Mitglieder', path: '/netzwerk#jury' },
|
||||
{ label: 'Partner & Sponsoren', path: '/netzwerk#partner' },
|
||||
{ label: 'Schirmherrschaft', path: '/netzwerk#schirmherrschaft' },
|
||||
{ label: 'Mitglied werden', path: '/mitglied-werden' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'presse', label: 'Presse', path: '/presse', subLabel: 'PRESSE',
|
||||
sub: [
|
||||
{ label: 'Events & Gala', path: '/presse#events' },
|
||||
{ label: 'Downloads & Impressionen', path: '/presse#downloads' },
|
||||
],
|
||||
},
|
||||
],
|
||||
secondaryLinks: [
|
||||
{ label: 'Startseite', path: '/' },
|
||||
{ label: 'Kontakt', path: '/kontakt' },
|
||||
{ label: 'Impressum', path: '/impressum' },
|
||||
{ label: 'Datenschutz', path: '/datenschutz' },
|
||||
],
|
||||
ctas: [
|
||||
{ label: 'Jetzt bewerben', path: '/teilnahme#bewerben', variant: 'primary' },
|
||||
{ label: 'Mitglied werden', path: '/mitglied-werden', variant: 'secondary' },
|
||||
{ label: 'Formular hochladen', path: '/formular-hochladen', variant: 'upload' },
|
||||
],
|
||||
}
|
||||
|
||||
export const defaultFooterData: SpaFooterData = {
|
||||
logo: { url: '/bmp-logo.png', alt: 'Bayerischer Mittelstandspreis' },
|
||||
logoAlt: 'Bayerischer Mittelstandspreis',
|
||||
headlinePrefix: 'Der Preis des',
|
||||
headlineAccent: 'Bayerischen',
|
||||
headlineSuffix: 'Mittelstands',
|
||||
sinceLabel: 'Exzellenz seit 2005',
|
||||
year: '2026',
|
||||
description: 'Die renommierteste Auszeichnung für herausragende Unternehmen des bayerischen Mittelstands.',
|
||||
ctas: [
|
||||
{ label: 'Kostenlos bewerben', path: '/teilnahme#bewerben', variant: 'primary' },
|
||||
{ label: 'Mitglied werden', path: '/mitglied-werden', variant: 'secondary' },
|
||||
{ label: 'Sponsoring-Anfrage →', path: '/netzwerk#sponsoring', variant: 'subtle' },
|
||||
],
|
||||
linkColumns: [
|
||||
{ label: 'BMP 2026', links: [
|
||||
{ label: 'Startseite', path: '/' },
|
||||
{ label: 'Preisträger', path: '/preistraeger' },
|
||||
{ label: 'Teilnahme', path: '/teilnahme' },
|
||||
] },
|
||||
{ label: 'Engagement', links: [
|
||||
{ label: 'Netzwerk & Jury', path: '/netzwerk' },
|
||||
{ label: 'Presse', path: '/presse' },
|
||||
{ label: 'Kontakt', path: '/kontakt' },
|
||||
] },
|
||||
{ label: 'Legal', links: [
|
||||
{ label: 'Datenschutz', path: '/datenschutz' },
|
||||
{ label: 'Impressum', path: '/impressum' },
|
||||
] },
|
||||
],
|
||||
partnerLabel: 'Partner',
|
||||
partnerLogos: [
|
||||
{ alt: 'EWIF – Europäisches Wirtschaftsforum', image: { url: '/images/ewif-logo.png' } },
|
||||
{ alt: 'Hochschule für angewandtes Management · Gipfeldialog Altaussee', image: { url: '/images/partner-logos.png' } },
|
||||
],
|
||||
copyright: '© 2026 Bayerischer Mittelstandspreis · Alle Rechte vorbehalten',
|
||||
socialLinks: defaultSocialLinks,
|
||||
}
|
||||
|
||||
const isMedia = (value: unknown): value is Media => Boolean(value && typeof value === 'object' && 'url' in value)
|
||||
const mediaToSpa = (value: unknown, fallback?: SpaMedia): SpaMedia | undefined => {
|
||||
if (isMedia(value)) return { url: value.url || fallback?.url, alt: value.alt || fallback?.alt }
|
||||
return fallback
|
||||
}
|
||||
|
||||
export function normalizeHeaderData(header: any): SpaHeaderData {
|
||||
return {
|
||||
...defaultHeaderData,
|
||||
...header,
|
||||
logo: mediaToSpa(header?.logo, defaultHeaderData.logo),
|
||||
navItems: header?.navItems?.length ? header.navItems : defaultHeaderData.navItems,
|
||||
secondaryLinks: header?.secondaryLinks?.length ? header.secondaryLinks : defaultHeaderData.secondaryLinks,
|
||||
socialLinks: header?.socialLinks?.length ? header.socialLinks : defaultHeaderData.socialLinks,
|
||||
ctas: header?.ctas?.length ? header.ctas : defaultHeaderData.ctas,
|
||||
languages: header?.languages?.length ? header.languages.map((item: any) => item.label || item).filter(Boolean) : defaultHeaderData.languages,
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeFooterData(footer: any): SpaFooterData {
|
||||
return {
|
||||
...defaultFooterData,
|
||||
...footer,
|
||||
logo: mediaToSpa(footer?.logo, defaultFooterData.logo),
|
||||
ctas: footer?.ctas?.length ? footer.ctas : defaultFooterData.ctas,
|
||||
linkColumns: footer?.linkColumns?.length ? footer.linkColumns : defaultFooterData.linkColumns,
|
||||
socialLinks: footer?.socialLinks?.length ? footer.socialLinks : defaultFooterData.socialLinks,
|
||||
partnerLogos: footer?.partnerLogos?.length
|
||||
? footer.partnerLogos.map((item: any, index: number) => ({
|
||||
alt: item.alt || defaultFooterData.partnerLogos[index]?.alt || '',
|
||||
image: mediaToSpa(item.image, defaultFooterData.partnerLogos[index]?.image),
|
||||
}))
|
||||
: defaultFooterData.partnerLogos,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user