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
This commit is contained in:
Austin Chen 2022-01-09 23:05:24 -08:00 committed by GitHub
parent ed37d93868
commit feca042e47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 10 deletions

View File

@ -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;

View File

@ -93,6 +93,7 @@ export function getHtml(parsedReq: ParsedRequest) {
creatorUsername,
creatorAvatarUrl,
} = parsedReq;
const hideAvatar = creatorAvatarUrl ? "" : "hidden";
return `<!DOCTYPE html>
<html>
<head>
@ -110,11 +111,11 @@ export function getHtml(parsedReq: ParsedRequest) {
<div class="absolute left-24 top-8">
<div class="flex flex-row align-bottom gap-6">
<img
class="h-24 w-24 rounded-full bg-white flex items-center justify-center"
class="h-24 w-24 rounded-full bg-white flex items-center justify-center ${hideAvatar}"
src="${creatorAvatarUrl}"
alt=""
/>
<div class="flex flex-col">
<div class="flex flex-col gap-2">
<p class="text-gray-900 text-3xl">${creatorName}</p>
<p class="text-gray-500 text-3xl">@${creatorUsername}</p>
</div>
@ -139,11 +140,11 @@ export function getHtml(parsedReq: ParsedRequest) {
</div>
<div class="flex flex-row justify-between gap-12 pt-36">
<div class="text-indigo-700 text-6xl leading-snug">
<div class="text-indigo-700 text-6xl leading-tight">
${question}
</div>
<div class="flex flex-col text-primary">
<div class="text-8xl">${probability}%</div>
<div class="text-8xl">${probability}</div>
<div class="text-4xl">chance</div>
</div>
</div>

View File

@ -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",

View File

@ -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 (
<Head>
@ -34,6 +57,22 @@ export function SEO(props: {
/>
)}
{ogCardProps && (
<>
<meta
property="og:image"
content={buildCardUrl(ogCardProps)}
key="image1"
/>
<meta name="twitter:card" content="summary_large_image" key="card" />
<meta
name="twitter:image"
content={buildCardUrl(ogCardProps)}
key="image2"
/>
</>
)}
{children}
</Head>
)

View File

@ -165,3 +165,24 @@ export function ContractDetails(props: { contract: Contract }) {
</Col>
)
}
// 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(' ')}` : '')
)
}

View File

@ -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 (
<Page wide={allowTrade}>
<SEO
title={question}
description={description}
url={`/${props.username}/${props.slug}`}
ogCardProps={ogCardProps}
/>
<Col className="w-full md:flex-row justify-between mt-6">

View File

@ -26,15 +26,17 @@ function MyApp({ Component, pageProps }: AppProps) {
key="description2"
/>
<meta property="og:url" content="https://manifold.markets" key="url" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:card" content="summary" key="card" />
<meta name="twitter:site" content="@manifoldmarkets" />
<meta
property="og:image"
content="https://manifold.markets/logo-cover.png"
key="image1"
/>
<meta
name="twitter:image"
content="https://manifold.markets/logo-bg.png"
key="image2"
/>
</Head>