192 lines
5.1 KiB
TypeScript
192 lines
5.1 KiB
TypeScript
import React, { useEffect, useRef } from 'react'
|
|
import styled from 'styled-components'
|
|
import Split from 'split-grid'
|
|
import { ArrowDownIcon, Button, ChartIcon } from '@pancakeswap/uikit'
|
|
import debounce from 'lodash/debounce'
|
|
import delay from 'lodash/delay'
|
|
import { useAppDispatch } from 'state'
|
|
import { useGetPredictionsStatus, useIsChartPaneOpen, useIsHistoryPaneOpen } from 'state/hooks'
|
|
import { setChartPaneState } from 'state/predictions'
|
|
import { PredictionStatus } from 'state/types'
|
|
import { useTranslation } from 'contexts/Localization'
|
|
import TradingView from './components/TradingView'
|
|
import { ErrorNotification, PauseNotification } from './components/Notification'
|
|
import History from './History'
|
|
import Positions from './Positions'
|
|
|
|
// The value to set the chart when the user clicks the chart tab at the bottom
|
|
const GRID_TEMPLATE_ROW = '1.2fr 12px .8fr'
|
|
|
|
const ExpandChartButton = styled(Button)`
|
|
background-color: ${({ theme }) => theme.card.background};
|
|
border-bottom-left-radius: 0;
|
|
border-bottom-right-radius: 0;
|
|
bottom: 12px;
|
|
color: ${({ theme }) => theme.colors.text};
|
|
display: none;
|
|
left: 32px;
|
|
position: absolute;
|
|
z-index: 50;
|
|
|
|
&:hover:not(:disabled):not(.pancake-button--disabled):not(.pancake-button--disabled):not(:active) {
|
|
background-color: ${({ theme }) => theme.card.background};
|
|
opacity: 1;
|
|
}
|
|
|
|
${({ theme }) => theme.mediaQueries.lg} {
|
|
display: inline-flex;
|
|
}
|
|
`
|
|
|
|
const SplitWrapper = styled.div`
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
grid-template-rows: 1fr 12px 0;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
`
|
|
|
|
const ChartPane = styled.div`
|
|
overflow: hidden;
|
|
position: relative;
|
|
`
|
|
|
|
const HistoryPane = styled.div<{ isHistoryPaneOpen: boolean }>`
|
|
flex: none;
|
|
overflow: hidden;
|
|
transition: width 200ms ease-in-out;
|
|
width: ${({ isHistoryPaneOpen }) => (isHistoryPaneOpen ? '384px' : 0)};
|
|
`
|
|
|
|
const StyledDesktop = styled.div`
|
|
display: none;
|
|
|
|
${({ theme }) => theme.mediaQueries.lg} {
|
|
display: flex;
|
|
height: 100%;
|
|
}
|
|
`
|
|
|
|
const PositionPane = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
max-width: 100%;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
|
|
& > div {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
`
|
|
|
|
const Gutter = styled.div`
|
|
background: ${({ theme }) => theme.colors.dropdown};
|
|
cursor: row-resize;
|
|
height: 12px;
|
|
position: relative;
|
|
|
|
&:before {
|
|
background-color: ${({ theme }) => theme.colors.textSubtle};
|
|
border-radius: 8px;
|
|
content: '';
|
|
height: 4px;
|
|
left: 50%;
|
|
margin-left: -32px;
|
|
position: absolute;
|
|
top: 4px;
|
|
width: 64px;
|
|
}
|
|
`
|
|
|
|
const Desktop: React.FC = () => {
|
|
const splitWrapperRef = useRef<HTMLDivElement>()
|
|
const chartRef = useRef<HTMLDivElement>()
|
|
const gutterRef = useRef<HTMLDivElement>()
|
|
const isHistoryPaneOpen = useIsHistoryPaneOpen()
|
|
const isChartPaneOpen = useIsChartPaneOpen()
|
|
const dispatch = useAppDispatch()
|
|
const { t } = useTranslation()
|
|
const status = useGetPredictionsStatus()
|
|
|
|
const toggleChartPane = () => {
|
|
const newChartPaneState = !isChartPaneOpen
|
|
|
|
if (newChartPaneState) {
|
|
splitWrapperRef.current.style.transition = 'grid-template-rows 150ms'
|
|
splitWrapperRef.current.style.gridTemplateRows = GRID_TEMPLATE_ROW
|
|
|
|
// Purely comedic: We only want to animate if we are clicking the open chart button
|
|
// If we keep the transition on the resizing becomes very choppy
|
|
delay(() => {
|
|
splitWrapperRef.current.style.transition = ''
|
|
}, 150)
|
|
}
|
|
|
|
dispatch(setChartPaneState(newChartPaneState))
|
|
}
|
|
|
|
useEffect(() => {
|
|
const threshold = 100
|
|
const handleDrag = debounce(() => {
|
|
const { height } = chartRef.current.getBoundingClientRect()
|
|
|
|
// If the height of the chart pane goes below the "snapOffset" threshold mark the chart pane as closed
|
|
dispatch(setChartPaneState(height > threshold))
|
|
}, 50)
|
|
|
|
const split = Split({
|
|
dragInterval: 1,
|
|
snapOffset: threshold,
|
|
onDrag: handleDrag,
|
|
rowGutters: [
|
|
{
|
|
track: 1,
|
|
element: gutterRef.current,
|
|
},
|
|
],
|
|
})
|
|
|
|
return () => {
|
|
split.destroy()
|
|
}
|
|
}, [gutterRef, chartRef, dispatch])
|
|
|
|
return (
|
|
<>
|
|
{!isChartPaneOpen && (
|
|
<ExpandChartButton
|
|
variant="tertiary"
|
|
scale="sm"
|
|
startIcon={isChartPaneOpen ? <ArrowDownIcon /> : <ChartIcon />}
|
|
onClick={toggleChartPane}
|
|
>
|
|
{isChartPaneOpen ? t('Close') : t('Charts')}
|
|
</ExpandChartButton>
|
|
)}
|
|
<StyledDesktop>
|
|
<SplitWrapper ref={splitWrapperRef}>
|
|
<PositionPane>
|
|
{status === PredictionStatus.ERROR && <ErrorNotification />}
|
|
{status === PredictionStatus.PAUSED && <PauseNotification />}
|
|
{status === PredictionStatus.LIVE && (
|
|
<div>
|
|
<Positions />
|
|
</div>
|
|
)}
|
|
</PositionPane>
|
|
<Gutter ref={gutterRef} />
|
|
<ChartPane ref={chartRef}>
|
|
<TradingView />
|
|
</ChartPane>
|
|
</SplitWrapper>
|
|
<HistoryPane isHistoryPaneOpen={isHistoryPaneOpen}>
|
|
<History />
|
|
</HistoryPane>
|
|
</StyledDesktop>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default Desktop
|