Skip to content

Commit

Permalink
feat: update data fetching & image generation
Browse files Browse the repository at this point in the history
  • Loading branch information
borcherd committed Jan 3, 2025
1 parent 9635b8b commit 669a7c2
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 194 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 22 additions & 21 deletions apps/marginfi-v2-trading/src/components/common/Meta/Meta.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import Head from "next/head";
import { PublicKey } from "@solana/web3.js";

import { BankMetadataRaw } from "@mrgnlabs/mrgn-common";
import { getTokenImageURL } from "@mrgnlabs/mrgn-utils";
import { PoolListApiResponse } from "~/types/api.types";
import { TokenData } from "~/types";

type MrgnProps = {
path: string;
bank: BankMetadataRaw | null;
groupPk?: string | null;
poolData?: PoolListApiResponse[] | null;
tokenDetails?: TokenData[] | null;
baseUrl?: string;
};

const GCP_URL = "https://storage.googleapis.com/mrgn-public/mrgn-trade-token-share-images";

export const Meta = ({ path, bank }: MrgnProps) => {
export const Meta = ({ groupPk, poolData, tokenDetails, baseUrl }: MrgnProps) => {
let title = "The Arena";
let description = "Memecoin trading, with leverage.";
let image = GCP_URL + "/default.jpg";
const pageTitlePart = path.split("/").pop();
const pageTitle = pageTitlePart ? pageTitlePart.charAt(0).toUpperCase() + pageTitlePart.slice(1) : "";

if (path !== "/" && path !== "/blocked") {
title = pageTitle + " - The Arena";
description = "";
}
let image = `${baseUrl}/metadata/metadata-image-default.png`;

if (bank) {
title = `Long / short ${bank.tokenSymbol} with leverage in The Arena.`;
// image = GCP_URL + `/${bank.tokenAddress}.jpg`;
const tokenImageUrl = getTokenImageURL(new PublicKey(bank.tokenAddress));
image = `http://localhost:3006/api/share-image/generate?tokenSymbol=${bank.tokenSymbol}&tokenImageUrl=${tokenImageUrl}`;
if (groupPk) {
const _poolData = poolData?.find((pool) => pool.group === groupPk);
if (!_poolData) return;
const _tokenDetails = tokenDetails?.find(
(token) => token.address === _poolData?.base_bank?.mint.address.toString()
);
if (!_tokenDetails) return;
const _quoteTokenDetails = tokenDetails?.find(
(token) => token.address === _poolData?.quote_banks[0]?.mint.address.toString()
);
if (!_quoteTokenDetails) return;
title = `Trade ${_tokenDetails?.symbol}/${_quoteTokenDetails?.symbol} with leverage in The Arena.`;
description = `Trade ${_tokenDetails?.symbol} / ${_quoteTokenDetails?.symbol} with leverage in The Arena.`;
image = `${baseUrl}/api/share-image/generate?tokenSymbol=${_tokenDetails?.symbol}&tokenImageUrl=${_tokenDetails?.imageUrl}&quoteTokenSymbol=${_quoteTokenDetails?.symbol}&quoteTokenImageUrl=${_quoteTokenDetails?.imageUrl}`;
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
/* eslint-disable @next/next/no-img-element */

export function DynamicShareImage({
tokenSymbol,
tokenImageUrl,
quoteTokenImageUrl,
tokenSymbol,
quoteTokenSymbol,
baseUrl,
}: {
tokenSymbol: string | null;
tokenImageUrl: string | null;
tokenImageUrl: string;
quoteTokenImageUrl: string;
tokenSymbol: string;
quoteTokenSymbol: string;
baseUrl: string;
}) {
return (
<div
Expand All @@ -13,27 +20,28 @@ export function DynamicShareImage({
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
width: "960px",
height: "500px",
width: "720px",
height: "360px",
backgroundColor: "#F7F7F7",
backgroundImage: "url('https://staging.thearena.trade/sharing/share-position-bg.png')",
backgroundImage: `url('${baseUrl}/metadata/metadata-image-bg.png')`,
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
position: "relative",
fontFamily: "Arial, sans-serif",
fontFamily: "var(--font-aeonik)",
}}
>
<div
style={{
width: "80px",
height: "80px",
width: "84px",
height: "84px",
overflow: "hidden",
marginBottom: "20px",
padding: "2px",
display: "flex",
}}
>
<img
src={tokenImageUrl ?? ""}
src={tokenImageUrl}
alt="Profile"
height="80px"
width="80px"
Expand All @@ -45,138 +53,33 @@ export function DynamicShareImage({
width: "80px",
}}
/>
<img
src={quoteTokenImageUrl}
alt="Profile"
height="30px"
width="30px"
style={{
height: "30px",
width: "30px",
borderRadius: "50%",
objectFit: "cover",
position: "absolute",
bottom: "0",
right: "0",
}}
/>
</div>

<h1
style={{
fontSize: "32px",
fontWeight: "bold",
margin: 0,
fontFamily: "var(--font-aeonik)",
}}
>
Trade {tokenSymbol}
{tokenSymbol}/{quoteTokenSymbol}
</h1>

<h1
style={{
fontSize: "24px",
fontWeight: "bold",
margin: 0,
}}
>
The Arena
</h1>

<p
style={{
fontSize: "16px",
color: "#666",
marginTop: "5px",
}}
>
Memecoin trading, with leverage.
</p>
</div>
);
}

// export function DynamicShareImage({
// tokenImageUrl,
// quoteImageUrl,
// tokenSymbol,
// quoteSymbol,
// }: {
// tokenImageUrl: string;
// quoteImageUrl: string;
// tokenSymbol: string;
// quoteSymbol: string;
// }) {
// return (
// <div
// style={{
// display: "flex",
// flexDirection: "column",
// alignItems: "center",
// justifyContent: "center",
// width: "960px",
// height: "500px",
// backgroundColor: "#F7F7F7",
// backgroundImage: "url('http://localhost:3006/sharing/share-position-bg.png')",
// backgroundRepeat: "no-repeat",
// backgroundSize: "cover",
// position: "relative",
// fontFamily: "Arial, sans-serif",
// }}
// >
// <div
// style={{
// width: "84px",
// height: "84px",
// overflow: "hidden",
// marginBottom: "20px",
// padding: "2px",
// display: "flex",
// }}
// >
// <img
// src={tokenImageUrl}
// alt="Profile"
// height="80px"
// width="80px"
// style={{
// borderRadius: "50%",
// objectFit: "cover",
// position: "absolute",
// height: "80px",
// width: "80px",
// }}
// />
// <img
// src={quoteImageUrl}
// alt="Profile"
// height="30px"
// width="30px"
// style={{
// height: "30px",
// width: "30px",
// borderRadius: "50%",
// objectFit: "cover",
// position: "absolute",
// bottom: "0",
// right: "0",
// }}
// />
// </div>

// <h1
// style={{
// fontSize: "32px",
// fontWeight: "bold",
// margin: 0,
// }}
// >
// {tokenSymbol}/{quoteSymbol}
// </h1>

// <h1
// style={{
// fontSize: "24px",
// fontWeight: "bold",
// margin: 0,
// }}
// >
// The Arena
// </h1>

// <p
// style={{
// fontSize: "16px",
// color: "#666",
// marginTop: "5px",
// }}
// >
// Memecoin trading, with leverage.
// </p>
// </div>
// );
// }
31 changes: 9 additions & 22 deletions apps/marginfi-v2-trading/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import App, { AppContext, AppInitialProps, AppProps } from "next/app";
import { AppProps } from "next/app";
import { useRouter } from "next/router";
import { SpeedInsights } from "@vercel/speed-insights/next";

Expand All @@ -10,7 +10,6 @@ import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { TipLinkWalletAutoConnect } from "@tiplink/wallet-adapter-react-ui";
import { ToastContainer } from "react-toastify";
import { Analytics } from "@vercel/analytics/react";
import { BankMetadataRaw } from "@mrgnlabs/mrgn-common";
import { Desktop, Mobile, init as initAnalytics } from "@mrgnlabs/mrgn-utils";
import { ActionProvider } from "~/components/action-box-v2";
import { generateEndpoint } from "~/rpc.utils";
Expand All @@ -19,7 +18,6 @@ import config from "~/config";
import { useUiStore } from "~/store";
import { TradePovider } from "~/context";
import { WALLET_ADAPTERS } from "~/config/wallets";
import { BANK_METADATA_MAP } from "~/config/trade";
import { WalletProvider as MrgnWalletProvider } from "~/components/wallet-v2/hooks/use-wallet.hook";
import { ConnectionProvider } from "~/hooks/use-connection";

Expand All @@ -31,14 +29,19 @@ import { Footer } from "~/components/desktop/Footer";

import "react-toastify/dist/ReactToastify.min.css";
import { AuthDialog } from "~/components/wallet-v2";
import { StaticArenaProps } from "~/utils";
import { getArenaStaticProps } from "~/utils";
import { GetStaticProps } from "next";
import { GeoBlockingWrapper } from "~/components/common/geo-blocking-wrapper";

require("~/styles/globals.css");
require("~/styles/fonts.css");

type MrgnAppProps = { path: string; bank: BankMetadataRaw | null };
export const getStaticProps: GetStaticProps<StaticArenaProps> = async (context) => {
return getArenaStaticProps(context);
};

export default function MrgnApp({ Component, pageProps, path, bank }: AppProps & MrgnAppProps) {
export default function MrgnApp({ Component, pageProps }: AppProps & StaticArenaProps) {
const { query, isReady } = useRouter();
const [ready, setReady] = React.useState(false);
const [rpcEndpoint, setRpcEndpoint] = React.useState("");
Expand All @@ -63,7 +66,7 @@ export default function MrgnApp({ Component, pageProps, path, bank }: AppProps &

return (
<>
<Meta path={path} bank={bank} />
<Meta />
{ready && rpcEndpoint && (
<ConnectionProvider endpoint={rpcEndpoint}>
<TipLinkWalletAutoConnect isReady={isReady} query={query}>
Expand Down Expand Up @@ -113,19 +116,3 @@ export default function MrgnApp({ Component, pageProps, path, bank }: AppProps &
</>
);
}

MrgnApp.getInitialProps = async (appContext: AppContext): Promise<AppInitialProps & MrgnAppProps> => {
const appProps = await App.getInitialProps(appContext);
const path = appContext.ctx.asPath;
let bank = null;

if (path && path.includes("/trade")) {
const cleanPath = path.split("?")[0];
const groupAddress = cleanPath.split("/trade/")[1];
const res = await fetch(BANK_METADATA_MAP);
const data = await res.json();
bank = data.find((bank: BankMetadataRaw) => bank.groupAddress === groupAddress);
}

return { ...appProps, path: path || "/", bank };
};
23 changes: 14 additions & 9 deletions apps/marginfi-v2-trading/src/pages/api/share-image/generate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,27 @@ export const runtime = "edge";
// Generate link preview image
// Note that a lot of usual CSS is unsupported, including tailwind.
export default async function GET(request: NextRequest) {
const baseUrl = `${request.headers.get("x-forwarded-proto") ?? "https"}://${request.headers.get("host")}`;

const { searchParams } = new URL(request.url);
const tokenSymbol = searchParams.get("tokenSymbol");
const tokenImageUrl = searchParams.get("tokenImageUrl");
const quoteTokenSymbol = searchParams.get("quoteTokenSymbol");
const quoteTokenImageUrl = searchParams.get("quoteTokenImageUrl");

return new ImageResponse(
(
// <DynamicShareImage
// tokenImageUrl="https://storage.googleapis.com/mrgn-public/mrgn-token-icons/CzLSujWBLFsSjncfkh59rUFqvafWcY5tzedWJSuypump.png"
// quoteImageUrl="https://storage.googleapis.com/mrgn-public/mrgn-token-icons/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.png"
// tokenSymbol="GOAT"
// quoteSymbol="LST"
// />
<DynamicShareImage tokenSymbol={tokenSymbol} tokenImageUrl={tokenImageUrl} />
<DynamicShareImage
tokenImageUrl={tokenImageUrl ?? ""}
quoteTokenImageUrl={quoteTokenImageUrl ?? ""}
tokenSymbol={tokenSymbol ?? ""}
quoteTokenSymbol={quoteTokenSymbol ?? ""}
baseUrl={baseUrl ?? ""}
/>
),
{
width: 960, // TODO: figure out sizing
height: 500,
width: 720,
height: 360,
}
);
}
Loading

0 comments on commit 669a7c2

Please sign in to comment.