Update SEO for non-binary markets

This commit is contained in:
James Grugett 2022-02-17 18:34:11 -06:00
parent 8e33c2b639
commit 0a3b14883c
4 changed files with 64 additions and 58 deletions

View File

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

View File

@ -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 `<!DOCTYPE html>
<html>
<head>
@ -145,7 +145,7 @@ export function getHtml(parsedReq: ParsedRequest) {
</div>
<div class="flex flex-col text-primary">
<div class="text-8xl">${probability}</div>
<div class="text-4xl">chance</div>
<div class="text-4xl">${probability !== '' ? 'chance' : ''}</div>
</div>
</div>
@ -157,5 +157,5 @@ export function getHtml(parsedReq: ParsedRequest) {
</div>
</div>
</body>
</html>`;
</html>`
}

View File

@ -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)}`

View File

@ -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 (
<Page wide={hasSidePanel}>
@ -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}`