video-flow-b/components/ui/generate-video-modal.tsx
2025-07-25 11:41:12 +08:00

150 lines
5.6 KiB
TypeScript

'use client';
import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { X, ChevronDown } from 'lucide-react';
import { cn } from '@/public/lib/utils';
interface GenerateVideoModalProps {
isOpen: boolean;
onClose: () => void;
onGenerate: (params: { text: string; duration: string }) => void;
}
export function GenerateVideoModal({
isOpen,
onClose,
onGenerate
}: GenerateVideoModalProps) {
const [text, setText] = useState('');
const [duration, setDuration] = useState('5');
const [videoUrl, setVideoUrl] = useState('');
const handleGenerate = () => {
onGenerate({ text, duration });
};
return (
<AnimatePresence>
{isOpen && (
<>
{/* 背景遮罩 */}
<motion.div
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
/>
{/* 弹窗内容 */}
<div className="fixed inset-x-0 bottom-0 z-50 flex justify-center">
<motion.div
className="w-[66%] min-w-[800px] bg-[#1a1b1e] rounded-t-2xl overflow-hidden"
initial={{ y: '100%' }}
animate={{ y: 0 }}
exit={{ y: '100%' }}
transition={{
type: 'spring',
damping: 25,
stiffness: 200,
}}
>
{/* 标题栏 */}
<div className="flex items-center justify-between p-4 border-b border-white/10">
<div className="flex items-center gap-2">
<button
className="p-1 hover:bg-white/10 rounded-full transition-colors"
onClick={onClose}
>
<ChevronDown className="w-5 h-5" />
</button>
<h2 className="text-lg font-medium">generate video</h2>
</div>
</div>
{/* 主要内容区域 */}
<div className="p-6 space-y-6 h-[80vh] flex flex-col overflow-y-auto hide-scrollbar">
{/* 文本输入区域 */}
<div className="space-y-2 flex-shrink-0">
<label className="text-sm text-white/70">describe the scene</label>
<textarea
className="w-full h-32 p-4 bg-white/5 border border-white/10 rounded-lg
text-white placeholder-white/30 resize-none focus:outline-none focus:border-blue-500"
placeholder="describe the scene you want to generate..."
value={text}
onChange={(e) => setText(e.target.value)}
/>
</div>
{/* 时长选择 */}
{/* <div className="space-y-2">
<label className="text-sm text-white/70">视频时长(秒)</label>
<div className="flex gap-2">
{['5', '10', '15', '30'].map((value) => (
<motion.button
key={value}
className={cn(
'px-4 py-2 rounded-lg transition-colors',
duration === value
? 'bg-blue-500 text-white'
: 'bg-white/5 hover:bg-white/10'
)}
onClick={() => setDuration(value)}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{value}秒
</motion.button>
))}
</div>
</div> */}
{/* 生成按钮 */}
<div className="flex justify-end flex-shrink-0">
<motion.button
className="px-6 py-2 bg-blue-500 hover:bg-blue-600 rounded-lg
transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
onClick={handleGenerate}
disabled={!text.trim()}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
generate video
</motion.button>
</div>
{/* 生成视频预览 */}
<div className="flex justify-center flex-1 h-[450px]">
<div className="w-[800px] h-full bg-white/5 rounded-lg">
<video src={videoUrl} className="w-full object-cover" autoPlay />
</div>
</div>
</div>
{/* 底部操作栏 */}
<div className="p-4 border-t border-white/10 bg-black/20">
<div className="flex justify-end gap-3">
<motion.button
className="px-4 py-2 rounded-lg bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 transition-colors"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
add to library
</motion.button>
<motion.button
className="px-4 py-2 rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
apply
</motion.button>
</div>
</div>
</motion.div>
</div>
</>
)}
</AnimatePresence>
);
}