2025-08-05 20:45:02 +08:00

842 lines
29 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useRef, useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Edit3, Play, Pause, Volume2, VolumeX, Maximize, Minimize } from 'lucide-react';
import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal';
import { GlassIconButton } from '@/components/ui/glass-icon-button';
import { ScriptRenderer } from '@/components/script-renderer/ScriptRenderer';
import { mockScriptData } from '@/components/script-renderer/mock';
import { Skeleton } from '@/components/ui/skeleton';
interface MediaViewerProps {
scriptData: any;
currentStep: string;
currentSketchIndex: number;
taskSketch: any[];
taskVideos: any[];
isVideoPlaying: boolean;
isPlaying: boolean;
showControls: boolean;
isGeneratingSketch: boolean;
isGeneratingVideo: boolean;
onControlsChange: (show: boolean) => void;
onEditModalOpen: (tab: string) => void;
onToggleVideoPlay: () => void;
onTogglePlay: () => void;
final?: any;
}
export function MediaViewer({
scriptData,
currentStep,
currentSketchIndex,
taskSketch,
taskVideos,
isVideoPlaying,
isPlaying,
showControls,
isGeneratingSketch,
isGeneratingVideo,
onControlsChange,
onEditModalOpen,
onToggleVideoPlay,
onTogglePlay,
final
}: MediaViewerProps) {
const mainVideoRef = useRef<HTMLVideoElement>(null);
const finalVideoRef = useRef<HTMLVideoElement>(null);
// 音量控制状态
const [isMuted, setIsMuted] = useState(false);
const [volume, setVolume] = useState(0.8);
// 最终视频控制状态
const [isFinalVideoPlaying, setIsFinalVideoPlaying] = useState(true);
const [isFullscreen, setIsFullscreen] = useState(false);
const [finalVideoReady, setFinalVideoReady] = useState(false);
const [userHasInteracted, setUserHasInteracted] = useState(false);
// 音量控制函数
const toggleMute = () => {
setUserHasInteracted(true);
setIsMuted(!isMuted);
if (mainVideoRef.current) {
mainVideoRef.current.muted = !isMuted;
}
if (finalVideoRef.current) {
finalVideoRef.current.muted = !isMuted;
}
};
const handleVolumeChange = (newVolume: number) => {
setUserHasInteracted(true);
setVolume(newVolume);
if (mainVideoRef.current) {
mainVideoRef.current.volume = newVolume;
}
if (finalVideoRef.current) {
finalVideoRef.current.volume = newVolume;
}
};
// 应用音量设置到视频元素
const applyVolumeSettings = (videoElement: HTMLVideoElement) => {
if (videoElement) {
videoElement.volume = volume;
videoElement.muted = isMuted;
}
};
useEffect(() => {
if (finalVideoRef.current && finalVideoReady) {
if (isFinalVideoPlaying) {
finalVideoRef.current.play().catch(error => {
console.log('最终视频自动播放被阻止:', error);
// 如果自动播放被阻止,将状态设置为暂停
setIsFinalVideoPlaying(false);
});
} else {
finalVideoRef.current.pause();
}
}
}, [isFinalVideoPlaying, finalVideoReady]);
// 最终视频播放控制
const toggleFinalVideoPlay = () => {
setUserHasInteracted(true);
setIsFinalVideoPlaying(!isFinalVideoPlaying);
};
// 处理最终视频加载完成
const handleFinalVideoLoaded = () => {
if (finalVideoRef.current) {
setFinalVideoReady(true);
applyVolumeSettings(finalVideoRef.current);
// 如果当前状态是应该播放的,尝试播放
if (isFinalVideoPlaying) {
finalVideoRef.current.play().catch(error => {
console.log('最终视频自动播放被阻止:', error);
setIsFinalVideoPlaying(false);
});
}
}
};
// 处理视频点击 - 首次交互时尝试播放
const handleVideoClick = () => {
if (!userHasInteracted && finalVideoRef.current && finalVideoReady) {
setUserHasInteracted(true);
if (isFinalVideoPlaying) {
finalVideoRef.current.play().catch(error => {
console.log('视频播放失败:', error);
});
}
}
};
// 包装编辑按钮点击事件
const handleEditClick = (tab: string) => {
setUserHasInteracted(true);
onEditModalOpen(tab);
};
// 全屏控制
const toggleFullscreen = () => {
setUserHasInteracted(true);
if (!document.fullscreenElement) {
// 进入全屏
if (finalVideoRef.current) {
finalVideoRef.current.requestFullscreen?.() ||
(finalVideoRef.current as any).webkitRequestFullscreen?.() ||
(finalVideoRef.current as any).msRequestFullscreen?.();
setIsFullscreen(true);
}
} else {
// 退出全屏
document.exitFullscreen?.() ||
(document as any).webkitExitFullscreen?.() ||
(document as any).msExitFullscreen?.();
setIsFullscreen(false);
}
};
// 视频播放控制
useEffect(() => {
if (mainVideoRef.current) {
applyVolumeSettings(mainVideoRef.current);
if (isVideoPlaying) {
mainVideoRef.current.play().catch(error => {
console.log('视频播放失败:', error);
});
} else {
mainVideoRef.current.pause();
}
}
}, [isVideoPlaying]);
// 当切换视频时重置视频播放
useEffect(() => {
if (mainVideoRef.current) {
applyVolumeSettings(mainVideoRef.current);
mainVideoRef.current.currentTime = 0;
if (isVideoPlaying) {
mainVideoRef.current.play().catch(error => {
console.log('视频播放失败:', error);
});
}
}
}, [currentSketchIndex]);
// 音量设置变化时应用到所有视频
useEffect(() => {
if (mainVideoRef.current) {
applyVolumeSettings(mainVideoRef.current);
}
if (finalVideoRef.current) {
applyVolumeSettings(finalVideoRef.current);
}
}, [volume, isMuted]);
// 监听全屏状态变化
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement);
};
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
document.addEventListener('msfullscreenchange', handleFullscreenChange);
return () => {
document.removeEventListener('fullscreenchange', handleFullscreenChange);
document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);
document.removeEventListener('msfullscreenchange', handleFullscreenChange);
};
}, []);
// 组件卸载时清理视频状态
useEffect(() => {
return () => {
// 清理最终视频状态
setFinalVideoReady(false);
if (finalVideoRef.current) {
finalVideoRef.current.pause();
}
};
}, []);
// 渲染音量控制组件
const renderVolumeControls = () => (
<div className="flex items-center gap-2">
{/* 静音按钮 */}
<GlassIconButton
icon={isMuted ? VolumeX : Volume2}
tooltip={isMuted ? "取消静音" : "静音"}
onClick={toggleMute}
size="sm"
/>
{/* 音量滑块 - 一直显示 */}
<div className="flex items-center gap-2">
<div className="relative">
<input
type="range"
min="0"
max="1"
step="0.1"
value={volume}
onChange={(e) => handleVolumeChange(parseFloat(e.target.value))}
className="w-16 h-1 bg-white/20 rounded-lg appearance-none cursor-pointer
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white
[&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:shadow-lg
[&::-moz-range-thumb]:w-3 [&::-moz-range-thumb]:h-3 [&::-moz-range-thumb]:rounded-full
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:cursor-pointer
[&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:shadow-lg"
style={{
background: `linear-gradient(to right, white 0%, white ${volume * 100}%, rgba(255,255,255,0.2) ${volume * 100}%, rgba(255,255,255,0.2) 100%)`
}}
/>
</div>
<span className="text-xs text-white/70 w-8 text-center">
{Math.round(volume * 100)}%
</span>
</div>
</div>
);
// 渲染最终成片
const renderFinalVideo = (currentStep: string) => {
// 使用真实的final数据如果没有则使用默认值
const finalVideo = final || {
url: 'https://cdn.qikongjian.com/videos/1750389908_37d4fffa-8516-43a3-a423-fc0274f40e8a_text_to_video_0.mp4'
};
return (
<div
className="relative w-full h-full rounded-lg overflow-hidden"
key={`render-video-${currentStep}`}
onMouseEnter={() => onControlsChange(true)}
onMouseLeave={() => onControlsChange(false)}
>
<div className="relative w-full h-full">
{/* 背景模糊的视频 */}
<motion.div
className="absolute inset-0 overflow-hidden"
initial={{ filter: "blur(0px)", scale: 1, opacity: 1 }}
animate={{ filter: "blur(20px)", scale: 1.1, opacity: 0.5 }}
transition={{ duration: 0.8, ease: "easeInOut" }}
>
<video
className="w-full h-full rounded-lg object-cover object-center"
src={taskVideos[currentSketchIndex]?.url}
loop
playsInline
muted
/>
</motion.div>
{/* 最终成片视频 */}
<motion.div
initial={{ clipPath: "inset(0 50% 0 50%)", filter: "blur(10px)" }}
animate={{ clipPath: "inset(0 0% 0 0%)", filter: "blur(0px)" }}
transition={{
clipPath: { duration: 1.2, ease: [0.43, 0.13, 0.23, 0.96] },
filter: { duration: 0.6, delay: 0.3 }
}}
className="relative z-10 w-full h-full"
>
<video
ref={finalVideoRef}
className="w-full h-full object-cover rounded-lg"
src={finalVideo.url}
autoPlay={isFinalVideoPlaying}
loop
playsInline
preload="metadata"
poster={`${finalVideo.url}?vframe/jpg/offset/1`}
onLoadedData={handleFinalVideoLoaded}
onPlay={() => setIsFinalVideoPlaying(true)}
onPause={() => setIsFinalVideoPlaying(false)}
onClick={handleVideoClick}
/>
</motion.div>
{/* 操作按钮组 */}
<AnimatePresence>
{showControls && (
<motion.div
className="absolute top-4 right-4 z-10 flex gap-2"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
>
<GlassIconButton
icon={Edit3}
tooltip="Edit sketch"
onClick={() => handleEditClick('4')}
/>
</motion.div>
)}
</AnimatePresence>
{/* 视频信息浮层 */}
<motion.div
className="absolute bottom-0 left-0 right-0 z-10 p-4 bg-gradient-to-t from-black/80 via-black/40 to-transparent"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1, duration: 0.6 }}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<motion.div
className="w-2 h-2 rounded-full bg-emerald-500"
animate={{
scale: [1, 1.2, 1],
opacity: [1, 0.6, 1]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<span className="text-sm font-medium text-white/90">{currentStep === '6' ? 'Final product' : 'Trailer Video'}</span>
</div>
</div>
</motion.div>
{/* 底部控制区域 */}
<motion.div
className="absolute bottom-16 left-4 z-10 flex items-center gap-3"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 1, duration: 0.6 }}
>
{/* 播放/暂停按钮 */}
<motion.div
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className="relative"
>
{/* 播放时的发光效果 */}
{isFinalVideoPlaying && (
<motion.div
className="absolute inset-0 rounded-full blur-md"
animate={{
scale: [1, 1.2, 1],
opacity: [0.5, 0.8, 0.5]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
)}
<GlassIconButton
icon={isFinalVideoPlaying ? Pause : Play}
tooltip={isFinalVideoPlaying ? "Pause video" : "Play video"}
onClick={toggleFinalVideoPlay}
size="sm"
/>
</motion.div>
{/* 音量控制 */}
{renderVolumeControls()}
{/* 全屏按钮 */}
<GlassIconButton
icon={isFullscreen ? Minimize : Maximize}
tooltip={isFullscreen ? "退出全屏" : "全屏"}
onClick={toggleFullscreen}
size="sm"
/>
</motion.div>
{/* 完成标记 */}
<motion.div
className="absolute top-4 right-4 px-3 py-1.5 rounded-full bg-emerald-500/20 backdrop-blur-sm
border border-emerald-500/30 text-emerald-400 text-sm font-medium"
initial={{ opacity: 0, scale: 0.8, x: 20 }}
animate={{ opacity: 1, scale: 1, x: 0 }}
transition={{ delay: 1.2, duration: 0.6 }}
>
Task completed
</motion.div>
</div>
</div>
);
};
// 渲染视频内容
const renderVideoContent = () => {
const currentSketch = taskSketch[currentSketchIndex];
const defaultBgColors = ['RGB(45, 50, 70)', 'RGB(75, 80, 100)', 'RGB(105, 110, 130)'];
const bgColors = currentSketch?.bg_rgb || defaultBgColors;
return (
<div
className="relative w-full h-full rounded-lg"
onMouseEnter={() => onControlsChange(true)}
onMouseLeave={() => onControlsChange(false)}
>
{/* 只在生成过程中或没有视频时使用ProgressiveReveal */}
{(isGeneratingVideo || !taskVideos[currentSketchIndex]) ? (
taskVideos[currentSketchIndex] ? (
<ProgressiveReveal
key={`generte-video-${currentSketchIndex}`}
className="w-full h-full rounded-lg"
revealDuration={0.8}
blurDuration={0.3}
initialBlur={10}
customVariants={{
hidden: {
opacity: 0,
scale: 0.9,
filter: "blur(30px)",
clipPath: "inset(0 100% 0 0)"
},
visible: {
opacity: 1,
scale: 1,
filter: "blur(0px)",
clipPath: "inset(0 0% 0 0)",
transition: {
duration: 1.5,
ease: [0.23, 1, 0.32, 1],
opacity: { duration: 0.8, ease: "easeOut" },
scale: { duration: 1.2, ease: "easeOut" },
filter: { duration: 0.8, delay: 0.4, ease: "easeOut" },
clipPath: { duration: 1, ease: "easeInOut" }
}
}
}}
loadingBgConfig={{
fromColor: `from-[${bgColors[0]}]`,
viaColor: `via-[${bgColors[1]}]`,
toColor: `to-[${bgColors[2]}]`,
glowOpacity: 0.8,
duration: 4,
}}
>
<div className="relative w-full h-full">
{/* 背景模糊的图片 */}
<div className="absolute inset-0 overflow-hidden">
<img
className="w-full h-full object-cover filter blur-lg scale-110 opacity-50"
src={taskSketch[currentSketchIndex]?.url}
alt="background"
/>
</div>
{/* 视频 */}
<motion.div
initial={{ clipPath: "inset(0 100% 0 0)" }}
animate={{ clipPath: "inset(0 0% 0 0)" }}
transition={{ duration: 0.8, ease: [0.43, 0.13, 0.23, 0.96] }}
className="relative z-10 w-full h-full"
>
<video
ref={mainVideoRef}
key={taskVideos[currentSketchIndex].url}
className="w-full h-full rounded-lg object-cover object-center relative z-10"
src={taskVideos[currentSketchIndex].url}
autoPlay={isVideoPlaying}
loop={true}
playsInline
onLoadedData={() => applyVolumeSettings(mainVideoRef.current!)}
onEnded={() => {
if (isVideoPlaying) {
// 自动切换到下一个视频的逻辑在父组件处理
}
}}
/>
</motion.div>
</div>
</ProgressiveReveal>
) : (
<div className="w-full h-full flex items-center justify-center rounded-lg overflow-hidden relative">
<img
className="absolute inset-0 w-full h-full object-cover"
src={taskSketch[currentSketchIndex]?.url}
alt={`Sketch ${currentSketchIndex + 1}`}
/>
</div>
)
) : (
/* 生成完成后直接显示视频不使用ProgressiveReveal */
<div className="relative w-full h-full">
{/* 视频 修复播放没有声音 */}
<video
ref={mainVideoRef}
key={taskVideos[currentSketchIndex].url}
className="w-full h-full rounded-lg object-cover object-center relative z-10"
src={taskVideos[currentSketchIndex].url}
autoPlay={isVideoPlaying}
loop={true}
playsInline
onLoadedData={() => applyVolumeSettings(mainVideoRef.current!)}
onEnded={() => {
if (isVideoPlaying) {
// 自动切换到下一个视频的逻辑在父组件处理
}
}}
/>
</div>
)}
{/* 操作按钮组 */}
<AnimatePresence>
{showControls && (
<motion.div
className="absolute top-4 right-4 flex gap-2 z-[11]"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
>
<GlassIconButton
icon={Edit3}
tooltip="Edit sketch"
onClick={() => handleEditClick('3')}
/>
</motion.div>
)}
</AnimatePresence>
{/* 底部控制区域 */}
{ taskVideos[currentSketchIndex] && (
<AnimatePresence>
<motion.div
className="absolute bottom-4 left-4 z-[11] flex items-center gap-3"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
>
{/* 播放按钮 */}
<motion.div
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className="relative"
>
{/* 播放时的发光效果 */}
{isVideoPlaying && (
<motion.div
className="absolute inset-0 rounded-full blur-md"
animate={{
scale: [1, 1.2, 1],
opacity: [0.5, 0.8, 0.5]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
)}
<GlassIconButton
icon={isVideoPlaying ? Pause : Play}
tooltip={isVideoPlaying ? "Pause video" : "Play video"}
onClick={onToggleVideoPlay}
size="sm"
/>
</motion.div>
{/* 音量控制 */}
{renderVolumeControls()}
</motion.div>
</AnimatePresence>
)}
</div>
);
};
// 渲染分镜草图
const renderSketchContent = () => {
const currentSketch = taskSketch[currentSketchIndex];
const defaultBgColors = ['RGB(45, 50, 70)', 'RGB(75, 80, 100)', 'RGB(105, 110, 130)'];
const bgColors = currentSketch?.bg_rgb || defaultBgColors;
return (
<div
className="relative w-full h-full rounded-lg"
onMouseEnter={() => onControlsChange(true)}
onMouseLeave={() => onControlsChange(false)}
>
{/* 只在生成过程中或没有分镜图片时使用ProgressiveReveal */}
{(isGeneratingSketch || !currentSketch) ? (
currentSketch ? (
<ProgressiveReveal
key={`sketch-generating-${currentSketchIndex}`}
className="w-full h-full rounded-lg"
revealDuration={0.8}
blurDuration={0.3}
initialBlur={10}
customVariants={{
hidden: {
opacity: 0,
scale: 0.9,
filter: "blur(30px)"
},
visible: {
opacity: 1,
scale: 1,
filter: "blur(0px)",
transition: {
duration: 1.5,
ease: [0.23, 1, 0.32, 1],
opacity: { duration: 0.8, ease: "easeOut" },
scale: { duration: 1.2, ease: "easeOut" },
filter: { duration: 0.8, delay: 0.4, ease: "easeOut" }
}
}
}}
loadingBgConfig={{
fromColor: `from-[${bgColors[0]}]`,
viaColor: `via-[${bgColors[1]}]`,
toColor: `to-[${bgColors[2]}]`,
glowOpacity: 0.8,
duration: 4,
}}
>
<img
key={currentSketchIndex}
src={currentSketch.url}
alt={`Sketch ${currentSketchIndex + 1}`}
className="w-full h-full rounded-lg object-cover"
/>
</ProgressiveReveal>
) : (
<div className="w-full h-full flex items-center justify-center rounded-lg overflow-hidden relative">
{/* 动态渐变背景 */}
<motion.div
className={`absolute inset-0 bg-gradient-to-r from-[${bgColors[0]}] via-[${bgColors[1]}] to-[${bgColors[2]}]`}
animate={{
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "linear"
}}
style={{
backgroundSize: "200% 200%",
}}
/>
{/* 动态光效 */}
<motion.div
className="absolute inset-0 opacity-50"
style={{
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
}}
animate={{
scale: [1, 1.2, 1],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<motion.div
className="flex flex-col items-center gap-4 relative z-10"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<div className="relative">
<motion.div
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
animate={{
scale: [1, 1.2, 1],
rotate: [0, 180, 360],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "linear"
}}
/>
</div>
</motion.div>
</div>
)
) : (
/* 生成完成后直接显示图片不使用ProgressiveReveal */
<img
key={currentSketchIndex}
src={currentSketch.url}
alt={`NG-Sketch ${currentSketchIndex + 1}`}
className="w-full h-full rounded-lg object-cover"
/>
)}
{/* 操作按钮组 */}
<AnimatePresence>
{showControls && (
<motion.div
className="absolute top-4 right-4 flex gap-2"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
>
<GlassIconButton
icon={Edit3}
tooltip="Edit sketch"
onClick={() => handleEditClick('2')}
/>
</motion.div>
)}
</AnimatePresence>
{/* 底部播放按钮 */}
<AnimatePresence>
<motion.div
className="absolute bottom-4 left-4"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.2 }}
>
<motion.div
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className="relative"
>
{/* 播放时的发光效果 */}
{isPlaying && (
<motion.div
className="absolute inset-0 rounded-full bg-blue-500/30 blur-md"
animate={{
scale: [1, 1.2, 1],
opacity: [0.5, 0.8, 0.5]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
)}
<GlassIconButton
icon={isPlaying ? Pause : Play}
tooltip={isPlaying ? "Pause auto play" : "Start auto play"}
onClick={onTogglePlay}
size="sm"
className={isPlaying ? "border-blue-500/50 bg-blue-500/10" : ""}
/>
</motion.div>
</motion.div>
</AnimatePresence>
</div>
);
};
// 渲染剧本
const renderScriptContent = () => {
return (
<div className="relative w-full h-full bg-white/10 rounded-lg overflow-hidden p-2">
{
mockScriptData ? (
<ScriptRenderer data={mockScriptData} />
) : (
<div className="flex gap-2 w-full h-full">
<div className="w-[70%] h-full rounded-lg gap-2 flex flex-col">
<Skeleton className="w-full h-[33%] rounded-lg" />
<Skeleton className="w-full h-[33%] rounded-lg" />
<Skeleton className="w-full h-[33%] rounded-lg" />
</div>
<div className="w-[30%] h-full rounded-lg">
<Skeleton className="w-full h-full rounded-lg" />
</div>
</div>
)
}
</div>
);
};
// 根据当前步骤渲染对应内容
if (Number(currentStep) === 6 || Number(currentStep) === 5.5) {
return renderFinalVideo(currentStep);
}
if (Number(currentStep) > 2 && Number(currentStep) < 6) {
return renderVideoContent();
}
if (Number(currentStep) === 0) {
return renderScriptContent();
}
return renderSketchContent();
}