diff --git a/og-image/api/_lib/parser.ts b/og-image/api/_lib/parser.ts index 1f1a6bdc..b8163719 100644 --- a/og-image/api/_lib/parser.ts +++ b/og-image/api/_lib/parser.ts @@ -1,10 +1,10 @@ -import { IncomingMessage } from "http"; -import { parse } from "url"; -import { ParsedRequest } from "./types"; +import { IncomingMessage } from 'http' +import { parse } from 'url' +import { ParsedRequest } from './types' export function parseRequest(req: IncomingMessage) { - console.log("HTTP " + req.url); - const { pathname, query } = parse(req.url || "/", true); + console.log('HTTP ' + req.url) + const { pathname, query } = parse(req.url || '/', true) const { fontSize, images, @@ -20,73 +20,73 @@ export function parseRequest(req: IncomingMessage) { creatorName, creatorUsername, creatorAvatarUrl, - } = query || {}; + } = query || {} if (Array.isArray(fontSize)) { - throw new Error("Expected a single fontSize"); + throw new Error('Expected a single fontSize') } if (Array.isArray(theme)) { - throw new Error("Expected a single theme"); + throw new Error('Expected a single theme') } - const arr = (pathname || "/").slice(1).split("."); - let extension = ""; - let text = ""; + const arr = (pathname || '/').slice(1).split('.') + let extension = '' + let text = '' if (arr.length === 0) { - text = ""; + text = '' } else if (arr.length === 1) { - text = arr[0]; + text = arr[0] } else { - extension = arr.pop() as string; - text = arr.join("."); + extension = arr.pop() as string + text = arr.join('.') } // Take a url query param and return a single string const getString = (stringOrArray: string[] | string | undefined): string => { if (Array.isArray(stringOrArray)) { // If the query param is an array, return the first element - return stringOrArray[0]; + return stringOrArray[0] } - return stringOrArray || ""; - }; + return stringOrArray || '' + } const parsedRequest: ParsedRequest = { - fileType: extension === "jpeg" ? extension : "png", + fileType: extension === 'jpeg' ? extension : 'png', text: decodeURIComponent(text), - theme: theme === "dark" ? "dark" : "light", - md: md === "1" || md === "true", - fontSize: fontSize || "96px", + theme: theme === 'dark' ? 'dark' : 'light', + md: md === '1' || md === 'true', + fontSize: fontSize || '96px', images: getArray(images), widths: getArray(widths), heights: getArray(heights), question: - getString(question) || "Will you create a prediction market on Manifold?", - probability: getString(probability) || "85%", - metadata: getString(metadata) || "Jan 1  •  M$ 123 pool", - creatorName: getString(creatorName) || "Manifold Markets", - creatorUsername: getString(creatorUsername) || "ManifoldMarkets", - creatorAvatarUrl: getString(creatorAvatarUrl) || "", - }; - parsedRequest.images = getDefaultImages(parsedRequest.images); - return parsedRequest; + getString(question) || 'Will you create a prediction market on Manifold?', + probability: getString(probability), + metadata: getString(metadata) || 'Jan 1  •  M$ 123 pool', + creatorName: getString(creatorName) || 'Manifold Markets', + creatorUsername: getString(creatorUsername) || 'ManifoldMarkets', + creatorAvatarUrl: getString(creatorAvatarUrl) || '', + } + parsedRequest.images = getDefaultImages(parsedRequest.images) + return parsedRequest } function getArray(stringOrArray: string[] | string | undefined): string[] { - if (typeof stringOrArray === "undefined") { - return []; + if (typeof stringOrArray === 'undefined') { + return [] } else if (Array.isArray(stringOrArray)) { - return stringOrArray; + return stringOrArray } else { - return [stringOrArray]; + return [stringOrArray] } } function getDefaultImages(images: string[]): string[] { - const defaultImage = "https://manifold.markets/logo.png"; + const defaultImage = 'https://manifold.markets/logo.png' if (!images || !images[0]) { - return [defaultImage]; + return [defaultImage] } - return images; + return images } diff --git a/og-image/api/_lib/template.ts b/og-image/api/_lib/template.ts index 2b5a8bb2..73105f6b 100644 --- a/og-image/api/_lib/template.ts +++ b/og-image/api/_lib/template.ts @@ -1,15 +1,15 @@ -import { sanitizeHtml } from "./sanitizer"; -import { ParsedRequest } from "./types"; +import { sanitizeHtml } from './sanitizer' +import { ParsedRequest } from './types' function getCss(theme: string, fontSize: string) { - let background = "white"; - let foreground = "black"; - let radial = "lightgray"; + let background = 'white' + let foreground = 'black' + let radial = 'lightgray' - if (theme === "dark") { - background = "black"; - foreground = "white"; - radial = "dimgray"; + if (theme === 'dark') { + background = 'black' + foreground = 'white' + radial = 'dimgray' } // To use Readex Pro: `font-family: 'Readex Pro', sans-serif;` return ` @@ -78,7 +78,7 @@ function getCss(theme: string, fontSize: string) { .text-primary { color: #11b981; } - `; + ` } export function getHtml(parsedReq: ParsedRequest) { @@ -92,8 +92,8 @@ export function getHtml(parsedReq: ParsedRequest) { creatorName, creatorUsername, creatorAvatarUrl, - } = parsedReq; - const hideAvatar = creatorAvatarUrl ? "" : "hidden"; + } = parsedReq + const hideAvatar = creatorAvatarUrl ? '' : 'hidden' return ` @@ -145,7 +145,7 @@ export function getHtml(parsedReq: ParsedRequest) {
${probability}
-
chance
+
${probability !== '' ? 'chance' : ''}
@@ -157,5 +157,5 @@ export function getHtml(parsedReq: ParsedRequest) { -`; +` } diff --git a/web/components/SEO.tsx b/web/components/SEO.tsx index 697f4d33..84ba850c 100644 --- a/web/components/SEO.tsx +++ b/web/components/SEO.tsx @@ -2,7 +2,7 @@ import Head from 'next/head' export type OgCardProps = { question: string - probability: string + probability?: string metadata: string creatorName: string creatorUsername: string @@ -11,11 +11,16 @@ export type OgCardProps = { } function buildCardUrl(props: OgCardProps) { + const probabilityParam = + props.probability === undefined + ? '' + : `&probability=${encodeURIComponent(props.probability ?? '')}` + // 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)}` + + probabilityParam + `&metadata=${encodeURIComponent(props.metadata)}` + `&creatorName=${encodeURIComponent(props.creatorName)}` + `&creatorUsername=${encodeURIComponent(props.creatorUsername)}` diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index 08cbb337..557d5a45 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -102,8 +102,7 @@ export default function ContractPage(props: { const allowResolve = !isResolved && isCreator && !!user const hasSidePanel = isBinary && (allowTrade || allowResolve) - // TODO(James): Create SEO props for non-binary contracts. - const ogCardProps = isBinary ? getOpenGraphProps(contract) : undefined + const ogCardProps = getOpenGraphProps(contract) return ( @@ -191,8 +190,10 @@ function BetsSection(props: { } const getOpenGraphProps = (contract: Contract) => { - const { resolution, question, creatorName, creatorUsername } = contract - const probPercent = getBinaryProbPercent(contract) + const { resolution, question, creatorName, creatorUsername, outcomeType } = + contract + const probPercent = + outcomeType === 'BINARY' ? getBinaryProbPercent(contract) : undefined const description = resolution ? `Resolved ${resolution}. ${contract.description}`