From 50bb1ffd8aa00d85d3a17bc1a4e52d26187afa7e Mon Sep 17 00:00:00 2001 From: Aaron Pham <29749331+aarnphm@users.noreply.github.com> Date: Wed, 31 Jan 2024 12:38:42 -0500 Subject: [PATCH] feat(usability): update functions for search (#774) * feat(usability): update functions for search Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> * perf: slightly cleaner variables Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> --------- Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> --- quartz/components/scripts/search.inline.ts | 109 +++++++++++++++------ quartz/components/styles/search.scss | 3 +- 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/quartz/components/scripts/search.inline.ts b/quartz/components/scripts/search.inline.ts index cbcc9ab5a..0124e1f1d 100644 --- a/quartz/components/scripts/search.inline.ts +++ b/quartz/components/scripts/search.inline.ts @@ -86,7 +86,6 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { const searchIcon = document.getElementById("search-icon") const searchBar = document.getElementById("search-bar") as HTMLInputElement | null const searchLayout = document.getElementById("search-layout") - const resultCards = document.getElementsByClassName("result-card") const idDataMap = Object.keys(data) as FullSlug[] const appendLayout = (el: HTMLElement) => { @@ -151,41 +150,50 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { if (searchBar) searchBar.value = "#" } + const resultCards = document.getElementsByClassName("result-card") + + // If search is active, then we will render the first result and display accordingly if (!container?.classList.contains("active")) return - else if (e.key === "Enter") { - // If result has focus, navigate to that one, otherwise pick first result - if (results?.contains(document.activeElement)) { - const active = document.activeElement as HTMLInputElement + else if (results?.contains(document.activeElement)) { + const active = document.activeElement as HTMLInputElement + await displayPreview(active) + if (e.key === "Enter") { active.click() - } else { - const anchor = document.getElementsByClassName("result-card")[0] as HTMLInputElement | null + } + } else { + const anchor = resultCards[0] as HTMLInputElement | null + await displayPreview(anchor) + if (e.key === "Enter") { anchor?.click() } - } else if (e.key === "ArrowUp" || (e.shiftKey && e.key === "Tab")) { + } + + if (e.key === "ArrowUp" || (e.shiftKey && e.key === "Tab")) { e.preventDefault() if (results?.contains(document.activeElement)) { // If an element in results-container already has focus, focus previous one - const prevResult = document.activeElement?.previousElementSibling as HTMLInputElement | null - if (enablePreview && prevResult?.id) { - await displayPreview(prevResult?.id as FullSlug) - } + const currentResult = document.activeElement as HTMLInputElement | null + const prevResult = currentResult?.previousElementSibling as HTMLInputElement | null + currentResult?.classList.remove("focus") + await displayPreview(prevResult) prevResult?.focus() } } else if (e.key === "ArrowDown" || e.key === "Tab") { e.preventDefault() - // When first pressing ArrowDown, results wont contain the active element, so focus first element + // The results should already been focused, so we need to find the next one. + // The activeElement is the search bar, so we need to find the first result and focus it. if (!results?.contains(document.activeElement)) { const firstResult = resultCards[0] as HTMLInputElement | null - if (enablePreview && firstResult?.id) { - await displayPreview(firstResult?.id as FullSlug) - } - firstResult?.focus() + const secondResult = firstResult?.nextElementSibling as HTMLInputElement | null + firstResult?.classList.remove("focus") + await displayPreview(secondResult) + secondResult?.focus() } else { // If an element in results-container already has focus, focus next one - const nextResult = document.activeElement?.nextElementSibling as HTMLInputElement | null - if (enablePreview && nextResult?.id) { - await displayPreview(nextResult?.id as FullSlug) - } + const active = document.activeElement as HTMLInputElement | null + active?.classList.remove("focus") + const nextResult = active?.nextElementSibling as HTMLInputElement | null + await displayPreview(nextResult) nextResult?.focus() } } @@ -262,19 +270,50 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { const resultToHTML = ({ slug, title, content, tags }: Item) => { const htmlTags = tags.length > 0 ? `
${content}
` + const itemTile = document.createElement("a") itemTile.classList.add("result-card") - itemTile.id = slug - itemTile.href = resolveUrl(slug).toString() - itemTile.innerHTML = `${content}
`}` - itemTile.addEventListener("click", (event) => { - if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return - hideSearch() + Object.assign(itemTile, { + id: slug, + href: resolveUrl(slug).toString(), + innerHTML: `