nav_big.tmpl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <aside class="w-64 border-r border-zinc-800 bg-zinc-900/50 flex flex-col">
  2. <div class="p-4 flex justify-between items-center border-b border-zinc-800">
  3. <span class="text-xs font-bold uppercase tracking-widest text-zinc-500">Main Vault</span>
  4. <span class="text-[10px] px-1.5 py-0.5 rounded bg-zinc-800 text-zinc-400 border border-zinc-700">v2.4</span>
  5. </div>
  6. <div class="flex-1 overflow-y-auto custom-scrollbar p-2 space-y-0.5">
  7. {{range .Subfoldere}}
  8. {{template "folder" .}}
  9. {{end}}
  10. {{range .Fisiere}}
  11. {{template "file" .}}
  12. {{end}}
  13. </div>
  14. {{/* BOTTOM: NEW ROOT FOLDER */}}
  15. <div class="p-2 border-t border-zinc-800">
  16. <form method="POST" action="/api/create_dir" class="flex gap-1 items-center">
  17. <input type="hidden" name="director" value="">
  18. <input
  19. type="text"
  20. name="subdirector"
  21. placeholder="New folder..."
  22. class="flex-1 bg-zinc-800 text-zinc-300 text-xs rounded px-2 py-1 outline-none border border-zinc-700 focus:border-zinc-500 placeholder-zinc-600"
  23. >
  24. <button type="submit"
  25. class="text-zinc-400 hover:text-zinc-100 hover:bg-zinc-700 rounded p-1 transition-colors border border-zinc-700"
  26. title="Create folder">
  27. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  28. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  29. <line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
  30. </svg>
  31. </button>
  32. </form>
  33. </div>
  34. </aside>
  35. {{/* ================= FILE TEMPLATE ================= */}}
  36. {{define "file"}}
  37. <div class="group/file flex items-center justify-between px-2 py-1 text-xs rounded hover:bg-zinc-800 text-zinc-500 hover:text-zinc-300 transition-colors">
  38. <a href="/design_view/?note={{.Path}}" class="flex items-center gap-2 min-w-0 flex-1">
  39. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  40. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
  41. class="shrink-0 text-zinc-600">
  42. <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
  43. <polyline points="14 2 14 8 20 8"/>
  44. </svg>
  45. <span class="truncate">{{.Nume}}</span>
  46. </a>
  47. {{/* DELETE FILE BUTTON */}}
  48. <form id="delete-file-{{.Path}}" method="POST" action="/api/delete_file">
  49. <input type="hidden" name="path" value="{{.Path}}">
  50. <button type="button"
  51. onclick="event.stopPropagation(); showDeleteModal('Delete {{.Nume}}? This cannot be undone.', 'delete-file-{{.Path}}')"
  52. class="opacity-0 group-hover/file:opacity-100 transition-opacity text-zinc-600 hover:text-red-400 rounded p-0.5"
  53. title="Delete note">
  54. <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24"
  55. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  56. <polyline points="3 6 5 6 21 6"/>
  57. <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>
  58. <path d="M10 11v6M14 11v6"/>
  59. <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
  60. </svg>
  61. </button>
  62. </form>
  63. </div>
  64. {{end}}
  65. {{/* ================= FOLDER TEMPLATE ================= */}}
  66. {{define "folder"}}
  67. <details class="group" id="folder-{{.Nume}}"
  68. ontoggle="saveFolderState('folder-{{.Nume}}', this.open)">
  69. <summary class="flex items-center justify-between px-2 py-1 text-xs rounded hover:bg-zinc-800 cursor-pointer list-none text-zinc-400 group-open:text-zinc-200 transition-colors">
  70. <div class="flex items-center gap-1.5 min-w-0">
  71. <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24"
  72. fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"
  73. class="shrink-0 transition-transform duration-150 group-open:rotate-90">
  74. <polyline points="9 18 15 12 9 6"/>
  75. </svg>
  76. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  77. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
  78. class="shrink-0 text-zinc-500 group-open:hidden">
  79. <path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/>
  80. </svg>
  81. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  82. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
  83. class="shrink-0 text-zinc-300 hidden group-open:block">
  84. <path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/>
  85. <line x1="2" y1="10" x2="22" y2="10"/>
  86. </svg>
  87. <span class="truncate">{{.Display}}</span>
  88. </div>
  89. {{/* ACTION BUTTONS — visible on hover only */}}
  90. <div class="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity shrink-0">
  91. {{/* New note button */}}
  92. <form method="POST" action="/api/save_note">
  93. <input type="hidden" name="director" value="{{.Nume}}">
  94. <input type="hidden" name="titlu" value="Untitled">
  95. <input type="hidden" name="notita" value="">
  96. <button type="submit"
  97. onclick="event.stopPropagation()"
  98. class="text-zinc-500 hover:text-zinc-100 hover:bg-zinc-700 rounded p-0.5 transition-colors"
  99. title="New note">
  100. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  101. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  102. <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
  103. <polyline points="14 2 14 8 20 8"/>
  104. <line x1="12" y1="18" x2="12" y2="12"/>
  105. <line x1="9" y1="15" x2="15" y2="15"/>
  106. </svg>
  107. </button>
  108. </form>
  109. {{/* New subfolder button */}}
  110. <button
  111. onclick="event.stopPropagation(); var f = this.closest('details').querySelector('.new-folder-form'); f.style.display = f.style.display === 'none' ? 'flex' : 'none'; f.querySelector('input[type=text]').focus();"
  112. class="text-zinc-500 hover:text-zinc-100 hover:bg-zinc-700 rounded p-0.5 transition-colors"
  113. title="New folder">
  114. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  115. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  116. <path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/>
  117. <line x1="12" y1="13" x2="12" y2="19"/>
  118. <line x1="9" y1="16" x2="15" y2="16"/>
  119. </svg>
  120. </button>
  121. {{/* DELETE FOLDER BUTTON */}}
  122. <form id="delete-dir-{{.Nume}}" method="POST" action="/api/delete_dir">
  123. <input type="hidden" name="path" value="{{.Nume}}">
  124. <button type="button"
  125. onclick="event.stopPropagation(); showDeleteModal('Delete {{.Display}} and everything inside it? This cannot be undone.', 'delete-dir-{{.Nume}}')"
  126. class="text-zinc-500 hover:text-red-400 rounded p-0.5 transition-colors"
  127. title="Delete folder">
  128. <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24"
  129. fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  130. <polyline points="3 6 5 6 21 6"/>
  131. <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>
  132. <path d="M10 11v6M14 11v6"/>
  133. <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
  134. </svg>
  135. </button>
  136. </form>
  137. </div>
  138. </summary>
  139. {{/* INLINE FOLDER NAME INPUT */}}
  140. <form method="POST" action="/api/create_dir"
  141. class="new-folder-form gap-1 px-2 py-1 items-center"
  142. style="display:none;">
  143. <input type="hidden" name="director" value="{{.Nume}}">
  144. <input
  145. type="text"
  146. name="subdirector"
  147. placeholder="Folder name..."
  148. class="flex-1 bg-zinc-800 text-zinc-300 text-xs rounded px-2 py-1 outline-none border border-zinc-700 focus:border-zinc-500 placeholder-zinc-600"
  149. >
  150. <button type="submit"
  151. class="text-zinc-400 hover:text-zinc-100 hover:bg-zinc-700 rounded p-1 transition-colors border border-zinc-700">
  152. <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24"
  153. fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  154. <polyline points="20 6 9 17 4 12"/>
  155. </svg>
  156. </button>
  157. </form>
  158. {{/* CHILDREN */}}
  159. <div class="ml-3 pl-2 border-l border-zinc-800 space-y-0.5 mt-0.5">
  160. {{range .Fisiere}}
  161. {{template "file" .}}
  162. {{end}}
  163. {{range .Subfoldere}}
  164. {{template "folder" .}}
  165. {{end}}
  166. </div>
  167. </details>
  168. {{end}}
  169. <script>
  170. function saveFolderState(id, isOpen) {
  171. const states = JSON.parse(localStorage.getItem('folderStates') || '{}');
  172. states[id] = isOpen;
  173. localStorage.setItem('folderStates', JSON.stringify(states));
  174. }
  175. function restoreFolderStates() {
  176. const states = JSON.parse(localStorage.getItem('folderStates') || '{}');
  177. document.querySelectorAll('details[id^="folder-"]').forEach(details => {
  178. const id = details.id;
  179. if (id in states) {
  180. details.open = states[id];
  181. } else {
  182. details.open = true;
  183. }
  184. });
  185. }
  186. document.addEventListener('DOMContentLoaded', restoreFolderStates);
  187. function showDeleteModal(message, formId) {
  188. document.getElementById('delete-modal-message').textContent = message;
  189. document.getElementById('delete-modal-confirm').onclick = function() {
  190. document.getElementById(formId).submit();
  191. };
  192. document.getElementById('delete-modal').classList.remove('hidden');
  193. }
  194. function hideDeleteModal() {
  195. document.getElementById('delete-modal').classList.add('hidden');
  196. }
  197. // Close on Escape key
  198. document.addEventListener('keydown', function(e) {
  199. if (e.key === 'Escape') hideDeleteModal();
  200. });
  201. </script>