scrape / components /video-upload.tsx
kjbytes's picture
push code
ef4c36f
Raw
History Blame Contribute Delete
3.34 kB
"use client";
import { useCallback, useState } from "react";
import { useRouter } from "next/navigation";
import { Film, Loader2, Upload } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn, formatFileSize } from "@/lib/utils";
const MAX_SIZE = 500 * 1024 * 1024;
const ACCEPTED = ["video/mp4", "video/quicktime", "video/webm"];
export function VideoUpload() {
const router = useRouter();
const [dragging, setDragging] = useState(false);
const [uploading, setUploading] = useState(false);
const [error, setError] = useState<string | null>(null);
const uploadFile = useCallback(async (file: File) => {
setError(null);
if (!ACCEPTED.includes(file.type) && !file.name.match(/\.(mp4|mov|webm)$/i)) {
setError("Please upload MP4, MOV, or WebM.");
return;
}
if (file.size > MAX_SIZE) {
setError(`File too large (${formatFileSize(file.size)}). Max 500MB.`);
return;
}
setUploading(true);
try {
const formData = new FormData();
formData.append("video", file);
const res = await fetch("/api/upload", { method: "POST", body: formData });
const data = await res.json();
if (!res.ok) throw new Error(data.error || "Upload failed");
router.push(`/editor?id=${data.id}`);
} catch (err) {
setError(err instanceof Error ? err.message : "Upload failed");
} finally {
setUploading(false);
}
}, [router]);
const onDrop = (e: React.DragEvent) => {
e.preventDefault();
setDragging(false);
const file = e.dataTransfer.files?.[0];
if (file) void uploadFile(file);
};
return (
<div className="mx-auto w-full max-w-xl space-y-4">
<div
onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
onDragLeave={() => setDragging(false)}
onDrop={onDrop}
className={cn(
"flex min-h-[320px] cursor-pointer flex-col items-center justify-center rounded-2xl border-2 border-dashed p-10 transition-colors",
dragging ? "border-zinc-900 bg-zinc-50" : "border-zinc-300 bg-white hover:border-zinc-400",
)}
onClick={() => document.getElementById("video-input")?.click()}
>
<input
id="video-input"
type="file"
accept="video/mp4,video/quicktime,video/webm,.mp4,.mov,.webm"
className="hidden"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) void uploadFile(file);
}}
/>
{uploading ? (
<Loader2 className="h-12 w-12 animate-spin text-zinc-500" />
) : (
<Upload className="h-12 w-12 text-zinc-400" />
)}
<h2 className="mt-4 text-xl font-semibold">Drop video here</h2>
<p className="mt-2 text-sm text-zinc-500">or click to browse</p>
<p className="mt-4 text-xs text-zinc-400">MP4, MOV, WebM • Max 500MB • 5 min</p>
</div>
{error && (
<div className="rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
{error}
</div>
)}
<div className="flex items-center gap-2 rounded-lg bg-zinc-100 px-4 py-3 text-sm text-zinc-600">
<Film className="h-4 w-4" />
Upload a short vertical video to add viral-style captions
</div>
</div>
);
}