Skip to content

Commit 29a84e2

Browse files
refactor: optimize search on update
1 parent e2b8a21 commit 29a84e2

2 files changed

Lines changed: 35 additions & 15 deletions

File tree

app/components/AppHeader.vue

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import { debounce } from 'perfect-debounce'
23
import { isEditableElement } from '~/utils/input'
34
45
withDefaults(
@@ -16,30 +17,31 @@ const showFullSearch = shallowRef(false)
1617
const showMobileMenu = shallowRef(false)
1718
1819
// On mobile, clicking logo+search button expands search
19-
const route = useRoute()
2020
const isMobile = useIsMobile()
2121
const isSearchExpandedManually = shallowRef(false)
2222
const searchBoxRef = useTemplateRef('searchBoxRef')
2323
24-
const searchQuery = shallowRef('')
24+
const route = useRoute()
25+
const searchQuery = shallowRef<string>(normalizeSearchParam(route.query.q))
26+
2527
watch(
2628
() => route.query.q,
2729
queryValue => {
28-
searchQuery.value = normalizeSearchParam(queryValue)
30+
if (queryValue !== searchQuery.value) {
31+
searchQuery.value = normalizeSearchParam(queryValue)
32+
}
2933
},
30-
{ immediate: true },
3134
)
3235
33-
async function handleSearchSubmit() {
34-
if (!searchQuery.value) {
35-
return
36+
const router = useRouter()
37+
const onSearchQueryUpdate = debounce((newSearchQuery: string) => {
38+
if (newSearchQuery !== searchQuery.value) {
39+
router.replace({
40+
name: 'search',
41+
query: { q: newSearchQuery === '' ? undefined : newSearchQuery },
42+
})
3643
}
37-
38-
await navigateTo({
39-
name: 'search',
40-
query: { q: searchQuery.value },
41-
})
42-
}
44+
}, 500)
4345
4446
// On search page, always show search expanded on mobile
4547
const isOnHomePage = computed(() => route.name === 'index')
@@ -147,8 +149,8 @@ onKeyStroke(
147149
ref="searchBoxRef"
148150
class="max-w-sm"
149151
compact
150-
v-model="searchQuery"
151-
@submit="handleSearchSubmit"
152+
:model-value="searchQuery"
153+
@update:model-value="onSearchQueryUpdate"
152154
@focus="handleSearchFocus"
153155
@blur="handleSearchBlur"
154156
/>

app/pages/search.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,24 @@ watch(displayResults, results => {
573573
})
574574
575575
function handleResultsKeydown(e: KeyboardEvent) {
576+
// If the active element is an input, navigate to exact match or wait for results
577+
if (e.key === 'Enter' && document.activeElement?.tagName === 'INPUT') {
578+
// Get value directly from input (not from route query, which may be debounced)
579+
const inputValue = (document.activeElement as HTMLInputElement).value.trim()
580+
if (!inputValue) return
581+
582+
// Check if first result matches the input value exactly
583+
const firstResult = displayResults.value[0]
584+
if (firstResult?.package.name === inputValue) {
585+
pendingEnterQuery.value = null
586+
return navigateToPackage(firstResult.package.name)
587+
}
588+
589+
// No match yet - store input value, watcher will handle navigation when results arrive
590+
pendingEnterQuery.value = inputValue
591+
return
592+
}
593+
576594
if (totalSelectableCount.value <= 0) return
577595
578596
const elements = getFocusableElements()

0 commit comments

Comments
 (0)