feat: centralize contact cms defaults
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { Field } from 'payload'
|
||||
|
||||
import { contactFormContent } from '@/spa/contactFormContent'
|
||||
import { contactContent } from '@/spa/contactContent'
|
||||
|
||||
const uploadField = (name: string, label: string, description?: string): Field => ({
|
||||
name,
|
||||
@@ -45,14 +45,14 @@ export const contactFields: Field[] = [
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Top image, eyebrow, headline, and intro copy.'),
|
||||
fields: [
|
||||
uploadField('backgroundImage', 'Background image', 'Current frontend image: /images/gala-dinner.jpg'),
|
||||
text('imageAlt', 'Image alt text', 'BMP Gala'),
|
||||
text('eyebrow', 'Eyebrow', 'Dialog & Service'),
|
||||
textarea('heading', 'Headline', 'Wir sind\nfür Sie da.'),
|
||||
uploadField('backgroundImage', 'Background image', `Current frontend image: /images/${contactContent.hero.backgroundImageFilename}`),
|
||||
text('imageAlt', 'Image alt text', contactContent.hero.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', contactContent.hero.eyebrow),
|
||||
textarea('heading', 'Headline', contactContent.hero.heading),
|
||||
textarea(
|
||||
'description',
|
||||
'Intro paragraph',
|
||||
'Fragen zur Bewerbung, zur Gala oder zu Partnermöglichkeiten – unser Team begleitet Sie persönlich.',
|
||||
contactContent.hero.description,
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -62,18 +62,13 @@ export const contactFields: Field[] = [
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Left direct-contact list plus the gold contact form panel.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Direct contact eyebrow', 'Direktkontakt'),
|
||||
textarea('heading', 'Direct contact heading', 'Kontaktmöglichkeiten'),
|
||||
text('eyebrow', 'Direct contact eyebrow', contactContent.info.eyebrow),
|
||||
textarea('heading', 'Direct contact heading', contactContent.info.heading),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Contact methods',
|
||||
type: 'array',
|
||||
defaultValue: [
|
||||
{ icon: 'mapPin', title: 'Geschäftsstelle', lines: 'Maximilianstraße 42\n80538 München' },
|
||||
{ icon: 'mail', title: 'E-Mail', lines: 'info@bmp-bayern.de' },
|
||||
{ icon: 'phone', title: 'Telefon', lines: '+49 89 123 456 78' },
|
||||
{ icon: 'clock', title: 'Bürozeiten', lines: 'Mo – Fr: 09:00 – 17:00 Uhr' },
|
||||
],
|
||||
defaultValue: contactContent.info.items,
|
||||
fields: [
|
||||
{
|
||||
name: 'icon',
|
||||
@@ -91,13 +86,13 @@ export const contactFields: Field[] = [
|
||||
textarea('lines', 'Lines'),
|
||||
],
|
||||
},
|
||||
text('nextAwardLabel', 'Next award label', 'Nächste Preisverleihung:'),
|
||||
text('nextAwardDate', 'Next award date', '22. Oktober 2026'),
|
||||
uploadField('formImage', 'Desktop form image', 'Current frontend image: /images/preistraeger-gruppe.jpg'),
|
||||
text('formImageAlt', 'Form image alt text', 'BMP Gala 2025'),
|
||||
text('formImageLabel', 'Form image label', 'Gala 2025 München'),
|
||||
text('formEyebrow', 'Form eyebrow', 'Kontaktformular'),
|
||||
text('formTitle', 'Form title', 'Schreiben Sie uns'),
|
||||
text('nextAwardLabel', 'Next award label', contactContent.info.nextAwardLabel),
|
||||
text('nextAwardDate', 'Next award date', contactContent.info.nextAwardDate),
|
||||
uploadField('formImage', 'Desktop form image', `Current frontend image: /images/${contactContent.info.formImageFilename}`),
|
||||
text('formImageAlt', 'Form image alt text', contactContent.info.formImageAlt),
|
||||
text('formImageLabel', 'Form image label', contactContent.info.formImageLabel),
|
||||
text('formEyebrow', 'Form eyebrow', contactContent.info.formEyebrow),
|
||||
text('formTitle', 'Form title', contactContent.info.formTitle),
|
||||
{
|
||||
name: 'formCopy',
|
||||
label: 'Contact form copy',
|
||||
@@ -108,14 +103,14 @@ export const contactFields: Field[] = [
|
||||
name: 'steps',
|
||||
label: 'Step labels',
|
||||
type: 'array',
|
||||
defaultValue: contactFormContent.steps,
|
||||
defaultValue: contactContent.info.formCopy.steps,
|
||||
fields: [text('label', 'Label')],
|
||||
},
|
||||
{
|
||||
name: 'subjects',
|
||||
label: 'Subject choices',
|
||||
type: 'array',
|
||||
defaultValue: contactFormContent.subjects,
|
||||
defaultValue: contactContent.info.formCopy.subjects,
|
||||
fields: [text('value', 'Value'), text('label', 'Label'), textarea('desc', 'Description')],
|
||||
},
|
||||
{
|
||||
@@ -123,9 +118,9 @@ export const contactFields: Field[] = [
|
||||
label: 'Prompts',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('subject', 'Subject step prompt', contactFormContent.prompts.subject),
|
||||
text('contact', 'Contact step prompt', contactFormContent.prompts.contact),
|
||||
text('message', 'Message step prompt', contactFormContent.prompts.message),
|
||||
text('subject', 'Subject step prompt', contactContent.info.formCopy.prompts.subject),
|
||||
text('contact', 'Contact step prompt', contactContent.info.formCopy.prompts.contact),
|
||||
text('message', 'Message step prompt', contactContent.info.formCopy.prompts.message),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -133,12 +128,12 @@ export const contactFields: Field[] = [
|
||||
label: 'Fields',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('nameLabel', 'Name label', contactFormContent.fields.nameLabel),
|
||||
text('namePlaceholder', 'Name placeholder', contactFormContent.fields.namePlaceholder),
|
||||
text('emailLabel', 'Email label', contactFormContent.fields.emailLabel),
|
||||
text('emailPlaceholder', 'Email placeholder', contactFormContent.fields.emailPlaceholder),
|
||||
text('messageLabel', 'Message label', contactFormContent.fields.messageLabel),
|
||||
text('messagePlaceholder', 'Message placeholder', contactFormContent.fields.messagePlaceholder),
|
||||
text('nameLabel', 'Name label', contactContent.info.formCopy.fields.nameLabel),
|
||||
text('namePlaceholder', 'Name placeholder', contactContent.info.formCopy.fields.namePlaceholder),
|
||||
text('emailLabel', 'Email label', contactContent.info.formCopy.fields.emailLabel),
|
||||
text('emailPlaceholder', 'Email placeholder', contactContent.info.formCopy.fields.emailPlaceholder),
|
||||
text('messageLabel', 'Message label', contactContent.info.formCopy.fields.messageLabel),
|
||||
text('messagePlaceholder', 'Message placeholder', contactContent.info.formCopy.fields.messagePlaceholder),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -146,10 +141,10 @@ export const contactFields: Field[] = [
|
||||
label: 'Validation messages',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('nameRequired', 'Name required', contactFormContent.validation.nameRequired),
|
||||
text('emailRequired', 'Email required', contactFormContent.validation.emailRequired),
|
||||
text('emailInvalid', 'Email invalid', contactFormContent.validation.emailInvalid),
|
||||
text('messageRequired', 'Message required', contactFormContent.validation.messageRequired),
|
||||
text('nameRequired', 'Name required', contactContent.info.formCopy.validation.nameRequired),
|
||||
text('emailRequired', 'Email required', contactContent.info.formCopy.validation.emailRequired),
|
||||
text('emailInvalid', 'Email invalid', contactContent.info.formCopy.validation.emailInvalid),
|
||||
text('messageRequired', 'Message required', contactContent.info.formCopy.validation.messageRequired),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -157,9 +152,9 @@ export const contactFields: Field[] = [
|
||||
label: 'Navigation labels',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('back', 'Back', contactFormContent.navigation.back),
|
||||
text('next', 'Next', contactFormContent.navigation.next),
|
||||
text('submit', 'Submit', contactFormContent.navigation.submit),
|
||||
text('back', 'Back', contactContent.info.formCopy.navigation.back),
|
||||
text('next', 'Next', contactContent.info.formCopy.navigation.next),
|
||||
text('submit', 'Submit', contactContent.info.formCopy.navigation.submit),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -167,9 +162,9 @@ export const contactFields: Field[] = [
|
||||
label: 'Success copy',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('heading', 'Heading', contactFormContent.success.heading),
|
||||
text('prefix', 'Prefix', contactFormContent.success.prefix),
|
||||
text('suffixBeforeEmail', 'Suffix before email', contactFormContent.success.suffixBeforeEmail),
|
||||
text('heading', 'Heading', contactContent.info.formCopy.success.heading),
|
||||
text('prefix', 'Prefix', contactContent.info.formCopy.success.prefix),
|
||||
text('suffixBeforeEmail', 'Suffix before email', contactContent.info.formCopy.success.suffixBeforeEmail),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -182,17 +177,13 @@ export const contactFields: Field[] = [
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Dark 2026 timeline with three deadline columns.'),
|
||||
fields: [
|
||||
text('watermark', 'Large background year', '2026'),
|
||||
text('eyebrow', 'Eyebrow', 'Fahrplan 2026'),
|
||||
text('watermark', 'Large background year', contactContent.deadlines.watermark),
|
||||
text('eyebrow', 'Eyebrow', contactContent.deadlines.eyebrow),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Deadline items',
|
||||
type: 'array',
|
||||
defaultValue: [
|
||||
{ step: '01', label: 'Bewerbungsschluss', date: '30. Juni 2026', desc: 'Letzte Möglichkeit zur Einreichung Ihrer Unterlagen.' },
|
||||
{ step: '02', label: 'Nominierung', date: '15. August 2026', desc: 'Bekanntgabe der Nominierten nach Jury-Sichtung.' },
|
||||
{ step: '03', label: 'Preisverleihung', date: '22. Oktober 2026', desc: 'Festliche Gala in München.' },
|
||||
],
|
||||
defaultValue: contactContent.deadlines.items,
|
||||
fields: [text('step', 'Step'), text('label', 'Label'), text('date', 'Date'), textarea('desc', 'Description')],
|
||||
},
|
||||
],
|
||||
@@ -203,30 +194,13 @@ export const contactFields: Field[] = [
|
||||
type: 'group',
|
||||
admin: sectionAdmin('FAQ heading and accordion entries.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', 'Antworten'),
|
||||
textarea('heading', 'Heading', 'Häufige\nFragen'),
|
||||
text('eyebrow', 'Eyebrow', contactContent.faq.eyebrow),
|
||||
textarea('heading', 'Heading', contactContent.faq.heading),
|
||||
{
|
||||
name: 'items',
|
||||
label: 'FAQ items',
|
||||
type: 'array',
|
||||
defaultValue: [
|
||||
{
|
||||
q: 'Was kostet die Teilnahme am BMP?',
|
||||
a: 'Die Teilnahme am Bayerischen Mittelstandspreis ist für alle Unternehmen vollständig kostenfrei. Wir finanzieren uns durch Partner und Sponsoren, um exzellenten Mittelstand ohne finanzielle Hürden zu fördern.',
|
||||
},
|
||||
{
|
||||
q: 'Nach welchen Kriterien wird bewertet?',
|
||||
a: 'Die Bewertung basiert auf vier Säulen: Zukunftsfähigkeit & Innovation, Nachhaltigkeit & Verantwortung, Unternehmenskultur sowie Regionale Verwurzelung. Jede Säule fließt mit 25 % in das Gesamtergebnis ein.',
|
||||
},
|
||||
{
|
||||
q: 'Wie läuft der Bewerbungsprozess ab?',
|
||||
a: 'Der Prozess ist mehrstufig: 1. Online-Bewerbung oder Vorschlag, 2. Formale Prüfung & erste Jury-Sichtung, 3. Fach-Audits bei den Finalisten vor Ort, 4. Finale Jury-Sitzung und abschließende Preisverleihung.',
|
||||
},
|
||||
{
|
||||
q: 'Wie lange dauert die Bewerbung?',
|
||||
a: 'Dank unseres optimierten Bewerbungsformulars benötigen Sie für die erste Einreichung ca. 30–45 Minuten. Tiefergehende Unterlagen werden erst in der Audit-Phase angefordert.',
|
||||
},
|
||||
],
|
||||
defaultValue: contactContent.faq.items,
|
||||
fields: [textarea('q', 'Question'), textarea('a', 'Answer')],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dotenv/config'
|
||||
import config from '@payload-config'
|
||||
import { getPayload, type Payload } from 'payload'
|
||||
|
||||
import { contactFormContent } from '@/spa/contactFormContent'
|
||||
import { contactContent } from '@/spa/contactContent'
|
||||
|
||||
const mediaByFilename = async (payload: Payload, filename: string) => {
|
||||
const result = await payload.find({
|
||||
@@ -33,9 +33,11 @@ async function main() {
|
||||
if (!page) throw new Error('Contact page not found. Expected spaPath=/kontakt or slug=kontakt/contact.')
|
||||
|
||||
const [heroImage, formImage] = await Promise.all([
|
||||
mediaByFilename(payload, 'gala-dinner.jpg'),
|
||||
mediaByFilename(payload, 'preistraeger-gruppe.jpg'),
|
||||
mediaByFilename(payload, contactContent.hero.backgroundImageFilename),
|
||||
mediaByFilename(payload, contactContent.info.formImageFilename),
|
||||
])
|
||||
const { backgroundImageFilename: _heroFilename, ...heroContent } = contactContent.hero
|
||||
const { formImageFilename: _formImageFilename, ...infoContent } = contactContent.info
|
||||
|
||||
await payload.update({
|
||||
collection: 'pages',
|
||||
@@ -45,63 +47,17 @@ async function main() {
|
||||
data: {
|
||||
contact: {
|
||||
hero: {
|
||||
...heroContent,
|
||||
backgroundImage: heroImage,
|
||||
imageAlt: 'BMP Gala',
|
||||
eyebrow: 'Dialog & Service',
|
||||
heading: 'Wir sind\nfür Sie da.',
|
||||
description: 'Fragen zur Bewerbung, zur Gala oder zu Partnermöglichkeiten – unser Team begleitet Sie persönlich.',
|
||||
},
|
||||
info: {
|
||||
eyebrow: 'Direktkontakt',
|
||||
heading: 'Kontaktmöglichkeiten',
|
||||
items: [
|
||||
{ icon: 'mapPin', title: 'Geschäftsstelle', lines: 'Maximilianstraße 42\n80538 München' },
|
||||
{ icon: 'mail', title: 'E-Mail', lines: 'info@bmp-bayern.de' },
|
||||
{ icon: 'phone', title: 'Telefon', lines: '+49 89 123 456 78' },
|
||||
{ icon: 'clock', title: 'Bürozeiten', lines: 'Mo – Fr: 09:00 – 17:00 Uhr' },
|
||||
],
|
||||
nextAwardLabel: 'Nächste Preisverleihung:',
|
||||
nextAwardDate: '22. Oktober 2026',
|
||||
...infoContent,
|
||||
formImage,
|
||||
formImageAlt: 'BMP Gala 2025',
|
||||
formImageLabel: 'Gala 2025 München',
|
||||
formEyebrow: 'Kontaktformular',
|
||||
formTitle: 'Schreiben Sie uns',
|
||||
formCopy: contactFormContent,
|
||||
},
|
||||
deadlines: {
|
||||
watermark: '2026',
|
||||
eyebrow: 'Fahrplan 2026',
|
||||
items: [
|
||||
{ step: '01', label: 'Bewerbungsschluss', date: '30. Juni 2026', desc: 'Letzte Möglichkeit zur Einreichung Ihrer Unterlagen.' },
|
||||
{ step: '02', label: 'Nominierung', date: '15. August 2026', desc: 'Bekanntgabe der Nominierten nach Jury-Sichtung.' },
|
||||
{ step: '03', label: 'Preisverleihung', date: '22. Oktober 2026', desc: 'Festliche Gala in München.' },
|
||||
],
|
||||
},
|
||||
faq: {
|
||||
eyebrow: 'Antworten',
|
||||
heading: 'Häufige\nFragen',
|
||||
items: [
|
||||
{
|
||||
q: 'Was kostet die Teilnahme am BMP?',
|
||||
a: 'Die Teilnahme am Bayerischen Mittelstandspreis ist für alle Unternehmen vollständig kostenfrei. Wir finanzieren uns durch Partner und Sponsoren, um exzellenten Mittelstand ohne finanzielle Hürden zu fördern.',
|
||||
},
|
||||
{
|
||||
q: 'Nach welchen Kriterien wird bewertet?',
|
||||
a: 'Die Bewertung basiert auf vier Säulen: Zukunftsfähigkeit & Innovation, Nachhaltigkeit & Verantwortung, Unternehmenskultur sowie Regionale Verwurzelung. Jede Säule fließt mit 25 % in das Gesamtergebnis ein.',
|
||||
},
|
||||
{
|
||||
q: 'Wie läuft der Bewerbungsprozess ab?',
|
||||
a: 'Der Prozess ist mehrstufig: 1. Online-Bewerbung oder Vorschlag, 2. Formale Prüfung & erste Jury-Sichtung, 3. Fach-Audits bei den Finalisten vor Ort, 4. Finale Jury-Sitzung und abschließende Preisverleihung.',
|
||||
},
|
||||
{
|
||||
q: 'Wie lange dauert die Bewerbung?',
|
||||
a: 'Dank unseres optimierten Bewerbungsformulars benötigen Sie für die erste Einreichung ca. 30–45 Minuten. Tiefergehende Unterlagen werden erst in der Audit-Phase angefordert.',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
deadlines: contactContent.deadlines,
|
||||
faq: contactContent.faq,
|
||||
},
|
||||
} as never,
|
||||
})
|
||||
|
||||
payload.logger.info(`Preloaded contact CMS fields for page ${page.id}`)
|
||||
|
||||
61
src/spa/contactContent.ts
Normal file
61
src/spa/contactContent.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { contactFormContent } from '@/spa/contactFormContent'
|
||||
|
||||
export const contactContent = {
|
||||
hero: {
|
||||
backgroundImageFilename: 'gala-dinner.jpg',
|
||||
imageAlt: 'BMP Gala',
|
||||
eyebrow: 'Dialog & Service',
|
||||
heading: 'Wir sind\nfür Sie da.',
|
||||
description: 'Fragen zur Bewerbung, zur Gala oder zu Partnermöglichkeiten – unser Team begleitet Sie persönlich.',
|
||||
},
|
||||
info: {
|
||||
eyebrow: 'Direktkontakt',
|
||||
heading: 'Kontaktmöglichkeiten',
|
||||
items: [
|
||||
{ icon: 'mapPin', title: 'Geschäftsstelle', lines: 'Maximilianstraße 42\n80538 München' },
|
||||
{ icon: 'mail', title: 'E-Mail', lines: 'info@bmp-bayern.de' },
|
||||
{ icon: 'phone', title: 'Telefon', lines: '+49 89 123 456 78' },
|
||||
{ icon: 'clock', title: 'Bürozeiten', lines: 'Mo – Fr: 09:00 – 17:00 Uhr' },
|
||||
],
|
||||
nextAwardLabel: 'Nächste Preisverleihung:',
|
||||
nextAwardDate: '22. Oktober 2026',
|
||||
formImageFilename: 'preistraeger-gruppe.jpg',
|
||||
formImageAlt: 'BMP Gala 2025',
|
||||
formImageLabel: 'Gala 2025 München',
|
||||
formEyebrow: 'Kontaktformular',
|
||||
formTitle: 'Schreiben Sie uns',
|
||||
formCopy: contactFormContent,
|
||||
},
|
||||
deadlines: {
|
||||
watermark: '2026',
|
||||
eyebrow: 'Fahrplan 2026',
|
||||
items: [
|
||||
{ step: '01', label: 'Bewerbungsschluss', date: '30. Juni 2026', desc: 'Letzte Möglichkeit zur Einreichung Ihrer Unterlagen.' },
|
||||
{ step: '02', label: 'Nominierung', date: '15. August 2026', desc: 'Bekanntgabe der Nominierten nach Jury-Sichtung.' },
|
||||
{ step: '03', label: 'Preisverleihung', date: '22. Oktober 2026', desc: 'Festliche Gala in München.' },
|
||||
],
|
||||
},
|
||||
faq: {
|
||||
eyebrow: 'Antworten',
|
||||
heading: 'Häufige\nFragen',
|
||||
items: [
|
||||
{
|
||||
q: 'Was kostet die Teilnahme am BMP?',
|
||||
a: 'Die Teilnahme am Bayerischen Mittelstandspreis ist für alle Unternehmen vollständig kostenfrei. Wir finanzieren uns durch Partner und Sponsoren, um exzellenten Mittelstand ohne finanzielle Hürden zu fördern.',
|
||||
},
|
||||
{
|
||||
q: 'Nach welchen Kriterien wird bewertet?',
|
||||
a: 'Die Bewertung basiert auf vier Säulen: Zukunftsfähigkeit & Innovation, Nachhaltigkeit & Verantwortung, Unternehmenskultur sowie Regionale Verwurzelung. Jede Säule fließt mit 25 % in das Gesamtergebnis ein.',
|
||||
},
|
||||
{
|
||||
q: 'Wie läuft der Bewerbungsprozess ab?',
|
||||
a: 'Der Prozess ist mehrstufig: 1. Online-Bewerbung oder Vorschlag, 2. Formale Prüfung & erste Jury-Sichtung, 3. Fach-Audits bei den Finalisten vor Ort, 4. Finale Jury-Sitzung und abschließende Preisverleihung.',
|
||||
},
|
||||
{
|
||||
q: 'Wie lange dauert die Bewerbung?',
|
||||
a: 'Dank unseres optimierten Bewerbungsformulars benötigen Sie für die erste Einreichung ca. 30–45 Minuten. Tiefergehende Unterlagen werden erst in der Audit-Phase angefordert.',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField';
|
||||
import { useCmsRoute } from '@/spa/cmsRoute';
|
||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||
import type { Page } from '@/payload-types';
|
||||
import { contactContent } from '@/spa/contactContent';
|
||||
|
||||
const NAVY = '#111D55';
|
||||
const GOLD = '#EFBF04';
|
||||
@@ -17,7 +18,7 @@ type ContactCms = NonNullable<Page['contact']>;
|
||||
type ContactItem = NonNullable<NonNullable<ContactCms['info']>['items']>[number] | {
|
||||
icon: string;
|
||||
title: string;
|
||||
lines: string[];
|
||||
lines: string | string[];
|
||||
};
|
||||
type DeadlineItem = NonNullable<NonNullable<ContactCms['deadlines']>['items']>[number];
|
||||
type FaqItem = NonNullable<NonNullable<ContactCms['faq']>['items']>[number];
|
||||
@@ -39,38 +40,6 @@ const ICONS = {
|
||||
clock: Clock,
|
||||
};
|
||||
|
||||
const DEFAULT_FAQS = [
|
||||
{
|
||||
q: 'Was kostet die Teilnahme am BMP?',
|
||||
a: 'Die Teilnahme am Bayerischen Mittelstandspreis ist für alle Unternehmen vollständig kostenfrei. Wir finanzieren uns durch Partner und Sponsoren, um exzellenten Mittelstand ohne finanzielle Hürden zu fördern.',
|
||||
},
|
||||
{
|
||||
q: 'Nach welchen Kriterien wird bewertet?',
|
||||
a: 'Die Bewertung basiert auf vier Säulen: Zukunftsfähigkeit & Innovation, Nachhaltigkeit & Verantwortung, Unternehmenskultur sowie Regionale Verwurzelung. Jede Säule fließt mit 25 % in das Gesamtergebnis ein.',
|
||||
},
|
||||
{
|
||||
q: 'Wie läuft der Bewerbungsprozess ab?',
|
||||
a: 'Der Prozess ist mehrstufig: 1. Online-Bewerbung oder Vorschlag, 2. Formale Prüfung & erste Jury-Sichtung, 3. Fach-Audits bei den Finalisten vor Ort, 4. Finale Jury-Sitzung und abschließende Preisverleihung.',
|
||||
},
|
||||
{
|
||||
q: 'Wie lange dauert die Bewerbung?',
|
||||
a: 'Dank unseres optimierten Bewerbungsformulars benötigen Sie für die erste Einreichung ca. 30–45 Minuten. Tiefergehende Unterlagen werden erst in der Audit-Phase angefordert.',
|
||||
},
|
||||
];
|
||||
|
||||
const DEFAULT_DEADLINES = [
|
||||
{ step: '01', label: 'Bewerbungsschluss', date: '30. Juni 2026', desc: 'Letzte Möglichkeit zur Einreichung Ihrer Unterlagen.' },
|
||||
{ step: '02', label: 'Nominierung', date: '15. August 2026', desc: 'Bekanntgabe der Nominierten nach Jury-Sichtung.' },
|
||||
{ step: '03', label: 'Preisverleihung', date: '22. Oktober 2026', desc: 'Festliche Gala in München.' },
|
||||
];
|
||||
|
||||
const DEFAULT_CONTACT_ITEMS = [
|
||||
{ icon: 'mapPin', title: 'Geschäftsstelle', lines: ['Maximilianstraße 42', '80538 München'] },
|
||||
{ icon: 'mail', title: 'E-Mail', lines: ['info@bmp-bayern.de'] },
|
||||
{ icon: 'phone', title: 'Telefon', lines: ['+49 89 123 456 78'] },
|
||||
{ icon: 'clock', title: 'Bürozeiten', lines: ['Mo – Fr: 09:00 – 17:00 Uhr'] },
|
||||
];
|
||||
|
||||
const Contact: React.FC = () => {
|
||||
const [openFaq, setOpenFaq] = useState<number | null>(0);
|
||||
const isMobile = useIsMobile();
|
||||
@@ -79,9 +48,9 @@ const Contact: React.FC = () => {
|
||||
const info = contact.info || {};
|
||||
const deadlines = contact.deadlines || {};
|
||||
const faq = contact.faq || {};
|
||||
const contactItems = fallbackArray<ContactItem>(info.items, DEFAULT_CONTACT_ITEMS);
|
||||
const deadlineItems = fallbackArray<DeadlineItem>(deadlines.items, DEFAULT_DEADLINES);
|
||||
const faqItems = fallbackArray<FaqItem>(faq.items, DEFAULT_FAQS);
|
||||
const contactItems = fallbackArray<ContactItem>(info.items, contactContent.info.items);
|
||||
const deadlineItems = fallbackArray<DeadlineItem>(deadlines.items, contactContent.deadlines.items);
|
||||
const faqItems = fallbackArray<FaqItem>(faq.items, contactContent.faq.items);
|
||||
|
||||
return (
|
||||
<div style={{ background: CREAM }}>
|
||||
@@ -89,8 +58,8 @@ const Contact: React.FC = () => {
|
||||
{/* ── Hero ───────────────────────────────────────────────────────── */}
|
||||
<section style={{ position: 'relative', height: '68vh', minHeight: 520, overflow: 'hidden', display: 'flex', alignItems: 'flex-end' }}>
|
||||
<Image unoptimized
|
||||
src={mediaUrl(hero.backgroundImage, '/images/gala-dinner.jpg')}
|
||||
alt={mediaAlt(hero.backgroundImage, fallbackText(hero.imageAlt, 'BMP Gala'))}
|
||||
src={mediaUrl(hero.backgroundImage, `/images/${contactContent.hero.backgroundImageFilename}`)}
|
||||
alt={mediaAlt(hero.backgroundImage, fallbackText(hero.imageAlt, contactContent.hero.imageAlt))}
|
||||
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 40%' }}
|
||||
/>
|
||||
{/* Diagonal overlay */}
|
||||
@@ -100,13 +69,13 @@ const Contact: React.FC = () => {
|
||||
|
||||
<div style={{ position: 'relative', zIndex: 2, width: '100%', paddingBottom: isMobile ? '3rem' : '5rem', paddingLeft: isMobile ? 24 : 80, paddingRight: isMobile ? 24 : 80 }}>
|
||||
<p style={{ fontSize: 11, fontWeight: 800, letterSpacing: '0.28em', textTransform: 'uppercase', color: GOLD, marginBottom: 16 }}>
|
||||
{fallbackText(hero.eyebrow, 'Dialog & Service')}
|
||||
{fallbackText(hero.eyebrow, contactContent.hero.eyebrow)}
|
||||
</p>
|
||||
<h1 style={{ fontSize: isMobile ? 'clamp(2rem, 10vw, 3rem)' : 'clamp(3rem, 7vw, 6rem)', fontWeight: 900, lineHeight: 1.0, color: '#fff', letterSpacing: '-0.03em', marginBottom: 24, maxWidth: 640 }}>
|
||||
<Lines text={fallbackText(hero.heading, 'Wir sind\nfür Sie da.')} />
|
||||
<Lines text={fallbackText(hero.heading, contactContent.hero.heading)} />
|
||||
</h1>
|
||||
<p style={{ fontSize: 18, color: 'rgba(255,255,255,0.72)', maxWidth: 480, lineHeight: 1.65, fontWeight: 400 }}>
|
||||
{fallbackText(hero.description, 'Fragen zur Bewerbung, zur Gala oder zu Partnermöglichkeiten – unser Team begleitet Sie persönlich.')}
|
||||
{fallbackText(hero.description, contactContent.hero.description)}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -121,11 +90,11 @@ const Contact: React.FC = () => {
|
||||
{/* Left – info panel */}
|
||||
<div style={{ padding: isMobile ? '48px 24px' : '88px 56px 88px 64px', display: 'flex', flexDirection: 'column', justifyContent: 'center', position: 'relative' }}>
|
||||
<p style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.28em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.4)', marginBottom: 20 }}>
|
||||
{fallbackText(info.eyebrow, 'Direktkontakt')}
|
||||
{fallbackText(info.eyebrow, contactContent.info.eyebrow)}
|
||||
</p>
|
||||
<div style={{ width: 36, height: 2, background: GOLD, marginBottom: 20 }} />
|
||||
<h2 style={{ fontSize: 'clamp(1.6rem, 3vw, 2.4rem)', fontWeight: 900, color: '#fff', lineHeight: 1.15, letterSpacing: '-0.03em', marginBottom: 52 }}>
|
||||
<Lines text={fallbackText(info.heading, 'Kontaktmöglichkeiten')} />
|
||||
<Lines text={fallbackText(info.heading, contactContent.info.heading)} />
|
||||
</h2>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
|
||||
@@ -152,7 +121,7 @@ const Contact: React.FC = () => {
|
||||
|
||||
<div style={{ marginTop: 52, paddingTop: 28, borderTop: '1px solid rgba(255,255,255,0.10)' }}>
|
||||
<p style={{ fontSize: 15, color: 'rgba(255,255,255,0.40)', lineHeight: 1.65 }}>
|
||||
{fallbackText(info.nextAwardLabel, 'Nächste Preisverleihung:')} <strong style={{ color: '#fff' }}>{fallbackText(info.nextAwardDate, '22. Oktober 2026')}</strong>
|
||||
{fallbackText(info.nextAwardLabel, contactContent.info.nextAwardLabel)} <strong style={{ color: '#fff' }}>{fallbackText(info.nextAwardDate, contactContent.info.nextAwardDate)}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,19 +147,19 @@ const Contact: React.FC = () => {
|
||||
|
||||
{!isMobile && (
|
||||
<div style={{ height: 200, position: 'relative', overflow: 'hidden', flexShrink: 0, zIndex: 1 }}>
|
||||
<Image unoptimized src={mediaUrl(info.formImage, '/images/preistraeger-gruppe.jpg')} alt={mediaAlt(info.formImage, fallbackText(info.formImageAlt, 'BMP Gala 2025'))} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 30%', filter: 'sepia(0.18) brightness(0.92)' }} />
|
||||
<Image unoptimized src={mediaUrl(info.formImage, `/images/${contactContent.info.formImageFilename}`)} alt={mediaAlt(info.formImage, fallbackText(info.formImageAlt, contactContent.info.formImageAlt))} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 30%', filter: 'sepia(0.18) brightness(0.92)' }} />
|
||||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to bottom, rgba(168,120,0,0.1) 0%, rgba(168,120,0,0.25) 50%, rgba(168,120,0,0.92) 88%, #A87800 100%)' }} />
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: 2, background: 'rgba(17,29,85,0.35)' }} />
|
||||
<div style={{ position: 'absolute', bottom: 14, left: 40, display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ width: 5, height: 5, borderRadius: '50%', background: 'rgba(17,29,85,0.7)' }} />
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 10, fontWeight: 700, color: 'rgba(17,29,85,0.75)', textTransform: 'uppercase', letterSpacing: '0.2em' }}>{fallbackText(info.formImageLabel, 'Gala 2025 München')}</span>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 10, fontWeight: 700, color: 'rgba(17,29,85,0.75)', textTransform: 'uppercase', letterSpacing: '0.2em' }}>{fallbackText(info.formImageLabel, contactContent.info.formImageLabel)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '36px 20px' : '32px 48px 32px 40px', flex: isMobile ? 'none' : 1, display: 'flex', flexDirection: 'column', minHeight: isMobile ? 480 : 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 8 }}>{fallbackText(info.formEyebrow, 'Kontaktformular')}</span>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 8 }}>{fallbackText(info.formEyebrow, contactContent.info.formEyebrow)}</span>
|
||||
<h3 style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 'clamp(1.2rem, 1.8vw, 1.6rem)', fontWeight: 900, color: '#111D55', letterSpacing: '-0.025em', textTransform: 'uppercase', lineHeight: 1.1, marginBottom: 24 }}>
|
||||
{fallbackText(info.formTitle, 'Schreiben Sie uns')}
|
||||
{fallbackText(info.formTitle, contactContent.info.formTitle)}
|
||||
</h3>
|
||||
<KontaktForm theme="gold" content={info.formCopy || undefined} />
|
||||
</div>
|
||||
@@ -201,12 +170,12 @@ const Contact: React.FC = () => {
|
||||
{/* ── Deadlines ──────────────────────────────────────────────────── */}
|
||||
<section style={{ background: '#0D1640', padding: isMobile ? '56px 0' : '88px 0', position: 'relative', overflow: 'hidden' }}>
|
||||
<div style={{ position: 'absolute', right: -20, top: '50%', transform: 'translateY(-50%)', fontSize: 'clamp(160px, 22vw, 280px)', fontWeight: 900, color: '#fff', opacity: 0.025, lineHeight: 1, pointerEvents: 'none', userSelect: 'none', letterSpacing: '-0.05em' }}>
|
||||
{fallbackText(deadlines.watermark, '2026')}
|
||||
{fallbackText(deadlines.watermark, contactContent.deadlines.watermark)}
|
||||
</div>
|
||||
<div className="container mx-auto px-6" style={{ position: 'relative' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 20, marginBottom: isMobile ? 48 : 72 }}>
|
||||
<span style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.28em', textTransform: 'uppercase', color: '#EFBF04', whiteSpace: 'nowrap' }}>
|
||||
{fallbackText(deadlines.eyebrow, 'Fahrplan 2026')}
|
||||
{fallbackText(deadlines.eyebrow, contactContent.deadlines.eyebrow)}
|
||||
</span>
|
||||
<div style={{ flex: 1, height: 1, background: 'rgba(255,255,255,0.10)' }} />
|
||||
</div>
|
||||
@@ -248,11 +217,11 @@ const Contact: React.FC = () => {
|
||||
{/* Left – sticky label */}
|
||||
<div style={isMobile ? undefined : { position: 'sticky', top: 96, alignSelf: 'start' }}>
|
||||
<p style={{ fontSize: 10, fontWeight: 800, letterSpacing: '0.28em', textTransform: 'uppercase', color: '#4A8FC9', marginBottom: 20 }}>
|
||||
{fallbackText(faq.eyebrow, 'Antworten')}
|
||||
{fallbackText(faq.eyebrow, contactContent.faq.eyebrow)}
|
||||
</p>
|
||||
<div style={{ width: 28, height: 2, background: GOLD, marginBottom: 20 }} />
|
||||
<h2 style={{ fontSize: isMobile ? 'clamp(1.8rem, 8vw, 2.4rem)' : 'clamp(2rem, 3.5vw, 2.8rem)', fontWeight: 900, color: NAVY, letterSpacing: '-0.03em', lineHeight: 1.1 }}>
|
||||
<Lines text={fallbackText(faq.heading, 'Häufige\nFragen')} />
|
||||
<Lines text={fallbackText(faq.heading, contactContent.faq.heading)} />
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user