Revert the merge revert (double revert)

This commit is contained in:
Pico2x 2022-10-03 17:31:07 +01:00
parent 5ae9049295
commit 77a5f8b9dd
14 changed files with 232 additions and 269 deletions

View File

@ -1,139 +0,0 @@
import { Point, ResponsiveLine } from '@nivo/line'
import clsx from 'clsx'
import { formatPercent } from 'common/util/format'
import dayjs from 'dayjs'
import { zip } from 'lodash'
import { useWindowSize } from 'web/hooks/use-window-size'
import { Col } from '../layout/col'
export function DailyCountChart(props: {
startDate: number
dailyCounts: number[]
small?: boolean
}) {
const { dailyCounts, startDate, small } = props
const { width } = useWindowSize()
const dates = dailyCounts.map((_, i) =>
dayjs(startDate).add(i, 'day').toDate()
)
const points = zip(dates, dailyCounts).map(([date, betCount]) => ({
x: date,
y: betCount,
}))
const data = [{ id: 'Count', data: points, color: '#11b981' }]
const bottomAxisTicks = width && width < 600 ? 6 : undefined
return (
<div
className={clsx(
'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
>
<ResponsiveLine
data={data}
yScale={{ type: 'linear', stacked: false }}
xScale={{
type: 'time',
}}
axisBottom={{
tickValues: bottomAxisTicks,
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} />
}}
/>
</div>
)
}
export function DailyPercentChart(props: {
startDate: number
dailyPercent: number[]
small?: boolean
excludeFirstDays?: number
}) {
const { dailyPercent, startDate, small, excludeFirstDays } = props
const { width } = useWindowSize()
const dates = dailyPercent.map((_, i) =>
dayjs(startDate).add(i, 'day').toDate()
)
const points = zip(dates, dailyPercent)
.map(([date, percent]) => ({
x: date,
y: percent,
}))
.slice(excludeFirstDays ?? 0)
const data = [{ id: 'Percent', data: points, color: '#11b981' }]
const bottomAxisTicks = width && width < 600 ? 6 : undefined
return (
<div
className={clsx(
'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
>
<ResponsiveLine
data={data}
yScale={{ type: 'linear', stacked: false }}
xScale={{
type: 'time',
}}
axisLeft={{
format: formatPercent,
}}
axisBottom={{
tickValues: bottomAxisTicks,
format: (date) => dayjs(date).format('MMM DD'),
}}
colors={{ datum: 'color' }}
pointSize={0}
pointBorderWidth={1}
pointBorderColor="#fff"
enableSlices="x"
enableGridX={!!width && width >= 800}
enableArea
margin={{ top: 20, right: 28, bottom: 22, left: 40 }}
sliceTooltip={({ slice }) => {
const point = slice.points[0]
return <Tooltip point={point} isPercent />
}}
/>
</div>
)
}
function Tooltip(props: { point: Point; isPercent?: boolean }) {
const { point, isPercent } = props
return (
<Col className="border border-gray-300 bg-white py-2 px-3">
<div
className="pb-1"
style={{
color: point.serieColor,
}}
>
<strong>{point.serieId}</strong>{' '}
{isPercent ? formatPercent(+point.data.y) : Math.round(+point.data.y)}
</div>
<div>{dayjs(point.data.x).format('MMM DD')}</div>
</Col>
)
}

View File

@ -1,6 +1,7 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { last, sortBy } from 'lodash' import { last, sortBy } from 'lodash'
import { scaleTime, scaleLinear } from 'd3-scale' import { scaleTime, scaleLinear } from 'd3-scale'
import { curveStepAfter } from 'd3-shape'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { getProbability, getInitialProbability } from 'common/calculate' import { getProbability, getInitialProbability } from 'common/calculate'
@ -76,6 +77,7 @@ export const BinaryContractChart = (props: {
yScale={yScale} yScale={yScale}
data={data} data={data}
color="#11b981" color="#11b981"
curve={curveStepAfter}
onMouseOver={onMouseOver} onMouseOver={onMouseOver}
Tooltip={BinaryChartTooltip} Tooltip={BinaryChartTooltip}
pct pct

View File

@ -1,6 +1,7 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { last, sum, sortBy, groupBy } from 'lodash' import { last, sum, sortBy, groupBy } from 'lodash'
import { scaleTime, scaleLinear } from 'd3-scale' import { scaleTime, scaleLinear } from 'd3-scale'
import { curveStepAfter } from 'd3-shape'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { Answer } from 'common/answer' import { Answer } from 'common/answer'
@ -214,6 +215,7 @@ export const ChoiceContractChart = (props: {
yScale={yScale} yScale={yScale}
data={data} data={data}
colors={CATEGORY_COLORS} colors={CATEGORY_COLORS}
curve={curveStepAfter}
onMouseOver={onMouseOver} onMouseOver={onMouseOver}
Tooltip={ChoiceTooltip} Tooltip={ChoiceTooltip}
pct pct

View File

@ -1,6 +1,7 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import { last, sortBy } from 'lodash' import { last, sortBy } from 'lodash'
import { scaleTime, scaleLog, scaleLinear } from 'd3-scale' import { scaleTime, scaleLog, scaleLinear } from 'd3-scale'
import { curveStepAfter } from 'd3-shape'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { DAY_MS } from 'common/util/time' import { DAY_MS } from 'common/util/time'
@ -85,11 +86,11 @@ export const PseudoNumericContractChart = (props: {
Date.now() Date.now()
) )
const visibleRange = [start, rightmostDate] const visibleRange = [start, rightmostDate]
const xScale = scaleTime(visibleRange, [0, width ?? 0 - MARGIN_X]) const xScale = scaleTime(visibleRange, [0, width - MARGIN_X])
// clamp log scale to make sure zeroes go to the bottom // clamp log scale to make sure zeroes go to the bottom
const yScale = isLogScale const yScale = isLogScale
? scaleLog([Math.max(min, 1), max], [height ?? 0 - MARGIN_Y, 0]).clamp(true) ? scaleLog([Math.max(min, 1), max], [height - MARGIN_Y, 0]).clamp(true)
: scaleLinear([min, max], [height ?? 0 - MARGIN_Y, 0]) : scaleLinear([min, max], [height - MARGIN_Y, 0])
return ( return (
<SingleValueHistoryChart <SingleValueHistoryChart
w={width} w={width}
@ -97,6 +98,7 @@ export const PseudoNumericContractChart = (props: {
xScale={xScale} xScale={xScale}
yScale={yScale} yScale={yScale}
data={data} data={data}
curve={curveStepAfter}
onMouseOver={onMouseOver} onMouseOver={onMouseOver}
Tooltip={PseudoNumericChartTooltip} Tooltip={PseudoNumericChartTooltip}
color={NUMERIC_GRAPH_COLOR} color={NUMERIC_GRAPH_COLOR}

View File

@ -4,11 +4,11 @@ import { axisBottom, axisLeft } from 'd3-axis'
import { D3BrushEvent } from 'd3-brush' import { D3BrushEvent } from 'd3-brush'
import { ScaleTime, ScaleContinuousNumeric } from 'd3-scale' import { ScaleTime, ScaleContinuousNumeric } from 'd3-scale'
import { import {
CurveFactory,
SeriesPoint,
curveLinear, curveLinear,
curveStepAfter,
stack, stack,
stackOrderReverse, stackOrderReverse,
SeriesPoint,
} from 'd3-shape' } from 'd3-shape'
import { range } from 'lodash' import { range } from 'lodash'
@ -52,10 +52,11 @@ export const DistributionChart = <P extends DistributionPoint>(props: {
color: string color: string
xScale: ScaleContinuousNumeric<number, number> xScale: ScaleContinuousNumeric<number, number>
yScale: ScaleContinuousNumeric<number, number> yScale: ScaleContinuousNumeric<number, number>
curve?: CurveFactory
onMouseOver?: (p: P | undefined) => void onMouseOver?: (p: P | undefined) => void
Tooltip?: TooltipComponent<number, P> Tooltip?: TooltipComponent<number, P>
}) => { }) => {
const { color, data, yScale, w, h, Tooltip } = props const { color, data, yScale, w, h, curve, Tooltip } = props
const [viewXScale, setViewXScale] = const [viewXScale, setViewXScale] =
useState<ScaleContinuousNumeric<number, number>>() useState<ScaleContinuousNumeric<number, number>>()
@ -100,7 +101,7 @@ export const DistributionChart = <P extends DistributionPoint>(props: {
px={px} px={px}
py0={py0} py0={py0}
py1={py1} py1={py1}
curve={curveLinear} curve={curve ?? curveLinear}
/> />
</SVGChart> </SVGChart>
) )
@ -113,11 +114,12 @@ export const MultiValueHistoryChart = <P extends MultiPoint>(props: {
colors: readonly string[] colors: readonly string[]
xScale: ScaleTime<number, number> xScale: ScaleTime<number, number>
yScale: ScaleContinuousNumeric<number, number> yScale: ScaleContinuousNumeric<number, number>
curve?: CurveFactory
onMouseOver?: (p: P | undefined) => void onMouseOver?: (p: P | undefined) => void
Tooltip?: TooltipComponent<Date, P> Tooltip?: TooltipComponent<Date, P>
pct?: boolean pct?: boolean
}) => { }) => {
const { colors, data, yScale, w, h, Tooltip, pct } = props const { colors, data, yScale, w, h, curve, Tooltip, pct } = props
const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>()
const xScale = viewXScale ?? props.xScale const xScale = viewXScale ?? props.xScale
@ -177,7 +179,7 @@ export const MultiValueHistoryChart = <P extends MultiPoint>(props: {
px={px} px={px}
py0={py0} py0={py0}
py1={py1} py1={py1}
curve={curveStepAfter} curve={curve ?? curveLinear}
fill={colors[i]} fill={colors[i]}
/> />
))} ))}
@ -192,11 +194,12 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: {
color: string color: string
xScale: ScaleTime<number, number> xScale: ScaleTime<number, number>
yScale: ScaleContinuousNumeric<number, number> yScale: ScaleContinuousNumeric<number, number>
curve?: CurveFactory
onMouseOver?: (p: P | undefined) => void onMouseOver?: (p: P | undefined) => void
Tooltip?: TooltipComponent<Date, P> Tooltip?: TooltipComponent<Date, P>
pct?: boolean pct?: boolean
}) => { }) => {
const { color, data, yScale, w, h, Tooltip, pct } = props const { color, data, yScale, w, h, curve, Tooltip, pct } = props
const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>()
const xScale = viewXScale ?? props.xScale const xScale = viewXScale ?? props.xScale
@ -246,7 +249,7 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: {
px={px} px={px}
py0={py0} py0={py0}
py1={py1} py1={py1}
curve={curveStepAfter} curve={curve ?? curveLinear}
/> />
</SVGChart> </SVGChart>
) )

View File

@ -10,7 +10,7 @@ import {
import { pointer, select } from 'd3-selection' import { pointer, select } from 'd3-selection'
import { Axis, AxisScale } from 'd3-axis' import { Axis, AxisScale } from 'd3-axis'
import { brushX, D3BrushEvent } from 'd3-brush' import { brushX, D3BrushEvent } from 'd3-brush'
import { area, line, curveStepAfter, CurveFactory } from 'd3-shape' import { area, line, CurveFactory } from 'd3-shape'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import clsx from 'clsx' import clsx from 'clsx'
@ -73,11 +73,11 @@ const LinePathInternal = <P,>(
data: P[] data: P[]
px: number | ((p: P) => number) px: number | ((p: P) => number)
py: number | ((p: P) => number) py: number | ((p: P) => number)
curve?: CurveFactory curve: CurveFactory
} & SVGProps<SVGPathElement> } & SVGProps<SVGPathElement>
) => { ) => {
const { data, px, py, curve, ...rest } = props const { data, px, py, curve, ...rest } = props
const d3Line = line<P>(px, py).curve(curve ?? curveStepAfter) const d3Line = line<P>(px, py).curve(curve)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return <path {...rest} fill="none" d={d3Line(data)!} /> return <path {...rest} fill="none" d={d3Line(data)!} />
} }
@ -89,11 +89,11 @@ const AreaPathInternal = <P,>(
px: number | ((p: P) => number) px: number | ((p: P) => number)
py0: number | ((p: P) => number) py0: number | ((p: P) => number)
py1: number | ((p: P) => number) py1: number | ((p: P) => number)
curve?: CurveFactory curve: CurveFactory
} & SVGProps<SVGPathElement> } & SVGProps<SVGPathElement>
) => { ) => {
const { data, px, py0, py1, curve, ...rest } = props const { data, px, py0, py1, curve, ...rest } = props
const d3Area = area<P>(px, py0, py1).curve(curve ?? curveStepAfter) const d3Area = area<P>(px, py0, py1).curve(curve)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return <path {...rest} d={d3Area(data)!} /> return <path {...rest} d={d3Area(data)!} />
} }
@ -105,7 +105,7 @@ export const AreaWithTopStroke = <P,>(props: {
px: number | ((p: P) => number) px: number | ((p: P) => number)
py0: number | ((p: P) => number) py0: number | ((p: P) => number)
py1: number | ((p: P) => number) py1: number | ((p: P) => number)
curve?: CurveFactory curve: CurveFactory
}) => { }) => {
const { color, data, px, py0, py1, curve } = props const { color, data, px, py0, py1, curve } = props
return ( return (

View File

@ -0,0 +1,76 @@
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<Date, HistoryPoint>) => {
const { data, mouseX, xScale } = props
const d = xScale.invert(mouseX)
return (
<Row className="items-center gap-2">
<span className="font-semibold">{dayjs(d).format('MMM DD')}</span>
<span className="text-greyscale-6">{data.y}</span>
</Row>
)
}
const DailyPercentTooltip = (props: TooltipProps<Date, HistoryPoint>) => {
const { data, mouseX, xScale } = props
const d = xScale.invert(mouseX)
return (
<Row className="items-center gap-2">
<span className="font-semibold">{dayjs(d).format('MMM DD')}</span>
<span className="text-greyscale-6">{formatPercent(data.y)}</span>
</Row>
)
}
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 (
<SizedContainer fullHeight={250} mobileHeight={250}>
{(width, height) => (
<SingleValueHistoryChart
w={width}
h={height}
xScale={scaleTime([minDate, maxDate], [0, width - MARGIN_X])}
yScale={scaleLinear([0, maxValue], [height - MARGIN_Y, 0])}
data={data}
Tooltip={pct ? DailyPercentTooltip : DailyCountTooltip}
color="#11b981"
pct={pct}
/>
)}
</SizedContainer>
)
}

View File

@ -395,7 +395,9 @@ export function ContractCardProbChange(props: {
noLinkAvatar?: boolean noLinkAvatar?: boolean
className?: string className?: string
}) { }) {
const { contract, noLinkAvatar, className } = props const { noLinkAvatar, className } = props
const contract = useContractWithPreload(props.contract) as CPMMBinaryContract
return ( return (
<Col <Col
className={clsx( className={clsx(

View File

@ -1,5 +1,3 @@
import React, { useEffect, useRef, useState } from 'react'
import { tradingAllowed } from 'web/lib/firebase/contracts' import { tradingAllowed } from 'web/lib/firebase/contracts'
import { Col } from '../layout/col' import { Col } from '../layout/col'
import { ContractChart } from 'web/components/charts/contract' import { ContractChart } from 'web/components/charts/contract'
@ -25,6 +23,7 @@ import {
} from 'common/contract' } from 'common/contract'
import { ContractDetails } from './contract-details' import { ContractDetails } from './contract-details'
import { ContractReportResolution } from './contract-report-resolution' import { ContractReportResolution } from './contract-report-resolution'
import { SizedContainer } from 'web/components/sized-container'
const OverviewQuestion = (props: { text: string }) => ( const OverviewQuestion = (props: { text: string }) => (
<Linkify className="text-lg text-indigo-700 sm:text-2xl" text={props.text} /> <Linkify className="text-lg text-indigo-700 sm:text-2xl" text={props.text} />
@ -50,32 +49,18 @@ const SizedContractChart = (props: {
fullHeight: number fullHeight: number
mobileHeight: number mobileHeight: number
}) => { }) => {
const { contract, bets, fullHeight, mobileHeight } = props const { fullHeight, mobileHeight, contract, bets } = props
const containerRef = useRef<HTMLDivElement>(null)
const [chartWidth, setChartWidth] = useState<number>()
const [chartHeight, setChartHeight] = useState<number>()
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 ( return (
<div ref={containerRef}> <SizedContainer fullHeight={fullHeight} mobileHeight={mobileHeight}>
{chartWidth != null && chartHeight != null && ( {(width, height) => (
<ContractChart <ContractChart
width={width}
height={height}
contract={contract} contract={contract}
bets={bets} bets={bets}
width={chartWidth}
height={chartHeight}
/> />
)} )}
</div> </SizedContainer>
) )
} }

View File

@ -85,13 +85,34 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
store: storageStore(safeLocalStorage()), store: storageStore(safeLocalStorage()),
}) })
const me = useUser() const me = useUser()
if (comments == null) { if (comments == null) {
return <LoadingIndicator /> return <LoadingIndicator />
} }
if (contract.outcomeType === 'FREE_RESPONSE') {
const generalComments = comments.filter( const tipsOrBountiesAwarded =
(c) => c.answerOutcome === undefined && c.betId === undefined 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 sortedAnswers = sortBy( const sortedAnswers = sortBy(
contract.answers, contract.answers,
(a) => -getOutcomeProbability(contract, a.id) (a) => -getOutcomeProbability(contract, a.id)
@ -100,6 +121,9 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
comments, comments,
(c) => c.answerOutcome ?? c.betOutcome ?? '_' (c) => c.answerOutcome ?? c.betOutcome ?? '_'
) )
const generalTopLevelComments = topLevelComments.filter(
(c) => c.answerOutcome === undefined && c.betId === undefined
)
return ( return (
<> <>
{sortedAnswers.map((answer) => ( {sortedAnswers.map((answer) => (
@ -123,12 +147,12 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
<div className="text-md mt-8 mb-2 text-left">General Comments</div> <div className="text-md mt-8 mb-2 text-left">General Comments</div>
<div className="mb-4 w-full border-b border-gray-200" /> <div className="mb-4 w-full border-b border-gray-200" />
<ContractCommentInput className="mb-5" contract={contract} /> <ContractCommentInput className="mb-5" contract={contract} />
{generalComments.map((comment) => ( {generalTopLevelComments.map((comment) => (
<FeedCommentThread <FeedCommentThread
key={comment.id} key={comment.id}
contract={contract} contract={contract}
parentComment={comment} parentComment={comment}
threadComments={[]} threadComments={commentsByParent[comment.id] ?? []}
tips={tips} tips={tips}
/> />
))} ))}

View File

@ -0,0 +1,35 @@
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<HTMLDivElement>(null)
const [width, setWidth] = useState<number>()
const [height, setHeight] = useState<number>()
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 (
<div ref={containerRef}>
{width != null && height != null && children(width, height)}
</div>
)
}

View File

@ -11,7 +11,7 @@ const App = () => {
url="/cowp" url="/cowp"
/> />
<Link href="https://www.youtube.com/watch?v=FavUpD_IjVY"> <Link href="https://www.youtube.com/watch?v=FavUpD_IjVY">
<img src="https://i.imgur.com/Lt54IiU.png" /> <img src="https://i.imgur.com/Lt54IiU.png" className="cursor-pointer" />
</Link> </Link>
</Page> </Page>
) )

View File

@ -16,7 +16,7 @@ export default function LabsPage() {
url="/labs" url="/labs"
/> />
<Col className="px-4"> <Col className="px-4">
<Title className="sm:!mt-0" text="Manifold Labs" /> <Title className="sm:!mt-0" text="🧪 Manifold Labs" />
<Masonry <Masonry
breakpointCols={{ default: 2, 768: 1 }} breakpointCols={{ default: 2, 768: 1 }}

View File

@ -1,8 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { import { DailyChart } from 'web/components/charts/stats'
DailyCountChart,
DailyPercentChart,
} from 'web/components/analytics/charts'
import { Col } from 'web/components/layout/col' import { Col } from 'web/components/layout/col'
import { Spacer } from 'web/components/layout/spacer' import { Spacer } from 'web/components/layout/spacer'
import { Tabs } from 'web/components/layout/tabs' import { Tabs } from 'web/components/layout/tabs'
@ -96,40 +93,36 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyActiveUsers} dailyValues={dailyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Daily (7d avg)', title: 'Daily (7d avg)',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyActiveUsersWeeklyAvg} dailyValues={dailyActiveUsersWeeklyAvg}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Weekly', title: 'Weekly',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={weeklyActiveUsers} dailyValues={weeklyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Monthly', title: 'Monthly',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={monthlyActiveUsers} dailyValues={monthlyActiveUsers}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
@ -149,44 +142,44 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'D1', title: 'D1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={d1} dailyValues={d1}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={1} excludeFirstDays={1}
pct
/> />
), ),
}, },
{ {
title: 'D1 (7d avg)', title: 'D1 (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={d1WeeklyAvg} dailyValues={d1WeeklyAvg}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={7} excludeFirstDays={7}
pct
/> />
), ),
}, },
{ {
title: 'W1', title: 'W1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={weekOnWeekRetention} dailyValues={weekOnWeekRetention}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={14} excludeFirstDays={14}
pct
/> />
), ),
}, },
{ {
title: 'M1', title: 'M1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={monthlyRetention} dailyValues={monthlyRetention}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={60} excludeFirstDays={60}
pct
/> />
), ),
}, },
@ -207,33 +200,33 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'ND1', title: 'ND1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nd1} dailyValues={nd1}
startDate={startDate} startDate={startDate}
excludeFirstDays={1} excludeFirstDays={1}
small pct
/> />
), ),
}, },
{ {
title: 'ND1 (7d avg)', title: 'ND1 (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nd1WeeklyAvg} dailyValues={nd1WeeklyAvg}
startDate={startDate} startDate={startDate}
excludeFirstDays={7} excludeFirstDays={7}
small pct
/> />
), ),
}, },
{ {
title: 'NW1', title: 'NW1',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={nw1} dailyValues={nw1}
startDate={startDate} startDate={startDate}
excludeFirstDays={14} excludeFirstDays={14}
small pct
/> />
), ),
}, },
@ -249,41 +242,31 @@ export function CustomAnalytics(props: Stats) {
{ {
title: capitalize(PAST_BETS), title: capitalize(PAST_BETS),
content: ( content: (
<DailyCountChart <DailyChart dailyValues={dailyBetCounts} startDate={startDate} />
dailyCounts={dailyBetCounts}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Markets created', title: 'Markets created',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyContractCounts} dailyValues={dailyContractCounts}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Comments', title: 'Comments',
content: ( content: (
<DailyCountChart <DailyChart
dailyCounts={dailyCommentCounts} dailyValues={dailyCommentCounts}
startDate={startDate} startDate={startDate}
small
/> />
), ),
}, },
{ {
title: 'Signups', title: 'Signups',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={dailySignups} startDate={startDate} />
dailyCounts={dailySignups}
startDate={startDate}
small
/>
), ),
}, },
]} ]}
@ -304,22 +287,22 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyActivationRate} dailyValues={dailyActivationRate}
startDate={startDate} startDate={startDate}
excludeFirstDays={1} excludeFirstDays={1}
small pct
/> />
), ),
}, },
{ {
title: 'Daily (7d avg)', title: 'Daily (7d avg)',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyActivationRateWeeklyAvg} dailyValues={dailyActivationRateWeeklyAvg}
startDate={startDate} startDate={startDate}
excludeFirstDays={7} excludeFirstDays={7}
small pct
/> />
), ),
}, },
@ -335,33 +318,33 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily / Weekly', title: 'Daily / Weekly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyDividedByWeekly} dailyValues={dailyDividedByWeekly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={7} excludeFirstDays={7}
pct
/> />
), ),
}, },
{ {
title: 'Daily / Monthly', title: 'Daily / Monthly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={dailyDividedByMonthly} dailyValues={dailyDividedByMonthly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={30} excludeFirstDays={30}
pct
/> />
), ),
}, },
{ {
title: 'Weekly / Monthly', title: 'Weekly / Monthly',
content: ( content: (
<DailyPercentChart <DailyChart
dailyPercent={weeklyDividedByMonthly} dailyValues={weeklyDividedByMonthly}
startDate={startDate} startDate={startDate}
small
excludeFirstDays={30} excludeFirstDays={30}
pct
/> />
), ),
}, },
@ -380,31 +363,19 @@ export function CustomAnalytics(props: Stats) {
{ {
title: 'Daily', title: 'Daily',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.daily} startDate={startDate} />
dailyCounts={manaBet.daily}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Weekly', title: 'Weekly',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.weekly} startDate={startDate} />
dailyCounts={manaBet.weekly}
startDate={startDate}
small
/>
), ),
}, },
{ {
title: 'Monthly', title: 'Monthly',
content: ( content: (
<DailyCountChart <DailyChart dailyValues={manaBet.monthly} startDate={startDate} />
dailyCounts={manaBet.monthly}
startDate={startDate}
small
/>
), ),
}, },
]} ]}