deepfake-server / frontend /src /components /VideoUploader.jsx
DevQueen's picture
Sync from GitHub via hub-sync
1dc2504 verified
Raw
History Blame Contribute Delete
3.13 kB
import { useRef, useState } from "react";
const ACCEPTED = ["video/mp4", "video/avi", "video/quicktime", "video/x-matroska", "video/webm"];
export default function VideoUploader({ onAnalyse, isLoading }) {
const inputRef = useRef(null);
const [file, setFile] = useState(null);
const [preview, setPreview] = useState(null);
const [dragOver, setDragOver] = useState(false);
function handleFile(f) {
if (!f) return;
setFile(f);
setPreview(URL.createObjectURL(f));
}
function onDrop(e) {
e.preventDefault();
setDragOver(false);
handleFile(e.dataTransfer.files[0]);
}
return (
<div className="w-full flex flex-col items-center gap-10">
<div
onDrop={onDrop}
onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
onDragLeave={() => setDragOver(false)}
onClick={() => inputRef.current?.click()}
className={`w-full aspect-[16/9] max-h-[320px] border-2 border-dashed rounded-3xl flex flex-col items-center justify-center cursor-pointer transition-all duration-200
${dragOver
? "border-indigo-400 bg-indigo-50/80 scale-[1.01]"
: "border-slate-200 bg-white hover:border-slate-300 hover:shadow-md shadow-sm"}`}
>
<div className={`w-14 h-14 rounded-2xl flex items-center justify-center mb-5 transition-colors
${dragOver ? "bg-indigo-100" : "bg-slate-100"}`}>
<svg className="w-7 h-7 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5}
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6h.1a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
</div>
<p className="text-slate-600 font-medium">Drop video here</p>
<p className="text-slate-400 text-sm mt-1">or click to browse</p>
<input
ref={inputRef}
type="file"
accept={ACCEPTED.join(",")}
className="hidden"
onChange={(e) => handleFile(e.target.files[0])}
/>
</div>
{preview && (
<video
src={preview}
controls
className="w-full rounded-2xl border border-slate-200 bg-white shadow-sm"
style={{ maxHeight: 280 }}
/>
)}
{file && (
<button
onClick={() => onAnalyse(file)}
disabled={isLoading}
className="px-10 py-3.5 rounded-full font-medium text-white bg-slate-900 hover:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed transition-all shadow-sm hover:shadow-md"
>
{isLoading ? (
<span className="flex items-center gap-2.5">
<svg className="animate-spin h-4 w-4" viewBox="0 0 24 24" fill="none">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"/>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"/>
</svg>
Analysing…
</span>
) : "Analyse"}
</button>
)}
</div>
);
}