diff --git a/docs/logo-512.svg b/docs/logo-512.svg new file mode 100644 index 0000000..d970569 --- /dev/null +++ b/docs/logo-512.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo-cropped.svg b/docs/logo-cropped.svg new file mode 100644 index 0000000..1f0f458 --- /dev/null +++ b/docs/logo-cropped.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/FEATURES.md b/documentation/FEATURES.md index 78887d6..a1ff48f 100644 --- a/documentation/FEATURES.md +++ b/documentation/FEATURES.md @@ -49,6 +49,7 @@ - **Browser history** - Back/forward buttons navigate between notes - **Shareable links** - Bookmark or share direct links to notes with highlighted terms - **Refresh safe** - Page reload keeps you on the same note with search context +- **Copy link button** - One-click copy of note URL to clipboard ## 🎨 Customization @@ -275,6 +276,7 @@ date: {{date}} | `Ctrl+B` | `Cmd+B` | Bold | `**text**` | | `Ctrl+I` | `Cmd+I` | Italic | `*text*` | | `Ctrl+K` | `Cmd+K` | Insert link | `[text](url)` | +| `Ctrl+Alt+T` | `Cmd+Option+T` | Insert table | 3x3 table placeholder | ## 🚀 Performance diff --git a/frontend/app.js b/frontend/app.js index 92cb3a4..3b7a0a4 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -55,6 +55,7 @@ function noteApp() { totalMatches: 0, // Total number of matches in the note isSaving: false, lastSaved: false, + linkCopied: false, saveTimeout: null, // Theme state @@ -461,6 +462,12 @@ function noteApp() { e.preventDefault(); this.insertLink(); } + + // Ctrl/Cmd + Alt + T for table + if ((e.ctrlKey || e.metaKey) && e.altKey && e.key === 't') { + e.preventDefault(); + this.insertTable(); + } } }); } @@ -2548,6 +2555,39 @@ function noteApp() { this.autoSave(); }, + // Insert a markdown table placeholder + insertTable() { + const editor = document.getElementById('note-editor'); + if (!editor) return; + + const cursorPos = editor.selectionStart; + + // Basic 3x3 table placeholder + const table = `| Header 1 | Header 2 | Header 3 | +|----------|----------|----------| +| Cell 1 | Cell 2 | Cell 3 | +| Cell 4 | Cell 5 | Cell 6 | +`; + + // Add newline before if not at start of line + const textBefore = this.noteContent.substring(0, cursorPos); + const needsNewlineBefore = textBefore.length > 0 && !textBefore.endsWith('\n'); + const prefix = needsNewlineBefore ? '\n\n' : ''; + + // Insert the table + this.noteContent = textBefore + prefix + table + this.noteContent.substring(cursorPos); + + // Position cursor at first header for easy editing + this.$nextTick(() => { + const newPos = cursorPos + prefix.length + 2; // After "| " + editor.setSelectionRange(newPos, newPos + 8); // Select "Header 1" + editor.focus(); + }); + + // Trigger autosave + this.autoSave(); + }, + // Save current note async saveNote() { if (!this.currentNote) return; @@ -3975,6 +4015,34 @@ function noteApp() { } }, + // Copy current note link to clipboard + async copyNoteLink() { + if (!this.currentNote) return; + + // Build the full URL + const pathWithoutExtension = this.currentNote.replace('.md', ''); + const encodedPath = pathWithoutExtension.split('/').map(segment => encodeURIComponent(segment)).join('/'); + const url = `${window.location.origin}/${encodedPath}`; + + try { + await navigator.clipboard.writeText(url); + } catch (error) { + // Fallback for older browsers + const textArea = document.createElement('textarea'); + textArea.value = url; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + } + + // Show brief "Copied!" feedback + this.linkCopied = true; + setTimeout(() => { + this.linkCopied = false; + }, 1500); + }, + // Homepage folder navigation methods goToHomepageFolder(folderPath) { this.showGraph = false; // Close graph when navigating diff --git a/frontend/index.html b/frontend/index.html index 527e5ff..663b764 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1829,6 +1829,8 @@ @click="viewMode = 'edit'" class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" :style="viewMode === 'edit' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" + @mouseenter="if (viewMode !== 'edit') $el.style.backgroundColor = 'var(--bg-secondary)'" + @mouseleave="if (viewMode !== 'edit') $el.style.backgroundColor = 'transparent'" > Edit @@ -1836,6 +1838,8 @@ @click="viewMode = 'split'" class="mobile-hide-split px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" :style="viewMode === 'split' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" + @mouseenter="if (viewMode !== 'split') $el.style.backgroundColor = 'var(--bg-secondary)'" + @mouseleave="if (viewMode !== 'split') $el.style.backgroundColor = 'transparent'" > Split @@ -1843,21 +1847,50 @@ @click="viewMode = 'preview'" class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" :style="viewMode === 'preview' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" + @mouseenter="if (viewMode !== 'preview') $el.style.backgroundColor = 'var(--bg-secondary)'" + @mouseleave="if (viewMode !== 'preview') $el.style.backgroundColor = 'transparent'" > Preview - - + +
+ +