forked from 77media/video-flow
197 lines
6.3 KiB
TypeScript
197 lines
6.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { ArrowLeft } from 'lucide-react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { FilmstripStepper } from '@/components/filmstrip-stepper';
|
|
import { AISuggestionBar } from '@/components/ai-suggestion-bar';
|
|
import ScriptOverview from '@/components/pages/script-overview';
|
|
import StoryboardView from '@/components/pages/storyboard-view';
|
|
|
|
// 定义工作流程阶段
|
|
const WORKFLOW_STAGES = [
|
|
{
|
|
id: 'overview',
|
|
title: 'Script Overview',
|
|
subtitle: 'Script Overview',
|
|
description: 'Extract script structure and key elements'
|
|
},
|
|
{
|
|
id: 'storyboard',
|
|
title: 'Storyboard',
|
|
subtitle: 'Storyboard',
|
|
description: 'Visualize scene design and transitions'
|
|
},
|
|
{
|
|
id: 'character',
|
|
title: 'Character Design',
|
|
subtitle: 'Character Design',
|
|
description: 'Customize character appearance and personality'
|
|
},
|
|
{
|
|
id: 'post',
|
|
title: 'Post Production',
|
|
subtitle: 'Post Production',
|
|
description: 'Sound effects, music and special effects'
|
|
},
|
|
{
|
|
id: 'output',
|
|
title: 'Final Output',
|
|
subtitle: 'Final Output',
|
|
description: 'Preview and export works'
|
|
}
|
|
];
|
|
|
|
export default function ScriptWorkFlow() {
|
|
const router = useRouter();
|
|
const [currentStep, setCurrentStep] = useState('overview');
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// 根据当前步骤获取智能预设词条
|
|
const getSmartSuggestions = (stepId: string): string[] => {
|
|
const suggestions = {
|
|
overview: [
|
|
"Analyze core themes and emotions",
|
|
"Extract character relationship map",
|
|
"Generate scene and plot outline",
|
|
"Identify key turning points",
|
|
"Optimize story structure and pacing"
|
|
],
|
|
storyboard: [
|
|
"Design opening shot sequence",
|
|
"Plan transitions and visual effects",
|
|
"Generate key scene storyboards",
|
|
"Optimize shot language and rhythm",
|
|
"Add camera movement notes"
|
|
],
|
|
character: [
|
|
"Design protagonist appearance",
|
|
"Generate supporting character references",
|
|
"Create character relationship map",
|
|
"Add costume and prop designs",
|
|
"Optimize character actions"
|
|
],
|
|
post: [
|
|
"Plan sound and music style",
|
|
"Design visual effects solution",
|
|
"Add subtitles and graphics",
|
|
"Optimize color and lighting",
|
|
"Plan post-production workflow"
|
|
],
|
|
output: [
|
|
"Generate preview version",
|
|
"Optimize output parameters",
|
|
"Add opening and ending design",
|
|
"Export different formats",
|
|
"Create release plan"
|
|
]
|
|
};
|
|
return suggestions[stepId as keyof typeof suggestions] || [];
|
|
};
|
|
|
|
useEffect(() => {
|
|
// 模拟加载效果
|
|
const timer = setTimeout(() => {
|
|
setLoading(false);
|
|
}, 1500);
|
|
return () => clearTimeout(timer);
|
|
}, []);
|
|
|
|
// 处理步骤切换
|
|
const handleStepChange = async (stepId: string) => {
|
|
setLoading(true);
|
|
setCurrentStep(stepId);
|
|
// 模拟加载效果
|
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
setLoading(false);
|
|
};
|
|
|
|
// 处理 AI 建议点击
|
|
const handleSuggestionClick = (suggestion: string) => {
|
|
console.log('选择了建议:', suggestion);
|
|
// TODO: 处理建议点击逻辑
|
|
};
|
|
|
|
// 处理输入提交
|
|
const handleSubmit = (text: string) => {
|
|
console.log('提交了文本:', text);
|
|
// TODO: 处理文本提交逻辑
|
|
};
|
|
|
|
return (
|
|
<div className="h-full bg-[#0C0E11] text-white overflow-hidden">
|
|
{/* Navigation Tabs */}
|
|
<div className="fixed top-0 left-0 right-0 z-50">
|
|
{/* Glass Effect Background */}
|
|
<div className="absolute inset-0 bg-[#0C0E11]/80 backdrop-blur-md" />
|
|
|
|
{/* Bottom Border */}
|
|
<div className="absolute bottom-0 left-0 right-0 h-[1px] bg-white/10" />
|
|
|
|
{/* Navigation Content */}
|
|
<div className="relative h-16 flex items-center">
|
|
<div className="w-full max-w-screen-xl mx-auto px-6">
|
|
<div className="flex items-center justify-center gap-2">
|
|
{WORKFLOW_STAGES.map(stage => (
|
|
<motion.button
|
|
key={stage.id}
|
|
onClick={() => handleStepChange(stage.id)}
|
|
className={`
|
|
flex-shrink-0 px-6 py-2 rounded-lg transition-all duration-300
|
|
${currentStep === stage.id
|
|
? 'bg-white/10 text-white shadow-[0_0_15px_rgba(255,255,255,0.15)]'
|
|
: 'hover:bg-white/5 text-white/60 hover:text-white/80'
|
|
}
|
|
`}
|
|
whileHover={{ scale: 1.02 }}
|
|
whileTap={{ scale: 0.98 }}
|
|
>
|
|
<span className="text-sm font-medium whitespace-nowrap">{stage.title}</span>
|
|
</motion.button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Content Area */}
|
|
<main className="pt-[3.5rem] px-6 h-[calc(100vh-9rem)] overflow-hidden">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={currentStep}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
transition={{ duration: 0.3 }}
|
|
className="w-full h-full overflow-hidden"
|
|
>
|
|
{loading ? (
|
|
<div className="space-y-4">
|
|
{[1, 2, 3].map(i => (
|
|
<div
|
|
key={i}
|
|
className="h-24 bg-white/5 rounded-lg animate-pulse"
|
|
/>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<>
|
|
{currentStep === 'overview' && <ScriptOverview />}
|
|
{currentStep === 'storyboard' && <StoryboardView />}
|
|
</>
|
|
)}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</main>
|
|
|
|
{/* AI Suggestion Bar */}
|
|
<AISuggestionBar
|
|
suggestions={getSmartSuggestions(currentStep)}
|
|
onSuggestionClick={handleSuggestionClick}
|
|
onSubmit={handleSubmit}
|
|
placeholder={`What would you like AI to help you with in the ${WORKFLOW_STAGES.find(stage => stage.id === currentStep)?.title} stage?`}
|
|
/>
|
|
</div>
|
|
);
|
|
} |