/** * DownloadWorkspaceButton — FIX-6 * Bottone compatto stile Replit per scaricare il VFS come ZIP. * Da montare nella StatusBar (slot destra). */ import { useState, useEffect, useCallback } from "react"; import { vfsAsync, onVfsChanged } from "@/lib/vfsDb"; import { downloadBlob } from "@/lib/fileConverter"; export function DownloadWorkspaceButton() { const [fileCount, setFileCount] = useState(0); const [state, setState] = useState<"idle" | "loading" | "done">("idle"); const reload = useCallback(() => { vfsAsync.list().then(f => setFileCount(f.length)).catch(() => {}); }, []); useEffect(() => { reload(); return onVfsChanged(reload); }, [reload]); useEffect(() => { if (state !== "done") return; const t = setTimeout(() => setState("idle"), 2000); return () => clearTimeout(t); }, [state]); if (fileCount === 0) return null; const handleClick = async () => { if (state !== "idle") return; setState("loading"); try { const { default: JSZip } = await import("jszip"); const zip = new JSZip(); const files = await vfsAsync.list(); for (const f of files) { const c = f.opfs ? (await vfsAsync.read(f.path) ?? "") : f.content; zip.file(f.path.startsWith("/") ? f.path.slice(1) : f.path, c); } const blob = await zip.generateAsync({ type: "blob", compression: "DEFLATE", compressionOptions: { level: 6 } }); downloadBlob(blob, `workspace-${Date.now()}.zip`); setState("done"); } catch { setState("idle"); } }; const isDone = state === "done"; const isLoading = state === "loading"; return ( ); } export default DownloadWorkspaceButton;