diff --git a/frontend/src/lib/components/AppShell.svelte b/frontend/src/lib/components/AppShell.svelte index 0abff3e4..fc2c335a 100644 --- a/frontend/src/lib/components/AppShell.svelte +++ b/frontend/src/lib/components/AppShell.svelte @@ -872,7 +872,10 @@ top: calc(100% + 4px); left: 0; right: 0; - z-index: 50; + /* Search suggestions render above `.page-sticky-header` — otherwise the + dropdown clips under the action bar on the content pages. Design-token + `--z-dropdown` (1000) sits above `--z-sticky` (100) by construction. */ + z-index: var(--z-dropdown); list-style: none; margin: 0; padding: 0.25rem; @@ -1117,7 +1120,8 @@ position: absolute; bottom: calc(100% + 4px); right: 0; - z-index: 60; + /* Sits above `--z-sticky` for the same reason as `.suggest` above. */ + z-index: var(--z-dropdown); min-width: 12rem; max-height: 18rem; overflow: auto; diff --git a/frontend/src/lib/components/ResourceList.svelte b/frontend/src/lib/components/ResourceList.svelte index ba645ee7..e7a003e0 100644 --- a/frontend/src/lib/components/ResourceList.svelte +++ b/frontend/src/lib/components/ResourceList.svelte @@ -902,28 +902,44 @@ // breadcrumb) are handled by the existing `onitemdrop` hooks and use // a private `application/x-oxi-item` MIME so the `Files` type check // below never matches them. - let systemDropOver = $state(false); + // Drag-enter/leave chatter is unavoidable when the drag pointer moves + // between the wrapper and its descendants — the browser fires + // `dragleave` on the parent BEFORE firing `dragenter` on the child, + // so a naive `systemDropOver = false` in the leave handler produces + // a false→true flash on every row hover during the drag. Counter + // approach: increment on every dragenter, decrement on every + // dragleave; the overlay is visible when the count is positive. The + // count zeroes only when the drag has truly left the wrapper (or + // hit `drop`/`dragend`), so the overlay stays stable throughout. + let systemDragDepth = $state(0); + const systemDropOver = $derived(systemDragDepth > 0); function isSystemDrag(e: DragEvent): boolean { return !!e.dataTransfer?.types?.includes('Files'); } function onSystemDragEnter(e: DragEvent) { if (!isSystemDrag(e)) return; e.preventDefault(); - systemDropOver = true; + systemDragDepth++; } function onSystemDragOver(e: DragEvent) { if (!isSystemDrag(e)) return; + // preventDefault on `dragover` is what tells the browser this + // element accepts drops — without it, `drop` never fires and + // the pointer shows the OS "no-drop" cursor. e.preventDefault(); if (e.dataTransfer) e.dataTransfer.dropEffect = enableSystemDrop ? 'copy' : 'none'; } function onSystemDragLeave(e: DragEvent) { if (!isSystemDrag(e)) return; - systemDropOver = false; + if (systemDragDepth > 0) systemDragDepth--; } function onSystemDrop(e: DragEvent) { if (!isSystemDrag(e)) return; e.preventDefault(); - systemDropOver = false; + // Drop ends the drag; force-clear regardless of counter state + // (a stray unbalanced dragenter would otherwise leave the + // overlay stuck on). + systemDragDepth = 0; if (enableSystemDrop && onsystemdrop) { onsystemdrop(e); } else if (!enableSystemDrop) { @@ -1138,7 +1154,6 @@ {/if} + + + {#if systemDropOver && enableSystemDrop} + + {/if} @@ -1419,13 +1452,50 @@ position: relative; } - .rl-root--drop-over::after { - content: ''; - position: absolute; + /* Viewport-fixed drop overlay. `position: fixed` (not absolute) so + it covers the whole visible browser window regardless of the + user's scroll position — an absolute-inset-0 inside `.rl-root` + would center the card at the middle of the FULL list height, + which sits above the fold on a scrolled folder. The dashed border + also gets painted at the true viewport edge, so the sticky + action-bar + breadcrumb are covered rather than clipping the + border. `pointer-events: none` so drag events still fall through + to `.rl-root`'s handlers underneath. + `--z-overlay` beats `--z-sticky` (page chrome) + `--z-dropdown` + (search suggestions); stays below `--z-modal` so a modal opened + concurrently still wins. */ + .rl-drop-overlay { + position: fixed; inset: 0; + display: flex; + align-items: center; + justify-content: center; + background: color-mix(in srgb, var(--color-accent) 12%, transparent); border: 2px dashed var(--color-accent); border-radius: var(--radius-md); pointer-events: none; + z-index: var(--z-overlay); + } + + .rl-drop-overlay__inner { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-3); + padding: var(--space-6) var(--space-8); + color: var(--color-accent); + background: var(--color-bg-surface); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + } + + .rl-drop-overlay :global(.rl-drop-overlay__icon) { + font-size: 3rem; + } + + .rl-drop-overlay__label { + font-weight: var(--weight-semibold); + font-size: var(--text-lg); } /* ── Rubberband (marquee) selection ──────────────────────────── diff --git a/frontend/static/locales/ar.json b/frontend/static/locales/ar.json index 00fcd333..5aec9991 100644 --- a/frontend/static/locales/ar.json +++ b/frontend/static/locales/ar.json @@ -339,6 +339,7 @@ "modified": "تاريخ التعديل", "no_files": "لا توجد ملفات في هذا المجلد", "empty_hint": "ارفع ملفات أو أنشئ مجلدات للبدء", + "drop_to_upload": "أفلت الملفات هنا للرفع", "loading": "جارٍ تحميل الملفات…", "view_grid": "عرض شبكي", "view_list": "عرض قائمة", diff --git a/frontend/static/locales/de.json b/frontend/static/locales/de.json index 5b3b6915..a0ec447d 100644 --- a/frontend/static/locales/de.json +++ b/frontend/static/locales/de.json @@ -339,6 +339,7 @@ "modified": "Geändert", "no_files": "Keine Dateien in diesem Ordner", "empty_hint": "Laden Sie Dateien hoch oder erstellen Sie Ordner, um loszulegen", + "drop_to_upload": "Dateien zum Hochladen hier ablegen", "loading": "Dateien werden geladen…", "view_grid": "Rasteransicht", "view_list": "Listenansicht", diff --git a/frontend/static/locales/en.json b/frontend/static/locales/en.json index 3438c366..628bde40 100644 --- a/frontend/static/locales/en.json +++ b/frontend/static/locales/en.json @@ -444,6 +444,7 @@ "modified": "Modified", "no_files": "No files in this folder", "empty_hint": "Upload files or create folders to get started", + "drop_to_upload": "Drop files here to upload", "loading": "Loading files…", "view_grid": "Grid view", "view_list": "List view", diff --git a/frontend/static/locales/es.json b/frontend/static/locales/es.json index 5e959f44..19d0ddbd 100644 --- a/frontend/static/locales/es.json +++ b/frontend/static/locales/es.json @@ -339,6 +339,7 @@ "modified": "Modificado", "no_files": "No hay archivos en esta carpeta", "empty_hint": "Sube archivos o crea carpetas para comenzar", + "drop_to_upload": "Arrastra archivos aquí para subirlos", "loading": "Cargando archivos…", "view_grid": "Vista de cuadrícula", "view_list": "Vista de lista", diff --git a/frontend/static/locales/fa.json b/frontend/static/locales/fa.json index 8a4f90d1..10db53d5 100644 --- a/frontend/static/locales/fa.json +++ b/frontend/static/locales/fa.json @@ -339,6 +339,7 @@ "modified": "تاریخ تغییر", "no_files": "هنوز هیچ پرونده‌ای در این پوشه وجود ندارد", "empty_hint": "برای شروع، فایل‌ها را آپلود کنید یا پوشه بسازید", + "drop_to_upload": "برای بارگذاری، فایل‌ها را اینجا رها کنید", "loading": "در حال بارگذاری فایل‌ها…", "view_grid": "نمای شبکه‌ای", "view_list": "نمای فهرستی", diff --git a/frontend/static/locales/fr.json b/frontend/static/locales/fr.json index c285f539..b2cfc6c9 100644 --- a/frontend/static/locales/fr.json +++ b/frontend/static/locales/fr.json @@ -339,6 +339,7 @@ "modified": "Modifié", "no_files": "Aucun fichier dans ce dossier", "empty_hint": "Téléversez des fichiers ou créez des dossiers pour commencer", + "drop_to_upload": "Déposez les fichiers ici pour les téléverser", "loading": "Chargement des fichiers…", "view_grid": "Vue en grille", "view_list": "Vue en liste", diff --git a/frontend/static/locales/hi.json b/frontend/static/locales/hi.json index e63f537e..31a152ed 100644 --- a/frontend/static/locales/hi.json +++ b/frontend/static/locales/hi.json @@ -339,6 +339,7 @@ "modified": "संशोधित", "no_files": "इस फ़ोल्डर में कोई फ़ाइल नहीं", "empty_hint": "शुरू करने के लिए ह़ैलें अपलोड करें या होल्डर बनाएँ", + "drop_to_upload": "अपलोड करने के लिए फ़ाइलें यहाँ छोड़ें", "loading": "फ़ाइलें लोड हो रही हैं…", "view_grid": "ग्रिड दृश्य", "view_list": "सूची दृश्य", diff --git a/frontend/static/locales/it.json b/frontend/static/locales/it.json index 6a8a0335..1ddd3942 100644 --- a/frontend/static/locales/it.json +++ b/frontend/static/locales/it.json @@ -339,6 +339,7 @@ "modified": "Modificato", "no_files": "Nessun file in questa cartella", "empty_hint": "Carica file o crea cartelle per iniziare", + "drop_to_upload": "Trascina i file qui per caricarli", "loading": "Caricamento file…", "view_grid": "Visualizzazione griglia", "view_list": "Visualizzazione elenco", diff --git a/frontend/static/locales/ja.json b/frontend/static/locales/ja.json index adbb1125..5feff156 100644 --- a/frontend/static/locales/ja.json +++ b/frontend/static/locales/ja.json @@ -339,6 +339,7 @@ "modified": "更新日", "no_files": "このフォルダにファイルはありません", "empty_hint": "ファイルをアップロードするかフォルダを作成して始めましょう", + "drop_to_upload": "アップロードするファイルをここにドロップ", "loading": "ファイルを読み込み中…", "view_grid": "グリッド表示", "view_list": "リスト表示", diff --git a/frontend/static/locales/ko.json b/frontend/static/locales/ko.json index 05939621..082c323b 100644 --- a/frontend/static/locales/ko.json +++ b/frontend/static/locales/ko.json @@ -409,6 +409,7 @@ "modified": "수정일", "no_files": "이 폴더에 파일이 없습니다", "empty_hint": "파일을 업로드하거나 폴더를 만들어 시작하세요", + "drop_to_upload": "업로드할 파일을 여기에 놓으세요", "loading": "파일 로딩 중…", "view_grid": "그리드 보기", "view_list": "목록 보기", diff --git a/frontend/static/locales/nl.json b/frontend/static/locales/nl.json index 916950f7..fc74afae 100644 --- a/frontend/static/locales/nl.json +++ b/frontend/static/locales/nl.json @@ -339,6 +339,7 @@ "modified": "Gewijzigd", "no_files": "Geen bestanden in deze map", "empty_hint": "Upload bestanden of maak mappen aan om te beginnen", + "drop_to_upload": "Sleep bestanden hier om te uploaden", "loading": "Bestanden laden…", "view_grid": "Rasterweergave", "view_list": "Lijstweergave", diff --git a/frontend/static/locales/pl.json b/frontend/static/locales/pl.json index d8fc732d..f58b9426 100644 --- a/frontend/static/locales/pl.json +++ b/frontend/static/locales/pl.json @@ -339,6 +339,7 @@ "modified": "Zmodyfikowano", "no_files": "Brak plików w tym folderze", "empty_hint": "Prześlij pliki lub utwórz foldery, aby rozpocząć", + "drop_to_upload": "Upuść pliki tutaj, aby wysłać", "loading": "Ładowanie plików…", "view_grid": "Widok siatki", "view_list": "Widok listy", diff --git a/frontend/static/locales/pt.json b/frontend/static/locales/pt.json index c67388a8..80dee965 100644 --- a/frontend/static/locales/pt.json +++ b/frontend/static/locales/pt.json @@ -339,6 +339,7 @@ "modified": "Modificado", "no_files": "Nenhum arquivo nesta pasta", "empty_hint": "Envie arquivos ou crie pastas para começar", + "drop_to_upload": "Solte arquivos aqui para enviar", "loading": "Carregando arquivos…", "view_grid": "Visualização em grade", "view_list": "Visualização em lista", diff --git a/frontend/static/locales/ru.json b/frontend/static/locales/ru.json index ac182e02..71a83525 100644 --- a/frontend/static/locales/ru.json +++ b/frontend/static/locales/ru.json @@ -339,6 +339,7 @@ "modified": "Изменён", "no_files": "В этой папке нет файлов", "empty_hint": "Загрузите файлы или создайте папки, чтобы начать", + "drop_to_upload": "Перетащите файлы сюда для загрузки", "loading": "Загрузка файлов…", "view_grid": "Сетка", "view_list": "Список", diff --git a/frontend/static/locales/zh-TW.json b/frontend/static/locales/zh-TW.json index 6e0dc07e..c08b89ba 100644 --- a/frontend/static/locales/zh-TW.json +++ b/frontend/static/locales/zh-TW.json @@ -339,6 +339,7 @@ "modified": "修改日期", "no_files": "此資料夾中沒有檔案", "empty_hint": "上傳檔案或建立資料夾以開始使用", + "drop_to_upload": "將檔案拖放到此處上傳", "loading": "正在載入檔案…", "view_grid": "網格檢視", "view_list": "列表檢視", diff --git a/frontend/static/locales/zh.json b/frontend/static/locales/zh.json index 48f1dca7..61516be3 100644 --- a/frontend/static/locales/zh.json +++ b/frontend/static/locales/zh.json @@ -339,6 +339,7 @@ "modified": "修改日期", "no_files": "此文件夹中没有文件", "empty_hint": "上传文件或创建文件夹以开始使用", + "drop_to_upload": "将文件拖放到此处上传", "loading": "正在加载文件…", "view_grid": "网格视图", "view_list": "列表视图",