Skip to content

Commit 6bf0fd1

Browse files
committed
fix: adapt instant search into user preferences
1 parent 03b723d commit 6bf0fd1

6 files changed

Lines changed: 32 additions & 16 deletions

File tree

app/app.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ if (import.meta.server) {
4848
}
4949
5050
const keyboardShortcuts = useKeyboardShortcuts()
51-
const { settings } = useSettings()
51+
const instantSearch = useInstantSearch()
5252
5353
onKeyDown(
5454
'/',
5555
e => {
5656
if (e.ctrlKey) {
5757
e.preventDefault()
58-
settings.value.instantSearch = !settings.value.instantSearch
58+
instantSearch.value = !instantSearch.value
5959
return
6060
}
6161

app/components/InstantSearch.vue

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
<script setup lang="ts">
2-
import { useSettings } from '~/composables/useSettings'
3-
4-
const { settings } = useSettings()
2+
const instantSearch = useInstantSearch()
53
64
onPrehydrate(el => {
7-
const settingsSaved = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
8-
const enabled = settingsSaved.instantSearch
5+
let userPreferences: Record<string, unknown> = {}
6+
7+
try {
8+
userPreferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
9+
} catch {}
10+
11+
const enabled = userPreferences.instantSearch
912
if (enabled === false) {
1013
el.querySelector('[data-instant-search-on]')!.className = 'hidden'
1114
el.querySelector('[data-instant-search-off]')!.className = ''
@@ -20,7 +23,7 @@ onPrehydrate(el => {
2023
style="font-size: 0.8em"
2124
aria-hidden="true"
2225
/>
23-
<span data-instant-search-on :class="settings.instantSearch ? '' : 'hidden'">
26+
<span data-instant-search-on :class="instantSearch ? '' : 'hidden'">
2427
<i18n-t keypath="search.instant_search_advisory">
2528
<template #label>
2629
{{ $t('search.instant_search') }}
@@ -29,13 +32,13 @@ onPrehydrate(el => {
2932
<strong>{{ $t('search.instant_search_on') }}</strong>
3033
</template>
3134
<template #action>
32-
<button type="button" class="underline" @click="settings.instantSearch = false">
35+
<button type="button" class="underline" @click="instantSearch = false">
3336
{{ $t('search.instant_search_turn_off') }}
3437
</button>
3538
</template>
3639
</i18n-t>
3740
</span>
38-
<span data-instant-search-off :class="settings.instantSearch ? 'hidden' : ''">
41+
<span data-instant-search-off :class="instantSearch ? 'hidden' : ''">
3942
<i18n-t keypath="search.instant_search_advisory">
4043
<template #label>
4144
{{ $t('search.instant_search') }}
@@ -44,7 +47,7 @@ onPrehydrate(el => {
4447
<strong>{{ $t('search.instant_search_off') }}</strong>
4548
</template>
4649
<template #action>
47-
<button type="button" class="underline" @click="settings.instantSearch = true">
50+
<button type="button" class="underline" @click="instantSearch = true">
4851
{{ $t('search.instant_search_turn_on') }}
4952
</button>
5053
</template>

app/composables/useGlobalSearch.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { debounce } from 'perfect-debounce'
55
const pagesWithLocalFilter = new Set(['~username', 'org'])
66

77
export function useGlobalSearch(place: 'header' | 'content' = 'content') {
8-
const { settings } = useSettings()
8+
const instantSearch = useInstantSearch()
99
const { searchProvider } = useSearchProvider()
1010
const searchProviderValue = computed(() => {
1111
const p = normalizeSearchParam(route.query.p)
@@ -29,7 +29,7 @@ export function useGlobalSearch(place: 'header' | 'content' = 'content') {
2929

3030
// This is basically doing instant search as user types
3131
watch(searchQuery, val => {
32-
if (settings.value.instantSearch) {
32+
if (instantSearch.value) {
3333
committedSearchQuery.value = val
3434
}
3535
})
@@ -77,7 +77,7 @@ export function useGlobalSearch(place: 'header' | 'content' = 'content') {
7777
// Commit the current query when explicitly submitted (Enter pressed)
7878
committedSearchQuery.value = searchQuery.value
7979
// When instant search is off the debounce queue is empty, so call directly
80-
if (!settings.value.instantSearch) {
80+
if (!instantSearch.value) {
8181
updateUrlQueryImpl(searchQuery.value, searchProvider.value)
8282
} else {
8383
updateUrlQuery.flush()
@@ -91,7 +91,7 @@ export function useGlobalSearch(place: 'header' | 'content' = 'content') {
9191

9292
// When instant search is off, skip debounced URL updates
9393
// Only explicitly called flushUpdateUrlQuery commits and navigates
94-
if (!settings.value.instantSearch) return
94+
if (!instantSearch.value) return
9595

9696
// Leading debounce implementation as it doesn't work properly out of the box (https://github.com/unjs/perfect-debounce/issues/43)
9797
if (!updateUrlQuery.isPending()) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const useInstantSearch = createSharedComposable(function useInstantSearch() {
2+
const { preferences } = useUserPreferencesState()
3+
4+
return computed({
5+
get: () => preferences.value.instantSearch ?? true,
6+
set: (value: boolean) => {
7+
preferences.value.instantSearch = value
8+
},
9+
})
10+
})

app/pages/settings.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ const setLocale: typeof setNuxti18nLocale = locale => {
262262
<SettingsToggle
263263
:label="$t('settings.instant_search')"
264264
:description="$t('settings.instant_search_description')"
265-
v-model="settings.instantSearch"
265+
v-model="preferences.instantSearch"
266266
/>
267267
</div>
268268
</section>

shared/schemas/userPreferences.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export const UserPreferencesSchema = object({
2828
searchProvider: optional(SearchProviderSchema),
2929
/** Whether keyboard shortcuts are enabled globally */
3030
keyboardShortcuts: optional(boolean()),
31+
/** Whether search runs as user types (vs requiring explicit submit) */
32+
instantSearch: optional(boolean()),
3133
/** Timestamp of last update (ISO 8601) - managed by server */
3234
updatedAt: optional(string()),
3335
})
@@ -53,6 +55,7 @@ export const DEFAULT_USER_PREFERENCES: Required<Omit<UserPreferences, 'updatedAt
5355
colorModePreference: null,
5456
searchProvider: import.meta.test ? 'npm' : 'algolia',
5557
keyboardShortcuts: true,
58+
instantSearch: true,
5659
}
5760

5861
export const USER_PREFERENCES_STORAGE_BASE = 'npmx-kv-user-preferences'

0 commit comments

Comments
 (0)