81 lines
3.2 KiB
TypeScript
81 lines
3.2 KiB
TypeScript
|
|
import React from 'react';
|
|
import { ProcessingStep, VideoJob } from '../types';
|
|
import { Loader2, CheckCircle2, Music, Video, FileText, UploadCloud } from 'lucide-react';
|
|
|
|
interface ProcessTrackerProps {
|
|
job: VideoJob;
|
|
}
|
|
|
|
const steps = [
|
|
{ id: ProcessingStep.UPLOAD, label: "Upload", icon: UploadCloud },
|
|
{ id: ProcessingStep.LYRICS, label: "Lyrics", icon: FileText },
|
|
{ id: ProcessingStep.MUSIC, label: "Music", icon: Music },
|
|
{ id: ProcessingStep.VIDEO, label: "Video", icon: Video },
|
|
];
|
|
|
|
export const ProcessTracker: React.FC<ProcessTrackerProps> = ({ job }) => {
|
|
const getCurrentStepIndex = () => {
|
|
if (job.currentStep === ProcessingStep.DONE) return steps.length;
|
|
return steps.findIndex(s => s.id === job.currentStep);
|
|
};
|
|
|
|
const currentIndex = getCurrentStepIndex();
|
|
|
|
return (
|
|
<div className="w-full max-w-2xl mx-auto p-6 bg-glass backdrop-blur-xl border border-glassBorder rounded-2xl shadow-2xl">
|
|
<h3 className="text-xl font-serif font-bold text-center mb-6 text-white">
|
|
Creating Magic for {job.data.customer_name}
|
|
</h3>
|
|
|
|
<div className="relative flex justify-between items-center mb-8">
|
|
{/* Connecting Line */}
|
|
<div className="absolute top-1/2 left-0 w-full h-1 bg-gray-700 -z-10 transform -translate-y-1/2 rounded-full overflow-hidden">
|
|
<div
|
|
className="h-full bg-gradient-to-r from-blue-500 to-accent transition-all duration-700 ease-out"
|
|
style={{ width: `${(currentIndex / (steps.length - 1)) * 100}%` }}
|
|
/>
|
|
</div>
|
|
|
|
{steps.map((step, index) => {
|
|
const isActive = index === currentIndex;
|
|
const isCompleted = index < currentIndex;
|
|
const Icon = step.icon;
|
|
|
|
return (
|
|
<div key={step.id} className="flex flex-col items-center gap-2">
|
|
<div
|
|
className={`
|
|
w-12 h-12 rounded-full flex items-center justify-center border-2 transition-all duration-500
|
|
${isCompleted
|
|
? 'bg-accent border-accent text-white scale-110'
|
|
: isActive
|
|
? 'bg-gray-900 border-blue-400 text-blue-400 shadow-[0_0_15px_rgba(59,130,246,0.5)]'
|
|
: 'bg-gray-900 border-gray-600 text-gray-400'
|
|
}
|
|
`}
|
|
>
|
|
{isCompleted ? <CheckCircle2 size={24} /> : isActive ? <Loader2 size={24} className="animate-spin" /> : <Icon size={20} />}
|
|
</div>
|
|
<span className={`
|
|
text-xs uppercase tracking-wider transition-colors duration-300 text-center
|
|
${isActive ? 'text-blue-300 font-bold drop-shadow-[0_0_5px_rgba(147,197,253,0.5)]' : ''}
|
|
${isCompleted ? 'text-white font-semibold' : ''}
|
|
${!isActive && !isCompleted ? 'text-gray-400 font-medium' : ''}
|
|
`}>
|
|
{step.label}
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="text-center h-8">
|
|
<p className="text-blue-200 animate-pulse text-sm font-medium">
|
|
{job.currentStep !== ProcessingStep.DONE ? `Current Step: ${job.currentStep}` : 'Finalizing output...'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|