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
-
-