feat : add elemental ickn
This commit is contained in:
@@ -8,6 +8,20 @@ const elementBackgroundColors: Record<string, string> = {
|
||||
Geo: "#0F0D00",
|
||||
};
|
||||
|
||||
const elementIconFilters: Record<string, string> = {
|
||||
Anemo: "brightness(0) saturate(100%) invert(76%) sepia(19%) saturate(867%) hue-rotate(113deg) brightness(92%) contrast(86%)",
|
||||
Geo: "brightness(0) saturate(100%) invert(77%) sepia(80%) saturate(1159%) hue-rotate(337deg) brightness(99%) contrast(90%)",
|
||||
Electro: "brightness(0) saturate(100%) invert(66%) sepia(17%) saturate(1525%) hue-rotate(225deg) brightness(91%) contrast(89%)",
|
||||
Dendro: "brightness(0) saturate(100%) invert(70%) sepia(39%) saturate(713%) hue-rotate(32deg) brightness(93%) contrast(87%)",
|
||||
Hydro: "brightness(0) saturate(100%) invert(71%) sepia(68%) saturate(1329%) hue-rotate(164deg) brightness(97%) contrast(95%)",
|
||||
Pyro: "brightness(0) saturate(100%) invert(54%) sepia(72%) saturate(1836%) hue-rotate(339deg) brightness(99%) contrast(89%)",
|
||||
Cryo: "brightness(0) saturate(100%) invert(87%) sepia(20%) saturate(952%) hue-rotate(167deg) brightness(93%) contrast(89%)",
|
||||
};
|
||||
|
||||
export function elementBackgroundColor(element: string | null | undefined): string {
|
||||
return (element && elementBackgroundColors[element]) || "#17383d";
|
||||
}
|
||||
|
||||
export function elementIconFilter(element: string): string | undefined {
|
||||
return elementIconFilters[element];
|
||||
}
|
||||
|
||||
@@ -104,6 +104,21 @@ export async function getPublicGuide(slug: string) {
|
||||
getDb().select().from(teamCompositions).where(eq(teamCompositions.guideId, row.guide.id)).orderBy(asc(teamCompositions.sortOrder)),
|
||||
]);
|
||||
|
||||
const elementIconUrls = Object.fromEntries(
|
||||
(await getDb()
|
||||
.select({
|
||||
element: catalogCharacters.element,
|
||||
elementIconKey: catalogCharacters.elementIconKey,
|
||||
})
|
||||
.from(catalogCharacters)
|
||||
.where(isNotNull(catalogCharacters.elementIconKey)))
|
||||
.flatMap((character) =>
|
||||
character.element && character.elementIconKey
|
||||
? [[character.element, publicMediaUrl(character.elementIconKey)] as const]
|
||||
: [],
|
||||
),
|
||||
);
|
||||
|
||||
const weaponRows = weaponConditionsRows.length ? await getDb().select({ recommendation: weaponRecommendations, weapon: catalogWeapons }).from(weaponRecommendations).innerJoin(catalogWeapons, eq(catalogWeapons.key, weaponRecommendations.weaponKey)).where(inArray(weaponRecommendations.conditionId, weaponConditionsRows.map((condition) => condition.id))).orderBy(asc(weaponRecommendations.sortOrder)) : [];
|
||||
|
||||
const constellations = constellationGroups.length ? await getDb().select().from(constellationRecommendations).where(inArray(constellationRecommendations.conditionId, constellationGroups.map((group) => group.id))).orderBy(asc(constellationRecommendations.level)) : [];
|
||||
@@ -124,6 +139,7 @@ export async function getPublicGuide(slug: string) {
|
||||
...row.guide,
|
||||
coverUrl: publicMediaUrl(row.cover.objectKey),
|
||||
character: catalogCharacterWithUrls(row.character),
|
||||
elementIconUrls,
|
||||
sections,
|
||||
weapons: weaponRows.map(({ recommendation, weapon }) => ({ ...recommendation, weapon: { ...weapon, imageUrl: publicMediaUrl(weapon.imageKey) } })),
|
||||
weaponGroups: weaponConditionsRows.map((condition) => ({ ...condition, rows: weaponRows.filter(({ recommendation }) => recommendation.conditionId === condition.id).map(({ recommendation, weapon }) => ({ ...recommendation, weapon: { ...weapon, imageUrl: publicMediaUrl(weapon.imageKey) } })) })),
|
||||
|
||||
@@ -2,7 +2,11 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { calculateTeamMetrics } from "@/lib/guides/calculations";
|
||||
import { artifactSectionSchema, constellationSectionSchema, createGuideSchema, teamSectionSchema, updateGuideSchema, weaponSectionSchema } from "@/lib/guides/schemas";
|
||||
import { recommendedStatIconName, targetStatIconName } from "@/lib/guides/stats";
|
||||
import {
|
||||
recommendedStatElement,
|
||||
recommendedStatIconName,
|
||||
targetStatIconName,
|
||||
} from "@/lib/guides/stats";
|
||||
|
||||
describe("structured guide validation", () => {
|
||||
const artifactGroups = [
|
||||
@@ -63,6 +67,12 @@ describe("structured guide validation", () => {
|
||||
expect(targetStatIconName("DEF")).toBe(recommendedStatIconName("DEF%"));
|
||||
});
|
||||
|
||||
it("maps elemental damage recommendations to Lunaris element icons", () => {
|
||||
expect(recommendedStatElement("Pyro DMG%")).toBe("Pyro");
|
||||
expect(recommendedStatElement("Hydro DMG%")).toBe("Hydro");
|
||||
expect(recommendedStatElement("Physical DMG%")).toBeNull();
|
||||
});
|
||||
|
||||
it("limits an optional note on each artifact recommendation", () => {
|
||||
const row = { firstArtifactKey: "1", secondArtifactKey: null, percent: 100 };
|
||||
const base = { expectedVersion: 1, sands: [], goblet: [], circlet: [], substats: [], targets: [], talents: [], note: null };
|
||||
|
||||
@@ -51,6 +51,11 @@ export function recommendedStatIconName(value: string): string | null {
|
||||
return ["hp", "atk", "def", "em", "er"].includes(base) ? base : null;
|
||||
}
|
||||
|
||||
export function recommendedStatElement(value: string): string | null {
|
||||
const match = /^(Anemo|Geo|Electro|Dendro|Hydro|Pyro|Cryo) DMG%$/u.exec(value);
|
||||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
export function statPriorityColorClass(index: number): string {
|
||||
return index === 0
|
||||
? "text-tier-gold"
|
||||
|
||||
Reference in New Issue
Block a user