-
Notifications
You must be signed in to change notification settings - Fork 427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enricobarbieri1997/og images dynamic generation #3995
base: stage
Are you sure you want to change the base?
Changes from all commits
8881097
7219845
5438642
c883d32
027be31
babf29c
f9201f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,118 @@ | ||||||
import { getAsset, getAssetPrice } from "@osmosis-labs/server"; | ||||||
import { ImageResponse } from "next/og"; | ||||||
|
||||||
import { AssetLists } from "~/config/generated/asset-lists"; | ||||||
import { loadGoogleFont } from "~/utils/og-images"; | ||||||
import { getBaseUrl } from "~/utils/url"; | ||||||
|
||||||
// App router includes @vercel/og. | ||||||
// No need to install it. | ||||||
|
||||||
// We're using the edge-runtime | ||||||
export const config = { | ||||||
runtime: "edge", | ||||||
}; | ||||||
|
||||||
const imageHeight = 240; | ||||||
const imageAspectRatio = 1.97; | ||||||
const textOsmoverse300 = "text-[#B0AADC]"; | ||||||
const baseUrl = getBaseUrl(); | ||||||
|
||||||
export default async function GET(request: Request) { | ||||||
const { searchParams } = new URL(request.url); | ||||||
const tokenDenom = searchParams.get("denom"); | ||||||
if (!tokenDenom) { | ||||||
return new Response("Denom is required", { status: 400 }); | ||||||
} | ||||||
const tokenDetails = getAsset({ | ||||||
assetLists: AssetLists, | ||||||
anyDenom: tokenDenom, | ||||||
}); | ||||||
let tokenPrice = undefined; | ||||||
if (tokenDetails.coinGeckoId) { | ||||||
try { | ||||||
tokenPrice = await getAssetPrice({ | ||||||
chainList: [], | ||||||
assetLists: AssetLists, | ||||||
asset: { | ||||||
coinDenom: tokenDetails.coinMinimalDenom, | ||||||
coinGeckoId: tokenDetails.coinGeckoId, | ||||||
}, | ||||||
currency: "usd", | ||||||
}); | ||||||
} catch (error) { | ||||||
console.error("Failed to get asset price", error); | ||||||
} | ||||||
} | ||||||
const token = tokenDetails; | ||||||
const title = token.coinName; | ||||||
const formattedTokenPrice = tokenPrice ? tokenPrice.toString(2) : ""; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect number formatting in 'formattedTokenPrice'. The method Apply this diff to fix the issue: -const formattedTokenPrice = tokenPrice ? tokenPrice.toString(2) : "";
+const formattedTokenPrice = tokenPrice ? tokenPrice.toFixed(2) : ""; 📝 Committable suggestion
Suggested change
|
||||||
return new ImageResponse( | ||||||
( | ||||||
<div | ||||||
style={{ | ||||||
fontFamily: "Inter", | ||||||
}} | ||||||
Comment on lines
+54
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistent The Either change the Apply this diff to set the style={{
- fontFamily: "Inter",
+ fontFamily: "Geist",
}} Alternatively, change the fonts: [
{
- name: "Geist",
+ name: "Inter",
data: await loadGoogleFont(
"Inter",
token.coinDenom.toString() + title + formattedTokenPrice
),
style: "normal",
},
],
|
||||||
tw="flex h-screen w-screen px-6 py-8 bg-[#090524]" | ||||||
> | ||||||
<div tw="flex w-2/5 mr-7"> | ||||||
{token.coinImageUrl ? ( | ||||||
<img | ||||||
src={`${baseUrl}${token.coinImageUrl}`} | ||||||
alt={token.coinName} | ||||||
tw="h-auto" | ||||||
/> | ||||||
) : null} | ||||||
</div> | ||||||
<div tw="flex flex-col justify-center w-3/5"> | ||||||
<div tw="flex flex-col mb-2"> | ||||||
<h6 | ||||||
style={{ | ||||||
fontSize: "70px", | ||||||
lineHeight: "60px", | ||||||
}} | ||||||
tw={`m-0 mb-1 text-white`} | ||||||
> | ||||||
{token.coinDenom} | ||||||
</h6> | ||||||
{title ? ( | ||||||
<h6 | ||||||
style={{ | ||||||
fontSize: "24px", | ||||||
}} | ||||||
tw={`${textOsmoverse300} m-0 ml-3`} | ||||||
> | ||||||
{title} | ||||||
</h6> | ||||||
) : null} | ||||||
</div> | ||||||
{tokenPrice ? ( | ||||||
<h6 | ||||||
style={{ | ||||||
fontSize: "54px", | ||||||
lineHeight: "30px", | ||||||
}} | ||||||
tw={`m-0 ml-2 text-white`} | ||||||
> | ||||||
${formattedTokenPrice} | ||||||
</h6> | ||||||
) : null} | ||||||
</div> | ||||||
</div> | ||||||
), | ||||||
{ | ||||||
width: imageHeight * imageAspectRatio, | ||||||
height: imageHeight, | ||||||
fonts: [ | ||||||
{ | ||||||
name: "Geist", | ||||||
data: await loadGoogleFont( | ||||||
"Inter", | ||||||
token.coinDenom.toString() + title + formattedTokenPrice | ||||||
), | ||||||
style: "normal", | ||||||
}, | ||||||
], | ||||||
} | ||||||
); | ||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -46,6 +46,7 @@ import { AssetInfoViewProvider } from "~/hooks/use-asset-info-view"; | |||||||||||||
import { PreviousTrade, SwapPreviousTradeKey } from "~/pages"; | ||||||||||||||
import { SUPPORTED_LANGUAGES } from "~/stores/user-settings"; | ||||||||||||||
import { trpcHelpers } from "~/utils/helpers"; | ||||||||||||||
import { getBaseUrl } from "~/utils/url"; | ||||||||||||||
|
||||||||||||||
type AssetInfoPageStaticProps = InferGetStaticPropsType<typeof getStaticProps>; | ||||||||||||||
|
||||||||||||||
|
@@ -79,6 +80,10 @@ const AssetInfoView: FunctionComponent<AssetInfoPageStaticProps> = observer( | |||||||||||||
|
||||||||||||||
const { title, details, coinGeckoId, asset: asset } = useAssetInfo(); | ||||||||||||||
|
||||||||||||||
const pageTitle = `${ | ||||||||||||||
title ? `${title} (${asset.coinDenom})` : asset.coinDenom | ||||||||||||||
} | Osmosis`; | ||||||||||||||
|
||||||||||||||
if (!asset) { | ||||||||||||||
return null; | ||||||||||||||
} | ||||||||||||||
|
@@ -166,10 +171,20 @@ const AssetInfoView: FunctionComponent<AssetInfoPageStaticProps> = observer( | |||||||||||||
strategy="afterInteractive" | ||||||||||||||
/> | ||||||||||||||
<NextSeo | ||||||||||||||
title={`${ | ||||||||||||||
title ? `${title} (${asset.coinDenom})` : asset.coinDenom | ||||||||||||||
} | Osmosis`} | ||||||||||||||
title={pageTitle} | ||||||||||||||
description={details?.description} | ||||||||||||||
openGraph={{ | ||||||||||||||
title: pageTitle, | ||||||||||||||
description: details?.description?.substring(0, 120) + "...", | ||||||||||||||
images: [ | ||||||||||||||
Comment on lines
+178
to
+179
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent 'undefined' in Open Graph description when When Modify the code to handle Apply this diff to fix the issue: openGraph={{
title: pageTitle,
- description: details?.description?.substring(0, 120) + "...",
+ description: details?.description
+ ? details.description.substring(0, 120) + "..."
+ : undefined,
images: [ 📝 Committable suggestion
Suggested change
|
||||||||||||||
{ | ||||||||||||||
url: `${getBaseUrl(true)}/api/og-images/assets/${ | ||||||||||||||
asset.coinDenom | ||||||||||||||
}`, | ||||||||||||||
Comment on lines
+181
to
+183
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure To handle special characters in Apply this diff to encode {
url: `${getBaseUrl(true)}/api/og-images/assets/${
- asset.coinDenom
+ encodeURIComponent(asset.coinDenom)
}`,
alt: title,
}, 📝 Committable suggestion
Suggested change
|
||||||||||||||
alt: title, | ||||||||||||||
}, | ||||||||||||||
], | ||||||||||||||
}} | ||||||||||||||
/> | ||||||||||||||
<main className="mx-auto flex max-w-7xl flex-col gap-8 px-10 pb-11 xs:px-2"> | ||||||||||||||
<LinkButton | ||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,19 @@ | ||||||
export async function loadGoogleFont(font: string, text: string) { | ||||||
const url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential security issue: Encode The Apply this diff to encode export async function loadGoogleFont(font: string, text: string) {
- const url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(
+ const url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(font)}&text=${encodeURIComponent(
text
)}`; 📝 Committable suggestion
Suggested change
|
||||||
text | ||||||
)}`; | ||||||
console.log(url); | ||||||
const css = await (await fetch(url)).text(); | ||||||
const resource = css.match( | ||||||
/src: url\((.+)\) format\('(opentype|truetype)'\)/ | ||||||
); | ||||||
|
||||||
if (resource) { | ||||||
const response = await fetch(resource[1]); | ||||||
if (response.status == 200) { | ||||||
return await response.arrayBuffer(); | ||||||
} | ||||||
} | ||||||
|
||||||
throw new Error("failed to load font data"); | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for missing token details.
If
getAsset
does not find a matching asset,tokenDetails
might beundefined
, leading to errors when accessing its properties later.Add a check to handle the case where
tokenDetails
isundefined
.Apply this diff:
📝 Committable suggestion