/* eslint-disable @next/next/no-img-element */ import { ImageResponse } from "next/og"; import sharp from "sharp"; import { rarityGradient } from "@/lib/catalog/rarity"; import { imageContentDisposition } from "@/lib/guides/export-image"; import { getPublicArtifactExport } from "@/lib/guides/queries"; import { normalizeTalentPriorities } from "@/lib/guides/talents"; const anuphanFonts = Promise.all( [ { subset: "latin", weight: 400 as const }, { subset: "thai", weight: 400 as const }, { subset: "latin", weight: 700 as const }, { subset: "thai", weight: 700 as const }, ].map(async ({ subset, weight }) => { const response = await fetch( `https://unpkg.com/@fontsource/anuphan@5.3.0/files/anuphan-${subset}-${weight}-normal.woff`, ); if (!response.ok) throw new Error(`Unable to load Anuphan ${subset} ${weight}`); return { name: "Anuphan", data: await response.arrayBuffer(), weight, style: "normal" as const, }; }), ).catch(() => []); function metric(value: string): string { return `${Number(value).toLocaleString("en-US", { maximumFractionDigits: 2 })}%`; } function statLabel(value: string): string { return value === "EM" ? "Elemental Mastery" : value === "ER" ? "Energy Recharge" : value; } async function pngDataUrl(url: string): Promise { try { const response = await fetch(url); if (!response.ok) return null; const png = await sharp(Buffer.from(await response.arrayBuffer())) .resize(96, 96, { fit: "contain" }) .png() .toBuffer(); return `data:image/png;base64,${png.toString("base64")}`; } catch { return null; } } export async function GET( _request: Request, context: RouteContext<"/api/guides/[guideId]/artifacts/image">, ) { const { guideId } = await context.params; const guide = await getPublicArtifactExport(guideId); if (!guide) return new Response("Guide not found", { status: 404 }); const [fonts, groupAssets] = await Promise.all([ anuphanFonts, Promise.all( guide.groups.map((group) => Promise.all( group.rows.map(async (row) => ({ first: await pngDataUrl(row.first.imageUrl), second: row.second ? await pngDataUrl(row.second.imageUrl) : null, })), ), ), ), ]); const profile = guide.profile; const leftHeight = guide.groups.reduce((sum, group) => sum + 68 + group.rows.length * 76, 0) + Math.max(0, guide.groups.length - 1) * 16; const detailHeight = profile ? 60 + profile.targets.length * 30 + (profile.talents.length ? 58 : 0) + (profile.note ? Math.max(48, Math.ceil(profile.note.length / 58) * 24) : 0) : 0; const rightHeight = profile ? 194 + (profile.substats.length ? 76 : 0) + (detailHeight > 60 ? detailHeight + 16 : 0) + 32 : 0; const height = Math.max(520, 190 + Math.max(leftHeight, rightHeight)); const talents = normalizeTalentPriorities(profile?.talents ?? []); return new ImageResponse(
อาร์ติแฟกต์และสเตตัสที่แนะนำ
Artifacts & Stats
{guide.groups.map((group, groupIndex) => (
{group.name}
{group.rows.map((row, rowIndex) => (
{groupAssets[groupIndex][rowIndex].first ? (
) : null} {row.second && groupAssets[groupIndex][rowIndex].second ? (
) : null}
{rowIndex + 1}. {row.first.name}{row.second ? ` + ${row.second.name}` : ""}
{metric(row.percent)}
))}
))}
{profile ? (
Artifact Stats
{[ { label: "Sands", values: profile.sands }, { label: "Goblet", values: profile.goblet }, { label: "Circlet", values: profile.circlet }, ].map((stat) => (
{stat.label}
{stat.values.length ? stat.values.map(statLabel).join(" > ") : "—"}
))}
{profile.substats.length ? (
Stat Priority: {profile.substats.map(statLabel).join(" > ")}
) : null} {detailHeight > 60 ? (
รายละเอียดเพิ่มเติม
{profile.targets.length ? (
Target Stats
{profile.targets.map((target) => (
{target.stat}{target.value}
))}
) : null} {talents.length ? (
ลำดับการอัพพรสวรรค์
{talents.map((talent, index) => (
{talent.type}{talent.level ? ` Lv.${talent.level}+` : ""} {index < talents.length - 1 ? {talent.relationToNext === "gte" ? ">=" : ">"} : null}
))}
) : null} {profile.note ? (
โน็ต
{profile.note}
) : null}
) : null}
) : null}
, { width: 1200, height, fonts: fonts.length ? fonts : undefined, headers: { "Cache-Control": "no-store", "Content-Disposition": imageContentDisposition(`${guide.guideName} Artifacts`, "artifacts"), "Content-Type": "image/png", }, }, ); }