>()
@@ -101,7 +100,7 @@ export const DistributionChart = (props: {
px={px}
py0={py0}
py1={py1}
- curve={curve ?? curveLinear}
+ curve={curveLinear}
/>
)
@@ -114,12 +113,11 @@ export const MultiValueHistoryChart =
(props: {
colors: readonly string[]
xScale: ScaleTime
yScale: ScaleContinuousNumeric
- curve?: CurveFactory
onMouseOver?: (p: P | undefined) => void
Tooltip?: TooltipComponent
pct?: boolean
}) => {
- const { colors, data, yScale, w, h, curve, Tooltip, pct } = props
+ const { colors, data, yScale, w, h, Tooltip, pct } = props
const [viewXScale, setViewXScale] = useState>()
const xScale = viewXScale ?? props.xScale
@@ -179,7 +177,7 @@ export const MultiValueHistoryChart = (props: {
px={px}
py0={py0}
py1={py1}
- curve={curve ?? curveLinear}
+ curve={curveStepAfter}
fill={colors[i]}
/>
))}
@@ -194,12 +192,11 @@ export const SingleValueHistoryChart =
(props: {
color: string
xScale: ScaleTime
yScale: ScaleContinuousNumeric
- curve?: CurveFactory
onMouseOver?: (p: P | undefined) => void
Tooltip?: TooltipComponent
pct?: boolean
}) => {
- const { color, data, yScale, w, h, curve, Tooltip, pct } = props
+ const { color, data, yScale, w, h, Tooltip, pct } = props
const [viewXScale, setViewXScale] = useState>()
const xScale = viewXScale ?? props.xScale
@@ -249,7 +246,7 @@ export const SingleValueHistoryChart = (props: {
px={px}
py0={py0}
py1={py1}
- curve={curve ?? curveLinear}
+ curve={curveStepAfter}
/>
)
diff --git a/web/components/charts/helpers.tsx b/web/components/charts/helpers.tsx
index b40ab7db..96115dc0 100644
--- a/web/components/charts/helpers.tsx
+++ b/web/components/charts/helpers.tsx
@@ -10,7 +10,7 @@ import {
import { pointer, select } from 'd3-selection'
import { Axis, AxisScale } from 'd3-axis'
import { brushX, D3BrushEvent } from 'd3-brush'
-import { area, line, CurveFactory } from 'd3-shape'
+import { area, line, curveStepAfter, CurveFactory } from 'd3-shape'
import { nanoid } from 'nanoid'
import dayjs from 'dayjs'
import clsx from 'clsx'
@@ -73,11 +73,11 @@ const LinePathInternal =
(
data: P[]
px: number | ((p: P) => number)
py: number | ((p: P) => number)
- curve: CurveFactory
+ curve?: CurveFactory
} & SVGProps
) => {
const { data, px, py, curve, ...rest } = props
- const d3Line = line(px, py).curve(curve)
+ const d3Line = line
(px, py).curve(curve ?? curveStepAfter)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return
}
@@ -89,11 +89,11 @@ const AreaPathInternal =
(
px: number | ((p: P) => number)
py0: number | ((p: P) => number)
py1: number | ((p: P) => number)
- curve: CurveFactory
+ curve?: CurveFactory
} & SVGProps
) => {
const { data, px, py0, py1, curve, ...rest } = props
- const d3Area = area(px, py0, py1).curve(curve)
+ const d3Area = area
(px, py0, py1).curve(curve ?? curveStepAfter)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return
}
@@ -105,7 +105,7 @@ export const AreaWithTopStroke =
(props: {
px: number | ((p: P) => number)
py0: number | ((p: P) => number)
py1: number | ((p: P) => number)
- curve: CurveFactory
+ curve?: CurveFactory
}) => {
const { color, data, px, py0, py1, curve } = props
return (
diff --git a/web/components/charts/stats.tsx b/web/components/charts/stats.tsx
deleted file mode 100644
index a630657a..00000000
--- a/web/components/charts/stats.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { useMemo } from 'react'
-import { scaleTime, scaleLinear } from 'd3-scale'
-import { min, max } from 'lodash'
-import dayjs from 'dayjs'
-
-import { formatPercent } from 'common/util/format'
-import { Row } from '../layout/row'
-import { HistoryPoint, SingleValueHistoryChart } from './generic-charts'
-import { TooltipProps, MARGIN_X, MARGIN_Y } from './helpers'
-import { SizedContainer } from 'web/components/sized-container'
-
-const getPoints = (startDate: number, dailyValues: number[]) => {
- const startDateDayJs = dayjs(startDate)
- return dailyValues.map((y, i) => ({
- x: startDateDayJs.add(i, 'day').toDate(),
- y: y,
- }))
-}
-
-const DailyCountTooltip = (props: TooltipProps) => {
- const { data, mouseX, xScale } = props
- const d = xScale.invert(mouseX)
- return (
-
- {dayjs(d).format('MMM DD')}
- {data.y}
-
- )
-}
-
-const DailyPercentTooltip = (props: TooltipProps) => {
- const { data, mouseX, xScale } = props
- const d = xScale.invert(mouseX)
- return (
-
- {dayjs(d).format('MMM DD')}
- {formatPercent(data.y)}
-
- )
-}
-
-export function DailyChart(props: {
- startDate: number
- dailyValues: number[]
- excludeFirstDays?: number
- pct?: boolean
-}) {
- const { dailyValues, startDate, excludeFirstDays, pct } = props
-
- const data = useMemo(
- () => getPoints(startDate, dailyValues).slice(excludeFirstDays ?? 0),
- [startDate, dailyValues, excludeFirstDays]
- )
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const minDate = min(data.map((d) => d.x))!
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const maxDate = max(data.map((d) => d.x))!
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const maxValue = max(data.map((d) => d.y))!
- return (
-
- {(width, height) => (
-
- )}
-
- )
-}
diff --git a/web/components/contract/contract-card.tsx b/web/components/contract/contract-card.tsx
index 4b4a32b6..a8caf7bd 100644
--- a/web/components/contract/contract-card.tsx
+++ b/web/components/contract/contract-card.tsx
@@ -393,9 +393,7 @@ export function ContractCardProbChange(props: {
noLinkAvatar?: boolean
className?: string
}) {
- const { noLinkAvatar, className } = props
- const contract = useContractWithPreload(props.contract) as CPMMBinaryContract
-
+ const { contract, noLinkAvatar, className } = props
return (
(
@@ -48,18 +49,32 @@ const SizedContractChart = (props: {
fullHeight: number
mobileHeight: number
}) => {
- const { fullHeight, mobileHeight, contract, bets } = props
+ const { contract, bets, fullHeight, mobileHeight } = props
+ const containerRef = useRef(null)
+ const [chartWidth, setChartWidth] = useState()
+ const [chartHeight, setChartHeight] = useState()
+ useEffect(() => {
+ const handleResize = () => {
+ setChartHeight(window.innerWidth < 800 ? mobileHeight : fullHeight)
+ setChartWidth(containerRef.current?.clientWidth)
+ }
+ handleResize()
+ window.addEventListener('resize', handleResize)
+ return () => {
+ window.removeEventListener('resize', handleResize)
+ }
+ }, [fullHeight, mobileHeight])
return (
-
- {(width, height) => (
+
+ {chartWidth != null && chartHeight != null && (
)}
-
+
)
}
@@ -99,11 +114,7 @@ const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => {
-
+
('Newest')
const me = useUser()
-
if (comments == null) {
return
}
-
- const tipsOrBountiesAwarded =
- Object.keys(tips).length > 0 || comments.some((c) => c.bountiesAwarded)
-
- const sortedComments = sortBy(comments, (c) =>
- sort === 'Newest'
- ? c.createdTime
- : // Is this too magic? If there are tips/bounties, 'Best' shows your own comments made within the last 10 minutes first, then sorts by score
- tipsOrBountiesAwarded &&
- c.createdTime > Date.now() - 10 * MINUTE_MS &&
- c.userId === me?.id
- ? -Infinity
- : -((c.bountiesAwarded ?? 0) + sum(Object.values(tips[c.id] ?? [])))
- )
-
- const commentsByParent = groupBy(
- sortedComments,
- (c) => c.replyToCommentId ?? '_'
- )
- const topLevelComments = commentsByParent['_'] ?? []
- // Top level comments are reverse-chronological, while replies are chronological
- if (sort === 'Newest') topLevelComments.reverse()
-
if (contract.outcomeType === 'FREE_RESPONSE') {
+ const generalComments = comments.filter(
+ (c) => c.answerOutcome === undefined && c.betId === undefined
+ )
const sortedAnswers = sortBy(
contract.answers,
(a) => -getOutcomeProbability(contract, a.id)
@@ -113,9 +92,6 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
comments,
(c) => c.answerOutcome ?? c.betOutcome ?? '_'
)
- const generalTopLevelComments = topLevelComments.filter(
- (c) => c.answerOutcome === undefined && c.betId === undefined
- )
return (
<>
{sortedAnswers.map((answer) => (
@@ -139,12 +115,12 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
General Comments
- {generalTopLevelComments.map((comment) => (
+ {generalComments.map((comment) => (
))}
@@ -152,6 +128,24 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
>
)
} else {
+ const tipsOrBountiesAwarded =
+ Object.keys(tips).length > 0 || comments.some((c) => c.bountiesAwarded)
+
+ const commentsByParent = groupBy(
+ sortBy(comments, (c) =>
+ sort === 'Newest'
+ ? -c.createdTime
+ : // Is this too magic? If there are tips/bounties, 'Best' shows your own comments made within the last 10 minutes first, then sorts by score
+ tipsOrBountiesAwarded &&
+ c.createdTime > Date.now() - 10 * MINUTE_MS &&
+ c.userId === me?.id
+ ? -Infinity
+ : -((c.bountiesAwarded ?? 0) + sum(Object.values(tips[c.id] ?? [])))
+ ),
+ (c) => c.replyToCommentId ?? '_'
+ )
+
+ const topLevelComments = commentsByParent['_'] ?? []
return (
<>
diff --git a/web/components/sized-container.tsx b/web/components/sized-container.tsx
deleted file mode 100644
index 26532047..00000000
--- a/web/components/sized-container.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { ReactNode, useEffect, useRef, useState } from 'react'
-
-export const SizedContainer = (props: {
- fullHeight: number
- mobileHeight: number
- mobileThreshold?: number
- children: (width: number, height: number) => ReactNode
-}) => {
- const { children, fullHeight, mobileHeight } = props
- const threshold = props.mobileThreshold ?? 800
- const containerRef = useRef(null)
- const [width, setWidth] = useState()
- const [height, setHeight] = useState()
- useEffect(() => {
- if (containerRef.current) {
- const handleResize = () => {
- setHeight(window.innerWidth <= threshold ? mobileHeight : fullHeight)
- setWidth(containerRef.current?.clientWidth)
- }
- handleResize()
- const resizeObserver = new ResizeObserver(handleResize)
- resizeObserver.observe(containerRef.current)
- window.addEventListener('resize', handleResize)
- return () => {
- window.removeEventListener('resize', handleResize)
- resizeObserver.disconnect()
- }
- }
- }, [threshold, fullHeight, mobileHeight])
- return (
-
- {width != null && height != null && children(width, height)}
-
- )
-}
diff --git a/web/pages/cowp.tsx b/web/pages/cowp.tsx
index a854f141..21494c37 100644
--- a/web/pages/cowp.tsx
+++ b/web/pages/cowp.tsx
@@ -11,7 +11,7 @@ const App = () => {
url="/cowp"
/>
-
+
)
diff --git a/web/pages/labs/index.tsx b/web/pages/labs/index.tsx
index 79f44a64..bd1dbb35 100644
--- a/web/pages/labs/index.tsx
+++ b/web/pages/labs/index.tsx
@@ -16,7 +16,7 @@ export default function LabsPage() {
url="/labs"
/>
-
+
),
},
{
title: 'Daily (7d avg)',
content: (
-
),
},
{
title: 'Weekly',
content: (
-
),
},
{
title: 'Monthly',
content: (
-
),
},
@@ -142,44 +149,44 @@ export function CustomAnalytics(props: Stats) {
{
title: 'D1',
content: (
-
),
},
{
title: 'D1 (7d avg)',
content: (
-
),
},
{
title: 'W1',
content: (
-
),
},
{
title: 'M1',
content: (
-
),
},
@@ -200,33 +207,33 @@ export function CustomAnalytics(props: Stats) {
{
title: 'ND1',
content: (
-
),
},
{
title: 'ND1 (7d avg)',
content: (
-
),
},
{
title: 'NW1',
content: (
-
),
},
@@ -242,31 +249,41 @@ export function CustomAnalytics(props: Stats) {
{
title: capitalize(PAST_BETS),
content: (
-
+
),
},
{
title: 'Markets created',
content: (
-
),
},
{
title: 'Comments',
content: (
-
),
},
{
title: 'Signups',
content: (
-
+
),
},
]}
@@ -287,22 +304,22 @@ export function CustomAnalytics(props: Stats) {
{
title: 'Daily',
content: (
-
),
},
{
title: 'Daily (7d avg)',
content: (
-
),
},
@@ -318,33 +335,33 @@ export function CustomAnalytics(props: Stats) {
{
title: 'Daily / Weekly',
content: (
-
),
},
{
title: 'Daily / Monthly',
content: (
-
),
},
{
title: 'Weekly / Monthly',
content: (
-
),
},
@@ -363,19 +380,31 @@ export function CustomAnalytics(props: Stats) {
{
title: 'Daily',
content: (
-
+
),
},
{
title: 'Weekly',
content: (
-
+
),
},
{
title: 'Monthly',
content: (
-
+
),
},
]}