From feca042e47322ebb39c93fc7639c5a3cded85e86 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Sun, 9 Jan 2022 23:05:24 -0800 Subject: [PATCH] Use the generated OpenGraph card in all markets (#23) * Run OpenGraph server on dev port 3001 * Cut '%' since frontend already passes it * Use the generated card in markets * Rename to ogCardProps * Don't show creator avatar url, for now * Remove bad comment --- og-image/api/_lib/parser.ts | 5 ++- og-image/api/_lib/template.ts | 9 +++--- og-image/package.json | 2 +- web/components/SEO.tsx | 41 ++++++++++++++++++++++++- web/components/contract-card.tsx | 21 +++++++++++++ web/pages/[username]/[contractSlug].tsx | 10 ++++++ web/pages/_app.tsx | 4 ++- 7 files changed, 82 insertions(+), 10 deletions(-) diff --git a/og-image/api/_lib/parser.ts b/og-image/api/_lib/parser.ts index f65fcf27..1f1a6bdc 100644 --- a/og-image/api/_lib/parser.ts +++ b/og-image/api/_lib/parser.ts @@ -62,12 +62,11 @@ export function parseRequest(req: IncomingMessage) { question: getString(question) || "Will you create a prediction market on Manifold?", - probability: getString(probability) || "85", + probability: getString(probability) || "85%", metadata: getString(metadata) || "Jan 1  •  M$ 123 pool", creatorName: getString(creatorName) || "Manifold Markets", creatorUsername: getString(creatorUsername) || "ManifoldMarkets", - creatorAvatarUrl: - getString(creatorAvatarUrl) || "https://manifold.markets/logo.png", + creatorAvatarUrl: getString(creatorAvatarUrl) || "", }; parsedRequest.images = getDefaultImages(parsedRequest.images); return parsedRequest; diff --git a/og-image/api/_lib/template.ts b/og-image/api/_lib/template.ts index 3689cc2e..2b5a8bb2 100644 --- a/og-image/api/_lib/template.ts +++ b/og-image/api/_lib/template.ts @@ -93,6 +93,7 @@ export function getHtml(parsedReq: ParsedRequest) { creatorUsername, creatorAvatarUrl, } = parsedReq; + const hideAvatar = creatorAvatarUrl ? "" : "hidden"; return ` @@ -110,11 +111,11 @@ export function getHtml(parsedReq: ParsedRequest) {
-
+

${creatorName}

@${creatorUsername}

@@ -139,11 +140,11 @@ export function getHtml(parsedReq: ParsedRequest) {
-
+
${question}
-
${probability}%
+
${probability}
chance
diff --git a/og-image/package.json b/og-image/package.json index 6f7bf48a..563a7d45 100644 --- a/og-image/package.json +++ b/og-image/package.json @@ -2,7 +2,7 @@ "private": true, "scripts": { "build": "tsc -p api/tsconfig.json && tsc -p web/tsconfig.json", - "start": "cd .. && vercel dev" + "start": "cd .. && vercel dev --listen 3001" }, "dependencies": { "chrome-aws-lambda": "7.0.0", diff --git a/web/components/SEO.tsx b/web/components/SEO.tsx index e8d6547f..697f4d33 100644 --- a/web/components/SEO.tsx +++ b/web/components/SEO.tsx @@ -1,12 +1,35 @@ import Head from 'next/head' +export type OgCardProps = { + question: string + probability: string + metadata: string + creatorName: string + creatorUsername: string + // TODO: Store creator avatar url in each contract, then enable this + // creatorAvatarUrl: string +} + +function buildCardUrl(props: OgCardProps) { + // URL encode each of the props, then add them as query params + return ( + `https://manifold-og-image.vercel.app/m.png` + + `?question=${encodeURIComponent(props.question)}` + + `&probability=${encodeURIComponent(props.probability)}` + + `&metadata=${encodeURIComponent(props.metadata)}` + + `&creatorName=${encodeURIComponent(props.creatorName)}` + + `&creatorUsername=${encodeURIComponent(props.creatorUsername)}` + ) +} + export function SEO(props: { title: string description: string url?: string children?: any[] + ogCardProps?: OgCardProps }) { - const { title, description, url, children } = props + const { title, description, url, children, ogCardProps } = props return ( @@ -34,6 +57,22 @@ export function SEO(props: { /> )} + {ogCardProps && ( + <> + + + + + )} + {children} ) diff --git a/web/components/contract-card.tsx b/web/components/contract-card.tsx index c4c8c7fa..046e8914 100644 --- a/web/components/contract-card.tsx +++ b/web/components/contract-card.tsx @@ -165,3 +165,24 @@ export function ContractDetails(props: { contract: Contract }) { ) } + +// String version of the above, to send to the OpenGraph image generator +export function contractTextDetails(contract: Contract) { + const { question, description, closeTime } = contract + const { truePool, createdDate, resolvedDate } = compute(contract) + + const tags = parseTags(`${question} ${description}`).map((tag) => `#${tag}`) + + return ( + `${contract.creatorUsername} • ${ + resolvedDate ? `${createdDate} - ${resolvedDate}` : createdDate + }` + + (closeTime + ? ` • ${closeTime > Date.now() ? 'Closes' : 'Closed'} ${dayjs( + closeTime + ).format('MMM D, h:mma')}` + : '') + + ` • ${formatMoney(truePool)} pool` + + (tags.length > 0 ? ` • ${tags.join(' ')}` : '') + ) +} diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index f467578a..7aabede2 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -18,6 +18,7 @@ import { } from '../../lib/firebase/contracts' import { SEO } from '../../components/SEO' import { Page } from '../../components/page' +import { contractTextDetails } from '../../components/contract-card' export async function getStaticProps(props: { params: any }) { const { username, contractSlug } = props.params @@ -63,12 +64,21 @@ export default function ContractPage(props: { ? `Resolved ${resolution}. ${contract.description}` : `${probPercent} chance. ${contract.description}` + const ogCardProps = { + question, + probability: probPercent, + metadata: contractTextDetails(contract), + creatorName: contract.creatorName, + creatorUsername: contract.creatorUsername, + } + return ( diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index f2f2619d..cfa65f04 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -26,15 +26,17 @@ function MyApp({ Component, pageProps }: AppProps) { key="description2" /> - +