feat: manage home form copy via payload
This commit is contained in:
@@ -33,6 +33,33 @@ const sectionAdmin = (description: string) => ({
|
||||
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',
|
||||
@@ -236,9 +263,125 @@ export const homeFields: Field[] = [
|
||||
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: '09 · Video modal placeholder',
|
||||
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)],
|
||||
|
||||
@@ -414,6 +414,165 @@ export interface Page {
|
||||
footnote?: string | null;
|
||||
footnoteStrong?: string | null;
|
||||
};
|
||||
/**
|
||||
* Text, options, and eligibility thresholds used inside the home page multi-step application form.
|
||||
*/
|
||||
form?: {
|
||||
stepCompleteLabel?: string | null;
|
||||
backLabel?: string | null;
|
||||
nextLabel?: string | null;
|
||||
submitLabel?: string | null;
|
||||
yesLabel?: string | null;
|
||||
noLabel?: string | null;
|
||||
requiredSuffix?: string | null;
|
||||
validation?: {
|
||||
choose?: string | null;
|
||||
required?: string | null;
|
||||
invalidEmail?: string | null;
|
||||
};
|
||||
typeStep?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
selfTitle?: string | null;
|
||||
selfDesc?: string | null;
|
||||
nominationTitle?: string | null;
|
||||
nominationDesc?: string | null;
|
||||
};
|
||||
selfSteps?:
|
||||
| {
|
||||
label?: string | null;
|
||||
icon?:
|
||||
| (
|
||||
| 'alertCircle'
|
||||
| 'arrowRight'
|
||||
| 'building2'
|
||||
| 'check'
|
||||
| 'checkCircle2'
|
||||
| 'fileText'
|
||||
| 'mapPin'
|
||||
| 'search'
|
||||
| 'send'
|
||||
| 'star'
|
||||
| 'trendingUp'
|
||||
| 'trophy'
|
||||
| 'user'
|
||||
| 'userCheck'
|
||||
| 'userPlus'
|
||||
| 'users'
|
||||
)
|
||||
| null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
nominationSteps?:
|
||||
| {
|
||||
label?: string | null;
|
||||
icon?:
|
||||
| (
|
||||
| 'alertCircle'
|
||||
| 'arrowRight'
|
||||
| 'building2'
|
||||
| 'check'
|
||||
| 'checkCircle2'
|
||||
| 'fileText'
|
||||
| 'mapPin'
|
||||
| 'search'
|
||||
| 'send'
|
||||
| 'star'
|
||||
| 'trendingUp'
|
||||
| 'trophy'
|
||||
| 'user'
|
||||
| 'userCheck'
|
||||
| 'userPlus'
|
||||
| 'users'
|
||||
)
|
||||
| null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
employeeOptions?:
|
||||
| {
|
||||
value?: string | null;
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
eligibility?: {
|
||||
allowedEmployeeValues?: string | null;
|
||||
requiredBayernValue?: string | null;
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
employeesLabel?: string | null;
|
||||
bayernLabel?: string | null;
|
||||
ownerLabel?: string | null;
|
||||
ineligibleHeading?: string | null;
|
||||
ineligibleBody?: string | null;
|
||||
ineligibleContactPrefix?: string | null;
|
||||
ineligibleContactEmail?: string | null;
|
||||
};
|
||||
selfContact?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
companyLabel?: string | null;
|
||||
companyPlaceholder?: string | null;
|
||||
nameLabel?: string | null;
|
||||
namePlaceholder?: string | null;
|
||||
emailLabel?: string | null;
|
||||
emailPlaceholder?: string | null;
|
||||
phoneLabel?: string | null;
|
||||
phonePlaceholder?: string | null;
|
||||
footnote?: string | null;
|
||||
};
|
||||
selfSummary?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
companyLabel?: string | null;
|
||||
employeesLabel?: string | null;
|
||||
locationLabel?: string | null;
|
||||
locationPrefix?: string | null;
|
||||
contactLabel?: string | null;
|
||||
};
|
||||
nominationCompany?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
companyLabel?: string | null;
|
||||
companyPlaceholder?: string | null;
|
||||
industryLabel?: string | null;
|
||||
industryPlaceholder?: string | null;
|
||||
locationLabel?: string | null;
|
||||
locationPlaceholder?: string | null;
|
||||
};
|
||||
nominationContact?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
nameLabel?: string | null;
|
||||
namePlaceholder?: string | null;
|
||||
emailLabel?: string | null;
|
||||
emailPlaceholder?: string | null;
|
||||
relationshipLabel?: string | null;
|
||||
relationshipPlaceholder?: string | null;
|
||||
footnote?: string | null;
|
||||
};
|
||||
nominationSummary?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
companyLabel?: string | null;
|
||||
industryLabel?: string | null;
|
||||
locationLabel?: string | null;
|
||||
nominatedByLabel?: string | null;
|
||||
emptyValue?: string | null;
|
||||
};
|
||||
success?: {
|
||||
selfHeading?: string | null;
|
||||
nominationHeading?: string | null;
|
||||
selfPrefix?: string | null;
|
||||
selfMiddle?: string | null;
|
||||
selfSuffix?: string | null;
|
||||
nominationPrefix?: string | null;
|
||||
nominationMiddle?: string | null;
|
||||
nominationSuffix?: string | null;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Copy shown when the hero video button is clicked.
|
||||
*/
|
||||
@@ -3232,6 +3391,144 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
footnote?: T;
|
||||
footnoteStrong?: T;
|
||||
};
|
||||
form?:
|
||||
| T
|
||||
| {
|
||||
stepCompleteLabel?: T;
|
||||
backLabel?: T;
|
||||
nextLabel?: T;
|
||||
submitLabel?: T;
|
||||
yesLabel?: T;
|
||||
noLabel?: T;
|
||||
requiredSuffix?: T;
|
||||
validation?:
|
||||
| T
|
||||
| {
|
||||
choose?: T;
|
||||
required?: T;
|
||||
invalidEmail?: T;
|
||||
};
|
||||
typeStep?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
selfTitle?: T;
|
||||
selfDesc?: T;
|
||||
nominationTitle?: T;
|
||||
nominationDesc?: T;
|
||||
};
|
||||
selfSteps?:
|
||||
| T
|
||||
| {
|
||||
label?: T;
|
||||
icon?: T;
|
||||
id?: T;
|
||||
};
|
||||
nominationSteps?:
|
||||
| T
|
||||
| {
|
||||
label?: T;
|
||||
icon?: T;
|
||||
id?: T;
|
||||
};
|
||||
employeeOptions?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
label?: T;
|
||||
id?: T;
|
||||
};
|
||||
eligibility?:
|
||||
| T
|
||||
| {
|
||||
allowedEmployeeValues?: T;
|
||||
requiredBayernValue?: T;
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
employeesLabel?: T;
|
||||
bayernLabel?: T;
|
||||
ownerLabel?: T;
|
||||
ineligibleHeading?: T;
|
||||
ineligibleBody?: T;
|
||||
ineligibleContactPrefix?: T;
|
||||
ineligibleContactEmail?: T;
|
||||
};
|
||||
selfContact?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
companyLabel?: T;
|
||||
companyPlaceholder?: T;
|
||||
nameLabel?: T;
|
||||
namePlaceholder?: T;
|
||||
emailLabel?: T;
|
||||
emailPlaceholder?: T;
|
||||
phoneLabel?: T;
|
||||
phonePlaceholder?: T;
|
||||
footnote?: T;
|
||||
};
|
||||
selfSummary?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
companyLabel?: T;
|
||||
employeesLabel?: T;
|
||||
locationLabel?: T;
|
||||
locationPrefix?: T;
|
||||
contactLabel?: T;
|
||||
};
|
||||
nominationCompany?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
companyLabel?: T;
|
||||
companyPlaceholder?: T;
|
||||
industryLabel?: T;
|
||||
industryPlaceholder?: T;
|
||||
locationLabel?: T;
|
||||
locationPlaceholder?: T;
|
||||
};
|
||||
nominationContact?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
nameLabel?: T;
|
||||
namePlaceholder?: T;
|
||||
emailLabel?: T;
|
||||
emailPlaceholder?: T;
|
||||
relationshipLabel?: T;
|
||||
relationshipPlaceholder?: T;
|
||||
footnote?: T;
|
||||
};
|
||||
nominationSummary?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
companyLabel?: T;
|
||||
industryLabel?: T;
|
||||
locationLabel?: T;
|
||||
nominatedByLabel?: T;
|
||||
emptyValue?: T;
|
||||
};
|
||||
success?:
|
||||
| T
|
||||
| {
|
||||
selfHeading?: T;
|
||||
nominationHeading?: T;
|
||||
selfPrefix?: T;
|
||||
selfMiddle?: T;
|
||||
selfSuffix?: T;
|
||||
nominationPrefix?: T;
|
||||
nominationMiddle?: T;
|
||||
nominationSuffix?: T;
|
||||
};
|
||||
};
|
||||
videoModal?:
|
||||
| T
|
||||
| {
|
||||
|
||||
@@ -89,6 +89,7 @@ async function main() {
|
||||
...applicationContent,
|
||||
awardImage,
|
||||
},
|
||||
form: homeContent.form,
|
||||
videoModal: homeContent.videoModal,
|
||||
},
|
||||
} as never,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { participationContent } from '@/spa/participationContent'
|
||||
|
||||
export const homeContent = {
|
||||
hero: {
|
||||
backgroundImageFilename: 'gala-saal-overview.jpg',
|
||||
@@ -209,6 +211,7 @@ export const homeContent = {
|
||||
footnote: 'Kostenlos und unverbindlich –',
|
||||
footnoteStrong: 'keine Teilnahmegebühr',
|
||||
},
|
||||
form: participationContent.form,
|
||||
videoModal: {
|
||||
title: 'Video-Player Platzhalter',
|
||||
description: 'Hier würde das Image-Video des BMP geladen werden.',
|
||||
|
||||
@@ -116,6 +116,7 @@ const Home: React.FC = () => {
|
||||
const winnersSection = home.winners || {};
|
||||
const benefits = home.benefits || {};
|
||||
const application = home.application || {};
|
||||
const form = home.form || {};
|
||||
const videoModal = home.videoModal || {};
|
||||
const cmsPreistraeger = useCmsCollection('preistraeger');
|
||||
const selectedWinners = fallbackArray(winnersSection.featured, []);
|
||||
@@ -551,7 +552,7 @@ const Home: React.FC = () => {
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '24px 48px 32px 40px', flex: isMobile ? 'none' : 1, height: isMobile ? '82svh' : undefined, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 8 }}>{fallbackText(application.formEyebrow, homeContent.application.formEyebrow)}</span>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 'clamp(1.2rem, 1.8vw, 1.6rem)', fontWeight: 900, color: '#111D55', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.1, marginBottom: 24 }}>{fallbackText(application.formTitle, homeContent.application.formTitle)}</h3>
|
||||
<BewerbungsForm theme="gold" />
|
||||
<BewerbungsForm theme="gold" content={form} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user