feat: manage contact form copy via payload
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import type { Field } from 'payload'
|
||||
|
||||
import { contactFormContent } from '@/spa/contactFormContent'
|
||||
|
||||
const uploadField = (name: string, label: string, description?: string): Field => ({
|
||||
name,
|
||||
type: 'upload',
|
||||
@@ -96,6 +98,82 @@ export const contactFields: Field[] = [
|
||||
text('formImageLabel', 'Form image label', 'Gala 2025 München'),
|
||||
text('formEyebrow', 'Form eyebrow', 'Kontaktformular'),
|
||||
text('formTitle', 'Form title', 'Schreiben Sie uns'),
|
||||
{
|
||||
name: 'formCopy',
|
||||
label: 'Contact form copy',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Step labels, subject choices, field labels, validation messages, and success copy.'),
|
||||
fields: [
|
||||
{
|
||||
name: 'steps',
|
||||
label: 'Step labels',
|
||||
type: 'array',
|
||||
defaultValue: contactFormContent.steps,
|
||||
fields: [text('label', 'Label')],
|
||||
},
|
||||
{
|
||||
name: 'subjects',
|
||||
label: 'Subject choices',
|
||||
type: 'array',
|
||||
defaultValue: contactFormContent.subjects,
|
||||
fields: [text('value', 'Value'), text('label', 'Label'), textarea('desc', 'Description')],
|
||||
},
|
||||
{
|
||||
name: 'prompts',
|
||||
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),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'fields',
|
||||
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),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'validation',
|
||||
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),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'navigation',
|
||||
label: 'Navigation labels',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('back', 'Back', contactFormContent.navigation.back),
|
||||
text('next', 'Next', contactFormContent.navigation.next),
|
||||
text('submit', 'Submit', contactFormContent.navigation.submit),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'success',
|
||||
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),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -456,6 +456,54 @@ export interface Page {
|
||||
formImageLabel?: string | null;
|
||||
formEyebrow?: string | null;
|
||||
formTitle?: string | null;
|
||||
/**
|
||||
* Step labels, subject choices, field labels, validation messages, and success copy.
|
||||
*/
|
||||
formCopy?: {
|
||||
steps?:
|
||||
| {
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
subjects?:
|
||||
| {
|
||||
value?: string | null;
|
||||
label?: string | null;
|
||||
desc?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
prompts?: {
|
||||
subject?: string | null;
|
||||
contact?: string | null;
|
||||
message?: string | null;
|
||||
};
|
||||
fields?: {
|
||||
nameLabel?: string | null;
|
||||
namePlaceholder?: string | null;
|
||||
emailLabel?: string | null;
|
||||
emailPlaceholder?: string | null;
|
||||
messageLabel?: string | null;
|
||||
messagePlaceholder?: string | null;
|
||||
};
|
||||
validation?: {
|
||||
nameRequired?: string | null;
|
||||
emailRequired?: string | null;
|
||||
emailInvalid?: string | null;
|
||||
messageRequired?: string | null;
|
||||
};
|
||||
navigation?: {
|
||||
back?: string | null;
|
||||
next?: string | null;
|
||||
submit?: string | null;
|
||||
};
|
||||
success?: {
|
||||
heading?: string | null;
|
||||
prefix?: string | null;
|
||||
suffixBeforeEmail?: string | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Dark 2026 timeline with three deadline columns.
|
||||
@@ -3211,6 +3259,63 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
formImageLabel?: T;
|
||||
formEyebrow?: T;
|
||||
formTitle?: T;
|
||||
formCopy?:
|
||||
| T
|
||||
| {
|
||||
steps?:
|
||||
| T
|
||||
| {
|
||||
label?: T;
|
||||
id?: T;
|
||||
};
|
||||
subjects?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
label?: T;
|
||||
desc?: T;
|
||||
id?: T;
|
||||
};
|
||||
prompts?:
|
||||
| T
|
||||
| {
|
||||
subject?: T;
|
||||
contact?: T;
|
||||
message?: T;
|
||||
};
|
||||
fields?:
|
||||
| T
|
||||
| {
|
||||
nameLabel?: T;
|
||||
namePlaceholder?: T;
|
||||
emailLabel?: T;
|
||||
emailPlaceholder?: T;
|
||||
messageLabel?: T;
|
||||
messagePlaceholder?: T;
|
||||
};
|
||||
validation?:
|
||||
| T
|
||||
| {
|
||||
nameRequired?: T;
|
||||
emailRequired?: T;
|
||||
emailInvalid?: T;
|
||||
messageRequired?: T;
|
||||
};
|
||||
navigation?:
|
||||
| T
|
||||
| {
|
||||
back?: T;
|
||||
next?: T;
|
||||
submit?: T;
|
||||
};
|
||||
success?:
|
||||
| T
|
||||
| {
|
||||
heading?: T;
|
||||
prefix?: T;
|
||||
suffixBeforeEmail?: T;
|
||||
};
|
||||
};
|
||||
};
|
||||
deadlines?:
|
||||
| T
|
||||
|
||||
@@ -3,6 +3,8 @@ import 'dotenv/config'
|
||||
import config from '@payload-config'
|
||||
import { getPayload, type Payload } from 'payload'
|
||||
|
||||
import { contactFormContent } from '@/spa/contactFormContent'
|
||||
|
||||
const mediaByFilename = async (payload: Payload, filename: string) => {
|
||||
const result = await payload.find({
|
||||
collection: 'media',
|
||||
@@ -65,6 +67,7 @@ async function main() {
|
||||
formImageLabel: 'Gala 2025 München',
|
||||
formEyebrow: 'Kontaktformular',
|
||||
formTitle: 'Schreiben Sie uns',
|
||||
formCopy: contactFormContent,
|
||||
},
|
||||
deadlines: {
|
||||
watermark: '2026',
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { ArrowRight, ArrowLeft, Check, MessageSquare, User, Send } from 'lucide-react';
|
||||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||||
import { contactFormContent } from '@/spa/contactFormContent';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -94,18 +95,27 @@ type FormData = {
|
||||
nachricht: string;
|
||||
};
|
||||
|
||||
const STEPS = [
|
||||
{ label: 'Betreff', icon: MessageSquare },
|
||||
{ label: 'Kontakt', icon: User },
|
||||
{ label: 'Nachricht', icon: Send },
|
||||
];
|
||||
type ContactFormCopy = typeof contactFormContent;
|
||||
type SubjectChoice = (typeof contactFormContent.subjects)[number];
|
||||
|
||||
const BETREFFS = [
|
||||
{ value: 'allgemein', label: 'Allgemeine Anfrage', desc: 'Ich habe eine allgemeine Frage.' },
|
||||
{ value: 'bewerbung', label: 'Frage zur Bewerbung', desc: 'Ich möchte mich bewerben oder habe Rückfragen.' },
|
||||
{ value: 'presse', label: 'Presseanfrage', desc: 'Ich bin Journalist:in und recherchiere zum BMP.' },
|
||||
{ value: 'sponsoring', label: 'Sponsoring', desc: 'Ich interessiere mich für eine Partnerschaft.' },
|
||||
];
|
||||
const STEP_ICONS = [MessageSquare, User, Send];
|
||||
const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback;
|
||||
const fallbackArray = <T,>(value: unknown, fallback: T[]) => Array.isArray(value) && value.length ? value as T[] : fallback;
|
||||
|
||||
function mergeCopy(content?: unknown): ContactFormCopy {
|
||||
const data = (content && typeof content === 'object' ? content : {}) as Partial<ContactFormCopy>;
|
||||
return {
|
||||
...contactFormContent,
|
||||
...data,
|
||||
steps: fallbackArray(data.steps, contactFormContent.steps),
|
||||
subjects: fallbackArray(data.subjects, contactFormContent.subjects),
|
||||
prompts: { ...contactFormContent.prompts, ...data.prompts },
|
||||
fields: { ...contactFormContent.fields, ...data.fields },
|
||||
validation: { ...contactFormContent.validation, ...data.validation },
|
||||
navigation: { ...contactFormContent.navigation, ...data.navigation },
|
||||
success: { ...contactFormContent.success, ...data.success },
|
||||
};
|
||||
}
|
||||
|
||||
const variants = {
|
||||
enter: (dir: number) => ({ x: dir > 0 ? 40 : -40, opacity: 0 }),
|
||||
@@ -156,7 +166,7 @@ function StyledTextarea({ c, ...props }: React.TextareaHTMLAttributes<HTMLTextAr
|
||||
);
|
||||
}
|
||||
|
||||
function BetreffCard({ c, item, selected, onClick }: { c: C; item: typeof BETREFFS[0]; selected: boolean; onClick: () => void }) {
|
||||
function BetreffCard({ c, item, selected, onClick }: { c: C; item: SubjectChoice; selected: boolean; onClick: () => void }) {
|
||||
return (
|
||||
<button
|
||||
type="button" onClick={onClick}
|
||||
@@ -184,7 +194,8 @@ function BetreffCard({ c, item, selected, onClick }: { c: C; item: typeof BETREF
|
||||
);
|
||||
}
|
||||
|
||||
export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold' }) {
|
||||
export default function KontaktForm({ theme = 'dark', content }: { theme?: 'dark' | 'gold'; content?: unknown }) {
|
||||
const copy = mergeCopy(content);
|
||||
const c = theme === 'gold' ? GOLD : DARK;
|
||||
const isMobile = useIsMobile();
|
||||
const [step, setStep] = useState(0);
|
||||
@@ -201,11 +212,11 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
const validate = () => {
|
||||
const e: typeof errors = {};
|
||||
if (step === 1) {
|
||||
if (!data.name) e.name = 'Bitte Namen angeben';
|
||||
if (!data.email) e.email = 'Bitte E-Mail angeben';
|
||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) e.email = 'Ungültige E-Mail';
|
||||
if (!data.name) e.name = copy.validation.nameRequired;
|
||||
if (!data.email) e.email = copy.validation.emailRequired;
|
||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) e.email = copy.validation.emailInvalid;
|
||||
}
|
||||
if (step === 2 && !data.nachricht) e.nachricht = 'Bitte Nachricht verfassen.';
|
||||
if (step === 2 && !data.nachricht) e.nachricht = copy.validation.messageRequired;
|
||||
setErrors(e);
|
||||
return Object.keys(e).length === 0;
|
||||
};
|
||||
@@ -223,10 +234,10 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
<Check size={24} color={c.successIconIn} strokeWidth={2.5} />
|
||||
</div>
|
||||
<h3 style={{ fontSize: 20, fontWeight: 800, color: c.successHeading, marginBottom: 10, letterSpacing: '-0.02em', fontFamily: FF }}>
|
||||
Nachricht gesendet
|
||||
{fallbackText(copy.success.heading, contactFormContent.success.heading)}
|
||||
</h3>
|
||||
<p style={{ fontSize: 15, color: c.successBody, lineHeight: 1.7, maxWidth: 280, margin: '0 auto', fontFamily: FF, overflowWrap: 'anywhere' }}>
|
||||
Danke, <strong style={{ color: c.successHeading }}>{data.name}</strong>. Wir melden uns zeitnah bei{' '}
|
||||
{fallbackText(copy.success.prefix, contactFormContent.success.prefix)} <strong style={{ color: c.successHeading }}>{data.name}</strong>. {fallbackText(copy.success.suffixBeforeEmail, contactFormContent.success.suffixBeforeEmail)}{' '}
|
||||
<strong style={{ color: c.successIcon }}>{data.email}</strong>.
|
||||
</p>
|
||||
</motion.div>
|
||||
@@ -237,13 +248,13 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}>
|
||||
{/* Progress */}
|
||||
<div style={{ height: 3, background: c.progressBg, flexShrink: 0 }}>
|
||||
<div style={{ height: '100%', background: c.progressFill, width: step === 0 ? '0%' : `${(step / (STEPS.length - 1)) * 100}%`, transition: 'width 0.4s ease' }} />
|
||||
<div style={{ height: '100%', background: c.progressFill, width: step === 0 ? '0%' : `${(step / (copy.steps.length - 1)) * 100}%`, transition: 'width 0.4s ease' }} />
|
||||
</div>
|
||||
|
||||
{/* Step tabs */}
|
||||
<div style={{ display: 'flex', borderBottom: `1px solid ${c.border}`, flexShrink: 0 }}>
|
||||
{STEPS.map((s, i) => {
|
||||
const Icon = s.icon;
|
||||
{copy.steps.map((s, i) => {
|
||||
const Icon = STEP_ICONS[i] || Send;
|
||||
const done = i < step, active = i === step;
|
||||
return (
|
||||
<div key={i} style={{
|
||||
@@ -256,7 +267,7 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
marginBottom: -1, transition: 'color 0.2s',
|
||||
}}>
|
||||
<Icon size={11} strokeWidth={active ? 2 : 1.5} />
|
||||
<span>{done ? '✓' : s.label}</span>
|
||||
<span>{done ? '✓' : fallbackText(s.label, contactFormContent.steps[i]?.label || '')}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -271,8 +282,8 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
|
||||
{step === 0 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 12, fontFamily: FF }}>Womit können wir Ihnen helfen?</p>
|
||||
{BETREFFS.map(item => (
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 12, fontFamily: FF }}>{fallbackText(copy.prompts.subject, contactFormContent.prompts.subject)}</p>
|
||||
{copy.subjects.map(item => (
|
||||
<BetreffCard key={item.value} c={c} item={item} selected={data.betreff === item.value}
|
||||
onClick={() => { set('betreff', item.value); setDir(1); setStep(1); }} />
|
||||
))}
|
||||
@@ -281,10 +292,10 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
|
||||
{step === 1 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 4, fontFamily: FF }}>Wie dürfen wir Sie kontaktieren?</p>
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 4, fontFamily: FF }}>{fallbackText(copy.prompts.contact, contactFormContent.prompts.contact)}</p>
|
||||
{([
|
||||
{ label: 'Name', key: 'name' as const, type: 'text', placeholder: 'Vor- und Nachname', error: errors.name },
|
||||
{ label: 'E-Mail', key: 'email' as const, type: 'email', placeholder: 'ihre@email.de', error: errors.email },
|
||||
{ label: copy.fields.nameLabel, key: 'name' as const, type: 'text', placeholder: copy.fields.namePlaceholder, error: errors.name },
|
||||
{ label: copy.fields.emailLabel, key: 'email' as const, type: 'email', placeholder: copy.fields.emailPlaceholder, error: errors.email },
|
||||
] as const).map(f => (
|
||||
<div key={f.key} style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<label style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: c.labelText, fontFamily: FF }}>{f.label}</label>
|
||||
@@ -297,10 +308,10 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
|
||||
{step === 2 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 4, fontFamily: FF }}>Was möchten Sie uns mitteilen?</p>
|
||||
<p style={{ fontSize: 14, color: c.subtext, marginBottom: 4, fontFamily: FF }}>{fallbackText(copy.prompts.message, contactFormContent.prompts.message)}</p>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
<label style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: c.labelText, fontFamily: FF }}>Nachricht</label>
|
||||
<StyledTextarea c={c} value={data.nachricht} onChange={e => set('nachricht', e.target.value)} rows={5} placeholder="Schreiben Sie Ihre Nachricht…" />
|
||||
<label style={{ fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: c.labelText, fontFamily: FF }}>{fallbackText(copy.fields.messageLabel, contactFormContent.fields.messageLabel)}</label>
|
||||
<StyledTextarea c={c} value={data.nachricht} onChange={e => set('nachricht', e.target.value)} rows={5} placeholder={fallbackText(copy.fields.messagePlaceholder, contactFormContent.fields.messagePlaceholder)} />
|
||||
{errors.nachricht && <span style={{ fontSize: 11, color: c.errorText, fontFamily: FF }}>{errors.nachricht}</span>}
|
||||
</div>
|
||||
</div>
|
||||
@@ -320,10 +331,10 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
onMouseEnter={e => (e.currentTarget.style.color = c.backTextHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.color = c.backText)}
|
||||
>
|
||||
<ArrowLeft size={13} /> Zurück
|
||||
<ArrowLeft size={13} /> {fallbackText(copy.navigation.back, contactFormContent.navigation.back)}
|
||||
</button>
|
||||
|
||||
{step < STEPS.length - 1 ? (
|
||||
{step < copy.steps.length - 1 ? (
|
||||
<button type="button" onClick={next} style={{
|
||||
fontSize: 14, fontWeight: 700, color: c.btnText, background: c.btnBg, border: 'none', cursor: 'pointer',
|
||||
padding: '12px 28px', fontFamily: FF, display: 'flex', alignItems: 'center', gap: 8,
|
||||
@@ -333,7 +344,7 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
onMouseEnter={e => (e.currentTarget.style.background = c.btnBgHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.background = c.btnBg)}
|
||||
>
|
||||
Weiter <ArrowRight size={14} />
|
||||
{fallbackText(copy.navigation.next, contactFormContent.navigation.next)} <ArrowRight size={14} />
|
||||
</button>
|
||||
) : (
|
||||
<button type="button" onClick={submit} style={{
|
||||
@@ -345,7 +356,7 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
onMouseEnter={e => (e.currentTarget.style.background = c.btnBgHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.background = c.btnBg)}
|
||||
>
|
||||
Anfrage senden <Send size={14} />
|
||||
{fallbackText(copy.navigation.submit, contactFormContent.navigation.submit)} <Send size={14} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
42
src/spa/contactFormContent.ts
Normal file
42
src/spa/contactFormContent.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export const contactFormContent = {
|
||||
steps: [
|
||||
{ label: 'Betreff' },
|
||||
{ label: 'Kontakt' },
|
||||
{ label: 'Nachricht' },
|
||||
],
|
||||
subjects: [
|
||||
{ value: 'allgemein', label: 'Allgemeine Anfrage', desc: 'Ich habe eine allgemeine Frage.' },
|
||||
{ value: 'bewerbung', label: 'Frage zur Bewerbung', desc: 'Ich möchte mich bewerben oder habe Rückfragen.' },
|
||||
{ value: 'presse', label: 'Presseanfrage', desc: 'Ich bin Journalist:in und recherchiere zum BMP.' },
|
||||
{ value: 'sponsoring', label: 'Sponsoring', desc: 'Ich interessiere mich für eine Partnerschaft.' },
|
||||
],
|
||||
prompts: {
|
||||
subject: 'Womit können wir Ihnen helfen?',
|
||||
contact: 'Wie dürfen wir Sie kontaktieren?',
|
||||
message: 'Was möchten Sie uns mitteilen?',
|
||||
},
|
||||
fields: {
|
||||
nameLabel: 'Name',
|
||||
namePlaceholder: 'Vor- und Nachname',
|
||||
emailLabel: 'E-Mail',
|
||||
emailPlaceholder: 'ihre@email.de',
|
||||
messageLabel: 'Nachricht',
|
||||
messagePlaceholder: 'Schreiben Sie Ihre Nachricht…',
|
||||
},
|
||||
validation: {
|
||||
nameRequired: 'Bitte Namen angeben',
|
||||
emailRequired: 'Bitte E-Mail angeben',
|
||||
emailInvalid: 'Ungültige E-Mail',
|
||||
messageRequired: 'Bitte Nachricht verfassen.',
|
||||
},
|
||||
navigation: {
|
||||
back: 'Zurück',
|
||||
next: 'Weiter',
|
||||
submit: 'Anfrage senden',
|
||||
},
|
||||
success: {
|
||||
heading: 'Nachricht gesendet',
|
||||
prefix: 'Danke,',
|
||||
suffixBeforeEmail: 'Wir melden uns zeitnah bei',
|
||||
},
|
||||
}
|
||||
@@ -192,7 +192,7 @@ const Contact: React.FC = () => {
|
||||
<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')}
|
||||
</h3>
|
||||
<KontaktForm theme="gold" />
|
||||
<KontaktForm theme="gold" content={info.formCopy || undefined} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user