feat: add drag-and-drop file upload to Cloud folders

Drag files over the native file browser area to see a drop zone overlay
with dashed orange border. Dropping files triggers the existing upload
handler. Uses debounced dragleave to prevent flicker between children.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-05 07:08:57 +00:00
co-authored by Claude Opus 4.6
parent 37105e6be6
commit 621d74bfb3
3 changed files with 67 additions and 2 deletions
+38 -1
View File
@@ -72,7 +72,23 @@
</div>
<!-- Native File Browser (for FileBrowser-backed sections) -->
<div v-else-if="useNativeUI" class="flex-1 min-h-0 flex flex-col">
<div
v-else-if="useNativeUI"
class="flex-1 min-h-0 flex flex-col relative"
@dragover.prevent="onDragOver"
@dragleave="onDragLeave"
@drop.prevent="onDrop"
>
<!-- Drag-and-drop overlay -->
<div v-if="draggingOver" class="cloud-drop-overlay">
<div class="cloud-drop-overlay-inner">
<svg class="w-12 h-12 text-white/80 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
<p class="text-lg font-medium text-white/90">Drop files to upload</p>
<p class="text-sm text-white/50">Files will be added to the current folder</p>
</div>
</div>
<!-- Upload progress -->
<div v-if="uploading" class="glass-card p-3 mb-3 flex items-center gap-3">
<div class="w-5 h-5 border-2 border-white/20 border-t-white/80 rounded-full animate-spin"></div>
@@ -274,6 +290,27 @@ watch(useNativeUI, async (native) => {
}, { immediate: true })
const uploadError = ref<string | null>(null)
const draggingOver = ref(false)
let dragLeaveTimer: ReturnType<typeof setTimeout> | null = null
function onDragOver() {
if (dragLeaveTimer) { clearTimeout(dragLeaveTimer); dragLeaveTimer = null }
draggingOver.value = true
}
function onDragLeave() {
// Debounce to avoid flicker when dragging between child elements
if (dragLeaveTimer) clearTimeout(dragLeaveTimer)
dragLeaveTimer = setTimeout(() => { draggingOver.value = false }, 100)
}
function onDrop(e: DragEvent) {
draggingOver.value = false
if (dragLeaveTimer) { clearTimeout(dragLeaveTimer); dragLeaveTimer = null }
const dt = e.dataTransfer
if (!dt?.files?.length) return
handleUpload(Array.from(dt.files))
}
async function handleUpload(files: File[]) {
uploading.value = true