forked from 77media/video-flow
218 lines
6.5 KiB
TypeScript
218 lines
6.5 KiB
TypeScript
'use client';
|
||
|
||
import React from 'react';
|
||
import { motion } from 'framer-motion';
|
||
import { Skeleton } from '@/components/ui/skeleton';
|
||
|
||
interface TaskInfoProps {
|
||
isLoading: boolean;
|
||
taskObject: any;
|
||
currentLoadingText: string;
|
||
}
|
||
|
||
export function TaskInfo({ isLoading, taskObject, currentLoadingText }: TaskInfoProps) {
|
||
if (isLoading) {
|
||
return (
|
||
<>
|
||
<Skeleton className="h-8 w-64 mb-2" />
|
||
<Skeleton className="h-4 w-96" />
|
||
</>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<div className="title-JtMejk">
|
||
{taskObject?.projectName}:{taskObject?.taskName}
|
||
</div>
|
||
|
||
{currentLoadingText === 'Task completed' ? (
|
||
<motion.div
|
||
className="flex items-center gap-3 justify-center"
|
||
initial={{ opacity: 0, y: -10 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.5 }}
|
||
>
|
||
<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
|
||
}}
|
||
/>
|
||
<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 }}
|
||
>
|
||
<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
|
||
}}
|
||
/>
|
||
<motion.div
|
||
className="relative"
|
||
key={currentLoadingText}
|
||
initial={{ opacity: 0, x: -10 }}
|
||
animate={{ opacity: 1, x: 0 }}
|
||
exit={{ opacity: 0, x: 10 }}
|
||
transition={{ duration: 0.3 }}
|
||
>
|
||
{/* 背景发光效果 */}
|
||
<motion.div
|
||
className="absolute inset-0 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-purple-400 blur-sm"
|
||
animate={{
|
||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||
}}
|
||
transition={{
|
||
duration: 2,
|
||
repeat: Infinity,
|
||
ease: "linear"
|
||
}}
|
||
style={{
|
||
backgroundSize: "200% 200%",
|
||
}}
|
||
>
|
||
<span className="normalS400 subtitle-had8uE">{currentLoadingText}</span>
|
||
</motion.div>
|
||
|
||
{/* 主文字 - 颜色填充动画 */}
|
||
<motion.div
|
||
className="relative z-10"
|
||
animate={{
|
||
scale: [1, 1.02, 1],
|
||
}}
|
||
transition={{
|
||
duration: 1.5,
|
||
repeat: Infinity,
|
||
ease: "easeInOut"
|
||
}}
|
||
>
|
||
<motion.span
|
||
className="normalS400 subtitle-had8uE text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-cyan-500 to-purple-600"
|
||
animate={{
|
||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||
}}
|
||
transition={{
|
||
duration: 3,
|
||
repeat: Infinity,
|
||
ease: "linear"
|
||
}}
|
||
style={{
|
||
backgroundSize: "300% 300%",
|
||
}}
|
||
>
|
||
{currentLoadingText}
|
||
</motion.span>
|
||
</motion.div>
|
||
|
||
{/* 动态光点效果 */}
|
||
<motion.div
|
||
className="absolute left-0 top-1/2 transform -translate-y-1/2 w-2 h-2 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full blur-sm"
|
||
animate={{
|
||
x: [0, 200, 0],
|
||
opacity: [0, 1, 0],
|
||
scale: [0.5, 1, 0.5],
|
||
}}
|
||
transition={{
|
||
duration: 2.5,
|
||
repeat: Infinity,
|
||
ease: "easeInOut",
|
||
}}
|
||
/>
|
||
|
||
{/* 文字底部装饰线 */}
|
||
<motion.div
|
||
className="absolute bottom-0 left-0 h-0.5 bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500"
|
||
animate={{
|
||
width: ["0%", "100%", "0%"],
|
||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||
}}
|
||
transition={{
|
||
width: { duration: 2, repeat: Infinity, ease: "easeInOut" },
|
||
backgroundPosition: { duration: 1.5, repeat: Infinity, ease: "linear" }
|
||
}}
|
||
style={{
|
||
backgroundSize: "200% 200%",
|
||
}}
|
||
/>
|
||
</motion.div>
|
||
<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.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>
|
||
)}
|
||
</>
|
||
);
|
||
}
|