From 0516dbe74334aed3272b42f0cd3532e6607e8a3a Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Fri, 15 May 2026 11:03:01 +0200 Subject: [PATCH] feat: modernize digital presence, team layout, and hero component parity --- app/[locale]/[slug]/page.tsx | 2 + app/[locale]/contact/page.tsx | 16 +- app/[locale]/layout.tsx | 7 +- app/[locale]/team/opengraph-image.tsx | 25 -- app/[locale]/team/page.tsx | 326 ---------------------- components/blocks/CompanyTimeline.tsx | 2 +- components/blocks/CompetenceBentoGrid.tsx | 12 +- components/blocks/HeroSection.tsx | 20 +- components/blocks/HeroVideo.tsx | 20 +- components/blocks/ServiceDetailGrid.tsx | 4 +- components/blocks/TeamGrid.tsx | 151 +++++++--- components/layout/Footer.tsx | 13 + components/layout/Header.tsx | 128 ++++++--- content/de/bohrtechnik.mdx | 60 ++++ content/de/glasfaser.mdx | 60 ++++ content/de/home.mdx | 16 +- content/de/kabeltiefbau.mdx | 61 ++++ content/de/kompetenzen.mdx | 62 ++-- content/de/planung.mdx | 62 ++++ content/de/team.mdx | 89 ++++++ content/de/vermessung.mdx | 60 ++++ content/en/team.mdx | 89 ++++++ messages/de.json | 10 +- messages/en.json | 24 +- public/assets/photos/team/danny.jpg | Bin 0 -> 120024 bytes public/assets/photos/team/dirk.jpg | Bin 0 -> 307496 bytes public/assets/photos/team/kathrin.jpg | Bin 0 -> 105320 bytes public/assets/photos/team/kerstin.jpg | Bin 0 -> 101368 bytes public/assets/photos/team/maik.jpg | Bin 0 -> 66343 bytes public/assets/photos/team/martin.jpg | Bin 0 -> 64129 bytes public/assets/photos/team/oliver.jpg | Bin 0 -> 76817 bytes public/assets/photos/team/sven.jpg | Bin 0 -> 665444 bytes 32 files changed, 824 insertions(+), 495 deletions(-) delete mode 100644 app/[locale]/team/opengraph-image.tsx delete mode 100644 app/[locale]/team/page.tsx create mode 100644 content/de/bohrtechnik.mdx create mode 100644 content/de/glasfaser.mdx create mode 100644 content/de/kabeltiefbau.mdx create mode 100644 content/de/planung.mdx create mode 100644 content/de/team.mdx create mode 100644 content/de/vermessung.mdx create mode 100644 content/en/team.mdx create mode 100644 public/assets/photos/team/danny.jpg create mode 100644 public/assets/photos/team/dirk.jpg create mode 100644 public/assets/photos/team/kathrin.jpg create mode 100644 public/assets/photos/team/kerstin.jpg create mode 100644 public/assets/photos/team/maik.jpg create mode 100644 public/assets/photos/team/martin.jpg create mode 100644 public/assets/photos/team/oliver.jpg create mode 100644 public/assets/photos/team/sven.jpg diff --git a/app/[locale]/[slug]/page.tsx b/app/[locale]/[slug]/page.tsx index 97a180876..25decb21a 100644 --- a/app/[locale]/[slug]/page.tsx +++ b/app/[locale]/[slug]/page.tsx @@ -25,6 +25,7 @@ import { InteractiveGermanyMap } from '@/components/blocks/InteractiveGermanyMap import { FaqBlock } from '@/components/blocks/FaqBlock'; import { CertificatesBlock } from '@/components/blocks/CertificatesBlock'; import { HeroSection } from '@/components/blocks/HeroSection'; +import { TeamGrid } from '@/components/blocks/TeamGrid'; import JsonLd from '@/components/JsonLd'; import { Button } from '@/components/ui/Button'; @@ -43,6 +44,7 @@ const mdxComponents = { FaqBlock, CertificatesBlock, HeroSection, + TeamGrid, JsonLd, Button, // Standard HTML element mapping for consistent E-TIB typography diff --git a/app/[locale]/contact/page.tsx b/app/[locale]/contact/page.tsx index ef8942157..ecc9c21a4 100644 --- a/app/[locale]/contact/page.tsx +++ b/app/[locale]/contact/page.tsx @@ -120,7 +120,7 @@ export default async function ContactPage({ params }: ContactPageProps) { { '@type': 'OpeningHoursSpecification', dayOfWeek: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], - opens: '08:00', + opens: '07:00', closes: '17:00', }, ], @@ -214,6 +214,20 @@ export default async function ContactPage({ params }: ContactPageProps) { /> + +
+
+ +
+
+

