feat: connect header and footer to cms as globals

This commit is contained in:
syntaxbullet
2026-06-16 14:25:58 +02:00
parent 6b395e5735
commit cde2164773
13 changed files with 842 additions and 456 deletions

View File

@@ -1,29 +1,122 @@
import type { GlobalConfig } from 'payload'
import { link } from '@/fields/link'
import { revalidateFooter } from './hooks/revalidateFooter'
import { defaultFooterData } from '@/spa/cmsNavigation'
const linkFields = [
{ name: 'label', type: 'text' as const, required: true },
{ name: 'path', type: 'text' as const, required: true },
]
const socialFields = [
{ name: 'label', type: 'text' as const, required: true },
{ name: 'href', type: 'text' as const, required: true },
{
name: 'icon',
type: 'select' as const,
required: true,
options: [
{ label: 'Instagram', value: 'instagram' },
{ label: 'LinkedIn', value: 'linkedin' },
{ label: 'Facebook', value: 'facebook' },
],
},
]
export const Footer: GlobalConfig = {
slug: 'footer',
access: {
read: () => true,
},
admin: {
livePreview: {
url: () => '/',
},
preview: () => '/',
},
fields: [
{
name: 'navItems',
type: 'array',
fields: [
link({
appearances: false,
}),
],
maxRows: 6,
admin: {
initCollapsed: true,
components: {
RowLabel: '@/Footer/RowLabel#RowLabel',
type: 'tabs',
tabs: [
{
label: 'Brand & Copy',
fields: [
{ name: 'logo', type: 'upload', relationTo: 'media', admin: { description: 'Falls leer, wird /bmp-logo.png verwendet.' } },
{ name: 'logoAlt', type: 'text', defaultValue: defaultFooterData.logoAlt, required: true },
{ name: 'headlinePrefix', type: 'text', defaultValue: defaultFooterData.headlinePrefix, required: true },
{ name: 'headlineAccent', type: 'text', defaultValue: defaultFooterData.headlineAccent, required: true },
{ name: 'headlineSuffix', type: 'text', defaultValue: defaultFooterData.headlineSuffix, required: true },
{ name: 'sinceLabel', type: 'text', defaultValue: defaultFooterData.sinceLabel, required: true },
{ name: 'year', type: 'text', defaultValue: defaultFooterData.year, required: true },
{ name: 'description', type: 'textarea', defaultValue: defaultFooterData.description, required: true },
{ name: 'copyright', type: 'text', defaultValue: defaultFooterData.copyright, required: true },
],
},
},
{
label: 'Links',
fields: [
{
name: 'ctas',
label: 'CTA links',
type: 'array',
defaultValue: defaultFooterData.ctas,
fields: [
...linkFields,
{
name: 'variant',
type: 'select',
defaultValue: 'primary',
options: [
{ label: 'Primary gold button', value: 'primary' },
{ label: 'Secondary outline button', value: 'secondary' },
{ label: 'Subtle text link', value: 'subtle' },
],
},
],
maxRows: 4,
admin: { initCollapsed: true },
},
{
name: 'linkColumns',
type: 'array',
defaultValue: defaultFooterData.linkColumns,
fields: [
{ name: 'label', type: 'text', required: true },
{ name: 'links', type: 'array', fields: linkFields, required: true, admin: { initCollapsed: true } },
],
maxRows: 4,
admin: {
initCollapsed: true,
components: {
RowLabel: '@/Footer/RowLabel#RowLabel',
},
},
},
],
},
{
label: 'Partner & Social',
fields: [
{ name: 'partnerLabel', type: 'text', defaultValue: defaultFooterData.partnerLabel, required: true },
{
name: 'partnerLogos',
type: 'array',
fields: [
{ name: 'image', type: 'upload', relationTo: 'media', required: true },
{ name: 'alt', type: 'text', required: true },
],
admin: { initCollapsed: true },
},
{
name: 'socialLinks',
type: 'array',
defaultValue: defaultFooterData.socialLinks,
fields: socialFields,
admin: { initCollapsed: true },
},
],
},
],
},
],
hooks: {