94 lines
2.3 KiB
TypeScript
94 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
|
|
import {
|
|
ComboboxContent,
|
|
ComboboxEmpty,
|
|
ComboboxInput,
|
|
ComboboxItem,
|
|
ComboboxList,
|
|
FuzzyCombobox,
|
|
} from "@/components/ui/combobox";
|
|
import { rarityGradientClass } from "@/lib/catalog/rarity";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export interface ImageCatalogItem {
|
|
key: string;
|
|
name: string;
|
|
aliases: string[];
|
|
imageUrl: string;
|
|
rarity: number | null;
|
|
}
|
|
|
|
export interface ImageCatalogCharacter extends ImageCatalogItem {
|
|
element: string | null;
|
|
weaponType: string | null;
|
|
splashImageUrl: string | null;
|
|
}
|
|
|
|
export interface ImageCatalogWeapon extends ImageCatalogItem {
|
|
weaponType: string | null;
|
|
}
|
|
|
|
export type ImageCatalogArtifact = ImageCatalogItem;
|
|
|
|
export function ImageCatalogPicker<Item extends ImageCatalogItem>({
|
|
items,
|
|
value,
|
|
onChange,
|
|
placeholder,
|
|
invalid = false,
|
|
}: {
|
|
items: Item[];
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
placeholder: string;
|
|
invalid?: boolean;
|
|
}) {
|
|
const selected = items.find((item) => item.key === value) ?? null;
|
|
|
|
return (
|
|
<FuzzyCombobox
|
|
items={items}
|
|
value={selected}
|
|
onValueChange={(item) => onChange(item?.key ?? "")}
|
|
itemToStringLabel={(item) => item.name}
|
|
itemToStringValue={(item) => item.key}
|
|
searchNames={(item) => [item.name, ...item.aliases]}
|
|
autoHighlight
|
|
>
|
|
<ComboboxInput
|
|
className="w-full"
|
|
placeholder={placeholder}
|
|
showClear
|
|
aria-invalid={invalid}
|
|
/>
|
|
<ComboboxContent className="min-w-72">
|
|
<ComboboxEmpty>ไม่พบรายการ</ComboboxEmpty>
|
|
<ComboboxList>
|
|
{(item) => (
|
|
<ComboboxItem key={item.key} value={item}>
|
|
<span
|
|
className={cn(
|
|
"relative size-8 shrink-0 overflow-hidden rounded-md",
|
|
rarityGradientClass(item.rarity),
|
|
)}
|
|
>
|
|
<Image
|
|
src={item.imageUrl}
|
|
alt=""
|
|
fill
|
|
sizes="32px"
|
|
className="object-contain"
|
|
/>
|
|
</span>
|
|
<span>{item.name}</span>
|
|
</ComboboxItem>
|
|
)}
|
|
</ComboboxList>
|
|
</ComboboxContent>
|
|
</FuzzyCombobox>
|
|
);
|
|
}
|