fix : buzz feedback
This commit is contained in:
@@ -18,42 +18,11 @@ export default async function Image({
|
|||||||
await connection();
|
await connection();
|
||||||
const guide = await getCachedPublicGuide((await params).character);
|
const guide = await getCachedPublicGuide((await params).character);
|
||||||
if (!guide) return new Response("Not found", { status: 404 });
|
if (!guide) return new Response("Not found", { status: 404 });
|
||||||
const recommendedWeapon = guide.weapons[0];
|
|
||||||
const recommendedArtifact = guide.artifactGroups.find(
|
|
||||||
(group) => group.rows.length > 0,
|
|
||||||
)?.rows[0];
|
|
||||||
return generateOgImage({
|
return generateOgImage({
|
||||||
title: guide.name,
|
title: guide.name,
|
||||||
sub: guide.overview,
|
sub: guide.overview,
|
||||||
characterCard: true,
|
characterCard: true,
|
||||||
backgroundUrl: guide.character.nameCardImageUrl,
|
backgroundUrl: guide.character.nameCardImageUrl,
|
||||||
characterUrl: guide.character.splashImageUrl ?? guide.character.imageUrl,
|
characterUrl: guide.character.splashImageUrl ?? guide.character.imageUrl,
|
||||||
recommendedWeapon: recommendedWeapon
|
|
||||||
? {
|
|
||||||
name: recommendedWeapon.weapon.name,
|
|
||||||
refinement: recommendedWeapon.refinement,
|
|
||||||
rarity: recommendedWeapon.weapon.rarity,
|
|
||||||
imageUrl: recommendedWeapon.weapon.imageUrl,
|
|
||||||
overallPercent: recommendedWeapon.overallPercent,
|
|
||||||
personalPercent: recommendedWeapon.personalPercent,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
recommendedArtifact: recommendedArtifact
|
|
||||||
? {
|
|
||||||
first: {
|
|
||||||
name: recommendedArtifact.first.name,
|
|
||||||
rarity: recommendedArtifact.first.rarity,
|
|
||||||
imageUrl: recommendedArtifact.first.imageUrl,
|
|
||||||
},
|
|
||||||
second: recommendedArtifact.second
|
|
||||||
? {
|
|
||||||
name: recommendedArtifact.second.name,
|
|
||||||
rarity: recommendedArtifact.second.rarity,
|
|
||||||
imageUrl: recommendedArtifact.second.imageUrl,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
percent: recommendedArtifact.percent,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,42 +18,11 @@ export default async function Image({
|
|||||||
await connection();
|
await connection();
|
||||||
const guide = await getCachedPublicGuide((await params).character);
|
const guide = await getCachedPublicGuide((await params).character);
|
||||||
if (!guide) return new Response("Not found", { status: 404 });
|
if (!guide) return new Response("Not found", { status: 404 });
|
||||||
const recommendedWeapon = guide.weapons[0];
|
|
||||||
const recommendedArtifact = guide.artifactGroups.find(
|
|
||||||
(group) => group.rows.length > 0,
|
|
||||||
)?.rows[0];
|
|
||||||
return generateOgImage({
|
return generateOgImage({
|
||||||
title: guide.name,
|
title: guide.name,
|
||||||
sub: guide.overview,
|
sub: guide.overview,
|
||||||
characterCard: true,
|
characterCard: true,
|
||||||
backgroundUrl: guide.character.nameCardImageUrl,
|
backgroundUrl: guide.character.nameCardImageUrl,
|
||||||
characterUrl: guide.character.splashImageUrl ?? guide.character.imageUrl,
|
characterUrl: guide.character.splashImageUrl ?? guide.character.imageUrl,
|
||||||
recommendedWeapon: recommendedWeapon
|
|
||||||
? {
|
|
||||||
name: recommendedWeapon.weapon.name,
|
|
||||||
refinement: recommendedWeapon.refinement,
|
|
||||||
rarity: recommendedWeapon.weapon.rarity,
|
|
||||||
imageUrl: recommendedWeapon.weapon.imageUrl,
|
|
||||||
overallPercent: recommendedWeapon.overallPercent,
|
|
||||||
personalPercent: recommendedWeapon.personalPercent,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
recommendedArtifact: recommendedArtifact
|
|
||||||
? {
|
|
||||||
first: {
|
|
||||||
name: recommendedArtifact.first.name,
|
|
||||||
rarity: recommendedArtifact.first.rarity,
|
|
||||||
imageUrl: recommendedArtifact.first.imageUrl,
|
|
||||||
},
|
|
||||||
second: recommendedArtifact.second
|
|
||||||
? {
|
|
||||||
name: recommendedArtifact.second.name,
|
|
||||||
rarity: recommendedArtifact.second.rarity,
|
|
||||||
imageUrl: recommendedArtifact.second.imageUrl,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
percent: recommendedArtifact.percent,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-157
@@ -6,9 +6,6 @@ import { join } from "node:path";
|
|||||||
import { ImageResponse } from "next/og";
|
import { ImageResponse } from "next/og";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
|
|
||||||
import { rarityGradient } from "@/lib/catalog/rarity";
|
|
||||||
import { artifactTierCount } from "@/lib/guides/artifacts";
|
|
||||||
|
|
||||||
export const ogImageSize = { width: 1222, height: 560 } as const;
|
export const ogImageSize = { width: 1222, height: 560 } as const;
|
||||||
export const ogImageContentType = "image/png";
|
export const ogImageContentType = "image/png";
|
||||||
|
|
||||||
@@ -24,12 +21,6 @@ function shorten(value: string, length: number): string {
|
|||||||
: normalized;
|
: normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
function metric(value: string): string {
|
|
||||||
return Number(value) === 0
|
|
||||||
? "-%"
|
|
||||||
: `${Number(value).toLocaleString("en-US", { maximumFractionDigits: 2 })}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBannerData(): Promise<string> {
|
function getBannerData(): Promise<string> {
|
||||||
bannerDataPromise ??= readFile(
|
bannerDataPromise ??= readFile(
|
||||||
join(process.cwd(), "public/web_banner.png"),
|
join(process.cwd(), "public/web_banner.png"),
|
||||||
@@ -71,35 +62,12 @@ export async function generateOgImage({
|
|||||||
characterCard = false,
|
characterCard = false,
|
||||||
backgroundUrl,
|
backgroundUrl,
|
||||||
characterUrl,
|
characterUrl,
|
||||||
recommendedWeapon,
|
|
||||||
recommendedArtifact,
|
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
sub: string;
|
sub: string;
|
||||||
characterCard?: boolean;
|
characterCard?: boolean;
|
||||||
backgroundUrl?: string | null;
|
backgroundUrl?: string | null;
|
||||||
characterUrl?: string | null;
|
characterUrl?: string | null;
|
||||||
recommendedWeapon?: {
|
|
||||||
name: string;
|
|
||||||
refinement: number;
|
|
||||||
rarity: number | null;
|
|
||||||
imageUrl: string;
|
|
||||||
overallPercent: string | null;
|
|
||||||
personalPercent: string | null;
|
|
||||||
} | null;
|
|
||||||
recommendedArtifact?: {
|
|
||||||
first: {
|
|
||||||
name: string;
|
|
||||||
rarity: number | null;
|
|
||||||
imageUrl: string;
|
|
||||||
};
|
|
||||||
second: {
|
|
||||||
name: string;
|
|
||||||
rarity: number | null;
|
|
||||||
imageUrl: string;
|
|
||||||
} | null;
|
|
||||||
percent: string;
|
|
||||||
} | null;
|
|
||||||
}) {
|
}) {
|
||||||
const [
|
const [
|
||||||
bannerSrc,
|
bannerSrc,
|
||||||
@@ -107,22 +75,13 @@ export async function generateOgImage({
|
|||||||
characterFont,
|
characterFont,
|
||||||
characterBackgroundSrc,
|
characterBackgroundSrc,
|
||||||
characterArtSrc,
|
characterArtSrc,
|
||||||
weaponArtSrc,
|
] = await Promise.all([
|
||||||
firstArtifactArtSrc,
|
characterCard ? null : getBannerData(),
|
||||||
secondArtifactArtSrc,
|
getFontData(),
|
||||||
] =
|
characterCard ? getCharacterFontData() : null,
|
||||||
await Promise.all([
|
characterCard && backgroundUrl ? getImageData(backgroundUrl) : null,
|
||||||
characterCard ? null : getBannerData(),
|
characterCard && characterUrl ? getImageData(characterUrl) : null,
|
||||||
getFontData(),
|
]);
|
||||||
characterCard ? getCharacterFontData() : null,
|
|
||||||
characterCard && backgroundUrl ? getImageData(backgroundUrl) : null,
|
|
||||||
characterCard && characterUrl ? getImageData(characterUrl) : null,
|
|
||||||
recommendedWeapon ? getImageData(recommendedWeapon.imageUrl) : null,
|
|
||||||
recommendedArtifact ? getImageData(recommendedArtifact.first.imageUrl) : null,
|
|
||||||
recommendedArtifact?.second
|
|
||||||
? getImageData(recommendedArtifact.second.imageUrl)
|
|
||||||
: null,
|
|
||||||
]);
|
|
||||||
const backgroundSrc = characterCard ? characterBackgroundSrc : bannerSrc;
|
const backgroundSrc = characterCard ? characterBackgroundSrc : bannerSrc;
|
||||||
|
|
||||||
return new ImageResponse(
|
return new ImageResponse(
|
||||||
@@ -172,16 +131,13 @@ export async function generateOgImage({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: characterCard
|
|
||||||
? recommendedWeapon || recommendedArtifact
|
|
||||||
? "36px"
|
|
||||||
: "52px"
|
|
||||||
: "160px",
|
|
||||||
left: "60px",
|
left: "60px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
right: characterCard ? "560px" : "450px",
|
right: characterCard ? "560px" : "450px",
|
||||||
bottom: recommendedWeapon || recommendedArtifact ? "28px" : "100px",
|
...(characterCard
|
||||||
|
? { top: 0, bottom: 0, justifyContent: "center" }
|
||||||
|
: { top: "160px", bottom: "100px" }),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{characterCard ? (
|
{characterCard ? (
|
||||||
@@ -202,109 +158,6 @@ export async function generateOgImage({
|
|||||||
>
|
>
|
||||||
{shorten(sub, 92)}
|
{shorten(sub, 92)}
|
||||||
</div>
|
</div>
|
||||||
{recommendedWeapon ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
width: "500px",
|
|
||||||
height: "72px",
|
|
||||||
marginTop: "14px",
|
|
||||||
overflow: "hidden",
|
|
||||||
borderRadius: "12px",
|
|
||||||
background: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flex: recommendedWeapon.overallPercent || recommendedWeapon.personalPercent ? 3 : 1,
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "10px",
|
|
||||||
overflow: "hidden",
|
|
||||||
borderBottomRightRadius: "48px",
|
|
||||||
background: rarityGradient(recommendedWeapon.rarity),
|
|
||||||
color: "#fff",
|
|
||||||
padding: "2px 28px 2px 6px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{weaponArtSrc ? (
|
|
||||||
<img
|
|
||||||
src={weaponArtSrc}
|
|
||||||
alt=""
|
|
||||||
width={68}
|
|
||||||
height={68}
|
|
||||||
style={{ width: "68px", height: "68px", objectFit: "contain" }}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<div style={{ display: "flex", fontSize: 20 }}>
|
|
||||||
{shorten(recommendedWeapon.name, 19)} R{recommendedWeapon.refinement}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{recommendedWeapon.overallPercent || recommendedWeapon.personalPercent ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flex: 1,
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-around",
|
|
||||||
color: "#17171c",
|
|
||||||
textShadow: "none",
|
|
||||||
padding: "6px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{recommendedWeapon.overallPercent ? (
|
|
||||||
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
||||||
<div style={{ display: "flex", fontSize: 22, fontWeight: 700 }}>{metric(recommendedWeapon.overallPercent)}</div>
|
|
||||||
<div style={{ display: "flex", fontSize: 8 }}>ทั้งทีม</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{recommendedWeapon.personalPercent ? (
|
|
||||||
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
||||||
<div style={{ display: "flex", fontSize: 22, fontWeight: 700 }}>{metric(recommendedWeapon.personalPercent)}</div>
|
|
||||||
<div style={{ display: "flex", fontSize: 8 }}>ส่วนตัว</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{recommendedArtifact ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
width: "500px",
|
|
||||||
height: "72px",
|
|
||||||
marginTop: recommendedWeapon ? "10px" : "14px",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "10px",
|
|
||||||
overflow: "hidden",
|
|
||||||
border: "1px solid #ffffff1f",
|
|
||||||
borderRadius: "12px",
|
|
||||||
background: "#34343d",
|
|
||||||
padding: "2px 8px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{ display: "flex", width: recommendedArtifact.second ? "108px" : "68px" }}>
|
|
||||||
{firstArtifactArtSrc ? (
|
|
||||||
<div style={{ display: "flex", width: "68px", height: "68px", overflow: "hidden", border: "1px solid #ffffff2a", borderRadius: "10px", background: rarityGradient(recommendedArtifact.first.rarity) }}>
|
|
||||||
<img src={firstArtifactArtSrc} alt="" width={68} height={68} style={{ objectFit: "contain" }} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{recommendedArtifact.second && secondArtifactArtSrc ? (
|
|
||||||
<div style={{ display: "flex", width: "68px", height: "68px", overflow: "hidden", marginLeft: "-28px", border: "1px solid #ffffff2a", borderRadius: "10px", background: rarityGradient(recommendedArtifact.second.rarity) }}>
|
|
||||||
<img src={secondArtifactArtSrc} alt="" width={68} height={68} style={{ objectFit: "contain" }} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", flex: 1, fontSize: 18 }}>
|
|
||||||
{artifactTierCount(recommendedArtifact.second?.name ?? null)} {shorten(recommendedArtifact.first.name, recommendedArtifact.second ? 12 : 21)}
|
|
||||||
{recommendedArtifact.second ? ` + ${shorten(recommendedArtifact.second.name, 12)}` : ""}
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "flex", color: "#f0b72f", fontSize: 22 }}>
|
|
||||||
{metric(recommendedArtifact.percent)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user