Spaces:
Sleeping
Sleeping
File size: 3,415 Bytes
4bea261 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 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>
);
}
|