Show resolution on og card image (#834)

* Handle resolved markets

* Add in group names as hashtags
This commit is contained in:
Ian Philips 2022-09-01 13:55:24 -06:00 committed by GitHub
parent 1208694d2d
commit 8d853815d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 188 deletions

View File

@ -27,10 +27,10 @@ export function contractMetrics(contract: Contract) {
export function contractTextDetails(contract: Contract) { export function contractTextDetails(contract: Contract) {
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const dayjs = require('dayjs') const dayjs = require('dayjs')
const { closeTime, tags } = contract const { closeTime, groupLinks } = contract
const { createdDate, resolvedDate, volumeLabel } = contractMetrics(contract) const { createdDate, resolvedDate, volumeLabel } = contractMetrics(contract)
const hashtags = tags.map((tag) => `#${tag}`) const groupHashtags = groupLinks?.slice(0, 5).map((g) => `#${g.name}`)
return ( return (
`${resolvedDate ? `${createdDate} - ${resolvedDate}` : createdDate}` + `${resolvedDate ? `${createdDate} - ${resolvedDate}` : createdDate}` +
@ -40,7 +40,7 @@ export function contractTextDetails(contract: Contract) {
).format('MMM D, h:mma')}` ).format('MMM D, h:mma')}`
: '') + : '') +
`${volumeLabel}` + `${volumeLabel}` +
(hashtags.length > 0 ? `${hashtags.join(' ')}` : '') (groupHashtags ? `${groupHashtags.join(' ')}` : '')
) )
} }
@ -92,6 +92,7 @@ export const getOpenGraphProps = (contract: Contract) => {
creatorAvatarUrl, creatorAvatarUrl,
description, description,
numericValue, numericValue,
resolution,
} }
} }
@ -103,6 +104,7 @@ export type OgCardProps = {
creatorUsername: string creatorUsername: string
creatorAvatarUrl?: string creatorAvatarUrl?: string
numericValue?: string numericValue?: string
resolution?: string
} }
export function buildCardUrl(props: OgCardProps, challenge?: Challenge) { export function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
@ -113,22 +115,32 @@ export function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
creatorOutcome, creatorOutcome,
acceptorOutcome, acceptorOutcome,
} = challenge || {} } = challenge || {}
const {
probability,
numericValue,
resolution,
creatorAvatarUrl,
question,
metadata,
creatorUsername,
creatorName,
} = props
const { userName, userAvatarUrl } = acceptances?.[0] ?? {} const { userName, userAvatarUrl } = acceptances?.[0] ?? {}
const probabilityParam = const probabilityParam =
props.probability === undefined probability === undefined
? '' ? ''
: `&probability=${encodeURIComponent(props.probability ?? '')}` : `&probability=${encodeURIComponent(probability ?? '')}`
const numericValueParam = const numericValueParam =
props.numericValue === undefined numericValue === undefined
? '' ? ''
: `&numericValue=${encodeURIComponent(props.numericValue ?? '')}` : `&numericValue=${encodeURIComponent(numericValue ?? '')}`
const creatorAvatarUrlParam = const creatorAvatarUrlParam =
props.creatorAvatarUrl === undefined creatorAvatarUrl === undefined
? '' ? ''
: `&creatorAvatarUrl=${encodeURIComponent(props.creatorAvatarUrl ?? '')}` : `&creatorAvatarUrl=${encodeURIComponent(creatorAvatarUrl ?? '')}`
const challengeUrlParams = challenge const challengeUrlParams = challenge
? `&creatorAmount=${creatorAmount}&creatorOutcome=${creatorOutcome}` + ? `&creatorAmount=${creatorAmount}&creatorOutcome=${creatorOutcome}` +
@ -136,16 +148,21 @@ export function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
`&acceptedName=${userName ?? ''}&acceptedAvatarUrl=${userAvatarUrl ?? ''}` `&acceptedName=${userName ?? ''}&acceptedAvatarUrl=${userAvatarUrl ?? ''}`
: '' : ''
const resolutionUrlParam = resolution
? `&resolution=${encodeURIComponent(resolution)}`
: ''
// URL encode each of the props, then add them as query params // URL encode each of the props, then add them as query params
return ( return (
`https://manifold-og-image.vercel.app/m.png` + `https://manifold-og-image.vercel.app/m.png` +
`?question=${encodeURIComponent(props.question)}` + `?question=${encodeURIComponent(question)}` +
probabilityParam + probabilityParam +
numericValueParam + numericValueParam +
`&metadata=${encodeURIComponent(props.metadata)}` + `&metadata=${encodeURIComponent(metadata)}` +
`&creatorName=${encodeURIComponent(props.creatorName)}` + `&creatorName=${encodeURIComponent(creatorName)}` +
creatorAvatarUrlParam + creatorAvatarUrlParam +
`&creatorUsername=${encodeURIComponent(props.creatorUsername)}` + `&creatorUsername=${encodeURIComponent(creatorUsername)}` +
challengeUrlParams challengeUrlParams +
resolutionUrlParam
) )
} }

View File

