1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-22 03:05:32 +02:00

fix(frontend): guard ctrl/meta cache-miss fetch; add / search shortcut

App.jsx ctrl/meta branch: cache-miss fetchEntryDetail now captures
tok = ++jkSeqRef.current before the fetch and gates selectEntry on
tok === jkSeqRef.current — same pattern as the j/k handler — so a
slow response after a later click/navigate can't overwrite selection.

/ key: reuses the Cmd+K/Ctrl+K handler path (focus+select search input,
or pendingSearchFocus + archive view switch). Guards: editable targets
(INPUT/TEXTAREA/SELECT/contentEditable) and modifier keys are checked
before preventDefault() so typing / in inputs is untouched.
This commit is contained in:
TheGeneralist 2026-07-21 17:27:14 +02:00
parent bd90a4b77f
commit 33e51bbaef
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
3 changed files with 31 additions and 26 deletions

View file

@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Archivr</title>
<script type="module" crossorigin src="/assets/index-BOyLHdsN.js"></script>
<script type="module" crossorigin src="/assets/index-B2Gbe8XQ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D8ic-z4p.css">
</head>
<body>

View file

@ -308,9 +308,9 @@ export default function App() {
if (cached) {
selectEntry(cached)
} else {
// Cache miss fetch from server rather than clearing the detail panel.
const tok = ++jkSeqRef.current
fetchEntryDetail(archiveId, remainingUid)
.then(det => { if (det?.summary) selectEntry(det.summary) })
.then(det => { if (tok === jkSeqRef.current && det?.summary) selectEntry(det.summary) })
.catch(() => {})
}
} else {
@ -436,10 +436,16 @@ export default function App() {
if (current !== url) history.replaceState(null, '', url)
}, [searchQuery, tagFilter, selectedEntryUid, view])
// K / Ctrl+K: focus the search input, switching to archive view first if needed.
// K / Ctrl+K / /: focus the search input, switching to archive view first if needed.
useEffect(() => {
const handler = (e) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
const isSlash = e.key === '/' && !e.metaKey && !e.ctrlKey && !e.altKey
const isCmdK = (e.metaKey || e.ctrlKey) && e.key === 'k'
if (!isSlash && !isCmdK) return
// Don't intercept / when already typing in an input
const tag = document.activeElement?.tagName
if (isSlash && (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT')) return
if (isSlash && document.activeElement?.isContentEditable) return
e.preventDefault()
if (view === 'archive') {
searchInputRef.current?.focus()
@ -449,7 +455,6 @@ export default function App() {
setView('archive')
}
}
}
document.addEventListener('keydown', handler)
return () => document.removeEventListener('keydown', handler)
}, [view])