fix(ui): remove hero video image wrapper and fix carousel edge sticking padding
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 1m24s
Build & Deploy / 🧪 QA (push) Successful in 1m45s
Build & Deploy / 🏗️ Build (push) Successful in 3m11s
Build & Deploy / 🚀 Deploy (push) Successful in 38s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m8s
Build & Deploy / 🔔 Notify (push) Successful in 2s

This commit is contained in:
2026-06-21 20:24:51 +02:00
parent 1b6f1d9405
commit b60e7c2aea
2 changed files with 23 additions and 16 deletions

View File

@@ -4,6 +4,7 @@ import { Button } from '@/components/ui/Button';
import Image from 'next/image'; import Image from 'next/image';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { preload } from 'react-dom';
interface HeroVideoProps { interface HeroVideoProps {
data?: any; data?: any;
@@ -41,6 +42,10 @@ export function HeroVideo(props: HeroVideoProps) {
const secondaryCtaLabel = props.secondaryCtaLabel || data?.secondaryCtaLabel || (currentLocale === 'de' ? 'Projekt anfragen' : 'Inquire Project'); const secondaryCtaLabel = props.secondaryCtaLabel || data?.secondaryCtaLabel || (currentLocale === 'de' ? 'Projekt anfragen' : 'Inquire Project');
const secondaryCtaHref = props.secondaryCtaHref || data?.secondaryCtaHref || `/${currentLocale}/contact`; const secondaryCtaHref = props.secondaryCtaHref || data?.secondaryCtaHref || `/${currentLocale}/contact`;
if (posterSrc) {
preload(posterSrc, { as: 'image' });
}
const [videoSrcLoaded, setVideoSrcLoaded] = useState(false); const [videoSrcLoaded, setVideoSrcLoaded] = useState(false);
useEffect(() => { useEffect(() => {
let interactionTriggered = false; let interactionTriggered = false;
@@ -73,28 +78,30 @@ export function HeroVideo(props: HeroVideoProps) {
{/* Background color while video loads */} {/* Background color while video loads */}
<div className="absolute inset-0 z-0 bg-neutral-dark" /> <div className="absolute inset-0 z-0 bg-neutral-dark" />
{/* ALWAYS render the Next.js optimized Image as the LCP element */} {/* Dramatic Vignette & Fade to content */}
<Image <div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_var(--tw-gradient-stops))] from-transparent via-black/20 to-black/80 z-[2]" />
key={`img-${pathname}-${posterSrc}`} <div className="absolute inset-0 bg-gradient-to-t from-neutral-dark via-neutral-dark/60 to-transparent z-[3]" />
src={posterSrc}
alt={posterAlt}
fill
className="object-cover z-[1] pointer-events-none filter contrast-125 saturate-110 brightness-90"
sizes="100vw"
priority
/>
{/* Render video on top if available, but defer src to avoid blocking LCP */} {/* Top Fade for Header Navigation Readability */}
{videoUrl && ( <div className="absolute top-0 left-0 w-full h-48 bg-gradient-to-b from-black/70 to-transparent z-[3] pointer-events-none" />
{videoUrl ? (
<video <video
key={`${pathname}-${videoUrl}`} key={`${pathname}-${videoUrl}`}
className="absolute inset-0 w-full h-full object-cover z-[2] pointer-events-none filter contrast-125 saturate-110 brightness-90" className="absolute inset-0 w-full h-full object-cover z-[1] pointer-events-none filter contrast-125 saturate-110 brightness-90"
src={videoSrcLoaded ? videoUrl : undefined} src={videoUrl}
poster={posterSrc}
autoPlay autoPlay
muted muted
loop loop
playsInline playsInline
preload="none" preload="auto"
/>
) : (
<div
key={`img-${pathname}-${posterSrc}`}
className="absolute inset-0 w-full h-full object-cover z-[1] pointer-events-none filter contrast-125 saturate-110 brightness-90"
style={{ backgroundImage: `url(${posterSrc})`, backgroundSize: 'cover', backgroundPosition: 'center' }}
/> />
)} )}

View File

@@ -115,7 +115,7 @@ export function ReferencesSlider(props: ReferencesSliderProps) {
onMouseLeave={onMouseLeave} onMouseLeave={onMouseLeave}
onMouseUp={onMouseUp} onMouseUp={onMouseUp}
onMouseMove={onMouseMove} onMouseMove={onMouseMove}
className={`select-none flex gap-6 overflow-x-auto pb-8 pt-4 px-6 md:px-[max(2rem,calc((100vw-1280px)/2))] lg:px-[max(2.5rem,calc((100vw-1280px)/2))] [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden ${isDragging ? 'cursor-grabbing snap-none' : 'cursor-grab snap-x snap-mandatory'}`} className={`select-none flex gap-6 overflow-x-auto pb-8 pt-4 px-4 sm:px-6 md:px-8 lg:px-10 xl:px-[calc(50vw_-_640px_+_3rem)] 2xl:px-[calc(50vw_-_700px_+_4rem)] [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden ${isDragging ? 'cursor-grabbing snap-none' : 'cursor-grab snap-x snap-mandatory'}`}
> >
{references.map((ref, i) => { {references.map((ref, i) => {
const imgSrc = ref.image const imgSrc = ref.image