feat: update
CI / Verify (push) Successful in 55s
CI / Build immutable images and deploy (push) Successful in 1m13s

This commit is contained in:
2026-09-01 16:31:05 +07:00 Unverified
parent 8fa651684f
commit 1d19961d8b
11 changed files with 113 additions and 91 deletions
+11 -11
View File
@@ -3,19 +3,19 @@ import { describe, expect, it } from "vitest";
import { elementBackgroundColor } from "@/lib/catalog/element";
describe("catalog element backgrounds", () => {
it("maps every character element to its 40% opacity color", () => {
expect(elementBackgroundColor("Pyro")).toBe("#12000066");
expect(elementBackgroundColor("Hydro")).toBe("#00051266");
expect(elementBackgroundColor("Anemo")).toBe("#06141566");
expect(elementBackgroundColor("Electro")).toBe("#0D000F66");
expect(elementBackgroundColor("Dendro")).toBe("#000F0466");
expect(elementBackgroundColor("Cryo")).toBe("#03202166");
expect(elementBackgroundColor("Geo")).toBe("#0F0D0066");
it("maps every character element to its opaque background color", () => {
expect(elementBackgroundColor("Pyro")).toBe("#120000");
expect(elementBackgroundColor("Hydro")).toBe("#000512");
expect(elementBackgroundColor("Anemo")).toBe("#061415");
expect(elementBackgroundColor("Electro")).toBe("#0D000F");
expect(elementBackgroundColor("Dendro")).toBe("#000F04");
expect(elementBackgroundColor("Cryo")).toBe("#032021");
expect(elementBackgroundColor("Geo")).toBe("#0F0D00");
});
it("uses the neutral character background when the element is unavailable", () => {
expect(elementBackgroundColor(null)).toBe("#17383d66");
expect(elementBackgroundColor(undefined)).toBe("#17383d66");
expect(elementBackgroundColor("Unknown")).toBe("#17383d66");
expect(elementBackgroundColor(null)).toBe("#17383d");
expect(elementBackgroundColor(undefined)).toBe("#17383d");
expect(elementBackgroundColor("Unknown")).toBe("#17383d");
});
});
+8 -8
View File
@@ -1,13 +1,13 @@
const elementBackgroundColors: Record<string, string> = {
Pyro: "#12000066",
Hydro: "#00051266",
Anemo: "#06141566",
Electro: "#0D000F66",
Dendro: "#000F0466",
Cryo: "#03202166",
Geo: "#0F0D0066",
Pyro: "#120000",
Hydro: "#000512",
Anemo: "#061415",
Electro: "#0D000F",
Dendro: "#000F04",
Cryo: "#032021",
Geo: "#0F0D00",
};
export function elementBackgroundColor(element: string | null | undefined): string {
return (element && elementBackgroundColors[element]) || "#17383d66";
return (element && elementBackgroundColors[element]) || "#17383d";
}
+5 -3
View File
@@ -31,9 +31,10 @@ describe("structured guide validation", () => {
expect(constellationSectionSchema.safeParse({ expectedVersion: 1, note: "x".repeat(2_001), rows: [] }).success).toBe(false);
});
it("limits artifact main stats to two per slot", () => {
const result = artifactSectionSchema.safeParse({ expectedVersion: 1, groups: artifactGroups, sands: ["EM", "ER", "ATK%"], goblet: [], circlet: [], substats: [], targets: [], talents: [], note: null });
expect(result.success).toBe(false);
it("limits artifact main stats to three per slot", () => {
const base = { expectedVersion: 1, groups: artifactGroups, goblet: [], circlet: [], substats: [], targets: [], talents: [], note: null };
expect(artifactSectionSchema.safeParse({ ...base, sands: ["EM", "ER", "ATK%"] }).success).toBe(true);
expect(artifactSectionSchema.safeParse({ ...base, sands: ["EM", "ER", "ATK%", "HP%"] }).success).toBe(false);
});
it("accepts flat artifact substats with the same icons as their percentage variants", () => {
@@ -80,6 +81,7 @@ describe("structured guide validation", () => {
it("accepts talent comparison relations while keeping legacy talents valid", () => {
const base = { expectedVersion: 1, groups: artifactGroups, sands: [], goblet: [], circlet: [], substats: [], targets: [], note: null };
expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "E", priority: 1, relationToNext: "gte" }] }).success).toBe(true);
expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "E", priority: 1, relationToNext: "eq" }] }).success).toBe(true);
expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "E", priority: 1 }] }).success).toBe(true);
expect(artifactSectionSchema.safeParse({ ...base, talents: [{ type: "E", priority: 1, relationToNext: "equal" }] }).success).toBe(false);
});
+4 -4
View File
@@ -42,7 +42,7 @@ export const mainStatOptions = {
export const substatOptions = ["CRIT Rate%/CRIT DMG%", "HP%", "HP", "ATK%", "ATK", "DEF%", "DEF", "EM", "ER"] as const;
export const talentLevelOptions = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] as const;
export const talentRelationOptions = ["gt", "gte"] as const;
export const talentRelationOptions = ["gt", "gte", "eq"] as const;
const artifactGroupSchema = (name: "Late Game" | "Early Game") => z.strictObject({
name: z.literal(name),
@@ -60,9 +60,9 @@ export const artifactSectionSchema = z.strictObject({
artifactGroupSchema("Late Game"),
artifactGroupSchema("Early Game"),
]),
sands: z.array(z.enum(mainStatOptions.sands)).max(2),
goblet: z.array(z.enum(mainStatOptions.goblet)).max(2),
circlet: z.array(z.enum(mainStatOptions.circlet)).max(2),
sands: z.array(z.enum(mainStatOptions.sands)).max(3),
goblet: z.array(z.enum(mainStatOptions.goblet)).max(3),
circlet: z.array(z.enum(mainStatOptions.circlet)).max(3),
substats: z.array(z.enum(substatOptions)).max(substatOptions.length),
targets: z.array(z.strictObject({
stat: z.enum(targetStatOptions),
+2 -1
View File
@@ -27,9 +27,10 @@ describe("talent priorities", () => {
]);
});
it("formats strict and greater-than-or-equal relations", () => {
it("formats every supported talent relation", () => {
expect(talentRelationSymbol("gt")).toBe(">");
expect(talentRelationSymbol("gte")).toBe("≥");
expect(talentRelationSymbol("eq")).toBe("=");
expect(talentRelationSymbol()).toBe(">");
});
+3 -3
View File
@@ -1,4 +1,4 @@
export type TalentRelation = "gt" | "gte";
export type TalentRelation = "gt" | "gte" | "eq";
export interface TalentPriority {
type: "NA" | "E" | "Q";
@@ -38,8 +38,8 @@ export function reorderTalentPriorities(
}));
}
export function talentRelationSymbol(relation?: TalentRelation): ">" | "≥" {
return relation === "gte" ? "≥" : ">";
export function talentRelationSymbol(relation?: TalentRelation): ">" | "≥" | "=" {
return relation === "gte" ? "≥" : relation === "eq" ? "=" : ">";
}
export function talentTypeLabel(type: TalentPriority["type"]): string {