diff --git a/app/admin/[character]/[page]/page.tsx b/app/admin/[character]/[page]/page.tsx index b7d0553..579f24e 100644 --- a/app/admin/[character]/[page]/page.tsx +++ b/app/admin/[character]/[page]/page.tsx @@ -109,11 +109,16 @@ export default async function StructuredEditorPage({ artifactGroups: content.artifactGroups.map((group) => ({ id: group.id, name: group.name, - rows: group.rows.map((row) => ({ - firstArtifactKey: row.firstArtifactKey, - secondArtifactKey: row.secondArtifactKey, - percent: row.percent, - note: row.note, + note: group.note, + tiers: group.tiers.map((tier) => ({ + id: tier.id, + name: tier.name, + rows: tier.rows.map((row) => ({ + firstArtifactKey: row.firstArtifactKey, + secondArtifactKey: row.secondArtifactKey, + percent: row.percent, + note: row.note, + })), })), })), artifactProfile: content.artifactProfile, diff --git a/components/admin/guide-section-editor.tsx b/components/admin/guide-section-editor.tsx index a5a4fe8..f931414 100644 --- a/components/admin/guide-section-editor.tsx +++ b/components/admin/guide-section-editor.tsx @@ -237,7 +237,7 @@ type WeaponGroupValue = { note: string | null; rows: WeaponValue[]; }; -type ArtifactValue = { +type ArtifactTierValue = { id: string; name: string; rows: Array<{ @@ -247,6 +247,12 @@ type ArtifactValue = { note: string | null; }>; }; +type ArtifactValue = { + id: string; + name: string | null; + note: string | null; + tiers: ArtifactTierValue[]; +}; type ArtifactProfile = { sands: string[]; goblet: string[]; @@ -1773,16 +1779,27 @@ function ArtifactEditor({ coordinateGetter: sortableKeyboardCoordinates, }), ); - const [groups, setGroups] = useState(() => - (["Late Game", "Early Game"] as const).map((name, index) => ({ - name, - rows: - initial.artifactGroups[index]?.rows.map((row, rowIndex) => ({ - ...row, - clientId: `${name}-${rowIndex}`, - })) ?? [], - })), - ); + const [groups, setGroups] = useState(() => { + const source = initial.artifactGroups.length ? initial.artifactGroups : [{ id: "artifact-condition-default", name: null, note: null, tiers: [] }]; + return source.map((condition, conditionIndex) => ({ + clientId: condition.id, + name: condition.name ?? "", + note: condition.note ?? "", + tiers: (["Late Game", "Early Game"] as const).map((name, tierIndex) => ({ + name, + rows: condition.tiers[tierIndex]?.rows.map((row, rowIndex) => ({ ...row, clientId: `${conditionIndex}-${name}-${rowIndex}` })) ?? [], + })), + })); + }); + const [activeArtifactGroupIndex, setActiveArtifactGroupIndex] = useState(0); + const [renamingArtifactGroupIndex, setRenamingArtifactGroupIndex] = useState(null); + const artifactTiers = groups[activeArtifactGroupIndex]?.tiers ?? []; + const setArtifactTierRows = ( + tierIndex: number, + update: (rows: (typeof artifactTiers)[number]["rows"]) => (typeof artifactTiers)[number]["rows"], + ) => setGroups((current) => current.map((condition, conditionIndex) => conditionIndex === activeArtifactGroupIndex + ? { ...condition, tiers: condition.tiers.map((tier, index) => index === tierIndex ? { ...tier, rows: update(tier.rows) } : tier) } + : condition)); const [recommendedGroups, setRecommendedGroups] = useState(() => { const source = profile?.recommendedConditions.length ? profile.recommendedConditions @@ -1839,12 +1856,16 @@ function ArtifactEditor({ const [note, setNote] = useState(profile?.note ?? ""); const value = { groups: groups.map((group) => ({ - name: group.name, - rows: group.rows.map((row) => ({ - firstArtifactKey: row.firstArtifactKey, - secondArtifactKey: row.secondArtifactKey, - percent: Number(row.percent), - note: row.note?.trim() || null, + name: group.name.trim() || null, + note: group.note.trim() || null, + tiers: group.tiers.map((tier) => ({ + name: tier.name, + rows: tier.rows.map((row) => ({ + firstArtifactKey: row.firstArtifactKey, + secondArtifactKey: row.secondArtifactKey, + percent: Number(row.percent), + note: row.note?.trim() || null, + })), })), })), sands: recommendedGroups[0].sands, @@ -1868,6 +1889,7 @@ function ArtifactEditor({ !validation.success && hasIssuePrefix(validation.error.issues, ...path); const localDraft = { groups, + activeArtifactGroupIndex, sands, goblet, circlet, @@ -1905,6 +1927,7 @@ function ArtifactEditor({ ), restoreLocalDraft: (draft) => { setGroups(draft.groups); + setActiveArtifactGroupIndex(draft.activeArtifactGroupIndex ?? 0); setRecommendedGroups(draft.recommendedGroups?.length ? draft.recommendedGroups : [{ clientId: createClientId("recommended-condition"), name: "", note: "", sands: draft.sands, goblet: draft.goblet, circlet: draft.circlet, substats: draft.substats }]); setActiveRecommendedGroupIndex(Math.min(draft.activeRecommendedGroupIndex ?? 0, Math.max(0, (draft.recommendedGroups?.length ?? 1) - 1))); setTargetGroups(draft.targetGroups.map((group) => ({ ...group, name: group.name ?? "" }))); @@ -1916,21 +1939,22 @@ function ArtifactEditor({ const orderedTalents = normalizeTalentPriorities(talents); const handleArtifactDragEnd = ({ active, over }: DragEndEvent) => { if (!over || active.id === over.id) return; - const activeGroupIndex = groups.findIndex((group) => + const activeTierIndex = artifactTiers.findIndex((group) => group.rows.some((row) => row.clientId === active.id), ); - const overGroupIndex = groups.findIndex((group) => + const overTierIndex = artifactTiers.findIndex((group) => group.rows.some((row) => row.clientId === over.id), ); - if (activeGroupIndex === -1 || activeGroupIndex !== overGroupIndex) return; + if (activeTierIndex === -1 || activeTierIndex !== overTierIndex) return; setGroups((current) => - current.map((group, groupIndex) => { - if (groupIndex !== activeGroupIndex) return group; - const from = group.rows.findIndex((row) => row.clientId === active.id); - const to = group.rows.findIndex((row) => row.clientId === over.id); - return from === -1 || to === -1 - ? group - : { ...group, rows: arrayMove(group.rows, from, to) }; + current.map((condition, conditionIndex) => { + if (conditionIndex !== activeArtifactGroupIndex) return condition; + return { ...condition, tiers: condition.tiers.map((group, groupIndex) => { + if (groupIndex !== activeTierIndex) return group; + const from = group.rows.findIndex((row) => row.clientId === active.id); + const to = group.rows.findIndex((row) => row.clientId === over.id); + return from === -1 || to === -1 ? group : { ...group, rows: arrayMove(group.rows, from, to) }; + }) }; }), ); }; @@ -1966,7 +1990,45 @@ function ArtifactEditor({ - {groups.map((group, groupIndex) => ( + { + const reordered = reorderConditions(groups, activeArtifactGroupIndex, from, to); + setGroups(reordered.items); + setActiveArtifactGroupIndex(reordered.activeIndex); + }} + onAdd={() => { + setGroups([...groups, { clientId: createClientId("artifact-condition"), name: "", note: "", tiers: [{ name: "Late Game", rows: [] }, { name: "Early Game", rows: [] }] }]); + setActiveArtifactGroupIndex(groups.length); + }} + onDuplicate={() => { + const source = groups[activeArtifactGroupIndex]; + if (!source) return; + setGroups([...groups, { ...source, clientId: createClientId("artifact-condition"), tiers: source.tiers.map((tier) => ({ ...tier, rows: tier.rows.map((row) => ({ ...row, clientId: createClientId("artifact") })) })) }]); + setActiveArtifactGroupIndex(groups.length); + }} + onDelete={() => { + const next = groups.filter((_, index) => index !== activeArtifactGroupIndex); + setGroups(next); + setActiveArtifactGroupIndex(Math.min(activeArtifactGroupIndex, next.length - 1)); + }} + /> + { if (!open) setRenamingArtifactGroupIndex(null); }} + onChange={(name) => setGroups(groups.map((group, index) => index === renamingArtifactGroupIndex ? { ...group, name } : group))} + /> + + Condition note (optional) +