From 25c8f98b7fa9ba37b4093e2e04e6b1a06c1e6c1e Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Sun, 24 May 2026 15:30:42 +0000 Subject: [PATCH] Fix keyboard shortcut scoping; add tab switching with Ctrl+Alt+PgUp/Down - Use sentinel element to properly clean up detail view Ctrl+E listener - Single document listener per view handles all shortcuts regardless of focus - Ctrl+S/D now work from preview tab and title input without separate listeners - Ctrl+Alt+PageUp/Down switches Write/Preview tabs Co-Authored-By: Claude Sonnet 4.6 --- public/app.mjs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/public/app.mjs b/public/app.mjs index ac17128..f752c44 100644 --- a/public/app.mjs +++ b/public/app.mjs @@ -656,15 +656,18 @@ function render_entry_detail(container) { const et = state.entry_types.find(t => t.id === entry.type); const back_hash = 'type/' + entry.type; + const sentinel = document.createElement('div'); const on_keydown = e => { if (e.ctrlKey && e.key === 'e') { e.preventDefault(); navigate('edit/' + entry.id); } }; document.addEventListener('keydown', on_keydown); const observer = new MutationObserver(() => { - if (!container.isConnected) { document.removeEventListener('keydown', on_keydown); observer.disconnect(); } + if (!sentinel.isConnected) { document.removeEventListener('keydown', on_keydown); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); + container.appendChild(sentinel); + // Header const header = document.createElement('div'); header.className = 'detail-header'; @@ -843,6 +846,13 @@ function render_edit_view(container) { tab_bar.appendChild(write_tab); tab_bar.appendChild(preview_tab); + const tabs = [write_tab, preview_tab]; + function switch_tab(dir) { + const current = tabs.findIndex(t => t.classList.contains('active')); + const next = (current + dir + tabs.length) % tabs.length; + tabs[next].click(); + } + // CodeMirror editor const cm_host = document.createElement('div'); cm_host.className = 'edit-cm-host'; @@ -861,8 +871,6 @@ function render_edit_view(container) { ...defaultKeymap, ...historyKeymap, indentWithTab, - { key: 'Ctrl-s', mac: 'Cmd-s', run: () => { save_btn.click(); return true; } }, - { key: 'Ctrl-d', run: () => { cancel_btn.click(); return true; } }, ]), EditorView.lineWrapping, placeholder('Body (markdown)'), @@ -909,10 +917,18 @@ function render_edit_view(container) { }); // Ctrl+S on title input - title_input.addEventListener('keydown', e => { - if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); save_btn.click(); } - if ((e.ctrlKey || e.metaKey) && e.key === 'd') { e.preventDefault(); cancel_btn.click(); } + + const on_edit_keydown = e => { + if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); save_btn.click(); } + if ((e.ctrlKey || e.metaKey) && e.key === 'd') { e.preventDefault(); cancel_btn.click(); } + if (e.ctrlKey && e.altKey && e.key === 'PageUp') { e.preventDefault(); switch_tab(-1); } + if (e.ctrlKey && e.altKey && e.key === 'PageDown') { e.preventDefault(); switch_tab(+1); } + }; + document.addEventListener('keydown', on_edit_keydown); + const edit_observer = new MutationObserver(() => { + if (!view.isConnected) { document.removeEventListener('keydown', on_edit_keydown); edit_observer.disconnect(); } }); + edit_observer.observe(document.body, { childList: true, subtree: true }); // --- Sidebar --- const sidebar = document.createElement('div');