Align bet icons with the percentages

This commit is contained in:
Austin Chen 2022-05-21 13:26:34 -07:00
parent 3d368216b2
commit d1fab9937f
2 changed files with 122 additions and 91 deletions

View File

@ -25,7 +25,11 @@ import {
OUTCOME_TO_COLOR, OUTCOME_TO_COLOR,
} from '../outcome-label' } from '../outcome-label'
import { getOutcomeProbability, getTopAnswer } from 'common/calculate' import { getOutcomeProbability, getTopAnswer } from 'common/calculate'
import { AbbrContractDetails } from './contract-details' import {
AbbrContractDetails,
AvatarDetails,
MiscDetails,
} from './contract-details'
import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm' import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm'
import { import {
ArrowCircleUpIcon, ArrowCircleUpIcon,
@ -33,6 +37,7 @@ import {
StarIcon, StarIcon,
PaperAirplaneIcon, PaperAirplaneIcon,
} from '@heroicons/react/outline' } from '@heroicons/react/outline'
import { PaperAirplaneIcon as SolidPlaneIcon } from '@heroicons/react/solid'
// Return a number from 0 to 1 for this contract // Return a number from 0 to 1 for this contract
// Resolved contracts are set to 1, for coloring purposes (even if NO) // Resolved contracts are set to 1, for coloring purposes (even if NO)
@ -56,6 +61,9 @@ function getNumericScale(contract: NumericContract) {
} }
function getColor(contract: Contract) { function getColor(contract: Contract) {
// TODO: Not sure why eg green-400 doesn't work here; try upgrading Tailwind
// TODO: Try injecting a gradient here
// return 'primary'
const { resolution } = contract const { resolution } = contract
if (resolution) { if (resolution) {
return ( return (
@ -103,66 +111,64 @@ export function ContractCard(props: {
<a className="absolute left-0 right-0 top-0 bottom-0" /> <a className="absolute left-0 right-0 top-0 bottom-0" />
</Link> </Link>
<AbbrContractDetails
contract={contract}
showHotVolume={showHotVolume}
showCloseTime={showCloseTime}
/>
<Row className={clsx('justify-between gap-4')}> <Row className={clsx('justify-between gap-4')}>
<Col className="gap-3"> <Col className="gap-3">
<AvatarDetails contract={contract} />
<p <p
className="break-words font-medium text-indigo-700" className="break-words font-medium text-indigo-700"
style={{ /* For iOS safari */ wordBreak: 'break-word' }} style={{ /* For iOS safari */ wordBreak: 'break-word' }}
> >
{question} {question}
</p> </p>
</Col>
{outcomeType === 'BINARY' && ( <MiscDetails
<BinaryResolutionOrChance
className="items-center"
contract={contract} contract={contract}
showHotVolume={showHotVolume}
showCloseTime={showCloseTime}
/> />
)} </Col>
{outcomeType === 'NUMERIC' && ( <Col className="gap-2">
<NumericResolutionOrExpectation {contract.createdTime % 3 == 0 ? (
className="items-center" <SolidPlaneIcon
contract={contract as NumericContract} className={clsx('mx-auto h-6 w-6', `text-${color}`)}
/> />
)} ) : (
<PaperAirplaneIcon className="mx-auto h-6 w-6 text-gray-400" />
)}
{outcomeType === 'BINARY' && (
<BinaryResolutionOrChance
className="items-center"
contract={contract}
/>
)}
{outcomeType === 'NUMERIC' && (
<NumericResolutionOrExpectation
className="items-center"
contract={contract as NumericContract}
/>
)}
{outcomeType === 'FREE_RESPONSE' && (
<FreeResponseResolutionOrChance
className="self-end text-gray-600"
contract={contract as FullContract<DPM, FreeResponse>}
truncate="long"
/>
)}
{contract.createdTime % 3 == 2 ? (
<SolidPlaneIcon
className={clsx('mx-auto h-6 w-6 rotate-180', `text-${color}`)}
/>
) : (
<PaperAirplaneIcon className="mx-auto h-6 w-6 rotate-180 text-gray-400" />
)}
</Col>
</Row> </Row>
{outcomeType === 'FREE_RESPONSE' && (
<FreeResponseResolutionOrChance
className="self-end text-gray-600"
contract={contract as FullContract<DPM, FreeResponse>}
truncate="long"
/>
)}
{/* Show a row with 3 clickable icons: star, upvote, downvote */}
<div className="grid grid-cols-3">
<PaperAirplaneIcon
className={clsx(
'mx-auto h-5 w-5',
contract.createdTime % 3 == 0 ? 'text-primary' : 'text-gray-400'
)}
/>
<StarIcon
className={clsx(
'mx-auto h-5 w-5',
contract.createdTime % 3 == 1 ? 'text-blue-400' : 'text-gray-400'
)}
/>
<PaperAirplaneIcon
className={clsx(
'mx-auto h-5 w-5 rotate-180',
contract.createdTime % 3 == 2 ? 'text-red-400' : 'text-gray-400'
)}
/>
</div>
<div <div
className={clsx( className={clsx(
'absolute right-0 top-0 w-2 rounded-tr-md', 'absolute right-0 top-0 w-2 rounded-tr-md',
@ -269,6 +275,7 @@ export function NumericResolutionOrExpectation(props: {
}) { }) {
const { contract, className } = props const { contract, className } = props
const { resolution } = contract const { resolution } = contract
const textColor = `text-${getColor(contract)}`
const resolutionValue = const resolutionValue =
contract.resolutionValue ?? getValueFromBucket(resolution ?? '', contract) contract.resolutionValue ?? getValueFromBucket(resolution ?? '', contract)
@ -282,10 +289,10 @@ export function NumericResolutionOrExpectation(props: {
</> </>
) : ( ) : (
<> <>
<div className="text-3xl text-blue-400"> <div className={clsx('text-3xl', textColor)}>
{formatLargeNumber(getExpectedValue(contract))} {formatLargeNumber(getExpectedValue(contract))}
</div> </div>
<div className="text-base text-blue-400">expected</div> <div className={clsx('text-base', textColor)}>expected</div>
</> </>
)} )}
</Col> </Col>

View File

@ -5,7 +5,9 @@ import {
PencilIcon, PencilIcon,
CurrencyDollarIcon, CurrencyDollarIcon,
TrendingUpIcon, TrendingUpIcon,
StarIcon,
} from '@heroicons/react/outline' } from '@heroicons/react/outline'
import { StarIcon as SolidStarIcon } from '@heroicons/react/solid'
import { Row } from '../layout/row' import { Row } from '../layout/row'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { UserLink } from '../user-page' import { UserLink } from '../user-page'
@ -26,20 +28,13 @@ import NewContractBadge from '../new-contract-badge'
import { CATEGORY_LIST } from 'common/categories' import { CATEGORY_LIST } from 'common/categories'
import { TagsList } from '../tags-list' import { TagsList } from '../tags-list'
export function AbbrContractDetails(props: { export function MiscDetails(props: {
contract: Contract contract: Contract
showHotVolume?: boolean showHotVolume?: boolean
showCloseTime?: boolean showCloseTime?: boolean
}) { }) {
const { contract, showHotVolume, showCloseTime } = props const { contract, showHotVolume, showCloseTime } = props
const { const { volume, volume24Hours, closeTime, tags } = contract
volume,
volume24Hours,
creatorName,
creatorUsername,
closeTime,
tags,
} = contract
const { volumeLabel } = contractMetrics(contract) const { volumeLabel } = contractMetrics(contract)
// Show at most one category that this contract is tagged by // Show at most one category that this contract is tagged by
const categories = CATEGORY_LIST.filter((category) => const categories = CATEGORY_LIST.filter((category) =>
@ -47,39 +42,68 @@ export function AbbrContractDetails(props: {
).slice(0, 1) ).slice(0, 1)
return ( return (
<Col className={clsx('gap-2 text-sm text-gray-500')}> <Row className="items-center gap-3 text-sm text-gray-400">
{contract.createdTime % 3 == 1 ? (
<SolidStarIcon className="h-6 w-6 text-indigo-600" />
) : (
<StarIcon className="h-6 w-6 text-gray-400" />
)}
{categories.length > 0 && (
<TagsList className="text-gray-400" tags={categories} noLabel />
)}
{showHotVolume ? (
<Row className="gap-0.5">
<TrendingUpIcon className="h-5 w-5" /> {formatMoney(volume24Hours)}
</Row>
) : showCloseTime ? (
<Row className="gap-0.5">
<ClockIcon className="h-5 w-5" />
{(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '}
{fromNow(closeTime || 0)}
</Row>
) : volume > 0 ? (
<Row>{volumeLabel}</Row>
) : (
<NewContractBadge />
)}
</Row>
)
}
export function AvatarDetails(props: { contract: Contract }) {
const { contract } = props
const { creatorName, creatorUsername } = contract
return (
<Row className="items-center gap-2 text-sm text-gray-500">
<Avatar
username={creatorUsername}
avatarUrl={contract.creatorAvatarUrl}
size={6}
/>
<UserLink name={creatorName} username={creatorUsername} />
</Row>
)
}
export function AbbrContractDetails(props: {
contract: Contract
showHotVolume?: boolean
showCloseTime?: boolean
}) {
const { contract, showHotVolume, showCloseTime } = props
return (
<Col className="gap-2">
<Row className="items-center justify-between"> <Row className="items-center justify-between">
<Row className="items-center gap-2"> <AvatarDetails contract={contract} />
<Avatar
username={creatorUsername}
avatarUrl={contract.creatorAvatarUrl}
size={6}
/>
<UserLink name={creatorName} username={creatorUsername} />
</Row>
<Row className="gap-3 text-gray-400"> <MiscDetails
{categories.length > 0 && ( contract={contract}
<TagsList className="text-gray-400" tags={categories} noLabel /> showHotVolume={showHotVolume}
)} showCloseTime={showCloseTime}
/>
{showHotVolume ? (
<Row className="gap-0.5">
<TrendingUpIcon className="h-5 w-5" />{' '}
{formatMoney(volume24Hours)}
</Row>
) : showCloseTime ? (
<Row className="gap-0.5">
<ClockIcon className="h-5 w-5" />
{(closeTime || 0) < Date.now() ? 'Closed' : 'Closes'}{' '}
{fromNow(closeTime || 0)}
</Row>
) : volume > 0 ? (
<Row>{volumeLabel}</Row>
) : (
<NewContractBadge />
)}
</Row>
</Row> </Row>
</Col> </Col>
) )
@ -93,7 +117,7 @@ export function ContractDetails(props: {
}) { }) {
const { contract, bets, isCreator, disabled } = props const { contract, bets, isCreator, disabled } = props
const { closeTime, creatorName, creatorUsername } = contract const { closeTime, creatorName, creatorUsername } = contract
const { volumeLabel, createdDate, resolvedDate } = contractMetrics(contract) const { volumeLabel, resolvedDate } = contractMetrics(contract)
return ( return (
<Row className="flex-1 flex-wrap items-center gap-x-4 gap-y-2 text-sm text-gray-500"> <Row className="flex-1 flex-wrap items-center gap-x-4 gap-y-2 text-sm text-gray-500">