"use client"; import Image from "@/components/ui/resilient-image"; import { CircleHelpIcon } from "lucide-react"; import type { ReactNode } from "react"; import { TeamArtifactIcon } from "@/components/public/team-search"; import { ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger, FuzzyCombobox, } from "@/components/ui/combobox"; import { characterRarityGradientClass, rarityGradientClass } from "@/lib/catalog/rarity"; import { cn } from "@/lib/utils"; export interface AdminCatalogItem { key: string; name: string; aliases?: string[]; imageUrl: string; rarity?: number | null; } export interface AdminCatalogCharacter extends AdminCatalogItem { aliases: string[]; rarity: number | null; element: string | null; elementIconUrl?: string | null; weaponType: string | null; splashImageUrl: string | null; } export interface AdminCatalogWeapon extends AdminCatalogItem { aliases: string[]; rarity: number | null; weaponType: string | null; } export interface AdminCatalogArtifact extends AdminCatalogItem { aliases: string[]; rarity: number | null; } type CommonSelectProps = { items: Item[]; placeholder: string; emptyLabel?: string; invalid?: boolean; rarityBackground?: boolean; characterBackground?: boolean; searchNames?: (item: Item) => string[]; }; type CatalogDropdownProps = CommonSelectProps & { value: string; onValueChange: (value: string) => void; showSelectedImage?: boolean; showClear?: boolean; label?: string; }; export function CatalogDropdown({ items, value, onValueChange, placeholder, emptyLabel = "ไม่พบรายการ", invalid = false, rarityBackground = false, characterBackground = false, showSelectedImage = false, showClear = true, label, searchNames = (item) => [item.name, ...(item.aliases ?? [])], }: CatalogDropdownProps) { const selected = items.find((item) => item.key === value) ?? null; return (
{showSelectedImage && selected ? (
) : null}
onValueChange(next?.key ?? "")} itemToStringLabel={(item) => item.name} itemToStringValue={(item) => item.key} searchNames={searchNames} autoHighlight > {emptyLabel} {(item) => ( {item.name} )}
); } type CatalogSlotSelectProps = CommonSelectProps & { value: string; onValueChange: (value: string) => void; label: string; className?: string; placeholderIcon?: ReactNode; }; function CatalogSlotSelect({ items, value, onValueChange, label, placeholder, emptyLabel = "ไม่พบรายการ", invalid = false, rarityBackground = true, characterBackground = false, searchNames = (item) => [item.name, ...(item.aliases ?? [])], className, placeholderIcon, }: CatalogSlotSelectProps) { const selected = items.find((item) => item.key === value) ?? null; return ( onValueChange(next?.key ?? "")} itemToStringLabel={(item) => item.name} itemToStringValue={(item) => item.key} searchNames={searchNames} autoHighlight > svg]:hidden", rarityBackground && selected && (characterBackground ? characterRarityGradientClass(selected.key, selected.rarity) : rarityGradientClass(selected.rarity)), className, )} > {selected ? ( ) : ( {placeholderIcon ?? )} {emptyLabel} {(item) => ( {item.name} )} ); } type DomainSelectProps = CommonSelectProps & { value: string; onValueChange: (value: string) => void; presentation?: "dropdown" | "slot"; label?: string; className?: string; showSelectedImage?: boolean; showClear?: boolean; placeholderIcon?: ReactNode; }; function DomainCatalogSelect({ presentation = "dropdown", label, className, showSelectedImage, placeholderIcon, rarityBackground = true, ...props }: DomainSelectProps) { if (presentation === "slot") { return ( ); } return ; } export function CharacterSelect(props: DomainSelectProps) { return ; } export function WeaponSelect(props: DomainSelectProps) { return ; } type SingleArtifactSelectProps = DomainSelectProps & { multiple?: false; }; type MultipleArtifactSelectProps = Omit< CommonSelectProps, "rarityBackground" > & { multiple: true; values: string[]; onValuesChange: (values: string[]) => void; label: string; max?: number; className?: string; }; export function ArtifactSelect( props: SingleArtifactSelectProps | MultipleArtifactSelectProps, ) { if (!props.multiple) return ; const { items, values, onValuesChange, label, placeholder, emptyLabel = "ไม่พบชุด Artifact", invalid = false, max = 2, searchNames = (item) => [item.name, ...(item.aliases ?? [])], className, } = props; const selected = values.flatMap((value) => { const item = items.find((candidate) => candidate.key === value); return item ? [item] : []; }); const iconValue = (item: Item | undefined) => item ? { key: item.key, name: item.name, imageUrl: item.imageUrl, rarity: item.rarity ?? null } : null; return ( onValuesChange(next.slice(0, max).map((item) => item.key))} itemToStringLabel={(item) => item.name} itemToStringValue={(item) => item.key} isItemEqualToValue={(item, value) => item.key === value.key} searchNames={searchNames} autoHighlight > item.name).join(", ")}` : label} aria-invalid={invalid} className={cn( "relative aspect-square w-full overflow-hidden rounded-md border bg-muted outline-none focus-visible:ring-2 focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 [&>svg]:hidden", className, )} > {selected.length ? ( ) : ( {emptyLabel} {(item) => ( = max && !selected.some((candidate) => candidate.key === item.key)} > {item.name} )} ); } function CatalogOptionImage({ item, rarityBackground, characterBackground = false, }: { item: AdminCatalogItem; rarityBackground: boolean; characterBackground?: boolean; }) { return (
); }