()
| 719 | // --- Keyboard shortcuts --------------------------------------- |
| 720 | |
| 721 | function initKeyboardShortcuts() { |
| 722 | document.addEventListener("keydown", (e) => { |
| 723 | const graphOpen = document.getElementById("graph-overlay").classList.contains("visible"); |
| 724 | const tag = (document.activeElement || {}).tagName?.toLowerCase() ?? ""; |
| 725 | const inInput = tag === "input" || tag === "textarea" || tag === "select"; |
| 726 | |
| 727 | // Ctrl+K or / → focus search |
| 728 | if (!graphOpen && ( |
| 729 | (e.key === "/" && !inInput) || |
| 730 | (e.key === "k" && (e.ctrlKey || e.metaKey)) |
| 731 | )) { |
| 732 | e.preventDefault(); |
| 733 | searchInput.focus(); |
| 734 | searchInput.select(); |
| 735 | return; |
| 736 | } |
| 737 | |
| 738 | // Escape → clear/close search (graph escape is handled separately in onGraphEscape) |
| 739 | if (e.key === "Escape" && !graphOpen) { |
| 740 | if (document.activeElement === searchInput || searchInput.value) { |
| 741 | e.preventDefault(); |
| 742 | searchInput.blur(); |
| 743 | searchInput.value = ""; |
| 744 | searchResultsEl.innerHTML = ""; |
| 745 | } |
| 746 | return; |
| 747 | } |
| 748 | |
| 749 | // [ → navigate back in note history |
| 750 | if (e.key === "[" && !inInput && !graphOpen) { |
| 751 | e.preventDefault(); |
| 752 | navigateBack(); |
| 753 | return; |
| 754 | } |
| 755 | |
| 756 | // ] → navigate forward in note history |
| 757 | if (e.key === "]" && !inInput && !graphOpen) { |
| 758 | e.preventDefault(); |
| 759 | navigateForward(); |
| 760 | return; |
| 761 | } |
| 762 | }); |
| 763 | } |
| 764 | |
| 765 | // --- Init ----------------------------------------------------- |
| 766 |
no test coverage detected