Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 23x 23x 23x 1x 23x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 23x 3x 3x 2x 2x 2x 1x 1x 1x 2x 1x 1x 2x 23x | import { useRef, useCallback, useState } from "react";
type FileEntry = { name: string; content: string };
interface UseFileManagerOptions {
tabs?: Array<{ name: string; content: string }>;
onFilesLoaded?: (files: FileEntry[], replaceAll: boolean) => void;
toast?: (params: { title: string; description?: string; variant?: string }) => void;
}
export function useFileManager({ tabs = [], onFilesLoaded, toast }: UseFileManagerOptions = {}) {
const fileInputRef = useRef<HTMLInputElement | null>(null);
const [lastLoadedFiles, setLastLoadedFiles] = useState<FileEntry[] | null>(null);
const onLoadFiles = useCallback(() => {
fileInputRef.current?.click();
}, []);
const downloadAllFiles = useCallback(async (providedTabs?: Array<{ name: string; content: string }>) => {
const which = providedTabs ?? tabs ?? [];
if (!which || which.length === 0) {
try {
toast?.({ title: "Nothing to download", description: "There are no open files to download" });
} catch {}
return;
}
which.forEach((tab, index) => {
setTimeout(() => {
const element = document.createElement("a");
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(tab.content));
element.setAttribute("download", tab.name);
(element as any).style.display = "none";
document.body.appendChild(element);
(element as any).click();
element.remove();
}, index * 200);
});
setTimeout(() => {
try {
toast?.({ title: "Download started", description: `${which.length} file(s) will be downloaded` });
} catch {}
}, which.length * 200 + 100);
}, [tabs, toast]);
const handleHiddenFileInput = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
const fl = e.target.files;
if (!fl || fl.length === 0) return;
const files: FileEntry[] = [];
for (const f of Array.from(fl)) {
if (!f.name.endsWith(".ino") && !f.name.endsWith(".h")) continue;
try {
const txt = await f.text();
files.push({ name: f.name, content: txt });
} catch {}
}
if (files.length > 0) {
setLastLoadedFiles(files);
onFilesLoaded?.(files, false);
}
// clear input value to allow re-upload of same file
Iif (fileInputRef.current) fileInputRef.current.value = "";
}, [onFilesLoaded]);
return {
fileInputRef,
onLoadFiles,
downloadAllFiles,
handleHiddenFileInput,
lastLoadedFiles,
} as const;
}
|