94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { SearchIcon } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import {
|
|
Empty,
|
|
EmptyDescription,
|
|
EmptyHeader,
|
|
EmptyTitle,
|
|
} from "@/components/ui/empty";
|
|
import {
|
|
InputGroup,
|
|
InputGroupAddon,
|
|
InputGroupInput,
|
|
} from "@/components/ui/input-group";
|
|
|
|
type GuideCard = {
|
|
id: string;
|
|
slug: string;
|
|
name: string;
|
|
overview: string;
|
|
coverUrl: string;
|
|
version: number;
|
|
};
|
|
|
|
export function StructuredDirectory({ guides }: { guides: GuideCard[] }) {
|
|
const [query, setQuery] = useState("");
|
|
const normalized = query.trim().toLowerCase();
|
|
const filtered = guides.filter((guide) =>
|
|
`${guide.name} ${guide.overview}`.toLowerCase().includes(normalized),
|
|
);
|
|
return (
|
|
<div className="flex flex-col gap-8">
|
|
<InputGroup className="h-11 max-w-2xl">
|
|
<InputGroupAddon>
|
|
<SearchIcon />
|
|
</InputGroupAddon>
|
|
<InputGroupInput
|
|
value={query}
|
|
onChange={(event) => setQuery(event.target.value)}
|
|
placeholder="ค้นหา Guide…"
|
|
aria-label="ค้นหา Guide"
|
|
/>
|
|
</InputGroup>
|
|
{filtered.length ? (
|
|
<div className="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
|
{filtered.map((guide) => (
|
|
<Link
|
|
key={guide.id}
|
|
href={`/${guide.slug}`}
|
|
className="group rounded-xl outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
>
|
|
<Card className="h-full overflow-hidden py-0 transition-transform group-hover:-translate-y-0.5">
|
|
<div className="relative aspect-square bg-muted">
|
|
<Image
|
|
src={guide.coverUrl}
|
|
alt={`Guide ${guide.name}`}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<CardHeader className="pt-5">
|
|
<CardTitle>{guide.name}</CardTitle>
|
|
<CardDescription className="line-clamp-3">
|
|
{guide.overview}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
</Card>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<Empty className="border">
|
|
<EmptyHeader>
|
|
<EmptyTitle>ไม่พบ Guide</EmptyTitle>
|
|
<EmptyDescription>ลองค้นหาด้วยชื่อตัวละครอื่น</EmptyDescription>
|
|
</EmptyHeader>
|
|
</Empty>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|