feat: search feature working well!

This commit is contained in:
2025-07-21 15:05:28 +01:00
parent 251e2bc553
commit 68010503ab
3 changed files with 45 additions and 50 deletions

View File

@ -26,7 +26,7 @@ export const SearchCard = (props: { item: UserImage }) => {
return (
<A
href={`/entity/${props.item.data.ID}`}
class="h-[144px] border relative border-neutral-200 cursor-pointer overflow-hidden rounded-xl"
class="w-full h-[144px] border relative border-neutral-200 cursor-pointer overflow-hidden rounded-xl"
>
<UnwrappedSearchCard item={props.item} />
</A>

View File

@ -1,8 +1,9 @@
import { Component, createSignal } from "solid-js";
import { Component, createSignal, For } from "solid-js";
import { Search } from "@kobalte/core/search";
import { IconSearch } from "@tabler/icons-solidjs";
import { useSearch } from "./search";
import { UserImage } from "@network/index";
import { SearchCard } from "@components/search-card/SearchCard";
export const SearchPage: Component = () => {
const fuse = useSearch();
@ -13,16 +14,12 @@ export const SearchPage: Component = () => {
<Search
options={searchItems()}
onInputChange={(e) => {
const items = fuse().search(e);
setSearchItems(items.map((i) => i.item.image));
setSearchItems(
fuse()
.search(e)
.map((i) => i.item),
);
}}
itemComponent={(props) => (
<Search.Item item={props.item}>
<Search.ItemLabel>
{JSON.stringify(props.item.rawValue)}
</Search.ItemLabel>
</Search.Item>
)}
>
<Search.Label />
<Search.Control class="flex">
@ -37,9 +34,9 @@ export const SearchPage: Component = () => {
/>
</Search.Control>
<Search.Portal>
<Search.Content class="w-full rounded-xl bg-white p-4">
<Search.Content class="container relative w-full rounded-xl bg-white p-4 grid grid-cols-3 gap-4">
<Search.Arrow />
<Search.Listbox />
<For each={searchItems()}>{(item) => <SearchCard item={item} />}</For>
<Search.NoResult>No result found</Search.NoResult>
</Search.Content>
</Search.Portal>

View File

@ -1,47 +1,45 @@
import { useSearchImageContext } from "@contexts/SearchImageContext";
import { UserImage } from "@network/index";
import { createMemo } from "solid-js";
import Fuse from "fuse.js";
import { createEffect } from "solid-js";
const getSearchTerms = (image: UserImage): Array<string> => {
switch (image.type) {
case "location":
return [
image.data.Name,
image.data.Description,
image.data.Address,
image.data.CreatedAt,
].filter((i) => i != null);
case "event":
return [
image.data.Name,
image.data.Description,
image.data.CreatedAt,
].filter((i) => i != null);
case "contact":
return [
image.data.Name,
image.data.Description,
image.data.CreatedAt,
image.data.Email,
image.data.PhoneNumber,
].filter((i) => i != null);
case "note":
return [
image.data.Name,
image.data.Description,
image.data.CreatedAt,
image.data.Content,
].filter((i) => i != null);
}
// This language is stupid. `keyof` only returns common keys but this somehow doesnt.
type KeysOfUnion<T> = T extends T ? keyof T : never;
const weightedTerms: Record<
KeysOfUnion<UserImage["data"]>,
number | undefined
> = {
ID: undefined,
LocationID: undefined,
OrganizerID: undefined,
Images: undefined,
Name: 5,
Description: 2,
Address: 2,
PhoneNumber: 2,
Email: 2,
CreatedAt: 1,
StartDateTime: 1,
EndDateTime: 1,
Content: 1,
};
export const useSearch = () => {
const { images } = useSearchImageContext();
const searchTerms = createMemo(() =>
images().map((i) => ({ image: i, searchTerms: getSearchTerms(i) })),
);
return () => new Fuse(searchTerms(), { keys: ["searchTerms"] });
return () =>
new Fuse(images(), {
shouldSort: true,
keys: Object.entries(weightedTerms)
.filter(([, w]) => w != null)
.map(([name, weight]) => ({
name: `data.${name}`,
weight,
})),
});
};