diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-21 16:13:12 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-21 16:13:12 +0200 |
| commit | 07a83b2e3db40f4a380092d6566500799b340dcd (patch) | |
| tree | 25bbe37ec3c459b48bcc14bf10eb8ad75836ef20 /src/routes | |
| parent | 8f95ffb13be709036916d604849f8fde7e777a8f (diff) | |
feat: fuzzy autocomplete for add-item input
Replace the native <datalist> with a custom fuzzysort-driven component
(FuzzyAutocomplete) with keyboard nav and highlighted matches, preserving
exact-match auto-add. Extract a unit-tested fuzzy-search helper, and gitignore
.juggler/. Fix the dev DB boot failure caused by a sibling project's ambient
DATABASE_URL leaking in by overriding it (file:./data.db) in mise.toml.
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/+page.svelte | 51 |
1 files changed, 6 insertions, 45 deletions
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 9900bb3..66380a4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,10 +2,10 @@ import { deserialize } from '$app/forms'; import { goto } from '$app/navigation'; import { enhance } from '$app/forms'; + import FuzzyAutocomplete from '$lib/components/FuzzyAutocomplete.svelte'; let { data, form } = $props(); let name = $state(''); - let inputRef: HTMLInputElement; // eslint-disable-next-line svelte/prefer-writable-derived let localItems = $state([]); let addError = $state(''); @@ -41,7 +41,6 @@ const action = redirectToEdit ? '?/addAndEdit' : '?/add'; name = ''; - inputRef.focus(); try { const response = await fetch(action, { @@ -79,48 +78,15 @@ </script> <div class="add-bar"> - <input - bind:this={inputRef} - class="form-input" - type="text" + <FuzzyAutocomplete + items={data.catalog} bind:value={name} placeholder="Ajouter un article..." - autocomplete="off" - list="item-suggestions" - onkeydown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - handleAdd(false); - } - }} - oninput={(e) => { - if ((e as InputEvent).inputType === 'insertReplacementText') { - const val = e.currentTarget.value.trim().toLowerCase(); - const match = data.catalog.find( - (item) => item.name.toLowerCase() === val, - ); - if (match) { - name = match.name; - handleAdd(false); - } - } - }} - onchange={(e) => { - const val = e.currentTarget.value.trim().toLowerCase(); - const match = data.catalog.find( - (item) => item.name.toLowerCase() === val, - ); - if (match) { - name = match.name; - handleAdd(false); - } + onselect={(item) => { + name = item.name; + handleAdd(false); }} /> - <datalist id="item-suggestions"> - {#each data.catalog as item (item.id)} - <option value={item.name}></option> - {/each} - </datalist> <button type="button" aria-label="Ajouter" onclick={() => handleAdd(false)} >+</button > @@ -187,11 +153,6 @@ z-index: 10; } - .add-bar input { - flex: 1; - background: var(--surface); - } - .add-bar button { width: 3rem; height: 3rem; |
