'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'; import { getImageForProject } from '@/lib/image-matcher'; 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; // Map the display category back to our internal image matcher categories const mapCategoryToInternal = (cat: string) => { const lower = cat.toLowerCase(); if (lower.includes('pv') || lower.includes('solar')) return 'pv'; if (lower.includes('wind')) return 'wind'; if (lower.includes('trasse') || lower.includes('spannung') || lower.includes('power')) return 'power'; if (lower.includes('batterie') || lower.includes('bess') || lower.includes('speicher')) return 'battery'; return 'fiber'; // fallback for Tiefbau / Breitband }; 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 === 'object' && ref.image.url) ? ref.image.url : typeof ref.image === 'string' ? ref.image : getImageForProject(ref.slug || ref.id, mapCategoryToInternal(ref.category)); return ( { if (dragDistanceRef.current > 15) { e.preventDefault(); } dragDistanceRef.current = 0; }} className="block relative select-none aspect-[16/10] bg-neutral-800 rounded-2xl overflow-hidden mb-5 border border-white/5 shadow-2xl" > {ref.title}
{ref.category}

{ref.title}

); })}
{ctaLabel}
); }