made a custom component, beautiful curve thingy
This commit is contained in:
parent
7e29733144
commit
c8d2e19c3e
|
@ -3,7 +3,7 @@ import { getOutcomeProbability } from 'common/calculate'
|
||||||
import { Pagination } from 'web/components/pagination'
|
import { Pagination } from 'web/components/pagination'
|
||||||
import { FeedBet } from '../feed/feed-bets'
|
import { FeedBet } from '../feed/feed-bets'
|
||||||
import { FeedLiquidity } from '../feed/feed-liquidity'
|
import { FeedLiquidity } from '../feed/feed-liquidity'
|
||||||
import { FeedAnswerCommentGroup } from '../feed/feed-answer-comment-group'
|
import { CommentsAnswer } from '../feed/feed-answer-comment-group'
|
||||||
import { FeedCommentThread, ContractCommentInput } from '../feed/feed-comments'
|
import { FeedCommentThread, ContractCommentInput } from '../feed/feed-comments'
|
||||||
import { groupBy, sortBy, sum } from 'lodash'
|
import { groupBy, sortBy, sum } from 'lodash'
|
||||||
import { Bet } from 'common/bet'
|
import { Bet } from 'common/bet'
|
||||||
|
@ -157,59 +157,22 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (contract.outcomeType === 'FREE_RESPONSE') {
|
if (contract.outcomeType === 'FREE_RESPONSE') {
|
||||||
const sortedAnswers = sortBy(
|
|
||||||
contract.answers,
|
|
||||||
(a) => -getOutcomeProbability(contract, a.id)
|
|
||||||
)
|
|
||||||
const commentsByOutcome = groupBy(
|
|
||||||
sortedComments,
|
|
||||||
(c) => c.answerOutcome ?? c.betOutcome ?? '_'
|
|
||||||
)
|
|
||||||
// const generalTopLevelComments = topLevelComments.filter(
|
|
||||||
// (c) => c.answerOutcome === undefined && c.betId === undefined
|
|
||||||
// )
|
|
||||||
// console.log('answer: ', sortedAnswers)
|
|
||||||
// console.log('comments by outcome:', commentsByOutcome)
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{sortRow}
|
{sortRow}
|
||||||
<ContractCommentInput className="mb-5" contract={contract} />
|
<ContractCommentInput className="mb-5" contract={contract} />
|
||||||
{topLevelComments.map((parent) => {
|
{topLevelComments.map((parent) => {
|
||||||
if (parent.answerOutcome != undefined) {
|
if (parent.answerOutcome != undefined) {
|
||||||
const answer = sortedAnswers.find(
|
const answer = contract.answers.find(
|
||||||
(answer) => answer.id === parent.answerOutcome
|
(answer) => answer.id === parent.answerOutcome
|
||||||
)
|
)
|
||||||
if (answer === undefined) {
|
if (answer === undefined) {
|
||||||
console.error('Could not find answer that matches ID')
|
console.error('Could not find answer that matches ID')
|
||||||
return <></>
|
return <></>
|
||||||
} else {
|
} else {
|
||||||
const { username, avatarUrl, name, text } = answer
|
|
||||||
const answerElementId = `answer-${answer.id}`
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Row className="bg-greyscale-2 w-fit gap-1 rounded-t-xl rounded-bl-xl px-2 py-2">
|
<CommentsAnswer answer={answer} contract={contract} />
|
||||||
<div className="ml-2">
|
|
||||||
<Avatar
|
|
||||||
username={username}
|
|
||||||
avatarUrl={avatarUrl}
|
|
||||||
size="xxs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Col>
|
|
||||||
<Row className="gap-1">
|
|
||||||
<div className="text-greyscale-6 text-xs">
|
|
||||||
<UserLink username={username} name={name} /> answered
|
|
||||||
<CopyLinkDateTimeComponent
|
|
||||||
prefix={contract.creatorUsername}
|
|
||||||
slug={contract.slug}
|
|
||||||
createdTime={answer.createdTime}
|
|
||||||
elementId={answerElementId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
<div className="text-greyscale-7 text-sm">{text}</div>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
<Row>
|
||||||
<div className="ml-2">
|
<div className="ml-2">
|
||||||
<Curve size={28} strokeWidth={1} color="#B1B1C7" />
|
<Curve size={28} strokeWidth={1} color="#B1B1C7" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Answer } from 'common/answer'
|
import { Answer } from 'common/answer'
|
||||||
import { FreeResponseContract } from 'common/contract'
|
import { Contract, FreeResponseContract } from 'common/contract'
|
||||||
import { ContractComment } from 'common/comment'
|
import { ContractComment } from 'common/comment'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { Col } from 'web/components/layout/col'
|
import { Col } from 'web/components/layout/col'
|
||||||
|
@ -20,40 +20,17 @@ import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon'
|
||||||
import { ReplyToggle } from '../comments/comments'
|
import { ReplyToggle } from '../comments/comments'
|
||||||
import { ReplyIcon } from '@heroicons/react/solid'
|
import { ReplyIcon } from '@heroicons/react/solid'
|
||||||
|
|
||||||
export function FeedAnswerCommentGroup(props: {
|
export function CommentsAnswer(props: { answer: Answer; contract: Contract }) {
|
||||||
contract: FreeResponseContract
|
const { answer, contract } = props
|
||||||
answer: Answer
|
|
||||||
answerComments: ContractComment[]
|
|
||||||
tips: CommentTipMap
|
|
||||||
}) {
|
|
||||||
const { answer, contract, answerComments, tips } = props
|
|
||||||
const { username, avatarUrl, name, text } = answer
|
const { username, avatarUrl, name, text } = answer
|
||||||
|
|
||||||
const [seeReplies, setSeeReplies] = useState(false)
|
|
||||||
|
|
||||||
const [replyTo, setReplyTo] = useState<ReplyTo>()
|
|
||||||
const router = useRouter()
|
|
||||||
const answerElementId = `answer-${answer.id}`
|
const answerElementId = `answer-${answer.id}`
|
||||||
const highlighted = router.asPath.endsWith(`#${answerElementId}`)
|
|
||||||
const answerRef = useRef<HTMLDivElement>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (highlighted && answerRef.current != null) {
|
|
||||||
answerRef.current.scrollIntoView(true)
|
|
||||||
}
|
|
||||||
}, [highlighted])
|
|
||||||
return (
|
return (
|
||||||
<Col className="relative flex-1 items-stretch gap-3">
|
<Row className="bg-greyscale-2 w-fit gap-1 rounded-t-xl rounded-bl-xl px-2 py-2">
|
||||||
<Row
|
<div className="ml-2">
|
||||||
className={clsx(
|
<Avatar username={username} avatarUrl={avatarUrl} size="xxs" />
|
||||||
'gap- space-x-3 pt-4 transition-all duration-1000',
|
</div>
|
||||||
highlighted ? `-m-2 my-3 rounded bg-indigo-500/[0.2] p-2` : ''
|
<Col>
|
||||||
)}
|
<Row className="gap-1">
|
||||||
ref={answerRef}
|
|
||||||
id={answerElementId}
|
|
||||||
>
|
|
||||||
<Avatar username={username} avatarUrl={avatarUrl} size="sm" />
|
|
||||||
<Col className="min-w-0 flex-1">
|
|
||||||
<div className="text-greyscale-6 text-xs">
|
<div className="text-greyscale-6 text-xs">
|
||||||
<UserLink username={username} name={name} /> answered
|
<UserLink username={username} name={name} /> answered
|
||||||
<CopyLinkDateTimeComponent
|
<CopyLinkDateTimeComponent
|
||||||
|
@ -63,70 +40,9 @@ export function FeedAnswerCommentGroup(props: {
|
||||||
elementId={answerElementId}
|
elementId={answerElementId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* <Row className="align-items justify-between gap-2 sm:flex-row"> */}
|
|
||||||
<span className="text-md whitespace-pre-line">
|
|
||||||
<Linkify text={text} />
|
|
||||||
</span>
|
|
||||||
{/* <div>
|
|
||||||
<button
|
|
||||||
className="text-xs font-bold text-gray-500 hover:underline"
|
|
||||||
onClick={() =>
|
|
||||||
setReplyTo({ id: answer.id, username: answer.username })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Reply
|
|
||||||
</button>
|
|
||||||
</div> */}
|
|
||||||
{/* </Row> */}
|
|
||||||
<Row className="w-full">
|
|
||||||
<ReplyToggle
|
|
||||||
seeReplies={seeReplies}
|
|
||||||
numComments={answerComments.length}
|
|
||||||
onClick={() => setSeeReplies(!seeReplies)}
|
|
||||||
/>
|
|
||||||
<div className="justify-self-end">
|
|
||||||
<button
|
|
||||||
className="text-greyscale-5"
|
|
||||||
onClick={() =>
|
|
||||||
setReplyTo({ id: answer.id, username: answer.username })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ReplyIcon className="h-5 w-5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Row>
|
</Row>
|
||||||
|
<div className="text-greyscale-7 text-sm">{text}</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{seeReplies && (
|
|
||||||
<Col className="w-full gap-3 pl-1">
|
|
||||||
{answerComments.map((comment) => (
|
|
||||||
<FeedComment
|
|
||||||
key={comment.id}
|
|
||||||
indent={true}
|
|
||||||
contract={contract}
|
|
||||||
comment={comment}
|
|
||||||
tips={tips[comment.id] ?? {}}
|
|
||||||
onReplyClick={() =>
|
|
||||||
setReplyTo({ id: comment.id, username: comment.userUsername })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
{replyTo && (
|
|
||||||
<div className="relative ml-7">
|
|
||||||
<span
|
|
||||||
className="bg-greyscale-2 absolute -left-1 -ml-[1px] mt-[1.25rem] h-2 w-0.5 rotate-90"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
<ContractCommentInput
|
|
||||||
contract={contract}
|
|
||||||
parentAnswerOutcome={answer.number.toString()}
|
|
||||||
replyTo={replyTo}
|
|
||||||
onSubmitComment={() => setReplyTo(undefined)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
19
web/public/custom-components/curve.tsx
Normal file
19
web/public/custom-components/curve.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export default function Curve({
|
||||||
|
size = 24,
|
||||||
|
color = '#B1B1C7',
|
||||||
|
strokeWidth = 2,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
fill="none"
|
||||||
|
stroke={color}
|
||||||
|
stroke-width={strokeWidth}
|
||||||
|
>
|
||||||
|
<path d="M5.02,0V5.24c0,4.3,3.49,7.79,7.79,7.79h5.2" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user