feat: complete character list
im too sleepless to document the commits
This commit is contained in:
+23
-1
@@ -2,9 +2,10 @@ import { readdirSync } from "node:fs";
|
||||
import { mkdir, readdir, rm } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { file, hash, write } from "bun";
|
||||
import { TTLCache } from "enka.ts";
|
||||
import { ResolvedPlayerInfo, TTLCache } from "enka.ts";
|
||||
import {
|
||||
AvatarStore,
|
||||
ElementList,
|
||||
EnkaLocs,
|
||||
EnkaNamecards,
|
||||
EnkaPfps,
|
||||
@@ -199,3 +200,24 @@ export async function getEnkaStore<K extends keyof StoreTypeMap>(
|
||||
cache.set(`store.${key}`, data, 86400); // 24 hours
|
||||
return data;
|
||||
}
|
||||
|
||||
export function getAvatar(
|
||||
store: AvatarStore,
|
||||
playerInfo: ResolvedPlayerInfo,
|
||||
id: number,
|
||||
) {
|
||||
return (
|
||||
Object.entries(store).find(
|
||||
([avatarId, avatar]) =>
|
||||
avatarId.split("-")[0] === `${id}` &&
|
||||
avatar.Element ===
|
||||
ElementList[
|
||||
(
|
||||
playerInfo.showAvatarInfoList.find(
|
||||
(e) => e.avatar.avatarId === id,
|
||||
) as { energyType: number } | undefined
|
||||
)?.energyType ?? 0
|
||||
],
|
||||
)?.[1] || store[id]
|
||||
);
|
||||
}
|
||||
|
||||
+9
-16
@@ -22,13 +22,13 @@ import { star } from "@/assets/stars";
|
||||
import { TalentSvg } from "@/assets/talent";
|
||||
import { WeaponGlazeSvg } from "@/assets/weapon-glaze";
|
||||
import type { App } from "@/index";
|
||||
import { assets, batchStore } from "@/lib/assets";
|
||||
import { assets, batchStore, getAvatar } from "@/lib/assets";
|
||||
import { Deduplicator } from "@/lib/dedupe";
|
||||
import { cardErrorLocs } from "@/lib/locs";
|
||||
import { createLogger } from "@/lib/logger";
|
||||
import { mockData } from "@/lib/mock";
|
||||
import { buildDisplayRows } from "@/lib/rows";
|
||||
import { ElementList, Locale, SubstatOrder } from "@/type/enka";
|
||||
import { Locale, SubstatOrder } from "@/type/enka";
|
||||
import { PercentageFightProp } from "@/type/fightPropMap";
|
||||
import { ErrorPage } from "./error";
|
||||
import { ListPage } from "./list";
|
||||
@@ -106,7 +106,7 @@ export function card(app: App) {
|
||||
)
|
||||
.get(
|
||||
"/genshin/:uid",
|
||||
async ({ params: { uid }, query: { debug }, log }) => {
|
||||
async ({ params: { uid }, query: { debug, lang }, log }) => {
|
||||
// #region Character List
|
||||
const [[avatarStore, locs, pfps, namecards], data] =
|
||||
await Promise.all([
|
||||
@@ -132,6 +132,7 @@ export function card(app: App) {
|
||||
namecards[`${data.playerInfo.nameCardId ?? 210001}`].Icon,
|
||||
namecards,
|
||||
avatarStore,
|
||||
locs[lang ?? "en"],
|
||||
log,
|
||||
);
|
||||
},
|
||||
@@ -210,19 +211,11 @@ export function card(app: App) {
|
||||
);
|
||||
if (!char) return error(400, errorLoc.notInShowcase);
|
||||
|
||||
const avatar =
|
||||
Object.entries(avatarStore).find(
|
||||
([avatarId, avatar]) =>
|
||||
avatarId.split("-")[0] === `${char.avatar.avatarId}` &&
|
||||
avatar.Element ===
|
||||
ElementList[
|
||||
(
|
||||
data.playerInfo.showAvatarInfoList.find(
|
||||
(e) => e.avatar.avatarId === char.avatar.avatarId,
|
||||
) as { energyType: number } | undefined
|
||||
)?.energyType ?? 0
|
||||
],
|
||||
)?.[1] || avatarStore[char.avatar.avatarId];
|
||||
const avatar = getAvatar(
|
||||
avatarStore,
|
||||
data.playerInfo,
|
||||
char.avatar.avatarId,
|
||||
);
|
||||
if (!avatar) return error(400, errorLoc.unsupported);
|
||||
|
||||
if (!char.equipList)
|
||||
|
||||
+34
-20
@@ -1,8 +1,8 @@
|
||||
import { ResolvedRoot } from "enka.ts";
|
||||
import { assets } from "@/lib/assets";
|
||||
import { assets, getAvatar } from "@/lib/assets";
|
||||
import { Logger } from "@/lib/logger";
|
||||
import { CharacterNamecardMap } from "@/lib/namecards";
|
||||
import { AvatarStore, EnkaNamecards } from "@/type/enka";
|
||||
import { AvatarStore, EnkaLocsLanguage, EnkaNamecards } from "@/type/enka";
|
||||
import { CardResponse } from "./response";
|
||||
|
||||
export async function ListPage(
|
||||
@@ -11,6 +11,7 @@ export async function ListPage(
|
||||
namecard: string,
|
||||
namecards: EnkaNamecards,
|
||||
avatars: AvatarStore,
|
||||
locs: EnkaLocsLanguage,
|
||||
log: Logger,
|
||||
) {
|
||||
return CardResponse(
|
||||
@@ -66,8 +67,8 @@ export async function ListPage(
|
||||
<div tw="flex items-center font-[ShinShin]">
|
||||
{p.finishAchievementNum}
|
||||
</div>
|
||||
<div tw="text-[.9em] flex items-center justify-end opacity-50 pb-2">
|
||||
Achievements
|
||||
<div tw="text-[.75em] flex items-center justify-end opacity-50 pb-2 whitespace-nowrap text-ellipsis">
|
||||
{locs.achievements}
|
||||
</div>
|
||||
{p.towerFloorIndex && (
|
||||
<>
|
||||
@@ -76,8 +77,8 @@ export async function ListPage(
|
||||
{p.towerFloorIndex}-{p.towerLevelIndex}
|
||||
{p.towerStarIndex ? ` | ${p.towerStarIndex}★` : ""}
|
||||
</div>
|
||||
<div tw="text-[.9em] flex items-center justify-end opacity-50 pb-2">
|
||||
Spiral Abyss
|
||||
<div tw="text-[.75em] flex items-center justify-end opacity-50 pb-2 whitespace-nowrap text-ellipsis">
|
||||
{locs.abyss}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -89,8 +90,8 @@ export async function ListPage(
|
||||
alt="theater"
|
||||
/>
|
||||
<div tw="flex items-center font-[ShinShin]">{`${p.theaterActIndex} | ${p.theaterStarIndex}`}</div>
|
||||
<div tw="text-[.9em] flex items-center justify-end opacity-50 pb-2">
|
||||
Theater
|
||||
<div tw="text-[.75em] flex items-center justify-end opacity-50 pb-2 whitespace-nowrap text-ellipsis">
|
||||
{locs.theater}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -104,8 +105,8 @@ export async function ListPage(
|
||||
<div tw="flex items-center font-[ShinShin]">
|
||||
{p.stygianSeconds}s
|
||||
</div>
|
||||
<div tw="text-[.9em] flex items-center justify-end opacity-50 pb-2">
|
||||
Stygian Onslaught
|
||||
<div tw="text-[.75em] flex items-center justify-end opacity-50 pb-2 whitespace-nowrap text-ellipsis">
|
||||
{locs.stygian}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -113,14 +114,14 @@ export async function ListPage(
|
||||
</div>
|
||||
</div>
|
||||
{/* character list (for some reason ________ absolute hates me) */}
|
||||
<div tw="absolute top-0 right-0 w-[62.5%] h-[117%]">
|
||||
<div tw="flex relative flex-wrap gap-x-[1.25%] gap-y-[0.75%] p-[.5em] w-full">
|
||||
<div tw="absolute top-0 right-0 w-[62.5%] h-[97vh]">
|
||||
<div tw="flex relative flex-wrap gap-x-[1.25%] gap-y-[0.75%] p-[.5em] w-full h-full">
|
||||
{p.showAvatarInfoList.map((a) => (
|
||||
<div tw="w-[49.625%] bg-black/50 relative overflow-hidden rounded-lg flex">
|
||||
<div tw="w-[49.625%] h-[16.04166667%] bg-black/50 relative overflow-hidden rounded-lg flex">
|
||||
<img
|
||||
src={`/namecard/${a.avatar.avatarId}`}
|
||||
alt="namecard"
|
||||
tw="absolute top-0 left-0 right-0 bottom-0 object-cover brightness-50"
|
||||
tw="absolute top-0 left-0 right-0 bottom-0 object-cover blur-[2px] brightness-50"
|
||||
/>
|
||||
<img
|
||||
src={`/pfp/${a.avatar.avatarId}`}
|
||||
@@ -132,9 +133,23 @@ export async function ListPage(
|
||||
alt="pfp"
|
||||
tw="absolute top-0 left-0 bottom-0 aspect-square"
|
||||
/>
|
||||
<div tw="ml-[20%] p-[.25em] font-[ShinShin] flex flex-col">
|
||||
<div>{a.avatar.name}</div>
|
||||
<div>Lv. {a.level}</div>
|
||||
<div tw="ml-[22.5%] flex">
|
||||
<hr tw="border-none h-[90%] w-px mt-[5%] bg-white/60" />
|
||||
<div tw="p-[.25em] font-[ShinShin] flex flex-col grow">
|
||||
<div>{a.avatar.name}</div>
|
||||
<div>
|
||||
{locs.level} {a.level}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div tw="absolute bottom-[.2em] right-[.2em] leading-none p-[.2em] rounded-md bg-black/50">
|
||||
{uid
|
||||
.slice(-7)
|
||||
.split("")
|
||||
.map((c, i) => (
|
||||
<div style={{ opacity: i / 5 }}>{c}</div>
|
||||
))}
|
||||
/{a.avatar.avatarId}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -155,6 +170,7 @@ export async function ListPage(
|
||||
},
|
||||
...(p.showAvatarInfoList
|
||||
.flatMap((a) => {
|
||||
const avatar = getAvatar(avatars, p, a.avatar.avatarId);
|
||||
const card =
|
||||
namecards[`${CharacterNamecardMap[`${a.avatar.avatarId}`]}`];
|
||||
return [
|
||||
@@ -166,9 +182,7 @@ export async function ListPage(
|
||||
: null,
|
||||
{
|
||||
src: `/pfp/${a.avatar.avatarId}`,
|
||||
data: assets.load(
|
||||
avatars[a.avatar.avatarId].SideIconName.replace("_Side", ""),
|
||||
),
|
||||
data: assets.load(avatar.SideIconName.replace("_Side", "")),
|
||||
},
|
||||
];
|
||||
})
|
||||
|
||||
+1
-2
@@ -24,8 +24,7 @@ export async function CardResponse(
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<div tw="grow" />
|
||||
<div tw="ml-[.5em] flex items-center">
|
||||
<div tw="absolute bottom-0 left-0 ml-[.5em] flex items-center">
|
||||
<div tw="text-[2em] font-[shicon] pb-[.1em] -mr-[.3em] text-white/25">
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user