UI-UX/src/components/artist/PerformanceVideo.tsx

147 lines
4.6 KiB
TypeScript

"use client";
import { useRef, useState } from "react";
import { Play, Pause, Volume2, VolumeX, Maximize2 } from "lucide-react";
import { cn } from "@/lib/cn";
interface PerformanceVideoProps {
src?: string;
poster?: string;
duration?: string;
themeColor?: string;
className?: string;
}
export default function PerformanceVideo({
src,
poster,
duration = "00:15",
themeColor = "#8b5cf6",
className,
}: PerformanceVideoProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const [playing, setPlaying] = useState(false);
const [muted, setMuted] = useState(false);
const togglePlay = () => {
const v = videoRef.current;
if (!v) return;
if (v.paused) {
v.play();
setPlaying(true);
} else {
v.pause();
setPlaying(false);
}
};
const toggleMute = () => {
const v = videoRef.current;
if (!v) return;
v.muted = !v.muted;
setMuted(v.muted);
};
const goFullscreen = () => {
videoRef.current?.requestFullscreen?.();
};
return (
<div
className={cn(
"relative w-full aspect-video bg-deep rounded-xl overflow-hidden border border-white/[0.08] group",
className,
)}
>
{src ? (
<video
ref={videoRef}
src={src}
poster={poster}
playsInline
onEnded={() => setPlaying(false)}
className="absolute inset-0 w-full h-full object-cover"
/>
) : (
<div
className="absolute inset-0"
style={{
background: `radial-gradient(circle at 50% 40%, ${themeColor}55 0%, #1a1638 55%, #08051a 100%)`,
}}
>
{/* 装饰星点 */}
<div className="absolute inset-0 opacity-50">
<span className="absolute top-[15%] left-[20%] text-white text-xs">
</span>
<span className="absolute top-[70%] left-[80%] text-purple-300 text-sm">
</span>
<span className="absolute top-[30%] left-[70%] text-white/60 text-[10px]">
</span>
</div>
</div>
)}
{/* 顶部 15s 标签 */}
<div className="absolute top-3 left-3 inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-purple-600/90 backdrop-blur-md text-white text-[10px] font-display tracking-widest uppercase shadow-purple-glow z-10">
15s Performance
</div>
{/* 时长徽章 */}
<div className="absolute bottom-3 right-3 px-2 py-0.5 rounded bg-black/65 backdrop-blur-md text-white text-[10px] font-display tracking-wider tabular-nums z-10">
{duration}
</div>
{/* 中央播放按钮(未播放时) */}
{!playing && (
<button
type="button"
onClick={togglePlay}
className="absolute inset-0 flex items-center justify-center z-10 group/play"
aria-label="播放视频"
>
<span className="w-16 h-16 rounded-full bg-white/15 backdrop-blur-md border-2 border-white/40 flex items-center justify-center text-white group-hover/play:scale-110 transition-transform">
<Play size={22} fill="white" />
</span>
</button>
)}
{/* 暂停按钮 + 控制条(播放中) */}
{playing && (
<div className="absolute inset-0 flex items-center justify-center z-10 opacity-0 group-hover:opacity-100 transition-opacity bg-black/30">
<button
type="button"
onClick={togglePlay}
className="w-14 h-14 rounded-full bg-white/15 backdrop-blur-md border-2 border-white/40 flex items-center justify-center text-white hover:scale-105 transition-transform"
aria-label="暂停"
>
<Pause size={20} />
</button>
</div>
)}
{/* 右下:音量 / 全屏 */}
<div className="absolute bottom-3 left-3 flex items-center gap-1.5 z-10 opacity-0 group-hover:opacity-100 transition-opacity">
<button
type="button"
onClick={toggleMute}
aria-label={muted ? "取消静音" : "静音"}
className="w-7 h-7 rounded-full bg-black/55 backdrop-blur-md flex items-center justify-center text-white/85 hover:text-white"
>
{muted ? <VolumeX size={12} /> : <Volume2 size={12} />}
</button>
<button
type="button"
onClick={goFullscreen}
aria-label="全屏"
className="w-7 h-7 rounded-full bg-black/55 backdrop-blur-md flex items-center justify-center text-white/85 hover:text-white"
>
<Maximize2 size={12} />
</button>
</div>
</div>
);
}