@ -1,85 +1,5 @@
import { sanitizeHtml } from './sanitizer'
import { ParsedRequest } from './types' import { ParsedRequest } from './types'
import { getTemplateCss } from './template-css'
function getCss(theme: string, fontSize: string) {
let background = 'white'
let foreground = 'black'
let radial = 'lightgray'
if (theme === 'dark') {
background = 'black'
foreground = 'white'
radial = 'dimgray'
}
// To use Readex Pro: `font-family: 'Readex Pro', sans-serif;`
return `
@import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&family=Readex+Pro:wght@400;700&display=swap');
body {
background: ${background};
background-image: radial-gradient(circle at 25px 25px, ${radial} 2%, transparent 0%), radial-gradient(circle at 75px 75px, ${radial} 2%, transparent 0%);
background-size: 100px 100px;
height: 100vh;
font-family: "Readex Pro", sans-serif;
}
code {
color: #D400FF;
font-family: 'Vera';
white-space: pre-wrap;
letter-spacing: -5px;
}
code:before, code:after {
content: '\`';
}
.logo-wrapper {
display: flex;
align-items: center;
align-content: center;
justify-content: center;
justify-items: center;
}
.logo {
margin: 0 75px;
}
.plus {
color: #BBB;
font-family: Times New Roman, Verdana;
font-size: 100px;
}
.spacer {
margin: 150px;
}
.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
.heading {
font-family: 'Major Mono Display', monospace;
font-size: ${sanitizeHtml(fontSize)};
font-style: normal;
color: ${foreground};
line-height: 1.8;
}
.font-major-mono {
font-family: "Major Mono Display", monospace;
}
.text-primary {
color: #11b981;
}
`
}
export function getChallengeHtml(parsedReq: ParsedRequest) { export function getChallengeHtml(parsedReq: ParsedRequest) {
const { const {
@ -112,7 +32,7 @@ export function getChallengeHtml(parsedReq: ParsedRequest) {
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
</head> </head>
<style> <style>
${getCss(theme, fontSize)} ${getTemplateCss(theme, fontSize)}
</style> </style>
<body> <body>
<div class="px-24"> <div class="px-24">

View File

@ -21,6 +21,7 @@ export function parseRequest(req: IncomingMessage) {
creatorName, creatorName,
creatorUsername, creatorUsername,
creatorAvatarUrl, creatorAvatarUrl,
resolution,
// Challenge attributes: // Challenge attributes:
challengerAmount, challengerAmount,
@ -71,6 +72,7 @@ export function parseRequest(req: IncomingMessage) {
question: question:
getString(question) || 'Will you create a prediction market on Manifold?', getString(question) || 'Will you create a prediction market on Manifold?',
resolution: getString(resolution),
probability: getString(probability), probability: getString(probability),
numericValue: getString(numericValue) || '', numericValue: getString(numericValue) || '',
metadata: getString(metadata) || 'Jan 1 &nbsp;•&nbsp; M$ 123 pool', metadata: getString(metadata) || 'Jan 1 &nbsp;•&nbsp; M$ 123 pool',

View File

@ -0,0 +1,81 @@
import { sanitizeHtml } from './sanitizer'
export function getTemplateCss(theme: string, fontSize: string) {
let background = 'white'
let foreground = 'black'
let radial = 'lightgray'
if (theme === 'dark') {
background = 'black'
foreground = 'white'
radial = 'dimgray'
}
// To use Readex Pro: `font-family: 'Readex Pro', sans-serif;`
return `
@import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&family=Readex+Pro:wght@400;700&display=swap');
body {
background: ${background};
background-image: radial-gradient(circle at 25px 25px, ${radial} 2%, transparent 0%), radial-gradient(circle at 75px 75px, ${radial} 2%, transparent 0%);
background-size: 100px 100px;
height: 100vh;
font-family: "Readex Pro", sans-serif;
}
code {
color: #D400FF;
font-family: 'Vera';
white-space: pre-wrap;
letter-spacing: -5px;
}
code:before, code:after {
content: '\`';
}
.logo-wrapper {
display: flex;
align-items: center;
align-content: center;
justify-content: center;
justify-items: center;
}
.logo {
margin: 0 75px;
}
.plus {
color: #BBB;
font-family: Times New Roman, Verdana;
font-size: 100px;
}
.spacer {
margin: 150px;
}
.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
.heading {
font-family: 'Major Mono Display', monospace;
font-size: ${sanitizeHtml(fontSize)};
font-style: normal;
color: ${foreground};
line-height: 1.8;
}
.font-major-mono {
font-family: "Major Mono Display", monospace;
}
.text-primary {
color: #11b981;
}
`
}

View File

@ -1,85 +1,5 @@
import { sanitizeHtml } from './sanitizer'
import { ParsedRequest } from './types' import { ParsedRequest } from './types'
import { getTemplateCss } from './template-css'
function getCss(theme: string, fontSize: string) {
let background = 'white'
let foreground = 'black'
let radial = 'lightgray'
if (theme === 'dark') {
background = 'black'
foreground = 'white'
radial = 'dimgray'
}
// To use Readex Pro: `font-family: 'Readex Pro', sans-serif;`
return `
@import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&family=Readex+Pro:wght@400;700&display=swap');
body {
background: ${background};
background-image: radial-gradient(circle at 25px 25px, ${radial} 2%, transparent 0%), radial-gradient(circle at 75px 75px, ${radial} 2%, transparent 0%);
background-size: 100px 100px;
height: 100vh;
font-family: "Readex Pro", sans-serif;
}
code {
color: #D400FF;
font-family: 'Vera';
white-space: pre-wrap;
letter-spacing: -5px;
}
code:before, code:after {
content: '\`';
}
.logo-wrapper {
display: flex;
align-items: center;
align-content: center;
justify-content: center;
justify-items: center;
}
.logo {
margin: 0 75px;
}
.plus {
color: #BBB;
font-family: Times New Roman, Verdana;
font-size: 100px;
}
.spacer {
margin: 150px;
}
.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
}
.heading {
font-family: 'Major Mono Display', monospace;
font-size: ${sanitizeHtml(fontSize)};
font-style: normal;
color: ${foreground};
line-height: 1.8;
}
.font-major-mono {
font-family: "Major Mono Display", monospace;
}
.text-primary {
color: #11b981;
}
`
}
export function getHtml(parsedReq: ParsedRequest) { export function getHtml(parsedReq: ParsedRequest) {
const { const {
@ -92,6 +12,7 @@ export function getHtml(parsedReq: ParsedRequest) {
creatorUsername, creatorUsername,
creatorAvatarUrl, creatorAvatarUrl,
numericValue, numericValue,
resolution,
} = parsedReq } = parsedReq
const MAX_QUESTION_CHARS = 100 const MAX_QUESTION_CHARS = 100
const truncatedQuestion = const truncatedQuestion =
@ -99,6 +20,49 @@ export function getHtml(parsedReq: ParsedRequest) {
? question.slice(0, MAX_QUESTION_CHARS) + '...' ? question.slice(0, MAX_QUESTION_CHARS) + '...'
: question : question
const hideAvatar = creatorAvatarUrl ? '' : 'hidden' const hideAvatar = creatorAvatarUrl ? '' : 'hidden'
let resolutionColor = 'text-primary'
let resolutionString = 'Yes'
switch (resolution) {
case 'YES':
break
case 'NO':
resolutionColor = 'text-red-500'
resolutionString = 'No'
break
case 'CANCEL':
resolutionColor = 'text-yellow-500'
resolutionString = 'N/A'
break
case 'MKT':
resolutionColor = 'text-blue-500'
resolutionString = numericValue ? numericValue : probability
break
}
const resolutionDiv = `
<span class='text-center ${resolutionColor}'>
<div class="text-8xl">
${resolutionString}
</div>
<div class="text-4xl">${
resolution === 'CANCEL' ? '' : 'resolved'
}</div>
</span>`
const probabilityDiv = `
<span class='text-primary text-center'>
<div class="text-8xl">${probability}</div>
<div class="text-4xl">chance</div>
</span>`
const numericValueDiv = `
<span class='text-blue-500 text-center'>
<div class="text-8xl ">${numericValue}</div>
<div class="text-4xl">expected</div>
</span>
`
return `<!DOCTYPE html> return `<!DOCTYPE html>
<html> <html>
<head> <head>
@ -108,7 +72,7 @@ export function getHtml(parsedReq: ParsedRequest) {
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
</head> </head>
<style> <style>
${getCss(theme, fontSize)} ${getTemplateCss(theme, fontSize)}
</style> </style>
<body> <body>
<div class="px-24"> <div class="px-24">
@ -148,21 +112,20 @@ export function getHtml(parsedReq: ParsedRequest) {
<div class="text-indigo-700 text-6xl leading-tight"> <div class="text-indigo-700 text-6xl leading-tight">
${truncatedQuestion} ${truncatedQuestion}
</div> </div>
<div class="flex flex-col text-primary"> <div class="flex flex-col">
<div class="text-8xl">${probability}</div> ${
<div class="text-4xl">${probability !== '' ? 'chance' : ''}</div> resolution
<span class='text-blue-500 text-center'> ? resolutionDiv
<div class="text-8xl ">${ : numericValue
numericValue !== '' && probability === '' ? numericValue : '' ? numericValueDiv
}</div> : probabilityDiv
<div class="text-4xl">${numericValue !== '' ? 'expected' : ''}</div> }
</span>
</div> </div>
</div> </div>
<!-- Metadata --> <!-- Metadata -->
<div class="absolute bottom-16"> <div class="absolute bottom-16">
<div class="text-gray-500 text-3xl"> <div class="text-gray-500 text-3xl max-w-[80vw]">
${metadata} ${metadata}
</div> </div>
</div> </div>

View File

@ -19,6 +19,7 @@ export interface ParsedRequest {
creatorName: string creatorName: string
creatorUsername: string creatorUsername: string
creatorAvatarUrl: string creatorAvatarUrl: string
resolution: string
// Challenge attributes: // Challenge attributes:
challengerAmount: string challengerAmount: string
challengerOutcome: string challengerOutcome: string