Skip to content

Commit 551d956

Browse files
committed
feat: fuzzy search with microfuzz
1 parent 078ed32 commit 551d956

File tree

5 files changed

+70
-32
lines changed

5 files changed

+70
-32
lines changed

frontend/package-lock.json

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"format": "prettier . --write"
1818
},
1919
"dependencies": {
20+
"@nozbe/microfuzz": "^1.0.0",
2021
"@pinia/colada": "^0.17.1",
2122
"@tailwindcss/vite": "^4.1.11",
2223
"@vee-validate/zod": "^4.15.1",

frontend/src/components/CompanyOrSpeakerAutocompleteWithDialog.vue

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ import {
271271
} from "@/components/ui/alert-dialog";
272272
import type { Company } from "@/dto/companies";
273273
import type { Speaker } from "@/dto/speakers";
274+
import createFuzzySearch from "@nozbe/microfuzz";
274275
275276
type SelectedItem = Company | Speaker;
276277
@@ -315,10 +316,15 @@ const highlightedIndex = ref(-1);
315316
316317
// Detect platform for keyboard shortcut
317318
const isMac = computed(() => {
318-
return (
319-
typeof navigator !== "undefined" &&
320-
navigator.platform.toUpperCase().indexOf("MAC") >= 0
321-
);
319+
if (typeof navigator === "undefined") return false;
320+
321+
const uaData = navigator.userAgentData;
322+
if (uaData && typeof uaData.platform === "string") {
323+
return uaData.platform === "macOS";
324+
}
325+
326+
const ua = navigator.userAgent || "";
327+
return /\bMacintosh\b|\bMac OS X\b/.test(ua);
322328
});
323329
324330
// Companies query
@@ -339,41 +345,51 @@ const isLoading = computed(
339345
() => companiesLoading.value || speakersLoading.value,
340346
);
341347
348+
const companyFuzzy = computed(() => {
349+
const list = companiesData.value?.data ?? [];
350+
if (!list.length) return null;
351+
352+
return createFuzzySearch(list, {
353+
// match on multiple fields
354+
getText: (company: Company) => [company.name, company.description ?? ""],
355+
});
356+
});
357+
358+
const speakerFuzzy = computed(() => {
359+
const list = speakersData.value?.data ?? [];
360+
if (!list.length) return null;
361+
362+
return createFuzzySearch(list, {
363+
getText: (speaker: Speaker) => [speaker.name, speaker.companyName ?? ""],
364+
});
365+
});
366+
342367
const filteredCompanies = computed(() => {
343-
if (!companiesData.value?.data) return [];
368+
const list = companiesData.value?.data ?? [];
369+
const term = searchTerm.value.trim();
344370
345-
const term = searchTerm.value.toLowerCase();
371+
// Show recent companies when no search term
372+
if (!term) return list.slice(0, 5);
346373
347-
if (!term) {
348-
// Show recent companies when no search term
349-
return companiesData.value.data.slice(0, 5);
350-
}
374+
const fuzzy = companyFuzzy.value;
375+
if (!fuzzy) return [];
351376
352-
return companiesData.value.data
353-
.filter(
354-
(company: Company) =>
355-
company.name.toLowerCase().includes(term) ||
356-
company.description?.toLowerCase().includes(term),
357-
)
377+
return fuzzy(term)
378+
.map((res) => res.item)
358379
.slice(0, 5); // Limit to 5 results
359380
});
360381
361382
const filteredSpeakers = computed(() => {
362-
if (!speakersData.value?.data) return [];
383+
const list = speakersData.value?.data ?? [];
384+
const term = searchTerm.value.trim();
363385
364-
const term = searchTerm.value.toLowerCase();
386+
if (!term) return list.slice(0, 5);
365387
366-
if (!term) {
367-
// Show recent speakers when no search term
368-
return speakersData.value.data.slice(0, 5);
369-
}
388+
const fuzzy = speakerFuzzy.value;
389+
if (!fuzzy) return [];
370390
371-
return speakersData.value.data
372-
.filter(
373-
(speaker: Speaker) =>
374-
speaker.name.toLowerCase().includes(term) ||
375-
speaker.companyName?.toLowerCase().includes(term),
376-
)
391+
return fuzzy(term)
392+
.map((res) => res.item)
377393
.slice(0, 5); // Limit to 5 results
378394
});
379395

frontend/src/global.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
interface NavigatorUAData {
2+
platform?: string;
3+
brands?: Array<{ brand: string; version: string }>;
4+
mobile?: boolean;
5+
}
6+
7+
declare global {
8+
interface Navigator {
9+
userAgentData?: NavigatorUAData;
10+
}
11+
}
12+
13+
export {};

frontend/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
"paths": {
1010
"@/*": ["./src/*"]
1111
}
12-
}
12+
},
13+
"include": ["src"]
1314
}

0 commit comments

Comments
 (0)