feat: search feature working well!
This commit is contained in:
@ -26,7 +26,7 @@ export const SearchCard = (props: { item: UserImage }) => {
|
|||||||
return (
|
return (
|
||||||
<A
|
<A
|
||||||
href={`/entity/${props.item.data.ID}`}
|
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} />
|
<UnwrappedSearchCard item={props.item} />
|
||||||
</A>
|
</A>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Component, createSignal } from "solid-js";
|
import { Component, createSignal, For } from "solid-js";
|
||||||
import { Search } from "@kobalte/core/search";
|
import { Search } from "@kobalte/core/search";
|
||||||
import { IconSearch } from "@tabler/icons-solidjs";
|
import { IconSearch } from "@tabler/icons-solidjs";
|
||||||
import { useSearch } from "./search";
|
import { useSearch } from "./search";
|
||||||
import { UserImage } from "@network/index";
|
import { UserImage } from "@network/index";
|
||||||
|
import { SearchCard } from "@components/search-card/SearchCard";
|
||||||
|
|
||||||
export const SearchPage: Component = () => {
|
export const SearchPage: Component = () => {
|
||||||
const fuse = useSearch();
|
const fuse = useSearch();
|
||||||
@ -13,16 +14,12 @@ export const SearchPage: Component = () => {
|
|||||||
<Search
|
<Search
|
||||||
options={searchItems()}
|
options={searchItems()}
|
||||||
onInputChange={(e) => {
|
onInputChange={(e) => {
|
||||||
const items = fuse().search(e);
|
setSearchItems(
|
||||||
setSearchItems(items.map((i) => i.item.image));
|
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.Label />
|
||||||
<Search.Control class="flex">
|
<Search.Control class="flex">
|
||||||
@ -37,9 +34,9 @@ export const SearchPage: Component = () => {
|
|||||||
/>
|
/>
|
||||||
</Search.Control>
|
</Search.Control>
|
||||||
<Search.Portal>
|
<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.Arrow />
|
||||||
<Search.Listbox />
|
<For each={searchItems()}>{(item) => <SearchCard item={item} />}</For>
|
||||||
<Search.NoResult>No result found</Search.NoResult>
|
<Search.NoResult>No result found</Search.NoResult>
|
||||||
</Search.Content>
|
</Search.Content>
|
||||||
</Search.Portal>
|
</Search.Portal>
|
||||||
|
@ -1,47 +1,45 @@
|
|||||||
import { useSearchImageContext } from "@contexts/SearchImageContext";
|
import { useSearchImageContext } from "@contexts/SearchImageContext";
|
||||||
import { UserImage } from "@network/index";
|
import { UserImage } from "@network/index";
|
||||||
import { createMemo } from "solid-js";
|
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
|
import { createEffect } from "solid-js";
|
||||||
|
|
||||||
const getSearchTerms = (image: UserImage): Array<string> => {
|
// This language is stupid. `keyof` only returns common keys but this somehow doesnt.
|
||||||
switch (image.type) {
|
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
||||||
case "location":
|
|
||||||
return [
|
const weightedTerms: Record<
|
||||||
image.data.Name,
|
KeysOfUnion<UserImage["data"]>,
|
||||||
image.data.Description,
|
number | undefined
|
||||||
image.data.Address,
|
> = {
|
||||||
image.data.CreatedAt,
|
ID: undefined,
|
||||||
].filter((i) => i != null);
|
LocationID: undefined,
|
||||||
case "event":
|
OrganizerID: undefined,
|
||||||
return [
|
Images: undefined,
|
||||||
image.data.Name,
|
|
||||||
image.data.Description,
|
Name: 5,
|
||||||
image.data.CreatedAt,
|
Description: 2,
|
||||||
].filter((i) => i != null);
|
Address: 2,
|
||||||
case "contact":
|
|
||||||
return [
|
PhoneNumber: 2,
|
||||||
image.data.Name,
|
Email: 2,
|
||||||
image.data.Description,
|
|
||||||
image.data.CreatedAt,
|
CreatedAt: 1,
|
||||||
image.data.Email,
|
StartDateTime: 1,
|
||||||
image.data.PhoneNumber,
|
EndDateTime: 1,
|
||||||
].filter((i) => i != null);
|
|
||||||
case "note":
|
Content: 1,
|
||||||
return [
|
|
||||||
image.data.Name,
|
|
||||||
image.data.Description,
|
|
||||||
image.data.CreatedAt,
|
|
||||||
image.data.Content,
|
|
||||||
].filter((i) => i != null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSearch = () => {
|
export const useSearch = () => {
|
||||||
const { images } = useSearchImageContext();
|
const { images } = useSearchImageContext();
|
||||||
|
|
||||||
const searchTerms = createMemo(() =>
|
return () =>
|
||||||
images().map((i) => ({ image: i, searchTerms: getSearchTerms(i) })),
|
new Fuse(images(), {
|
||||||
);
|
shouldSort: true,
|
||||||
|
keys: Object.entries(weightedTerms)
|
||||||
return () => new Fuse(searchTerms(), { keys: ["searchTerms"] });
|
.filter(([, w]) => w != null)
|
||||||
|
.map(([name, weight]) => ({
|
||||||
|
name: `data.${name}`,
|
||||||
|
weight,
|
||||||
|
})),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user