personal_website/src/components/AudioUploader.tsx
2025-12-21 13:21:20 +01:00

79 lines
2.5 KiB
TypeScript
Executable File

import { useCallback } from 'react';
import { Upload, Music } from 'lucide-react';
import { cn } from '@/lib/utils';
interface AudioUploaderProps {
onFileSelect: (file: File) => void;
isLoading: boolean;
fileName: string | null;
}
export function AudioUploader({ onFileSelect, isLoading, fileName }: AudioUploaderProps) {
const handleDrop = useCallback((e: React.DragEvent) => {
e.preventDefault();
const file = e.dataTransfer.files[0];
if (file && file.type.startsWith('audio/')) {
onFileSelect(file);
}
}, [onFileSelect]);
const handleFileInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
onFileSelect(file);
}
}, [onFileSelect]);
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
};
return (
<div
className={cn(
"relative border-2 border-dashed border-primary/40 rounded-lg p-8 text-center",
"hover:border-primary/70 transition-all duration-300 cursor-pointer",
"bg-secondary/20 hover:bg-secondary/30",
isLoading && "opacity-50 pointer-events-none"
)}
onDrop={handleDrop}
onDragOver={handleDragOver}
>
<input
type="file"
accept="audio/*"
onChange={handleFileInput}
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
disabled={isLoading}
/>
<div className="flex flex-col items-center gap-4">
{fileName ? (
<>
<Music className="w-12 h-12 text-primary phosphor-glow" />
<div>
<p className="text-lg font-crt text-primary text-glow">{fileName}</p>
<p className="text-sm text-muted-foreground mt-1">Click or drop to replace</p>
</div>
</>
) : (
<>
<Upload className="w-12 h-12 text-primary/60" />
<div>
<p className="text-lg font-crt text-primary/80">Drop audio file here</p>
<p className="text-sm text-muted-foreground mt-1">or click to browse</p>
<p className="text-xs text-muted-foreground mt-2">MP3, WAV, FLAC, OGG supported</p>
</div>
</>
)}
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-background/50 rounded-lg">
<div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
</div>
)}
</div>
</div>
);
}