feat: manage netzwerk page via payload
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
"preload:formular-upload-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-formular-upload-page-cms.ts",
|
||||
"preload:home-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-home-page-cms.ts",
|
||||
"preload:impressum-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-impressum-page-cms.ts",
|
||||
"preload:netzwerk-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-netzwerk-page-cms.ts",
|
||||
"preload:participation-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-participation-page-cms.ts",
|
||||
"preload:preistraeger-index-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-preistraeger-index-page-cms.ts",
|
||||
"preload:press-index-page-cms": "cross-env NODE_OPTIONS=--no-deprecation tsx src/scripts/preload-press-index-page-cms.ts",
|
||||
|
||||
@@ -14,6 +14,7 @@ import { datenschutzFields } from './datenschutzFields'
|
||||
import { formularUploadFields } from './formularUploadFields'
|
||||
import { homeFields } from './homeFields'
|
||||
import { impressumFields } from './impressumFields'
|
||||
import { netzwerkFields } from './netzwerkFields'
|
||||
import { participationFields } from './participationFields'
|
||||
import { preistraegerIndexFields } from './preistraegerIndexFields'
|
||||
import { pressIndexFields } from './pressIndexFields'
|
||||
@@ -102,6 +103,14 @@ const isFormularUploadPage = (_: unknown, siblingData?: { slug?: string; spaPath
|
||||
return spaPath === '/formular-hochladen' || slug === 'formular-hochladen' || slug === 'upload' || title === 'formular hochladen'
|
||||
}
|
||||
|
||||
const isNetzwerkPage = (_: unknown, siblingData?: { slug?: string; spaPath?: string; title?: string }) => {
|
||||
const slug = siblingData?.slug
|
||||
const spaPath = siblingData?.spaPath
|
||||
const title = siblingData?.title?.toLowerCase()
|
||||
|
||||
return spaPath === '/netzwerk' || slug === 'netzwerk' || slug === 'network' || title === 'netzwerk' || title === 'network'
|
||||
}
|
||||
|
||||
const isManagedSpaPage = (_: unknown, siblingData?: { slug?: string; spaPath?: string; title?: string }) =>
|
||||
isHomePage(undefined, siblingData) ||
|
||||
isContactPage(undefined, siblingData) ||
|
||||
@@ -111,7 +120,8 @@ const isManagedSpaPage = (_: unknown, siblingData?: { slug?: string; spaPath?: s
|
||||
isDatenschutzPage(undefined, siblingData) ||
|
||||
isPreistraegerIndexPage(undefined, siblingData) ||
|
||||
isPressIndexPage(undefined, siblingData) ||
|
||||
isFormularUploadPage(undefined, siblingData)
|
||||
isFormularUploadPage(undefined, siblingData) ||
|
||||
isNetzwerkPage(undefined, siblingData)
|
||||
|
||||
export const Pages: CollectionConfig<'pages'> = {
|
||||
slug: 'pages',
|
||||
@@ -242,6 +252,13 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
fields: formularUploadFields,
|
||||
label: 'Formular Upload Page',
|
||||
},
|
||||
{
|
||||
admin: {
|
||||
condition: (data) => isNetzwerkPage(undefined, data),
|
||||
},
|
||||
fields: netzwerkFields,
|
||||
label: 'Network Page',
|
||||
},
|
||||
{
|
||||
name: 'meta',
|
||||
label: 'SEO',
|
||||
|
||||
334
src/collections/Pages/netzwerkFields.ts
Normal file
334
src/collections/Pages/netzwerkFields.ts
Normal file
@@ -0,0 +1,334 @@
|
||||
import type { Field } from 'payload'
|
||||
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent'
|
||||
|
||||
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 numberField = (name: string, label: string, defaultValue?: number): Field => ({
|
||||
name,
|
||||
type: 'number',
|
||||
label,
|
||||
defaultValue,
|
||||
})
|
||||
|
||||
const uploadField = (name: string, label: string, description?: string): Field => ({
|
||||
name,
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label,
|
||||
admin: description ? { description } : undefined,
|
||||
})
|
||||
|
||||
const sectionAdmin = (description: string) => ({
|
||||
description,
|
||||
initCollapsed: true,
|
||||
})
|
||||
|
||||
const statFields: Field[] = [text('value', 'Value'), text('label', 'Label')]
|
||||
|
||||
const personFields: Field[] = [
|
||||
text('image', 'Image URL'),
|
||||
text('imageAlt', 'Image alt text'),
|
||||
text('name', 'Name'),
|
||||
text('titleLine1', 'Title line 1'),
|
||||
text('titleLine2', 'Title line 2'),
|
||||
text('institution', 'Institution'),
|
||||
]
|
||||
|
||||
const juryMemberFields: Field[] = [
|
||||
text('name', 'Name'),
|
||||
text('role', 'Role'),
|
||||
textarea('bio', 'Bio'),
|
||||
text('image', 'Image URL'),
|
||||
]
|
||||
|
||||
const rowFields: Field[] = [text('num', 'Number'), text('label', 'Label'), textarea('body', 'Body')]
|
||||
|
||||
const partnerFields: Field[] = [
|
||||
text('id', 'Stable ID'),
|
||||
text('name', 'Name'),
|
||||
text('role', 'Role'),
|
||||
numberField('tier', 'Tier'),
|
||||
textarea('desc', 'Short description'),
|
||||
textarea('fullDesc', 'Full modal description'),
|
||||
{
|
||||
name: 'logoKind',
|
||||
label: 'Logo style',
|
||||
type: 'select',
|
||||
defaultValue: 'text',
|
||||
options: [
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'Serif text', value: 'serif' },
|
||||
{ label: 'Badge', value: 'badge' },
|
||||
{ label: 'Monogram', value: 'monogram' },
|
||||
{ label: 'Dot mark', value: 'dot' },
|
||||
{ label: 'Leaf mark', value: 'leaf' },
|
||||
{ label: 'RSM blocks', value: 'rsm' },
|
||||
{ label: 'Deutsche Bank mark', value: 'deutschebank' },
|
||||
],
|
||||
},
|
||||
text('logoText', 'Logo text'),
|
||||
text('logoSubtext', 'Logo subtext'),
|
||||
text('logoColor', 'Logo color'),
|
||||
text('industry', 'Industry'),
|
||||
text('location', 'Location'),
|
||||
text('website', 'Website'),
|
||||
text('linkedin', 'LinkedIn URL'),
|
||||
text('heroImg', 'Modal hero image URL'),
|
||||
]
|
||||
|
||||
const benefitFields: Field[] = [text('num', 'Number'), text('label', 'Label'), text('sub', 'Subline')]
|
||||
const packageFields: Field[] = [text('value', 'Value'), text('title', 'Title'), textarea('desc', 'Description')]
|
||||
const formStepFields: Field[] = [text('label', 'Label')]
|
||||
|
||||
export const netzwerkFields: Field[] = [
|
||||
{
|
||||
name: 'netzwerk',
|
||||
label: 'Network page content',
|
||||
type: 'group',
|
||||
admin: {
|
||||
description: 'Edit the Netzwerk page sections, partner records, modal labels, and sponsoring form copy.',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'hero',
|
||||
label: '01 · Hero',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Hero image, eyebrow, headline, highlight word, and intro copy.'),
|
||||
fields: [
|
||||
uploadField('image', 'Hero image', `Current frontend image: /images/${netzwerkContent.hero.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', netzwerkContent.hero.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.hero.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.hero.heading),
|
||||
text('highlight', 'Highlighted heading token', netzwerkContent.hero.highlight),
|
||||
textarea('description', 'Description', netzwerkContent.hero.description),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'patronage',
|
||||
label: '02 · Patronage',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Patron cards and greeting quote.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.patronage.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.patronage.heading),
|
||||
text('description', 'Description', netzwerkContent.patronage.description),
|
||||
{
|
||||
name: 'people',
|
||||
label: 'People',
|
||||
type: 'array',
|
||||
dbName: 'network_patrons',
|
||||
defaultValue: netzwerkContent.patronage.people,
|
||||
fields: personFields,
|
||||
},
|
||||
text('greetingEyebrow', 'Greeting eyebrow', netzwerkContent.patronage.greetingEyebrow),
|
||||
text('greetingRole', 'Greeting role', netzwerkContent.patronage.greetingRole),
|
||||
text('greetingName', 'Greeting name', netzwerkContent.patronage.greetingName),
|
||||
text('greetingTitleLine1', 'Greeting title line 1', netzwerkContent.patronage.greetingTitleLine1),
|
||||
text('greetingTitleLine2', 'Greeting title line 2', netzwerkContent.patronage.greetingTitleLine2),
|
||||
textarea('greetingQuote', 'Greeting quote', netzwerkContent.patronage.greetingQuote),
|
||||
text('greetingAttribution', 'Greeting attribution', netzwerkContent.patronage.greetingAttribution),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'juryIntro',
|
||||
label: '03 · Jury intro',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Editorial jury intro and stat strips.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.juryIntro.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.juryIntro.heading),
|
||||
textarea('description', 'Description', netzwerkContent.juryIntro.description),
|
||||
{
|
||||
name: 'stats',
|
||||
label: 'Mobile stats',
|
||||
type: 'array',
|
||||
dbName: 'network_jury_stats',
|
||||
defaultValue: netzwerkContent.juryIntro.stats,
|
||||
fields: statFields,
|
||||
},
|
||||
{
|
||||
name: 'desktopStats',
|
||||
label: 'Desktop stats',
|
||||
type: 'array',
|
||||
dbName: 'network_jury_d_stats',
|
||||
defaultValue: netzwerkContent.juryIntro.desktopStats,
|
||||
fields: statFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'jury',
|
||||
label: '04 · Jury members',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Jury section heading, chair badge, members, and note.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.jury.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.jury.heading),
|
||||
textarea('description', 'Description', netzwerkContent.jury.description),
|
||||
text('chairBadge', 'Chair badge', netzwerkContent.jury.chairBadge),
|
||||
textarea('note', 'Note', netzwerkContent.jury.note),
|
||||
{
|
||||
name: 'members',
|
||||
label: 'Members',
|
||||
type: 'array',
|
||||
dbName: 'network_jury',
|
||||
defaultValue: netzwerkContent.jury.members,
|
||||
fields: juryMemberFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'expertise',
|
||||
label: '05 · Expertise',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Evaluation process rows and quote.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.expertise.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.expertise.heading),
|
||||
textarea('quote', 'Quote', netzwerkContent.expertise.quote),
|
||||
text('quoteAttribution', 'Quote attribution', netzwerkContent.expertise.quoteAttribution),
|
||||
{
|
||||
name: 'rows',
|
||||
label: 'Process rows',
|
||||
type: 'array',
|
||||
dbName: 'network_eval',
|
||||
defaultValue: netzwerkContent.expertise.rows,
|
||||
fields: rowFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'partners',
|
||||
label: '06 · Partners',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Partner section, tier labels, partner records, and modal labels.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.partners.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.partners.heading),
|
||||
textarea('description', 'Description', netzwerkContent.partners.description),
|
||||
text('detailLabel', 'Detail label', netzwerkContent.partners.detailLabel),
|
||||
text('premiumLabel', 'Premium label', netzwerkContent.partners.premiumLabel),
|
||||
{
|
||||
name: 'tiers',
|
||||
label: 'Tiers',
|
||||
type: 'array',
|
||||
dbName: 'network_tiers',
|
||||
defaultValue: netzwerkContent.partners.tiers,
|
||||
fields: [numberField('tier', 'Tier'), text('label', 'Label'), text('note', 'Note')],
|
||||
},
|
||||
{
|
||||
name: 'modal',
|
||||
label: 'Modal labels',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('industryLabel', 'Industry label', netzwerkContent.partners.modal.industryLabel),
|
||||
text('locationLabel', 'Location label', netzwerkContent.partners.modal.locationLabel),
|
||||
text('webLabel', 'Web label', netzwerkContent.partners.modal.webLabel),
|
||||
text('aboutLabel', 'About label', netzwerkContent.partners.modal.aboutLabel),
|
||||
text('websiteLabel', 'Website CTA label', netzwerkContent.partners.modal.websiteLabel),
|
||||
text('closeLabel', 'Close label', netzwerkContent.partners.modal.closeLabel),
|
||||
text('footerTitle', 'Footer title', netzwerkContent.partners.modal.footerTitle),
|
||||
text('footerRolePrefix', 'Footer role prefix', netzwerkContent.partners.modal.footerRolePrefix),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Partners',
|
||||
type: 'array',
|
||||
dbName: 'network_partners',
|
||||
defaultValue: netzwerkContent.partners.items,
|
||||
fields: partnerFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'sponsoring',
|
||||
label: '07 · Sponsoring section',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Sponsoring pitch, image, benefits, form eyebrow, and membership footnote.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.sponsoring.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.sponsoring.heading),
|
||||
textarea('description', 'Description', netzwerkContent.sponsoring.description),
|
||||
uploadField('image', 'Form panel image', `Current frontend image: /images/${netzwerkContent.sponsoring.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', netzwerkContent.sponsoring.imageAlt),
|
||||
text('imageLabel', 'Image label', netzwerkContent.sponsoring.imageLabel),
|
||||
text('formEyebrow', 'Form eyebrow', netzwerkContent.sponsoring.formEyebrow),
|
||||
text('footnotePrefix', 'Footnote prefix', netzwerkContent.sponsoring.footnotePrefix),
|
||||
text('footnoteLabel', 'Footnote link label', netzwerkContent.sponsoring.footnoteLabel),
|
||||
text('footnoteUrl', 'Footnote link URL', netzwerkContent.sponsoring.footnoteUrl),
|
||||
{
|
||||
name: 'benefits',
|
||||
label: 'Benefits',
|
||||
type: 'array',
|
||||
dbName: 'network_sponsor_bens',
|
||||
defaultValue: netzwerkContent.sponsoring.benefits,
|
||||
fields: benefitFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'sponsoringForm',
|
||||
label: '08 · Sponsoring form',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Wizard labels, package options, validation messages, success copy, and footer note.'),
|
||||
fields: [
|
||||
{
|
||||
name: 'steps',
|
||||
label: 'Step labels',
|
||||
type: 'array',
|
||||
dbName: 'network_form_steps',
|
||||
defaultValue: netzwerkContent.sponsoringForm.steps,
|
||||
fields: formStepFields,
|
||||
},
|
||||
{
|
||||
name: 'packages',
|
||||
label: 'Package options',
|
||||
type: 'array',
|
||||
dbName: 'network_form_pkgs',
|
||||
defaultValue: netzwerkContent.sponsoringForm.packages,
|
||||
fields: packageFields,
|
||||
},
|
||||
text('step1Eyebrow', 'Step 1 eyebrow', netzwerkContent.sponsoringForm.step1Eyebrow),
|
||||
text('step1Heading', 'Step 1 heading', netzwerkContent.sponsoringForm.step1Heading),
|
||||
text('step2Eyebrow', 'Step 2 eyebrow', netzwerkContent.sponsoringForm.step2Eyebrow),
|
||||
text('step2Heading', 'Step 2 heading', netzwerkContent.sponsoringForm.step2Heading),
|
||||
text('companyLabel', 'Company label', netzwerkContent.sponsoringForm.companyLabel),
|
||||
text('companyPlaceholder', 'Company placeholder', netzwerkContent.sponsoringForm.companyPlaceholder),
|
||||
text('industryLabel', 'Industry label', netzwerkContent.sponsoringForm.industryLabel),
|
||||
text('industryPlaceholder', 'Industry placeholder', netzwerkContent.sponsoringForm.industryPlaceholder),
|
||||
text('step3Eyebrow', 'Step 3 eyebrow', netzwerkContent.sponsoringForm.step3Eyebrow),
|
||||
text('step3Heading', 'Step 3 heading', netzwerkContent.sponsoringForm.step3Heading),
|
||||
text('contactLabel', 'Contact label', netzwerkContent.sponsoringForm.contactLabel),
|
||||
text('contactPlaceholder', 'Contact placeholder', netzwerkContent.sponsoringForm.contactPlaceholder),
|
||||
text('emailLabel', 'Email label', netzwerkContent.sponsoringForm.emailLabel),
|
||||
text('emailPlaceholder', 'Email placeholder', netzwerkContent.sponsoringForm.emailPlaceholder),
|
||||
text('backLabel', 'Back label', netzwerkContent.sponsoringForm.backLabel),
|
||||
text('nextLabel', 'Next label', netzwerkContent.sponsoringForm.nextLabel),
|
||||
text('submitLabel', 'Submit label', netzwerkContent.sponsoringForm.submitLabel),
|
||||
text('requiredPackageError', 'Required package error', netzwerkContent.sponsoringForm.requiredPackageError),
|
||||
text('requiredFieldError', 'Required field error', netzwerkContent.sponsoringForm.requiredFieldError),
|
||||
text('invalidEmailError', 'Invalid email error', netzwerkContent.sponsoringForm.invalidEmailError),
|
||||
text('doneLabel', 'Done step label', netzwerkContent.sponsoringForm.doneLabel),
|
||||
text('successHeading', 'Success heading', netzwerkContent.sponsoringForm.successHeading),
|
||||
text('successMessagePrefix', 'Success message prefix', netzwerkContent.sponsoringForm.successMessagePrefix),
|
||||
text('successMessageSuffix', 'Success message suffix', netzwerkContent.sponsoringForm.successMessageSuffix),
|
||||
text('footerText', 'Footer text', netzwerkContent.sponsoringForm.footerText),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -1409,6 +1409,226 @@ export interface Page {
|
||||
buttonUrl?: string | null;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Edit the Netzwerk page sections, partner records, modal labels, and sponsoring form copy.
|
||||
*/
|
||||
netzwerk?: {
|
||||
/**
|
||||
* Hero image, eyebrow, headline, highlight word, and intro copy.
|
||||
*/
|
||||
hero?: {
|
||||
/**
|
||||
* Current frontend image: /images/netzwerk-hero.jpg
|
||||
*/
|
||||
image?: (number | null) | Media;
|
||||
imageAlt?: string | null;
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
highlight?: string | null;
|
||||
description?: string | null;
|
||||
};
|
||||
/**
|
||||
* Patron cards and greeting quote.
|
||||
*/
|
||||
patronage?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
description?: string | null;
|
||||
people?:
|
||||
| {
|
||||
image?: string | null;
|
||||
imageAlt?: string | null;
|
||||
name?: string | null;
|
||||
titleLine1?: string | null;
|
||||
titleLine2?: string | null;
|
||||
institution?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
greetingEyebrow?: string | null;
|
||||
greetingRole?: string | null;
|
||||
greetingName?: string | null;
|
||||
greetingTitleLine1?: string | null;
|
||||
greetingTitleLine2?: string | null;
|
||||
greetingQuote?: string | null;
|
||||
greetingAttribution?: string | null;
|
||||
};
|
||||
/**
|
||||
* Editorial jury intro and stat strips.
|
||||
*/
|
||||
juryIntro?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
description?: string | null;
|
||||
stats?:
|
||||
| {
|
||||
value?: string | null;
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
desktopStats?:
|
||||
| {
|
||||
value?: string | null;
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* Jury section heading, chair badge, members, and note.
|
||||
*/
|
||||
jury?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
description?: string | null;
|
||||
chairBadge?: string | null;
|
||||
note?: string | null;
|
||||
members?:
|
||||
| {
|
||||
name?: string | null;
|
||||
role?: string | null;
|
||||
bio?: string | null;
|
||||
image?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* Evaluation process rows and quote.
|
||||
*/
|
||||
expertise?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
quote?: string | null;
|
||||
quoteAttribution?: string | null;
|
||||
rows?:
|
||||
| {
|
||||
num?: string | null;
|
||||
label?: string | null;
|
||||
body?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* Partner section, tier labels, partner records, and modal labels.
|
||||
*/
|
||||
partners?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
description?: string | null;
|
||||
detailLabel?: string | null;
|
||||
premiumLabel?: string | null;
|
||||
tiers?:
|
||||
| {
|
||||
tier?: number | null;
|
||||
label?: string | null;
|
||||
note?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
modal?: {
|
||||
industryLabel?: string | null;
|
||||
locationLabel?: string | null;
|
||||
webLabel?: string | null;
|
||||
aboutLabel?: string | null;
|
||||
websiteLabel?: string | null;
|
||||
closeLabel?: string | null;
|
||||
footerTitle?: string | null;
|
||||
footerRolePrefix?: string | null;
|
||||
};
|
||||
items?:
|
||||
| {
|
||||
id?: string | null;
|
||||
name?: string | null;
|
||||
role?: string | null;
|
||||
tier?: number | null;
|
||||
desc?: string | null;
|
||||
fullDesc?: string | null;
|
||||
logoKind?: ('text' | 'serif' | 'badge' | 'monogram' | 'dot' | 'leaf' | 'rsm' | 'deutschebank') | null;
|
||||
logoText?: string | null;
|
||||
logoSubtext?: string | null;
|
||||
logoColor?: string | null;
|
||||
industry?: string | null;
|
||||
location?: string | null;
|
||||
website?: string | null;
|
||||
linkedin?: string | null;
|
||||
heroImg?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* Sponsoring pitch, image, benefits, form eyebrow, and membership footnote.
|
||||
*/
|
||||
sponsoring?: {
|
||||
eyebrow?: string | null;
|
||||
heading?: string | null;
|
||||
description?: string | null;
|
||||
/**
|
||||
* Current frontend image: /images/networking-innenhof.jpg
|
||||
*/
|
||||
image?: (number | null) | Media;
|
||||
imageAlt?: string | null;
|
||||
imageLabel?: string | null;
|
||||
formEyebrow?: string | null;
|
||||
footnotePrefix?: string | null;
|
||||
footnoteLabel?: string | null;
|
||||
footnoteUrl?: string | null;
|
||||
benefits?:
|
||||
| {
|
||||
num?: string | null;
|
||||
label?: string | null;
|
||||
sub?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
/**
|
||||
* Wizard labels, package options, validation messages, success copy, and footer note.
|
||||
*/
|
||||
sponsoringForm?: {
|
||||
steps?:
|
||||
| {
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
packages?:
|
||||
| {
|
||||
value?: string | null;
|
||||
title?: string | null;
|
||||
desc?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
step1Eyebrow?: string | null;
|
||||
step1Heading?: string | null;
|
||||
step2Eyebrow?: string | null;
|
||||
step2Heading?: string | null;
|
||||
companyLabel?: string | null;
|
||||
companyPlaceholder?: string | null;
|
||||
industryLabel?: string | null;
|
||||
industryPlaceholder?: string | null;
|
||||
step3Eyebrow?: string | null;
|
||||
step3Heading?: string | null;
|
||||
contactLabel?: string | null;
|
||||
contactPlaceholder?: string | null;
|
||||
emailLabel?: string | null;
|
||||
emailPlaceholder?: string | null;
|
||||
backLabel?: string | null;
|
||||
nextLabel?: string | null;
|
||||
submitLabel?: string | null;
|
||||
requiredPackageError?: string | null;
|
||||
requiredFieldError?: string | null;
|
||||
invalidEmailError?: string | null;
|
||||
doneLabel?: string | null;
|
||||
successHeading?: string | null;
|
||||
successMessagePrefix?: string | null;
|
||||
successMessageSuffix?: string | null;
|
||||
footerText?: string | null;
|
||||
};
|
||||
};
|
||||
meta?: {
|
||||
title?: string | null;
|
||||
/**
|
||||
@@ -3440,6 +3660,213 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
buttonUrl?: T;
|
||||
};
|
||||
};
|
||||
netzwerk?:
|
||||
| T
|
||||
| {
|
||||
hero?:
|
||||
| T
|
||||
| {
|
||||
image?: T;
|
||||
imageAlt?: T;
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
highlight?: T;
|
||||
description?: T;
|
||||
};
|
||||
patronage?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
description?: T;
|
||||
people?:
|
||||
| T
|
||||
| {
|
||||
image?: T;
|
||||
imageAlt?: T;
|
||||
name?: T;
|
||||
titleLine1?: T;
|
||||
titleLine2?: T;
|
||||
institution?: T;
|
||||
id?: T;
|
||||
};
|
||||
greetingEyebrow?: T;
|
||||
greetingRole?: T;
|
||||
greetingName?: T;
|
||||
greetingTitleLine1?: T;
|
||||
greetingTitleLine2?: T;
|
||||
greetingQuote?: T;
|
||||
greetingAttribution?: T;
|
||||
};
|
||||
juryIntro?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
description?: T;
|
||||
stats?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
label?: T;
|
||||
id?: T;
|
||||
};
|
||||
desktopStats?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
label?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
jury?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
description?: T;
|
||||
chairBadge?: T;
|
||||
note?: T;
|
||||
members?:
|
||||
| T
|
||||
| {
|
||||
name?: T;
|
||||
role?: T;
|
||||
bio?: T;
|
||||
image?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
expertise?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
quote?: T;
|
||||
quoteAttribution?: T;
|
||||
rows?:
|
||||
| T
|
||||
| {
|
||||
num?: T;
|
||||
label?: T;
|
||||
body?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
partners?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
description?: T;
|
||||
detailLabel?: T;
|
||||
premiumLabel?: T;
|
||||
tiers?:
|
||||
| T
|
||||
| {
|
||||
tier?: T;
|
||||
label?: T;
|
||||
note?: T;
|
||||
id?: T;
|
||||
};
|
||||
modal?:
|
||||
| T
|
||||
| {
|
||||
industryLabel?: T;
|
||||
locationLabel?: T;
|
||||
webLabel?: T;
|
||||
aboutLabel?: T;
|
||||
websiteLabel?: T;
|
||||
closeLabel?: T;
|
||||
footerTitle?: T;
|
||||
footerRolePrefix?: T;
|
||||
};
|
||||
items?:
|
||||
| T
|
||||
| {
|
||||
id?: T;
|
||||
name?: T;
|
||||
role?: T;
|
||||
tier?: T;
|
||||
desc?: T;
|
||||
fullDesc?: T;
|
||||
logoKind?: T;
|
||||
logoText?: T;
|
||||
logoSubtext?: T;
|
||||
logoColor?: T;
|
||||
industry?: T;
|
||||
location?: T;
|
||||
website?: T;
|
||||
linkedin?: T;
|
||||
heroImg?: T;
|
||||
};
|
||||
};
|
||||
sponsoring?:
|
||||
| T
|
||||
| {
|
||||
eyebrow?: T;
|
||||
heading?: T;
|
||||
description?: T;
|
||||
image?: T;
|
||||
imageAlt?: T;
|
||||
imageLabel?: T;
|
||||
formEyebrow?: T;
|
||||
footnotePrefix?: T;
|
||||
footnoteLabel?: T;
|
||||
footnoteUrl?: T;
|
||||
benefits?:
|
||||
| T
|
||||
| {
|
||||
num?: T;
|
||||
label?: T;
|
||||
sub?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
sponsoringForm?:
|
||||
| T
|
||||
| {
|
||||
steps?:
|
||||
| T
|
||||
| {
|
||||
label?: T;
|
||||
id?: T;
|
||||
};
|
||||
packages?:
|
||||
| T
|
||||
| {
|
||||
value?: T;
|
||||
title?: T;
|
||||
desc?: T;
|
||||
id?: T;
|
||||
};
|
||||
step1Eyebrow?: T;
|
||||
step1Heading?: T;
|
||||
step2Eyebrow?: T;
|
||||
step2Heading?: T;
|
||||
companyLabel?: T;
|
||||
companyPlaceholder?: T;
|
||||
industryLabel?: T;
|
||||
industryPlaceholder?: T;
|
||||
step3Eyebrow?: T;
|
||||
step3Heading?: T;
|
||||
contactLabel?: T;
|
||||
contactPlaceholder?: T;
|
||||
emailLabel?: T;
|
||||
emailPlaceholder?: T;
|
||||
backLabel?: T;
|
||||
nextLabel?: T;
|
||||
submitLabel?: T;
|
||||
requiredPackageError?: T;
|
||||
requiredFieldError?: T;
|
||||
invalidEmailError?: T;
|
||||
doneLabel?: T;
|
||||
successHeading?: T;
|
||||
successMessagePrefix?: T;
|
||||
successMessageSuffix?: T;
|
||||
footerText?: T;
|
||||
};
|
||||
};
|
||||
meta?:
|
||||
| T
|
||||
| {
|
||||
|
||||
66
src/scripts/preload-netzwerk-page-cms.ts
Normal file
66
src/scripts/preload-netzwerk-page-cms.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'dotenv/config'
|
||||
|
||||
import config from '@payload-config'
|
||||
import { getPayload, type Payload } from 'payload'
|
||||
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent'
|
||||
|
||||
const mediaByFilename = async (payload: Payload, filename: string) => {
|
||||
const result = await payload.find({
|
||||
collection: 'media',
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
where: { filename: { equals: filename } },
|
||||
})
|
||||
return result.docs[0]?.id
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
const pageResult = await payload.find({
|
||||
collection: 'pages',
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
draft: true,
|
||||
overrideAccess: true,
|
||||
where: {
|
||||
or: [{ spaPath: { equals: '/netzwerk' } }, { slug: { equals: 'netzwerk' } }, { slug: { equals: 'network' } }],
|
||||
},
|
||||
})
|
||||
|
||||
const page = pageResult.docs[0]
|
||||
if (!page) throw new Error('Netzwerk page not found. Expected spaPath=/netzwerk or slug=netzwerk/network.')
|
||||
|
||||
const heroImage = await mediaByFilename(payload, netzwerkContent.hero.imageFilename)
|
||||
const sponsoringImage = await mediaByFilename(payload, netzwerkContent.sponsoring.imageFilename)
|
||||
const { imageFilename: _heroFilename, ...heroContent } = netzwerkContent.hero
|
||||
const { imageFilename: _sponsoringFilename, ...sponsoringContent } = netzwerkContent.sponsoring
|
||||
|
||||
await payload.update({
|
||||
collection: 'pages',
|
||||
id: page.id,
|
||||
overrideAccess: true,
|
||||
context: { disableRevalidate: true },
|
||||
data: {
|
||||
netzwerk: {
|
||||
...netzwerkContent,
|
||||
hero: {
|
||||
...heroContent,
|
||||
image: heroImage,
|
||||
},
|
||||
sponsoring: {
|
||||
...sponsoringContent,
|
||||
image: sponsoringImage,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
})
|
||||
|
||||
payload.logger.info(`Preloaded Netzwerk CMS fields for page ${page.id}`)
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { ArrowRight, ArrowLeft, Check, Layers, Building2, Mail } from 'lucide-react';
|
||||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -93,17 +94,14 @@ type FormData = {
|
||||
email: string;
|
||||
};
|
||||
|
||||
const STEPS = [
|
||||
{ label: 'Paket', icon: Layers },
|
||||
{ label: 'Unternehmen', icon: Building2 },
|
||||
{ label: 'Kontakt', icon: Mail },
|
||||
];
|
||||
const STEP_ICONS = [Layers, Building2, Mail];
|
||||
|
||||
const PAKETE = [
|
||||
{ value: 'main', title: 'Haupt-Sponsoring', desc: 'Maximale Sichtbarkeit auf allen Kanälen – Bühne, Digital, Print.' },
|
||||
{ value: 'category', title: 'Kategorie-Partner', desc: 'Namensgebung einer Auszeichnungskategorie – fokussiertes Branding.' },
|
||||
{ value: 'event', title: 'Event-Partner', desc: 'Präsenz beim exklusiven Gala-Abend in München.' },
|
||||
];
|
||||
type SponsoringFormContent = Partial<typeof netzwerkContent.sponsoringForm>;
|
||||
type PackageOption = (typeof netzwerkContent.sponsoringForm.packages)[number];
|
||||
type StepOption = (typeof netzwerkContent.sponsoringForm.steps)[number];
|
||||
|
||||
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;
|
||||
|
||||
const variants = {
|
||||
enter: (dir: number) => ({ x: dir > 0 ? 40 : -40, opacity: 0 }),
|
||||
@@ -142,7 +140,7 @@ function StyledInput({ c, ...props }: React.InputHTMLAttributes<HTMLInputElement
|
||||
);
|
||||
}
|
||||
|
||||
function PaketCard({ c, pkg, selected, onClick }: { c: C; pkg: typeof PAKETE[0]; selected: boolean; onClick: () => void }) {
|
||||
function PaketCard({ c, pkg, selected, onClick }: { c: C; pkg: PackageOption; selected: boolean; onClick: () => void }) {
|
||||
return (
|
||||
<button type="button" onClick={onClick} style={{
|
||||
width: '100%', padding: '13px 18px', textAlign: 'left', cursor: 'pointer',
|
||||
@@ -165,9 +163,12 @@ function PaketCard({ c, pkg, selected, onClick }: { c: C; pkg: typeof PAKETE[0];
|
||||
);
|
||||
}
|
||||
|
||||
export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'gold' }) {
|
||||
export default function SponsoringForm({ theme = 'dark', content }: { theme?: 'dark' | 'gold'; content?: SponsoringFormContent }) {
|
||||
const c = theme === 'gold' ? GOLD : DARK;
|
||||
const isMobile = useIsMobile();
|
||||
const copy = { ...netzwerkContent.sponsoringForm, ...(content || {}) };
|
||||
const steps = fallbackArray<StepOption>(copy.steps, netzwerkContent.sponsoringForm.steps);
|
||||
const packages = fallbackArray<PackageOption>(copy.packages, netzwerkContent.sponsoringForm.packages);
|
||||
const [step, setStep] = useState(0);
|
||||
const [dir, setDir] = useState(1);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
@@ -181,12 +182,12 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
|
||||
const validate = () => {
|
||||
const e: typeof errors = {};
|
||||
if (step === 0 && !data.paket) e.paket = 'Bitte wählen Sie ein Paket.';
|
||||
if (step === 1 && !data.unternehmen) e.unternehmen = 'Pflichtfeld';
|
||||
if (step === 0 && !data.paket) e.paket = fallbackText(copy.requiredPackageError, netzwerkContent.sponsoringForm.requiredPackageError);
|
||||
if (step === 1 && !data.unternehmen) e.unternehmen = fallbackText(copy.requiredFieldError, netzwerkContent.sponsoringForm.requiredFieldError);
|
||||
if (step === 2) {
|
||||
if (!data.kontakt) e.kontakt = 'Pflichtfeld';
|
||||
if (!data.email) e.email = 'Pflichtfeld';
|
||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) e.email = 'Ungültige E-Mail';
|
||||
if (!data.kontakt) e.kontakt = fallbackText(copy.requiredFieldError, netzwerkContent.sponsoringForm.requiredFieldError);
|
||||
if (!data.email) e.email = fallbackText(copy.requiredFieldError, netzwerkContent.sponsoringForm.requiredFieldError);
|
||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) e.email = fallbackText(copy.invalidEmailError, netzwerkContent.sponsoringForm.invalidEmailError);
|
||||
}
|
||||
setErrors(e);
|
||||
return Object.keys(e).length === 0;
|
||||
@@ -196,7 +197,7 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
const prev = () => { setDir(-1); setStep(s => s - 1); };
|
||||
const submit = () => { if (validate()) setSubmitted(true); };
|
||||
|
||||
const progress = (step / (STEPS.length - 1)) * 100;
|
||||
const progress = (step / (steps.length - 1)) * 100;
|
||||
|
||||
if (submitted) {
|
||||
return (
|
||||
@@ -205,10 +206,10 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<Check size={22} color={c.successIconIn} strokeWidth={3} />
|
||||
</div>
|
||||
<h3 style={{ fontSize: 18, fontWeight: 900, color: c.successHeading, textTransform: 'uppercase', letterSpacing: '-0.01em', marginBottom: 10 }}>
|
||||
Anfrage eingegangen
|
||||
{fallbackText(copy.successHeading, netzwerkContent.sponsoringForm.successHeading)}
|
||||
</h3>
|
||||
<p style={{ fontSize: 12, color: c.successBody, maxWidth: 320, margin: '0 auto', lineHeight: 1.6 }}>
|
||||
Vielen Dank, <strong style={{ color: c.successHeading }}>{data.kontakt}</strong>. Wir senden Ihnen unser Sponsoring-Exposé innerhalb von 48 Stunden zu.
|
||||
{fallbackText(copy.successMessagePrefix, netzwerkContent.sponsoringForm.successMessagePrefix)} <strong style={{ color: c.successHeading }}>{data.kontakt}</strong>. {fallbackText(copy.successMessageSuffix, netzwerkContent.sponsoringForm.successMessageSuffix)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -223,8 +224,8 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
|
||||
{/* Step tabs */}
|
||||
<div style={{ display: 'flex', borderBottom: `1px solid ${c.border}`, flexShrink: 0 }}>
|
||||
{STEPS.map((s, i) => {
|
||||
const Icon = s.icon;
|
||||
{steps.map((s, i) => {
|
||||
const Icon = STEP_ICONS[i] || Layers;
|
||||
const done = i < step, active = i === step;
|
||||
return (
|
||||
<div key={i} style={{
|
||||
@@ -237,7 +238,7 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
marginBottom: -1, transition: 'color 0.2s',
|
||||
}}>
|
||||
<Icon size={11} strokeWidth={active ? 2 : 1.5} />
|
||||
<span>{done ? '✓' : s.label}</span>
|
||||
<span>{done ? fallbackText(copy.doneLabel, netzwerkContent.sponsoringForm.doneLabel) : fallbackText(s.label, netzwerkContent.sponsoringForm.steps[i]?.label || '')}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -253,11 +254,11 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
{step === 0 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||||
<div>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 6 }}>Schritt 1 – Paket wählen</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em', marginBottom: 12 }}>Interesse an</h3>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 6 }}>{fallbackText(copy.step1Eyebrow, netzwerkContent.sponsoringForm.step1Eyebrow)}</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em', marginBottom: 12 }}>{fallbackText(copy.step1Heading, netzwerkContent.sponsoringForm.step1Heading)}</h3>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
{PAKETE.map(pkg => (
|
||||
{packages.map(pkg => (
|
||||
<PaketCard key={pkg.value} c={c} pkg={pkg} selected={data.paket === pkg.value} onClick={() => set('paket', pkg.value)} />
|
||||
))}
|
||||
</div>
|
||||
@@ -268,14 +269,14 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
{step === 1 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 8 }}>Schritt 2 – Unternehmen</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>Ihr Unternehmen</h3>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 8 }}>{fallbackText(copy.step2Eyebrow, netzwerkContent.sponsoringForm.step2Eyebrow)}</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>{fallbackText(copy.step2Heading, netzwerkContent.sponsoringForm.step2Heading)}</h3>
|
||||
</div>
|
||||
<Field c={c} label="Unternehmen *" error={errors.unternehmen}>
|
||||
<StyledInput c={c} value={data.unternehmen} onChange={e => set('unternehmen', e.target.value)} placeholder="Firmenname" />
|
||||
<Field c={c} label={fallbackText(copy.companyLabel, netzwerkContent.sponsoringForm.companyLabel)} error={errors.unternehmen}>
|
||||
<StyledInput c={c} value={data.unternehmen} onChange={e => set('unternehmen', e.target.value)} placeholder={fallbackText(copy.companyPlaceholder, netzwerkContent.sponsoringForm.companyPlaceholder)} />
|
||||
</Field>
|
||||
<Field c={c} label="Branche">
|
||||
<StyledInput c={c} value={data.branche} onChange={e => set('branche', e.target.value)} placeholder="z. B. Finanzdienstleistungen" />
|
||||
<Field c={c} label={fallbackText(copy.industryLabel, netzwerkContent.sponsoringForm.industryLabel)}>
|
||||
<StyledInput c={c} value={data.branche} onChange={e => set('branche', e.target.value)} placeholder={fallbackText(copy.industryPlaceholder, netzwerkContent.sponsoringForm.industryPlaceholder)} />
|
||||
</Field>
|
||||
</div>
|
||||
)}
|
||||
@@ -283,14 +284,14 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
{step === 2 && (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
<div>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 8 }}>Schritt 3 – Kontakt</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>Ansprechpartner</h3>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 8 }}>{fallbackText(copy.step3Eyebrow, netzwerkContent.sponsoringForm.step3Eyebrow)}</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>{fallbackText(copy.step3Heading, netzwerkContent.sponsoringForm.step3Heading)}</h3>
|
||||
</div>
|
||||
<Field c={c} label="Ansprechpartner *" error={errors.kontakt}>
|
||||
<StyledInput c={c} value={data.kontakt} onChange={e => set('kontakt', e.target.value)} placeholder="Vor- und Nachname" />
|
||||
<Field c={c} label={fallbackText(copy.contactLabel, netzwerkContent.sponsoringForm.contactLabel)} error={errors.kontakt}>
|
||||
<StyledInput c={c} value={data.kontakt} onChange={e => set('kontakt', e.target.value)} placeholder={fallbackText(copy.contactPlaceholder, netzwerkContent.sponsoringForm.contactPlaceholder)} />
|
||||
</Field>
|
||||
<Field c={c} label="E-Mail *" error={errors.email}>
|
||||
<StyledInput c={c} type="email" value={data.email} onChange={e => set('email', e.target.value)} placeholder="name@unternehmen.de" />
|
||||
<Field c={c} label={fallbackText(copy.emailLabel, netzwerkContent.sponsoringForm.emailLabel)} error={errors.email}>
|
||||
<StyledInput c={c} type="email" value={data.email} onChange={e => set('email', e.target.value)} placeholder={fallbackText(copy.emailPlaceholder, netzwerkContent.sponsoringForm.emailPlaceholder)} />
|
||||
</Field>
|
||||
</div>
|
||||
)}
|
||||
@@ -311,11 +312,11 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
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.backLabel, netzwerkContent.sponsoringForm.backLabel)}
|
||||
</button>
|
||||
) : <div />}
|
||||
|
||||
{step < STEPS.length - 1 ? (
|
||||
{step < steps.length - 1 ? (
|
||||
<button type="button" onClick={next} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em',
|
||||
color: c.btnText, background: c.btnBg, border: 'none', cursor: 'pointer',
|
||||
@@ -325,7 +326,7 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = c.btnBg; }}
|
||||
>
|
||||
Weiter <ArrowRight size={13} />
|
||||
{fallbackText(copy.nextLabel, netzwerkContent.sponsoringForm.nextLabel)} <ArrowRight size={13} />
|
||||
</button>
|
||||
) : (
|
||||
<button type="button" onClick={submit} style={{
|
||||
@@ -337,13 +338,13 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = c.btnBg; }}
|
||||
>
|
||||
Exposé anfordern <ArrowRight size={13} />
|
||||
{fallbackText(copy.submitLabel, netzwerkContent.sponsoringForm.submitLabel)} <ArrowRight size={13} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p style={{ fontFamily: FF, textAlign: 'center', fontSize: 12, color: c.footerText, paddingTop: 12 }}>
|
||||
Wir melden uns innerhalb von 48 Stunden.
|
||||
{fallbackText(copy.footerText, netzwerkContent.sponsoringForm.footerText)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
386
src/spa/netzwerkContent.ts
Normal file
386
src/spa/netzwerkContent.ts
Normal file
@@ -0,0 +1,386 @@
|
||||
export const netzwerkContent = {
|
||||
hero: {
|
||||
imageFilename: 'netzwerk-hero.jpg',
|
||||
imageAlt: 'BMP Netzwerk Preisverleihung',
|
||||
eyebrow: 'Jury & Partner',
|
||||
heading: 'DAS NETZWERK\nHINTER DEM AWARD.',
|
||||
highlight: 'AWARD.',
|
||||
description:
|
||||
'Der Bayerische Mittelstandspreis wird getragen von einem starken Netzwerk aus Schirmherrschaft, unabhängiger Fach-Jury und langjährigen Partnern aus Wirtschaft und Gesellschaft.',
|
||||
},
|
||||
patronage: {
|
||||
eyebrow: 'Die Schirmherrschaft',
|
||||
heading: 'Schirmherrin und Schirmherr',
|
||||
description: 'des Bayerischen Mittelstandspreises',
|
||||
people: [
|
||||
{
|
||||
image: 'https://images.unsplash.com/photo-1551836022-d5d88e9218df?auto=format&fit=crop&q=80&w=800',
|
||||
imageAlt: 'Ilse Aigner',
|
||||
name: 'Ilse Aigner MdL',
|
||||
titleLine1: 'Präsidentin des Bayerischen Landtags',
|
||||
titleLine2: 'Bayerische Staatsministerin für Wirtschaft a.D.',
|
||||
institution: 'Bayerischer Landtag',
|
||||
},
|
||||
{
|
||||
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&q=80&w=800',
|
||||
imageAlt: 'Hubert Aiwanger',
|
||||
name: 'Hubert Aiwanger MdL',
|
||||
titleLine1: 'Bayerischer Staatsminister für Wirtschaft,',
|
||||
titleLine2: 'Landesentwicklung und Energie · Stv. Ministerpräsident',
|
||||
institution: 'Bayerische Staatsregierung',
|
||||
},
|
||||
],
|
||||
greetingEyebrow: 'Grußwort',
|
||||
greetingRole: 'Schirmherrin',
|
||||
greetingName: 'Ilse Aigner MdL',
|
||||
greetingTitleLine1: 'Präsidentin des Bayerischen Landtags',
|
||||
greetingTitleLine2: 'Bayerische Staatsministerin für Wirtschaft a.D.',
|
||||
greetingQuote:
|
||||
'„Der Bayerische Mittelstandspreis steht für das, was Bayern stark macht: Unternehmergeist, Verantwortung und Qualität. Mit großer Freude übernehme ich erneut die Schirmherrschaft für diesen bedeutenden Preis.“',
|
||||
greetingAttribution: '– Ilse Aigner MdL, Präsidentin des Bayerischen Landtags',
|
||||
},
|
||||
juryIntro: {
|
||||
eyebrow: 'Wer entscheidet?',
|
||||
heading: 'UNABHÄNGIGE EXPERTISE FÜR DEN MITTELSTAND.',
|
||||
description:
|
||||
'Die Jury des Bayerischen Mittelstandspreises besteht ausschließlich aus ehrenamtlich tätigen Expertinnen und Experten. Kein Mitglied steht in wirtschaftlicher Verbindung zu einem Bewerber – Transparenz und Unparteilichkeit sind die Grundpfeiler unseres Verfahrens.',
|
||||
stats: [
|
||||
{ value: '11', label: 'Jurymitglieder' },
|
||||
{ value: 'Mehrstufig', label: 'Bewertungsverfahren' },
|
||||
{ value: '100%', label: 'Unabhängig' },
|
||||
],
|
||||
desktopStats: [
|
||||
{ value: '11', label: 'Unabhängige Jurymitglieder' },
|
||||
{ value: 'Mehrstufig', label: 'Bewertungsverfahren' },
|
||||
{ value: '100%', label: 'Unabhängig & ehrenamtlich' },
|
||||
],
|
||||
},
|
||||
jury: {
|
||||
eyebrow: 'Das Gremium',
|
||||
heading: 'UNSERE JURY 2026',
|
||||
description:
|
||||
'Unabhängige Expertinnen und Experten aus Wirtschaft, Wissenschaft und Verbänden, für einen vollständig unabhängigen Bewertungsprozess.',
|
||||
chairBadge: 'Jury-Vorsitz',
|
||||
note: 'Hinweis: Einzelne Persönlichkeiten engagieren sich sowohl in der Jury als auch als Partner des BMP – beide Rollen werden auf dieser Seite getrennt ausgewiesen.',
|
||||
members: [
|
||||
{
|
||||
name: 'Prof. Dr. Klaus Bergmann',
|
||||
role: 'Vorsitzender / LMU München',
|
||||
bio: 'Spezialist für KMU-Strategien und Innovations-Ökosysteme.',
|
||||
image: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&q=80&w=400',
|
||||
},
|
||||
{
|
||||
name: 'Dr. Sabine Hofmann',
|
||||
role: 'IHK Bayern',
|
||||
bio: 'Expertin für digitale Transformation und regionale Wertschöpfung.',
|
||||
image: 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&q=80&w=400',
|
||||
},
|
||||
{
|
||||
name: 'Maximilian Reiter',
|
||||
role: 'Unternehmer',
|
||||
bio: 'CEO der Reiter Group, bringt die wertvolle Unternehmer-Perspektive ein.',
|
||||
image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&q=80&w=400',
|
||||
},
|
||||
{
|
||||
name: 'Dr. Elena Fischer',
|
||||
role: 'TU München',
|
||||
bio: 'Lehrstuhl für nachhaltige Unternehmensführung.',
|
||||
image: 'https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&q=80&w=400',
|
||||
},
|
||||
],
|
||||
},
|
||||
expertise: {
|
||||
eyebrow: 'Hintergrund & Expertise',
|
||||
heading: 'WIE BEWERTET DIE JURY?',
|
||||
quote:
|
||||
'Die Jury des BMP ist vollständig von wirtschaftlichen Interessen unabhängig. Jede Entscheidung wird transparent nachvollzogen – das ist unser Versprechen an die Unternehmen Bayerns.',
|
||||
quoteAttribution: 'Prof. Dr. Klaus Bergmann, Juryvorsitzender',
|
||||
rows: [
|
||||
{
|
||||
num: '01',
|
||||
label: 'Aktenstudium',
|
||||
body: 'Alle Einreichungen werden zunächst vollständig gesichtet und nach den festgelegten Kriterien geprüft.',
|
||||
},
|
||||
{
|
||||
num: '02',
|
||||
label: 'Scoring-Matrix',
|
||||
body: 'Jedes Jurymitglied bewertet die Einreichungen unabhängig nach den festgelegten Kriterien.',
|
||||
},
|
||||
{
|
||||
num: '03',
|
||||
label: 'Jury-Plenum',
|
||||
body: 'In der gemeinsamen Sitzung werden Argumente und Ansichten ausgetauscht, Eigenschaften verglichen und gemeinsam bewertet. Daraus entsteht die Liste der Finalisten.',
|
||||
},
|
||||
{
|
||||
num: '04',
|
||||
label: 'Ergebnis',
|
||||
body: 'Die Gewinner des Bayerischen Mittelstandspreises werden nach vorgegebenem Punktesystem bestimmt, erweitert um Jury-Mitglieder aus der Praxis.',
|
||||
},
|
||||
],
|
||||
},
|
||||
partners: {
|
||||
eyebrow: 'Netzwerkqualität',
|
||||
heading: 'PARTNER & SPONSOREN',
|
||||
description: 'Partner in drei Kategorien: Hauptsponsoren, Medienpartner und weitere Sponsoren. Klicken für Details.',
|
||||
detailLabel: 'Details',
|
||||
premiumLabel: 'Premium',
|
||||
tiers: [
|
||||
{ tier: 1, label: 'Hauptsponsoren', note: 'Premium' },
|
||||
{ tier: 2, label: 'Medienpartner', note: '' },
|
||||
{ tier: 3, label: 'Weitere Sponsoren', note: '' },
|
||||
],
|
||||
modal: {
|
||||
industryLabel: 'Branche',
|
||||
locationLabel: 'Standort',
|
||||
webLabel: 'Web',
|
||||
aboutLabel: 'Über das Unternehmen',
|
||||
websiteLabel: 'Website besuchen',
|
||||
closeLabel: 'Schließen',
|
||||
footerTitle: 'Bayerischer Mittelstandspreis 2026',
|
||||
footerRolePrefix: 'Offizieller',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
id: 'rsm',
|
||||
name: 'RSM Ebner Stolz',
|
||||
role: 'Hauptsponsor',
|
||||
tier: 1,
|
||||
desc: 'Führende mittelständische Wirtschaftsprüfungs- und Steuerberatungsgesellschaft.',
|
||||
fullDesc:
|
||||
'RSM Ebner Stolz ist eine der größten unabhängigen Wirtschaftsprüfungs- und Steuerberatungsgesellschaften Deutschlands mit besonderer Expertise im Mittelstand. Als Hauptsponsor des BMP unterstützen sie die Identifikation herausragender Unternehmen und bringen ihre Netzwerke aktiv in die Nominierungsphase ein.',
|
||||
logoKind: 'rsm',
|
||||
logoText: 'RSM',
|
||||
logoSubtext: 'EBNER STOLZ',
|
||||
logoColor: '#374151',
|
||||
industry: 'Wirtschaftsprüfung & Beratung',
|
||||
location: 'München, Bayern',
|
||||
website: 'rsm-ebner-stolz.de',
|
||||
linkedin: 'https://linkedin.com/company/rsm-ebner-stolz',
|
||||
},
|
||||
{
|
||||
id: 'wwk',
|
||||
name: 'WWK',
|
||||
role: 'Hauptsponsor',
|
||||
tier: 1,
|
||||
desc: 'Eine starke Gemeinschaft – Lebensversicherungsgruppe mit bayerischen Wurzeln.',
|
||||
fullDesc:
|
||||
'Die WWK Lebensversicherung a. G. ist eine der leistungsstärksten deutschen Lebensversicherungsgruppen. Als Münchner Traditionsunternehmen verbindet die WWK tiefe bayerische Verwurzelung mit finanzieller Stärke – Werte, die sie mit dem Bayerischen Mittelstandspreis teilt.',
|
||||
logoKind: 'text',
|
||||
logoText: 'WWK',
|
||||
logoColor: '#16a34a',
|
||||
industry: 'Lebensversicherung',
|
||||
location: 'München, Bayern',
|
||||
website: 'wwk.de',
|
||||
linkedin: 'https://linkedin.com/company/wwk-versicherung',
|
||||
},
|
||||
{
|
||||
id: 'radiogong',
|
||||
name: 'Radio Gong 96.3',
|
||||
role: 'Medienpartner',
|
||||
tier: 2,
|
||||
desc: 'Der reichweitenstärkste Radiosender Münchens – Stimme des Mittelstands.',
|
||||
fullDesc:
|
||||
'Radio Gong 96.3 ist der reichweitenstärkste Radiosender Münchens. Als Medienpartner des BMP sorgt er für Aufmerksamkeit für die Nominierten in Sendemitschnitten und redaktionellen Beiträgen.',
|
||||
logoKind: 'badge',
|
||||
logoText: 'Radio\nGong 96.3',
|
||||
logoColor: '#e11d48',
|
||||
industry: 'Medien',
|
||||
location: 'München',
|
||||
website: 'radiogong.com',
|
||||
},
|
||||
{
|
||||
id: 'muenchentv',
|
||||
name: 'münchen.tv',
|
||||
role: 'Medienpartner',
|
||||
tier: 2,
|
||||
desc: 'Der lokale Fernsehsender der Landeshauptstadt München.',
|
||||
fullDesc:
|
||||
'münchen.tv ist der lokale Fernsehsender der Landeshauptstadt München. Als Medienpartner überträgt münchen.tv Highlights der BMP-Gala und produziert Porträts der Nominierten.',
|
||||
logoKind: 'text',
|
||||
logoText: 'münchen.tv',
|
||||
logoColor: '#0ea5e9',
|
||||
industry: 'Medien',
|
||||
location: 'München',
|
||||
website: 'muenchen.tv',
|
||||
},
|
||||
{
|
||||
id: 'metzler',
|
||||
name: 'METZLER',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Älteste Privatbank Deutschlands – Unabhängigkeit seit 1674.',
|
||||
fullDesc:
|
||||
'B. Metzler seel. Sohn & Co. KGaA ist die älteste deutsche Privatbank in Familienbesitz – seit über 350 Jahren unabhängig. Ihr Engagement für den BMP unterstreicht die tiefe Verbundenheit mit dem Mittelstand, dessen Werte wie Verlässlichkeit, Substanz und Langfristigkeit Metzler selbst verkörpert.',
|
||||
logoKind: 'serif',
|
||||
logoText: 'METZLER',
|
||||
logoColor: '#1a1a1a',
|
||||
industry: 'Privatbankwesen',
|
||||
location: 'Frankfurt a. M.',
|
||||
website: 'metzler.com',
|
||||
linkedin: 'https://linkedin.com/company/metzler',
|
||||
},
|
||||
{
|
||||
id: 'wieselhuber',
|
||||
name: 'Dr. Wieselhuber & Partner',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Unabhängige Top-Management-Beratung für Familienunternehmen und Mittelstand.',
|
||||
fullDesc:
|
||||
'Dr. Wieselhuber & Partner ist eine unabhängige, branchenübergreifende Top-Management-Beratung mit besonderem Fokus auf Familienunternehmen und Mittelstand. Als Sponsor bringt das Haus seine Strategie- und Transformationsexpertise in das Netzwerk des BMP ein.',
|
||||
logoKind: 'text',
|
||||
logoText: 'W&P WIESELHUBER',
|
||||
logoColor: '#1a2b4a',
|
||||
industry: 'Unternehmensberatung',
|
||||
location: 'München, Bayern',
|
||||
website: 'wieselhuber.de',
|
||||
},
|
||||
{
|
||||
id: 'fristads',
|
||||
name: 'Fristads',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Premium-Arbeitsbekleidung – Funktion, Qualität und Design.',
|
||||
fullDesc:
|
||||
'Fristads steht für hochwertige, funktionale Arbeitsbekleidung, die Schutz, Komfort und Design vereint. Als Sponsor des Bayerischen Mittelstandspreises unterstützt das Unternehmen die Auszeichnung herausragender mittelständischer Betriebe.',
|
||||
logoKind: 'text',
|
||||
logoText: 'FRISTADS',
|
||||
logoColor: '#1a1a1a',
|
||||
industry: 'Workwear & Textil',
|
||||
location: 'Deutschland',
|
||||
website: 'fristads.com',
|
||||
},
|
||||
{
|
||||
id: 'newedge',
|
||||
name: 'New Edge',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Digitale Markenführung, Web und Design für den Mittelstand.',
|
||||
fullDesc:
|
||||
'New Edge gestaltet Marken, Web-Erlebnisse und digitale Auftritte für mittelständische Unternehmen. Als Sponsor des BMP unterstützt die Agentur die Sichtbarkeit und das digitale Profil ausgezeichneter Unternehmen.',
|
||||
logoKind: 'monogram',
|
||||
logoText: 'New Edge',
|
||||
logoSubtext: 'NE',
|
||||
logoColor: '#005E67',
|
||||
industry: 'Branding & Digital',
|
||||
location: 'Bayern',
|
||||
website: 'newedgebrand.com',
|
||||
},
|
||||
{
|
||||
id: 'moodtalk',
|
||||
name: 'Moodtalk',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Plattform für Teamkultur und Mitarbeiter-Feedback.',
|
||||
fullDesc:
|
||||
'Moodtalk ist eine Plattform für Teamkultur, Stimmung und kontinuierliches Mitarbeiter-Feedback. Als Sponsor des BMP steht das Unternehmen für moderne, wertebasierte Unternehmensführung.',
|
||||
logoKind: 'dot',
|
||||
logoText: 'moodtalk',
|
||||
logoColor: '#7c3aed',
|
||||
industry: 'HR & Software',
|
||||
location: 'Bayern',
|
||||
website: 'moodtalk.io',
|
||||
},
|
||||
{
|
||||
id: 'deutschebank',
|
||||
name: 'Deutsche Bank',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Partnerbank für die Finanzierung und Skalierung von KMU-Wachstum.',
|
||||
fullDesc:
|
||||
'Die Deutsche Bank begleitet mittelständische Unternehmen als verlässlicher Finanzpartner durch alle Wachstumsphasen. Im Rahmen des BMP stellt sie ihr deutschlandweites Netzwerk, spezifische Mittelstandsprodukte und direkte Ansprechpartner für die Nominierten bereit.',
|
||||
logoKind: 'deutschebank',
|
||||
logoText: 'Deutsche Bank',
|
||||
logoColor: '#1d1d1b',
|
||||
industry: 'Bankwesen & Finanzen',
|
||||
location: 'Frankfurt a. M.',
|
||||
website: 'db.com',
|
||||
linkedin: 'https://linkedin.com/company/deutsche-bank',
|
||||
},
|
||||
{
|
||||
id: 'bionorica',
|
||||
name: 'Bionorica',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Weltmarktführer für pflanzliche Arzneimittel aus dem bayerischen Neumarkt.',
|
||||
fullDesc:
|
||||
'Bionorica SE ist ein international agierendes Pharmaunternehmen mit Sitz in Neumarkt i. d. OPf. und Weltmarktführer bei pflanzlichen Arzneimitteln. Das Unternehmen selbst ist ein Paradebeispiel eines bayerischen Mittelständlers mit globalem Anspruch und verkörpert die Innovationskraft, die der BMP würdigt.',
|
||||
logoKind: 'leaf',
|
||||
logoText: 'Bionorica®',
|
||||
logoColor: '#16a34a',
|
||||
industry: 'Pharmaindustrie',
|
||||
location: 'Neumarkt i.d.OPf., Bayern',
|
||||
website: 'bionorica.de',
|
||||
linkedin: 'https://linkedin.com/company/bionorica',
|
||||
},
|
||||
{
|
||||
id: 'primus',
|
||||
name: 'Primus',
|
||||
role: 'Sponsor',
|
||||
tier: 3,
|
||||
desc: 'Partner des Bayerischen Mittelstandspreises.',
|
||||
fullDesc: 'Primus unterstützt als Sponsor den Bayerischen Mittelstandspreis und sein Engagement für herausragende Unternehmen des bayerischen Mittelstands.',
|
||||
logoKind: 'serif',
|
||||
logoText: 'PRIMUS',
|
||||
logoColor: '#b8860b',
|
||||
industry: 'Partner',
|
||||
location: 'Bayern',
|
||||
website: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
sponsoring: {
|
||||
eyebrow: 'Wachstum durch Partnerschaft',
|
||||
heading: 'WIR FREUEN UNS ÜBER NEUE SPONSOREN.',
|
||||
description:
|
||||
'Positionieren Sie Ihre Marke im exklusivsten Netzwerk des bayerischen Mittelstands – mit maßgeschneiderten Sponsoring-Paketen.',
|
||||
imageFilename: 'networking-innenhof.jpg',
|
||||
imageAlt: 'BMP Partnernetzwerk',
|
||||
imageLabel: 'BMP Partnernetzwerk',
|
||||
formEyebrow: 'Sponsoring 2026',
|
||||
footnotePrefix: 'Oder:',
|
||||
footnoteLabel: 'Vereinsmitglied werden',
|
||||
footnoteUrl: '/mitglied-werden',
|
||||
benefits: [
|
||||
{ num: '01', label: 'Markenpräsenz', sub: 'Bühne, Drucksachen, digitale Kanäle' },
|
||||
{ num: '02', label: 'Top-Entscheider', sub: 'Exklusives Netzwerk-Dinner für Partner' },
|
||||
{ num: '03', label: 'Multichannel', sub: 'Online, Print, Radio & TV-Partner' },
|
||||
],
|
||||
},
|
||||
sponsoringForm: {
|
||||
steps: [
|
||||
{ label: 'Paket' },
|
||||
{ label: 'Unternehmen' },
|
||||
{ label: 'Kontakt' },
|
||||
],
|
||||
packages: [
|
||||
{ value: 'main', title: 'Haupt-Sponsoring', desc: 'Maximale Sichtbarkeit auf allen Kanälen – Bühne, Digital, Print.' },
|
||||
{ value: 'category', title: 'Kategorie-Partner', desc: 'Namensgebung einer Auszeichnungskategorie – fokussiertes Branding.' },
|
||||
{ value: 'event', title: 'Event-Partner', desc: 'Präsenz beim exklusiven Gala-Abend in München.' },
|
||||
],
|
||||
step1Eyebrow: 'Schritt 1 – Paket wählen',
|
||||
step1Heading: 'Interesse an',
|
||||
step2Eyebrow: 'Schritt 2 – Unternehmen',
|
||||
step2Heading: 'Ihr Unternehmen',
|
||||
companyLabel: 'Unternehmen *',
|
||||
companyPlaceholder: 'Firmenname',
|
||||
industryLabel: 'Branche',
|
||||
industryPlaceholder: 'z. B. Finanzdienstleistungen',
|
||||
step3Eyebrow: 'Schritt 3 – Kontakt',
|
||||
step3Heading: 'Ansprechpartner',
|
||||
contactLabel: 'Ansprechpartner *',
|
||||
contactPlaceholder: 'Vor- und Nachname',
|
||||
emailLabel: 'E-Mail *',
|
||||
emailPlaceholder: 'name@unternehmen.de',
|
||||
backLabel: 'Zurück',
|
||||
nextLabel: 'Weiter',
|
||||
submitLabel: 'Exposé anfordern',
|
||||
requiredPackageError: 'Bitte wählen Sie ein Paket.',
|
||||
requiredFieldError: 'Pflichtfeld',
|
||||
invalidEmailError: 'Ungültige E-Mail',
|
||||
doneLabel: '✓',
|
||||
successHeading: 'Anfrage eingegangen',
|
||||
successMessagePrefix: 'Vielen Dank,',
|
||||
successMessageSuffix: 'Wir senden Ihnen unser Sponsoring-Exposé innerhalb von 48 Stunden zu.',
|
||||
footerText: 'Wir melden uns innerhalb von 48 Stunden.',
|
||||
},
|
||||
}
|
||||
@@ -4,6 +4,9 @@ import { ChevronRight, X, ArrowRight, Globe, Linkedin, Building2, MapPin, Extern
|
||||
import SponsoringForm from '@/spa/components/forms/SponsoringForm';
|
||||
import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg';
|
||||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||||
import { useCmsRoute } from '@/spa/cmsRoute';
|
||||
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField';
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent';
|
||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
@@ -20,6 +23,43 @@ const ROLE_COLOR: Record<string, string> = {
|
||||
'Medienpartner': '#DC2626',
|
||||
};
|
||||
|
||||
type NetzwerkCms = Partial<typeof netzwerkContent> & {
|
||||
hero?: Partial<typeof netzwerkContent.hero> & { image?: unknown }
|
||||
sponsoring?: Partial<typeof netzwerkContent.sponsoring> & { image?: unknown }
|
||||
}
|
||||
|
||||
type PatronPerson = (typeof netzwerkContent.patronage.people)[number]
|
||||
type JuryMember = (typeof netzwerkContent.jury.members)[number]
|
||||
type Partner = (typeof netzwerkContent.partners.items)[number] & { tier: 1 | 2 | 3; heroImg?: string; linkedin?: string; logoSubtext?: string }
|
||||
type PartnerTier = (typeof netzwerkContent.partners.tiers)[number]
|
||||
type ExpertiseRow = (typeof netzwerkContent.expertise.rows)[number]
|
||||
type StatItem = (typeof netzwerkContent.juryIntro.stats)[number]
|
||||
type BenefitItem = (typeof netzwerkContent.sponsoring.benefits)[number]
|
||||
type PartnerModalCopy = typeof netzwerkContent.partners.modal
|
||||
|
||||
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 Lines({ text, highlight }: { text: string; highlight?: string }) {
|
||||
return (
|
||||
<>
|
||||
{text.split('\n').map((line, i) => {
|
||||
const highlighted = highlight && line.includes(highlight)
|
||||
return (
|
||||
<React.Fragment key={`${line}-${i}`}>
|
||||
{i > 0 && <br />}
|
||||
{highlighted ? (
|
||||
<>
|
||||
{line.replace(highlight, '')}<span style={{ color: GOLD }}>{highlight}</span>
|
||||
</>
|
||||
) : line}
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// ── PersonCard (Schirmherrschaft) ─────────────────────────────────────────────
|
||||
|
||||
interface PersonCardProps {
|
||||
@@ -62,13 +102,6 @@ function PersonCard({ imgSrc, imgAlt, name, titleLine1, titleLine2, institution,
|
||||
|
||||
// ── JuryCard ──────────────────────────────────────────────────────────────────
|
||||
|
||||
interface JuryMember {
|
||||
name: string;
|
||||
role: string;
|
||||
bio: string;
|
||||
img: string;
|
||||
}
|
||||
|
||||
const JuryCard: React.FC<{ member: JuryMember; idx: number }> = ({ member, idx }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCard = useIsMobile();
|
||||
@@ -79,7 +112,7 @@ const JuryCard: React.FC<{ member: JuryMember; idx: number }> = ({ member, idx }
|
||||
style={{ borderLeft: !isMobileCard && idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', display: 'flex', flexDirection: 'column', cursor: 'default', background: hovered ? 'rgba(255,255,255,0.03)' : 'transparent', transition: 'background 0.2s', ...(isMobileCard ? { minWidth: '74vw', maxWidth: '74vw', flexShrink: 0, scrollSnapAlign: 'start', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 16, overflow: 'hidden' } : {}) }}
|
||||
>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', aspectRatio: '3/4' }}>
|
||||
<Image unoptimized src={member.img} alt={member.name} style={{ width: '100%', height: '100%', objectFit: 'cover', filter: hovered ? 'none' : 'grayscale(100%)', transition: 'filter 0.5s', display: 'block' }} />
|
||||
<Image unoptimized src={member.image} alt={member.name} style={{ width: '100%', height: '100%', objectFit: 'cover', filter: hovered ? 'none' : 'grayscale(100%)', transition: 'filter 0.5s', display: 'block' }} />
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: '40%', background: 'linear-gradient(to top, rgba(3,9,58,0.65), transparent)' }} />
|
||||
</div>
|
||||
<div style={{ padding: isMobileCard ? '28px 28px 32px' : '32px 32px 36px' }}>
|
||||
@@ -94,7 +127,7 @@ const JuryCard: React.FC<{ member: JuryMember; idx: number }> = ({ member, idx }
|
||||
|
||||
// ── JuryChairCard (Vorsitz – prominent) ───────────────────────────────────────
|
||||
|
||||
const JuryChairCard: React.FC<{ member: JuryMember }> = ({ member }) => {
|
||||
const JuryChairCard: React.FC<{ member: JuryMember; badge: string }> = ({ member, badge }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCard = useIsMobile();
|
||||
return (
|
||||
@@ -112,12 +145,12 @@ const JuryChairCard: React.FC<{ member: JuryMember }> = ({ member }) => {
|
||||
}}
|
||||
>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', aspectRatio: isMobileCard ? '16/10' : '3/4', minHeight: isMobileCard ? 240 : 'auto' }}>
|
||||
<Image unoptimized src={member.img} alt={member.name} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center top', filter: hovered ? 'none' : 'grayscale(100%)', transition: 'filter 0.5s', display: 'block' }} />
|
||||
<Image unoptimized src={member.image} alt={member.name} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center top', filter: hovered ? 'none' : 'grayscale(100%)', transition: 'filter 0.5s', display: 'block' }} />
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: '45%', background: 'linear-gradient(to top, rgba(3,9,58,0.7), transparent)' }} />
|
||||
</div>
|
||||
<div style={{ padding: isMobileCard ? '32px 28px 36px' : '56px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<span style={{ alignSelf: 'flex-start', fontFamily: FF, fontSize: 11, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.18em', color: NAVY, background: GOLD, padding: '7px 16px', borderRadius: 999, marginBottom: 24 }}>
|
||||
Jury-Vorsitz
|
||||
{badge}
|
||||
</span>
|
||||
<div style={{ fontFamily: FF, fontSize: isMobileCard ? 26 : 34, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.05, marginBottom: 10 }}>{member.name}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 13, color: GOLD, textTransform: 'uppercase', letterSpacing: '0.18em', fontWeight: 700, marginBottom: 24 }}>{member.role}</div>
|
||||
@@ -130,24 +163,41 @@ const JuryChairCard: React.FC<{ member: JuryMember }> = ({ member }) => {
|
||||
|
||||
// ── PartnerCell ───────────────────────────────────────────────────────────────
|
||||
|
||||
interface Partner {
|
||||
id: string;
|
||||
name: string;
|
||||
role: string;
|
||||
tier: 1 | 2 | 3;
|
||||
desc: string;
|
||||
fullDesc: string;
|
||||
logo: React.ReactNode;
|
||||
industry: string;
|
||||
location: string;
|
||||
website: string;
|
||||
heroImg?: string;
|
||||
linkedin?: string;
|
||||
}
|
||||
|
||||
// ── SponsorCell (tiered) ──────────────────────────────────────────────────────
|
||||
|
||||
const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx: number; cols: number; onClick: () => void }> = ({ partner, variant, idx, cols, onClick }) => {
|
||||
function PartnerLogo({ partner }: { partner: Partner }) {
|
||||
const color = fallbackText(partner.logoColor, '#111D55');
|
||||
const text = fallbackText(partner.logoText, partner.name);
|
||||
const subtext = fallbackText(partner.logoSubtext, '');
|
||||
|
||||
if (partner.logoKind === 'badge') {
|
||||
return <span style={{ background: color, color: '#fff', fontWeight: 900, fontSize: 14, padding: '4px 10px', lineHeight: 1.25, display: 'inline-block', textAlign: 'center' as const, fontFamily: FF }}>{text.split('\n').map((line, index) => <React.Fragment key={`${line}-${index}`}>{index > 0 && <br />}{line}</React.Fragment>)}</span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'monogram') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 22, height: 22, background: '#3a3a3a', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 900, fontSize: 11, fontFamily: FF }}>{subtext || text.slice(0, 2)}</span><span style={{ fontWeight: 700, fontSize: 15, color, fontFamily: FF }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'dot') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 20, height: 20, borderRadius: '50%', background: color, display: 'block' }} /><span style={{ fontWeight: 700, fontSize: 16, color, fontFamily: FF }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'leaf') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><svg width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="9" fill={color} /><path d="M10 3 Q14 7 14 10 Q14 14 10 17 Q6 14 6 10 Q6 7 10 3Z" fill="white" opacity="0.8" /></svg><span style={{ fontWeight: 700, fontSize: 15, color, fontFamily: FB }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'rsm') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ display: 'flex', gap: 2 }}><span style={{ width: 10, height: 10, background: '#6b7280', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#22c55e', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#3b82f6', display: 'block' }} /></span><span style={{ fontWeight: 900, fontSize: 15, letterSpacing: '-0.02em', color, fontFamily: FF }}>{text} {subtext && <span style={{ color: '#6b7280', fontWeight: 600 }}>{subtext}</span>}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'deutschebank') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}><svg width="20" height="20" viewBox="0 0 20 20"><rect x="1" y="1" width="18" height="18" fill="none" stroke={color} strokeWidth="1.5" /><line x1="5" y1="15" x2="15" y2="5" stroke={color} strokeWidth="2" /></svg><span style={{ fontWeight: 600, fontSize: 15, color, fontFamily: FB }}>{text}</span></span>
|
||||
}
|
||||
|
||||
return <span style={{ fontWeight: 900, fontSize: partner.logoKind === 'serif' ? 21 : 16, letterSpacing: partner.logoKind === 'serif' ? '0.12em' : '-0.01em', color, fontFamily: partner.logoKind === 'serif' ? 'Georgia, serif' : FF }}>{text}</span>
|
||||
}
|
||||
|
||||
const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx: number; cols: number; detailLabel: string; premiumLabel: string; onClick: () => void }> = ({ partner, variant, idx, cols, detailLabel, premiumLabel, onClick }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCell = useIsMobile();
|
||||
const lg = variant === 'lg';
|
||||
@@ -170,15 +220,15 @@ const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx
|
||||
}}
|
||||
>
|
||||
{lg && (
|
||||
<span style={{ position: 'absolute', top: 18, right: 18, fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.18em', color: '#101828', background: GOLD, padding: '4px 10px', borderRadius: 100, zIndex: 1 }}>Premium</span>
|
||||
<span style={{ position: 'absolute', top: 18, right: 18, fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.18em', color: '#101828', background: GOLD, padding: '4px 10px', borderRadius: 100, zIndex: 1 }}>{premiumLabel}</span>
|
||||
)}
|
||||
<div style={{ height: lg ? 52 : 44, display: 'flex', alignItems: 'center' }}>{partner.logo}</div>
|
||||
<div style={{ height: lg ? 52 : 44, display: 'flex', alignItems: 'center' }}><PartnerLogo partner={partner} /></div>
|
||||
<div style={{ width: hovered ? 48 : 20, height: 1, background: GOLD, transition: 'width 0.3s ease' }} />
|
||||
<div style={{ fontFamily: FF, fontSize: lg ? 22 : 18, fontWeight: 700, color: '#101828', letterSpacing: '-0.01em', lineHeight: 1.15 }}>{partner.name}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: sm ? 10 : 11, color: GOLD, textTransform: 'uppercase', letterSpacing: '0.2em', fontWeight: 700 }}>{partner.role}</div>
|
||||
{!sm && <div style={{ fontFamily: FB, fontSize: lg ? 17 : 16, color: 'rgba(16,24,40,0.45)', lineHeight: 1.6, flexGrow: 1 }}>{partner.desc}</div>}
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.12em', color: GOLD, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||
Details <ArrowRight size={10} />
|
||||
{detailLabel} <ArrowRight size={10} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -186,7 +236,7 @@ const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx
|
||||
|
||||
// ── PartnerModal ─────────────────────────────────────────────────────────────
|
||||
|
||||
function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => void }) {
|
||||
function PartnerModal({ partner, copy, onClose }: { partner: Partner; copy: PartnerModalCopy; onClose: () => void }) {
|
||||
const accentColor = ROLE_COLOR[partner.role] ?? GOLD;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -283,7 +333,7 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
padding: 10, zIndex: 2,
|
||||
}}>
|
||||
{partner.logo}
|
||||
<PartnerLogo partner={partner} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -304,9 +354,9 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
{/* 3 info cards */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10, marginBottom: 28 }}>
|
||||
{[
|
||||
{ Icon: Building2, label: 'Branche', value: partner.industry },
|
||||
{ Icon: MapPin, label: 'Standort', value: partner.location },
|
||||
{ Icon: Globe, label: 'Web', value: partner.website },
|
||||
{ Icon: Building2, label: fallbackText(copy.industryLabel, netzwerkContent.partners.modal.industryLabel), value: partner.industry },
|
||||
{ Icon: MapPin, label: fallbackText(copy.locationLabel, netzwerkContent.partners.modal.locationLabel), value: partner.location },
|
||||
{ Icon: Globe, label: fallbackText(copy.webLabel, netzwerkContent.partners.modal.webLabel), value: partner.website },
|
||||
].map(({ Icon, label, value }) => (
|
||||
<div key={label} style={{ background: 'hsl(220,40%,97%)', padding: '14px 16px', borderRadius: 8 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
|
||||
@@ -325,7 +375,7 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14 }}>
|
||||
<div style={{ width: 4, height: 20, background: accentColor, borderRadius: 2, flexShrink: 0 }} />
|
||||
<span style={{ fontFamily: FF, fontSize: 17, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: '#101828' }}>
|
||||
Über das Unternehmen
|
||||
{fallbackText(copy.aboutLabel, netzwerkContent.partners.modal.aboutLabel)}
|
||||
</span>
|
||||
</div>
|
||||
<p style={{ fontFamily: FB, fontSize: 19, color: 'rgba(16,24,40,0.6)', lineHeight: 1.82, marginBottom: 36 }}>
|
||||
@@ -349,7 +399,7 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
onMouseEnter={e => { const el = e.currentTarget as HTMLElement; el.style.background = '#FFD130'; el.style.boxShadow = '0 0 18px rgba(239,191,4,0.65), 0 0 40px rgba(239,191,4,0.3)'; }}
|
||||
onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = GOLD; el.style.boxShadow = 'none'; }}
|
||||
>
|
||||
Website besuchen <ExternalLink size={12} />
|
||||
{fallbackText(copy.websiteLabel, netzwerkContent.partners.modal.websiteLabel)} <ExternalLink size={12} />
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
@@ -364,7 +414,7 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
onMouseEnter={e => { const el = e.currentTarget as HTMLElement; el.style.background = NAVY; el.style.color = '#fff'; el.style.borderColor = NAVY; }}
|
||||
onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = 'rgba(16,24,40,0.45)'; el.style.borderColor = 'rgba(16,24,40,0.12)'; }}
|
||||
>
|
||||
Schließen
|
||||
{fallbackText(copy.closeLabel, netzwerkContent.partners.modal.closeLabel)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -376,10 +426,10 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
borderTop: '1px solid rgba(16,24,40,0.06)',
|
||||
}}>
|
||||
<span style={{ fontFamily: FF, fontSize: 9, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'rgba(16,24,40,0.3)' }}>
|
||||
Bayerischer Mittelstandspreis 2026
|
||||
{fallbackText(copy.footerTitle, netzwerkContent.partners.modal.footerTitle)}
|
||||
</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: accentColor }}>
|
||||
Offizieller {partner.role}
|
||||
{fallbackText(copy.footerRolePrefix, netzwerkContent.partners.modal.footerRolePrefix)} {partner.role}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -392,119 +442,30 @@ function PartnerModal({ partner, onClose }: { partner: Partner; onClose: () => v
|
||||
const Netzwerk: React.FC = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const [selectedPartner, setSelectedPartner] = useState<Partner | null>(null);
|
||||
|
||||
const juryMembers: JuryMember[] = [
|
||||
{ name: 'Prof. Dr. Klaus Bergmann', role: 'Vorsitzender / LMU München', bio: 'Spezialist für KMU-Strategien und Innovations-Ökosysteme.', img: 'https://images.unsplash.com/photo-1560250097-0b93528c311a?auto=format&fit=crop&q=80&w=400' },
|
||||
{ name: 'Dr. Sabine Hofmann', role: 'IHK Bayern', bio: 'Expertin für digitale Transformation und regionale Wertschöpfung.', img: 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&q=80&w=400' },
|
||||
{ name: 'Maximilian Reiter', role: 'Unternehmer', bio: 'CEO der Reiter Group, bringt die wertvolle Unternehmer-Perspektive ein.', img: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&q=80&w=400' },
|
||||
{ name: 'Dr. Elena Fischer', role: 'TU München', bio: 'Lehrstuhl für nachhaltige Unternehmensführung.', img: 'https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&q=80&w=400' },
|
||||
];
|
||||
|
||||
const partners: Partner[] = [
|
||||
/* ── TIER 1 · Hauptsponsoren ─────────────────────────────── */
|
||||
{
|
||||
id: 'rsm', name: 'RSM Ebner Stolz', role: 'Hauptsponsor', tier: 1,
|
||||
desc: 'Führende mittelständische Wirtschaftsprüfungs- und Steuerberatungsgesellschaft.',
|
||||
fullDesc: 'RSM Ebner Stolz ist eine der größten unabhängigen Wirtschaftsprüfungs- und Steuerberatungsgesellschaften Deutschlands mit besonderer Expertise im Mittelstand. Als Hauptsponsor des BMP unterstützen sie die Identifikation herausragender Unternehmen und bringen ihre Netzwerke aktiv in die Nominierungsphase ein.',
|
||||
logo: (<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ display: 'flex', gap: 2 }}><span style={{ width: 10, height: 10, background: '#6b7280', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#22c55e', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#3b82f6', display: 'block' }} /></span><span style={{ fontWeight: 900, fontSize: 15, letterSpacing: '-0.02em', color: '#374151', fontFamily: FF }}>RSM <span style={{ color: '#6b7280', fontWeight: 600 }}>EBNER STOLZ</span></span></span>),
|
||||
industry: 'Wirtschaftsprüfung & Beratung', location: 'München, Bayern', website: 'rsm-ebner-stolz.de', linkedin: 'https://linkedin.com/company/rsm-ebner-stolz',
|
||||
},
|
||||
{
|
||||
id: 'wwk', name: 'WWK', role: 'Hauptsponsor', tier: 1,
|
||||
desc: 'Eine starke Gemeinschaft – Lebensversicherungsgruppe mit bayerischen Wurzeln.',
|
||||
fullDesc: 'Die WWK Lebensversicherung a. G. ist eine der leistungsstärksten deutschen Lebensversicherungsgruppen. Als Münchner Traditionsunternehmen verbindet die WWK tiefe bayerische Verwurzelung mit finanzieller Stärke – Werte, die sie mit dem Bayerischen Mittelstandspreis teilt.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 24, letterSpacing: '-0.02em', color: '#16a34a', fontFamily: 'Arial Black, sans-serif' }}>WWK</span>),
|
||||
industry: 'Lebensversicherung', location: 'München, Bayern', website: 'wwk.de', linkedin: 'https://linkedin.com/company/wwk-versicherung',
|
||||
},
|
||||
|
||||
/* ── TIER 2 · Medienpartner ──────────────────────────────── */
|
||||
{
|
||||
id: 'radiogong', name: 'Radio Gong 96.3', role: 'Medienpartner', tier: 2,
|
||||
desc: 'Der reichweitenstärkste Radiosender Münchens – Stimme des Mittelstands.',
|
||||
fullDesc: 'Radio Gong 96.3 ist der reichweitenstärkste Radiosender Münchens. Als Medienpartner des BMP sorgt er für Aufmerksamkeit für die Nominierten in Sendemitschnitten und redaktionellen Beiträgen.',
|
||||
logo: (<span style={{ background: '#e11d48', color: '#fff', fontWeight: 900, fontSize: 14, padding: '4px 10px', lineHeight: 1.25, display: 'inline-block', textAlign: 'center' as const, fontFamily: '"IBM Plex Sans", sans-serif' }}>Radio<br/>Gong <span style={{ color: '#fde047' }}>96.3</span></span>),
|
||||
industry: 'Medien', location: 'München', website: 'radiogong.com',
|
||||
},
|
||||
{
|
||||
id: 'muenchentv', name: 'münchen.tv', role: 'Medienpartner', tier: 2,
|
||||
desc: 'Der lokale Fernsehsender der Landeshauptstadt München.',
|
||||
fullDesc: 'münchen.tv ist der lokale Fernsehsender der Landeshauptstadt München. Als Medienpartner überträgt münchen.tv Highlights der BMP-Gala und produziert Porträts der Nominierten.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 15, color: '#0ea5e9', fontFamily: '"Inter", sans-serif' }}>münchen<span style={{ color: '#1e293b' }}>.tv</span></span>),
|
||||
industry: 'Medien', location: 'München', website: 'muenchen.tv',
|
||||
},
|
||||
|
||||
/* ── TIER 3 · Weitere Sponsoren ──────────────────────────── */
|
||||
{
|
||||
id: 'metzler', name: 'METZLER', role: 'Sponsor', tier: 3,
|
||||
desc: 'Älteste Privatbank Deutschlands – Unabhängigkeit seit 1674.',
|
||||
fullDesc: 'B. Metzler seel. Sohn & Co. KGaA ist die älteste deutsche Privatbank in Familienbesitz – seit über 350 Jahren unabhängig. Ihr Engagement für den BMP unterstreicht die tiefe Verbundenheit mit dem Mittelstand, dessen Werte wie Verlässlichkeit, Substanz und Langfristigkeit Metzler selbst verkörpert.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 21, letterSpacing: '0.15em', color: '#1a1a1a', fontFamily: 'Georgia, serif' }}>METZLER</span>),
|
||||
industry: 'Privatbankwesen', location: 'Frankfurt a. M.', website: 'metzler.com', linkedin: 'https://linkedin.com/company/metzler',
|
||||
},
|
||||
{
|
||||
id: 'wieselhuber', name: 'Dr. Wieselhuber & Partner', role: 'Sponsor', tier: 3,
|
||||
desc: 'Unabhängige Top-Management-Beratung für Familienunternehmen und Mittelstand.',
|
||||
fullDesc: 'Dr. Wieselhuber & Partner ist eine unabhängige, branchenübergreifende Top-Management-Beratung mit besonderem Fokus auf Familienunternehmen und Mittelstand. Als Sponsor bringt das Haus seine Strategie- und Transformationsexpertise in das Netzwerk des BMP ein.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 16, letterSpacing: '-0.01em', color: '#1a2b4a', fontFamily: FF }}>W&P <span style={{ fontWeight: 600, color: '#5a6b85' }}>WIESELHUBER</span></span>),
|
||||
industry: 'Unternehmensberatung', location: 'München, Bayern', website: 'wieselhuber.de',
|
||||
},
|
||||
{
|
||||
id: 'fristads', name: 'Fristads', role: 'Sponsor', tier: 3,
|
||||
desc: 'Premium-Arbeitsbekleidung – Funktion, Qualität und Design.',
|
||||
fullDesc: 'Fristads steht für hochwertige, funktionale Arbeitsbekleidung, die Schutz, Komfort und Design vereint. Als Sponsor des Bayerischen Mittelstandspreises unterstützt das Unternehmen die Auszeichnung herausragender mittelständischer Betriebe.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 19, letterSpacing: '0.02em', color: '#1a1a1a', fontFamily: 'Arial Black, sans-serif' }}>FRISTADS</span>),
|
||||
industry: 'Workwear & Textil', location: 'Deutschland', website: 'fristads.com',
|
||||
},
|
||||
{
|
||||
id: 'newedge', name: 'New Edge', role: 'Sponsor', tier: 3,
|
||||
desc: 'Digitale Markenführung, Web und Design für den Mittelstand.',
|
||||
fullDesc: 'New Edge gestaltet Marken, Web-Erlebnisse und digitale Auftritte für mittelständische Unternehmen. Als Sponsor des BMP unterstützt die Agentur die Sichtbarkeit und das digitale Profil ausgezeichneter Unternehmen.',
|
||||
logo: (<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 22, height: 22, background: '#3a3a3a', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 900, fontSize: 11, fontFamily: FF }}>NE</span><span style={{ fontWeight: 700, fontSize: 15, color: '#005E67', fontFamily: FF }}>New Edge</span></span>),
|
||||
industry: 'Branding & Digital', location: 'Bayern', website: 'newedgebrand.com',
|
||||
},
|
||||
{
|
||||
id: 'moodtalk', name: 'Moodtalk', role: 'Sponsor', tier: 3,
|
||||
desc: 'Plattform für Teamkultur und Mitarbeiter-Feedback.',
|
||||
fullDesc: 'Moodtalk ist eine Plattform für Teamkultur, Stimmung und kontinuierliches Mitarbeiter-Feedback. Als Sponsor des BMP steht das Unternehmen für moderne, wertebasierte Unternehmensführung.',
|
||||
logo: (<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 20, height: 20, borderRadius: '50%', background: '#7c3aed', display: 'block' }} /><span style={{ fontWeight: 700, fontSize: 16, color: '#7c3aed', fontFamily: FF }}>moodtalk</span></span>),
|
||||
industry: 'HR & Software', location: 'Bayern', website: 'moodtalk.io',
|
||||
},
|
||||
{
|
||||
id: 'deutschebank', name: 'Deutsche Bank', role: 'Sponsor', tier: 3,
|
||||
desc: 'Partnerbank für die Finanzierung und Skalierung von KMU-Wachstum.',
|
||||
fullDesc: 'Die Deutsche Bank begleitet mittelständische Unternehmen als verlässlicher Finanzpartner durch alle Wachstumsphasen. Im Rahmen des BMP stellt sie ihr deutschlandweites Netzwerk, spezifische Mittelstandsprodukte und direkte Ansprechpartner für die Nominierten bereit.',
|
||||
logo: (<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}><svg width="20" height="20" viewBox="0 0 20 20"><rect x="1" y="1" width="18" height="18" fill="none" stroke="#1d1d1b" strokeWidth="1.5" /><line x1="5" y1="15" x2="15" y2="5" stroke="#1d1d1b" strokeWidth="2" /></svg><span style={{ fontWeight: 600, fontSize: 15, color: '#1d1d1b', fontFamily: FB }}>Deutsche Bank</span></span>),
|
||||
industry: 'Bankwesen & Finanzen', location: 'Frankfurt a. M.', website: 'db.com', linkedin: 'https://linkedin.com/company/deutsche-bank',
|
||||
},
|
||||
{
|
||||
id: 'bionorica', name: 'Bionorica', role: 'Sponsor', tier: 3,
|
||||
desc: 'Weltmarktführer für pflanzliche Arzneimittel aus dem bayerischen Neumarkt.',
|
||||
fullDesc: 'Bionorica SE ist ein international agierendes Pharmaunternehmen mit Sitz in Neumarkt i. d. OPf. und Weltmarktführer bei pflanzlichen Arzneimitteln. Das Unternehmen selbst ist ein Paradebeispiel eines bayerischen Mittelständlers mit globalem Anspruch und verkörpert die Innovationskraft, die der BMP würdigt.',
|
||||
logo: (<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><svg width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="9" fill="#16a34a" /><path d="M10 3 Q14 7 14 10 Q14 14 10 17 Q6 14 6 10 Q6 7 10 3Z" fill="white" opacity="0.8" /></svg><span style={{ fontWeight: 700, fontSize: 15, color: '#16a34a', fontFamily: FB }}>Bionorica<sup style={{ fontSize: 8 }}>®</sup></span></span>),
|
||||
industry: 'Pharmaindustrie', location: 'Neumarkt i.d.OPf., Bayern', website: 'bionorica.de', linkedin: 'https://linkedin.com/company/bionorica',
|
||||
},
|
||||
{
|
||||
id: 'primus', name: 'Primus', role: 'Sponsor', tier: 3,
|
||||
desc: 'Partner des Bayerischen Mittelstandspreises.',
|
||||
fullDesc: 'Primus unterstützt als Sponsor den Bayerischen Mittelstandspreis und sein Engagement für herausragende Unternehmen des bayerischen Mittelstands.',
|
||||
logo: (<span style={{ fontWeight: 900, fontSize: 18, letterSpacing: '0.04em', color: '#b8860b', fontFamily: 'Georgia, serif' }}>PRIMUS</span>),
|
||||
industry: 'Partner', location: 'Bayern', website: '',
|
||||
},
|
||||
];
|
||||
|
||||
const expertiseRows = [
|
||||
{ num: '01', label: 'Aktenstudium', body: 'Alle Einreichungen werden zunächst vollständig gesichtet und nach den festgelegten Kriterien geprüft.' },
|
||||
{ num: '02', label: 'Scoring-Matrix', body: 'Jedes Jurymitglied bewertet die Einreichungen unabhängig nach den festgelegten Kriterien.' },
|
||||
{ num: '03', label: 'Jury-Plenum', body: 'In der gemeinsamen Sitzung werden Argumente und Ansichten ausgetauscht, Eigenschaften verglichen und gemeinsam bewertet. Daraus entsteht die Liste der Finalisten.' },
|
||||
{ num: '04', label: 'Ergebnis', body: 'Die Gewinner des Bayerischen Mittelstandspreises werden nach vorgegebenem Punktesystem bestimmt, erweitert um Jury-Mitglieder aus der Praxis.' },
|
||||
];
|
||||
const cms = (useCmsRoute()?.doc?.netzwerk || {}) as NetzwerkCms;
|
||||
const hero = { ...netzwerkContent.hero, ...(cms.hero || {}) };
|
||||
const patronage = { ...netzwerkContent.patronage, ...(cms.patronage || {}) };
|
||||
const juryIntro = { ...netzwerkContent.juryIntro, ...(cms.juryIntro || {}) };
|
||||
const jury = { ...netzwerkContent.jury, ...(cms.jury || {}) };
|
||||
const expertise = { ...netzwerkContent.expertise, ...(cms.expertise || {}) };
|
||||
const partnerSection = { ...netzwerkContent.partners, ...(cms.partners || {}) };
|
||||
const partnerModal = { ...netzwerkContent.partners.modal, ...((cms.partners as typeof netzwerkContent.partners | undefined)?.modal || {}) };
|
||||
const sponsoring = { ...netzwerkContent.sponsoring, ...(cms.sponsoring || {}) };
|
||||
const patronPeople = fallbackArray<PatronPerson>(patronage.people, netzwerkContent.patronage.people);
|
||||
const juryMembers = fallbackArray<JuryMember>(jury.members, netzwerkContent.jury.members);
|
||||
const expertiseRows = fallbackArray<ExpertiseRow>(expertise.rows, netzwerkContent.expertise.rows);
|
||||
const partners = fallbackArray<Partner>(partnerSection.items, netzwerkContent.partners.items as Partner[]);
|
||||
const partnerTiers = fallbackArray<PartnerTier>(partnerSection.tiers, netzwerkContent.partners.tiers);
|
||||
const mobileStats = fallbackArray<StatItem>(juryIntro.stats, netzwerkContent.juryIntro.stats);
|
||||
const desktopStats = fallbackArray<StatItem>(juryIntro.desktopStats, netzwerkContent.juryIntro.desktopStats);
|
||||
const sponsorBenefits = fallbackArray<BenefitItem>(sponsoring.benefits, netzwerkContent.sponsoring.benefits);
|
||||
|
||||
return (
|
||||
<div className="animate-fade-in">
|
||||
|
||||
{/* ── 1. HERO ──────────────────────────────────────────────────────────── */}
|
||||
<section style={{ position: 'relative', minHeight: '72vh', display: 'flex', alignItems: 'flex-end', overflow: 'hidden', background: '#060C14' }}>
|
||||
<Image unoptimized src="/images/netzwerk-hero.jpg" alt="BMP Netzwerk Preisverleihung" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 30%' }} />
|
||||
<Image unoptimized src={mediaUrl(hero.image, `/images/${netzwerkContent.hero.imageFilename}`)} alt={mediaAlt(hero.image, fallbackText(hero.imageAlt, netzwerkContent.hero.imageAlt))} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 30%' }} />
|
||||
<div style={{ position: 'absolute', inset: 0, background: isMobile ? 'linear-gradient(to top, rgba(2,9,48,0.95) 0%, rgba(2,9,48,0.72) 38%, rgba(2,9,48,0.22) 72%, transparent 100%)' : 'linear-gradient(to right, #020930 0%, rgba(2,9,48,0.90) 38%, rgba(2,9,48,0.18) 65%, transparent 100%)' }} />
|
||||
<div style={{ position: 'absolute', top: 0, left: 80, width: 2, height: '100%', background: `linear-gradient(to bottom, transparent, ${GOLD}, transparent)`, opacity: 0.4 }} />
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: 2, background: 'linear-gradient(to right, #EFBF04, rgba(239,191,4,0.3), transparent)', zIndex: 2 }} />
|
||||
@@ -512,13 +473,13 @@ const Netzwerk: React.FC = () => {
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: isMobile ? '0 24px 48px' : '0 80px 88px', maxWidth: 860 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 28 }}>
|
||||
<div style={{ width: 40, height: 2, background: GOLD }} />
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD }}>Jury & Partner</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD }}>{fallbackText(hero.eyebrow, netzwerkContent.hero.eyebrow)}</span>
|
||||
</div>
|
||||
<h1 style={{ fontFamily: FF, fontSize: isMobile ? 'clamp(1.6rem, 6vw, 5rem)' : 'clamp(2.8rem, 6vw, 5rem)', fontWeight: 900, color: '#fff', lineHeight: 0.95, letterSpacing: '-0.03em', textTransform: 'uppercase', margin: '0 0 28px' }}>
|
||||
DAS NETZWERK<br />HINTER DEM <span style={{ color: GOLD }}>AWARD.</span>
|
||||
<Lines text={fallbackText(hero.heading, netzwerkContent.hero.heading)} highlight={fallbackText(hero.highlight, netzwerkContent.hero.highlight)} />
|
||||
</h1>
|
||||
<p style={{ fontFamily: FB, fontSize: 18, color: 'rgba(255,255,255,0.65)', lineHeight: 1.7, maxWidth: 560, margin: 0, fontWeight: 300 }}>
|
||||
Der Bayerische Mittelstandspreis wird getragen von einem starken Netzwerk aus Schirmherrschaft, unabhängiger Fach-Jury und langjährigen Partnern aus Wirtschaft und Gesellschaft.
|
||||
{fallbackText(hero.description, netzwerkContent.hero.description)}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -527,48 +488,43 @@ const Netzwerk: React.FC = () => {
|
||||
{/* ── 2. SCHIRMHERRSCHAFT ──────────────────────────────────────────────── */}
|
||||
<section id="schirmherrschaft" style={{ background: NAVY }}>
|
||||
<div style={{ padding: isMobile ? '48px 24px 32px' : '80px 80px 56px' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD, display: 'block', marginBottom: 16 }}>Die Schirmherrschaft</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(2rem, 4vw, 3rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1, margin: '0 0 20px' }}>Schirmherrin und Schirmherr</h2>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD, display: 'block', marginBottom: 16 }}>{fallbackText(patronage.eyebrow, netzwerkContent.patronage.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(2rem, 4vw, 3rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1, margin: '0 0 20px' }}>{fallbackText(patronage.heading, netzwerkContent.patronage.heading)}</h2>
|
||||
<div style={{ width: 40, height: 2, background: GOLD, marginBottom: 14 }} />
|
||||
<p style={{ fontFamily: FF, fontSize: 18, color: 'rgba(255,255,255,0.5)', margin: 0 }}>des Bayerischen Mittelstandspreises</p>
|
||||
<p style={{ fontFamily: FF, fontSize: 18, color: 'rgba(255,255,255,0.5)', margin: 0 }}>{fallbackText(patronage.description, netzwerkContent.patronage.description)}</p>
|
||||
</div>
|
||||
|
||||
<div style={{ display: isMobile ? 'flex' : 'grid', gridTemplateColumns: isMobile ? undefined : '1fr 1fr', overflowX: isMobile ? 'auto' : undefined, scrollSnapType: isMobile ? 'x mandatory' : undefined, gap: isMobile ? 14 : 0, padding: isMobile ? '0 24px 28px' : 0, WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none' }}>
|
||||
<PersonCard
|
||||
imgSrc="https://images.unsplash.com/photo-1551836022-d5d88e9218df?auto=format&fit=crop&q=80&w=800"
|
||||
imgAlt="Ilse Aigner"
|
||||
name="Ilse Aigner MdL"
|
||||
titleLine1="Präsidentin des Bayerischen Landtags"
|
||||
titleLine2="Bayerische Staatsministerin für Wirtschaft a.D."
|
||||
institution="Bayerischer Landtag"
|
||||
borderRight
|
||||
/>
|
||||
<PersonCard
|
||||
imgSrc="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&q=80&w=800"
|
||||
imgAlt="Hubert Aiwanger"
|
||||
name="Hubert Aiwanger MdL"
|
||||
titleLine1="Bayerischer Staatsminister für Wirtschaft,"
|
||||
titleLine2="Landesentwicklung und Energie · Stv. Ministerpräsident"
|
||||
institution="Bayerische Staatsregierung"
|
||||
/>
|
||||
{patronPeople.map((person, index) => (
|
||||
<PersonCard
|
||||
key={`${person.name}-${index}`}
|
||||
imgSrc={fallbackText(person.image, netzwerkContent.patronage.people[index]?.image || '')}
|
||||
imgAlt={fallbackText(person.imageAlt, person.name)}
|
||||
name={fallbackText(person.name, netzwerkContent.patronage.people[index]?.name || '')}
|
||||
titleLine1={fallbackText(person.titleLine1, netzwerkContent.patronage.people[index]?.titleLine1 || '')}
|
||||
titleLine2={fallbackText(person.titleLine2, netzwerkContent.patronage.people[index]?.titleLine2 || '')}
|
||||
institution={fallbackText(person.institution, netzwerkContent.patronage.people[index]?.institution || '')}
|
||||
borderRight={index === 0}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Grußwort – Ilse Aigner */}
|
||||
<div style={{ background: 'rgba(255,255,255,0.03)', borderTop: '1px solid rgba(255,255,255,0.07)' }}>
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '64px 80px', display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '40% 60%', gap: isMobile ? '24px 0' : '0 64px', alignItems: 'flex-start' }}>
|
||||
<div>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD, display: 'block', marginBottom: 8 }}>Grußwort</span>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, fontWeight: 400, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'rgba(255,255,255,0.3)', marginBottom: 16 }}>Schirmherrin</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.15, marginBottom: 10 }}>Ilse Aigner MdL</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 18, color: 'rgba(255,255,255,0.5)', lineHeight: 1.6, marginBottom: 4 }}>Präsidentin des Bayerischen Landtags</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 17, color: 'rgba(255,255,255,0.4)', lineHeight: 1.6 }}>Bayerische Staatsministerin für Wirtschaft a.D.</div>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: GOLD, display: 'block', marginBottom: 8 }}>{fallbackText(patronage.greetingEyebrow, netzwerkContent.patronage.greetingEyebrow)}</span>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, fontWeight: 400, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'rgba(255,255,255,0.3)', marginBottom: 16 }}>{fallbackText(patronage.greetingRole, netzwerkContent.patronage.greetingRole)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 18, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.15, marginBottom: 10 }}>{fallbackText(patronage.greetingName, netzwerkContent.patronage.greetingName)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 18, color: 'rgba(255,255,255,0.5)', lineHeight: 1.6, marginBottom: 4 }}>{fallbackText(patronage.greetingTitleLine1, netzwerkContent.patronage.greetingTitleLine1)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 17, color: 'rgba(255,255,255,0.4)', lineHeight: 1.6 }}>{fallbackText(patronage.greetingTitleLine2, netzwerkContent.patronage.greetingTitleLine2)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<blockquote style={{ fontFamily: FF, fontSize: 18, fontStyle: 'italic', color: 'rgba(255,255,255,0.8)', lineHeight: 1.75, margin: 0, paddingLeft: 24, borderLeft: `3px solid ${GOLD}` }}>
|
||||
„Der Bayerische Mittelstandspreis steht für das, was Bayern stark macht: Unternehmergeist, Verantwortung und Qualität. Mit großer Freude übernehme ich erneut die Schirmherrschaft für diesen bedeutenden Preis.“
|
||||
{fallbackText(patronage.greetingQuote, netzwerkContent.patronage.greetingQuote)}
|
||||
</blockquote>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, color: 'rgba(255,255,255,0.35)', marginTop: 20, paddingLeft: 24 }}>
|
||||
– Ilse Aigner MdL, Präsidentin des Bayerischen Landtags
|
||||
{fallbackText(patronage.greetingAttribution, netzwerkContent.patronage.greetingAttribution)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -587,24 +543,20 @@ const Netzwerk: React.FC = () => {
|
||||
{isMobile ? (
|
||||
/* Mobile: one cohesive navy module – copy + compact stat strip */
|
||||
<div style={{ padding: '48px 24px', position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 18 }}>Wer entscheidet?</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 18 }}>{fallbackText(juryIntro.eyebrow, netzwerkContent.juryIntro.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(1.7rem, 8vw, 2.2rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.08, margin: '0 0 22px' }}>
|
||||
UNABHÄNGIGE EXPERTISE FÜR DEN MITTELSTAND.
|
||||
<Lines text={fallbackText(juryIntro.heading, netzwerkContent.juryIntro.heading)} />
|
||||
</h2>
|
||||
<div style={{ width: 40, height: 2, background: GOLD, marginBottom: 22 }} />
|
||||
<p style={{ fontFamily: FB, fontSize: 16, color: 'rgba(255,255,255,0.55)', lineHeight: 1.75, margin: 0 }}>
|
||||
Die Jury des Bayerischen Mittelstandspreises besteht ausschließlich aus ehrenamtlich tätigen Expertinnen und Experten. Kein Mitglied steht in wirtschaftlicher Verbindung zu einem Bewerber – Transparenz und Unparteilichkeit sind die Grundpfeiler unseres Verfahrens.
|
||||
{fallbackText(juryIntro.description, netzwerkContent.juryIntro.description)}
|
||||
</p>
|
||||
{/* Stat strip */}
|
||||
<div style={{ display: 'flex', marginTop: 32, paddingTop: 26, borderTop: '1px solid rgba(255,255,255,0.14)' }}>
|
||||
{[
|
||||
{ v: '11', l: 'Jurymitglieder' },
|
||||
{ v: 'Mehrstufig', l: 'Bewertungsverfahren' },
|
||||
{ v: '100%', l: 'Unabhängig' },
|
||||
].map((s, i) => (
|
||||
{mobileStats.map((s, i) => (
|
||||
<div key={i} style={{ flex: 1, minWidth: 0, paddingLeft: i > 0 ? 14 : 0, borderLeft: i > 0 ? '1px solid rgba(255,255,255,0.14)' : 'none' }}>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(2.2rem, 9vw, 3rem)', fontWeight: 900, color: GOLD, letterSpacing: '-0.03em', lineHeight: 1 }}>{s.v}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'rgba(255,255,255,0.5)', marginTop: 8, lineHeight: 1.3 }}>{s.l}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(2.2rem, 9vw, 3rem)', fontWeight: 900, color: GOLD, letterSpacing: '-0.03em', lineHeight: 1 }}>{fallbackText(s.value, netzwerkContent.juryIntro.stats[i]?.value || '')}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'rgba(255,255,255,0.5)', marginTop: 8, lineHeight: 1.3 }}>{fallbackText(s.label, netzwerkContent.juryIntro.stats[i]?.label || '')}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -614,29 +566,29 @@ const Netzwerk: React.FC = () => {
|
||||
{/* Left – Cream, stats */}
|
||||
<div style={{ background: CREAM, padding: '72px 64px', display: 'flex', flexDirection: 'column', justifyContent: 'center', position: 'relative', zIndex: 1 }}>
|
||||
<div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(5rem, 8.5vw, 7.5rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.04em', lineHeight: 1 }}>11</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 4 }}>Unabhängige Jurymitglieder</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(5rem, 8.5vw, 7.5rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.04em', lineHeight: 1 }}>{fallbackText(desktopStats[0]?.value, netzwerkContent.juryIntro.desktopStats[0].value)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 4 }}>{fallbackText(desktopStats[0]?.label, netzwerkContent.juryIntro.desktopStats[0].label)}</div>
|
||||
</div>
|
||||
<div style={{ width: '100%', height: 1, background: 'rgba(3,9,58,0.1)', margin: '32px 0' }} />
|
||||
<div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(2.4rem, 4vw, 3.4rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.03em', lineHeight: 1 }}>Mehrstufig</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 8 }}>Bewertungsverfahren</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(2.4rem, 4vw, 3.4rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.03em', lineHeight: 1 }}>{fallbackText(desktopStats[1]?.value, netzwerkContent.juryIntro.desktopStats[1].value)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 8 }}>{fallbackText(desktopStats[1]?.label, netzwerkContent.juryIntro.desktopStats[1].label)}</div>
|
||||
</div>
|
||||
<div style={{ width: '100%', height: 1, background: 'rgba(3,9,58,0.1)', margin: '32px 0' }} />
|
||||
<div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(5rem, 8.5vw, 7.5rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.04em', lineHeight: 1 }}>100%</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 4 }}>Unabhängig & ehrenamtlich</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 'clamp(5rem, 8.5vw, 7.5rem)', fontWeight: 900, color: '#101828', letterSpacing: '-0.04em', lineHeight: 1 }}>{fallbackText(desktopStats[2]?.value, netzwerkContent.juryIntro.desktopStats[2].value)}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.15em', color: 'rgba(16,24,40,0.4)', marginTop: 4 }}>{fallbackText(desktopStats[2]?.label, netzwerkContent.juryIntro.desktopStats[2].label)}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Right – Navy, editorial copy */}
|
||||
<div style={{ background: NAVY, padding: '72px 64px', display: 'flex', flexDirection: 'column', justifyContent: 'center', position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, marginBottom: 20 }}>Wer entscheidet?</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, marginBottom: 20 }}>{fallbackText(juryIntro.eyebrow, netzwerkContent.juryIntro.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(1.6rem, 2.5vw, 2.2rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.08, margin: '0 0 24px' }}>
|
||||
UNABHÄNGIGE EXPERTISE FÜR DEN MITTELSTAND.
|
||||
<Lines text={fallbackText(juryIntro.heading, netzwerkContent.juryIntro.heading)} />
|
||||
</h2>
|
||||
<div style={{ width: 40, height: 2, background: GOLD }} />
|
||||
<p style={{ marginTop: 24, fontFamily: FB, fontSize: 19, color: 'rgba(255,255,255,0.45)', lineHeight: 1.85 }}>
|
||||
Die Jury des Bayerischen Mittelstandspreises besteht ausschließlich aus ehrenamtlich tätigen Expertinnen und Experten. Kein Mitglied steht in wirtschaftlicher Verbindung zu einem Bewerber – Transparenz und Unparteilichkeit sind die Grundpfeiler unseres Verfahrens.
|
||||
{fallbackText(juryIntro.description, netzwerkContent.juryIntro.description)}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
@@ -648,17 +600,17 @@ const Netzwerk: React.FC = () => {
|
||||
<section id="jury" style={{ background: NAVY, overflow: 'hidden', position: 'relative' }}>
|
||||
<div style={{ padding: isMobile ? '48px 24px 32px' : '80px 80px 56px', display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: isMobile ? 16 : 48, alignItems: 'flex-end', borderBottom: '1px solid rgba(255,255,255,0.07)' }}>
|
||||
<div>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 16 }}>Das Gremium</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(2rem, 3.5vw, 3rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 0.95, margin: 0 }}>UNSERE JURY 2026</h2>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 16 }}>{fallbackText(jury.eyebrow, netzwerkContent.jury.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(2rem, 3.5vw, 3rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 0.95, margin: 0 }}><Lines text={fallbackText(jury.heading, netzwerkContent.jury.heading)} /></h2>
|
||||
</div>
|
||||
<p style={{ fontFamily: FB, fontSize: 19, color: 'rgba(255,255,255,0.4)', lineHeight: 1.8, margin: 0 }}>
|
||||
Unabhängige Expertinnen und Experten aus Wirtschaft, Wissenschaft und Verbänden, für einen vollständig unabhängigen Bewertungsprozess.
|
||||
{fallbackText(jury.description, netzwerkContent.jury.description)}
|
||||
</p>
|
||||
</div>
|
||||
{/* ── Prominenter Vorsitz-Bereich ─────────────────────────────────── */}
|
||||
{/* TODO: echten Jury-Vorsitzenden bestätigen (Name & Foto sind Platzhalter) */}
|
||||
<div style={{ padding: isMobile ? '28px 24px 8px' : '64px 80px 16px' }}>
|
||||
<JuryChairCard member={juryMembers[0]} />
|
||||
<JuryChairCard member={juryMembers[0]} badge={fallbackText(jury.chairBadge, netzwerkContent.jury.chairBadge)} />
|
||||
</div>
|
||||
|
||||
{/* ── Übrige Jury-Mitglieder ──────────────────────────────────────── */}
|
||||
@@ -671,7 +623,7 @@ const Netzwerk: React.FC = () => {
|
||||
{/* ── Hinweis: Doppelrolle Jury / Partner (#179) ──────────────────── */}
|
||||
<div style={{ padding: isMobile ? '4px 24px 36px' : '8px 80px 56px' }}>
|
||||
<p style={{ fontFamily: FB, fontSize: isMobile ? 13 : 14, color: 'rgba(255,255,255,0.35)', lineHeight: 1.6, margin: 0, maxWidth: 720 }}>
|
||||
Hinweis: Einzelne Persönlichkeiten engagieren sich sowohl in der Jury als auch als Partner des BMP – beide Rollen werden auf dieser Seite getrennt ausgewiesen.
|
||||
{fallbackText(jury.note, netzwerkContent.jury.note)}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -680,8 +632,8 @@ const Netzwerk: React.FC = () => {
|
||||
{/* ── 5. HINTERGRUND & EXPERTISE ───────────────────────────────────────── */}
|
||||
<section style={{ background: '#101828', overflow: 'hidden', display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '55% 45%', borderTop: '1px solid rgba(255,255,255,0.07)' }}>
|
||||
<div style={{ padding: isMobile ? '48px 24px' : 80, display: 'flex', flexDirection: 'column', justifyContent: 'center', background: '#101828' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 16 }}>Hintergrund & Expertise</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(1.8rem, 3vw, 2.6rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 1.0, margin: '0 0 24px' }}>WIE BEWERTET DIE JURY?</h2>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 16 }}>{fallbackText(expertise.eyebrow, netzwerkContent.expertise.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(1.8rem, 3vw, 2.6rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 1.0, margin: '0 0 24px' }}><Lines text={fallbackText(expertise.heading, netzwerkContent.expertise.heading)} /></h2>
|
||||
<div style={{ width: 40, height: 2, background: GOLD, marginBottom: 40 }} />
|
||||
<div>
|
||||
{expertiseRows.map((row) => (
|
||||
@@ -698,11 +650,11 @@ const Netzwerk: React.FC = () => {
|
||||
<div style={{ padding: isMobile ? '48px 24px' : '80px 64px', display: 'flex', flexDirection: 'column', justifyContent: 'center', borderLeft: isMobile ? 'none' : '1px solid rgba(255,255,255,0.07)', borderTop: isMobile ? '1px solid rgba(255,255,255,0.07)' : 'none', overflow: 'hidden', background: '#101828' }}>
|
||||
<span style={{ fontFamily: 'Georgia, serif', fontSize: 'clamp(60px, 8vw, 120px)', color: 'rgba(239,191,4,0.1)', lineHeight: 0.8, display: 'block', marginBottom: -20 }}>“</span>
|
||||
<p style={{ fontFamily: FF, fontSize: 'clamp(1.1rem, 1.8vw, 1.4rem)', fontWeight: 300, color: 'rgba(255,255,255,0.75)', lineHeight: 1.65, margin: '0 0 40px' }}>
|
||||
Die Jury des BMP ist vollständig von wirtschaftlichen Interessen unabhängig. Jede Entscheidung wird transparent nachvollzogen – das ist unser Versprechen an die Unternehmen Bayerns.
|
||||
{fallbackText(expertise.quote, netzwerkContent.expertise.quote)}
|
||||
</p>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
|
||||
<div style={{ width: 40, height: 2, background: GOLD, flexShrink: 0 }} />
|
||||
<span style={{ fontFamily: FF, fontSize: 17, color: 'rgba(255,255,255,0.4)' }}>Prof. Dr. Klaus Bergmann, Juryvorsitzender</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 17, color: 'rgba(255,255,255,0.4)' }}>{fallbackText(expertise.quoteAttribution, netzwerkContent.expertise.quoteAttribution)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -713,26 +665,25 @@ const Netzwerk: React.FC = () => {
|
||||
<MunichSkylineBg />
|
||||
<div style={{ padding: isMobile ? '48px 24px 32px' : '80px 80px 56px', display: 'flex', flexDirection: isMobile ? 'column' : 'row', gap: isMobile ? 12 : 0, justifyContent: 'space-between', alignItems: isMobile ? 'flex-start' : 'flex-end', borderBottom: '1px solid rgba(3,9,58,0.1)' }}>
|
||||
<div>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: '#4A8FC9', display: 'block', marginBottom: 16 }}>Netzwerkqualität</span>
|
||||
<h2 style={{ fontFamily: FF, fontWeight: 900, color: '#101828', textTransform: 'uppercase', letterSpacing: '-0.025em', fontSize: 'clamp(2rem, 3.5vw, 3rem)', lineHeight: 0.95, margin: 0 }}>PARTNER & SPONSOREN</h2>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: '#4A8FC9', display: 'block', marginBottom: 16 }}>{fallbackText(partnerSection.eyebrow, netzwerkContent.partners.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontWeight: 900, color: '#101828', textTransform: 'uppercase', letterSpacing: '-0.025em', fontSize: 'clamp(2rem, 3.5vw, 3rem)', lineHeight: 0.95, margin: 0 }}><Lines text={fallbackText(partnerSection.heading, netzwerkContent.partners.heading)} /></h2>
|
||||
</div>
|
||||
<p style={{ fontFamily: FB, fontSize: 18, color: 'rgba(16,24,40,0.4)', maxWidth: isMobile ? '100%' : 220, textAlign: isMobile ? 'left' : 'right', lineHeight: 1.6, margin: 0 }}>
|
||||
Partner in drei Kategorien: Hauptsponsoren, Medienpartner und weitere Sponsoren. Klicken für Details.
|
||||
{fallbackText(partnerSection.description, netzwerkContent.partners.description)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tiered grid – continuous, ranks marked by label bars */}
|
||||
<div style={{ position: 'relative', zIndex: 1 }}>
|
||||
{([
|
||||
{ tier: 1 as const, label: 'Hauptsponsoren', note: 'Premium', variant: 'lg' as const, cols: isMobile ? 1 : 2 },
|
||||
{ tier: 2 as const, label: 'Medienpartner', note: '', variant: 'md' as const, cols: isMobile ? 2 : 2 },
|
||||
{ tier: 3 as const, label: 'Weitere Sponsoren', note: '', variant: 'sm' as const, cols: isMobile ? 2 : 4 },
|
||||
]).map(t => {
|
||||
const items = partners.filter(p => p.tier === t.tier);
|
||||
{partnerTiers.map(t => {
|
||||
const tier = Number(t.tier) as 1 | 2 | 3;
|
||||
const variant = tier === 1 ? 'lg' as const : tier === 2 ? 'md' as const : 'sm' as const;
|
||||
const cols = isMobile ? (tier === 1 ? 1 : 2) : (tier === 3 ? 4 : 2);
|
||||
const items = partners.filter(p => p.tier === tier);
|
||||
return (
|
||||
<div key={t.tier} style={{ display: 'grid', gridTemplateColumns: `repeat(${t.cols}, 1fr)` }}>
|
||||
<div key={t.tier} style={{ display: 'grid', gridTemplateColumns: `repeat(${cols}, 1fr)` }}>
|
||||
{items.map((p, i) => (
|
||||
<SponsorCell key={p.id} partner={p} variant={t.variant} idx={i} cols={t.cols} onClick={() => setSelectedPartner(p)} />
|
||||
<SponsorCell key={p.id} partner={p} variant={variant} idx={i} cols={cols} detailLabel={fallbackText(partnerSection.detailLabel, netzwerkContent.partners.detailLabel)} premiumLabel={fallbackText(partnerSection.premiumLabel, netzwerkContent.partners.premiumLabel)} onClick={() => setSelectedPartner(p)} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -750,17 +701,13 @@ const Netzwerk: React.FC = () => {
|
||||
<div style={{ flex: 1, position: 'relative', zIndex: 1, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', minHeight: 0, overflow: isMobile ? 'visible' : 'visible' }}>
|
||||
{/* Left – pitch */}
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: 'visible' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 8 }}>Wachstum durch Partnerschaft</span>
|
||||
<h2 style={{ fontFamily: FF, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', fontSize: 'clamp(1.6rem, 2.4vw, 2.4rem)', lineHeight: 1.0, margin: '0 0 12px' }}>WIR FREUEN UNS ÜBER NEUE SPONSOREN.</h2>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 8 }}>{fallbackText(sponsoring.eyebrow, netzwerkContent.sponsoring.eyebrow)}</span>
|
||||
<h2 style={{ fontFamily: FF, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', fontSize: 'clamp(1.6rem, 2.4vw, 2.4rem)', lineHeight: 1.0, margin: '0 0 12px' }}><Lines text={fallbackText(sponsoring.heading, netzwerkContent.sponsoring.heading)} /></h2>
|
||||
<div style={{ width: 36, height: 2, background: GOLD, margin: '0 0 14px', flexShrink: 0 }} />
|
||||
<p style={{ fontFamily: FB, fontSize: 'clamp(15px, 1.2vw, 17px)', color: 'rgba(255,255,255,0.75)', lineHeight: 1.65, marginBottom: 16 }}>
|
||||
Positionieren Sie Ihre Marke im exklusivsten Netzwerk des bayerischen Mittelstands – mit maßgeschneiderten Sponsoring-Paketen.
|
||||
{fallbackText(sponsoring.description, netzwerkContent.sponsoring.description)}
|
||||
</p>
|
||||
{[
|
||||
{ num: '01', label: 'Markenpräsenz', sub: 'Bühne, Drucksachen, digitale Kanäle' },
|
||||
{ num: '02', label: 'Top-Entscheider', sub: 'Exklusives Netzwerk-Dinner für Partner' },
|
||||
{ num: '03', label: 'Multichannel', sub: 'Online, Print, Radio & TV-Partner' },
|
||||
].map((item) => (
|
||||
{sponsorBenefits.map((item) => (
|
||||
<div key={item.num} style={{ display: 'grid', gridTemplateColumns: '32px 1fr', gap: '0 12px', padding: '10px 0', borderBottom: '1px solid rgba(255,255,255,0.06)', alignItems: 'center' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: 'rgba(239,191,4,0.5)' }}>{item.num}</span>
|
||||
<div>
|
||||
@@ -790,26 +737,26 @@ const Netzwerk: React.FC = () => {
|
||||
|
||||
{!isMobile && (
|
||||
<div style={{ height: 220, position: 'relative', overflow: 'hidden', flexShrink: 0, zIndex: 1 }}>
|
||||
<Image unoptimized src="/images/networking-innenhof.jpg" alt="BMP Partnernetzwerk" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 40%', filter: 'sepia(0.18) brightness(0.92)' }} />
|
||||
<Image unoptimized src={mediaUrl(sponsoring.image, `/images/${netzwerkContent.sponsoring.imageFilename}`)} alt={mediaAlt(sponsoring.image, fallbackText(sponsoring.imageAlt, netzwerkContent.sponsoring.imageAlt))} style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 40%', 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: FF, fontSize: 10, fontWeight: 700, color: 'rgba(17,29,85,0.75)', textTransform: 'uppercase', letterSpacing: '0.2em' }}>BMP Partnernetzwerk</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: 'rgba(17,29,85,0.75)', textTransform: 'uppercase', letterSpacing: '0.2em' }}>{fallbackText(sponsoring.imageLabel, netzwerkContent.sponsoring.imageLabel)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '28px 20px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: isMobile ? 560 : 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: 'rgba(17,29,85,0.5)', display: 'block', marginBottom: 8 }}>Sponsoring 2026</span>
|
||||
<SponsoringForm theme="gold" />
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: 'rgba(17,29,85,0.5)', display: 'block', marginBottom: 8 }}>{fallbackText(sponsoring.formEyebrow, netzwerkContent.sponsoring.formEyebrow)}</span>
|
||||
<SponsoringForm theme="gold" content={cms.sponsoringForm} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Footnote */}
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: isMobile ? '16px 20px 20px' : '14px 56px 18px', display: 'flex', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 15, color: 'rgba(255,255,255,0.45)', marginRight: 10 }}>Oder:</span>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 15, color: 'rgba(255,255,255,0.45)', marginRight: 10 }}>{fallbackText(sponsoring.footnotePrefix, netzwerkContent.sponsoring.footnotePrefix)}</span>
|
||||
<Link
|
||||
to="/mitglied-werden"
|
||||
to={fallbackText(sponsoring.footnoteUrl, netzwerkContent.sponsoring.footnoteUrl)}
|
||||
style={{
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
fontSize: 15,
|
||||
@@ -834,7 +781,7 @@ const Netzwerk: React.FC = () => {
|
||||
(e.currentTarget as HTMLElement).style.borderBottomColor = 'rgba(239,191,4,0.3)';
|
||||
}}
|
||||
>
|
||||
Vereinsmitglied werden <ChevronRight size={11} />
|
||||
{fallbackText(sponsoring.footnoteLabel, netzwerkContent.sponsoring.footnoteLabel)} <ChevronRight size={11} />
|
||||
</Link>
|
||||
</div>
|
||||
<div style={{ position: 'relative', zIndex: 1, height: 2, background: `linear-gradient(to right, ${GOLD}, rgba(239,191,4,0.3), transparent)`, flexShrink: 0 }} />
|
||||
@@ -843,7 +790,7 @@ const Netzwerk: React.FC = () => {
|
||||
|
||||
{/* ── 8. PARTNER MODAL ─────────────────────────────────────────────────── */}
|
||||
{selectedPartner && (
|
||||
<PartnerModal partner={selectedPartner} onClose={() => setSelectedPartner(null)} />
|
||||
<PartnerModal partner={selectedPartner} copy={partnerModal} onClose={() => setSelectedPartner(null)} />
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user