Files
buzz/app/(ui)/guide/client.tsx
T
dmgnr a31c8fbb54
Build and Push Image / build-backend (push) Successful in 52s
Build and Push Image / build-frontend (push) Successful in 2m8s
Build and Push Image / push (push) Successful in 1m24s
chore: oxc
2026-06-10 01:44:11 +07:00

101 lines
3.4 KiB
TypeScript

"use client";
import { Compass, Search, SearchX } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { useDebounce } from "react-use";
import Image from "@/components/image";
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group";
import { Spinner } from "@/components/ui/spinner";
import type { guides } from "@/lib/db/schema";
import { cn } from "@/lib/utils";
import { searchGuide } from "./api";
export function GuideList({
initialList,
}: {
initialList: (typeof guides.$inferSelect)[];
}) {
const [list, setList] = useState(initialList);
const [loading, setLoading] = useState(2);
const [search, setSearch] = useState("");
useDebounce(
() => {
if (loading === 2) return setLoading(0);
setLoading(1);
searchGuide(search)
.then(setList)
.finally(() => setLoading(0));
},
200,
[search],
);
return (
<div className="flex h-svh justify-center">
<div className="flex w-full flex-col border xl:max-w-2/3">
<div>
<Link
href="/"
className="flex items-center gap-2 border-b p-3 leading-none font-semibold"
>
<Compass className="opacity-50" />
ไกด์ตัวละคร
</Link>
</div>
<div className="p-4 pb-2">
<InputGroup className="h-10 w-full">
<InputGroupInput
placeholder="ค้นหา..."
onChange={(ev) => setSearch(ev.target.value)}
/>
<InputGroupAddon>
{loading === 1 ? <Spinner /> : <Search />}
</InputGroupAddon>
</InputGroup>
</div>
<div
className={cn(
"grid grid-cols-[repeat(auto-fill,minmax(min(300px,calc(100svw-2rem-2px)),1fr))] gap-4 overflow-auto p-4 transition-opacity",
loading === 1 && "opacity-50",
)}
>
{list.length === 0 && loading === 0 ? (
<div className="col-span-full flex flex-col items-center justify-center py-20 text-muted-foreground">
<SearchX className="mb-4 h-16 w-16 opacity-50" />
<p className="text-2xl font-semibold">ไม่พบตัวละครที่ค้นหา</p>
<p className="text-lg ">ลองคำอื่นที่ความหมายใกล้เคียงกันดูนะ</p>
</div>
) : (
list.map((card) => (
<Link href={card.link} key={card.id} target="_blank">
<Card className="rounded-sm bg-card/50 py-3 backdrop-blur-sm transition-colors hover:bg-border sm:rounded-xl sm:py-6">
<CardHeader className="px-3 sm:px-6">
<CardTitle>{card.name}</CardTitle>
<div className="relative mt-2 aspect-square w-full overflow-hidden rounded-sm border sm:rounded-lg">
{card.image && (
<Image
src={`/cdn/${card.image}`}
alt={card.name}
fill
className="object-cover"
/>
)}
</div>
</CardHeader>
</Card>
</Link>
))
)}
</div>
</div>
</div>
);
}