video-flow-b/components/workflow/final-composition-step.tsx
2025-06-19 17:15:03 +08:00

288 lines
10 KiB
TypeScript

"use client";
import { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Progress } from '@/components/ui/progress';
import { Separator } from '@/components/ui/separator';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import {
ArrowLeft,
Play,
Download,
Share2,
Settings,
Clock,
FileVideo,
Sparkles,
CheckCircle,
} from 'lucide-react';
interface FinalCompositionStepProps {
onPrevious: () => void;
}
const exportFormats = [
{ value: 'mp4-1080p', label: 'MP4 - 1080p (Recommended)', size: '~150MB' },
{ value: 'mp4-720p', label: 'MP4 - 720p', size: '~80MB' },
{ value: 'mp4-4k', label: 'MP4 - 4K', size: '~400MB' },
{ value: 'webm-1080p', label: 'WebM - 1080p', size: '~120MB' },
];
const projectSummary = {
title: 'AI Technology Guide',
totalDuration: '4:50',
chapters: 4,
totalShots: 8,
actors: 3,
musicTracks: 4,
};
export function FinalCompositionStep({ onPrevious }: FinalCompositionStepProps) {
const [exportFormat, setExportFormat] = useState('mp4-1080p');
const [isGenerating, setIsGenerating] = useState(false);
const [generationProgress, setGenerationProgress] = useState(0);
const [isComplete, setIsComplete] = useState(false);
const handleGenerate = () => {
setIsGenerating(true);
setGenerationProgress(0);
// Simulate video generation progress
const interval = setInterval(() => {
setGenerationProgress((prev) => {
if (prev >= 100) {
clearInterval(interval);
setIsGenerating(false);
setIsComplete(true);
return 100;
}
return prev + Math.random() * 10;
});
}, 500);
};
const handleDownload = () => {
// Simulate download
const link = document.createElement('a');
link.href = '#';
link.download = `${projectSummary.title.replace(/\s+/g, '_')}.mp4`;
link.click();
};
return (
<div className="space-y-6">
{/* Project Summary */}
<Card>
<CardHeader>
<CardTitle className="flex items-center space-x-2">
<FileVideo className="h-5 w-5" />
<span>Project Summary</span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
<div className="text-center space-y-2">
<div className="text-2xl font-bold text-primary">{projectSummary.totalDuration}</div>
<div className="text-sm text-muted-foreground">Total Duration</div>
</div>
<div className="text-center space-y-2">
<div className="text-2xl font-bold text-primary">{projectSummary.chapters}</div>
<div className="text-sm text-muted-foreground">Chapters</div>
</div>
<div className="text-center space-y-2">
<div className="text-2xl font-bold text-primary">{projectSummary.totalShots}</div>
<div className="text-sm text-muted-foreground">Total Shots</div>
</div>
<div className="text-center space-y-2">
<div className="text-2xl font-bold text-primary">{projectSummary.actors}</div>
<div className="text-sm text-muted-foreground">AI Actors</div>
</div>
</div>
</CardContent>
</Card>
{/* Video Preview */}
<Card>
<CardHeader>
<CardTitle>Video Preview</CardTitle>
</CardHeader>
<CardContent>
<div className="aspect-video bg-black rounded-lg flex items-center justify-center relative overflow-hidden">
<img
src="https://images.pexels.com/photos/3861969/pexels-photo-3861969.jpeg?auto=compress&cs=tinysrgb&w=800"
alt="Video preview"
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-black/40 flex items-center justify-center">
<Button size="lg" variant="secondary">
<Play className="mr-2 h-6 w-6" />
Preview Full Video
</Button>
</div>
<Badge className="absolute top-4 left-4">
{projectSummary.title}
</Badge>
<Badge variant="secondary" className="absolute top-4 right-4">
{projectSummary.totalDuration}
</Badge>
</div>
</CardContent>
</Card>
{/* Export Settings */}
<Card>
<CardHeader>
<CardTitle className="flex items-center space-x-2">
<Settings className="h-5 w-5" />
<span>Export Settings</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-3">
<label className="text-sm font-medium">Export Format</label>
<Select value={exportFormat} onValueChange={setExportFormat}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{exportFormats.map((format) => (
<SelectItem key={format.value} value={format.value}>
<div className="flex flex-col">
<span>{format.label}</span>
<span className="text-xs text-muted-foreground">{format.size}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-3">
<label className="text-sm font-medium">Estimated Size</label>
<div className="p-3 bg-muted rounded-lg">
<div className="text-lg font-semibold">
{exportFormats.find(f => f.value === exportFormat)?.size}
</div>
<div className="text-sm text-muted-foreground">
Based on {projectSummary.totalDuration} duration
</div>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Generation Status */}
<Card>
<CardHeader>
<CardTitle className="flex items-center space-x-2">
{isComplete ? (
<CheckCircle className="h-5 w-5 text-green-600" />
) : (
<Sparkles className="h-5 w-5" />
)}
<span>
{isComplete ? 'Video Ready!' : isGenerating ? 'Generating Video...' : 'Ready to Generate'}
</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{isGenerating && (
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>Processing...</span>
<span>{Math.round(generationProgress)}%</span>
</div>
<Progress value={generationProgress} className="h-2" />
<p className="text-sm text-muted-foreground">
This may take a few minutes. You can close this tab and return later.
</p>
</div>
)}
{isComplete && (
<div className="space-y-4">
<div className="flex items-center space-x-2 text-green-600">
<CheckCircle className="h-5 w-5" />
<span className="font-medium">Your video is ready for download!</span>
</div>
<div className="flex space-x-3">
<Button onClick={handleDownload} className="flex-1">
<Download className="mr-2 h-4 w-4" />
Download Video
</Button>
<Button variant="outline" className="flex-1">
<Share2 className="mr-2 h-4 w-4" />
Share Link
</Button>
</div>
</div>
)}
{!isGenerating && !isComplete && (
<div className="space-y-4">
<p className="text-muted-foreground">
All steps completed! Your video is ready to be generated with the selected settings.
</p>
<Button onClick={handleGenerate} size="lg" className="w-full">
<Sparkles className="mr-2 h-5 w-5" />
Generate Final Video
</Button>
</div>
)}
</CardContent>
</Card>
{/* Chapter Breakdown */}
<Card>
<CardHeader>
<CardTitle>Chapter Breakdown</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{[
{ name: 'Introduction', duration: '0:45', shots: 2 },
{ name: 'Core Concepts', duration: '1:20', shots: 2 },
{ name: 'Practical Applications', duration: '1:15', shots: 2 },
{ name: 'Future Outlook', duration: '0:50', shots: 2 },
].map((chapter, index) => (
<div key={index} className="flex items-center justify-between p-3 bg-muted rounded-lg">
<div className="flex items-center space-x-3">
<Badge variant="outline">Chapter {index + 1}</Badge>
<span className="font-medium">{chapter.name}</span>
</div>
<div className="flex items-center space-x-4 text-sm text-muted-foreground">
<div className="flex items-center">
<Clock className="mr-1 h-3 w-3" />
{chapter.duration}
</div>
<div>{chapter.shots} shots</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Action Buttons */}
<div className="flex justify-between">
<Button variant="outline" onClick={onPrevious} disabled={isGenerating}>
<ArrowLeft className="mr-2 h-4 w-4" />
Back to Music
</Button>
<div className="flex space-x-3">
<Button variant="outline" disabled={isGenerating}>
Save Project
</Button>
{isComplete && (
<Button onClick={() => window.location.href = '/'}>
Create New Video
</Button>
)}
</div>
</div>
</div>
);
}