@@ -380,128 +380,127 @@ function noteApp() {
380380 } ,
381381
382382 // Render folder recursively (helper for deep nesting)
383- renderFolderRecursive ( folder , level = 0 ) {
383+ renderFolderRecursive ( folder , level = 0 , isTopLevel = false ) {
384384 if ( ! folder ) return '' ;
385385
386386 let html = '' ;
387- const baseIndent = level * 12 ;
387+ const isExpanded = this . expandedFolders . has ( folder . path ) ;
388+
389+ // Render this folder's header
390+ html += `
391+ <div>
392+ <div
393+ draggable="true"
394+ x-data="{}"
395+ @dragstart="onFolderDragStart('${ folder . path . replace ( / ' / g, "\\'" ) } ' )"
396+ @dragend="onFolderDragEnd()"
397+ @dragover.prevent
398+ @drop.stop="onFolderDrop('${ folder . path . replace ( / ' / g, "\\'" ) } ')"
399+ class="folder-item px-2 py-2 mb-1 text-sm rounded transition-all relative"
400+ style="color: var(--text-primary); cursor: pointer;"
401+ :class="draggedNote || draggedFolder ? 'border-2 border-dashed border-accent-primary bg-accent-light' : 'border-2 border-transparent'"
402+ @mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'"
403+ @mouseout="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='transparent'"
404+ @click="toggleFolder('${ folder . path . replace ( / ' / g, "\\'" ) } ')"
405+ >
406+ <div class="flex items-center gap-1">
407+ <button
408+ class="flex-shrink-0 w-4 h-4 flex items-center justify-center"
409+ style="color: var(--text-tertiary); cursor: pointer; transition: transform 0.2s; pointer-events: none; ${ isExpanded ? 'transform: rotate(90deg);' : '' } "
410+ >
411+ <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
412+ <path d="M6 4l4 4-4 4V4z"/>
413+ </svg>
414+ </button>
415+ <span class="flex items-center gap-1 flex-1" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; pointer-events: none;">
416+ <span>${ folder . name } </span>
417+ ${ folder . notes . length === 0 && ( ! folder . children || Object . keys ( folder . children ) . length === 0 ) ? '<span class="text-xs" style="color: var(--text-tertiary); font-weight: 400;">(empty)</span>' : '' }
418+ </span>
419+ </div>
420+ <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>
421+ <button
422+ @click="createNoteInFolder('${ folder . path . replace ( / ' / g, "\\'" ) } ')"
423+ class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
424+ style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
425+ title="New note in this folder"
426+ >📄</button>
427+ <button
428+ @click="createNewFolder('${ folder . path . replace ( / ' / g, "\\'" ) } ')"
429+ class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
430+ style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
431+ title="New subfolder"
432+ >📁</button>
433+ <button
434+ @click="renameFolder('${ folder . path . replace ( / ' / g, "\\'" ) } ', '${ folder . name . replace ( / ' / g, "\\'" ) } ')"
435+ class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
436+ style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
437+ title="Rename folder"
438+ >✏️</button>
439+ <button
440+ @click="deleteFolder('${ folder . path . replace ( / ' / g, "\\'" ) } ', '${ folder . name . replace ( / ' / g, "\\'" ) } ')"
441+ class="px-1 py-0.5 text-xs rounded hover:brightness-110"
442+ style="color: var(--error);"
443+ title="Delete folder and all contents"
444+ >
445+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
446+ <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>
447+ </svg>
448+ </button>
449+ </div>
450+ </div>
451+ ` ;
388452
389- // First, render child folders (if any)
390- if ( folder . children && Object . keys ( folder . children ) . length > 0 ) {
391- const children = Object . entries ( folder . children ) . sort ( ( a , b ) =>
392- a [ 1 ] . name . toLowerCase ( ) . localeCompare ( b [ 1 ] . name . toLowerCase ( ) )
393- ) ;
453+ // If expanded, render folder contents (child folders + notes)
454+ if ( isExpanded ) {
455+ html += `<div class="folder-contents" style="padding-left: 12px;">` ;
394456
395- children . forEach ( ( [ childKey , childFolder ] ) => {
396- const isExpanded = this . expandedFolders . has ( childFolder . path ) ;
457+ // First, render child folders (if any)
458+ if ( folder . children && Object . keys ( folder . children ) . length > 0 ) {
459+ const children = Object . entries ( folder . children ) . sort ( ( a , b ) =>
460+ a [ 1 ] . name . toLowerCase ( ) . localeCompare ( b [ 1 ] . name . toLowerCase ( ) )
461+ ) ;
462+
463+ children . forEach ( ( [ childKey , childFolder ] ) => {
464+ html += this . renderFolderRecursive ( childFolder , 0 , false ) ;
465+ } ) ;
466+ }
397467
398- // Folder header HTML (no margin - it's inside folder-contents which provides the indent)
399- html += `
400- <div>
401- <div
402- draggable="true"
403- x-data="{}"
404- @dragstart="onFolderDragStart('${ childFolder . path . replace ( / ' / g, "\\'" ) } ' )"
405- @dragend="onFolderDragEnd()"
406- @dragover.prevent
407- @drop.stop="onFolderDrop('${ childFolder . path . replace ( / ' / g, "\\'" ) } ')"
408- class="folder-item px-2 py-2 mb-1 text-sm rounded transition-all relative"
409- style="color: var(--text-primary); cursor: pointer;"
410- :class="draggedNote || draggedFolder ? 'border-2 border-dashed border-accent-primary bg-accent-light' : 'border-2 border-transparent'"
411- @mouseover="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='var(--bg-hover)'"
412- @mouseout="if(!draggedNote && !draggedFolder) $el.style.backgroundColor='transparent'"
413- @click="toggleFolder('${ childFolder . path . replace ( / ' / g, "\\'" ) } ')"
414- >
415- <div class="flex items-center gap-1">
416- <button
417- class="flex-shrink-0 w-4 h-4 flex items-center justify-center"
418- style="color: var(--text-tertiary); cursor: pointer; transition: transform 0.2s; pointer-events: none; ${ isExpanded ? 'transform: rotate(90deg);' : '' } "
419- >
420- <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
421- <path d="M6 4l4 4-4 4V4z"/>
422- </svg>
423- </button>
424- <span class="flex items-center gap-1 flex-1" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; pointer-events: none;">
425- <span>${ childFolder . name } </span>
426- ${ 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>' : '' }
427- </span>
428- </div>
429- <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>
430- <button
431- @click="createNoteInFolder('${ childFolder . path . replace ( / ' / g, "\\'" ) } ')"
432- class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
433- style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
434- title="New note in this folder"
435- >📄</button>
436- <button
437- @click="createNewFolder('${ childFolder . path . replace ( / ' / g, "\\'" ) } ')"
438- class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
439- style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
440- title="New subfolder"
441- >📁</button>
442- <button
443- @click="renameFolder('${ childFolder . path . replace ( / ' / g, "\\'" ) } ', '${ childFolder . name . replace ( / ' / g, "\\'" ) } ')"
444- class="px-1.5 py-0.5 text-xs rounded hover:brightness-110"
445- style="background-color: var(--bg-tertiary); color: var(--text-secondary);"
446- title="Rename folder"
447- >✏️</button>
468+ // Then, render notes in this folder (after subfolders)
469+ if ( folder . notes && folder . notes . length > 0 ) {
470+ folder . notes . forEach ( note => {
471+ const isCurrentNote = this . currentNote === note . path ;
472+ html += `
473+ <div
474+ draggable="true"
475+ x-data="{}"
476+ @dragstart="onNoteDragStart('${ note . path . replace ( / ' / g, "\\'" ) } ', $event)"
477+ @dragend="onNoteDragEnd()"
478+ @click="loadNote('${ note . path . replace ( / ' / g, "\\'" ) } ')"
479+ class="note-item px-3 py-2 mb-1 text-sm rounded relative"
480+ style="${ isCurrentNote ? 'background-color: var(--accent-light); color: var(--accent-primary);' : 'color: var(--text-primary);' } cursor: pointer;"
481+ @mouseover="if('${ note . path } ' !== currentNote) $el.style.backgroundColor='var(--bg-hover)'"
482+ @mouseout="if('${ note . path } ' !== currentNote) $el.style.backgroundColor='transparent'"
483+ >
484+ <span class="truncate">${ note . name } </span>
448485 <button
449- @click="deleteFolder ('${ childFolder . path . replace ( / ' / g, "\\'" ) } ', '${ childFolder . name . replace ( / ' / g, "\\'" ) } ')"
450- class="px-1 py-0.5 text-xs rounded hover:brightness-110"
451- style="color: var(--error);"
452- title="Delete folder and all contents "
486+ @click.stop="deleteNote ('${ note . path . replace ( / ' / g, "\\'" ) } ', '${ note . name . replace ( / ' / g, "\\'" ) } ')"
487+ 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 "
488+ style="opacity: 0; color: var(--error);"
489+ title="Delete note "
453490 >
454491 <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
455492 <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>
456493 </svg>
457494 </button>
458495 </div>
459- </div>
460- ` ;
461-
462- // If expanded, recursively render this folder's contents (notes + subfolders)
463- if ( isExpanded ) {
464- html += `<div class="folder-contents" style="padding-left: 12px;">` ;
465- html += this . renderFolderRecursive ( childFolder , 0 ) ; // Reset level to 0 for relative positioning
466- html += `</div>` ;
496+ ` ;
497+ } ) ;
467498 }
468499
469- html += `</div>` ;
470- } ) ;
471- }
472-
473- // Then, render notes in this folder (after subfolders)
474- if ( folder . notes && folder . notes . length > 0 ) {
475- folder . notes . forEach ( note => {
476- const isCurrentNote = this . currentNote === note . path ;
477- html += `
478- <div
479- draggable="true"
480- x-data="{}"
481- @dragstart="onNoteDragStart('${ note . path . replace ( / ' / g, "\\'" ) } ', $event)"
482- @dragend="onNoteDragEnd()"
483- @click="loadNote('${ note . path . replace ( / ' / g, "\\'" ) } ')"
484- class="note-item px-3 py-2 mb-1 text-sm rounded relative"
485- style="${ isCurrentNote ? 'background-color: var(--accent-light); color: var(--accent-primary);' : 'color: var(--text-primary);' } cursor: pointer;"
486- @mouseover="if('${ note . path } ' !== currentNote) $el.style.backgroundColor='var(--bg-hover)'"
487- @mouseout="if('${ note . path } ' !== currentNote) $el.style.backgroundColor='transparent'"
488- >
489- <span class="truncate">${ note . name } </span>
490- <button
491- @click.stop="deleteNote('${ note . path . replace ( / ' / g, "\\'" ) } ', '${ note . name . replace ( / ' / g, "\\'" ) } ')"
492- 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"
493- style="opacity: 0; color: var(--error);"
494- title="Delete note"
495- >
496- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
497- <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>
498- </svg>
499- </button>
500- </div>
501- ` ;
502- } ) ;
500+ html += `</div>` ; // Close folder-contents
503501 }
504502
503+ html += `</div>` ; // Close folder wrapper
505504 return html ;
506505 } ,
507506
0 commit comments