2025-06-26 20:12:55 +08:00

129 lines
4.1 KiB
TypeScript

import { useRef, useState } from 'react';
import { motion } from 'framer-motion';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { Scene } from '../pages/script-overview';
import Image from 'next/image';
interface SceneFilmstripProps {
scenes: Scene[];
selectedSceneId?: string;
onSceneSelect: (sceneId: string) => void;
}
export function SceneFilmstrip({
scenes,
selectedSceneId,
onSceneSelect
}: SceneFilmstripProps) {
const [selectedSceneIdState, setSelectedSceneIdState] = useState<string | null>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null);
// 处理滚动
const handleScroll = (direction: 'left' | 'right') => {
if (!scrollContainerRef.current) return;
const scrollAmount = 300;
const container = scrollContainerRef.current;
container.scrollTo({
left: container.scrollLeft + (direction === 'left' ? -scrollAmount : scrollAmount),
behavior: 'smooth'
});
};
// 处理场景选择
const handleSceneSelect = (sceneId: string) => {
setSelectedSceneIdState(sceneId);
onSceneSelect(sceneId);
// 滚动到对应的场景卡片
const sceneCard = document.getElementById(`scene-card-${sceneId}`);
if (sceneCard) {
sceneCard.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'center'
});
}
};
return (
<div className="relative">
{/* 滚动按钮 */}
<button
onClick={() => handleScroll('left')}
className="absolute left-4 top-1/2 -translate-y-1/2 z-10 w-10 h-10 rounded-full
bg-black/50 hover:bg-black/70 backdrop-blur-sm flex items-center justify-center
transition-colors"
>
<ChevronLeft className="w-6 h-6" />
</button>
<button
onClick={() => handleScroll('right')}
className="absolute right-4 top-1/2 -translate-y-1/2 z-10 w-10 h-10 rounded-full
bg-black/50 hover:bg-black/70 backdrop-blur-sm flex items-center justify-center
transition-colors"
>
<ChevronRight className="w-6 h-6" />
</button>
{/* 胶片打孔效果 */}
<div className="absolute -top-2 left-0 right-0 flex justify-between px-4">
{Array.from({ length: 20 }).map((_, i) => (
<div
key={i}
className="w-3 h-3 rounded-full bg-black/50 border border-white/10"
/>
))}
</div>
<div className="absolute -bottom-2 left-0 right-0 flex justify-between px-4">
{Array.from({ length: 20 }).map((_, i) => (
<div
key={i}
className="w-3 h-3 rounded-full bg-black/50 border border-white/10"
/>
))}
</div>
{/* 场景缩略图 */}
<div
ref={scrollContainerRef}
className="flex gap-4 overflow-x-auto py-4 px-2 hide-scrollbar"
style={{ perspective: '1000px' }}
>
{scenes.map((scene, index) => (
<motion.div
key={scene.id}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
animate={{
scale: selectedSceneId === scene.id ? 1.1 : 1,
opacity: selectedSceneId === scene.id ? 1 : 0.7,
}}
onClick={() => handleSceneSelect(scene.id)}
className={`
relative flex-shrink-0 w-32 h-20 rounded-lg overflow-hidden cursor-pointer
${selectedSceneId === scene.id ? 'ring-2 ring-purple-500' : 'hover:ring-1 hover:ring-white/20'}
transition-shadow duration-200
`}
>
<Image
src={scene.imageUrl}
alt={scene.name}
fill
className="object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
<div className="absolute bottom-1 left-2 right-2 text-xs font-medium truncate">
{scene.name}
</div>
</motion.div>
))}
</div>
{/* 胶片装饰线 */}
<div className="absolute top-0 left-16 right-16 h-1 bg-white/5" />
<div className="absolute bottom-0 left-16 right-16 h-1 bg-white/5" />
</div>
);
}