Merge branch 'main' into categories

This commit is contained in:
mantikoros 2022-05-02 13:53:32 -04:00
commit 1d600037db
16 changed files with 145 additions and 56 deletions

View File

@ -56,7 +56,9 @@ export function AddLiquidityPanel(props: { contract: Contract }) {
return ( return (
<> <>
<div>Subsidize this market by adding liquidity for traders.</div> <div className="text-gray-500">
Subsidize this market by adding liquidity for traders.
</div>
<Row> <Row>
<AmountInput <AmountInput

View File

@ -45,7 +45,7 @@ export function AmountInput(props: {
<span className="bg-gray-200 text-sm">{label}</span> <span className="bg-gray-200 text-sm">{label}</span>
<input <input
className={clsx( className={clsx(
'input input-bordered', 'input input-bordered max-w-[200px] text-lg',
error && 'input-error', error && 'input-error',
inputClassName inputClassName
)} )}

View File

@ -116,7 +116,7 @@ export function AnswerBetPanel(props: {
</Row> </Row>
<div className="my-3 text-left text-sm text-gray-500">Amount </div> <div className="my-3 text-left text-sm text-gray-500">Amount </div>
<BuyAmountInput <BuyAmountInput
inputClassName="w-full" inputClassName="w-full max-w-none"
amount={betAmount} amount={betAmount}
onChange={setBetAmount} onChange={setBetAmount}
error={error} error={error}

View File

@ -62,7 +62,7 @@ export function BetPanel(props: {
className className
)} )}
> >
<div className="mb-6 text-2xl text-gray-700">Place a trade</div> <div className="mb-6 text-2xl">Place your bet</div>
{/* <Title className={clsx('!mt-0 text-neutral')} text="Place a trade" /> */} {/* <Title className={clsx('!mt-0 text-neutral')} text="Place a trade" /> */}
<BuyPanel contract={contract} user={user} userBets={userBets ?? []} /> <BuyPanel contract={contract} user={user} userBets={userBets ?? []} />
@ -125,6 +125,7 @@ export function BetPanelSwitcher(props: {
<BinaryOutcomeLabel outcome={sharesOutcome} /> shares <BinaryOutcomeLabel outcome={sharesOutcome} /> shares
</div> </div>
{tradeType === 'BUY' && (
<button <button
className="btn btn-sm" className="btn btn-sm"
style={{ style={{
@ -133,11 +134,14 @@ export function BetPanelSwitcher(props: {
color: '#3D4451', color: '#3D4451',
}} }}
onClick={() => onClick={() =>
tradeType === 'BUY' ? setTradeType('SELL') : setTradeType('BUY') tradeType === 'BUY'
? setTradeType('SELL')
: setTradeType('BUY')
} }
> >
{tradeType === 'BUY' ? 'Sell' : 'Bet'} {tradeType === 'BUY' ? 'Sell' : 'Bet'}
</button> </button>
)}
</Row> </Row>
</Col> </Col>
)} )}
@ -299,7 +303,7 @@ function BuyPanel(props: {
/> />
<div className="my-3 text-left text-sm text-gray-500">Amount</div> <div className="my-3 text-left text-sm text-gray-500">Amount</div>
<BuyAmountInput <BuyAmountInput
inputClassName="w-full" inputClassName="w-full max-w-none"
amount={betAmount} amount={betAmount}
onChange={onBetChange} onChange={onBetChange}
error={error} error={error}

View File

@ -3,6 +3,7 @@ import _ from 'lodash'
import Link from 'next/link' import Link from 'next/link'
import { Charity } from '../../../common/charity' import { Charity } from '../../../common/charity'
import { useCharityTxns } from '../../hooks/use-charity-txns' import { useCharityTxns } from '../../hooks/use-charity-txns'
import { manaToUSD } from '../../pages/charity/[charitySlug]'
import { Row } from '../layout/row' import { Row } from '../layout/row'
export function CharityCard(props: { charity: Charity }) { export function CharityCard(props: { charity: Charity }) {
@ -31,7 +32,9 @@ export function CharityCard(props: { charity: Charity }) {
{raised > 0 && ( {raised > 0 && (
<Row className="text-primary mt-4 flex-1 items-end justify-center gap-2"> <Row className="text-primary mt-4 flex-1 items-end justify-center gap-2">
<span className="text-3xl"> <span className="text-3xl">
${Math.floor((raised ?? 0) / 100)} {raised < 100
? manaToUSD(raised)
: '$' + Math.floor(raised / 100)}
</span> </span>
<span>raised</span> <span>raised</span>
</Row> </Row>

View File

@ -0,0 +1,34 @@
import { Txn } from '../../../common/txn'
import { Avatar } from '../avatar'
import { useUserById } from '../../hooks/use-users'
import { UserLink } from '../user-page'
import { manaToUSD } from '../../pages/charity/[charitySlug]'
import { RelativeTimestamp } from '../feed/feed-items'
export function Donation(props: { txn: Txn }) {
const { txn } = props
const user = useUserById(txn.fromId)
if (!user) {
return <>Loading...</>
}
return (
<div className="mb-2 flow-root pr-2 md:pr-0">
<div className="relative flex items-center space-x-3">
<Avatar username={user.name} avatarUrl={user.avatarUrl} size="sm" />
<div className="min-w-0 flex-1">
<p className="mt-0.5 text-sm text-gray-500">
<UserLink
className="text-gray-500"
username={user.username}
name={user.name}
/>{' '}
donated {manaToUSD(txn.amount)}
<RelativeTimestamp time={txn.createdTime} />
</p>
</div>
</div>
</div>
)
}

View File

@ -50,7 +50,19 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
<Col className="gap-4 rounded bg-white p-6"> <Col className="gap-4 rounded bg-white p-6">
<Title className="!mt-0 !mb-0" text="Market info" /> <Title className="!mt-0 !mb-0" text="Market info" />
<div className="text-gray-500">Stats</div> <div>Share</div>
<Row className="justify-start gap-4">
<CopyLinkButton contract={contract} />
<TweetButton
className="self-start"
tweetText={getTweetText(contract, false)}
/>
<ShareEmbedButton contract={contract} />
</Row>
<div />
<div>Stats</div>
<table className="table-compact table-zebra table w-full text-gray-500"> <table className="table-compact table-zebra table w-full text-gray-500">
<tbody> <tbody>
{category && ( {category && (
@ -105,19 +117,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
</tbody> </tbody>
</table> </table>
<div className="text-gray-500">Share</div> <div>Tags</div>
<Row className="justify-start gap-4">
<CopyLinkButton contract={contract} />
<TweetButton
className="self-start"
tweetText={getTweetText(contract, false)}
/>
<ShareEmbedButton contract={contract} />
</Row>
<div />
<div className="text-gray-500">Tags</div>
<TagsInput contract={contract} /> <TagsInput contract={contract} />
<div /> <div />
@ -125,7 +125,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
!contract.resolution && !contract.resolution &&
(!closeTime || closeTime > Date.now()) && ( (!closeTime || closeTime > Date.now()) && (
<> <>
<div className="text-gray-500">Add liquidity</div> <div className="">Add liquidity</div>
<AddLiquidityPanel contract={contract} /> <AddLiquidityPanel contract={contract} />
</> </>
)} )}

View File

@ -17,6 +17,7 @@ import { AnswersGraph } from '../answers/answers-graph'
import { DPM, FreeResponse, FullContract } from '../../../common/contract' import { DPM, FreeResponse, FullContract } from '../../../common/contract'
import { ContractDescription } from './contract-description' import { ContractDescription } from './contract-description'
import { ContractDetails } from './contract-details' import { ContractDetails } from './contract-details'
import { ShareMarket } from '../share-market'
export const ContractOverview = (props: { export const ContractOverview = (props: {
contract: Contract contract: Contract
@ -84,7 +85,9 @@ export const ContractOverview = (props: {
/> />
)} )}
{contract.description && <Spacer h={6} />} {(contract.description || isCreator) && <Spacer h={6} />}
{isCreator && <ShareMarket className="px-2" contract={contract} />}
<ContractDescription <ContractDescription
className="px-2" className="px-2"

View File

@ -1,6 +1,7 @@
import { Fragment } from 'react' import { Fragment } from 'react'
import { LinkIcon } from '@heroicons/react/outline' import { LinkIcon } from '@heroicons/react/outline'
import { Menu, Transition } from '@headlessui/react' import { Menu, Transition } from '@headlessui/react'
import clsx from 'clsx'
import { Contract } from '../../common/contract' import { Contract } from '../../common/contract'
import { copyToClipboard } from '../lib/util/copy' import { copyToClipboard } from '../lib/util/copy'
import { contractPath } from '../lib/firebase/contracts' import { contractPath } from '../lib/firebase/contracts'
@ -10,8 +11,11 @@ function copyContractUrl(contract: Contract) {
copyToClipboard(`https://${ENV_CONFIG.domain}${contractPath(contract)}`) copyToClipboard(`https://${ENV_CONFIG.domain}${contractPath(contract)}`)
} }
export function CopyLinkButton(props: { contract: Contract }) { export function CopyLinkButton(props: {
const { contract } = props contract: Contract
buttonClassName?: string
}) {
const { contract, buttonClassName } = props
return ( return (
<Menu <Menu
@ -20,12 +24,10 @@ export function CopyLinkButton(props: { contract: Contract }) {
onMouseUp={() => copyContractUrl(contract)} onMouseUp={() => copyContractUrl(contract)}
> >
<Menu.Button <Menu.Button
className="btn btn-xs normal-case" className={clsx(
style={{ 'btn btn-xs border-2 border-green-600 bg-white normal-case text-green-600 hover:border-green-600 hover:bg-white',
backgroundColor: 'white', buttonClassName
border: '2px solid #16A34A', )}
color: '#16A34A', // text-green-600
}}
> >
<LinkIcon className="mr-1.5 h-4 w-4" aria-hidden="true" /> <LinkIcon className="mr-1.5 h-4 w-4" aria-hidden="true" />
Copy link Copy link

View File

@ -310,7 +310,7 @@ export function CommentInput(props: {
) )
} }
function RelativeTimestamp(props: { time: number }) { export function RelativeTimestamp(props: { time: number }) {
const { time } = props const { time } = props
return ( return (
<DateTimeTooltip time={time}> <DateTimeTooltip time={time}>
@ -385,6 +385,7 @@ export function FeedBet(props: {
async function submitComment() { async function submitComment() {
if (!user || !comment || !canComment) return if (!user || !comment || !canComment) return
await createComment(contract.id, comment, user, id) await createComment(contract.id, comment, user, id)
setComment('')
} }
const bought = amount >= 0 ? 'bought' : 'sold' const bought = amount >= 0 ? 'bought' : 'sold'

View File

@ -1,3 +1,4 @@
import clsx from 'clsx'
import { Answer } from '../../common/answer' import { Answer } from '../../common/answer'
import { getProbability } from '../../common/calculate' import { getProbability } from '../../common/calculate'
import { import {
@ -126,7 +127,14 @@ export function AnswerLabel(props: {
truncated = text.slice(0, 75) + '...' truncated = text.slice(0, 75) + '...'
} }
return <span className={className}>{truncated}</span> return (
<span
style={{ wordBreak: 'break-word' }}
className={clsx('whitespace-pre-line break-words', className)}
>
{truncated}
</span>
)
} }
function FreeResponseAnswerToolTip(props: { function FreeResponseAnswerToolTip(props: {

View File

@ -72,9 +72,9 @@ export function ResolutionPanel(props: {
return ( return (
<Col className={clsx('rounded-md bg-white px-8 py-6', className)}> <Col className={clsx('rounded-md bg-white px-8 py-6', className)}>
<Title className="!mt-0 whitespace-nowrap" text="Resolve market" /> <div className="mb-6 whitespace-nowrap text-2xl">Resolve market</div>
<div className="mb-2 text-sm text-gray-500">Outcome</div> <div className="mb-3 text-sm text-gray-500">Outcome</div>
<YesNoCancelSelector <YesNoCancelSelector
className="mx-auto my-2" className="mx-auto my-2"

View File

@ -0,0 +1,26 @@
import clsx from 'clsx'
import { Contract, contractUrl } from '../lib/firebase/contracts'
import { CopyLinkButton } from './copy-link-button'
import { Col } from './layout/col'
import { Row } from './layout/row'
export function ShareMarket(props: { contract: Contract; className?: string }) {
const { contract, className } = props
return (
<Col className={clsx(className, 'gap-3')}>
<div>Share your market</div>
<Row className="mb-6 items-center">
<input
className="input input-bordered flex-1 rounded-r-none text-gray-500"
type="text"
value={contractUrl(contract)}
/>
<CopyLinkButton
contract={contract}
buttonClassName="btn-md rounded-l-none"
/>
</Row>
</Col>
)
}

View File

@ -26,10 +26,8 @@ export const useSaveShares = (
_.sumBy(noBets, (bet) => bet.shares), _.sumBy(noBets, (bet) => bet.shares),
] ]
const [yesFloorShares, noFloorShares] = [ const yesFloorShares = Math.round(yesShares) === 0 ? 0 : Math.floor(yesShares)
Math.floor(yesShares), const noFloorShares = Math.round(noShares) === 0 ? 0 : Math.floor(noShares)
Math.floor(noShares),
]
useEffect(() => { useEffect(() => {
// Save yes and no shares to local storage. // Save yes and no shares to local storage.

View File

@ -26,6 +26,7 @@ import { DAY_MS } from '../../../common/util/time'
import { MAX_FEED_CONTRACTS } from '../../../common/recommended-contracts' import { MAX_FEED_CONTRACTS } from '../../../common/recommended-contracts'
import { Bet } from '../../../common/bet' import { Bet } from '../../../common/bet'
import { Comment } from '../../../common/comment' import { Comment } from '../../../common/comment'
import { ENV_CONFIG } from '../../../common/envs/constants'
export type { Contract } export type { Contract }
export function contractPath(contract: Contract) { export function contractPath(contract: Contract) {
@ -36,6 +37,10 @@ export function homeContractPath(contract: Contract) {
return `/home?c=${contract.slug}` return `/home?c=${contract.slug}`
} }
export function contractUrl(contract: Contract) {
return `https://${ENV_CONFIG.domain}${contractPath(contract)}`
}
export function contractMetrics(contract: Contract) { export function contractMetrics(contract: Contract) {
const { createdTime, resolutionTime, isResolved } = contract const { createdTime, resolutionTime, isResolved } = contract

View File

@ -17,8 +17,9 @@ import Custom404 from '../404'
import { useCharityTxns } from '../../hooks/use-charity-txns' import { useCharityTxns } from '../../hooks/use-charity-txns'
import { useWindowSize } from '../../hooks/use-window-size' import { useWindowSize } from '../../hooks/use-window-size'
import Confetti from 'react-confetti' import Confetti from 'react-confetti'
import { Donation } from '../../components/charity/feed-items'
const manaToUSD = (mana: number) => export const manaToUSD = (mana: number) =>
(mana / 100).toLocaleString('en-US', { style: 'currency', currency: 'USD' }) (mana / 100).toLocaleString('en-US', { style: 'currency', currency: 'USD' })
export default function CharityPageWrapper() { export default function CharityPageWrapper() {
@ -91,6 +92,9 @@ function CharityPage(props: { charity: Charity }) {
</Row> </Row>
<h2 className="mt-7 mb-2 text-xl text-indigo-700">About</h2> <h2 className="mt-7 mb-2 text-xl text-indigo-700">About</h2>
<Blurb text={description} /> <Blurb text={description} />
{txns.map((txn) => (
<Donation key={txn.id} txn={txn} />
))}
</Col> </Col>
</Col> </Col>
</Page> </Page>
@ -98,8 +102,7 @@ function CharityPage(props: { charity: Charity }) {
} }
function Blurb({ text }: { text: string }) { function Blurb({ text }: { text: string }) {
// Default to open for now (aka don't actually hide any text yet.) const [open, setOpen] = useState(false)
const [open, setOpen] = useState(true)
// Calculate whether the full blurb is already shown // Calculate whether the full blurb is already shown
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
@ -125,7 +128,7 @@ function Blurb({ text }: { text: string }) {
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
className={clsx( className={clsx(
'btn btn-link capitalize-none my-3 normal-case text-indigo-700', 'btn btn-link capitalize-none my-3 normal-case text-indigo-700',
hideExpander && 'hidden' hideExpander && 'invisible'
)} )}
> >
{open ? 'Hide' : 'Read more'} {open ? 'Hide' : 'Read more'}
@ -204,7 +207,7 @@ function DonationBox(props: {
Amount Amount
</label> </label>
<BuyAmountInput <BuyAmountInput
inputClassName="w-full donate-input" inputClassName="w-full max-w-none donate-input"
amount={amount} amount={amount}
onChange={setAmount} onChange={setAmount}
error={error} error={error}