From 4bbd6f7d9d9f507fbf75709e1b5dfc41492c5c0a Mon Sep 17 00:00:00 2001 From: Gamosoft Date: Thu, 15 Jan 2026 16:32:35 +0100 Subject: [PATCH] added quick search --- docs/index.html | 8 +++ documentation/FEATURES.md | 5 +- frontend/app.js | 108 ++++++++++++++++++++++++++++++++++++++ frontend/index.html | 66 +++++++++++++++++++++++ locales/de-DE.json | 9 ++++ locales/en-GB.json | 9 ++++ locales/en-US.json | 9 ++++ locales/es-ES.json | 9 ++++ locales/fr-FR.json | 9 ++++ locales/it-IT.json | 9 ++++ locales/ja-JP.json | 9 ++++ locales/ru-RU.json | 9 ++++ locales/sl-SI.json | 9 ++++ locales/zh-CN.json | 9 ++++ 14 files changed, 276 insertions(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index fc519be..e67a79f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -972,6 +972,14 @@ +
+ 🔍 +
+ Quick Switcher + Jump to any note with Ctrl+Alt+P +
+
+
🔐
diff --git a/documentation/FEATURES.md b/documentation/FEATURES.md index 0c52d73..2a3e674 100644 --- a/documentation/FEATURES.md +++ b/documentation/FEATURES.md @@ -286,6 +286,7 @@ date: {{date}} | Windows/Linux | Mac | Action | |---------------|-----|--------| +| `Ctrl+Alt+P` | `Cmd+Option+P` | Quick Switcher (jump to any note) | | `Ctrl+S` | `Cmd+S` | Save note | | `Ctrl+Alt+N` | `Cmd+Option+N` | New note | | `Ctrl+Alt+F` | `Cmd+Option+F` | New folder | @@ -304,9 +305,11 @@ date: {{date}} |---------------|-----|--------|--------| | `Ctrl+B` | `Cmd+B` | Bold | `**text**` | | `Ctrl+I` | `Cmd+I` | Italic | `*text*` | -| `Ctrl+K` | `Cmd+K` | Insert link | `[text](url)` | +| `Ctrl+K` | `Cmd+K` | Insert link (in editor) | `[text](url)` | | `Ctrl+Alt+T` | `Cmd+Option+T` | Insert table | 3x3 table placeholder | +> **Tip:** Use `Ctrl+Alt+P` to quickly jump to any note from anywhere in the app. + ## 🧘 Zen Mode Full immersive distraction-free writing experience: diff --git a/frontend/app.js b/frontend/app.js index 592fd2f..7ad6f66 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -262,6 +262,12 @@ function noteApp() { shareLinkCopied: false, _sharedNotePaths: new Set(), // O(1) lookup for shared note indicators + // Quick Switcher state (Ctrl+Alt+P) + showQuickSwitcher: false, + quickSwitcherQuery: '', + quickSwitcherIndex: 0, + quickSwitcherResults: [], + // Homepage state selectedHomepageFolder: '', _homepageCache: { @@ -569,6 +575,13 @@ function noteApp() { this.saveNote(); } + // Ctrl/Cmd + Alt + P for Quick Switcher + if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyP') { + e.preventDefault(); + this.openQuickSwitcher(); + return; + } + // Ctrl/Cmd + Alt/Option + N for new note if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyN') { e.preventDefault(); @@ -5040,6 +5053,101 @@ function noteApp() { return this._sharedNotePaths.has(notePath); }, + // ============================================ + // Quick Switcher (Ctrl+Alt+P) + // ============================================ + + openQuickSwitcher() { + this.showQuickSwitcher = true; + this.quickSwitcherQuery = ''; + this.quickSwitcherIndex = 0; + // Populate initial results + this.quickSwitcherResults = (this.allNotes || []).slice(0, 10); + // Focus the input after the modal renders + this.$nextTick(() => { + const input = document.getElementById('quickSwitcherInput'); + if (input) input.focus(); + }); + }, + + closeQuickSwitcher() { + this.showQuickSwitcher = false; + this.quickSwitcherQuery = ''; + this.quickSwitcherIndex = 0; + }, + + // Filter notes for quick switcher based on query + filterQuickSwitcher(query) { + // Only include actual notes, not images + const notes = (this.notes || []).filter(n => n.type === 'note'); + if (!query || !query.trim()) { + // Show recent notes when no query + return notes.slice(0, 10); + } + const q = query.toLowerCase(); + return notes + .filter(n => + n.name.toLowerCase().includes(q) || + n.path.toLowerCase().includes(q) + ) + .slice(0, 10); + }, + + // Handle keyboard navigation in quick switcher + handleQuickSwitcherKeydown(e) { + const results = this.quickSwitcherResults; + + if (e.key === 'ArrowDown') { + e.preventDefault(); + this.quickSwitcherIndex = Math.min(this.quickSwitcherIndex + 1, results.length - 1); + this.scrollQuickSwitcherIntoView(); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + this.quickSwitcherIndex = Math.max(this.quickSwitcherIndex - 1, 0); + this.scrollQuickSwitcherIntoView(); + } else if (e.key === 'Enter') { + e.preventDefault(); + const note = results[this.quickSwitcherIndex]; + if (note) { + this.loadNote(note.path); + this.closeQuickSwitcher(); + } + } else if (e.key === 'Escape') { + e.preventDefault(); + this.closeQuickSwitcher(); + } + }, + + // Scroll selected item into view in quick switcher + scrollQuickSwitcherIntoView() { + const container = document.getElementById('quickSwitcherResults'); + if (!container) return; + + // Get all result items (skip the "no results" template) + const items = container.querySelectorAll('[data-quick-switcher-item]'); + const selectedItem = items[this.quickSwitcherIndex]; + + if (selectedItem) { + // Calculate if we need to scroll + const containerRect = container.getBoundingClientRect(); + const itemRect = selectedItem.getBoundingClientRect(); + + if (itemRect.top < containerRect.top) { + // Item is above visible area + container.scrollTop -= (containerRect.top - itemRect.top); + } else if (itemRect.bottom > containerRect.bottom) { + // Item is below visible area + container.scrollTop += (itemRect.bottom - containerRect.bottom); + } + } + }, + + // Select note from quick switcher by click + selectQuickSwitcherNote(note) { + this.loadNote(note.path); + this.closeQuickSwitcher(); + }, + // Open share modal and fetch current share status async openShareModal() { if (!this.currentNote) return; diff --git a/frontend/index.html b/frontend/index.html index d30edf3..3802665 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2784,6 +2784,72 @@
+ +
+
+ + +
+ +
+ + +
+ + + + +
+ +
+
+ + +
+ ↑↓ + + esc +
+
+
+