101 lines
4.2 KiB
TypeScript
101 lines
4.2 KiB
TypeScript
|
|
import React, { useState, useEffect } from 'react';
|
|
import { Button } from '../ui/button';
|
|
import { X, Wand2, Check, Music2 } from 'lucide-react';
|
|
import { useToast } from '../../context/ToastContext';
|
|
|
|
interface DetectedData {
|
|
bpm: number;
|
|
key: string;
|
|
genre: string;
|
|
energy: string;
|
|
}
|
|
|
|
interface AutoMetadataDetectionModalProps {
|
|
onClose: () => void;
|
|
onApply: (data: DetectedData) => void;
|
|
fileName: string;
|
|
}
|
|
|
|
export const AutoMetadataDetectionModal: React.FC<AutoMetadataDetectionModalProps> = ({ onClose, onApply, fileName }) => {
|
|
const { addToast: _addToast } = useToast();
|
|
const [loading, setLoading] = useState(true);
|
|
const [result, setResult] = useState<DetectedData | null>(null);
|
|
|
|
useEffect(() => {
|
|
// Simulate AI detection
|
|
const timer = setTimeout(() => {
|
|
setResult({
|
|
bpm: 128,
|
|
key: 'F# Minor',
|
|
genre: 'Synthwave',
|
|
energy: 'High'
|
|
});
|
|
setLoading(false);
|
|
}, 2500);
|
|
return () => clearTimeout(timer);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
|
<div className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm" onClick={onClose}></div>
|
|
<div className="relative w-full max-w-md bg-kodo-graphite border border-kodo-cyan/30 rounded-xl shadow-neon-cyan/20 overflow-hidden animate-scaleIn">
|
|
|
|
<div className="p-4 border-b border-kodo-steel bg-kodo-ink flex justify-between items-center">
|
|
<h3 className="font-bold text-white flex items-center gap-2">
|
|
<Wand2 className="w-4 h-4 text-kodo-cyan" /> AI Metadata Detection
|
|
</h3>
|
|
<button onClick={onClose}><X className="w-5 h-5 text-gray-400 hover:text-white" /></button>
|
|
</div>
|
|
|
|
<div className="p-8 flex flex-col items-center text-center">
|
|
|
|
{loading ? (
|
|
<div className="space-y-6">
|
|
<div className="relative">
|
|
<div className="w-20 h-20 rounded-full border-4 border-kodo-steel border-t-kodo-cyan animate-spin mx-auto"></div>
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<Music2 className="w-8 h-8 text-kodo-cyan/50" />
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h4 className="text-lg font-bold text-white animate-pulse">Analyzing Audio...</h4>
|
|
<p className="text-sm text-gray-400 mt-2">Detecting BPM, Key, and Genre for <br /><span className="text-kodo-cyan">{fileName}</span></p>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="w-full space-y-6 animate-fadeIn">
|
|
<div className="bg-kodo-ink border border-kodo-cyan/20 rounded-lg p-6 w-full">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="text-center p-2">
|
|
<div className="text-xs text-gray-500 uppercase font-bold mb-1">Detected BPM</div>
|
|
<div className="text-2xl font-bold text-white">{result?.bpm}</div>
|
|
</div>
|
|
<div className="text-center p-2">
|
|
<div className="text-xs text-gray-500 uppercase font-bold mb-1">Detected Key</div>
|
|
<div className="text-2xl font-bold text-kodo-cyan">{result?.key}</div>
|
|
</div>
|
|
<div className="text-center p-2">
|
|
<div className="text-xs text-gray-500 uppercase font-bold mb-1">Genre</div>
|
|
<div className="text-lg font-medium text-white">{result?.genre}</div>
|
|
</div>
|
|
<div className="text-center p-2">
|
|
<div className="text-xs text-gray-500 uppercase font-bold mb-1">Energy Level</div>
|
|
<div className="text-lg font-medium text-kodo-gold">{result?.energy}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex gap-3 w-full">
|
|
<Button variant="ghost" onClick={onClose} className="flex-1">Discard</Button>
|
|
<Button variant="primary" className="flex-1" icon={<Check className="w-4 h-4" />} onClick={() => result && onApply(result)}>
|
|
Apply Tags
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|