video-flow-b/components/video-grid-layout.tsx
2025-06-26 20:12:55 +08:00

115 lines
3.8 KiB
TypeScript

import React, { useState } from 'react';
import { Edit2, Trash2, Play } from 'lucide-react';
import { Button } from '@/components/ui/button';
interface VideoGridLayoutProps {
videos: {
id: string;
url: string;
title: string;
date?: string;
}[];
onEdit?: (id: string) => void;
onDelete?: (id: string) => void;
}
export function VideoGridLayout({ videos, onEdit, onDelete }: VideoGridLayoutProps) {
const [hoveredId, setHoveredId] = useState<string | null>(null);
const [isPlaying, setIsPlaying] = useState<{ [key: string]: boolean }>({});
const handleMouseEnter = (id: string) => {
setHoveredId(id);
};
const handleMouseLeave = (id: string) => {
setHoveredId(null);
// 暂停视频
const video = document.getElementById(`video-${id}`) as HTMLVideoElement;
if (video) {
video.pause();
setIsPlaying(prev => ({ ...prev, [id]: false }));
}
};
const togglePlay = (id: string) => {
const video = document.getElementById(`video-${id}`) as HTMLVideoElement;
if (video) {
if (video.paused) {
video.play();
setIsPlaying(prev => ({ ...prev, [id]: true }));
} else {
video.pause();
setIsPlaying(prev => ({ ...prev, [id]: false }));
}
}
};
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-6">
{videos.map((video) => (
<div
key={video.id}
className="group relative bg-white/5 rounded-lg overflow-hidden transition-all duration-300 hover:bg-white/10"
onMouseEnter={() => handleMouseEnter(video.id)}
onMouseLeave={() => handleMouseLeave(video.id)}
>
{/* 视频容器 */}
<div className="relative aspect-video">
<video
id={`video-${video.id}`}
src={video.url}
className="w-full h-full object-cover"
loop
muted
playsInline
/>
{/* 播放按钮遮罩 */}
<div
className={`absolute inset-0 flex items-center justify-center bg-black/40 transition-opacity duration-300
${hoveredId === video.id ? 'opacity-100' : 'opacity-0'}
`}
onClick={() => togglePlay(video.id)}
>
<Play className={`w-12 h-12 text-white/90 transition-transform duration-300
${isPlaying[video.id] ? 'scale-90 opacity-0' : 'scale-100 opacity-100'}`}
/>
</div>
{/* 操作按钮 */}
<div
className={`absolute top-4 right-4 flex gap-2 transition-all duration-300 transform
${hoveredId === video.id ? 'translate-y-0 opacity-100' : 'translate-y-[-10px] opacity-0'}
`}
>
<Button
variant="ghost"
size="icon"
className="w-8 h-8 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm"
onClick={() => onEdit?.(video.id)}
>
<Edit2 className="w-4 h-4 text-white" />
</Button>
<Button
variant="ghost"
size="icon"
className="w-8 h-8 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm"
onClick={() => onDelete?.(video.id)}
>
<Trash2 className="w-4 h-4 text-white" />
</Button>
</div>
</div>
{/* 视频信息 */}
<div className="p-4">
<h3 className="text-white text-lg font-medium mb-1">{video.title}</h3>
{video.date && (
<p className="text-white/60 text-sm">{video.date}</p>
)}
</div>
</div>
))}
</div>
);
}