3-调整动画

This commit is contained in:
北枳 2025-06-29 01:34:20 +08:00
parent 8d85eee872
commit 39c5e99c88
2 changed files with 380 additions and 454 deletions

View File

@ -58,7 +58,7 @@
overflow: hidden; overflow: hidden;
} }
.videoContainer-qteKNi { .videoContainer-qteKNi {
flex: 3; /* flex: 3; */
min-height: 0; min-height: 0;
display: flex display: flex
; ;

View File

@ -524,46 +524,114 @@ export default function WorkFlow() {
}, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length]); }, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length]);
const renderSketchContent = () => { const renderSketchContent = () => {
if (!taskObject) {
// 展示最终成片
if (Number(currentStep) === 6) {
return ( return (
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-black/40 via-black/20 to-black/40 backdrop-blur-sm rounded-lg overflow-hidden"> <div className="relative w-full h-full rounded-lg overflow-hidden" onMouseEnter={() => setShowControls(true)} onMouseLeave={() => setShowControls(false)}>
<motion.div <div className="relative w-full h-full">
className="flex flex-col items-center gap-4" {/* 背景模糊的视频 */}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<motion.div <motion.div
animate={{ className="absolute inset-0 overflow-hidden"
scale: [1, 1.2, 1], initial={{ filter: "blur(0px)", scale: 1, opacity: 1 }}
rotate: [0, 360], animate={{ filter: "blur(20px)", scale: 1.1, opacity: 0.5 }}
}} transition={{ duration: 0.8, ease: "easeInOut" }}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
> >
<Loader2 className="w-8 h-8 text-blue-500" /> <video
className="w-full h-full rounded-lg object-cover object-center"
src={taskVideos[currentSketchIndex]?.url}
autoPlay
loop
muted
playsInline
/>
</motion.div> </motion.div>
<motion.p
className="text-sm text-white/70" {/* 最终成片视频 */}
animate={{ <motion.div
opacity: [0.5, 1, 0.5], initial={{ clipPath: "inset(0 50% 0 50%)", filter: "blur(10px)" }}
}} animate={{ clipPath: "inset(0 0% 0 0%)", filter: "blur(0px)" }}
transition={{ transition={{
duration: 2, clipPath: { duration: 1.2, ease: [0.43, 0.13, 0.23, 0.96] },
repeat: Infinity, filter: { duration: 0.6, delay: 0.3 }
ease: "linear"
}} }}
className="relative z-10"
> >
... <video
</motion.p> className="w-full h-full object-cover rounded-lg"
</motion.div> src={MOCK_FINAL_VIDEO.url}
poster={MOCK_FINAL_VIDEO.thumbnail}
autoPlay
loop
muted
playsInline
/>
</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="编辑分镜"
onClick={() => handleEditModalOpen('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"></span>
</div>
</div>
</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 }}
>
</motion.div>
</div>
</div> </div>
); );
} }
// 展示分镜视频
if (Number(currentStep) > 2 && Number(currentStep) < 6) { if (Number(currentStep) > 2 && Number(currentStep) < 6) {
return ( return (
<div <div
@ -574,102 +642,71 @@ export default function WorkFlow() {
{taskVideos[currentSketchIndex] ? ( {taskVideos[currentSketchIndex] ? (
<ProgressiveReveal <ProgressiveReveal
className="w-full h-full rounded-lg" className="w-full h-full rounded-lg"
{...presets.main} customVariants={{
> hidden: {
<video opacity: 0,
ref={mainVideoRef} filter: "blur(20px)",
key={taskVideos[currentSketchIndex].url} clipPath: "inset(0 100% 0 0)"
className="w-full h-full rounded-lg object-cover object-center" },
src={taskVideos[currentSketchIndex].url} visible: {
autoPlay={isVideoPlaying} opacity: 1,
muted filter: "blur(0px)",
loop={false} clipPath: "inset(0 0% 0 0)",
playsInline transition: {
poster={taskSketch[currentSketchIndex]?.url} duration: 1,
onEnded={() => { ease: [0.43, 0.13, 0.23, 0.96],
if (isVideoPlaying) { opacity: { duration: 0.8, ease: "easeOut" },
setCurrentSketchIndex(prev => (prev + 1) % taskVideos.length); filter: { duration: 0.6, ease: "easeOut" },
clipPath: { duration: 0.8, ease: "easeInOut" }
} }
}} }
/> }}
>
<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"
>
<video
ref={mainVideoRef}
key={taskVideos[currentSketchIndex].url}
className="w-full h-full rounded-lg object-cover object-center"
src={taskVideos[currentSketchIndex].url}
autoPlay={isVideoPlaying}
muted
loop={false}
playsInline
poster={taskSketch[currentSketchIndex]?.url}
onEnded={() => {
if (isVideoPlaying) {
setCurrentSketchIndex(prev => (prev + 1) % taskVideos.length);
}
}}
/>
</motion.div>
</div>
</ProgressiveReveal> </ProgressiveReveal>
) : ( ) : (
<div className="w-full h-full flex items-center justify-center rounded-lg overflow-hidden relative"> <div className="w-full h-full flex items-center justify-center rounded-lg overflow-hidden relative">
{/* 动态渐变背景 */} {/* 保持显示当前分镜草图 */}
<motion.div <img
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500" className="absolute inset-0 w-full h-full object-cover"
animate={{ src={taskSketch[currentSketchIndex]?.url}
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"], alt={`分镜草图 ${currentSketchIndex + 1}`}
}}
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"
}}
/>
<motion.div
animate={{
rotate: [0, 360],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
>
</motion.div>
</div>
<motion.p
className="text-sm text-white font-medium"
animate={{
opacity: [0.7, 1, 0.7],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
>
{taskVideos.length + 1}/{taskSketch.length}
</motion.p>
</motion.div>
</div> </div>
)} )}
@ -690,11 +727,6 @@ export default function WorkFlow() {
tooltip="编辑分镜" tooltip="编辑分镜"
onClick={() => handleEditModalOpen('3')} onClick={() => handleEditModalOpen('3')}
/> />
{/* <GlassIconButton
icon={FileText}
tooltip="显示脚本"
onClick={() => console.log('显示脚本')}
/> */}
</motion.div> </motion.div>
</> </>
)} )}
@ -726,101 +758,7 @@ export default function WorkFlow() {
); );
} }
// 展示最终成片 // 展示分镜草图
if (Number(currentStep) === 6) {
return (
<div className="relative w-full h-full rounded-lg overflow-hidden">
<ProgressiveReveal
className="w-full h-full rounded-lg"
customVariants={{
hidden: {
opacity: 0,
filter: "blur(20px)",
clipPath: "inset(0 50% 0 50%)"
},
visible: {
opacity: 1,
filter: "blur(0px)",
clipPath: "inset(0 0% 0 0%)",
transition: {
duration: 1.2,
ease: [0.43, 0.13, 0.23, 0.96], // 自定义缓动函数
opacity: { duration: 0.8, ease: "easeOut" },
filter: { duration: 0.6, ease: "easeOut" },
clipPath: { duration: 1, ease: "easeInOut", delay: 0.2 }
}
}
}}
loadingBgConfig={{
fromColor: 'from-emerald-300',
viaColor: 'via-cyan-400',
toColor: 'to-blue-500',
glowOpacity: 0.6,
duration: 6
}}
>
<div className="relative w-full h-full">
{/* 最终成片视频 */}
<video
className="w-full h-full object-cover rounded-lg"
src={MOCK_FINAL_VIDEO.url}
poster={MOCK_FINAL_VIDEO.thumbnail}
autoPlay
loop
muted
playsInline
/>
{/* 视频信息浮层 */}
<motion.div
className="absolute bottom-0 left-0 right-0 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"></span>
</div>
<div className="flex items-center gap-2">
<GlassIconButton
icon={Edit3}
tooltip="编辑成片"
onClick={() => handleEditModalOpen('4')}
size="sm"
/>
</div>
</div>
</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 }}
>
</motion.div>
</div>
</ProgressiveReveal>
</div>
);
}
return ( return (
<div <div
className="relative w-full h-full rounded-lg" className="relative w-full h-full rounded-lg"
@ -890,31 +828,7 @@ export default function WorkFlow() {
ease: "linear" ease: "linear"
}} }}
/> />
<motion.div
animate={{
rotate: [0, 360],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
>
</motion.div>
</div> </div>
<motion.p
className="text-sm text-white font-medium"
animate={{
opacity: [0.7, 1, 0.7],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
>
{sketchCount + 1}/{MOCK_SKETCH_COUNT}
</motion.p>
</motion.div> </motion.div>
</div> </div>
)} )}
@ -936,11 +850,6 @@ export default function WorkFlow() {
tooltip="编辑分镜" tooltip="编辑分镜"
onClick={() => handleEditModalOpen('1')} onClick={() => handleEditModalOpen('1')}
/> />
{/* <GlassIconButton
icon={FileText}
tooltip="显示脚本"
onClick={() => console.log('显示脚本')}
/> */}
</motion.div> </motion.div>
</> </>
)} )}
@ -969,7 +878,6 @@ export default function WorkFlow() {
</motion.div> </motion.div>
</AnimatePresence> </AnimatePresence>
{/* 播放进度指示器 */} {/* 播放进度指示器 */}
<AnimatePresence> <AnimatePresence>
{isPlaying && ( {isPlaying && (
@ -1003,67 +911,122 @@ export default function WorkFlow() {
<> <>
<div className="title-JtMejk">{taskObject?.projectName}{taskObject?.taskName}</div> <div className="title-JtMejk">{taskObject?.projectName}{taskObject?.taskName}</div>
{/* 实时反馈当前 currentLoadingText */} {/* 实时反馈当前 currentLoadingText */}
<motion.div {currentLoadingText === '任务完成' ? (
className="flex items-center gap-2 justify-center"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<motion.div <motion.div
className="w-1.5 h-1.5 rounded-full bg-blue-500" className="flex items-center gap-3 justify-center"
animate={{ initial={{ opacity: 0, y: -10 }}
scale: [1, 1.5, 1], animate={{ opacity: 1, y: 0 }}
opacity: [1, 0.5, 1] transition={{ duration: 0.5 }}
}} >
transition={{ <motion.div
duration: 1, className="w-2 h-2 rounded-full bg-emerald-500"
repeat: Infinity, animate={{
repeatDelay: 0.2 scale: [1, 1.5, 1],
}} opacity: [1, 0.5, 1]
/> }}
<motion.p transition={{
className="normalS400 subtitle-had8uE text-blue-500/80" duration: 1,
key={currentLoadingText} repeat: Infinity,
initial={{ opacity: 0, x: -10 }} repeatDelay: 0.2
animate={{ opacity: 1, x: 0 }} }}
exit={{ opacity: 0, x: 10 }} />
<motion.div
className="flex items-center gap-1.5"
initial="hidden"
animate="visible"
variants={{
hidden: { opacity: 0 },
visible: { opacity: 1 }
}}
>
<motion.span
className="text-emerald-500 font-medium"
variants={{
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
}}
transition={{ duration: 0.5 }}
>
{currentLoadingText}
</motion.span>
</motion.div>
<motion.div
className="w-2 h-2 rounded-full bg-emerald-500"
animate={{
scale: [1, 1.5, 1],
opacity: [1, 0.5, 1]
}}
transition={{
duration: 1,
repeat: Infinity,
repeatDelay: 0.2,
delay: 0.3
}}
/>
</motion.div>
) : (
<motion.div
className="flex items-center gap-2 justify-center"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }} transition={{ duration: 0.3 }}
> >
{currentLoadingText} <motion.div
</motion.p> className="w-1.5 h-1.5 rounded-full bg-blue-500"
<motion.div animate={{
className="w-1.5 h-1.5 rounded-full bg-blue-500" scale: [1, 1.5, 1],
animate={{ opacity: [1, 0.5, 1]
scale: [1, 1.5, 1], }}
opacity: [1, 0.5, 1] transition={{
}} duration: 1,
transition={{ repeat: Infinity,
duration: 1, repeatDelay: 0.2
repeat: Infinity, }}
repeatDelay: 0.2, />
delay: 0.3 <motion.p
}} className="normalS400 subtitle-had8uE text-blue-500/80"
/> key={currentLoadingText}
<motion.div initial={{ opacity: 0, x: -10 }}
className="w-1.5 h-1.5 rounded-full bg-blue-500" animate={{ opacity: 1, x: 0 }}
animate={{ exit={{ opacity: 0, x: 10 }}
scale: [1, 1.5, 1], transition={{ duration: 0.3 }}
opacity: [1, 0.5, 1] >
}} {currentLoadingText}
transition={{ </motion.p>
duration: 1, <motion.div
repeat: Infinity, className="w-1.5 h-1.5 rounded-full bg-blue-500"
repeatDelay: 0.2, animate={{
delay: 0.6 scale: [1, 1.5, 1],
}} opacity: [1, 0.5, 1]
/> }}
</motion.div> transition={{
duration: 1,
repeat: Infinity,
repeatDelay: 0.2,
delay: 0.3
}}
/>
<motion.div
className="w-1.5 h-1.5 rounded-full bg-blue-500"
animate={{
scale: [1, 1.5, 1],
opacity: [1, 0.5, 1]
}}
transition={{
duration: 1,
repeat: Infinity,
repeatDelay: 0.2,
delay: 0.6
}}
/>
</motion.div>
)}
</> </>
)} )}
</div> </div>
</div> </div>
<div className="media-Ocdu1O"> <div className="media-Ocdu1O">
<div className="videoContainer-qteKNi" ref={containerRef}> <div className="videoContainer-qteKNi" style={currentStep !== '6' ? { flex: 3 } : {}} ref={containerRef}>
{isLoading ? ( {isLoading ? (
<Skeleton className="w-full aspect-video rounded-lg" /> <Skeleton className="w-full aspect-video rounded-lg" />
) : ( ) : (
@ -1091,169 +1054,132 @@ export default function WorkFlow() {
onMouseUp={handleMouseUp} onMouseUp={handleMouseUp}
onMouseLeave={() => setIsDragging(false)} onMouseLeave={() => setIsDragging(false)}
> >
{(Number(currentStep) > 2 && Number(currentStep) < 6) ? ( {Number(currentStep) === 6 ? null : (
<> <>
{renderedVideos} {(Number(currentStep) > 2 && Number(currentStep) < 6) ? (
{isGeneratingVideo && taskVideos.length < taskSketch.length && ( <>
<motion.div {taskSketch.map((sketch, index) => (
className="relative aspect-video rounded-lg overflow-hidden" <div
initial={{ opacity: 0, scale: 0.8 }} key={`video-${index}`}
animate={{ opacity: 1, scale: 1 }} className={`relative aspect-video rounded-lg overflow-hidden
transition={{ duration: 0.3 }} ${currentSketchIndex === index ? 'ring-2 ring-blue-500 z-10' : 'hover:ring-2 hover:ring-blue-500/50'}`}
> onClick={() => !isDragging && setCurrentSketchIndex(index)}
{/* 动态渐变背景 */} >
<motion.div <ProgressiveReveal
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500" {...presets.thumbnail}
animate={{ delay={index * 0.1}
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"], customVariants={{
}} hidden: {
transition={{ opacity: 0,
duration: 5, scale: 0.95,
repeat: Infinity, filter: "blur(10px)"
ease: "linear" },
}} visible: {
style={{ opacity: 1,
backgroundSize: "200% 200%", scale: 1,
}} filter: "blur(0px)",
/> transition: {
{/* 动态光效 */} duration: 0.8,
<motion.div ease: [0.23, 1, 0.32, 1],
className="absolute inset-0 opacity-50" opacity: { duration: 0.6, ease: "easeInOut" },
style={{ scale: { duration: 1, ease: "easeOut" },
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)", filter: { duration: 0.8, ease: "easeOut", delay: 0.2 }
}} }
animate={{ }
scale: [1, 1.2, 1], }}
}} loadingBgConfig={{
transition={{ ...presets.thumbnail.loadingBgConfig,
duration: 2, glowOpacity: 0.4,
repeat: Infinity, duration: 4
ease: "easeInOut" }}
}} >
/> <div className="w-full h-full transform hover:scale-105 transition-transform duration-500">
<div className="absolute inset-0 flex items-center justify-center"> {taskVideos[index] ? (
<div className="relative"> <video
className="w-full h-full object-cover"
src={taskVideos[index].url}
muted
playsInline
loop
poster={sketch.url}
/>
) : (
<img
className="w-full h-full object-cover"
src={sketch.url}
alt={`缩略图 ${index + 1}`}
/>
)}
</div>
</ProgressiveReveal>
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
<span className="text-xs text-white/90"> {index + 1}</span>
</div>
</div>
))}
</>
) : (
<>
{renderedSketches}
{isGeneratingSketch && sketchCount < MOCK_SKETCH_COUNT && (
<motion.div
className="relative aspect-video rounded-lg overflow-hidden"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.3 }}
>
{/* 动态渐变背景 */}
<motion.div <motion.div
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl" className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
animate={{ animate={{
scale: [1, 1.2, 1], backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
rotate: [0, 180, 360],
}} }}
transition={{ transition={{
duration: 4, duration: 5,
repeat: Infinity, repeat: Infinity,
ease: "linear" ease: "linear"
}} }}
style={{
backgroundSize: "200% 200%",
}}
/> />
{/* 动态光效 */}
<motion.div <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={{ animate={{
rotate: [0, 360], scale: [1, 1.2, 1],
}} }}
transition={{ transition={{
duration: 2, duration: 2,
repeat: Infinity, repeat: Infinity,
ease: "linear" ease: "easeInOut"
}}
>
</motion.div>
</div>
</div>
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
<span className="text-xs text-white/90"> {taskVideos.length + 1}</span>
</div>
</motion.div>
)}
</>
) : Number(currentStep) === 6 ? (
<motion.div
className="relative aspect-video rounded-lg overflow-hidden"
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6, delay: 1.4 }}
>
<video
className="w-full h-full object-cover"
src={MOCK_FINAL_VIDEO.url}
poster={MOCK_FINAL_VIDEO.thumbnail}
muted
playsInline
loop
/>
<div className="absolute inset-0 flex items-center justify-center bg-black/40 backdrop-blur-sm">
<span className="text-sm font-medium text-white"></span>
</div>
</motion.div>
) : (
<>
{renderedSketches}
{isGeneratingSketch && sketchCount < MOCK_SKETCH_COUNT && (
<motion.div
className="relative aspect-video rounded-lg overflow-hidden"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.3 }}
>
{/* 动态渐变背景 */}
<motion.div
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
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"
}}
/>
<div className="absolute inset-0 flex items-center justify-center">
<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"
}} }}
/> />
<motion.div <div className="absolute inset-0 flex items-center justify-center">
animate={{ <div className="relative">
rotate: [0, 360], <motion.div
}} className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
transition={{ animate={{
duration: 2, scale: [1, 1.2, 1],
repeat: Infinity, rotate: [0, 180, 360],
ease: "linear" }}
}} transition={{
> duration: 4,
</motion.div> repeat: Infinity,
</div> ease: "linear"
</div> }}
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent"> />
<span className="text-xs text-white/90"> {sketchCount + 1}</span> </div>
</div> </div>
</motion.div> <div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
<span className="text-xs text-white/90"> {sketchCount + 1}</span>
</div>
</motion.div>
)}
</>
)} )}
</> </>
)} )}