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 {
ChartNoAxesCombinedIcon,
ChevronDownIcon,
ChevronUpIcon,
ClipboardCopyIcon,
ClipboardPasteIcon,
CopyIcon,
@@ -3370,48 +3368,76 @@ function ExtraCatalogItemsEditor({
artifacts: CatalogItem[];
onChange: (value: ExtraCatalogItem[]) => void;
}) {
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
}),
);
const [kind, setKind] = useState<ExtraCatalogItem["kind"]>("character");
const [key, setKey] = useState("");
const catalogs = { character: characters, weapon: weapons, artifact: artifacts };
const labels = { character: "ตัวละคร", weapon: "อาวุธ", artifact: "อาร์ติแฟกต์" };
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 (
<Field>
<FieldLabel>ตัวละคร อาวุธ และอาร์ติแฟกต์</FieldLabel>
<div className="flex flex-col gap-3">
{value.length ? (
<div className="flex flex-col gap-2">
{value.map((reference, index) => {
const item = catalogs[reference.kind].find(
(candidate) => candidate.key === reference.key,
);
return (
<Card key={`${reference.kind}:${reference.key}`} size="sm">
<CardContent className="flex items-center gap-3">
{item ? (
<div className={cn("relative size-12 shrink-0 overflow-hidden rounded-md", rarityGradientClass(item.rarity))}>
<Image src={item.imageUrl} alt="" fill className="object-contain" />
</div>
) : null}
<div className="min-w-0 flex-1">
<p className="truncate font-medium">{item?.name ?? reference.key}</p>
<p className="text-sm text-muted-foreground">{labels[reference.kind]}</p>
</div>
<Button type="button" variant="ghost" size="icon-sm" disabled={index === 0} onClick={() => onChange(arrayMove(value, index, index - 1))} aria-label="เลื่อนขึ้น">
<ChevronUpIcon />
</Button>
<Button type="button" variant="ghost" size="icon-sm" disabled={index === value.length - 1} onClick={() => onChange(arrayMove(value, index, index + 1))} aria-label="เลื่อนลง">
<ChevronDownIcon />
</Button>
<Button type="button" variant="ghost" size="icon-sm" onClick={() => onChange(value.filter((_, itemIndex) => itemIndex !== index))} aria-label={`ลบ ${item?.name ?? reference.key}`}>
<XIcon />
</Button>
</CardContent>
</Card>
);
})}
</div>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContext
items={value.map(itemId)}
strategy={verticalListSortingStrategy}
>
<div className="flex flex-col gap-2">
{value.map((reference, index) => {
const item = catalogs[reference.kind].find(
(candidate) => candidate.key === reference.key,
);
const label = item?.name ?? reference.key;
return (
<SortableExtraItem
key={itemId(reference)}
id={itemId(reference)}
label={`ลากเพื่อจัดลำดับ ${label}`}
>
{(dragHandle) => (
<Card size="sm">
<CardContent className="flex items-center gap-3">
{item ? (
<div className={cn("relative size-12 shrink-0 overflow-hidden rounded-md", rarityGradientClass(item.rarity))}>
<Image src={item.imageUrl} alt="" fill className="object-contain" />
</div>
) : null}
<div className="min-w-0 flex-1">
<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}
<div className="flex flex-wrap items-center gap-2">
<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",
key: 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 }) {