2026-01-07 09:31:02 +00:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
|
import { Button } from '../ui/button';
|
|
|
|
|
import { X, Wand2, Check, Music2 } from 'lucide-react';
|
2026-01-07 18:39:21 +00:00
|
|
|
import { useToast } from '../../context/ToastContext';
|
2026-01-07 09:31:02 +00:00
|
|
|
|
|
|
|
|
interface DetectedData {
|
|
|
|
|
bpm: number;
|
|
|
|
|
key: string;
|
|
|
|
|
genre: string;
|
|
|
|
|
energy: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface AutoMetadataDetectionModalProps {
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
onApply: (data: DetectedData) => void;
|
|
|
|
|
fileName: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
export const AutoMetadataDetectionModal: React.FC<
|
|
|
|
|
AutoMetadataDetectionModalProps
|
|
|
|
|
> = ({ onClose, onApply, fileName }) => {
|
2026-01-07 09:31:02 +00:00
|
|
|
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',
|
2026-01-13 18:47:57 +00:00
|
|
|
energy: 'High',
|
2026-01-07 09:31:02 +00:00
|
|
|
});
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}, 2500);
|
|
|
|
|
return () => clearTimeout(timer);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
2026-01-13 18:47:57 +00:00
|
|
|
<div
|
|
|
|
|
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
></div>
|
aesthetic-improvements: reduce more decorative cyan backgrounds (80/20 rule, batch 3)
- Layout components: Sidebar hub header icon, Header icon background (2 instances) - decorative icons
- AutoMetadataDetectionModal: modal border (decorative)
- CourseDetailView: card border (decorative)
- Total: ~4 files, ~4 instances replaced
- Preserved: Active/selected states (AudioPlayer dragged item, Header active notification, VisualizerSettingsModal selected mode, CreateProjectModal selected DAW, AIToolsView active tool, CourseLearningView active lesson, TipStreamerModal selected payment, CloudFileBrowser active tag, PlaylistDetailView dragged item, AddToPlaylistModal selected playlist, CreatorModal selected visibility)
- Action 11.3.1.3 in progress (third batch: layout and modal decorative elements)
2026-01-16 10:07:01 +00:00
|
|
|
<div className="relative w-full max-w-md bg-kodo-graphite border border-kodo-steel/30 rounded-xl shadow-2xl overflow-hidden animate-scaleIn">
|
2026-01-07 09:31:02 +00:00
|
|
|
<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>
|
2026-01-13 18:47:57 +00:00
|
|
|
<button onClick={onClose}>
|
2026-01-16 00:59:31 +00:00
|
|
|
<X className="w-5 h-5 text-kodo-content-dim hover:text-white" />
|
2026-01-13 18:47:57 +00:00
|
|
|
</button>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="p-8 flex flex-col items-center text-center">
|
2026-01-07 18:39:21 +00:00
|
|
|
{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" />
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
|
|
|
|
<div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<h4 className="text-lg font-bold text-white animate-pulse">
|
|
|
|
|
Analyzing Audio...
|
|
|
|
|
</h4>
|
2026-01-16 00:59:31 +00:00
|
|
|
<p className="text-sm text-kodo-content-dim mt-2">
|
2026-01-13 18:47:57 +00:00
|
|
|
Detecting BPM, Key, and Genre for <br />
|
|
|
|
|
<span className="text-kodo-cyan">{fileName}</span>
|
|
|
|
|
</p>
|
2026-01-07 18:39:21 +00:00
|
|
|
</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">
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold mb-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
Detected BPM
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-2xl font-bold text-white">
|
|
|
|
|
{result?.bpm}
|
|
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="text-center p-2">
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold mb-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
Detected Key
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-2xl font-bold text-kodo-cyan">
|
|
|
|
|
{result?.key}
|
|
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="text-center p-2">
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold mb-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
Genre
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-lg font-medium text-white">
|
|
|
|
|
{result?.genre}
|
|
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="text-center p-2">
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold mb-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
Energy Level
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-lg font-medium text-kodo-gold">
|
|
|
|
|
{result?.energy}
|
|
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex gap-3 w-full">
|
2026-01-13 18:47:57 +00:00
|
|
|
<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)}
|
|
|
|
|
>
|
2026-01-07 18:39:21 +00:00
|
|
|
Apply Tags
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|