Spaces:
Sleeping
Sleeping
File size: 6,165 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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | import { Play, Info } from 'lucide-react';
import { useState, useRef } from 'react';
import { formatImageUrl } from '../lib/image';
export default function TopTenCard({ movie, index }) {
const [showPreview, setShowPreview] = useState(false);
const hoverTimer = useRef(null);
const handleMouseEnter = () => {
hoverTimer.current = setTimeout(() => {
setShowPreview(true);
}, 400); // Mượt mà hơn với 400ms phản hồi
};
const handleMouseLeave = () => {
if (hoverTimer.current) clearTimeout(hoverTimer.current);
setShowPreview(false);
};
const year = movie.year || (movie.modified?.time ? new Date(movie.modified.time).getFullYear() : '');
const epCount = movie.episode_current?.match(/\d+/)?.[0] || '??';
// horizontal backdrop for preview
const backdrop = formatImageUrl(movie.poster_url || movie.thumb_url);
const poster = formatImageUrl(movie.thumb_url || movie.poster_url);
return (
<div
className="relative flex flex-col group/card h-[240px] md:h-[340px] w-full"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{/* Giant Netflix Outlined Number */}
<div
className="pointer-events-none absolute select-none leading-none font-black transition-all duration-700 group-hover/card:scale-105"
style={{
left: '-12px',
bottom: '40px',
fontSize: '180px',
fontWeight: 950,
fontStyle: 'italic',
fontFamily: '"Outfit", "Impact", "Arial Black", sans-serif',
color: '#0c0c0c',
WebkitTextStroke: '4px rgba(255, 255, 255, 0.45)',
textShadow: '0 10px 30px rgba(0,0,0,0.9), 10px 10px 20px rgba(0,0,0,0.7)',
zIndex: 10,
}}
>
{index + 1}
</div>
{/* Overlapping Poster Card */}
<div className="relative ml-[35%] w-[65%] h-[80%] z-20 transition-all duration-500 group-hover/card:translate-x-2 group-hover/card:scale-[1.03]">
<div
className="absolute inset-0 overflow-hidden rounded-2xl shadow-[0_15px_30px_rgba(0,0,0,0.8)] ring-1 ring-white/10 group-hover/card:shadow-[0_20px_40px_rgba(229,9,20,0.45)] group-hover/card:ring-primary/50"
>
<img src={poster} alt={movie.name} className="h-full w-full object-cover" />
<div className="absolute inset-0 bg-gradient-to-t from-black/90 via-transparent to-transparent" />
</div>
{/* Episode Badge */}
<div className="absolute bottom-2 left-2 z-20 flex flex-wrap gap-1">
<span className="rounded px-2 py-[3px] text-[9px] md:text-[10px] font-black uppercase tracking-wide text-white bg-black/85 border border-white/10 backdrop-blur-sm shadow-md">
TẬP {epCount}
</span>
</div>
<a href={`/phim/${movie.slug}`} className="absolute inset-0 z-40 rounded-2xl" />
</div>
{/* Info below aligned with poster */}
<div className="ml-[35%] pl-3 pr-1 pt-3 h-[20%] flex flex-col justify-center min-w-0">
<h3 className="line-clamp-1 text-[13px] md:text-[15px] font-black uppercase tracking-tight text-white transition-colors duration-300 group-hover/card:text-primary">
{movie.name}
</h3>
<p className="mt-1 line-clamp-1 text-[9px] md:text-[11px] font-bold uppercase tracking-widest text-gray-400">
{movie.origin_name}
</p>
</div>
{/* Premium Hover Preview Popup */}
{showPreview && (
<div className="absolute left-[65%] top-[10%] z-[100] w-[280px] -translate-x-1/2 -translate-y-[20%] animate-in fade-in zoom-in duration-300 pointer-events-auto">
<div className="overflow-hidden rounded-2xl bg-[#141414] shadow-[0_25px_60px_rgba(0,0,0,0.95)] ring-1 ring-white/10 border border-white/5">
<div className="relative aspect-video w-full overflow-hidden">
<img src={backdrop} className="h-full w-full object-cover" alt="preview" />
<div className="absolute inset-0 bg-gradient-to-t from-[#141414] via-transparent to-transparent" />
<div className="absolute bottom-3 left-3 right-3 flex items-end justify-between">
<div className="flex flex-col min-w-0">
<span className="text-[10px] font-black text-white shadow-black drop-shadow-lg truncate">{movie.name}</span>
<span className="text-[7px] font-bold text-gray-400 uppercase tracking-widest truncate">{movie.origin_name}</span>
</div>
<span className="rounded bg-primary px-1.5 py-0.5 text-[7px] font-black text-white uppercase shrink-0 shadow-lg">{movie.quality || 'FHD'}</span>
</div>
</div>
<div className="p-4 bg-[#141414]">
<div className="flex items-center gap-3 mb-3.5">
<a href={`/xem/${movie.slug}`} className="flex flex-1 items-center justify-center gap-2 rounded-xl bg-white py-2.5 text-[9px] font-black uppercase tracking-widest text-black transition-all hover:bg-white/90 hover:scale-[1.02] active:scale-95 shadow-md">
<Play size={10} fill="black" /> Xem ngay
</a>
<a href={`/phim/${movie.slug}`} className="flex h-9 w-9 items-center justify-center rounded-xl bg-white/10 text-white transition-all hover:bg-white/20 hover:scale-[1.02] border border-white/5 shadow-md">
<Info size={14} />
</a>
</div>
<p className="line-clamp-2 text-[9px] leading-relaxed text-gray-400 font-medium">
{movie.content?.replace(/<[^>]*>/g, '') || 'Đang cập nhật nội dung cốt truyện...'}
</p>
<div className="mt-3.5 pt-3 border-t border-white/5 flex items-center gap-2 text-[8px] font-bold text-gray-500 uppercase tracking-wider">
<span>{year}</span>
<span className="h-1 w-1 rounded-full bg-gray-700" />
<span>{movie.episode_current}</span>
</div>
</div>
</div>
</div>
)}
</div>
);
} |