diff --git a/.claude/plans/reflective-meandering-castle.md b/.claude/plans/reflective-meandering-castle.md index 9f10703c..ab3792e3 100644 --- a/.claude/plans/reflective-meandering-castle.md +++ b/.claude/plans/reflective-meandering-castle.md @@ -45,7 +45,7 @@ After getting Claude Max OAuth working on the live server, hardening the deploy - **Change**: Add `getUsage()` method to filebrowser-client. In Home.vue, replace hardcoded "2.4 GB" and "5" folders with real data from FileBrowser API. Add `formatBytes()` helper. Show loading state while fetching. - **Verify**: Home Cloud card shows real storage numbers from FileBrowser -### Task 8: Cloud file drag-and-drop upload +### Task 8: Cloud file drag-and-drop upload [DONE] - **Files**: `neode-ui/src/views/CloudFolder.vue`, `neode-ui/src/style.css` - **Change**: Add drag-and-drop overlay with `@dragover.prevent` and `@drop.prevent`. Show visual drop zone when dragging. Extract files from `dataTransfer` and call existing `handleUpload()`. - **Verify**: Drag a file over CloudFolder — drop zone overlay appears, dropping uploads file diff --git a/neode-ui/src/style.css b/neode-ui/src/style.css index 89490682..eb79c2b4 100644 --- a/neode-ui/src/style.css +++ b/neode-ui/src/style.css @@ -1220,3 +1220,31 @@ html:has(body.video-background-active)::before { border-radius: 2px; transition: width 0.3s linear; } + +/* ── Cloud Drag-and-Drop Overlay ──── */ + +.cloud-drop-overlay { + position: absolute; + inset: 0; + z-index: 30; + display: flex; + align-items: center; + justify-content: center; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + border-radius: 0.75rem; + border: 2px dashed rgba(251, 146, 60, 0.6); + animation: drop-overlay-in 0.2s ease-out; +} +.cloud-drop-overlay-inner { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 2rem; +} +@keyframes drop-overlay-in { + from { opacity: 0; } + to { opacity: 1; } +} diff --git a/neode-ui/src/views/CloudFolder.vue b/neode-ui/src/views/CloudFolder.vue index 034e135c..07304c47 100644 --- a/neode-ui/src/views/CloudFolder.vue +++ b/neode-ui/src/views/CloudFolder.vue @@ -72,7 +72,23 @@ -
+
+ +
+
+ + + +

Drop files to upload

+

Files will be added to the current folder

+
+
@@ -274,6 +290,27 @@ watch(useNativeUI, async (native) => { }, { immediate: true }) const uploadError = ref(null) +const draggingOver = ref(false) +let dragLeaveTimer: ReturnType | 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