feat : add fuzzy matching for searching
CI / Verify (push) Failing after 58s
CI / Build immutable images and deploy (push) Has been skipped

This commit is contained in:
2026-09-12 16:07:16 +07:00 Unverified
parent 0ec214d3e0
commit 92b57e0ed3
15 changed files with 318 additions and 79 deletions
+8 -4
View File
@@ -1,5 +1,8 @@
"use client";
import { searchItems } from "@/lib/search";
import { SearchNotice } from "@/components/search-notice";
import Image from "next/image";
import Link from "next/link";
import { SearchIcon, UsersIcon } from "lucide-react";
@@ -39,10 +42,10 @@ type GuideCard = {
export function StructuredDirectory({ guides }: { guides: GuideCard[] }) {
const [query, setQuery] = useState("");
const presence = useVisitorPresence(null);
const normalized = query.trim().toLowerCase();
const filtered = guides.filter((guide) =>
`${guide.name} ${guide.overview} ${guide.aliases.join(" ")}`.toLowerCase().includes(normalized),
);
const search = searchItems(guides, query,
(guide) => `${guide.name} ${guide.overview} ${guide.aliases.join(" ")}`,
(guide) => [guide.name, ...guide.aliases]);
const filtered = search.items;
return (
<div className="flex flex-col gap-8">
<InputGroup className="h-11 max-w-2xl">
@@ -56,6 +59,7 @@ export function StructuredDirectory({ guides }: { guides: GuideCard[] }) {
aria-label="ค้นหาไกด์"
/>
</InputGroup>
<SearchNotice fuzzy={search.fuzzy} />
{filtered.length ? (
<div className="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
{filtered.map((guide, index) => (
+10 -5
View File
@@ -1,5 +1,7 @@
"use client";
import { SearchNotice } from "@/components/search-notice";
import Image from "next/image";
import Link from "next/link";
import { ArrowUpRightIcon, SearchIcon, XIcon } from "lucide-react";
@@ -19,7 +21,7 @@ import { rarityGradientClass } from "@/lib/catalog/rarity";
import { isCustomTravelerKey } from "@/lib/catalog/travelers";
import type { PublicGuide } from "@/lib/guides/queries";
import {
matchesTeamSearch,
searchTeams,
sortTeamsByDps,
type DpsOrder,
type TeamSearchTarget,
@@ -379,18 +381,21 @@ export function TeamSearch({ groups }: { groups: PublicGuide["teamGroups"] }) {
const [query, setQuery] = useState("");
const [searchTarget, setSearchTarget] = useState<TeamSearchTarget>("all");
const [dpsOrder, setDpsOrder] = useState<DpsOrder>(null);
const filteredTeams = useMemo(
() => sortTeamsByDps(teams.filter((team) => matchesTeamSearch({
const search = useMemo(
() => searchTeams(teams, (team) => ({
team: [team.title],
character: team.members.flatMap((member) => [member.character.name, ...member.character.aliases]),
weapon: team.members.flatMap((member) => member.weapon ? [member.weapon.name, ...member.weapon.aliases] : []),
artifact: team.members.flatMap((member) => [member.artifact, member.secondArtifact].flatMap((artifact) => artifact ? [artifact.name, ...artifact.aliases] : [])),
}, query, searchTarget)), dpsOrder),
[dpsOrder, query, searchTarget, teams],
}), query, searchTarget),
[query, searchTarget, teams],
);
const filteredTeams = sortTeamsByDps(search.items, dpsOrder);
return (
<div className="flex min-w-0 flex-col gap-4">
<SearchNotice fuzzy={search.fuzzy} />
{groups.length > 1 ? (
<ScrollableNav ariaLabel="เลือกเงื่อนไขทีม" className="w-full min-w-0">
<ToggleGroup aria-label="เลือกเงื่อนไขทีม" variant="outline" value={[activeCondition]} onValueChange={(values) => {