234 lines
14 KiB
TypeScript
234 lines
14 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { Card } from '../../ui/card';
|
|
import { Button } from '../../ui/button';
|
|
import { Badge } from '../../ui/badge';
|
|
import { Input } from '../../ui/input';
|
|
import {
|
|
ArrowLeft, Play, Users, FileAudio, Save, Trash2,
|
|
HardDrive, Share2, MoreHorizontal,
|
|
Activity, History, Upload
|
|
} from 'lucide-react';
|
|
import { useToast } from '../../../context/ToastContext';
|
|
|
|
interface ProjectDetailViewProps {
|
|
project: any;
|
|
onBack: () => void;
|
|
onUpdate: (updatedProject: any) => void;
|
|
onDelete: (id: string) => void;
|
|
}
|
|
|
|
export const ProjectDetailView: React.FC<ProjectDetailViewProps> = ({ project, onBack, onUpdate, onDelete }) => {
|
|
const { addToast } = useToast();
|
|
const [activeTab, setActiveTab] = useState<'overview' | 'files' | 'settings'>('overview');
|
|
const [_editMode, setEditMode] = useState(false);
|
|
const [formData, setFormData] = useState(project);
|
|
|
|
// Mock Files for this project
|
|
const [projectFiles, _setProjectFiles] = useState([
|
|
{ id: 'f1', name: 'Demo_v3.mp3', size: '4.2 MB', type: 'audio', date: '2h ago' },
|
|
{ id: 'f2', name: 'Stems_Drums.zip', size: '45 MB', type: 'archive', date: '1d ago' },
|
|
{ id: 'f3', name: 'Vocals_Dry.wav', size: '22 MB', type: 'audio', date: '1d ago' },
|
|
]);
|
|
|
|
const handleSaveSettings = () => {
|
|
onUpdate(formData);
|
|
setEditMode(false);
|
|
addToast("Project settings saved", "success");
|
|
};
|
|
|
|
const handleDelete = () => {
|
|
if (confirm("Are you sure? This action cannot be undone.")) {
|
|
onDelete(project.id);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="animate-fadeIn pb-20 space-y-6">
|
|
{/* Header */}
|
|
<div className="flex flex-col md:flex-row justify-between items-start gap-4">
|
|
<div className="flex gap-4">
|
|
<Button variant="ghost" size="icon" onClick={onBack}><ArrowLeft className="w-5 h-5" /></Button>
|
|
<div>
|
|
<div className="flex items-center gap-3 mb-1">
|
|
<h2 className="text-3xl font-display font-bold text-white">{project.name}</h2>
|
|
<Badge
|
|
label={project.daw}
|
|
variant={project.daw === 'Ableton' ? 'cyan' : project.daw === 'FL Studio' ? 'gold' : 'magenta'}
|
|
/>
|
|
</div>
|
|
<div className="flex items-center gap-4 text-sm text-gray-400 font-mono">
|
|
<span>{project.bpm} BPM</span>
|
|
<span>{project.key}</span>
|
|
<span>Updated {project.modified}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Button variant="secondary" icon={<Share2 className="w-4 h-4" />} onClick={() => addToast("Collaboration link copied")}>Invite</Button>
|
|
<Button variant="primary" icon={<Play className="w-4 h-4 fill-current" />} onClick={() => addToast(`Opening in ${project.daw}...`, "success")}>Open DAW</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Navigation Tabs */}
|
|
<div className="border-b border-kodo-steel flex gap-6">
|
|
{['overview', 'files', 'settings'].map(tab => (
|
|
<button
|
|
key={tab}
|
|
onClick={() => setActiveTab(tab as any)}
|
|
className={`pb-3 text-sm font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === tab ? 'border-kodo-cyan text-white' : 'border-transparent text-gray-500 hover:text-gray-300'}`}
|
|
>
|
|
{tab}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
|
|
{/* Main Content Area */}
|
|
<div className="lg:col-span-2 space-y-6">
|
|
|
|
{activeTab === 'overview' && (
|
|
<>
|
|
<Card variant="default">
|
|
<h3 className="font-bold text-white mb-4">Project Status</h3>
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between text-sm text-gray-400 mb-1">
|
|
<span>Completion</span>
|
|
<span className="text-white">{project.progress}%</span>
|
|
</div>
|
|
<div className="h-2 bg-kodo-steel rounded-full overflow-hidden">
|
|
<div className="h-full bg-kodo-cyan" style={{width: `${project.progress}%`}}></div>
|
|
</div>
|
|
|
|
<div className="flex gap-4 pt-2">
|
|
<div className="flex-1 bg-kodo-ink p-3 rounded border border-kodo-steel">
|
|
<div className="text-xs text-gray-500 uppercase">Status</div>
|
|
<div className="text-sm font-bold text-white">{project.status}</div>
|
|
</div>
|
|
<div className="flex-1 bg-kodo-ink p-3 rounded border border-kodo-steel">
|
|
<div className="text-xs text-gray-500 uppercase">Version</div>
|
|
<div className="text-sm font-bold text-white">v1.4.2</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card variant="default">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h3 className="font-bold text-white flex items-center gap-2"><Activity className="w-4 h-4 text-kodo-gold" /> Recent Activity</h3>
|
|
</div>
|
|
<div className="space-y-4 relative">
|
|
<div className="absolute left-2.5 top-2 bottom-2 w-px bg-kodo-steel"></div>
|
|
{[1, 2, 3].map((_, i) => (
|
|
<div key={i} className="relative pl-8">
|
|
<div className="absolute left-0 top-1 w-5 h-5 bg-kodo-graphite border border-kodo-cyan rounded-full flex items-center justify-center">
|
|
<div className="w-2 h-2 bg-kodo-cyan rounded-full"></div>
|
|
</div>
|
|
<div className="text-sm text-gray-300">
|
|
<span className="font-bold text-white">You</span> uploaded a new bounce.
|
|
</div>
|
|
<div className="text-xs text-gray-500">2 hours ago</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</Card>
|
|
</>
|
|
)}
|
|
|
|
{activeTab === 'files' && (
|
|
<Card variant="default">
|
|
<div className="flex justify-between items-center mb-6">
|
|
<h3 className="font-bold text-white">Project Files</h3>
|
|
<Button variant="secondary" size="sm" icon={<Upload className="w-4 h-4" />}>Upload</Button>
|
|
</div>
|
|
<div className="space-y-2">
|
|
{projectFiles.map(file => (
|
|
<div key={file.id} className="flex items-center justify-between p-3 bg-kodo-ink rounded-lg border border-transparent hover:border-kodo-steel transition-all group">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 bg-kodo-slate rounded flex items-center justify-center text-gray-400">
|
|
{file.type === 'audio' ? <FileAudio className="w-5 h-5" /> : <HardDrive className="w-5 h-5" />}
|
|
</div>
|
|
<div>
|
|
<div className="font-bold text-sm text-white">{file.name}</div>
|
|
<div className="text-xs text-gray-500">{file.size} • {file.date}</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
<Button variant="ghost" size="icon"><Play className="w-4 h-4" /></Button>
|
|
<Button variant="ghost" size="icon"><MoreHorizontal className="w-4 h-4" /></Button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</Card>
|
|
)}
|
|
|
|
{activeTab === 'settings' && (
|
|
<div className="space-y-6">
|
|
<Card variant="default">
|
|
<h3 className="font-bold text-white mb-6 border-b border-kodo-steel pb-2">Project Settings</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
<Input label="Project Name" value={formData.name} onChange={(e) => setFormData({...formData, name: e.target.value})} />
|
|
<Input label="Status" value={formData.status} onChange={(e) => setFormData({...formData, status: e.target.value})} />
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
|
<Input label="BPM" value={formData.bpm} onChange={(e) => setFormData({...formData, bpm: e.target.value})} />
|
|
<Input label="Key" value={formData.key} onChange={(e) => setFormData({...formData, key: e.target.value})} />
|
|
</div>
|
|
<div className="flex justify-end pt-2">
|
|
<Button variant="primary" icon={<Save className="w-4 h-4" />} onClick={handleSaveSettings}>Save Changes</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card variant="default" className="border-kodo-red/30">
|
|
<h3 className="font-bold text-white mb-4 text-kodo-red flex items-center gap-2">
|
|
<Trash2 className="w-4 h-4" /> Danger Zone
|
|
</h3>
|
|
<p className="text-sm text-gray-400 mb-4">Permanently delete this project and all associated files.</p>
|
|
<Button variant="ghost" className="text-kodo-red border border-kodo-red/50 hover:bg-kodo-red/10 w-full" onClick={handleDelete}>
|
|
Delete Project
|
|
</Button>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Sidebar */}
|
|
<div className="space-y-6">
|
|
<Card variant="gaming">
|
|
<h3 className="font-bold text-white mb-4 text-sm uppercase tracking-wider flex items-center gap-2">
|
|
<Users className="w-4 h-4 text-kodo-gold" /> Collaborators
|
|
</h3>
|
|
<div className="flex -space-x-3 mb-4">
|
|
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-gray-700"></div>
|
|
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-gray-600"></div>
|
|
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-kodo-ink flex items-center justify-center text-xs text-gray-400 font-bold">+2</div>
|
|
</div>
|
|
<Button variant="ghost" size="sm" className="w-full text-xs border border-kodo-steel">Manage Team</Button>
|
|
</Card>
|
|
|
|
<Card variant="default">
|
|
<h3 className="font-bold text-white mb-4 text-sm uppercase tracking-wider flex items-center gap-2">
|
|
<History className="w-4 h-4 text-kodo-magenta" /> Versions
|
|
</h3>
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between items-center text-sm p-2 bg-white/5 rounded">
|
|
<span className="text-white">v1.4 (Current)</span>
|
|
<span className="text-xs text-gray-500">2h ago</span>
|
|
</div>
|
|
<div className="flex justify-between items-center text-sm p-2 hover:bg-white/5 rounded cursor-pointer text-gray-400">
|
|
<span>v1.3</span>
|
|
<span className="text-xs text-gray-600">1d ago</span>
|
|
</div>
|
|
<div className="flex justify-between items-center text-sm p-2 hover:bg-white/5 rounded cursor-pointer text-gray-400">
|
|
<span>v1.2</span>
|
|
<span className="text-xs text-gray-600">3d ago</span>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|