80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import useSWR from "swr";
|
|
import { useSearch } from "wouter";
|
|
import type { Document } from "dbtype/api";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Button } from "@/components/ui/button";
|
|
import { GalleryCard } from "../components/gallery/GalleryCard";
|
|
import TagBadge from "@/components/gallery/TagBadge";
|
|
|
|
async function fetcher(url: string) {
|
|
const res = await fetch(url);
|
|
return res.json();
|
|
}
|
|
|
|
interface SearchParams {
|
|
word?: string;
|
|
tags?: string;
|
|
limit?: number;
|
|
cursor?: number;
|
|
}
|
|
|
|
function useSearchGallery({
|
|
word,
|
|
tags,
|
|
limit,
|
|
cursor,
|
|
}: SearchParams) {
|
|
const search = new URLSearchParams();
|
|
if (word) search.set("word", word);
|
|
if (tags) search.set("allow_tag", tags);
|
|
if (limit) search.set("limit", limit.toString());
|
|
if (cursor) search.set("cursor", cursor.toString());
|
|
return useSWR<
|
|
Document[]
|
|
>(`/api/doc/search?${search.toString()}`, fetcher);
|
|
}
|
|
|
|
export default function Gallery() {
|
|
const search = useSearch();
|
|
const searchParams = new URLSearchParams(search);
|
|
const word = searchParams.get("word") ?? undefined;
|
|
const tags = searchParams.get("allow_tag") ?? undefined;
|
|
const limit = searchParams.get("limit");
|
|
const cursor = searchParams.get("cursor");
|
|
const { data, error, isLoading } = useSearchGallery({
|
|
word, tags,
|
|
limit: limit ? Number.parseInt(limit) : undefined,
|
|
cursor: cursor ? Number.parseInt(cursor) : undefined
|
|
});
|
|
|
|
if (isLoading) {
|
|
return <div className="p-4">Loading...</div>
|
|
}
|
|
if (error) {
|
|
return <div className="p-4">Error: {String(error)}</div>
|
|
}
|
|
|
|
return (<div className="p-4 grid gap-2 overflow-auto h-screen">
|
|
<div className="flex space-x-2">
|
|
<Input className="flex-1"/>
|
|
<Button className="flex-none">Search</Button>
|
|
</div>
|
|
{(word || tags) &&
|
|
<div className="bg-primary rounded-full p-1 sticky top-0 shadow-md">
|
|
{word && <span className="text-primary-foreground ml-4">Search: {word}</span>}
|
|
{tags && <span className="text-primary-foreground ml-4">Tags: <ul className="inline-flex">{tags.split(",").map(x=> <TagBadge tagname={x} key={x}/>)}</ul></span>}
|
|
</div>
|
|
}
|
|
{
|
|
data?.length === 0 && <div className="p-4">No results</div>
|
|
}
|
|
{
|
|
data?.map((x) => {
|
|
return (
|
|
<GalleryCard doc={x} />
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
);
|
|
}
|