@@ -31,7 +31,7 @@ const updateUrlPage = debounce((page: number) => {
3131}, 500 )
3232
3333const { model : searchQuery, provider : searchProvider } = useGlobalSearch ()
34- const query = computed (() => searchQuery .value )
34+ const query = computed (() => searchQuery .value . trim (). replace ( / ! $ / , ' ' ) )
3535
3636// Track if page just loaded (for hiding "Searching..." during view transition)
3737const hasInteracted = shallowRef (false )
@@ -424,28 +424,34 @@ async function navigateToPackage(packageName: string) {
424424// Track the input value when user pressed Enter (for navigating when results arrive)
425425const pendingEnterQuery = shallowRef <string | null >(null )
426426
427- // Watch for results to navigate when Enter was pressed before results arrived
428- watch (displayResults , results => {
429- if (! pendingEnterQuery .value ) return
427+ // Watch for results to navigate when Enter was pressed before results arrived,
428+ // or for "I'm feeling lucky" redirection when the query ends with "!" and there is the exact match.
429+ watch (
430+ displayResults ,
431+ results => {
432+ const rawQuery = normalizeSearchParam (route .query .q )
433+ const isFeelingLucky = rawQuery .endsWith (' !' )
430434
431- // Check if input is still focused (user hasn't started navigating or clicked elsewhere)
432- if (document .activeElement ?.tagName !== ' INPUT' ) {
433- pendingEnterQuery .value = null
434- return
435- }
435+ if (! pendingEnterQuery .value && ! isFeelingLucky ) return
436436
437- // Navigate if first result matches the query that was entered
438- const firstResult = results [0 ]
439- // eslint-disable-next-line no-console
440- console .log (' [search] watcher fired' , {
441- pending: pendingEnterQuery .value ,
442- firstResult: firstResult ?.package .name ,
443- })
444- if (firstResult ?.package .name === pendingEnterQuery .value ) {
445- pendingEnterQuery .value = null
446- navigateToPackage (firstResult .package .name )
447- }
448- })
437+ // For manual Enter, check if input is still focused (user hasn't started navigating or clicked elsewhere)
438+ if (pendingEnterQuery .value && document .activeElement ?.tagName !== ' INPUT' ) {
439+ pendingEnterQuery .value = null
440+ return
441+ }
442+
443+ const target = pendingEnterQuery .value || rawQuery .replace (/ !$ / , ' ' )
444+ if (! target ) return
445+
446+ // Navigate if first result matches the target query
447+ const firstResult = results [0 ]
448+ if (firstResult ?.package .name === target ) {
449+ pendingEnterQuery .value = null
450+ navigateToPackage (firstResult .package .name )
451+ }
452+ },
453+ { immediate: true },
454+ )
449455
450456function handleResultsKeydown(e : KeyboardEvent ) {
451457 // If the active element is an input, navigate to exact match or wait for results
@@ -454,15 +460,17 @@ function handleResultsKeydown(e: KeyboardEvent) {
454460 const inputValue = (document .activeElement as HTMLInputElement ).value .trim ()
455461 if (! inputValue ) return
456462
463+ const cleanedInputValue = inputValue .replace (/ !$ / , ' ' )
464+
457465 // Check if first result matches the input value exactly
458466 const firstResult = displayResults .value [0 ]
459- if (firstResult ?.package .name === inputValue ) {
467+ if (firstResult ?.package .name === cleanedInputValue ) {
460468 pendingEnterQuery .value = null
461469 return navigateToPackage (firstResult .package .name )
462470 }
463471
464- // No match yet - store input value, watcher will handle navigation when results arrive
465- pendingEnterQuery .value = inputValue
472+ // No match yet - store cleaned input value, watcher will handle navigation when results arrive
473+ pendingEnterQuery .value = cleanedInputValue
466474 return
467475 }
468476
0 commit comments