diff --git a/client/src/components/AppHeader.vue b/client/src/components/AppHeader.vue index 964803daf..7516fffac 100644 --- a/client/src/components/AppHeader.vue +++ b/client/src/components/AppHeader.vue @@ -1,153 +1,361 @@ diff --git a/client/src/features/book/composables/useGlobalSearch.ts b/client/src/features/book/composables/useGlobalSearch.ts new file mode 100644 index 000000000..ab7477460 --- /dev/null +++ b/client/src/features/book/composables/useGlobalSearch.ts @@ -0,0 +1,46 @@ +import { ref, watch, type Ref } from 'vue' +import { api } from '@/lib/api' + +export interface GlobalSearchResult { + id: number + title: string | null + authors: string[] + libraryId: number + libraryName: string +} + +export function useGlobalSearch(query: Ref) { + const results = ref([]) + const loading = ref(false) + let timer: ReturnType | null = null + + watch(query, (q) => { + if (timer) clearTimeout(timer) + if (q.trim().length < 2) { + results.value = [] + loading.value = false + return + } + loading.value = true + timer = setTimeout(async () => { + try { + const params = new URLSearchParams({ q: q.trim(), limit: '10' }) + const res = await api(`/api/books/search?${params}`) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + results.value = await res.json() + } catch { + results.value = [] + } finally { + loading.value = false + } + }, 300) + }) + + function clear() { + if (timer) clearTimeout(timer) + results.value = [] + loading.value = false + } + + return { results, loading, clear } +} diff --git a/client/src/views/HomeView.vue b/client/src/views/HomeView.vue index dad9739c7..9a47d431a 100644 --- a/client/src/views/HomeView.vue +++ b/client/src/views/HomeView.vue @@ -1,6 +1,7 @@