Fix dragging selected notes to notebooks

This commit is contained in:
Yuri Karamian
2026-08-03 00:27:18 +02:00
parent 54e051ba02
commit e62404d4c0
4 changed files with 78 additions and 19 deletions
+18 -5
View File
@@ -40,6 +40,7 @@
} from '$lib/api';
import { formatRelativeTime, formatDate, dateBucketLabel } from '$lib/utils/time';
import { openNoteWindow } from '$lib/utils/window';
import { encodeNoteDragPaths } from '$lib/utils/note-drag';
import { revealItemInDir } from '@tauri-apps/plugin-opener';
import type { NoteEntry, TrashNotebookEntry, SortMode, TaskItem } from '$lib/types';
import TasksView from './TasksView.svelte';
@@ -265,6 +266,19 @@
if (listContainer) listContainer.scrollTop = 0;
});
// Notes can also be removed from this list by a drop handled in the sidebar.
$effect(() => {
if (selectedPaths.size === 0) return;
const availablePaths = new Set($notes.map((note) => note.path));
const remaining = new Set([...selectedPaths].filter((path) => availablePaths.has(path)));
if (remaining.size === selectedPaths.size) return;
if (remaining.size === 0) {
clearSelection();
} else {
selectedPaths = remaining;
}
});
// Invalidate quickaccess cache when starred notes change (e.g. from Editor star toggle)
$effect(() => {
$quickAccessPaths;
@@ -1259,11 +1273,10 @@
e.dataTransfer!.effectAllowed = 'move';
return;
}
if (selectedPaths.size > 1 && selectedPaths.has(note.path)) {
e.dataTransfer!.setData('text/plain', [...selectedPaths].join('\n'));
} else {
e.dataTransfer!.setData('text/plain', note.path);
}
const dragPaths = selectedPaths.size > 1 && selectedPaths.has(note.path)
? selectedPaths
: [note.path];
e.dataTransfer!.setData('text/plain', encodeNoteDragPaths(dragPaths));
e.dataTransfer!.effectAllowed = 'move';
}}
ondragover={(e) => {
+25 -14
View File
@@ -27,6 +27,7 @@
import { convertFileSrc } from '@tauri-apps/api/core';
import type { NotebookEntry } from '$lib/types';
import { isMobile } from '$lib/platform';
import { decodeNoteDragPaths } from '$lib/utils/note-drag';
let { onViewChanged = () => {} }: {
onViewChanged?: () => void;
@@ -340,22 +341,32 @@
async function handleNoteDrop(e: DragEvent, nb: NotebookEntry) {
e.preventDefault();
dropTargetPath = null;
const notePath = e.dataTransfer?.getData('text/plain');
if (!notePath) return;
// Don't move if already in this notebook
const noteDir = notePath.substring(0, notePath.lastIndexOf('/'));
if (noteDir === nb.path) return;
try {
const newPath = await moveNote(notePath, nb.path);
$notes = $notes.filter(n => n.path !== notePath);
if ($activeNotePath === notePath) {
$activeNotePath = newPath;
$activeNote = await readNote(newPath);
const payload = e.dataTransfer?.getData('text/plain') ?? '';
const notePaths = [...new Set(decodeNoteDragPaths(payload))]
.filter((path) => norm(parentOf(path)) !== norm(nb.path));
if (notePaths.length === 0) return;
const movedPaths = new Map<string, string>();
for (const notePath of notePaths) {
try {
movedPaths.set(notePath, await moveNote(notePath, nb.path));
} catch (e) {
console.error('Failed to move note:', notePath, e);
}
await refresh();
} catch (e) {
console.error('Failed to move note:', e);
}
if (movedPaths.size === 0) return;
$notes = $notes.filter((note) => !movedPaths.has(note.path));
const activeNewPath = $activeNotePath ? movedPaths.get($activeNotePath) : undefined;
if (activeNewPath) {
$activeNotePath = activeNewPath;
try {
$activeNote = await readNote(activeNewPath);
} catch (e) {
console.error('Failed to reload moved note:', e);
}
}
await refresh();
}
async function handleNotebookDrop(e: DragEvent, destPath: string) {
+7
View File
@@ -0,0 +1,7 @@
export function encodeNoteDragPaths(paths: Iterable<string>): string {
return [...paths].join("\n");
}
export function decodeNoteDragPaths(payload: string): string[] {
return payload.split(/\r?\n/).filter((path) => path.length > 0);
}