better drag & drop experience

This commit is contained in:
Gamosoft 2025-11-18 10:03:47 +01:00
parent 8338657bad
commit 06edcf7dd1
2 changed files with 71 additions and 12 deletions

View File

@ -59,6 +59,7 @@ function noteApp() {
expandedFolders: new Set(), expandedFolders: new Set(),
draggedNote: null, draggedNote: null,
draggedFolder: null, draggedFolder: null,
dragOverFolder: null, // Track which folder is being hovered during drag
// Scroll sync state // Scroll sync state
isScrolling: false, isScrolling: false,
@ -441,15 +442,25 @@ function noteApp() {
<div <div
draggable="true" draggable="true"
x-data="{}" x-data="{}"
@dragstart="onFolderDragStart('${folder.path.replace(/'/g, "\\'")}' )" @dragstart="onFolderDragStart('${folder.path.replace(/'/g, "\\'")}', $event)"
@dragend="onFolderDragEnd()" @dragend="onFolderDragEnd()"
@dragover.prevent @dragover.prevent="dragOverFolder = '${folder.path.replace(/'/g, "\\'")}'"
@dragenter.prevent="dragOverFolder = '${folder.path.replace(/'/g, "\\'")}'"
@dragleave="dragOverFolder = null"
@drop.stop="onFolderDrop('${folder.path.replace(/'/g, "\\'")}' )" @drop.stop="onFolderDrop('${folder.path.replace(/'/g, "\\'")}' )"
class="folder-item px-2 py-2 mb-1 text-sm rounded transition-all relative" class="folder-item px-3 py-3 mb-1 text-sm rounded transition-all relative"
style="color: var(--text-primary); cursor: pointer;" style="color: var(--text-primary); cursor: pointer;"
:class="draggedNote || draggedFolder ? 'border-2 border-dashed border-accent-primary bg-accent-light' : 'border-2 border-transparent'" :class="{
'border-2 border-dashed bg-accent-light': (draggedNote || draggedFolder) && dragOverFolder === '${folder.path.replace(/'/g, "\\'")}',
'border-2 border-dashed': (draggedNote || draggedFolder) && dragOverFolder !== '${folder.path.replace(/'/g, "\\'")}',
'border-2 border-transparent': !draggedNote && !draggedFolder
}"
:style="{
'border-color': (draggedNote || draggedFolder) && dragOverFolder === '${folder.path.replace(/'/g, "\\'")}' ? 'var(--accent-primary)' : 'var(--border-secondary)',
'background-color': dragOverFolder === '${folder.path.replace(/'/g, "\\'")}' ? 'var(--accent-light)' : ''
}"
@mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'" @mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'"
@mouseout="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='transparent'" @mouseout="if(!draggedNote && !draggedFolder && dragOverFolder !== '${folder.path.replace(/'/g, "\\'")}' ) $el.style.backgroundColor='transparent'"
@click="toggleFolder('${folder.path.replace(/'/g, "\\'")}')" @click="toggleFolder('${folder.path.replace(/'/g, "\\'")}')"
> >
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
@ -665,12 +676,21 @@ function noteApp() {
// Move mode: drag to move note // Move mode: drag to move note
this.draggedNote = notePath; this.draggedNote = notePath;
event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.effectAllowed = 'move';
// Make drag image semi-transparent
if (event.target) {
event.target.style.opacity = '0.5';
}
} }
}, },
onNoteDragEnd() { onNoteDragEnd() {
this.draggedNote = null; this.draggedNote = null;
this.draggedNoteForLink = null; this.draggedNoteForLink = null;
this.dragOverFolder = null;
// Reset opacity of all note items
document.querySelectorAll('.note-item').forEach(el => {
el.style.opacity = '1';
});
}, },
// Handle dragover on editor to show cursor position // Handle dragover on editor to show cursor position
@ -776,12 +796,21 @@ function noteApp() {
}, },
// Folder drag handlers // Folder drag handlers
onFolderDragStart(folderPath) { onFolderDragStart(folderPath, event) {
this.draggedFolder = folderPath; this.draggedFolder = folderPath;
// Make drag image semi-transparent
if (event && event.target) {
event.target.style.opacity = '0.5';
}
}, },
onFolderDragEnd() { onFolderDragEnd() {
this.draggedFolder = null; this.draggedFolder = null;
this.dragOverFolder = null;
// Reset opacity of all folder items
document.querySelectorAll('.folder-item').forEach(el => {
el.style.opacity = '1';
});
}, },
async onFolderDrop(targetFolderPath) { async onFolderDrop(targetFolderPath) {

View File

@ -350,6 +350,7 @@
/* Folder tree styling */ /* Folder tree styling */
.folder-item { .folder-item {
user-select: none; user-select: none;
transition: all 0.2s ease;
} }
.folder-item:hover { .folder-item:hover {
@ -362,6 +363,29 @@
.note-item { .note-item {
padding-left: 1.5rem; padding-left: 1.5rem;
transition: all 0.2s ease;
}
/* Drag and drop improvements */
.note-item[draggable="true"],
.folder-item[draggable="true"] {
cursor: grab;
}
.note-item[draggable="true"]:active,
.folder-item[draggable="true"]:active {
cursor: grabbing;
}
/* Smooth transitions for drag states */
.folder-item,
.note-item {
transition: opacity 0.2s ease, transform 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
/* Better drop zone visibility */
.folder-item:has(+ .folder-contents) {
position: relative;
} }
.hover-buttons { .hover-buttons {
@ -893,13 +917,19 @@
<!-- Root drop zone - only visible when dragging --> <!-- Root drop zone - only visible when dragging -->
<div <div
x-show="draggedNote || draggedFolder" x-show="draggedNote || draggedFolder"
@dragover.prevent x-transition
@dragover.prevent="dragOverFolder = '';"
@dragenter.prevent="dragOverFolder = '';"
@dragleave="dragOverFolder = null;"
@drop="onFolderDrop('')" @drop="onFolderDrop('')"
class="mb-3 px-3 py-2 rounded-lg border-2 border-dashed transition-all" class="mb-3 px-4 py-3 rounded-lg border-2 border-dashed transition-all"
style="border-color: var(--accent-primary); background-color: var(--accent-light);" :class="dragOverFolder === '' ? 'bg-accent-light' : ''"
:style="dragOverFolder === '' ? 'border-color: var(--accent-primary); transform: scale(1.02);' : 'border-color: var(--border-primary);'"
> >
<div class="text-xs text-center font-medium" style="color: var(--accent-primary);"> <div class="text-sm text-center font-medium flex items-center justify-center gap-2"
📂 Drop here to move to root folder :style="dragOverFolder === '' ? 'color: var(--accent-primary);' : 'color: var(--text-secondary);'">
<span>📂</span>
<span>Drop here to move to root folder</span>
</div> </div>
</div> </div>