-
-
Notifications
You must be signed in to change notification settings - Fork 432
refactor(ui): fetch results on submit instead of on type #1107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
fc08134
67a79b3
8f40b1d
ef876a2
e8ac1e1
ef5bec4
a772aa3
0791856
65e7cf1
c91e729
c7b2d2a
97861a1
e2b8a21
29a84e2
d4a3281
ce7e64b
cc69daf
2f09f27
3176d58
6cc780c
6c285e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| <script setup lang="ts"> | ||
| defineProps<{ | ||
| compact?: boolean | ||
| }>() | ||
|
|
||
| const emit = defineEmits<{ | ||
| (e: 'submit', searchQuery: string): void | ||
| (e: 'blur'): void | ||
| (e: 'focus'): void | ||
| }>() | ||
|
|
||
| const searchQuery = defineModel<string>({ | ||
| default: '', | ||
| }) | ||
|
MatteoGabriele marked this conversation as resolved.
|
||
|
|
||
| function handleSubmit() { | ||
| emit('submit', searchQuery.value) | ||
| } | ||
|
|
||
| function handleBlur() { | ||
| emit('blur') | ||
| } | ||
| function handleFocus() { | ||
| emit('focus') | ||
| } | ||
|
|
||
| // Expose focus method for parent components | ||
| const inputRef = useTemplateRef('inputRef') | ||
| function focus() { | ||
| inputRef.value?.focus() | ||
| } | ||
|
|
||
| defineExpose({ | ||
| focus, | ||
| }) | ||
| </script> | ||
|
|
||
| <template> | ||
| <search class="w-full @container"> | ||
| <form method="GET" action="/search" class="relative" @submit.prevent="handleSubmit"> | ||
| <label for="search-box" class="sr-only"> | ||
| {{ $t('search.label') }} | ||
|
ghostdevv marked this conversation as resolved.
|
||
| </label> | ||
|
|
||
| <div class="relative group"> | ||
| <div | ||
| class="absolute -inset-px rounded-lg bg-gradient-to-r from-fg/0 via-fg/5 to-fg/0 opacity-0 transition-opacity duration-500 blur-sm group-[.is-focused]:opacity-100" | ||
| /> | ||
|
|
||
| <div class="search-box relative flex items-center"> | ||
| <span | ||
| class="absolute text-fg-subtle font-mono pointer-events-none transition-colors duration-200 motion-reduce:transition-none [.group:hover:not(:focus-within)_&]:text-fg/80 group-focus-within:text-accent z-1" | ||
| :class="compact ? 'inset-is-3 text-sm' : 'inset-is-4 text-xl'" | ||
| > | ||
| / | ||
| </span> | ||
|
|
||
| <input | ||
| id="search-box" | ||
| ref="inputRef" | ||
| v-model.trim="searchQuery" | ||
| type="search" | ||
| name="q" | ||
| :placeholder="$t('search.placeholder')" | ||
|
ghostdevv marked this conversation as resolved.
|
||
| v-bind="noCorrect" | ||
| class="w-full bg-bg-subtle border border-border text-base font-mono text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 motion-reduce:transition-none hover:border-fg-subtle outline-2 outline-transparent focus:border-accent focus-visible:(outline-2 outline-accent/70)" | ||
| :class=" | ||
| compact ? 'ps-7 pe-3 py-1.5 rounded-md text-sm!' : 'ps-8 pe-24 h-14 py-4 rounded-xl' | ||
| " | ||
| @blur="handleBlur" | ||
| @focus="handleFocus" | ||
| /> | ||
|
|
||
| <button | ||
| type="submit" | ||
| class="absolute hidden @xs:block group inset-ie-2.5 font-mono text-sm transition-[background-color,transform] duration-200 active:scale-95" | ||
| :class=" | ||
| compact | ||
| ? 'px-1.5 py-0.5 @md:ps-4 @md:pe-4' | ||
| : 'rounded-md px-2.5 @md:ps-4 @md:pe-4 py-2 text-bg bg-fg/90 hover:bg-fg! group-focus-within:bg-fg/80' | ||
| " | ||
| > | ||
| <span | ||
| class="inline-block i-carbon:search align-middle w-4 h-4 @md:me-2" | ||
| aria-hidden="true" | ||
| ></span> | ||
| <span class="sr-only @md:not-sr-only"> | ||
| {{ $t('search.button') }} | ||
|
ghostdevv marked this conversation as resolved.
|
||
| </span> | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </form> | ||
| </search> | ||
| </template> | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,28 +1,18 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <script setup lang="ts"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { debounce } from 'perfect-debounce' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { SHOWCASED_FRAMEWORKS } from '~/utils/frameworks' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const searchQuery = shallowRef('') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const searchInputRef = useTemplateRef('searchInputRef') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const { focused: isSearchFocused } = useFocus(searchInputRef) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async function handleSearchSubmit() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!searchQuery.value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| async function search() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const query = searchQuery.value.trim() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!query) return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await navigateTo({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| path: '/search', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| query: query ? { q: query } : undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'search', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| query: { q: searchQuery.value }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trim whitespace-only queries before navigating. Right now Suggested tweak async function handleSearchSubmit() {
- if (!searchQuery.value) {
+ const query = searchQuery.value.trim()
+ if (!query) {
return
}
await navigateTo({
name: 'search',
- query: { q: searchQuery.value },
+ query: { q: query },
})
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const newQuery = searchQuery.value.trim() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (newQuery !== query) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await search() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleInput = isTouchDevice() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ? search | ||||||||||||||||||||||||||||||||||||||||||||||||||
| : debounce(search, 250, { leading: true, trailing: true }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| useSeoMeta({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| title: () => $t('seo.home.title'), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ogTitle: () => $t('seo.home.title'), | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -62,56 +52,12 @@ defineOgImageComponent('Default', { | |||||||||||||||||||||||||||||||||||||||||||||||||
| {{ $t('tagline') }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <search | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="w-full max-w-xl motion-safe:animate-slide-up motion-safe:animate-fill-both" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <SearchBox | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="max-w-xl motion-safe:animate-slide-up motion-safe:animate-fill-both" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| style="animation-delay: 0.2s" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <form method="GET" action="/search" class="relative" @submit.prevent.trim="search"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <label for="home-search" class="sr-only"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| {{ $t('search.label') }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="relative group" :class="{ 'is-focused': isSearchFocused }"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="absolute -inset-px rounded-lg bg-gradient-to-r from-fg/0 via-fg/5 to-fg/0 opacity-0 transition-opacity duration-500 blur-sm group-[.is-focused]:opacity-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="search-box relative flex items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="absolute inset-is-4 text-fg-subtle font-mono text-lg pointer-events-none transition-colors duration-200 motion-reduce:transition-none [.group:hover:not(:focus-within)_&]:text-fg/80 group-focus-within:text-accent z-1" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||
| / | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||
| id="home-search" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ref="searchInputRef" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| v-model="searchQuery" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| type="search" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name="q" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| autofocus | ||||||||||||||||||||||||||||||||||||||||||||||||||
| :placeholder="$t('search.placeholder')" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| v-bind="noCorrect" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="w-full bg-bg-subtle border border-border rounded-xl ps-8 pe-24 h-14 py-4 font-mono text-base text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 motion-reduce:transition-none hover:border-fg-subtle outline-2 outline-transparent focus:border-accent focus-visible:(outline-2 outline-accent/70)" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @input="handleInput" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||||||
| type="submit" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="absolute group inset-ie-2.5 px-2.5 sm:ps-4 sm:pe-4 py-2 font-mono text-sm text-bg bg-fg/90 rounded-md transition-[background-color,transform] duration-200 hover:bg-fg! group-focus-within:bg-fg/80 active:scale-95 focus-visible:outline-accent/70" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||||||||||||||
| class="inline-block i-carbon:search align-middle w-4 h-4 sm:me-2" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| aria-hidden="true" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ></span> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="sr-only sm:not-sr-only"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| {{ $t('search.button') }} | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </form> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </search> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| v-model="searchQuery" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @submit="handleSearchSubmit" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| <BuildEnvironment class="mt-4" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| </header> | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the difference in nuxt between the
router.pushthat was happening before, and this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, I think either option would work.
Previously, this component had no route handling, so I copy-pasted the function from the homepage, as they serve the same purpose. I didn't check whether it was navigateTo or router.push, since they essentially perform the same action. I believe navigateTo is a helper function that can also be used on the server side.