fix(extra) : add drag sorting and correct character links

This commit is contained in:
2026-09-05 14:26:11 +07:00 Unverified
parent 65d675e52f
commit c19cbe6537
2 changed files with 61 additions and 34 deletions
+59 -33
View File
@@ -4,8 +4,6 @@ import dynamic from "next/dynamic";
import Image from "next/image"; import Image from "next/image";
import { import {
ChartNoAxesCombinedIcon, ChartNoAxesCombinedIcon,
ChevronDownIcon,
ChevronUpIcon,
ClipboardCopyIcon, ClipboardCopyIcon,
ClipboardPasteIcon, ClipboardPasteIcon,
CopyIcon, CopyIcon,
@@ -3370,48 +3368,76 @@ function ExtraCatalogItemsEditor({
artifacts: CatalogItem[]; artifacts: CatalogItem[];
onChange: (value: ExtraCatalogItem[]) => void; onChange: (value: ExtraCatalogItem[]) => void;
}) { }) {
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
const [kind, setKind] = useState<ExtraCatalogItem["kind"]>("character"); const [kind, setKind] = useState<ExtraCatalogItem["kind"]>("character");
const [key, setKey] = useState(""); const [key, setKey] = useState("");
const catalogs = { character: characters, weapon: weapons, artifact: artifacts }; const catalogs = { character: characters, weapon: weapons, artifact: artifacts };
const labels = { character: "ตัวละคร", weapon: "อาวุธ", artifact: "อาร์ติแฟกต์" }; const labels = { character: "ตัวละคร", weapon: "อาวุธ", artifact: "อาร์ติแฟกต์" };
const items = catalogs[kind]; const items = catalogs[kind];
const itemId = (item: ExtraCatalogItem) => `${item.kind}:${item.key}`;
const handleDragEnd = ({ active, over }: DragEndEvent) => {
if (!over || active.id === over.id) return;
const from = value.findIndex((item) => itemId(item) === active.id);
const to = value.findIndex((item) => itemId(item) === over.id);
if (from !== -1 && to !== -1) onChange(arrayMove(value, from, to));
};
return ( return (
<Field> <Field>
<FieldLabel>ตัวละคร อาวุธ และอาร์ติแฟกต์</FieldLabel> <FieldLabel>ตัวละคร อาวุธ และอาร์ติแฟกต์</FieldLabel>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
{value.length ? ( {value.length ? (
<div className="flex flex-col gap-2"> <DndContext
{value.map((reference, index) => { sensors={sensors}
const item = catalogs[reference.kind].find( collisionDetection={closestCenter}
(candidate) => candidate.key === reference.key, onDragEnd={handleDragEnd}
); >
return ( <SortableContext
<Card key={`${reference.kind}:${reference.key}`} size="sm"> items={value.map(itemId)}
<CardContent className="flex items-center gap-3"> strategy={verticalListSortingStrategy}
{item ? ( >
<div className={cn("relative size-12 shrink-0 overflow-hidden rounded-md", rarityGradientClass(item.rarity))}> <div className="flex flex-col gap-2">
<Image src={item.imageUrl} alt="" fill className="object-contain" /> {value.map((reference, index) => {
</div> const item = catalogs[reference.kind].find(
) : null} (candidate) => candidate.key === reference.key,
<div className="min-w-0 flex-1"> );
<p className="truncate font-medium">{item?.name ?? reference.key}</p> const label = item?.name ?? reference.key;
<p className="text-sm text-muted-foreground">{labels[reference.kind]}</p> return (
</div> <SortableExtraItem
<Button type="button" variant="ghost" size="icon-sm" disabled={index === 0} onClick={() => onChange(arrayMove(value, index, index - 1))} aria-label="เลื่อนขึ้น"> key={itemId(reference)}
<ChevronUpIcon /> id={itemId(reference)}
</Button> label={`ลากเพื่อจัดลำดับ ${label}`}
<Button type="button" variant="ghost" size="icon-sm" disabled={index === value.length - 1} onClick={() => onChange(arrayMove(value, index, index + 1))} aria-label="เลื่อนลง"> >
<ChevronDownIcon /> {(dragHandle) => (
</Button> <Card size="sm">
<Button type="button" variant="ghost" size="icon-sm" onClick={() => onChange(value.filter((_, itemIndex) => itemIndex !== index))} aria-label={`ลบ ${item?.name ?? reference.key}`}> <CardContent className="flex items-center gap-3">
<XIcon /> {item ? (
</Button> <div className={cn("relative size-12 shrink-0 overflow-hidden rounded-md", rarityGradientClass(item.rarity))}>
</CardContent> <Image src={item.imageUrl} alt="" fill className="object-contain" />
</Card> </div>
); ) : null}
})} <div className="min-w-0 flex-1">
</div> <p className="truncate font-medium">{label}</p>
<p className="text-sm text-muted-foreground">{labels[reference.kind]}</p>
</div>
{dragHandle}
<Button type="button" variant="ghost" size="icon-sm" onClick={() => onChange(value.filter((_, itemIndex) => itemIndex !== index))} aria-label={`ลบ ${label}`}>
<XIcon />
</Button>
</CardContent>
</Card>
)}
</SortableExtraItem>
);
})}
</div>
</SortableContext>
</DndContext>
) : null} ) : null}
<div className="flex flex-wrap items-center gap-2"> <div className="flex flex-wrap items-center gap-2">
<Select value={kind} onValueChange={(next) => { setKind(next as ExtraCatalogItem["kind"]); setKey(""); }}> <Select value={kind} onValueChange={(next) => { setKind(next as ExtraCatalogItem["kind"]); setKey(""); }}>
+2 -1
View File
@@ -318,7 +318,8 @@ function lunarisItemUrl(
kind: "character" | "weapon" | "artifact", kind: "character" | "weapon" | "artifact",
key: string, key: string,
): string { ): string {
return `https://lunaris.moe/${kind}/${encodeURIComponent(key)}`; const path = kind === "character" ? "char" : kind;
return `https://lunaris.moe/${path}/${encodeURIComponent(key)}`;
} }
function WeaponSection({ guide }: { guide: PublicGuide }) { function WeaponSection({ guide }: { guide: PublicGuide }) {