aboutsummaryrefslogtreecommitdiff
path: root/src/lib/components/fuzzy-search.ts
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-21 16:13:12 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-21 16:13:12 +0200
commit07a83b2e3db40f4a380092d6566500799b340dcd (patch)
tree25bbe37ec3c459b48bcc14bf10eb8ad75836ef20 /src/lib/components/fuzzy-search.ts
parent8f95ffb13be709036916d604849f8fde7e777a8f (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/lib/components/fuzzy-search.ts')
-rw-r--r--src/lib/components/fuzzy-search.ts25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/lib/components/fuzzy-search.ts b/src/lib/components/fuzzy-search.ts
new file mode 100644
index 0000000..31597b0
--- /dev/null
+++ b/src/lib/components/fuzzy-search.ts
@@ -0,0 +1,25 @@
+import fuzzysort, { type KeyResult } from 'fuzzysort';
+
+export type FuzzyItem = { id: number; name: string };
+
+export const FUZZ_LIMIT = 8;
+export const FUZZ_THRESHOLD = 0.2;
+
+export type FuzzyMatch = KeyResult<FuzzyItem>;
+
+/** Fuzzy-match `items` against `query`, ranked best-first. Empty/whitespace
+ * query returns no matches. Results carry `.score`, `.target`, `.highlight()`
+ * and `.obj` (the matched item). */
+export function matchItems(
+ items: FuzzyItem[],
+ query: string,
+ {
+ limit = FUZZ_LIMIT,
+ threshold = FUZZ_THRESHOLD,
+ }: { limit?: number; threshold?: number } = {},
+): FuzzyMatch[] {
+ const q = query.trim();
+ if (q === '') return [];
+ const snap = fuzzysort.snapshot(items, { key: 'name' });
+ return Array.from(fuzzysort.go(q, snap, { limit, threshold }));
+}