Embed market: dynamically adjust graph height

This commit is contained in:
James Grugett 2022-03-24 12:03:08 -05:00
parent b6281b0b56
commit 7d8a87615a
6 changed files with 95 additions and 13 deletions

View File

@ -1,3 +1,3 @@
export function filterDefined<T>(array: (T | null | undefined)[]) {
return array.filter((item) => item) as T[]
return array.filter((item) => item !== null && item !== undefined) as T[]
}

View File

@ -14,8 +14,9 @@ const NUM_LINES = 6
export function AnswersGraph(props: {
contract: FullContract<DPM, FreeResponse>
bets: Bet[]
height?: number
}) {
const { contract } = props
const { contract, height } = props
const { createdTime, resolutionTime, closeTime, answers } = contract
const bets = useBets(contract.id) ?? props.bets
@ -86,7 +87,7 @@ export function AnswersGraph(props: {
return (
<div
className="w-full overflow-hidden"
style={{ height: !width || width >= 800 ? 350 : 225 }}
style={{ height: height ?? (!width || width >= 800 ? 350 : 225) }}
>
<ResponsiveLine
data={data}

View File

@ -10,8 +10,9 @@ import { useWindowSize } from '../hooks/use-window-size'
export function ContractProbGraph(props: {
contract: FullContract<DPM | CPMM, Binary>
bets: Bet[]
height?: number
}) {
const { contract } = props
const { contract, height } = props
const { resolutionTime, closeTime } = contract
const bets = useBetsWithoutAntes(contract, props.bets).filter(
@ -63,7 +64,7 @@ export function ContractProbGraph(props: {
return (
<div
className="w-full overflow-hidden"
style={{ height: !width || width >= 800 ? 400 : 250 }}
style={{ height: height ?? (!width || width >= 800 ? 400 : 250) }}
>
<ResponsiveLine
data={data}

View File

@ -1,15 +1,16 @@
import clsx from 'clsx'
import { CSSProperties } from 'react'
import { CSSProperties, Ref } from 'react'
export function Col(props: {
children?: any
className?: string
style?: CSSProperties
ref?: Ref<HTMLDivElement>
}) {
const { children, className, style } = props
const { children, className, style, ref } = props
return (
<div className={clsx(className, 'flex flex-col')} style={style}>
<div className={clsx(className, 'flex flex-col')} style={style} ref={ref}>
{children}
</div>
)

View File

@ -0,0 +1,63 @@
import _ from 'lodash'
import { RefObject, useMemo, useLayoutEffect, useRef, useState } from 'react'
type elem_size =
| { width: number; height: number }
| { width: undefined; height: undefined }
const getSize = (elem: HTMLElement | null) =>
elem
? { width: elem.offsetWidth, height: elem.offsetHeight }
: { width: undefined, height: undefined }
export function useListenElemSize<T extends HTMLElement>(
elemRef: RefObject<T | null>,
callback: (size: elem_size) => void,
debounceMs: number | undefined = undefined
) {
const handleResize = useMemo(() => {
let updateSize = () => {
if (elemRef.current) callback(getSize(elemRef.current))
}
return debounceMs
? _.debounce(updateSize, debounceMs, { leading: false, trailing: true })
: updateSize
}, [callback, elemRef, debounceMs])
let elem = elemRef.current
useLayoutEffect(() => {
if (!elemRef.current) return
const resizeObserver = new ResizeObserver(handleResize)
resizeObserver.observe(elemRef.current)
return () => resizeObserver.disconnect()
}, [elemRef, elem, handleResize])
}
export function useMeasureSize(debounceMs: number | undefined = undefined) {
const elemRef = useRef<HTMLElement | null>(null)
const [size, setSize] = useState(() => getSize(null))
const sizeRef = useRef<elem_size>(size)
const setSizeIfDifferent = (newSize: typeof size) => {
if (newSize?.height !== size?.height || newSize?.width !== size?.width) {
sizeRef.current = newSize
setSize(newSize)
}
}
useListenElemSize(elemRef, setSizeIfDifferent, debounceMs)
const setElem = (elem: HTMLElement | null) => {
elemRef.current = elem
if (elem) {
setSizeIfDifferent(getSize(elem))
}
}
return { setElem, elemRef, sizeRef, ...size }
}

View File

@ -18,7 +18,9 @@ import { Spacer } from '../../../components/layout/spacer'
import { Linkify } from '../../../components/linkify'
import { SiteLink } from '../../../components/site-link'
import { useContractWithPreload } from '../../../hooks/use-contract'
import { useMeasureSize } from '../../../hooks/use-measure-size'
import { fromPropz, usePropz } from '../../../hooks/use-propz'
import { useWindowSize } from '../../../hooks/use-window-size'
import { listAllBets } from '../../../lib/firebase/bets'
import {
contractPath,
@ -85,9 +87,18 @@ function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {
const href = `https://${DOMAIN}${contractPath(contract)}`
const { height: windowHeight } = useWindowSize()
const { setElem, height: topSectionHeight } = useMeasureSize()
const paddingBottom = 8
const graphHeight =
windowHeight && topSectionHeight
? windowHeight - topSectionHeight - paddingBottom
: 0
return (
<Col className="w-full flex-1 bg-white py-2">
<Col className="relative">
<Col className="w-full flex-1 bg-white">
<div className="flex flex-col relative pt-2" ref={setElem}>
<SiteLink
className="absolute top-0 left-0 w-full h-full z-20"
href={href}
@ -112,15 +123,20 @@ function ContractEmbed(props: { contract: Contract; bets: Bet[] }) {
</Row>
<Spacer h={2} />
</Col>
</div>
<div className="mx-1">
<div className="mx-1" style={{ paddingBottom }}>
{isBinary ? (
<ContractProbGraph contract={contract} bets={bets} />
<ContractProbGraph
contract={contract}
bets={bets}
height={graphHeight}
/>
) : (
<AnswersGraph
contract={contract as FullContract<DPM, FreeResponse>}
bets={bets}
height={graphHeight}
/>
)}
</div>