...
This commit is contained in:
		
							
								
								
									
										9
									
								
								collections/notes/ttt/fdff/test_sub.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								collections/notes/ttt/fdff/test_sub.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
|  | ||||
| # test | ||||
|  | ||||
| - 1 | ||||
| - 2 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -1,4 +1,9 @@ | ||||
|  | ||||
| test | ||||
| # test | ||||
|  | ||||
| - 1 | ||||
| - 2 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,12 @@ | ||||
| /* File tree styles */ | ||||
| /* Bootstrap-styled File Tree */ | ||||
| .file-tree { | ||||
|     font-size: 14px; | ||||
|     font-size: 13px; | ||||
|     user-select: none; | ||||
|     padding: 8px 0; | ||||
| } | ||||
|  | ||||
| .tree-node-wrapper { | ||||
|     margin: 0; | ||||
| } | ||||
|  | ||||
| .tree-node { | ||||
| @@ -9,11 +14,14 @@ | ||||
|     cursor: pointer; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     gap: 8px; | ||||
|     gap: 6px; | ||||
|     border-radius: 4px; | ||||
|     margin: 2px 0; | ||||
|     margin: 1px 4px; | ||||
|     color: var(--text-primary); | ||||
|     transition: background-color 0.15s ease; | ||||
|     transition: all 0.15s ease; | ||||
|     white-space: nowrap; | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
| } | ||||
|  | ||||
| .tree-node:hover { | ||||
| @@ -21,20 +29,49 @@ | ||||
| } | ||||
|  | ||||
| .tree-node.active { | ||||
|     background-color: #0969da; | ||||
|     background-color: var(--link-color); | ||||
|     color: white; | ||||
|     font-weight: 500; | ||||
| } | ||||
|  | ||||
| .tree-node.active:hover { | ||||
|     background-color: var(--link-color); | ||||
|     filter: brightness(1.1); | ||||
| } | ||||
|  | ||||
| /* Toggle arrow */ | ||||
| .tree-node-toggle { | ||||
|     display: inline-flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     width: 16px; | ||||
|     height: 16px; | ||||
|     font-size: 10px; | ||||
|     color: var(--text-secondary); | ||||
|     flex-shrink: 0; | ||||
|     transition: transform 0.2s ease; | ||||
| } | ||||
|  | ||||
| .tree-node-toggle.expanded { | ||||
|     transform: rotate(90deg); | ||||
| } | ||||
|  | ||||
| /* Icon styling */ | ||||
| .tree-node-icon { | ||||
|     width: 16px; | ||||
|     height: 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     flex-shrink: 0; | ||||
|     color: var(--text-secondary); | ||||
| } | ||||
|  | ||||
| .tree-node.active .tree-node-icon { | ||||
|     color: white; | ||||
| } | ||||
|  | ||||
| body.dark-mode .tree-node.active { | ||||
|     background-color: #1f6feb; | ||||
| } | ||||
|  | ||||
| .tree-node-icon { | ||||
|     width: 16px; | ||||
|     text-align: center; | ||||
|     flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| /* Content wrapper */ | ||||
| .tree-node-content { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
| @@ -48,41 +85,89 @@ body.dark-mode .tree-node.active { | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|     font-size: 13px; | ||||
| } | ||||
|  | ||||
| .tree-node-size { | ||||
|     font-size: 11px; | ||||
| .file-size-badge { | ||||
|     font-size: 10px; | ||||
|     color: var(--text-secondary); | ||||
|     margin-left: auto; | ||||
|     flex-shrink: 0; | ||||
|     padding: 2px 6px; | ||||
|     background-color: var(--bg-tertiary); | ||||
|     border-radius: 3px; | ||||
| } | ||||
|  | ||||
| /* Children container */ | ||||
| .tree-children { | ||||
|     margin-left: 16px; | ||||
|     margin-left: 8px; | ||||
|     border-left: 1px solid var(--border-light); | ||||
|     padding-left: 4px; | ||||
|     max-height: 100%; | ||||
|     overflow: visible; | ||||
| } | ||||
|  | ||||
| .tree-children.collapsed { | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| /* Drag and drop */ | ||||
| .tree-node.dragging { | ||||
|     opacity: 0.5; | ||||
| } | ||||
|  | ||||
| .tree-node.drag-over { | ||||
|     background-color: var(--info-color); | ||||
|     color: white; | ||||
|     background-color: rgba(13, 110, 253, 0.2); | ||||
|     border: 1px dashed var(--link-color); | ||||
| } | ||||
|  | ||||
| /* Collection selector */ | ||||
| /* Collection selector - Bootstrap styled */ | ||||
| .collection-selector { | ||||
|     margin-bottom: 10px; | ||||
|     padding: 8px; | ||||
|     margin: 12px 8px; | ||||
|     padding: 8px 12px; | ||||
|     background-color: var(--bg-tertiary); | ||||
|     border-radius: 4px; | ||||
|     border-radius: 6px; | ||||
|     border: 1px solid var(--border-color); | ||||
| } | ||||
|  | ||||
| .collection-selector select { | ||||
|     width: 100%; | ||||
|     padding: 6px; | ||||
| .collection-selector .form-label { | ||||
|     margin-bottom: 6px; | ||||
|     font-weight: 500; | ||||
|     font-size: 12px; | ||||
|     color: var(--text-secondary); | ||||
| } | ||||
|  | ||||
| .collection-selector .form-select-sm { | ||||
|     padding: 4px 8px; | ||||
|     font-size: 13px; | ||||
|     background-color: var(--bg-primary); | ||||
|     color: var(--text-primary); | ||||
|     border: 1px solid var(--border-color); | ||||
|     border-radius: 4px; | ||||
| } | ||||
|  | ||||
| .collection-selector .form-select-sm:focus { | ||||
|     border-color: var(--link-color); | ||||
|     box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25); | ||||
| } | ||||
|  | ||||
| /* Dark mode adjustments */ | ||||
| body.dark-mode .tree-node:hover { | ||||
|     background-color: var(--bg-tertiary); | ||||
| } | ||||
|  | ||||
| body.dark-mode .tree-node.active { | ||||
|     background-color: var(--link-color); | ||||
| } | ||||
|  | ||||
| body.dark-mode .tree-children { | ||||
|     border-left-color: var(--border-color); | ||||
| } | ||||
|  | ||||
| /* Scrollbar in sidebar */ | ||||
| .sidebar::-webkit-scrollbar-thumb { | ||||
|     background-color: var(--border-color); | ||||
| } | ||||
|  | ||||
| .sidebar::-webkit-scrollbar-thumb:hover { | ||||
|     background-color: var(--text-secondary); | ||||
| } | ||||
| @@ -9,31 +9,89 @@ html, body { | ||||
|     transition: background-color 0.3s ease, color 0.3s ease; | ||||
| } | ||||
|  | ||||
| .container-fluid { | ||||
|     height: calc(100% - 56px); | ||||
| /* Column Resizer */ | ||||
| .column-resizer { | ||||
|     width: 4px; | ||||
|     background-color: var(--border-color); | ||||
|     cursor: col-resize; | ||||
|     transition: background-color 0.2s ease; | ||||
|     user-select: none; | ||||
|     flex-shrink: 0; | ||||
| } | ||||
|  | ||||
| .column-resizer:hover { | ||||
|     background-color: var(--link-color); | ||||
|     width: 6px; | ||||
|     margin: 0 -1px; | ||||
| } | ||||
|  | ||||
| .column-resizer.dragging { | ||||
|     background-color: var(--link-color); | ||||
| } | ||||
|  | ||||
| /* Adjust container for flex layout */ | ||||
| .container-fluid { | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     height: calc(100% - 56px); | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| .row { | ||||
|     width: 100%; | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     margin: 0; | ||||
|     height: 100%; | ||||
| } | ||||
|  | ||||
| #sidebarPane { | ||||
|     flex: 0 0 20%; | ||||
|     min-width: 150px; | ||||
|     max-width: 40%; | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| #editorPane { | ||||
|     flex: 1 1 40%; | ||||
|     min-width: 250px; | ||||
|     max-width: 70%; | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| #previewPane { | ||||
|     flex: 1 1 40%; | ||||
|     min-width: 250px; | ||||
|     max-width: 70%; | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| /* Sidebar - improved */ | ||||
| .sidebar { | ||||
|     background-color: var(--bg-secondary); | ||||
|     border-right: 1px solid var(--border-color); | ||||
|     overflow-y: auto; | ||||
|     overflow-x: hidden; | ||||
|     height: 100%; | ||||
|     transition: background-color 0.3s ease; | ||||
| } | ||||
|  | ||||
| .editor-pane { | ||||
|     background-color: var(--bg-primary); | ||||
|     height: 100%; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     border-right: 1px solid var(--border-color); | ||||
| } | ||||
|  | ||||
| .preview-pane { | ||||
|     background-color: var(--bg-primary); | ||||
|     height: 100%; | ||||
| .sidebar h6 { | ||||
|     margin: 12px 8px 6px; | ||||
|     font-size: 11px; | ||||
|     font-weight: 600; | ||||
|     color: var(--text-secondary); | ||||
|     text-transform: uppercase; | ||||
|     letter-spacing: 0.5px; | ||||
| } | ||||
|  | ||||
| #fileTree { | ||||
|     flex: 1; | ||||
|     overflow-y: auto; | ||||
|     padding: 20px; | ||||
|     overflow-x: hidden; | ||||
|     padding: 4px 0; | ||||
| } | ||||
|  | ||||
| /* Navbar */ | ||||
|   | ||||
| @@ -23,18 +23,18 @@ document.addEventListener('DOMContentLoaded', async () => { | ||||
|         darkMode.toggle(); | ||||
|     }); | ||||
|      | ||||
|     // Initialize file tree | ||||
|     fileTree = new FileTree('fileTree', webdavClient); | ||||
|     fileTree.onFileSelect = async (item) => { | ||||
|         await loadFile(item.path); | ||||
|     }; | ||||
|      | ||||
|     // Initialize collection selector | ||||
|     collectionSelector = new CollectionSelector('collectionSelect', webdavClient); | ||||
|     collectionSelector.onChange = async (collection) => { | ||||
|         await fileTree.load(); | ||||
|     }; | ||||
|     await collectionSelector.load(); | ||||
|      | ||||
|     // Initialize file tree | ||||
|     fileTree = new FileTree('fileTree', webdavClient); | ||||
|     fileTree.onFileSelect = async (item) => { | ||||
|         await loadFile(item.path); | ||||
|     }; | ||||
|     await fileTree.load(); | ||||
|      | ||||
|     // Initialize editor | ||||
| @@ -68,6 +68,13 @@ document.addEventListener('DOMContentLoaded', async () => { | ||||
|     mermaid.initialize({ startOnLoad: true, theme: darkMode.isDark ? 'dark' : 'default' }); | ||||
| }); | ||||
|  | ||||
| // Listen for column resize events to refresh editor | ||||
| window.addEventListener('column-resize', () => { | ||||
|     if (editor && editor.editor) { | ||||
|         editor.editor.refresh(); | ||||
|     } | ||||
| }); | ||||
|  | ||||
| /** | ||||
|  * File Operations | ||||
|  */ | ||||
|   | ||||
							
								
								
									
										102
									
								
								static/js/column-resizer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								static/js/column-resizer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /** | ||||
|  * Column Resizer Module | ||||
|  * Handles draggable column dividers | ||||
|  */ | ||||
|  | ||||
| class ColumnResizer { | ||||
|     constructor() { | ||||
|         this.resizer1 = document.getElementById('resizer1'); | ||||
|         this.resizer2 = document.getElementById('resizer2'); | ||||
|         this.sidebarPane = document.getElementById('sidebarPane'); | ||||
|         this.editorPane = document.getElementById('editorPane'); | ||||
|         this.previewPane = document.getElementById('previewPane'); | ||||
|          | ||||
|         // Load saved dimensions | ||||
|         this.loadDimensions(); | ||||
|          | ||||
|         // Setup listeners | ||||
|         this.setupResizers(); | ||||
|     } | ||||
|      | ||||
|     setupResizers() { | ||||
|         this.resizer1.addEventListener('mousedown', (e) => this.startResize(e, 1)); | ||||
|         this.resizer2.addEventListener('mousedown', (e) => this.startResize(e, 2)); | ||||
|     } | ||||
|      | ||||
|     startResize(e, resizerId) { | ||||
|         e.preventDefault(); | ||||
|          | ||||
|         const startX = e.clientX; | ||||
|         const startWidth1 = this.sidebarPane.offsetWidth; | ||||
|         const startWidth2 = this.editorPane.offsetWidth; | ||||
|         const containerWidth = this.sidebarPane.parentElement.offsetWidth; | ||||
|          | ||||
|         const resizer = resizerId === 1 ? this.resizer1 : this.resizer2; | ||||
|         resizer.classList.add('dragging'); | ||||
|          | ||||
|         const handleMouseMove = (moveEvent) => { | ||||
|             const deltaX = moveEvent.clientX - startX; | ||||
|              | ||||
|             if (resizerId === 1) { | ||||
|                 // Resize sidebar and editor | ||||
|                 const newWidth1 = Math.max(150, Math.min(40 * containerWidth / 100, startWidth1 + deltaX)); | ||||
|                 const newWidth2 = startWidth2 - (newWidth1 - startWidth1); | ||||
|                  | ||||
|                 this.sidebarPane.style.flex = `0 0 ${newWidth1}px`; | ||||
|                 this.editorPane.style.flex = `1 1 ${newWidth2}px`; | ||||
|             } else if (resizerId === 2) { | ||||
|                 // Resize editor and preview | ||||
|                 const newWidth2 = Math.max(250, Math.min(70 * containerWidth / 100, startWidth2 + deltaX)); | ||||
|                 const containerFlex = this.sidebarPane.offsetWidth; | ||||
|                  | ||||
|                 this.editorPane.style.flex = `0 0 ${newWidth2}px`; | ||||
|                 this.previewPane.style.flex = `1 1 auto`; | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         const handleMouseUp = () => { | ||||
|             resizer.classList.remove('dragging'); | ||||
|             document.removeEventListener('mousemove', handleMouseMove); | ||||
|             document.removeEventListener('mouseup', handleMouseUp); | ||||
|              | ||||
|             // Save dimensions | ||||
|             this.saveDimensions(); | ||||
|              | ||||
|             // Trigger editor resize | ||||
|             if (window.editor && window.editor.editor) { | ||||
|                 window.editor.editor.refresh(); | ||||
|             } | ||||
|         }; | ||||
|          | ||||
|         document.addEventListener('mousemove', handleMouseMove); | ||||
|         document.addEventListener('mouseup', handleMouseUp); | ||||
|     } | ||||
|      | ||||
|     saveDimensions() { | ||||
|         const dimensions = { | ||||
|             sidebar: this.sidebarPane.offsetWidth, | ||||
|             editor: this.editorPane.offsetWidth, | ||||
|             preview: this.previewPane.offsetWidth | ||||
|         }; | ||||
|         localStorage.setItem('columnDimensions', JSON.stringify(dimensions)); | ||||
|     } | ||||
|      | ||||
|     loadDimensions() { | ||||
|         const saved = localStorage.getItem('columnDimensions'); | ||||
|         if (!saved) return; | ||||
|          | ||||
|         try { | ||||
|             const { sidebar, editor, preview } = JSON.parse(saved); | ||||
|             this.sidebarPane.style.flex = `0 0 ${sidebar}px`; | ||||
|             this.editorPane.style.flex = `0 0 ${editor}px`; | ||||
|             this.previewPane.style.flex = `1 1 auto`; | ||||
|         } catch (error) { | ||||
|             console.error('Failed to load column dimensions:', error); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Initialize on DOM ready | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|     window.columnResizer = new ColumnResizer(); | ||||
| }); | ||||
| @@ -25,7 +25,7 @@ class FileTree { | ||||
|             const isDir = node.dataset.isdir === 'true'; | ||||
|              | ||||
|             // Toggle folder | ||||
|             if (e.target.closest('.tree-toggle')) { | ||||
|             if (e.target.closest('.tree-node-toggle')) { | ||||
|                 this.toggleFolder(node); | ||||
|                 return; | ||||
|             } | ||||
| @@ -83,21 +83,23 @@ class FileTree { | ||||
|     } | ||||
|      | ||||
|     createNodeElement(node, level) { | ||||
|         const nodeWrapper = document.createElement('div'); | ||||
|         nodeWrapper.className = 'tree-node-wrapper'; | ||||
|         nodeWrapper.style.marginLeft = `${level * 12}px`; | ||||
|          | ||||
|         const div = document.createElement('div'); | ||||
|         div.className = 'tree-node'; | ||||
|         div.dataset.path = node.path; | ||||
|         div.dataset.isdir = node.isDirectory; | ||||
|         div.style.paddingLeft = `${level * 20 + 10}px`; | ||||
|          | ||||
|         // Toggle arrow for folders | ||||
|         if (node.isDirectory) { | ||||
|             const toggle = document.createElement('span'); | ||||
|             toggle.className = 'tree-toggle'; | ||||
|             toggle.innerHTML = '<i class="bi bi-chevron-right"></i>'; | ||||
|             toggle.className = 'tree-node-toggle'; | ||||
|             toggle.innerHTML = '▶'; | ||||
|             div.appendChild(toggle); | ||||
|         } else { | ||||
|             const spacer = document.createElement('span'); | ||||
|             spacer.className = 'tree-spacer'; | ||||
|             spacer.style.width = '16px'; | ||||
|             spacer.style.display = 'inline-block'; | ||||
|             div.appendChild(spacer); | ||||
| @@ -105,45 +107,47 @@ class FileTree { | ||||
|          | ||||
|         // Icon | ||||
|         const icon = document.createElement('i'); | ||||
|         if (node.isDirectory) { | ||||
|             icon.className = 'bi bi-folder-fill'; | ||||
|             icon.style.color = '#dcb67a'; | ||||
|         } else { | ||||
|             icon.className = 'bi bi-file-earmark-text'; | ||||
|             icon.style.color = '#6a9fb5'; | ||||
|         } | ||||
|         icon.className = `bi ${node.isDirectory ? 'bi-folder-fill' : 'bi-file-earmark-text'} tree-node-icon`; | ||||
|         div.appendChild(icon); | ||||
|          | ||||
|         // Content wrapper | ||||
|         const contentWrapper = document.createElement('div'); | ||||
|         contentWrapper.className = 'tree-node-content'; | ||||
|          | ||||
|         // Name | ||||
|         const name = document.createElement('span'); | ||||
|         name.className = 'tree-name'; | ||||
|         name.className = 'tree-node-name'; | ||||
|         name.textContent = node.name; | ||||
|         div.appendChild(name); | ||||
|         name.title = node.name; // Tooltip on hover | ||||
|         contentWrapper.appendChild(name); | ||||
|          | ||||
|         // Size for files | ||||
|         if (!node.isDirectory && node.size) { | ||||
|             const size = document.createElement('span'); | ||||
|             size.className = 'tree-size'; | ||||
|             size.className = 'file-size-badge'; | ||||
|             size.textContent = this.formatSize(node.size); | ||||
|             div.appendChild(size); | ||||
|             contentWrapper.appendChild(size); | ||||
|         } | ||||
|          | ||||
|         return div; | ||||
|         div.appendChild(contentWrapper); | ||||
|         nodeWrapper.appendChild(div); | ||||
|          | ||||
|         return nodeWrapper; | ||||
|     } | ||||
|      | ||||
|     toggleFolder(nodeElement) { | ||||
|         const childContainer = nodeElement.querySelector('.tree-children'); | ||||
|         if (!childContainer) return; | ||||
|          | ||||
|         const toggle = nodeElement.querySelector('.tree-toggle i'); | ||||
|         const toggle = nodeElement.querySelector('.tree-node-toggle'); | ||||
|         const isExpanded = childContainer.style.display !== 'none'; | ||||
|          | ||||
|         if (isExpanded) { | ||||
|             childContainer.style.display = 'none'; | ||||
|             toggle.className = 'bi bi-chevron-right'; | ||||
|             toggle.innerHTML = '▶'; | ||||
|         } else { | ||||
|             childContainer.style.display = 'block'; | ||||
|             toggle.className = 'bi bi-chevron-down'; | ||||
|             toggle.innerHTML = '▼'; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|   | ||||
| @@ -51,19 +51,21 @@ | ||||
|     <div class="container-fluid"> | ||||
|         <div class="row h-100"> | ||||
|             <!-- Sidebar --> | ||||
|             <div class="col-md-2 sidebar"> | ||||
|             <div class="col-md-2 sidebar" id="sidebarPane"> | ||||
|                 <!-- Collection Selector --> | ||||
|                 <div class="collection-selector"> | ||||
|                     <label class="form-label small">Collection:</label> | ||||
|                     <select id="collectionSelect" class="form-select form-select-sm"></select> | ||||
|                 </div> | ||||
|  | ||||
|                 <!-- File Tree --> | ||||
|                 <div id="fileTree" class="file-tree"></div> | ||||
|             </div> | ||||
|  | ||||
|             <!-- Resizer between sidebar and editor --> | ||||
|             <div class="column-resizer" id="resizer1"></div> | ||||
|  | ||||
|             <!-- Editor Pane --> | ||||
|             <div class="col-md-5 editor-pane"> | ||||
|             <div class="col editor-pane" id="editorPane"> | ||||
|                 <div class="editor-header"> | ||||
|                     <input type="text" id="filenameInput" placeholder="filename.md" | ||||
|                         class="form-control form-control-sm"> | ||||
| @@ -73,8 +75,11 @@ | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <!-- Resizer between editor and preview --> | ||||
|             <div class="column-resizer" id="resizer2"></div> | ||||
|  | ||||
|             <!-- Preview Pane --> | ||||
|             <div class="col-md-5 preview-pane"> | ||||
|             <div class="col preview-pane" id="previewPane"> | ||||
|                 <h3>Preview</h3> | ||||
|                 <div id="preview"> | ||||
|                     <p class="text-muted">Start typing in the editor to see the preview</p> | ||||
| @@ -159,6 +164,7 @@ | ||||
|     <script src="/static/js/editor.js"></script> | ||||
|     <script src="/static/js/ui-utils.js"></script> | ||||
|     <script src="/static/js/app.js"></script> | ||||
|     <script src="/static/js/column-resizer.js"></script> | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
		Reference in New Issue
	
	Block a user