- Created a new collection `JuryMitglieder` with fields for name, image, quote, role, organization, bio, website, LinkedIn, sort order, active status, and published date. - Implemented access control for creating, reading, updating, and deleting jury members. - Added migration script to create necessary database tables and columns for jury members, including versioning support. - Updated existing `preistraeger` table to include new columns for award group, winner rank, sort order, and visibility settings. - Introduced a temporary global switch to control the visibility of testimonials in the SPA.
392 lines
21 KiB
TypeScript
392 lines
21 KiB
TypeScript
import React from 'react';
|
||
import { Link, useParams, Navigate } from '@/spa/router';
|
||
import { Trophy, ArrowLeft, MapPin, Building2, Globe, ChevronRight, Download, ChevronLeft, X } from 'lucide-react';
|
||
import { WINNERS } from '@/spa/data/winners';
|
||
import { useCmsRoute } from '@/spa/cmsRoute';
|
||
import { docImageUrl, mediaAlt, mediaUrl } from '@/spa/cmsMediaField';
|
||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||
import { preistraegerDetailContent } from '@/spa/preistraegerDetailContent';
|
||
import { usePreistraegerPlaceholderImage } from '@/spa/preistraegerPlaceholder';
|
||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||
|
||
const FF = '"IBM Plex Sans", sans-serif';
|
||
const FB = '"Inter", sans-serif';
|
||
const NAVY = '#111D55';
|
||
const GOLD = '#EFBF04';
|
||
const BORDER = '#D0D5DD';
|
||
const GRAY = '#666666';
|
||
const BG_ALT = '#E4E2E3';
|
||
|
||
type PreistraegerDetailCms = Partial<typeof preistraegerDetailContent> & {
|
||
fallbackImage?: unknown
|
||
sideImage?: Partial<typeof preistraegerDetailContent.sideImage> & { image?: unknown }
|
||
}
|
||
|
||
type GalleryImageCms = {
|
||
id?: string | null
|
||
image?: unknown
|
||
imageAlt?: string | null
|
||
caption?: string | null
|
||
}
|
||
|
||
type PreistraegerGalleryCms = {
|
||
enabled?: boolean | null
|
||
heading?: string | null
|
||
description?: string | null
|
||
images?: GalleryImageCms[] | null
|
||
}
|
||
|
||
const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback;
|
||
|
||
const mediaFilename = (media: unknown) => {
|
||
if (!media || typeof media !== 'object') return undefined;
|
||
const filename = (media as { filename?: unknown }).filename;
|
||
return typeof filename === 'string' && filename.length > 0 ? filename : undefined;
|
||
};
|
||
|
||
export default function PreistraegerDetail() {
|
||
const { slug } = useParams<{ slug: string }>();
|
||
const route = useCmsRoute();
|
||
const placeholderImage = usePreistraegerPlaceholderImage();
|
||
const cmsWinner = route?.collection === 'preistraeger' ? route.doc : undefined;
|
||
const cmsDetail = {
|
||
...preistraegerDetailContent,
|
||
...((cmsWinner?.detailPage || {}) as PreistraegerDetailCms),
|
||
} as PreistraegerDetailCms;
|
||
const fallbackWinner = cmsDetail.fallbackWinner || preistraegerDetailContent.fallbackWinner;
|
||
const cmsWinnerIsGoldeneBavaria = cmsWinner?.awardGroup === 'goldene-bavaria';
|
||
const winner = cmsWinner ? {
|
||
id: String(cmsWinner.id),
|
||
slug: String(cmsWinner.slug || slug),
|
||
name: String(cmsWinner.title || fallbackWinner.name || preistraegerDetailContent.fallbackWinner.name),
|
||
category: String(cmsWinner.category || fallbackWinner.category || preistraegerDetailContent.fallbackWinner.category),
|
||
year: Number(cmsWinner.year || new Date().getFullYear()),
|
||
type: String(cmsWinner.awardType || (cmsWinnerIsGoldeneBavaria ? 'Goldene Bavaria' : fallbackWinner.awardType) || preistraegerDetailContent.fallbackWinner.awardType),
|
||
img: docImageUrl(cmsWinner, placeholderImage),
|
||
shortDesc: String(cmsWinner.shortDesc || cmsWinner.description || cmsWinner.meta?.description || ''),
|
||
longDesc: String(cmsWinner.longDesc || cmsWinner.description || cmsWinner.meta?.description || fallbackWinner.longDesc || preistraegerDetailContent.fallbackWinner.longDesc),
|
||
quote: String(cmsWinner.quote || fallbackWinner.quote || preistraegerDetailContent.fallbackWinner.quote),
|
||
quotePerson: String(cmsWinner.quotePerson || cmsWinner.title || fallbackWinner.quotePerson || preistraegerDetailContent.fallbackWinner.quotePerson),
|
||
quoteRole: String(cmsWinner.quoteRole || fallbackWinner.quoteRole || preistraegerDetailContent.fallbackWinner.quoteRole),
|
||
location: String(cmsWinner.location || fallbackWinner.location || preistraegerDetailContent.fallbackWinner.location),
|
||
industry: String(cmsWinner.industry || fallbackWinner.industry || preistraegerDetailContent.fallbackWinner.industry),
|
||
website: String(cmsWinner.website || '#'),
|
||
hasMedia: Boolean(cmsWinner.hasMedia),
|
||
detailPage: (cmsWinner.detailPage || {}) as PreistraegerDetailCms,
|
||
} : WINNERS.find(w => w.slug === slug);
|
||
const isMobile = useIsMobile();
|
||
|
||
const detail = (winner && 'detailPage' in winner ? { ...preistraegerDetailContent, ...(winner.detailPage || {}) } : cmsDetail) as PreistraegerDetailCms;
|
||
const breadcrumb = { ...preistraegerDetailContent.breadcrumb, ...(detail.breadcrumb || {}) };
|
||
const sections = { ...preistraegerDetailContent.sections, ...(detail.sections || {}) };
|
||
const sideImage = { ...preistraegerDetailContent.sideImage, ...(detail.sideImage || {}) };
|
||
const facts = { ...preistraegerDetailContent.facts, ...(detail.facts || {}) };
|
||
const websiteCta = { ...preistraegerDetailContent.websiteCta, ...(detail.websiteCta || {}) };
|
||
const backLink = { ...preistraegerDetailContent.backLink, ...(detail.backLink || {}) };
|
||
const downloadHref = mediaUrl(cmsWinner?.downloadZip, '');
|
||
const downloadFilename = mediaFilename(cmsWinner?.downloadZip);
|
||
const downloadLabel = fallbackText(cmsWinner?.downloadLabel, 'Pressepaket herunterladen');
|
||
const gallery = (cmsWinner?.gallery || {}) as PreistraegerGalleryCms;
|
||
const galleryImages = Array.isArray(gallery.images)
|
||
? gallery.images
|
||
.map((item) => ({
|
||
id: item.id || mediaFilename(item.image) || String(mediaUrl(item.image, '')),
|
||
src: mediaUrl(item.image, ''),
|
||
alt: mediaAlt(item.image, fallbackText(item.imageAlt, fallbackText(item.caption, winner?.name || 'Galeriebild'))),
|
||
caption: fallbackText(item.caption, ''),
|
||
}))
|
||
.filter((item) => item.src)
|
||
: [];
|
||
const [activeGalleryIndex, setActiveGalleryIndex] = React.useState<number | undefined>(undefined);
|
||
const activeGalleryImage = typeof activeGalleryIndex === 'number' ? galleryImages[activeGalleryIndex] : undefined;
|
||
const showGallery = Boolean(gallery.enabled) && galleryImages.length > 0;
|
||
|
||
if (!winner) return <Navigate to={preistraegerDetailContent.notFoundRedirect} replace />;
|
||
|
||
return (
|
||
<div style={{ background: '#fff', minHeight: '100vh' }}>
|
||
{/* Hero */}
|
||
<div style={{ width: '100%', height: '60vh', overflow: 'hidden', position: 'relative' }}>
|
||
<Image unoptimized
|
||
src={winner.img}
|
||
alt={winner.name}
|
||
style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
|
||
/>
|
||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to bottom, transparent 50%, rgba(3,9,58,0.82) 100%)' }} />
|
||
</div>
|
||
|
||
{/* Breadcrumb */}
|
||
<div style={{ background: '#fff', borderBottom: `1px solid ${BORDER}`, padding: isMobile ? '16px 24px' : '16px 80px', display: 'flex', alignItems: 'center', gap: 8 }}>
|
||
<Link to={fallbackText(breadcrumb.url, preistraegerDetailContent.breadcrumb.url)} style={{ fontFamily: FF, fontSize: 16, color: GOLD, textDecoration: 'none', fontWeight: 600 }}>
|
||
{fallbackText(breadcrumb.label, preistraegerDetailContent.breadcrumb.label)}
|
||
</Link>
|
||
<ChevronRight size={14} style={{ color: GRAY }} />
|
||
<span style={{ fontFamily: FF, fontSize: 16, color: GRAY }}>{winner.name}</span>
|
||
</div>
|
||
|
||
{/* Header block */}
|
||
<div style={{ padding: isMobile ? '32px 24px 28px' : '48px 80px 40px', borderBottom: `1px solid ${BORDER}` }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 16, flexWrap: 'wrap' }}>
|
||
<span style={{
|
||
fontFamily: FF, fontSize: 11, fontWeight: 700, color: '#fff',
|
||
background: NAVY, padding: '4px 14px', borderRadius: 999,
|
||
textTransform: 'uppercase', letterSpacing: '0.1em',
|
||
}}>
|
||
{winner.category}
|
||
</span>
|
||
<span style={{ fontFamily: FF, fontSize: 15, fontWeight: 700, color: GOLD }}>
|
||
{winner.year}
|
||
</span>
|
||
<span style={{ fontFamily: FF, fontSize: 15, color: GRAY, textTransform: 'uppercase', letterSpacing: '0.08em' }}>
|
||
{winner.type}
|
||
</span>
|
||
</div>
|
||
<h1 style={{ fontFamily: FF, fontSize: isMobile ? 'clamp(1.6rem, 5vw, 3rem)' : 'clamp(2rem, 5vw, 3rem)', fontWeight: 900, color: '#101828', textTransform: 'uppercase', letterSpacing: '-0.02em', margin: '0 0 12px' }}>
|
||
{winner.name}
|
||
</h1>
|
||
<p style={{ fontFamily: FB, fontSize: 18, color: GRAY, margin: 0, maxWidth: 640, lineHeight: 1.6 }}>
|
||
{winner.shortDesc}
|
||
</p>
|
||
</div>
|
||
|
||
{/* Content 2-col */}
|
||
<div style={{ padding: isMobile ? '48px 24px' : '64px 80px', display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '55% 1fr', gap: isMobile ? 40 : 64 }}>
|
||
{/* Left: Text */}
|
||
<div>
|
||
<h2 style={{ fontFamily: FF, fontSize: 18, fontWeight: 800, color: '#101828', textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 20 }}>
|
||
{fallbackText(sections.companyHeading, preistraegerDetailContent.sections.companyHeading)}
|
||
</h2>
|
||
<p style={{ fontFamily: FB, fontSize: 18, color: '#333', lineHeight: 1.8, marginBottom: 40 }}>
|
||
{winner.longDesc}
|
||
</p>
|
||
|
||
<h2 style={{ fontFamily: FF, fontSize: 18, fontWeight: 800, color: '#101828', textTransform: 'uppercase', letterSpacing: '0.04em', marginBottom: 20 }}>
|
||
{fallbackText(sections.juryHeading, preistraegerDetailContent.sections.juryHeading)}
|
||
</h2>
|
||
<p style={{ fontFamily: FB, fontSize: 18, color: '#333', lineHeight: 1.8, marginBottom: 40 }}>
|
||
{fallbackText(sections.juryTextBeforeName, preistraegerDetailContent.sections.juryTextBeforeName)} {winner.name} {fallbackText(sections.juryTextAfterNameBeforeCategory, preistraegerDetailContent.sections.juryTextAfterNameBeforeCategory)} <strong>{winner.category}</strong>. {fallbackText(sections.juryTextAfterCategory, preistraegerDetailContent.sections.juryTextAfterCategory)}
|
||
</p>
|
||
|
||
{/* Quote */}
|
||
<div style={{ borderLeft: `4px solid ${GOLD}`, paddingLeft: 24, marginBottom: 40 }}>
|
||
<p style={{ fontFamily: FB, fontStyle: 'italic', fontSize: 18, color: '#101828', lineHeight: 1.7, marginBottom: 12 }}>
|
||
<span style={{ color: GOLD, fontSize: 28, lineHeight: 1, marginRight: 4, fontFamily: '"IBM Plex Sans"' }}>“</span>
|
||
{winner.quote}
|
||
<span style={{ color: GOLD, fontSize: 28, lineHeight: 1, marginLeft: 2, fontFamily: '"IBM Plex Sans"' }}>”</span>
|
||
</p>
|
||
<p style={{ fontFamily: FF, fontSize: 16, fontWeight: 700, color: GRAY, margin: 0, textTransform: 'uppercase', letterSpacing: '0.08em' }}>
|
||
– {winner.quotePerson}, {winner.quoteRole}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Right: Photo + Info box */}
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
|
||
{/* Photo */}
|
||
<div style={{ borderRadius: 0, overflow: 'hidden', aspectRatio: '4/3' }}>
|
||
<Image unoptimized src={mediaUrl(sideImage.image, `/${preistraegerDetailContent.sideImage.imageFilename}`)} alt={mediaAlt(sideImage.image, fallbackText(sideImage.imageAlt, preistraegerDetailContent.sideImage.imageAlt))} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', filter: 'brightness(0.95)' }} />
|
||
</div>
|
||
|
||
{/* Kenndaten */}
|
||
<div style={{ background: BG_ALT, borderLeft: `3px solid ${GOLD}`, padding: '20px 24px' }}>
|
||
<h3 style={{ fontFamily: FF, fontSize: 15, fontWeight: 700, color: GRAY, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 20 }}>
|
||
{fallbackText(facts.heading, preistraegerDetailContent.facts.heading)}
|
||
</h3>
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||
{[
|
||
{ label: fallbackText(facts.categoryLabel, preistraegerDetailContent.facts.categoryLabel), value: winner.category, icon: <Trophy size={14} style={{ color: GOLD }} /> },
|
||
{ label: fallbackText(facts.awardLabel, preistraegerDetailContent.facts.awardLabel), value: winner.type, icon: <Trophy size={14} style={{ color: GOLD }} /> },
|
||
{ label: fallbackText(facts.yearLabel, preistraegerDetailContent.facts.yearLabel), value: String(winner.year), icon: null },
|
||
{ label: fallbackText(facts.locationLabel, preistraegerDetailContent.facts.locationLabel), value: winner.location, icon: <MapPin size={14} style={{ color: GOLD }} /> },
|
||
{ label: fallbackText(facts.industryLabel, preistraegerDetailContent.facts.industryLabel), value: winner.industry, icon: <Building2 size={14} style={{ color: GOLD }} /> },
|
||
].map(row => (
|
||
<div key={row.label} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||
<span style={{ fontFamily: FF, fontSize: 11, color: GRAY, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{row.label}</span>
|
||
<span style={{ fontFamily: FF, fontSize: 17, fontWeight: 700, color: '#101828', overflowWrap: 'anywhere' }}>{row.value}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Website button */}
|
||
<a
|
||
href={`https://${winner.website}`}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
style={{
|
||
display: 'inline-flex', alignItems: 'center', gap: 8,
|
||
fontFamily: FF, fontSize: 16, fontWeight: 700,
|
||
color: '#101828', border: `2px solid ${NAVY}`,
|
||
padding: '12px 20px', textDecoration: 'none',
|
||
textTransform: 'uppercase', letterSpacing: '0.08em',
|
||
transition: 'all 0.2s', borderRadius: 0, overflowWrap: 'anywhere',
|
||
}}
|
||
onMouseEnter={e => { const el = e.currentTarget as HTMLElement; el.style.background = NAVY; el.style.color = '#fff'; }}
|
||
onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = NAVY; }}
|
||
>
|
||
<Globe size={16} /> {fallbackText(websiteCta.label, preistraegerDetailContent.websiteCta.label)}
|
||
</a>
|
||
|
||
{downloadHref ? (
|
||
<a
|
||
href={downloadHref}
|
||
download={downloadFilename}
|
||
style={{
|
||
display: 'inline-flex', alignItems: 'center', gap: 8,
|
||
fontFamily: FF, fontSize: 16, fontWeight: 700,
|
||
color: '#101828', border: `2px solid ${GOLD}`,
|
||
padding: '12px 20px', textDecoration: 'none',
|
||
textTransform: 'uppercase', letterSpacing: '0.08em',
|
||
transition: 'all 0.2s', borderRadius: 0, overflowWrap: 'anywhere',
|
||
}}
|
||
onMouseEnter={e => { const el = e.currentTarget as HTMLElement; el.style.background = GOLD; el.style.color = '#101828'; }}
|
||
onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = NAVY; }}
|
||
>
|
||
<Download size={16} /> {downloadLabel}
|
||
</a>
|
||
) : null}
|
||
</div>
|
||
</div>
|
||
|
||
{showGallery ? (
|
||
<section style={{ borderTop: `1px solid ${BORDER}`, background: '#fff' }}>
|
||
<div style={{ padding: isMobile ? '48px 24px' : '64px 80px' }}>
|
||
<div style={{ marginBottom: 28, maxWidth: 760 }}>
|
||
<h2 style={{ fontFamily: FF, fontSize: isMobile ? 26 : 34, fontWeight: 900, color: '#101828', textTransform: 'uppercase', letterSpacing: '0.02em', margin: '0 0 12px' }}>
|
||
{fallbackText(gallery.heading, 'Bildergalerie')}
|
||
</h2>
|
||
{gallery.description ? (
|
||
<p style={{ fontFamily: FB, fontSize: 17, color: GRAY, lineHeight: 1.7, margin: 0 }}>
|
||
{gallery.description}
|
||
</p>
|
||
) : null}
|
||
</div>
|
||
|
||
<div
|
||
style={{
|
||
display: 'grid',
|
||
gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, minmax(0, 1fr))',
|
||
gap: isMobile ? 14 : 18,
|
||
}}
|
||
>
|
||
{galleryImages.map((image, index) => (
|
||
<button
|
||
key={image.id || `${image.src}-${index}`}
|
||
type="button"
|
||
onClick={() => setActiveGalleryIndex(index)}
|
||
aria-label={`${image.alt} öffnen`}
|
||
style={{
|
||
appearance: 'none',
|
||
border: `1px solid ${BORDER}`,
|
||
background: '#fff',
|
||
padding: 0,
|
||
cursor: 'pointer',
|
||
textAlign: 'left',
|
||
overflow: 'hidden',
|
||
}}
|
||
>
|
||
<span style={{ display: 'block', aspectRatio: '4/3', background: BG_ALT, overflow: 'hidden' }}>
|
||
<Image
|
||
unoptimized
|
||
src={image.src}
|
||
alt={image.alt}
|
||
style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
|
||
/>
|
||
</span>
|
||
{image.caption ? (
|
||
<span style={{ display: 'block', fontFamily: FB, fontSize: 15, lineHeight: 1.5, color: '#333', padding: '12px 14px', overflowWrap: 'anywhere' }}>
|
||
{image.caption}
|
||
</span>
|
||
) : null}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
) : null}
|
||
|
||
{activeGalleryImage ? (
|
||
<div
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-label={activeGalleryImage.alt}
|
||
onClick={() => setActiveGalleryIndex(undefined)}
|
||
style={{
|
||
position: 'fixed',
|
||
inset: 0,
|
||
zIndex: 1000,
|
||
background: 'rgba(3,9,58,0.92)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: isMobile ? 18 : 40,
|
||
}}
|
||
>
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveGalleryIndex(undefined)}
|
||
aria-label="Galerie schließen"
|
||
style={{ position: 'absolute', top: 18, right: 18, width: 44, height: 44, border: `1px solid rgba(255,255,255,0.28)`, background: 'rgba(255,255,255,0.08)', color: '#fff', display: 'grid', placeItems: 'center', cursor: 'pointer' }}
|
||
>
|
||
<X size={22} />
|
||
</button>
|
||
|
||
{galleryImages.length > 1 ? (
|
||
<button
|
||
type="button"
|
||
onClick={(event) => {
|
||
event.stopPropagation();
|
||
setActiveGalleryIndex((activeGalleryIndex ?? 0) === 0 ? galleryImages.length - 1 : (activeGalleryIndex ?? 0) - 1);
|
||
}}
|
||
aria-label="Vorheriges Bild"
|
||
style={{ position: 'absolute', left: isMobile ? 12 : 24, top: '50%', transform: 'translateY(-50%)', width: 44, height: 44, border: `1px solid rgba(255,255,255,0.28)`, background: 'rgba(255,255,255,0.08)', color: '#fff', display: 'grid', placeItems: 'center', cursor: 'pointer' }}
|
||
>
|
||
<ChevronLeft size={24} />
|
||
</button>
|
||
) : null}
|
||
|
||
<div onClick={(event) => event.stopPropagation()} style={{ maxWidth: 'min(1120px, 100%)', maxHeight: '86vh', display: 'flex', flexDirection: 'column', gap: 14 }}>
|
||
<Image
|
||
unoptimized
|
||
src={activeGalleryImage.src}
|
||
alt={activeGalleryImage.alt}
|
||
style={{ maxWidth: '100%', maxHeight: activeGalleryImage.caption ? '76vh' : '84vh', objectFit: 'contain', display: 'block' }}
|
||
/>
|
||
{activeGalleryImage.caption ? (
|
||
<p style={{ fontFamily: FB, fontSize: 16, lineHeight: 1.6, color: '#fff', margin: 0, textAlign: 'center', overflowWrap: 'anywhere' }}>
|
||
{activeGalleryImage.caption}
|
||
</p>
|
||
) : null}
|
||
</div>
|
||
|
||
{galleryImages.length > 1 ? (
|
||
<button
|
||
type="button"
|
||
onClick={(event) => {
|
||
event.stopPropagation();
|
||
setActiveGalleryIndex((activeGalleryIndex ?? 0) === galleryImages.length - 1 ? 0 : (activeGalleryIndex ?? 0) + 1);
|
||
}}
|
||
aria-label="Nächstes Bild"
|
||
style={{ position: 'absolute', right: isMobile ? 12 : 24, top: '50%', transform: 'translateY(-50%)', width: 44, height: 44, border: `1px solid rgba(255,255,255,0.28)`, background: 'rgba(255,255,255,0.08)', color: '#fff', display: 'grid', placeItems: 'center', cursor: 'pointer' }}
|
||
>
|
||
<ChevronRight size={24} />
|
||
</button>
|
||
) : null}
|
||
</div>
|
||
) : null}
|
||
|
||
{/* Back link */}
|
||
<div style={{ padding: isMobile ? '32px 24px 48px' : '32px 80px 64px', borderTop: `1px solid ${BORDER}` }}>
|
||
<Link
|
||
to={fallbackText(backLink.url, preistraegerDetailContent.backLink.url)}
|
||
style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontFamily: FF, fontSize: 17, fontWeight: 700, color: '#101828', textDecoration: 'none', textTransform: 'uppercase', letterSpacing: '0.06em', transition: 'color 0.15s' }}
|
||
onMouseEnter={e => ((e.currentTarget as HTMLElement).style.color = GOLD)}
|
||
onMouseLeave={e => ((e.currentTarget as HTMLElement).style.color = NAVY)}
|
||
>
|
||
<ArrowLeft size={16} /> {fallbackText(backLink.label, preistraegerDetailContent.backLink.label)}
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|