/** * Component: Similar Series Row * Documentation: documentation/frontend/components.md * * Horizontal scrollable carousel of similar series cards. * Desktop: left/right nav arrows. Mobile: drag-to-scroll. * Each card navigates to the series detail page. */ 'use client'; import React, { useRef, useState, useEffect, useCallback } from 'react'; import Image from 'next/image'; import Link from 'next/link'; import { SimilarSeries } from '@/lib/hooks/useSeries'; interface SimilarSeriesRowProps { series: SimilarSeries[]; currentSeriesTitle?: string; squareCovers?: boolean; } export function SimilarSeriesRow({ series, currentSeriesTitle, squareCovers = false }: SimilarSeriesRowProps) { const scrollRef = useRef(null); const [canScrollLeft, setCanScrollLeft] = useState(false); const [canScrollRight, setCanScrollRight] = useState(false); const checkScroll = useCallback(() => { const el = scrollRef.current; if (!el) return; setCanScrollLeft(el.scrollLeft > 4); setCanScrollRight(el.scrollLeft < el.scrollWidth - el.clientWidth - 4); }, []); useEffect(() => { checkScroll(); const el = scrollRef.current; if (!el) return; el.addEventListener('scroll', checkScroll, { passive: true }); const observer = new ResizeObserver(checkScroll); observer.observe(el); return () => { el.removeEventListener('scroll', checkScroll); observer.disconnect(); }; }, [checkScroll, series]); const scroll = (direction: 'left' | 'right') => { const el = scrollRef.current; if (!el) return; const scrollAmount = el.clientWidth * 0.7; el.scrollBy({ left: direction === 'left' ? -scrollAmount : scrollAmount, behavior: 'smooth', }); }; if (series.length === 0) return null; return (

Similar Series

({series.length})
{/* Left arrow */} {canScrollLeft && ( )} {/* Scrollable row */}
{series.map(s => ( {/* Cover */}
{ (e.target as HTMLImageElement).src = '/placeholder_cover.svg'; }} />
{/* Title */}

{s.title}

))}
{/* Right arrow */} {canScrollRight && ( )} {/* Fade edges */} {canScrollLeft && (
)} {canScrollRight && (
)}
); } export function SimilarSeriesSkeleton({ squareCovers = false }: { squareCovers?: boolean }) { return (
{Array.from({ length: 8 }).map((_, i) => (
))}
); }