const fileInput = document.querySelector("#file-upload"); const fileCount = document.querySelector("#upload-file-count"); const fileList = document.querySelector(".upload-file-list"); const dropzone = document.querySelector(".upload-dropzone"); const uploadForm = document.querySelector(".upload-form"); const uploadStatus = document.querySelector(".upload-statusbar span:first-child"); function formatBytes(bytes) { const units = ["B", "KB", "MB", "GB"]; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex += 1; } if (unitIndex === 0) { return `${size} ${units[unitIndex]}`; } return `${size.toFixed(1)} ${units[unitIndex]}`; } function updateStatus(message) { if (uploadStatus) { uploadStatus.textContent = message; } } function updateSelectedFiles(files) { const selectedFiles = Array.from(files || []); if (fileCount) { fileCount.textContent = `${selectedFiles.length} ${selectedFiles.length === 1 ? "file" : "files"}`; } if (!fileList) { return; } fileList.replaceChildren(); if (!selectedFiles.length) { const emptyState = document.createElement("p"); emptyState.className = "upload-empty-state"; emptyState.textContent = "No files selected"; fileList.append(emptyState); updateStatus("Ready"); return; } const fragment = document.createDocumentFragment(); selectedFiles.forEach((file) => { const row = document.createElement("div"); row.className = "upload-file-row"; const icon = document.createElement("span"); icon.className = "upload-file-icon"; icon.setAttribute("aria-hidden", "true"); const name = document.createElement("span"); name.className = "upload-file-name"; name.textContent = file.name; name.title = file.name; const size = document.createElement("span"); size.className = "upload-file-size"; size.textContent = formatBytes(file.size); row.append(icon, name, size); fragment.append(row); }); fileList.append(fragment); updateStatus("Files selected"); } if (fileInput) { fileInput.addEventListener("change", () => { updateSelectedFiles(fileInput.files); }); } if (fileInput && dropzone) { dropzone.addEventListener("dragover", (event) => { event.preventDefault(); dropzone.classList.add("is-dragging"); }); dropzone.addEventListener("dragleave", () => { dropzone.classList.remove("is-dragging"); }); dropzone.addEventListener("drop", (event) => { event.preventDefault(); dropzone.classList.remove("is-dragging"); if (!event.dataTransfer.files.length) { return; } fileInput.files = event.dataTransfer.files; updateSelectedFiles(fileInput.files); }); } if (uploadForm && fileInput) { uploadForm.addEventListener("submit", async (event) => { event.preventDefault(); if (!fileInput.files.length) { updateStatus("Choose files first"); return; } updateStatus("Uploading..."); try { const response = await fetch(uploadForm.action, { method: "POST", body: new FormData(uploadForm), }); if (!response.ok) { throw new Error("Upload failed"); } const result = await response.json(); updateStatus(`Uploaded to ${result.box_url}`); } catch (error) { updateStatus("Upload failed"); } }); }