Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Link } from '@/spa/router';
|
||||
import { ChevronRight, X, ArrowRight, Globe, Linkedin, Building2, MapPin, ExternalLink, Play } from 'lucide-react';
|
||||
import { X, ArrowRight, Globe, Linkedin, Building2, MapPin, ExternalLink, Play } from 'lucide-react';
|
||||
import SponsoringForm from '@/spa/components/forms/SponsoringForm';
|
||||
import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg';
|
||||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||||
@@ -16,7 +16,6 @@ const FB = '"Inter", sans-serif';
|
||||
const NAVY = '#111D55';
|
||||
const GOLD = '#EFBF04';
|
||||
const CREAM = '#E4E2E3';
|
||||
const HIDE_MEMBERSHIP_NETWORK_CTA = true;
|
||||
|
||||
type NetzwerkCms = Partial<typeof netzwerkContent> & {
|
||||
hero?: Partial<typeof netzwerkContent.hero> & { image?: unknown }
|
||||
@@ -98,12 +97,6 @@ const sortedJuryMembers = (members: JuryMember[]) =>
|
||||
.map((member, index) => ({ member, index }))
|
||||
.sort((a, b) => Number(a.member.sortOrder ?? a.index) - Number(b.member.sortOrder ?? b.index))
|
||||
.map(({ member }) => member)
|
||||
const isMembershipCta = (cta?: { label?: string | null; url?: string | null } | null) => {
|
||||
const normalizedLabel = cta?.label?.trim().toLowerCase();
|
||||
|
||||
return cta?.url === '/mitglied-werden' || normalizedLabel === 'mitglied werden' || normalizedLabel === 'vereinsmitglied werden';
|
||||
}
|
||||
|
||||
function Lines({ text, highlight }: { text: string; highlight?: string }) {
|
||||
return (
|
||||
<>
|
||||
@@ -174,10 +167,10 @@ const JuryCard: React.FC<{ member: JuryMember }> = ({ member }) => {
|
||||
<div
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
style={{ display: 'flex', flexDirection: 'column', height: '100%', cursor: 'default', background: hovered ? 'rgba(255,255,255,0.04)' : NAVY, transition: 'background 0.2s', ...(isMobileCard ? { minWidth: '58vw', maxWidth: '58vw', flexShrink: 0, scrollSnapAlign: 'start', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 16, overflow: 'hidden' } : { minWidth: 0, border: '1px solid rgba(255,255,255,0.07)' }) }}
|
||||
style={{ display: 'flex', flexDirection: 'column', height: '100%', cursor: 'default', background: hovered ? 'rgba(255,255,255,0.04)' : NAVY, transition: 'background 0.2s', ...(isMobileCard ? { minWidth: '72vw', maxWidth: '72vw', flexShrink: 0, scrollSnapAlign: 'start', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 16, overflow: 'hidden' } : { minWidth: 0, border: '1px solid rgba(255,255,255,0.07)' }) }}
|
||||
>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', height: isMobileCard ? 142 : 170, flexShrink: 0 }}>
|
||||
<Image unoptimized src={managedImage(member.imageUpload, member.image)} alt={fallbackText(member.imageAlt, 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: 'relative', overflow: 'hidden', height: isMobileCard ? 142 : 170, flexShrink: 0, background: 'rgba(255,255,255,0.03)' }}>
|
||||
<Image unoptimized src={managedImage(member.imageUpload, member.image)} alt={fallbackText(member.imageAlt, member.name)} style={{ width: '100%', height: '100%', objectFit: 'contain', 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: '40%', background: 'linear-gradient(to top, rgba(3,9,58,0.65), transparent)' }} />
|
||||
</div>
|
||||
<div style={{ padding: isMobileCard ? '18px 18px 22px' : '20px 20px 24px', flex: 1, minWidth: 0, overflowWrap: 'anywhere', wordBreak: 'break-word' }}>
|
||||
@@ -215,8 +208,8 @@ const JuryChairCard: React.FC<{ member: JuryMember; badge: string }> = ({ member
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', aspectRatio: isMobileCard ? '16/10' : '3/4', minHeight: isMobileCard ? 240 : 'auto' }}>
|
||||
<Image unoptimized src={managedImage(member.imageUpload, member.image)} alt={fallbackText(member.imageAlt, 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: 'relative', overflow: 'hidden', aspectRatio: isMobileCard ? '16/10' : '3/4', minHeight: isMobileCard ? 240 : 'auto', background: 'rgba(255,255,255,0.03)' }}>
|
||||
<Image unoptimized src={managedImage(member.imageUpload, member.image)} alt={fallbackText(member.imageAlt, member.name)} style={{ width: '100%', height: '100%', objectFit: 'contain', 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' }}>
|
||||
@@ -354,20 +347,25 @@ function PartnerModal({ partner, copy, onClose }: { partner: Partner; copy: Part
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Logo box – bottom left (overflows hero) */}
|
||||
{/* Logo box – bottom left */}
|
||||
<div style={{
|
||||
position: 'absolute', bottom: -28, left: 28,
|
||||
width: 80, height: 80, background: '#fff',
|
||||
position: 'absolute', bottom: -38, left: 28,
|
||||
width: 'min(260px, calc(100% - 56px))', minWidth: 112, height: 112, background: '#fff',
|
||||
borderRadius: 12, boxShadow: '0 4px 24px rgba(0,0,0,0.14)',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
padding: 10, zIndex: 2,
|
||||
boxSizing: 'border-box',
|
||||
flexShrink: 0,
|
||||
overflow: 'hidden',
|
||||
padding: 14, zIndex: 2,
|
||||
}}>
|
||||
<PartnerLogoMark partner={partner} />
|
||||
<div style={{ width: '100%', height: '100%', minWidth: 0, overflow: 'hidden' }}>
|
||||
<PartnerLogoMark partner={partner} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Content ── */}
|
||||
<div style={{ padding: '52px 32px 32px' }}>
|
||||
<div style={{ padding: '72px 32px 32px' }}>
|
||||
<h2 style={{
|
||||
fontFamily: FF, fontSize: 'clamp(1.5rem, 3vw, 2rem)',
|
||||
fontWeight: 900, color: '#101828',
|
||||
@@ -507,9 +505,6 @@ const Netzwerk: React.FC = () => {
|
||||
const greetingVideoTitle = fallbackText(homeVideoModal.title, homeContent.videoModal.title);
|
||||
const greetingVideoLabel = fallbackText(home.hero?.videoLabel, homeContent.hero.videoLabel);
|
||||
const greetingVideoCloseLabel = fallbackText(homeVideoModal.closeLabel, homeContent.videoModal.closeLabel);
|
||||
const showMembershipFootnote =
|
||||
!HIDE_MEMBERSHIP_NETWORK_CTA ||
|
||||
!isMembershipCta({ label: sponsoring.footnoteLabel, url: sponsoring.footnoteUrl });
|
||||
|
||||
useEffect(() => {
|
||||
if (!showGreetingVideo || !greetingVideoSrc) return;
|
||||
@@ -712,18 +707,11 @@ const Netzwerk: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* ── Übrige Jury-Mitglieder ──────────────────────────────────────── */}
|
||||
<div style={{ display: isMobile ? 'flex' : 'grid', gridTemplateColumns: isMobile ? undefined : 'repeat(auto-fill, minmax(210px, 1fr))', overflowX: isMobile ? 'auto' : undefined, scrollSnapType: isMobile ? 'x mandatory' : undefined, gap: isMobile ? 12 : 0, padding: isMobile ? '24px 24px 12px' : '0', WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none', borderTop: isMobile ? 'none' : '1px solid rgba(255,255,255,0.07)' }}>
|
||||
<div style={{ display: isMobile ? 'flex' : 'grid', gridTemplateColumns: isMobile ? undefined : 'repeat(auto-fill, minmax(260px, 1fr))', overflowX: isMobile ? 'auto' : undefined, scrollSnapType: isMobile ? 'x mandatory' : undefined, gap: isMobile ? 12 : 0, padding: isMobile ? '24px 24px 36px' : '0 0 56px', WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none', borderTop: isMobile ? 'none' : '1px solid rgba(255,255,255,0.07)' }}>
|
||||
{juryMembers.slice(1).map((member, idx) => (
|
||||
<JuryCard key={idx} member={member} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* ── 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 }}>
|
||||
{fallbackText(jury.note, netzwerkContent.jury.note)}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -850,40 +838,6 @@ const Netzwerk: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Footnote */}
|
||||
{showMembershipFootnote && (
|
||||
<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 }}>{fallbackText(sponsoring.footnotePrefix, netzwerkContent.sponsoring.footnotePrefix)}</span>
|
||||
<Link
|
||||
to={fallbackText(sponsoring.footnoteUrl, netzwerkContent.sponsoring.footnoteUrl)}
|
||||
style={{
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
letterSpacing: '0.12em',
|
||||
textTransform: 'uppercase',
|
||||
color: 'rgba(239,191,4,0.7)',
|
||||
textDecoration: 'none',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
borderBottom: '1px solid rgba(239,191,4,0.3)',
|
||||
paddingBottom: 1,
|
||||
transition: 'color 0.15s, borderColor 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
(e.currentTarget as HTMLElement).style.color = '#EFBF04';
|
||||
(e.currentTarget as HTMLElement).style.borderBottomColor = '#EFBF04';
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
(e.currentTarget as HTMLElement).style.color = 'rgba(239,191,4,0.7)';
|
||||
(e.currentTarget as HTMLElement).style.borderBottomColor = 'rgba(239,191,4,0.3)';
|
||||
}}
|
||||
>
|
||||
{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 }} />
|
||||
</section>
|
||||
|
||||
|
||||
@@ -169,14 +169,6 @@ const Participation: React.FC = () => {
|
||||
>
|
||||
{fallbackText(eligibility.primaryCta?.label, participationContent.eligibility.primaryCta.label)} <ArrowRight size={13} />
|
||||
</Link>
|
||||
<Link
|
||||
to={fallbackText(eligibility.secondaryCta?.url, participationContent.eligibility.secondaryCta.url)}
|
||||
style={{ fontFamily: FF, fontSize: 16, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: NAVY, border: `1.5px solid rgba(3,9,58,0.3)`, padding: '10px 22px', textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: 8, transition: 'border-color 0.2s, color 0.2s', whiteSpace: 'nowrap' }}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.borderColor = NAVY; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.borderColor = 'rgba(3,9,58,0.3)'; }}
|
||||
>
|
||||
{fallbackText(eligibility.secondaryCta?.label, participationContent.eligibility.secondaryCta.label)}
|
||||
</Link>
|
||||
</div>
|
||||
<p style={{ fontFamily: FB, fontSize: 18, color: 'rgba(16,24,40,0.5)', lineHeight: 1.8, margin: 0, textAlign: isMobile ? 'left' : 'right' }}>
|
||||
{fallbackText(eligibility.description, participationContent.eligibility.description)}
|
||||
@@ -269,7 +261,7 @@ const Participation: React.FC = () => {
|
||||
</section>
|
||||
|
||||
{/* ── AWARDS GRID ─────────────────────────────────────────────────────── */}
|
||||
<AwardsGridSection content={awardsGrid} />
|
||||
<AwardsGridSection content={awardsGrid} featuredGoldeneBavaria />
|
||||
|
||||
{/* ── FORM SECTION ─────────────────────────────────────────────────────── */}
|
||||
<section style={{ background: NAVY, position: 'relative', overflow: 'hidden', height: isMobile ? 'auto' : showApplicationForm ? 'calc(100vh - 60px)' : 'auto', minHeight: isMobile ? undefined : showApplicationForm ? undefined : 560, display: 'flex', flexDirection: 'column' }} id="bewerben">
|
||||
|
||||
Reference in New Issue
Block a user