397 lines
18 KiB
TypeScript
397 lines
18 KiB
TypeScript
import type { Field } from 'payload'
|
|
import { homeContent } from '@/spa/homeContent'
|
|
|
|
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 linkGroup = (labelDefault: string, urlDefault: string): Field[] => [
|
|
text('label', 'Button text', labelDefault),
|
|
text('url', 'Link URL', urlDefault),
|
|
]
|
|
|
|
const sectionAdmin = (description: string) => ({
|
|
description,
|
|
initCollapsed: true,
|
|
})
|
|
|
|
const iconOptions = [
|
|
{ label: 'Alert circle', value: 'alertCircle' },
|
|
{ label: 'Arrow right', value: 'arrowRight' },
|
|
{ label: 'Building', value: 'building2' },
|
|
{ label: 'Check', value: 'check' },
|
|
{ label: 'Check circle', value: 'checkCircle2' },
|
|
{ label: 'File text', value: 'fileText' },
|
|
{ label: 'Map pin', value: 'mapPin' },
|
|
{ label: 'Search', value: 'search' },
|
|
{ label: 'Send', value: 'send' },
|
|
{ label: 'Star', value: 'star' },
|
|
{ label: 'Trending up', value: 'trendingUp' },
|
|
{ label: 'Trophy', value: 'trophy' },
|
|
{ label: 'User', value: 'user' },
|
|
{ label: 'User check', value: 'userCheck' },
|
|
{ label: 'User plus', value: 'userPlus' },
|
|
{ label: 'Users', value: 'users' },
|
|
]
|
|
|
|
const iconField = (defaultValue = 'star'): Field => ({
|
|
name: 'icon',
|
|
label: 'Icon',
|
|
type: 'select',
|
|
defaultValue,
|
|
options: iconOptions,
|
|
})
|
|
|
|
export const homeFields: Field[] = [
|
|
{
|
|
name: 'home',
|
|
label: 'Home page layout sections',
|
|
type: 'group',
|
|
admin: {
|
|
description:
|
|
'Edit the homepage in the same order it appears on the frontend. The generic Hero and Content tabs are hidden for the home page to avoid duplicate controls.',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'hero',
|
|
label: '01 · Hero / opening screen',
|
|
type: 'group',
|
|
admin: sectionAdmin('Top full-screen gala image, badge, headline, intro text, primary buttons, video trigger, and partner ticker.'),
|
|
fields: [
|
|
uploadField('backgroundImage', 'Background image', `Current frontend image: /images/${homeContent.hero.backgroundImageFilename}`),
|
|
text('imageAlt', 'Image alt text', homeContent.hero.imageAlt),
|
|
text('badge', 'Badge text', homeContent.hero.badge),
|
|
text('headingLine1', 'Headline line 1', homeContent.hero.headingLine1),
|
|
text('headingAccent', 'Headline accent line', homeContent.hero.headingAccent),
|
|
textarea(
|
|
'description',
|
|
'Intro paragraph',
|
|
homeContent.hero.description,
|
|
),
|
|
{ name: 'primaryCta', label: 'Primary CTA', type: 'group', fields: linkGroup(homeContent.hero.primaryCta.label, homeContent.hero.primaryCta.url) },
|
|
{ name: 'secondaryCta', label: 'Secondary CTA', type: 'group', fields: linkGroup(homeContent.hero.secondaryCta.label, homeContent.hero.secondaryCta.url) },
|
|
text('videoLabel', 'Video button label', homeContent.hero.videoLabel),
|
|
text('partnersLabel', 'Partner ticker label', homeContent.hero.partnersLabel),
|
|
{
|
|
name: 'partners',
|
|
label: 'Partner ticker names',
|
|
type: 'array',
|
|
defaultValue: homeContent.hero.partners,
|
|
fields: [text('name', 'Name')],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'quickCheck',
|
|
label: '02 · Schnell-Check eligibility section',
|
|
type: 'group',
|
|
admin: sectionAdmin('Cream text panel plus right-side stage image and five eligibility rows.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.quickCheck.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.quickCheck.heading),
|
|
uploadField('image', 'Image', `Current frontend image: /images/${homeContent.quickCheck.imageFilename}`),
|
|
text('imageAlt', 'Image alt text', homeContent.quickCheck.imageAlt),
|
|
textarea(
|
|
'body',
|
|
'Body copy',
|
|
homeContent.quickCheck.body,
|
|
),
|
|
{
|
|
name: 'criteria',
|
|
label: 'Criteria rows',
|
|
type: 'array',
|
|
defaultValue: homeContent.quickCheck.criteria,
|
|
fields: [text('label', 'Criterion'), text('desc', 'Description')],
|
|
},
|
|
textarea(
|
|
'note',
|
|
'Small note below criteria',
|
|
homeContent.quickCheck.note,
|
|
),
|
|
{ name: 'cta', label: 'CTA', type: 'group', fields: linkGroup(homeContent.quickCheck.cta.label, homeContent.quickCheck.cta.url) },
|
|
],
|
|
},
|
|
{
|
|
name: 'intro',
|
|
label: '03 · Award intro / value proposition',
|
|
type: 'group',
|
|
admin: sectionAdmin('Jubilation image, stats, editorial quote, body copy, and CTA.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.intro.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.intro.heading),
|
|
uploadField('image', 'Image', `Current frontend image: /images/${homeContent.intro.imageFilename}`),
|
|
text('imageAlt', 'Image alt text', homeContent.intro.imageAlt),
|
|
{
|
|
name: 'stats',
|
|
label: 'Stats',
|
|
type: 'array',
|
|
defaultValue: homeContent.intro.stats,
|
|
fields: [text('value', 'Value'), text('label', 'Label')],
|
|
},
|
|
textarea('quote', 'Quote', homeContent.intro.quote),
|
|
textarea(
|
|
'body',
|
|
'Body copy',
|
|
homeContent.intro.body,
|
|
),
|
|
{ name: 'cta', label: 'CTA', type: 'group', fields: linkGroup(homeContent.intro.cta.label, homeContent.intro.cta.url) },
|
|
],
|
|
},
|
|
{
|
|
name: 'status',
|
|
label: '04 · Application phase slider',
|
|
type: 'group',
|
|
admin: sectionAdmin('Three-slide status module shown after the award intro.'),
|
|
fields: [
|
|
{
|
|
name: 'activePhase',
|
|
label: 'Current phase shown on the homepage',
|
|
type: 'select',
|
|
defaultValue: homeContent.status.activePhase,
|
|
options: [
|
|
{ label: '01 · Bewerbungsphase offen', value: '0' },
|
|
{ label: '02 · Auswertung / Jury bewertet', value: '1' },
|
|
{ label: '03 · Preisverleihung abgeschlossen', value: '2' },
|
|
],
|
|
admin: { description: 'Only this selected phase is rendered on the frontend; visitors do not see a slider.' },
|
|
},
|
|
{
|
|
name: 'phases',
|
|
label: 'Slides',
|
|
type: 'array',
|
|
maxRows: 3,
|
|
defaultValue: homeContent.status.phases,
|
|
fields: [
|
|
text('num', 'Slide number'), text('tag', 'Badge'), { name: 'pulse', label: 'Show pulse dot', type: 'checkbox', defaultValue: true }, text('phase', 'Phase label'), text('headline', 'Headline'), textarea('body', 'Body copy'),
|
|
{ name: 'cta', label: 'Slide CTA', type: 'group', fields: linkGroup('', '') }, text('accent', 'Accent color'), text('bg', 'Background color'), text('glow', 'Glow color'), text('meta', 'Meta label'), text('successApplications', 'Success applications number'), text('successWinners', 'Success winners number'), { name: 'membershipCta', label: 'Membership CTA', type: 'group', fields: linkGroup('Mitglied werden', '/mitglied-werden') },
|
|
],
|
|
},
|
|
text('noActionLabel', 'No CTA fallback label', homeContent.status.noActionLabel),
|
|
text('successApplicationsLabel', 'Success applications label', homeContent.status.successApplicationsLabel),
|
|
text('successWinnersLabel', 'Success winners label', homeContent.status.successWinnersLabel),
|
|
],
|
|
},
|
|
{
|
|
name: 'winners',
|
|
label: '05 · Preisträger card grid',
|
|
type: 'group',
|
|
admin: sectionAdmin('Blue card grid with featured winner relationships.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.winners.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.winners.heading),
|
|
{ name: 'cta', label: 'CTA', type: 'group', fields: linkGroup(homeContent.winners.cta.label, homeContent.winners.cta.url) },
|
|
uploadField('fallbackImage', 'Fallback card image', `Current frontend image: /images/${homeContent.winners.fallbackImageFilename}`),
|
|
text('cardFallbackTitle', 'Fallback card title', homeContent.winners.cardFallbackTitle),
|
|
text('hoverLabel', 'Card hover label', homeContent.winners.hoverLabel),
|
|
{
|
|
name: 'featured',
|
|
label: 'Featured winner cards',
|
|
type: 'relationship',
|
|
relationTo: 'preistraeger',
|
|
hasMany: true,
|
|
admin: { description: 'Choose the winner cards shown on the home page. If empty, the latest 2025 winners are used.' },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'testimonials',
|
|
label: '06 · Testimonials carousel',
|
|
type: 'group',
|
|
admin: sectionAdmin('Portrait carousel and quote copy.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.testimonials.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.testimonials.heading),
|
|
textarea('desktopHeading', 'Desktop heading', homeContent.testimonials.desktopHeading),
|
|
text('yearPrefix', 'Award year prefix', homeContent.testimonials.yearPrefix),
|
|
text('previousLabel', 'Previous button label', homeContent.testimonials.previousLabel),
|
|
text('nextLabel', 'Next button label', homeContent.testimonials.nextLabel),
|
|
text('slideLabelPrefix', 'Slide dot label prefix', homeContent.testimonials.slideLabelPrefix),
|
|
{
|
|
name: 'items',
|
|
label: 'Testimonials',
|
|
type: 'array',
|
|
defaultValue: homeContent.testimonials.items,
|
|
fields: [uploadField('image', 'Portrait image'), text('imageUrl', 'External image URL'), text('name', 'Name'), text('role', 'Role'), text('company', 'Company'), text('year', 'Year'), textarea('quote', 'Quote')],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'benefits',
|
|
label: '07 · Participation benefits',
|
|
type: 'group',
|
|
admin: sectionAdmin('Cream left panel and networking image.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.benefits.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.benefits.heading),
|
|
uploadField('image', 'Image', `Current frontend image: /images/${homeContent.benefits.imageFilename}`),
|
|
text('imageAlt', 'Image alt text', homeContent.benefits.imageAlt),
|
|
text('imageLabel', 'Desktop image label', homeContent.benefits.imageLabel),
|
|
{
|
|
name: 'items', label: 'Benefit rows', type: 'array', defaultValue: homeContent.benefits.items, fields: [text('num', 'Number'), text('title', 'Title'), textarea('desc', 'Description')],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'application',
|
|
label: '08 · Application form section',
|
|
type: 'group',
|
|
admin: sectionAdmin('Final application pitch, award image, embedded form heading, and footnote.'),
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.application.eyebrow),
|
|
textarea('heading', 'Heading', homeContent.application.heading),
|
|
textarea('body', 'Body copy', homeContent.application.body),
|
|
{ name: 'benefits', label: 'Benefit rows', type: 'array', defaultValue: homeContent.application.benefits, fields: [text('num', 'Number'), text('label', 'Label'), text('desc', 'Description')] },
|
|
uploadField('awardImage', 'Award image', `Current frontend image: /images/${homeContent.application.awardImageFilename}`),
|
|
text('awardImageAlt', 'Award image alt text', homeContent.application.awardImageAlt),
|
|
text('awardCaption', 'Award image caption', homeContent.application.awardCaption),
|
|
text('formEyebrow', 'Form eyebrow', homeContent.application.formEyebrow),
|
|
text('formTitle', 'Form title', homeContent.application.formTitle),
|
|
text('footnote', 'Footnote normal text', homeContent.application.footnote),
|
|
text('footnoteStrong', 'Footnote highlighted text', homeContent.application.footnoteStrong),
|
|
],
|
|
},
|
|
{
|
|
name: 'form',
|
|
label: '09 · Embedded application form copy and logic labels',
|
|
type: 'group',
|
|
admin: sectionAdmin('Text, options, and eligibility thresholds used inside the home page multi-step application form.'),
|
|
fields: [
|
|
text('stepCompleteLabel', 'Completed step label', homeContent.form.stepCompleteLabel),
|
|
text('backLabel', 'Back button label', homeContent.form.backLabel),
|
|
text('nextLabel', 'Next button label', homeContent.form.nextLabel),
|
|
text('submitLabel', 'Submit button label', homeContent.form.submitLabel),
|
|
text('yesLabel', 'Yes option label', homeContent.form.yesLabel),
|
|
text('noLabel', 'No option label', homeContent.form.noLabel),
|
|
text('requiredSuffix', 'Required field suffix', homeContent.form.requiredSuffix),
|
|
{
|
|
name: 'validation',
|
|
label: 'Validation messages',
|
|
type: 'group',
|
|
fields: [
|
|
text('choose', 'Choose message', homeContent.form.validation.choose),
|
|
text('required', 'Required message', homeContent.form.validation.required),
|
|
text('invalidEmail', 'Invalid email message', homeContent.form.validation.invalidEmail),
|
|
],
|
|
},
|
|
{
|
|
name: 'typeStep',
|
|
label: 'Step 1 · Submission type',
|
|
type: 'group',
|
|
fields: [
|
|
text('eyebrow', 'Eyebrow', homeContent.form.typeStep.eyebrow),
|
|
text('heading', 'Heading', homeContent.form.typeStep.heading),
|
|
text('selfTitle', 'Self-application title', homeContent.form.typeStep.selfTitle),
|
|
textarea('selfDesc', 'Self-application description', homeContent.form.typeStep.selfDesc),
|
|
text('nominationTitle', 'Nomination title', homeContent.form.typeStep.nominationTitle),
|
|
textarea('nominationDesc', 'Nomination description', homeContent.form.typeStep.nominationDesc),
|
|
],
|
|
},
|
|
{
|
|
name: 'selfSteps',
|
|
label: 'Self-application step labels',
|
|
type: 'array',
|
|
dbName: 'home_self_steps',
|
|
defaultValue: homeContent.form.selfSteps,
|
|
fields: [text('label', 'Label'), iconField('trophy')],
|
|
},
|
|
{
|
|
name: 'nominationSteps',
|
|
label: 'Nomination step labels',
|
|
type: 'array',
|
|
dbName: 'home_nom_steps',
|
|
defaultValue: homeContent.form.nominationSteps,
|
|
fields: [text('label', 'Label'), iconField('trophy')],
|
|
},
|
|
{
|
|
name: 'employeeOptions',
|
|
label: 'Employee options',
|
|
type: 'array',
|
|
dbName: 'home_emp_opts',
|
|
defaultValue: homeContent.form.employeeOptions,
|
|
fields: [text('value', 'Value'), text('label', 'Label')],
|
|
},
|
|
{
|
|
name: 'eligibility',
|
|
label: 'Self-application eligibility step',
|
|
type: 'group',
|
|
fields: [
|
|
text('allowedEmployeeValues', 'Allowed employee option values, comma-separated', homeContent.form.eligibility.allowedEmployeeValues),
|
|
text('requiredBayernValue', 'Required Bavaria answer value', homeContent.form.eligibility.requiredBayernValue),
|
|
text('eyebrow', 'Eyebrow', homeContent.form.eligibility.eyebrow),
|
|
text('heading', 'Heading', homeContent.form.eligibility.heading),
|
|
text('employeesLabel', 'Employees field label', homeContent.form.eligibility.employeesLabel),
|
|
text('bayernLabel', 'Bavaria field label', homeContent.form.eligibility.bayernLabel),
|
|
text('ownerLabel', 'Owner field label', homeContent.form.eligibility.ownerLabel),
|
|
text('ineligibleHeading', 'Ineligible heading', homeContent.form.eligibility.ineligibleHeading),
|
|
textarea('ineligibleBody', 'Ineligible body', homeContent.form.eligibility.ineligibleBody),
|
|
text('ineligibleContactPrefix', 'Ineligible contact prefix', homeContent.form.eligibility.ineligibleContactPrefix),
|
|
text('ineligibleContactEmail', 'Ineligible contact email', homeContent.form.eligibility.ineligibleContactEmail),
|
|
],
|
|
},
|
|
{
|
|
name: 'selfContact',
|
|
label: 'Self-application contact step',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.selfContact).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
{
|
|
name: 'selfSummary',
|
|
label: 'Self-application summary step',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.selfSummary).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
{
|
|
name: 'nominationCompany',
|
|
label: 'Nomination company step',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.nominationCompany).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
{
|
|
name: 'nominationContact',
|
|
label: 'Nomination contact step',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.nominationContact).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
{
|
|
name: 'nominationSummary',
|
|
label: 'Nomination summary step',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.nominationSummary).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
{
|
|
name: 'success',
|
|
label: 'Success state copy',
|
|
type: 'group',
|
|
fields: Object.entries(homeContent.form.success).map(([name, value]) => text(name, name, value)),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'videoModal',
|
|
label: '10 · Video modal placeholder',
|
|
type: 'group',
|
|
admin: sectionAdmin('Copy shown when the hero video button is clicked.'),
|
|
fields: [text('title', 'Title', homeContent.videoModal.title), text('description', 'Description', homeContent.videoModal.description), text('closeLabel', 'Close button label', homeContent.videoModal.closeLabel)],
|
|
},
|
|
],
|
|
},
|
|
]
|