+ {locale === 'de' ? 'Telefon' : 'Phone'} +

+ + +49 (0) 3561 / 68577 33 + +
+
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 88a11e49d..8b4ad9346 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -89,7 +89,12 @@ export default async function Layout(props: { }, { label: safeLocale === 'de' ? 'Über uns' : 'About Us', - url: `/${safeLocale}/${await mapFileSlugToTranslated('ueber-uns', safeLocale)}` + url: `/${safeLocale}/${await mapFileSlugToTranslated('ueber-uns', safeLocale)}`, + children: [ + { label: safeLocale === 'de' ? 'Firma' : 'Company', url: `/${safeLocale}/${await mapFileSlugToTranslated('ueber-uns', safeLocale)}` }, + { label: safeLocale === 'de' ? 'Unser Team' : 'Our Team', url: `/${safeLocale}/team` }, + { label: safeLocale === 'de' ? 'Zertifikate' : 'Certificates', url: `/${safeLocale}/zertifikate` } + ] }, { label: safeLocale === 'de' ? 'Referenzen' : 'References', diff --git a/app/[locale]/team/opengraph-image.tsx b/app/[locale]/team/opengraph-image.tsx deleted file mode 100644 index a08a23884..000000000 --- a/app/[locale]/team/opengraph-image.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ImageResponse } from 'next/og'; -import { getTranslations } from 'next-intl/server'; -import { OGImageTemplate } from '@/components/OGImageTemplate'; -import { getOgFonts, OG_IMAGE_SIZE } from '@/lib/og-helper'; - -export const size = OG_IMAGE_SIZE; -export const contentType = 'image/png'; -export const runtime = 'nodejs'; - -export default async function Image({ params }: { params: Promise<{ locale: string }> }) { - const { locale } = await params; - const t = await getTranslations({ locale, namespace: 'Team' }); - const fonts = await getOgFonts(); - - const title = t('meta.title') || t('hero.subtitle'); - const description = t('meta.description') || t('hero.title'); - - return new ImageResponse( - , - { - ...OG_IMAGE_SIZE, - fonts, - }, - ); -} diff --git a/app/[locale]/team/page.tsx b/app/[locale]/team/page.tsx deleted file mode 100644 index 53d7d2eca..000000000 --- a/app/[locale]/team/page.tsx +++ /dev/null @@ -1,326 +0,0 @@ -import { getTranslations, setRequestLocale } from 'next-intl/server'; -import { Metadata } from 'next'; -import JsonLd from '@/components/JsonLd'; -import { getBreadcrumbSchema, SITE_URL } from '@/lib/schema'; -import { Section, Container, Heading, Badge } from '@/components/ui'; -import Image from 'next/image'; -import Reveal from '@/components/Reveal'; -import Gallery from '@/components/team/Gallery'; -import TrackedButton from '@/components/analytics/TrackedButton'; - -interface TeamPageProps { - params: Promise<{ - locale: string; - }>; -} - -export async function generateMetadata({ params }: TeamPageProps): Promise { - const { locale } = await params; - const t = await getTranslations({ locale, namespace: 'Team' }); - const title = t('meta.title') || t('hero.subtitle'); - const description = t('meta.description') || t('hero.title'); - return { - title, - description, - alternates: { - canonical: `${SITE_URL}/${locale}/team`, - languages: { - de: `${SITE_URL}/de/team`, - en: `${SITE_URL}/en/team`, - 'x-default': `${SITE_URL}/en/team`, - }, - }, - openGraph: { - title: `${title} | E-TIB`, - description, - url: `${SITE_URL}/${locale}/team`, - }, - twitter: { - card: 'summary_large_image', - title: `${title} | E-TIB`, - description, - }, - }; -} - -export default async function TeamPage({ params }: TeamPageProps) { - const { locale } = await params; - setRequestLocale(locale); - const t = await getTranslations({ locale, namespace: 'Team' }); - - return ( -
- - - - {/* Hero Section */} - -
-
- E-TIB Team -
-
- - - - {t('hero.badge')} - - - {t('hero.subtitle')} - -

- {t('hero.title')} -

-
-
-
- - {/* Michael Bodemer Section - Sticky Narrative Split Layout */} -
-
- -
-
- - {t('michael.role')} - - - {t('michael.name')} - -
-
-

- {t('michael.quote')} -

-
-

- {t('michael.description')} -

- - {t('michael.linkedin')} - - -
- - - {t('michael.name')} -
- -
-
- - {/* Legacy Section - Immersive Background */} - -
-
- {t('legacy.subtitle')} -
-
- -
-
- - {t('legacy.title')} - -
-

- {t('legacy.p1')} -

-

{t('legacy.p2')}

-
-
-
-
-
- {t('legacy.expertise')} -
-
- {t('legacy.expertiseDesc')} -
-
-
-
- {t('legacy.network')} -
-
- {t('legacy.networkDesc')} -
-
-
-
-
-
-
- - {/* Klaus Mintel Section - Reversed Split Layout */} -
-
- - {t('klaus.name')} -
- - -
-
- - {t('klaus.role')} - - - {t('klaus.name')} - -
-
-

- {t('klaus.quote')} -

-
-

- {t('klaus.description')} -

- - {t('klaus.linkedin')} - - -
- -
-
- - {/* Manifesto Section - Modern Grid */} -
- -
-
-
- - {t('manifesto.title')} - -

- {t('manifesto.tagline')} -

- - {/* Mobile-only progress indicator */} -
- {[0, 1, 2, 3, 4, 5].map((i) => ( -
-
-
- ))} -
-
-
-
    - {[0, 1, 2, 3, 4, 5].map((idx) => ( -
  • -
    - - 0{idx + 1} - -
    -

    - {t(`manifesto.items.${idx}.title`)} -

    -

    - {t(`manifesto.items.${idx}.description`)} -

    -
  • - ))} -
-
- -
- - - - -
- ); -} diff --git a/components/blocks/CompanyTimeline.tsx b/components/blocks/CompanyTimeline.tsx index 5987346a6..106cc3ee8 100644 --- a/components/blocks/CompanyTimeline.tsx +++ b/components/blocks/CompanyTimeline.tsx @@ -21,7 +21,7 @@ const defaultMilestones = [ date: '16.12.2015', year: '2015', title: 'Gründung E-TIB GmbH', - desc: 'Ausführung elektrischer Infrastrukturprojekte, Kabelbau und Horizontalspülbohrungen.', + desc: 'Ausführung elektrischer Infrastrukturprojekte, Kabeltiefbau und Horizontalspülbohrungen.', iconName: 'Building2', }, { diff --git a/components/blocks/CompetenceBentoGrid.tsx b/components/blocks/CompetenceBentoGrid.tsx index acc9dcb3c..058060543 100644 --- a/components/blocks/CompetenceBentoGrid.tsx +++ b/components/blocks/CompetenceBentoGrid.tsx @@ -19,6 +19,7 @@ interface CompetenceBentoGridProps { title?: string; description?: string; tag?: string; + href?: string; image?: { url?: string; alt?: string; @@ -34,6 +35,7 @@ interface CompetenceBentoGridProps { title?: string; description?: string; tag?: string; + href?: string; image?: { url?: string; alt?: string; @@ -111,8 +113,11 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) { whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: idx * 0.1 }} - className={gridClasses} + className={`${gridClasses} ${item.href ? 'cursor-pointer hover:-translate-y-1 transition-transform duration-300' : ''}`} > + {item.href && ( + + )}
{/* Subtle Background Logo Arcs */} @@ -135,8 +140,11 @@ export function CompetenceBentoGrid(props: CompetenceBentoGridProps) { whileInView={{ opacity: 1, scale: 1 }} viewport={{ once: true }} transition={{ delay: idx * 0.1 }} - className={gridClasses} + className={`${gridClasses} ${item.href ? 'cursor-pointer hover:-translate-y-1 transition-transform duration-300' : ''}`} > + {item.href && ( + + )} {!imgSrc && (
)} diff --git a/components/blocks/HeroSection.tsx b/components/blocks/HeroSection.tsx index 76e0ae3e2..cf54c0063 100644 --- a/components/blocks/HeroSection.tsx +++ b/components/blocks/HeroSection.tsx @@ -42,7 +42,7 @@ export const HeroSection: React.FC = (props) => { return (
{bgSrc && ( = (props) => { src={bgSrc} alt={title || 'Hero Background'} fill - className="object-cover opacity-30 md:opacity-40" + className="object-cover filter contrast-110 saturate-110 brightness-95" style={{ objectPosition: `${backgroundImage?.focalX ?? 50}% ${backgroundImage?.focalY ?? 50}%`, }} sizes="100vw" priority /> -
+ {/* Cinematic Color Grading Overlay */} +
+ + {/* Dramatic Vignette & Fade to content */} +
+
+ + {/* Top Fade for Header Navigation Readability */} +
)} @@ -80,19 +88,19 @@ export const HeroSection: React.FC = (props) => { )} - + {title} {subtitle && ( -

+

{subtitle}

)} {ctaLabel && ctaHref && ( - +