Add live registry search and themed input states
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page as currentPage } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import { navigating, page as currentPage } from '$app/state';
|
||||
import { onDestroy } from 'svelte';
|
||||
let {
|
||||
pagination,
|
||||
namespace = '',
|
||||
@@ -14,6 +16,35 @@
|
||||
const pageKey = $derived(namespace ? `${namespace}Page` : 'page');
|
||||
const perPageKey = $derived(namespace ? `${namespace}PerPage` : 'perPage');
|
||||
const searchKey = $derived(namespace ? `${namespace}Q` : 'q');
|
||||
let draftSearch = $state<string | null>(null);
|
||||
const searchValue = $derived(draftSearch ?? search ?? '');
|
||||
let searchTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
const searchPending = $derived(Boolean(navigating.to) && navigating.to?.url.searchParams.get(searchKey) !== currentPage.url.searchParams.get(searchKey));
|
||||
$effect(() => {
|
||||
if (draftSearch !== null && draftSearch.trim() === (search ?? '').trim()) draftSearch = null;
|
||||
});
|
||||
const searchHref = (query: string) => {
|
||||
const params = new URLSearchParams(currentPage.url.searchParams);
|
||||
const normalized = query.trim();
|
||||
if (normalized) params.set(searchKey, normalized);
|
||||
else params.delete(searchKey);
|
||||
params.delete(pageKey);
|
||||
const serialized = params.toString();
|
||||
return `${currentPage.url.pathname}${serialized ? `?${serialized}` : ''}`;
|
||||
};
|
||||
const submitSearch = (query = searchValue) => {
|
||||
if (searchTimer) clearTimeout(searchTimer);
|
||||
if (query.trim() === (search ?? '').trim()) return;
|
||||
void goto(searchHref(query), { replaceState: true, keepFocus: true, noScroll: true });
|
||||
};
|
||||
const scheduleSearch = (query: string) => {
|
||||
draftSearch = query;
|
||||
if (searchTimer) clearTimeout(searchTimer);
|
||||
searchTimer = setTimeout(() => submitSearch(query), 350);
|
||||
};
|
||||
onDestroy(() => {
|
||||
if (searchTimer) clearTimeout(searchTimer);
|
||||
});
|
||||
const href = (targetPage: number, perPage = pagination.perPage) => {
|
||||
const params = new URLSearchParams(currentPage.url.searchParams);
|
||||
params.set(pageKey, String(targetPage));
|
||||
@@ -38,10 +69,10 @@
|
||||
|
||||
<nav class="registry-pagination" aria-label="Registry pagination">
|
||||
{#if search !== undefined}
|
||||
<form class="pagination-search">
|
||||
<form class="pagination-search" role="search" onsubmit={(event) => { event.preventDefault(); submitSearch(); }}>
|
||||
{#each retainedParams as [key, value]}<input type="hidden" name={key} {value}/>{/each}
|
||||
<input type="search" name={searchKey} value={search} maxlength="80" placeholder={searchPlaceholder} aria-label={searchPlaceholder}/>
|
||||
<button class="secondary">SEARCH</button>
|
||||
<input type="search" name={searchKey} value={searchValue} maxlength="80" placeholder={searchPlaceholder} aria-label={`${searchPlaceholder} — results update as you type`} oninput={(event) => scheduleSearch(event.currentTarget.value)}/>
|
||||
<button class="secondary" aria-busy={searchPending} disabled={searchPending}>{searchPending ? 'SEARCHING…' : 'SEARCH'}</button>
|
||||
{#if search}<a href={clearSearchHref}>CLEAR</a>{/if}
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user