feat: manage about page via payload
This commit is contained in:
254
src/collections/Pages/aboutFields.ts
Normal file
254
src/collections/Pages/aboutFields.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import type { Field } from 'payload'
|
||||
|
||||
import { aboutContent } from '@/spa/aboutContent'
|
||||
|
||||
const uploadField = (name: string, label: string, description?: string): Field => ({
|
||||
name,
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label,
|
||||
admin: description ? { description } : undefined,
|
||||
})
|
||||
|
||||
const text = (name: string, label: string, defaultValue?: string): Field => ({
|
||||
name,
|
||||
type: 'text',
|
||||
label,
|
||||
defaultValue,
|
||||
})
|
||||
|
||||
const textarea = (name: string, label: string, defaultValue?: string): Field => ({
|
||||
name,
|
||||
type: 'textarea',
|
||||
label,
|
||||
defaultValue,
|
||||
})
|
||||
|
||||
const ctaGroup = (name: string, label: string, labelDefault: string, urlDefault: string): Field => ({
|
||||
name,
|
||||
label,
|
||||
type: 'group',
|
||||
fields: [text('label', 'Label', labelDefault), text('url', 'URL', urlDefault)],
|
||||
})
|
||||
|
||||
const sectionAdmin = (description: string) => ({
|
||||
description,
|
||||
initCollapsed: true,
|
||||
})
|
||||
|
||||
const statFields: Field[] = [text('value', 'Value'), text('label', 'Label')]
|
||||
const bodyFields: Field[] = [textarea('text', 'Paragraph')]
|
||||
const numberedFields: Field[] = [text('num', 'Number'), text('title', 'Title'), textarea('desc', 'Description')]
|
||||
|
||||
export const aboutFields: Field[] = [
|
||||
{
|
||||
name: 'about',
|
||||
label: 'About / Der BMP page layout sections',
|
||||
type: 'group',
|
||||
admin: {
|
||||
description:
|
||||
'Edit the Der BMP page in the same order it appears on the frontend. The generic Hero and Content tabs are hidden for this SPA-managed route.',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'hero',
|
||||
label: '01 · Hero',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Top hero image, headline, CTAs, and stats strip.'),
|
||||
fields: [
|
||||
uploadField('backgroundImage', 'Background image', `Current frontend image: /images/${aboutContent.hero.backgroundImageFilename}`),
|
||||
text('imageAlt', 'Image alt text', aboutContent.hero.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', aboutContent.hero.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.hero.heading),
|
||||
text('highlight', 'Highlighted heading line', aboutContent.hero.highlight),
|
||||
textarea('description', 'Intro paragraph', aboutContent.hero.description),
|
||||
ctaGroup('primaryCta', 'Primary CTA', aboutContent.hero.primaryCta.label, aboutContent.hero.primaryCta.url),
|
||||
ctaGroup('secondaryCta', 'Secondary CTA', aboutContent.hero.secondaryCta.label, aboutContent.hero.secondaryCta.url),
|
||||
{
|
||||
name: 'stats',
|
||||
label: 'Stats',
|
||||
type: 'array',
|
||||
dbName: 'about_hero_stats',
|
||||
defaultValue: aboutContent.hero.stats,
|
||||
fields: statFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'prize',
|
||||
label: '02 · Was ist der Preis?',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Cream text/image section explaining the prize.'),
|
||||
fields: [
|
||||
uploadField('image', 'Image', `Current frontend image: /images/${aboutContent.prize.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', aboutContent.prize.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', aboutContent.prize.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.prize.heading),
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Body paragraphs',
|
||||
type: 'array',
|
||||
dbName: 'about_prize_body',
|
||||
defaultValue: aboutContent.prize.body.map((text) => ({ text })),
|
||||
fields: bodyFields,
|
||||
},
|
||||
{
|
||||
name: 'facts',
|
||||
label: 'Key facts',
|
||||
type: 'array',
|
||||
dbName: 'about_prize_facts',
|
||||
defaultValue: aboutContent.prize.facts,
|
||||
fields: statFields,
|
||||
},
|
||||
text('imageLabel', 'Desktop image label', aboutContent.prize.imageLabel),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'mittelstand',
|
||||
label: '03 · Bedeutung für den Mittelstand',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Navy text/image section about relevance and goals.'),
|
||||
fields: [
|
||||
uploadField('image', 'Image', `Current frontend image: /images/${aboutContent.mittelstand.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', aboutContent.mittelstand.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', aboutContent.mittelstand.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.mittelstand.heading),
|
||||
{
|
||||
name: 'body',
|
||||
label: 'Body paragraphs',
|
||||
type: 'array',
|
||||
dbName: 'about_mid_body',
|
||||
defaultValue: aboutContent.mittelstand.body.map((text) => ({ text })),
|
||||
fields: bodyFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'highlights',
|
||||
label: '04 · Preisträger highlights',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Header copy and editor-selected winners for the photo grid.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.highlights.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.highlights.heading),
|
||||
ctaGroup('cta', 'CTA', aboutContent.highlights.cta.label, aboutContent.highlights.cta.url),
|
||||
text('hoverLabel', 'Card hover label', aboutContent.highlights.hoverLabel),
|
||||
{
|
||||
name: 'year',
|
||||
label: 'Fallback winner year',
|
||||
type: 'number',
|
||||
defaultValue: aboutContent.highlights.year,
|
||||
},
|
||||
{
|
||||
name: 'selectedWinners',
|
||||
label: 'Selected winners',
|
||||
type: 'relationship',
|
||||
relationTo: 'preistraeger',
|
||||
hasMany: true,
|
||||
maxRows: 8,
|
||||
admin: {
|
||||
description: 'Choose up to 8 Preisträger to show. If empty, the frontend falls back to winners from the selected year.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'testimonials',
|
||||
label: '05 · Testimonials',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Testimonial heading and slides. Upload images when available, or keep the migrated URL fallback.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.testimonials.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.testimonials.heading),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Testimonials',
|
||||
type: 'array',
|
||||
dbName: 'about_tst_items',
|
||||
defaultValue: aboutContent.testimonials.items,
|
||||
fields: [
|
||||
uploadField('image', 'Image'),
|
||||
text('imageUrl', 'Fallback image URL'),
|
||||
text('name', 'Name'),
|
||||
text('role', 'Role'),
|
||||
text('company', 'Company'),
|
||||
text('year', 'Award year'),
|
||||
textarea('quote', 'Quote'),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'history',
|
||||
label: '06 · Geschichte & Meilensteine',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Navy timeline section.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.history.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.history.heading),
|
||||
text('highlight', 'Highlighted heading word', aboutContent.history.highlight),
|
||||
text('watermark', 'Desktop watermark', aboutContent.history.watermark),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Timeline items',
|
||||
type: 'array',
|
||||
dbName: 'about_hist_items',
|
||||
defaultValue: aboutContent.history.items,
|
||||
fields: [text('year', 'Year'), text('title', 'Title'), textarea('desc', 'Description')],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'goals',
|
||||
label: '07 · Zielsetzung',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Cream values list next to the history timeline.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.goals.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.goals.heading),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Goal rows',
|
||||
type: 'array',
|
||||
dbName: 'about_goal_items',
|
||||
defaultValue: aboutContent.goals.items,
|
||||
fields: numberedFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'values',
|
||||
label: '08 · Vorteile & Werte',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Cream editorial rows before the final CTA.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.values.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.values.heading),
|
||||
textarea('description', 'Description', aboutContent.values.description),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Value rows',
|
||||
type: 'array',
|
||||
dbName: 'about_val_items',
|
||||
defaultValue: aboutContent.values.items,
|
||||
fields: [text('num', 'Number'), text('title', 'Title')],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'cta',
|
||||
label: '09 · Final CTA',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Bottom navy CTA section.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', aboutContent.cta.eyebrow),
|
||||
textarea('heading', 'Heading', aboutContent.cta.heading),
|
||||
textarea('description', 'Description', aboutContent.cta.description),
|
||||
ctaGroup('primaryCta', 'Primary CTA', aboutContent.cta.primaryCta.label, aboutContent.cta.primaryCta.url),
|
||||
text('secondaryPrefix', 'Secondary prefix', aboutContent.cta.secondaryPrefix),
|
||||
ctaGroup('secondaryCta', 'Secondary CTA', aboutContent.cta.secondaryCta.label, aboutContent.cta.secondaryCta.url),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -8,6 +8,7 @@ import { Content } from '../../blocks/Content/config'
|
||||
import { FormBlock } from '../../blocks/Form/config'
|
||||
import { MediaBlock } from '../../blocks/MediaBlock/config'
|
||||
import { hero } from '@/heros/config'
|
||||
import { aboutFields } from './aboutFields'
|
||||
import { contactFields } from './contactFields'
|
||||
import { homeFields } from './homeFields'
|
||||
import { impressumFields } from './impressumFields'
|
||||
@@ -49,6 +50,14 @@ const isParticipationPage = (_: unknown, siblingData?: { slug?: string; spaPath?
|
||||
return spaPath === '/teilnahme' || slug === 'teilnahme' || slug === 'participation' || title === 'teilnahme' || title === 'participation'
|
||||
}
|
||||
|
||||
const isAboutPage = (_: unknown, siblingData?: { slug?: string; spaPath?: string; title?: string }) => {
|
||||
const slug = siblingData?.slug
|
||||
const spaPath = siblingData?.spaPath
|
||||
const title = siblingData?.title?.toLowerCase()
|
||||
|
||||
return spaPath === '/der-bmp' || slug === 'der-bmp' || slug === 'about' || title === 'der bmp' || title === 'about'
|
||||
}
|
||||
|
||||
const isImpressumPage = (_: unknown, siblingData?: { slug?: string; spaPath?: string; title?: string }) => {
|
||||
const slug = siblingData?.slug
|
||||
const spaPath = siblingData?.spaPath
|
||||
@@ -61,6 +70,7 @@ const isManagedSpaPage = (_: unknown, siblingData?: { slug?: string; spaPath?: s
|
||||
isHomePage(undefined, siblingData) ||
|
||||
isContactPage(undefined, siblingData) ||
|
||||
isParticipationPage(undefined, siblingData) ||
|
||||
isAboutPage(undefined, siblingData) ||
|
||||
isImpressumPage(undefined, siblingData)
|
||||
|
||||
export const Pages: CollectionConfig<'pages'> = {
|
||||
@@ -150,6 +160,13 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
fields: participationFields,
|
||||
label: 'Participation Page',
|
||||
},
|
||||
{
|
||||
admin: {
|
||||
condition: (data) => isAboutPage(undefined, data),
|
||||
},
|
||||
fields: aboutFields,
|
||||
label: 'About Page',
|
||||
},
|
||||
{
|
||||
admin: {
|
||||
condition: (data) => isImpressumPage(undefined, data),
|
||||
|
||||
Reference in New Issue
Block a user