Spaces:
Sleeping
Sleeping
| import { useEffect, useRef, useState } from 'react'; | |
| import { ChevronLeft, ChevronRight } from 'lucide-react'; | |
| import MovieCard from './MovieCard'; | |
| export default function MovieSection({ title, movies = [], href = '#' }) { | |
| const [visible, setVisible] = useState(true); | |
| const sectionRef = useRef(null); | |
| const scrollRef = useRef(null); | |
| const [showLeft, setShowLeft] = useState(false); | |
| const [showRight, setShowRight] = useState(true); | |
| useEffect(() => { | |
| const observer = new IntersectionObserver( | |
| ([entry]) => { | |
| if (entry.isIntersecting) { | |
| setVisible(true); | |
| observer.unobserve(entry.target); | |
| } | |
| }, | |
| { threshold: 0.1 } | |
| ); | |
| if (sectionRef.current) observer.observe(sectionRef.current); | |
| return () => observer.disconnect(); | |
| }, []); | |
| const handleScroll = () => { | |
| if (!scrollRef.current) return; | |
| const { scrollLeft, scrollWidth, clientWidth } = scrollRef.current; | |
| setShowLeft(scrollLeft > 10); | |
| setShowRight(scrollLeft < scrollWidth - clientWidth - 10); | |
| }; | |
| const scroll = (dir) => { | |
| if (!scrollRef.current) return; | |
| const amount = scrollRef.current.clientWidth * 0.8; | |
| scrollRef.current.scrollBy({ left: dir * amount, behavior: 'smooth' }); | |
| }; | |
| if (!movies?.length) return null; | |
| return ( | |
| <section | |
| ref={sectionRef} | |
| className={`mx-auto max-w-7xl px-4 py-10 transition-all duration-1000 ${visible ? 'translate-y-0 opacity-100' : 'translate-y-10 opacity-0'}`} | |
| > | |
| <div className="mb-8 flex items-center justify-between"> | |
| <h2 className="flex items-center gap-3 text-2xl font-black uppercase tracking-tighter text-white md:text-3xl"> | |
| <span className="h-8 w-2 rounded-full bg-primary shadow-[0_0_15px_rgba(229,9,20,0.5)]" /> | |
| {title} | |
| </h2> | |
| {href !== '#' && ( | |
| <a href={href} className="group flex items-center gap-2 text-[10px] font-black uppercase tracking-widest text-gray-500 transition-colors hover:text-white"> | |
| Xem tất cả | |
| <ChevronRight size={14} className="transition-transform group-hover:translate-x-1" /> | |
| </a> | |
| )} | |
| </div> | |
| <div className="group relative"> | |
| {showLeft && ( | |
| <button | |
| onClick={() => scroll(-1)} | |
| className="absolute -left-4 top-1/2 z-30 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-black/60 text-white backdrop-blur-md opacity-0 transition-all group-hover:opacity-100 hover:bg-primary" | |
| > | |
| <ChevronLeft size={24} /> | |
| </button> | |
| )} | |
| {showRight && ( | |
| <button | |
| onClick={() => scroll(1)} | |
| className="absolute -right-4 top-1/2 z-30 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-black/60 text-white backdrop-blur-md opacity-0 transition-all group-hover:opacity-100 hover:bg-primary" | |
| > | |
| <ChevronRight size={24} /> | |
| </button> | |
| )} | |
| <div | |
| ref={scrollRef} | |
| onScroll={handleScroll} | |
| className="scrollbar-hide flex gap-5 overflow-x-auto pb-4" | |
| > | |
| {movies.map((movie) => ( | |
| <div key={movie._id || movie.slug} className="w-[180px] flex-shrink-0 md:w-[220px]"> | |
| <MovieCard movie={movie} /> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| </section> | |
| ); | |
| } | |