added recursion to folders
This commit is contained in:
parent
2ced303894
commit
37078ddc4c
130
frontend/app.js
130
frontend/app.js
|
|
@ -379,6 +379,132 @@ function noteApp() {
|
||||||
this.folderTree = { ...tree };
|
this.folderTree = { ...tree };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Render folder recursively (helper for deep nesting)
|
||||||
|
renderFolderRecursive(folder, level = 0) {
|
||||||
|
if (!folder) return '';
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
const baseIndent = level * 12;
|
||||||
|
|
||||||
|
// First, render child folders (if any)
|
||||||
|
if (folder.children && Object.keys(folder.children).length > 0) {
|
||||||
|
const children = Object.entries(folder.children).sort((a, b) =>
|
||||||
|
a[1].name.toLowerCase().localeCompare(b[1].name.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
children.forEach(([childKey, childFolder]) => {
|
||||||
|
const isExpanded = this.expandedFolders.has(childFolder.path);
|
||||||
|
|
||||||
|
// Folder header HTML (no margin - it's inside folder-contents which provides the indent)
|
||||||
|
html += `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
draggable="true"
|
||||||
|
x-data="{}"
|
||||||
|
@dragstart="onFolderDragStart('${childFolder.path.replace(/'/g, "\\'")}' )"
|
||||||
|
@dragend="onFolderDragEnd()"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop.stop="onFolderDrop('${childFolder.path.replace(/'/g, "\\'")}')"
|
||||||
|
class="folder-item px-2 py-2 mb-1 text-sm rounded transition-all relative"
|
||||||
|
style="color: var(--text-primary); cursor: pointer;"
|
||||||
|
:class="draggedNote || draggedFolder ? 'border-2 border-dashed border-accent-primary bg-accent-light' : 'border-2 border-transparent'"
|
||||||
|
@mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'"
|
||||||
|
@mouseout="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='transparent'"
|
||||||
|
@click="toggleFolder('${childFolder.path.replace(/'/g, "\\'")}')"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
class="flex-shrink-0 w-4 h-4 flex items-center justify-center"
|
||||||
|
style="color: var(--text-tertiary); cursor: pointer; transition: transform 0.2s; pointer-events: none; ${isExpanded ? 'transform: rotate(90deg);' : ''}"
|
||||||
|
>
|
||||||
|
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
|
||||||
|
<path d="M6 4l4 4-4 4V4z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<span class="flex items-center gap-1 flex-1" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; pointer-events: none;">
|
||||||
|
<span>${childFolder.name}</span>
|
||||||
|
${childFolder.notes.length === 0 && (!childFolder.children || Object.keys(childFolder.children).length === 0) ? '<span class="text-xs" style="color: var(--text-tertiary); font-weight: 400;">(empty)</span>' : ''}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="hover-buttons flex gap-1 transition-opacity absolute right-2 top-1/2 transform -translate-y-1/2" style="opacity: 0; pointer-events: none; background: linear-gradient(to right, transparent, var(--bg-hover) 20%, var(--bg-hover)); padding-left: 20px;" @click.stop>
|
||||||
|
<button
|
||||||
|
@click="createNoteInFolder('${childFolder.path.replace(/'/g, "\\'")}')"
|
||||||
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
|
title="New note in this folder"
|
||||||
|
>📄</button>
|
||||||
|
<button
|
||||||
|
@click="createNewFolder('${childFolder.path.replace(/'/g, "\\'")}')"
|
||||||
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
|
title="New subfolder"
|
||||||
|
>📁</button>
|
||||||
|
<button
|
||||||
|
@click="renameFolder('${childFolder.path.replace(/'/g, "\\'")}', '${childFolder.name.replace(/'/g, "\\'")}')"
|
||||||
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
|
title="Rename folder"
|
||||||
|
>✏️</button>
|
||||||
|
<button
|
||||||
|
@click="deleteFolder('${childFolder.path.replace(/'/g, "\\'")}', '${childFolder.name.replace(/'/g, "\\'")}')"
|
||||||
|
class="px-1 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
|
style="color: var(--error);"
|
||||||
|
title="Delete folder and all contents"
|
||||||
|
>
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// If expanded, recursively render this folder's contents (notes + subfolders)
|
||||||
|
if (isExpanded) {
|
||||||
|
html += `<div class="folder-contents" style="padding-left: 12px;">`;
|
||||||
|
html += this.renderFolderRecursive(childFolder, 0); // Reset level to 0 for relative positioning
|
||||||
|
html += `</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `</div>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, render notes in this folder (after subfolders)
|
||||||
|
if (folder.notes && folder.notes.length > 0) {
|
||||||
|
folder.notes.forEach(note => {
|
||||||
|
const isCurrentNote = this.currentNote === note.path;
|
||||||
|
html += `
|
||||||
|
<div
|
||||||
|
draggable="true"
|
||||||
|
x-data="{}"
|
||||||
|
@dragstart="onNoteDragStart('${note.path.replace(/'/g, "\\'")}', $event)"
|
||||||
|
@dragend="onNoteDragEnd()"
|
||||||
|
@click="loadNote('${note.path.replace(/'/g, "\\'")}')"
|
||||||
|
class="note-item px-3 py-2 mb-1 text-sm rounded relative"
|
||||||
|
style="${isCurrentNote ? 'background-color: var(--accent-light); color: var(--accent-primary);' : 'color: var(--text-primary);'} cursor: pointer;"
|
||||||
|
@mouseover="if('${note.path}' !== currentNote) $el.style.backgroundColor='var(--bg-hover)'"
|
||||||
|
@mouseout="if('${note.path}' !== currentNote) $el.style.backgroundColor='transparent'"
|
||||||
|
>
|
||||||
|
<span class="truncate">${note.name}</span>
|
||||||
|
<button
|
||||||
|
@click.stop="deleteNote('${note.path.replace(/'/g, "\\'")}', '${note.name.replace(/'/g, "\\'")}')"
|
||||||
|
class="note-delete-btn absolute right-2 top-1/2 transform -translate-y-1/2 px-1 py-0.5 text-xs rounded hover:brightness-110 transition-opacity"
|
||||||
|
style="opacity: 0; color: var(--error);"
|
||||||
|
title="Delete note"
|
||||||
|
>
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
|
||||||
// Toggle folder expansion
|
// Toggle folder expansion
|
||||||
toggleFolder(folderPath) {
|
toggleFolder(folderPath) {
|
||||||
if (this.expandedFolders.has(folderPath)) {
|
if (this.expandedFolders.has(folderPath)) {
|
||||||
|
|
@ -386,6 +512,10 @@ function noteApp() {
|
||||||
} else {
|
} else {
|
||||||
this.expandedFolders.add(folderPath);
|
this.expandedFolders.add(folderPath);
|
||||||
}
|
}
|
||||||
|
// Force Alpine reactivity by creating new Set reference
|
||||||
|
this.expandedFolders = new Set(this.expandedFolders);
|
||||||
|
// Also trigger folderTree reactivity to re-render x-html
|
||||||
|
this.folderTree = { ...this.folderTree };
|
||||||
},
|
},
|
||||||
|
|
||||||
// Check if folder is expanded
|
// Check if folder is expanded
|
||||||
|
|
|
||||||
|
|
@ -687,10 +687,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Folders -->
|
<!-- Folders (rendered recursively for unlimited nesting) -->
|
||||||
<template x-for="[folderKey, folder] in Object.entries(folderTree).filter(([k]) => k !== '__root__').sort((a, b) => a[1].name.toLowerCase().localeCompare(b[1].name.toLowerCase()))" :key="folderKey">
|
<template x-for="[folderKey, folder] in Object.entries(folderTree).filter(([k]) => k !== '__root__').sort((a, b) => a[1].name.toLowerCase().localeCompare(b[1].name.toLowerCase()))" :key="folderKey">
|
||||||
<div>
|
<div>
|
||||||
<!-- Folder header with drop zone -->
|
<!-- Top-level folder -->
|
||||||
<div
|
<div
|
||||||
draggable="true"
|
draggable="true"
|
||||||
@dragstart="onFolderDragStart(folder.path)"
|
@dragstart="onFolderDragStart(folder.path)"
|
||||||
|
|
@ -702,7 +702,7 @@
|
||||||
:style="'color: var(--text-primary);' + (draggedNote || draggedFolder ? ' cursor: grabbing;' : ' cursor: pointer;')"
|
:style="'color: var(--text-primary);' + (draggedNote || draggedFolder ? ' cursor: grabbing;' : ' cursor: pointer;')"
|
||||||
@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) $el.style.backgroundColor='transparent'"
|
||||||
@click="toggleFolder(folder.path); $nextTick(() => buildFolderTree())"
|
@click="toggleFolder(folder.path)"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
|
|
@ -719,166 +719,43 @@
|
||||||
<span x-show="folder.notes.length === 0 && (!folder.children || Object.keys(folder.children).length === 0)" class="text-xs" style="color: var(--text-tertiary); font-weight: 400;">(empty)</span>
|
<span x-show="folder.notes.length === 0 && (!folder.children || Object.keys(folder.children).length === 0)" class="text-xs" style="color: var(--text-tertiary); font-weight: 400;">(empty)</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hover-buttons flex gap-1 transition-opacity absolute right-2 top-1/2 transform -translate-y-1/2" style="opacity: 0; pointer-events: none; background: linear-gradient(to right, transparent, var(--bg-hover) 20%, var(--bg-hover)); padding-left: 20px;" @click.stop>
|
<div class="hover-buttons flex gap-1 transition-opacity absolute right-2 top-1/2 transform -translate-y-1/2" style="opacity: 0; pointer-events: none; background: linear-gradient(to right, transparent, var(--bg-hover) 20%, var(--bg-hover)); padding-left: 20px;" @click.stop>
|
||||||
<button
|
<button
|
||||||
@click="renameFolder(folder.path, folder.name)"
|
@click="createNoteInFolder(folder.path)"
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
title="Rename folder"
|
title="New note in this folder"
|
||||||
>✏️</button>
|
>📄</button>
|
||||||
<button
|
<button
|
||||||
@click="createNoteInFolder(folder.path)"
|
@click="createNewFolder(folder.path)"
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
title="New note in this folder"
|
title="New subfolder"
|
||||||
>📄</button>
|
>📁</button>
|
||||||
<button
|
<button
|
||||||
@click="createNewFolder(folder.path)"
|
@click="renameFolder(folder.path, folder.name)"
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
||||||
title="New subfolder"
|
title="Rename folder"
|
||||||
>📁</button>
|
>✏️</button>
|
||||||
<button
|
<button
|
||||||
@click="deleteFolder(folder.path, folder.name)"
|
@click="deleteFolder(folder.path, folder.name)"
|
||||||
class="px-1 py-0.5 text-xs rounded hover:brightness-110"
|
class="px-1 py-0.5 text-xs rounded hover:brightness-110"
|
||||||
style="color: var(--error);"
|
style="color: var(--error);"
|
||||||
title="Delete folder and all contents"
|
title="Delete folder and all contents"
|
||||||
>
|
>
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Folder contents (when expanded) -->
|
<!-- Folder contents (when expanded) - notes and recursive subfolders -->
|
||||||
<template x-if="isFolderExpanded(folder.path)">
|
<template x-if="isFolderExpanded(folder.path)">
|
||||||
<div class="folder-contents">
|
<div class="folder-contents" style="padding-left: 12px;">
|
||||||
<!-- Subfolders (recursive) -->
|
<!-- Recursively render notes and subfolders (infinite depth) -->
|
||||||
<template x-if="folder.children && Object.keys(folder.children).length > 0">
|
<div x-html="renderFolderRecursive(folder, 0)"></div>
|
||||||
<template x-for="[childKey, childFolder] in Object.entries(folder.children).sort((a, b) => a[1].name.toLowerCase().localeCompare(b[1].name.toLowerCase()))" :key="childKey">
|
|
||||||
<div>
|
|
||||||
<!-- Subfolder header -->
|
|
||||||
<div
|
|
||||||
draggable="true"
|
|
||||||
@dragstart="onFolderDragStart(childFolder.path)"
|
|
||||||
@dragend="onFolderDragEnd()"
|
|
||||||
@dragover.prevent
|
|
||||||
@drop.stop="onFolderDrop(childFolder.path)"
|
|
||||||
class="folder-item px-2 py-2 mb-1 text-sm rounded transition-all relative"
|
|
||||||
:class="draggedNote || draggedFolder ? 'border-2 border-dashed border-accent-primary bg-accent-light' : 'border-2 border-transparent'"
|
|
||||||
:style="'color: var(--text-primary);' + (draggedNote || draggedFolder ? ' cursor: grabbing;' : ' cursor: pointer;')"
|
|
||||||
@mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'"
|
|
||||||
@mouseout="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='transparent'"
|
|
||||||
@click="toggleFolder(childFolder.path); $nextTick(() => buildFolderTree())"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-1">
|
|
||||||
<button
|
|
||||||
class="flex-shrink-0 w-4 h-4 flex items-center justify-center"
|
|
||||||
style="color: var(--text-tertiary); cursor: pointer; transition: transform 0.2s; pointer-events: none;"
|
|
||||||
:style="isFolderExpanded(childFolder.path) ? 'transform: rotate(90deg);' : ''"
|
|
||||||
>
|
|
||||||
<svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
|
|
||||||
<path d="M6 4l4 4-4 4V4z"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<span class="flex items-center gap-1 flex-1" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; pointer-events: none;">
|
|
||||||
<span x-text="childFolder.name"></span>
|
|
||||||
<span x-show="childFolder.notes.length === 0 && (!childFolder.children || Object.keys(childFolder.children).length === 0)" class="text-xs" style="color: var(--text-tertiary); font-weight: 400;">(empty)</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="hover-buttons flex gap-1 transition-opacity absolute right-2 top-1/2 transform -translate-y-1/2" style="opacity: 0; pointer-events: none; background: linear-gradient(to right, transparent, var(--bg-hover) 20%, var(--bg-hover)); padding-left: 20px;" @click.stop>
|
|
||||||
<button
|
|
||||||
@click="renameFolder(childFolder.path, childFolder.name)"
|
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
|
||||||
title="Rename folder"
|
|
||||||
>✏️</button>
|
|
||||||
<button
|
|
||||||
@click="createNoteInFolder(childFolder.path)"
|
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
|
||||||
title="New note in this folder"
|
|
||||||
>📄</button>
|
|
||||||
<button
|
|
||||||
@click="createNewFolder(childFolder.path)"
|
|
||||||
class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
|
|
||||||
style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
|
|
||||||
title="New subfolder"
|
|
||||||
>📁</button>
|
|
||||||
<button
|
|
||||||
@click="deleteFolder(childFolder.path, childFolder.name)"
|
|
||||||
class="px-1 py-0.5 text-xs rounded hover:brightness-110"
|
|
||||||
style="color: var(--error);"
|
|
||||||
title="Delete folder and all contents"
|
|
||||||
>
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Subfolder notes -->
|
|
||||||
<template x-if="isFolderExpanded(childFolder.path) && childFolder.notes && childFolder.notes.length > 0">
|
|
||||||
<div class="folder-contents">
|
|
||||||
<template x-for="note in childFolder.notes" :key="note.path">
|
|
||||||
<div
|
|
||||||
draggable="true"
|
|
||||||
@dragstart="onNoteDragStart(note.path, $event)"
|
|
||||||
@dragend="onNoteDragEnd()"
|
|
||||||
@click="loadNote(note.path)"
|
|
||||||
class="note-item px-3 py-2 mb-1 text-sm rounded relative"
|
|
||||||
:style="(currentNote === note.path ? 'background-color: var(--accent-light); color: var(--accent-primary);' : 'color: var(--text-primary);') + (draggedNote || draggedFolder ? ' cursor: grabbing;' : ' cursor: pointer;')"
|
|
||||||
@mouseover="if(currentNote !== note.path) $el.style.backgroundColor='var(--bg-hover)'"
|
|
||||||
@mouseout="if(currentNote !== note.path) $el.style.backgroundColor='transparent'"
|
|
||||||
>
|
|
||||||
<span class="truncate" x-text="note.name"></span>
|
|
||||||
<button
|
|
||||||
@click.stop="deleteNote(note.path, note.name)"
|
|
||||||
class="note-delete-btn absolute right-2 top-1/2 transform -translate-y-1/2 px-1 py-0.5 text-xs rounded hover:brightness-110 transition-opacity"
|
|
||||||
style="opacity: 0; color: var(--error);"
|
|
||||||
title="Delete note"
|
|
||||||
>
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- Notes in this folder -->
|
|
||||||
<template x-if="folder.notes && folder.notes.length > 0">
|
|
||||||
<template x-for="note in folder.notes" :key="note.path">
|
|
||||||
<div
|
|
||||||
draggable="true"
|
|
||||||
@dragstart="onNoteDragStart(note.path, $event)"
|
|
||||||
@dragend="onNoteDragEnd()"
|
|
||||||
@click="loadNote(note.path)"
|
|
||||||
class="note-item px-3 py-2 mb-1 text-sm rounded relative"
|
|
||||||
:style="(currentNote === note.path ? 'background-color: var(--accent-light); color: var(--accent-primary);' : 'color: var(--text-primary);') + (draggedNote || draggedFolder ? ' cursor: grabbing;' : ' cursor: pointer;')"
|
|
||||||
@mouseover="if(currentNote !== note.path) $el.style.backgroundColor='var(--bg-hover)'"
|
|
||||||
@mouseout="if(currentNote !== note.path) $el.style.backgroundColor='transparent'"
|
|
||||||
>
|
|
||||||
<span class="truncate" x-text="note.name"></span>
|
|
||||||
<button
|
|
||||||
@click.stop="deleteNote(note.path, note.name)"
|
|
||||||
class="note-delete-btn absolute right-2 top-1/2 transform -translate-y-1/2 px-1 py-0.5 text-xs rounded hover:brightness-110 transition-opacity"
|
|
||||||
style="opacity: 0; color: var(--error);"
|
|
||||||
title="Delete note"
|
|
||||||
>
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue