feat : add image gen
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
export const overviewRoles = ["Main DPS", "Sub DPS", "Support"] as const;
|
||||
|
||||
export type OverviewRole = (typeof overviewRoles)[number];
|
||||
|
||||
export const elementOrder = [
|
||||
"Pyro",
|
||||
"Hydro",
|
||||
"Anemo",
|
||||
"Electro",
|
||||
"Dendro",
|
||||
"Cryo",
|
||||
"Geo",
|
||||
] as const;
|
||||
|
||||
const weaponIconNames: Record<string, string> = {
|
||||
WEAPON_SWORD_ONE_HAND: "sword.png",
|
||||
WEAPON_CLAYMORE: "claymore.png",
|
||||
WEAPON_POLE: "polearm.png",
|
||||
WEAPON_BOW: "bow.png",
|
||||
WEAPON_CATALYST: "catalyst.png",
|
||||
};
|
||||
|
||||
export function normalizeHex(value: string): string | null {
|
||||
const trimmed = value.trim();
|
||||
if (!/^#[\da-f]{6}$/iu.test(trimmed)) return null;
|
||||
return trimmed.toUpperCase();
|
||||
}
|
||||
|
||||
function mixHex(hex: string, target: number, amount: number): string {
|
||||
const normalized = normalizeHex(hex);
|
||||
if (!normalized) return hex;
|
||||
const channels = [1, 3, 5].map((offset) =>
|
||||
Number.parseInt(normalized.slice(offset, offset + 2), 16),
|
||||
);
|
||||
return `#${channels
|
||||
.map((channel) =>
|
||||
Math.round(channel + (target - channel) * amount)
|
||||
.toString(16)
|
||||
.padStart(2, "0"),
|
||||
)
|
||||
.join("")}`.toUpperCase();
|
||||
}
|
||||
|
||||
function mixColors(left: string, right: string): string {
|
||||
const leftHex = normalizeHex(left) ?? "#E9A51A";
|
||||
const rightHex = normalizeHex(right) ?? leftHex;
|
||||
const channels = [1, 3, 5].map((offset) =>
|
||||
Math.round(
|
||||
(Number.parseInt(leftHex.slice(offset, offset + 2), 16) +
|
||||
Number.parseInt(rightHex.slice(offset, offset + 2), 16)) /
|
||||
2,
|
||||
),
|
||||
);
|
||||
return `#${channels.map((channel) => channel.toString(16).padStart(2, "0")).join("")}`.toUpperCase();
|
||||
}
|
||||
|
||||
export function accentGradient(start: string, end = start): string {
|
||||
const normalizedStart = normalizeHex(start) ?? "#E9A51A";
|
||||
const normalizedEnd = normalizeHex(end) ?? normalizedStart;
|
||||
const startEdge = mixHex(normalizedStart, 0, 0.12);
|
||||
const endEdge = mixHex(normalizedEnd, 0, 0.12);
|
||||
const highlight = mixHex(mixColors(normalizedStart, normalizedEnd), 255, 0.35);
|
||||
return `linear-gradient(90deg, ${startEdge} 0%, ${normalizedStart} 25%, ${highlight} 50%, ${normalizedEnd} 75%, ${endEdge} 100%)`;
|
||||
}
|
||||
|
||||
export function weaponTypeIconPath(weaponType: string | null): string | null {
|
||||
const fileName = weaponType ? weaponIconNames[weaponType] : undefined;
|
||||
return fileName ? `/icon/weapon-types/${fileName}` : null;
|
||||
}
|
||||
|
||||
export function overviewFileName(characterKey: string, role: OverviewRole): string {
|
||||
const safeKey = characterKey.replace(/[^\p{L}\p{N}._-]+/gu, "-");
|
||||
const safeRole = role.toLowerCase().replaceAll(" ", "-");
|
||||
return `overview-${safeKey}-${safeRole}.png`;
|
||||
}
|
||||
Reference in New Issue
Block a user