Spaces:
Sleeping
Sleeping
| import React, { useState, useRef, useEffect } from 'react'; | |
| import ContentCard from './ContentCard'; | |
| import { ChevronLeft, ChevronRight } from 'lucide-react'; | |
| interface ContentItem { | |
| type: 'movie' | 'tvshow'; | |
| title: string; | |
| image: string; | |
| description?: string; | |
| genre?: string[]; | |
| year?: number | string; | |
| } | |
| interface ContentRowProps { | |
| title: string; | |
| items: ContentItem[]; | |
| } | |
| const ContentRow: React.FC<ContentRowProps> = ({ title, items }) => { | |
| const rowRef = useRef<HTMLDivElement>(null); | |
| const [showLeftButton, setShowLeftButton] = useState(false); | |
| const [showRightButton, setShowRightButton] = useState(true); | |
| // Handle scroll events to show/hide buttons | |
| const handleScroll = () => { | |
| if (rowRef.current) { | |
| const { scrollLeft, scrollWidth, clientWidth } = rowRef.current; | |
| setShowLeftButton(scrollLeft > 20); | |
| setShowRightButton(scrollLeft < scrollWidth - clientWidth - 20); | |
| } | |
| }; | |
| // Set up scroll listeners and initial state | |
| useEffect(() => { | |
| handleScroll(); | |
| window.addEventListener('resize', handleScroll); | |
| return () => window.removeEventListener('resize', handleScroll); | |
| }, [items]); | |
| const scroll = (direction: 'left' | 'right') => { | |
| if (rowRef.current) { | |
| const card = rowRef.current.querySelector('.card-hover'); | |
| const cardWidth = card ? card.clientWidth + 16 : 280; // Card width + margin | |
| const scrollAmount = direction === 'left' ? -cardWidth * 3 : cardWidth * 3; | |
| rowRef.current.scrollBy({ left: scrollAmount, behavior: 'smooth' }); | |
| } | |
| }; | |
| // Don't render the row if there are no items | |
| if (items.length === 0) { | |
| return null; | |
| } | |
| return ( | |
| <div className="content-row mb-8"> | |
| <h2 className="text-xl font-bold px-4 md:px-8 mb-4">{title}</h2> | |
| <div className="relative group"> | |
| {/* Left scroll button */} | |
| <button | |
| onClick={() => scroll('left')} | |
| className={`absolute left-2 top-1/2 transform -translate-y-1/2 z-30 | |
| bg-black/40 hover:bg-black/60 rounded-full p-2 transition-all duration-200 | |
| ${showLeftButton ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} | |
| aria-label="Scroll left" | |
| > | |
| <ChevronLeft className="w-6 h-6 text-white" /> | |
| </button> | |
| {/* Content row */} | |
| <div | |
| ref={rowRef} | |
| onScroll={handleScroll} | |
| className="flex gap-4 overflow-x-auto py-4 px-4 md:px-8 scrollbar-none scroll-smooth" | |
| style={{ scrollbarWidth: 'none' }} | |
| > | |
| {items.map((item, index) => ( | |
| <div key={`${item.title}-${index}`} className="flex-shrink-0"> | |
| <ContentCard | |
| type={item.type} | |
| title={item.title} | |
| image={item.image} | |
| description={item.description} | |
| genre={item.genre} | |
| year={item.year} | |
| /> | |
| </div> | |
| ))} | |
| </div> | |
| {/* Right scroll button */} | |
| <button | |
| onClick={() => scroll('right')} | |
| className={`absolute right-2 top-1/2 transform -translate-y-1/2 z-30 | |
| bg-black/40 hover:bg-black/60 rounded-full p-2 transition-all duration-200 | |
| ${showRightButton ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} | |
| aria-label="Scroll right" | |
| > | |
| <ChevronRight className="w-6 h-6 text-white" /> | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default ContentRow; | |