All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 31s
Build & Deploy / 🧪 QA (push) Successful in 1m31s
Build & Deploy / 🏗️ Build (push) Successful in 2m54s
Build & Deploy / 🚀 Deploy (push) Successful in 36s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m0s
Build & Deploy / 🔔 Notify (push) Successful in 3s
143 lines
7.1 KiB
TypeScript
143 lines
7.1 KiB
TypeScript
import { Container } from '@/components/ui';
|
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
|
import { Metadata } from 'next';
|
|
import TrackedLink from '@/components/analytics/TrackedLink';
|
|
import { MapPin, Navigation, ArrowUpRight } from 'lucide-react';
|
|
import { getButtonClasses, ButtonOverlay } from '@/components/ui/Button';
|
|
import { SITE_URL } from '@/lib/schema';
|
|
import Image from 'next/image';
|
|
import { standorteData, standorteLocations } from '@/lib/standorte-data';
|
|
import { InteractiveGermanyMap } from '@/components/blocks/InteractiveGermanyMap';
|
|
|
|
interface PageProps {
|
|
params: Promise<{
|
|
locale: string;
|
|
}>;
|
|
}
|
|
|
|
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
|
|
const { locale } = await params;
|
|
const safeLocale = locale === 'de' ? 'de' : 'en';
|
|
|
|
return {
|
|
title: safeLocale === 'en' ? 'Our Locations' : 'Unsere Standorte',
|
|
description: safeLocale === 'en' ? 'Our operational locations across Germany.' : 'Unsere operativen Standorte deutschlandweit.',
|
|
alternates: {
|
|
canonical: `${SITE_URL}/${safeLocale}/standorte`,
|
|
languages: {
|
|
de: `${SITE_URL}/de/standorte`,
|
|
en: `${SITE_URL}/en/standorte`,
|
|
'x-default': `${SITE_URL}/en/standorte`,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
export default async function StandorteOverview(props: { params: Promise<{ locale: string }> }) {
|
|
const { locale } = await props.params;
|
|
const safeLocale = locale === 'de' ? 'de' : 'en';
|
|
setRequestLocale(safeLocale);
|
|
const t = await getTranslations('StandardPage');
|
|
|
|
return (
|
|
<div className="flex flex-col min-h-screen bg-neutral-50 pb-16 md:pb-24">
|
|
{/* Map Hero Section */}
|
|
<InteractiveGermanyMap
|
|
isHero={true}
|
|
locations={standorteLocations}
|
|
badge={safeLocale === 'en' ? 'Our Locations' : 'Unsere Standorte'}
|
|
title={safeLocale === 'en' ? 'Nationwide operational for you.' : 'Deutschlandweit für Sie im Einsatz.'}
|
|
description={safeLocale === 'en'
|
|
? 'From our strategic locations in Guben, Kirchheilingen and Bülstedt, we control and implement complex infrastructure projects nationwide.'
|
|
: 'Von unseren strategischen Standorten in Guben, Kirchheilingen und Bülstedt steuern und realisieren wir komplexe Infrastrukturprojekte im gesamten Bundesgebiet.'}
|
|
/>
|
|
|
|
{/* Main Content Area */}
|
|
<Container className="relative z-20 mt-16 md:mt-24">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
|
|
{standorteData.map((standort) => (
|
|
<TrackedLink
|
|
key={standort.id}
|
|
href={`/${safeLocale}/standorte/${standort.id}`}
|
|
eventProperties={{ location: 'standorte_list_card', slug: standort.id }}
|
|
className="group flex flex-col bg-white border border-neutral-100 rounded-3xl overflow-hidden shadow-sm hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-1 cursor-pointer block"
|
|
>
|
|
<div className="flex flex-col h-full relative">
|
|
{/* Image Section */}
|
|
<div className="relative h-64 w-full bg-[#050B14] overflow-hidden shrink-0 border-b border-neutral-100">
|
|
<Image
|
|
src={standort.image}
|
|
alt={standort.name}
|
|
fill
|
|
className="object-cover transition-transform duration-1000 ease-[cubic-bezier(0.16,1,0.3,1)] filter grayscale-[20%] group-hover:scale-105 group-hover:grayscale-0"
|
|
/>
|
|
<div className="absolute inset-0 bg-black/10 transition-colors duration-500" />
|
|
|
|
{/* Location Badge */}
|
|
<div className="absolute top-4 left-4 z-10">
|
|
<span className="bg-white/95 backdrop-blur-md text-neutral-dark px-3 py-1.5 rounded-sm text-[10px] font-bold uppercase tracking-widest flex items-center gap-1.5 shadow-sm border border-neutral-200">
|
|
<MapPin className="w-3 h-3 text-primary" />
|
|
{standort.address.city}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content Section */}
|
|
<div className="flex flex-col flex-grow p-6 md:p-8 bg-white">
|
|
<div className="flex items-start justify-between gap-4 mb-4">
|
|
<h3 className="text-xl md:text-2xl font-bold font-heading text-neutral-dark transition-colors leading-[1.2] group-hover:text-primary">
|
|
{standort.name}
|
|
</h3>
|
|
<ArrowUpRight className="w-5 h-5 text-neutral-400 group-hover:text-primary transition-colors shrink-0" />
|
|
</div>
|
|
|
|
<p className="text-neutral-500 text-sm leading-relaxed mb-8 line-clamp-3">
|
|
{standort.description[safeLocale]}
|
|
</p>
|
|
|
|
{/* Meta Data */}
|
|
<div className="flex flex-col gap-3 mt-auto border-t border-neutral-100 pt-6 relative z-10">
|
|
<div className="min-w-0">
|
|
<span className="block text-[10px] uppercase tracking-widest text-neutral-400 font-bold mb-1">
|
|
{safeLocale === 'de' ? 'Adresse' : 'Address'}
|
|
</span>
|
|
<span className="flex items-start gap-2 text-sm font-semibold text-neutral-700 leading-tight">
|
|
<Navigation className="w-3.5 h-3.5 text-primary shrink-0 mt-[2px]" />
|
|
<span className="line-clamp-2">{standort.address.street}, {standort.address.city}</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TrackedLink>
|
|
))}
|
|
</div>
|
|
|
|
{/* Support Section */}
|
|
<div className="mt-12 md:mt-24 p-8 md:p-12 bg-primary-dark rounded-3xl text-white shadow-2xl relative overflow-hidden group">
|
|
<div className="absolute top-0 right-0 w-64 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform group-hover:translate-x-1/3" />
|
|
<div className="relative z-10 max-w-2xl">
|
|
<h3 className="text-2xl md:text-3xl font-bold mb-4">{t('nextProjectTitle')}</h3>
|
|
<p className="text-lg text-white/70 mb-8">{t('nextProjectDesc')}</p>
|
|
<TrackedLink
|
|
href={`/${safeLocale}/${safeLocale === 'de' ? 'kontakt' : 'contact'}`}
|
|
className={getButtonClasses('accent', 'lg')}
|
|
eventProperties={{
|
|
location: 'standorte_support_cta',
|
|
}}
|
|
>
|
|
<span className="relative z-10 flex items-center justify-center gap-2 transition-colors duration-500 group-hover/btn:text-primary-dark">
|
|
{t('contactUs')}
|
|
<span className="ml-2 transition-transform group-hover/btn:translate-x-1">
|
|
→
|
|
</span>
|
|
</span>
|
|
<ButtonOverlay variant="accent" />
|
|
</TrackedLink>
|
|
</div>
|
|
</div>
|
|
</Container>
|
|
</div>
|
|
);
|
|
}
|