diff --git a/components/admin/guide-section-editor.tsx b/components/admin/guide-section-editor.tsx
index 71d9e12..d054a8d 100644
--- a/components/admin/guide-section-editor.tsx
+++ b/components/admin/guide-section-editor.tsx
@@ -37,6 +37,7 @@ import {
extraSectionSchema,
mainStatOptions,
substatOptions,
+ talentLevelOptions,
teamSectionSchema,
weaponSectionSchema,
} from "@/lib/guides/schemas";
@@ -51,7 +52,7 @@ type ArtifactValue = { id: string; name: string; rows: Array<{ firstArtifactKey:
type ArtifactProfile = { sands: string[]; goblet: string[]; circlet: string[]; substats: string[]; targets: Array<{ stat: string; value: string }>; talents: Array<{ type: "NA" | "E" | "Q"; priority: number; level?: string }>; note: string | null } | null;
type ConstellationValue = { level: number; detail: string; cumulativePercent: string };
type CatalogConstellation = { level: number; name: string; description: string; iconUrl: string | null };
-type CatalogTalent = { type: "NA" | "E" | "Q"; name: string; description: string; iconUrl: string | null };
+type CatalogTalent = { type: "NA" | "E" | "Q"; name: string; iconUrl: string | null };
type TeamValue = { title: string; rotationSeconds: string; combo: string; members: Array<{ characterKey: string; weaponKey: string | null; artifactKey: string | null; constellation: number; refinement: number; damage: string }> };
export interface GuideSectionEditorProps {
@@ -103,6 +104,21 @@ function StatSelect({ label, options, value, max, onChange }: { label: string; o
);
}
+function TalentLevelPicker({ value, onChange }: { value?: string; onChange: (value?: string) => void }) {
+ const selected = talentLevelOptions.find((level) => level === value) ?? null;
+ return (
+
{label}
{values.length ? values.map(statLabel).join(" > ") : "—"}
diff --git a/lib/guides/schemas.test.ts b/lib/guides/schemas.test.ts index cbdbd61..c0a7370 100644 --- a/lib/guides/schemas.test.ts +++ b/lib/guides/schemas.test.ts @@ -29,6 +29,12 @@ describe("structured guide validation", () => { expect(artifactSectionSchema.safeParse({ ...base, groups: [...artifactGroups, { name: "Other", rows: [] }] }).success).toBe(false); }); + it("accepts only talent target levels from 1 through 10", () => { + const base = { expectedVersion: 1, groups: artifactGroups, sands: [], goblet: [], circlet: [], substats: [], targets: [], note: null }; + expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "NA", priority: 1, level: "10" }] }).success).toBe(true); + expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "NA", priority: 1, level: "11" }] }).success).toBe(false); + }); + it("requires four unique team members and non-zero damage", () => { const member = (characterKey: string) => ({ characterKey, weaponKey: null, artifactKey: null, constellation: 0, refinement: 1, damage: 100 }); const base = { expectedVersion: 1, teams: [{ title: "Test", rotationSeconds: 20, combo: "E > Q", members: ["1", "2", "3", "4"].map(member) }] }; diff --git a/lib/guides/schemas.ts b/lib/guides/schemas.ts index 96f751a..26b0052 100644 --- a/lib/guides/schemas.ts +++ b/lib/guides/schemas.ts @@ -37,6 +37,7 @@ export const mainStatOptions = { } as const; export const substatOptions = ["CRIT Rate%/CRIT DMG%", "HP%", "ATK%", "DEF%", "EM", "ER"] as const; +export const talentLevelOptions = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] as const; const artifactGroupSchema = (name: "Late Game" | "Early Game") => z.strictObject({ name: z.literal(name), @@ -64,7 +65,7 @@ export const artifactSectionSchema = z.strictObject({ talents: z.array(z.strictObject({ type: z.enum(["NA", "E", "Q"]), priority: z.number().int().min(1).max(3), - level: z.string().trim().max(24).optional(), + level: z.enum(talentLevelOptions).optional(), })).max(3), note: z.string().trim().max(2_000).nullable(), }); diff --git a/public/icon/Icon_Circlet_of_Logos.webp b/public/icon/Icon_Circlet_of_Logos.webp new file mode 100644 index 0000000..3d3ff9e Binary files /dev/null and b/public/icon/Icon_Circlet_of_Logos.webp differ diff --git a/public/icon/Icon_Goblet_of_Eonothem.webp b/public/icon/Icon_Goblet_of_Eonothem.webp new file mode 100644 index 0000000..d6b3636 Binary files /dev/null and b/public/icon/Icon_Goblet_of_Eonothem.webp differ diff --git a/public/icon/Icon_Sands_of_Eon.webp b/public/icon/Icon_Sands_of_Eon.webp new file mode 100644 index 0000000..c738bac Binary files /dev/null and b/public/icon/Icon_Sands_of_Eon.webp differ