Files
bmp-website-2026/src/spa/cmsNavigation.ts
2026-06-17 17:41:21 +02:00

220 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Footer, Header, 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
}
type HeaderLanguage = string | { label?: string }
type FooterPartnerLogo = {
alt?: string
image?: unknown
}
export function normalizeHeaderData(header?: Partial<Header>): SpaHeaderData {
return {
...defaultHeaderData,
...header,
logo: mediaToSpa(header?.logo, defaultHeaderData.logo),
navItems: header?.navItems?.length
? (header.navItems as unknown as SpaHeaderNavItem[])
: defaultHeaderData.navItems,
secondaryLinks: header?.secondaryLinks?.length
? (header.secondaryLinks as unknown as SpaLink[])
: defaultHeaderData.secondaryLinks,
socialLinks: header?.socialLinks?.length
? (header.socialLinks as unknown as SpaSocialLink[])
: defaultHeaderData.socialLinks,
ctas: header?.ctas?.length ? (header.ctas as unknown as SpaCtaLink[]) : defaultHeaderData.ctas,
languages: header?.languages?.length
? (header.languages as HeaderLanguage[])
.map((item) => (typeof item === 'string' ? item : item.label))
.filter((label): label is string => Boolean(label))
: defaultHeaderData.languages,
}
}
export function normalizeFooterData(footer?: Partial<Footer>): SpaFooterData {
return {
...defaultFooterData,
...footer,
logo: mediaToSpa(footer?.logo, defaultFooterData.logo),
ctas: footer?.ctas?.length ? (footer.ctas as unknown as SpaCtaLink[]) : defaultFooterData.ctas,
linkColumns: footer?.linkColumns?.length
? (footer.linkColumns as unknown as SpaFooterData['linkColumns'])
: defaultFooterData.linkColumns,
socialLinks: footer?.socialLinks?.length
? (footer.socialLinks as unknown as SpaSocialLink[])
: defaultFooterData.socialLinks,
partnerLogos: footer?.partnerLogos?.length
? (footer.partnerLogos as FooterPartnerLogo[]).map((item, index) => ({
alt: item.alt || defaultFooterData.partnerLogos[index]?.alt || '',
image: mediaToSpa(item.image, defaultFooterData.partnerLogos[index]?.image),
}))
: defaultFooterData.partnerLogos,
}
}