feat(extra) : add catalog items and image export
This commit is contained in:
@@ -4,6 +4,8 @@ import dynamic from "next/dynamic";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
ChartNoAxesCombinedIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon,
|
||||
ClipboardCopyIcon,
|
||||
ClipboardPasteIcon,
|
||||
CopyIcon,
|
||||
@@ -175,6 +177,10 @@ type CatalogItem = {
|
||||
element?: string | null;
|
||||
elementIconUrl?: string | null;
|
||||
};
|
||||
type ExtraCatalogItem = {
|
||||
kind: "character" | "weapon" | "artifact";
|
||||
key: string;
|
||||
};
|
||||
const teamMemberApplyOptions = [
|
||||
["characterKey", "Character"],
|
||||
["weaponKey", "Weapon"],
|
||||
@@ -323,6 +329,7 @@ export interface GuideSectionEditorProps {
|
||||
body: string;
|
||||
percent: string | null;
|
||||
backgroundColor: string | null;
|
||||
catalogItems: ExtraCatalogItem[];
|
||||
highlights: Array<{ text: string; color: string }>;
|
||||
imageUrl: string | null;
|
||||
imageWidth: number | null;
|
||||
@@ -3304,7 +3311,85 @@ function TeamEditor({
|
||||
);
|
||||
}
|
||||
|
||||
function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
function ExtraCatalogItemsEditor({
|
||||
value,
|
||||
characters,
|
||||
weapons,
|
||||
artifacts,
|
||||
onChange,
|
||||
}: {
|
||||
value: ExtraCatalogItem[];
|
||||
characters: CatalogItem[];
|
||||
weapons: CatalogItem[];
|
||||
artifacts: CatalogItem[];
|
||||
onChange: (value: ExtraCatalogItem[]) => void;
|
||||
}) {
|
||||
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];
|
||||
|
||||
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>
|
||||
) : null}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Select value={kind} onValueChange={(next) => { setKind(next as ExtraCatalogItem["kind"]); setKey(""); }}>
|
||||
<SelectTrigger className="w-40"><SelectValue /></SelectTrigger>
|
||||
<SelectContent><SelectGroup>
|
||||
<SelectItem value="character">ตัวละคร</SelectItem>
|
||||
<SelectItem value="weapon">อาวุธ</SelectItem>
|
||||
<SelectItem value="artifact">อาร์ติแฟกต์</SelectItem>
|
||||
</SelectGroup></SelectContent>
|
||||
</Select>
|
||||
<div className="min-w-64 flex-1">
|
||||
<CatalogPicker items={items} value={key} onChange={setKey} placeholder={`เลือก${labels[kind]}`} showSelectedImage rarityBackground />
|
||||
</div>
|
||||
<Button type="button" variant="outline" disabled={!key || value.some((item) => item.kind === kind && item.key === key)} onClick={() => { onChange([...value, { kind, key }]); setKey(""); }}>
|
||||
<PlusIcon data-icon="inline-start" />
|
||||
เพิ่มรายการ
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
|
||||
function ExtraEditor({ guide, initial, characters, weapons, artifacts }: EditorBase) {
|
||||
const extraSensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor, {
|
||||
@@ -3338,6 +3423,7 @@ function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
? null
|
||||
: Number(row.percent),
|
||||
backgroundColor: row.backgroundColor,
|
||||
catalogItems: row.catalogItems,
|
||||
highlights: [],
|
||||
})),
|
||||
})),
|
||||
@@ -3369,6 +3455,7 @@ function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
id: row.id || createClientId("extra-row-record"),
|
||||
body: normalizeExtraRichText(row.body, row.highlights ?? []),
|
||||
backgroundColor: row.backgroundColor ?? null,
|
||||
catalogItems: row.catalogItems ?? [],
|
||||
highlights: [],
|
||||
clientId: row.clientId || createClientId("extra-row"),
|
||||
})),
|
||||
@@ -3621,6 +3708,28 @@ function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
)
|
||||
}
|
||||
/>
|
||||
<ExtraCatalogItemsEditor
|
||||
value={row.catalogItems}
|
||||
characters={characters}
|
||||
weapons={weapons}
|
||||
artifacts={artifacts}
|
||||
onChange={(catalogItems) =>
|
||||
setSections(
|
||||
sections.map((item, index) =>
|
||||
index === sectionIndex
|
||||
? {
|
||||
...item,
|
||||
rows: item.rows.map((candidate, inner) =>
|
||||
inner === rowIndex
|
||||
? { ...candidate, catalogItems }
|
||||
: candidate,
|
||||
),
|
||||
}
|
||||
: item,
|
||||
),
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Field>
|
||||
<FieldLabel>หัวข้อ</FieldLabel>
|
||||
<Input
|
||||
@@ -3657,6 +3766,7 @@ function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
<FieldLabel>ข้อความ</FieldLabel>
|
||||
<RichTextEditor
|
||||
value={row.body}
|
||||
showBubbleMenu={false}
|
||||
invalid={extraIssue(
|
||||
"sections",
|
||||
sectionIndex,
|
||||
@@ -3837,6 +3947,7 @@ function ExtraEditor({ guide, initial }: EditorBase) {
|
||||
body: "",
|
||||
percent: null,
|
||||
backgroundColor: null,
|
||||
catalogItems: [],
|
||||
highlights: [],
|
||||
clientId: createClientId("extra-row"),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user