fix : show 25 item per page in admin glossary
This commit is contained in:
@@ -15,6 +15,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { FuzzyCombobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList } from "@/components/ui/combobox";
|
||||
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { GlossaryKind } from "@/lib/glossary";
|
||||
@@ -24,6 +25,15 @@ import { cn } from "@/lib/utils";
|
||||
type CatalogItem = { key: string; name: string; imageUrl: string; rarity?: number | null };
|
||||
type Alias = { id: string; kind: string; catalogKey: string; alias: string };
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
function paginationItems(currentPage: number, totalPages: number) {
|
||||
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);
|
||||
if (currentPage <= 4) return [1, 2, 3, 4, 5, "end-ellipsis", totalPages] as const;
|
||||
if (currentPage >= totalPages - 3) return [1, "start-ellipsis", totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages] as const;
|
||||
return [1, "start-ellipsis", currentPage - 1, currentPage, currentPage + 1, "end-ellipsis", totalPages] as const;
|
||||
}
|
||||
|
||||
const kindLabels: Record<GlossaryKind, string> = {
|
||||
character: "Character",
|
||||
weapon: "Weapon",
|
||||
@@ -43,6 +53,7 @@ export function GlossaryManager({
|
||||
const [item, setItem] = useState<CatalogItem | null>(null);
|
||||
const [alias, setAlias] = useState("");
|
||||
const [query, setQuery] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const itemsByKey = useMemo(() => new Map(
|
||||
Object.entries(catalogs).flatMap(([catalogKind, items]) =>
|
||||
items.map((catalogItem) => [`${catalogKind}:${catalogItem.key}`, catalogItem] as const),
|
||||
@@ -52,6 +63,10 @@ export function GlossaryManager({
|
||||
(entry) => `${entry.alias} ${itemsByKey.get(`${entry.kind}:${entry.catalogKey}`)?.name ?? entry.catalogKey}`,
|
||||
(entry) => [entry.alias, itemsByKey.get(`${entry.kind}:${entry.catalogKey}`)?.name ?? ""]);
|
||||
const visibleAliases = search.items;
|
||||
const totalPages = Math.max(1, Math.ceil(visibleAliases.length / PAGE_SIZE));
|
||||
const currentPage = Math.min(page, totalPages);
|
||||
const paginatedAliases = visibleAliases.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);
|
||||
const pages = paginationItems(currentPage, totalPages);
|
||||
|
||||
const submit = () => startTransition(async () => {
|
||||
const result = await addGlossaryAlias({ kind, catalogKey: item?.key, alias });
|
||||
@@ -142,11 +157,14 @@ export function GlossaryManager({
|
||||
<FieldLabel htmlFor="glossary-search">ค้นหา</FieldLabel>
|
||||
<div className="relative">
|
||||
<SearchIcon className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input id="glossary-search" className="pl-9" value={query} onChange={(event) => setQuery(event.target.value)} />
|
||||
<Input id="glossary-search" className="pl-9" value={query} onChange={(event) => {
|
||||
setQuery(event.target.value);
|
||||
setPage(1);
|
||||
}} />
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
{visibleAliases.map((entry) => {
|
||||
{paginatedAliases.map((entry) => {
|
||||
const catalogItem = itemsByKey.get(`${entry.kind}:${entry.catalogKey}`);
|
||||
const name = catalogItem?.name;
|
||||
return (
|
||||
@@ -175,6 +193,64 @@ export function GlossaryManager({
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{totalPages > 1 ? (
|
||||
<Pagination className="pt-2">
|
||||
<PaginationContent className="grid w-full grid-cols-[1fr_auto_1fr]">
|
||||
<PaginationItem className="justify-self-start">
|
||||
<PaginationPrevious
|
||||
href="#"
|
||||
text="ก่อนหน้า"
|
||||
aria-disabled={currentPage === 1}
|
||||
tabIndex={currentPage === 1 ? -1 : undefined}
|
||||
className={cn(currentPage === 1 && "pointer-events-none opacity-50")}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
setPage(currentPage - 1);
|
||||
}}
|
||||
/>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<ul className="flex items-center gap-0.5">
|
||||
{pages.map((pageItem) => (
|
||||
typeof pageItem === "number" ? (
|
||||
<PaginationItem key={pageItem}>
|
||||
<PaginationLink
|
||||
href="#"
|
||||
isActive={pageItem === currentPage}
|
||||
aria-label={`ไปหน้า ${pageItem}`}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
setPage(pageItem);
|
||||
}}
|
||||
>
|
||||
{pageItem}
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
) : (
|
||||
<PaginationItem key={pageItem}>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
)
|
||||
))}
|
||||
</ul>
|
||||
</PaginationItem>
|
||||
<PaginationItem className="justify-self-end">
|
||||
<PaginationNext
|
||||
href="#"
|
||||
text="ถัดไป"
|
||||
aria-disabled={currentPage === totalPages}
|
||||
tabIndex={currentPage === totalPages ? -1 : undefined}
|
||||
className={cn(currentPage === totalPages && "pointer-events-none opacity-50")}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
setPage(currentPage + 1);
|
||||
}}
|
||||
/>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
) : null}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user