ionian/packages/client/src/page/galleryPage.tsx
2024-04-06 01:03:56 +09:00

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>
);
}