'use client'; import * as React from 'react'; import { motion } from 'framer-motion'; import Link from 'next/link'; import Image from 'next/image'; import { HoverShineOverlay } from '@/components/ui/HoverShineOverlay'; import { useTranslations, useLocale } from 'next-intl'; export interface Reference { id: string; title: string; slug: string; category: string; image?: { url: string; alt?: string; } | string | null; } interface ReferencesSliderProps { references?: Reference[]; badge?: string; title?: string; description?: string; ctaLabel?: string; ctaHref?: string; data?: { badge?: string; title?: string; description?: string; ctaLabel?: string; ctaHref?: string; } } export function ReferencesSlider(props: ReferencesSliderProps) { const t = useTranslations('ReferencesSlider'); const locale = useLocale(); const { data } = props; const references = props.references || []; const containerRef = React.useRef(null); const dragDistanceRef = React.useRef(0); const startXRef = React.useRef(0); const scrollLeftRef = React.useRef(0); const isDraggingRef = React.useRef(false); const [isDragging, setIsDragging] = React.useState(false); const badge = props.badge || data?.badge || t('badge'); const title = props.title || data?.title || t('title'); const description = props.description || data?.description || t('description'); const ctaLabel = props.ctaLabel || data?.ctaLabel || t('ctaLabel'); const ctaHref = props.ctaHref || data?.ctaHref || `/${locale}/referenzen`; if (!references || references.length === 0) return null; // Fallback images pool if CMS doesn't provide one const fallbacks = [ '/assets/photos/DSC01123.JPG', '/assets/photos/DSC00850.JPG', '/assets/photos/DSC01129.JPG', '/assets/photos/DSC00010.JPG', ]; const onMouseDown = (e: React.MouseEvent) => { if (!containerRef.current) return; setIsDragging(true); isDraggingRef.current = true; const startXVal = e.clientX - (containerRef.current.offsetLeft || 0); startXRef.current = startXVal; scrollLeftRef.current = containerRef.current.scrollLeft || 0; dragDistanceRef.current = 0; }; const onMouseLeave = () => { setIsDragging(false); isDraggingRef.current = false; }; const onMouseUp = () => { setIsDragging(false); isDraggingRef.current = false; }; const onMouseMove = (e: React.MouseEvent) => { if (!isDraggingRef.current || !containerRef.current) return; e.preventDefault(); const x = e.clientX - (containerRef.current.offsetLeft || 0); const walk = (x - startXRef.current) * 2; // Scroll-fast containerRef.current.scrollLeft = scrollLeftRef.current - walk; dragDistanceRef.current = Math.abs(x - startXRef.current); }; return (

{badge}

{title}

{description}
{references.map((ref, i) => { const imgSrc = ref.image ? (typeof ref.image === 'string' ? ref.image : ref.image.url) : fallbacks[i % fallbacks.length]; return ( { if (dragDistanceRef.current > 5) { e.preventDefault(); } }} data-testid="reference-tile" className="block relative select-none aspect-[16/10] bg-neutral-800 rounded-2xl overflow-hidden mb-5 border border-white/5 shadow-2xl cursor-pointer" > {ref.title}
{ref.category}

{ref.title}

); })}
{ctaLabel}
); }