forked from 77media/video-flow
288 lines
10 KiB
TypeScript
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>
|
|
);
|
|
} |