vertically center orderbook as window is resized
This commit is contained in:
parent
2b9ada9ebc
commit
da13e3a0b5
|
@ -42,82 +42,83 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col justify-between transition-all duration-500 ${
|
||||
className={`transition-all duration-500 ${
|
||||
collapsed ? 'w-[64px]' : 'w-44 lg:w-48 xl:w-52'
|
||||
} min-h-screen border-r border-th-bkg-3 bg-th-bkg-1`}
|
||||
} border-r border-th-bkg-3 bg-th-bkg-1`}
|
||||
>
|
||||
<div className="my-2">
|
||||
<Link href={'/'} shallow={true} passHref>
|
||||
<div
|
||||
className={`h-14 items-center transition-all duration-500 ease-in-out ${
|
||||
collapsed ? '' : 'justify-start'
|
||||
} pb-1 pt-2 pl-4`}
|
||||
>
|
||||
<div className={`flex flex-shrink-0 cursor-pointer items-center`}>
|
||||
<img
|
||||
className={`h-8 w-8 flex-shrink-0`}
|
||||
src="/logos/logo-mark.svg"
|
||||
alt="next"
|
||||
/>
|
||||
<Transition
|
||||
show={!collapsed}
|
||||
as={Fragment}
|
||||
enter="transition ease-in duration-200"
|
||||
enterFrom="opacity-50"
|
||||
enterTo="opacity-100"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<span className="ml-3 text-lg font-bold text-th-fgd-1">
|
||||
Mango
|
||||
</span>
|
||||
</Transition>
|
||||
<div className="flex min-h-screen flex-col justify-between">
|
||||
<div className="my-2">
|
||||
<Link href={'/'} shallow={true} passHref>
|
||||
<div
|
||||
className={`h-14 items-center transition-all duration-500 ease-in-out ${
|
||||
collapsed ? '' : 'justify-start'
|
||||
} pb-1 pt-2 pl-4`}
|
||||
>
|
||||
<div className={`flex flex-shrink-0 cursor-pointer items-center`}>
|
||||
<img
|
||||
className={`h-8 w-8 flex-shrink-0`}
|
||||
src="/logos/logo-mark.svg"
|
||||
alt="next"
|
||||
/>
|
||||
<Transition
|
||||
show={!collapsed}
|
||||
as={Fragment}
|
||||
enter="transition ease-in duration-200"
|
||||
enterFrom="opacity-50"
|
||||
enterTo="opacity-100"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<span className="ml-3 text-lg font-bold text-th-fgd-1">
|
||||
Mango
|
||||
</span>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex flex-col items-start">
|
||||
<MenuItem
|
||||
active={pathname === '/'}
|
||||
collapsed={collapsed}
|
||||
icon={<CurrencyDollarIcon className="h-5 w-5" />}
|
||||
title={t('account')}
|
||||
pagePath="/"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/swap'}
|
||||
collapsed={collapsed}
|
||||
icon={<ArrowsRightLeftIcon className="h-5 w-5" />}
|
||||
title={t('swap')}
|
||||
pagePath="/swap"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/trade'}
|
||||
collapsed={collapsed}
|
||||
icon={<TradeIcon className="h-5 w-5" />}
|
||||
title={t('trade')}
|
||||
pagePath="/trade"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/stats'}
|
||||
collapsed={collapsed}
|
||||
icon={<ChartBarIcon className="h-5 w-5" />}
|
||||
title={t('stats')}
|
||||
pagePath="/stats"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/settings'}
|
||||
collapsed={collapsed}
|
||||
icon={<Cog8ToothIcon className="h-5 w-5" />}
|
||||
title={t('settings')}
|
||||
pagePath="/settings"
|
||||
/>
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={<EllipsisHorizontalIcon className="h-5 w-5" />}
|
||||
title={t('more')}
|
||||
>
|
||||
{/* <MenuItem
|
||||
</Link>
|
||||
<div className="flex flex-col items-start">
|
||||
<MenuItem
|
||||
active={pathname === '/'}
|
||||
collapsed={collapsed}
|
||||
icon={<CurrencyDollarIcon className="h-5 w-5" />}
|
||||
title={t('account')}
|
||||
pagePath="/"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/swap'}
|
||||
collapsed={collapsed}
|
||||
icon={<ArrowsRightLeftIcon className="h-5 w-5" />}
|
||||
title={t('swap')}
|
||||
pagePath="/swap"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/trade'}
|
||||
collapsed={collapsed}
|
||||
icon={<TradeIcon className="h-5 w-5" />}
|
||||
title={t('trade')}
|
||||
pagePath="/trade"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/stats'}
|
||||
collapsed={collapsed}
|
||||
icon={<ChartBarIcon className="h-5 w-5" />}
|
||||
title={t('stats')}
|
||||
pagePath="/stats"
|
||||
/>
|
||||
<MenuItem
|
||||
active={pathname === '/settings'}
|
||||
collapsed={collapsed}
|
||||
icon={<Cog8ToothIcon className="h-5 w-5" />}
|
||||
title={t('settings')}
|
||||
pagePath="/settings"
|
||||
/>
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={<EllipsisHorizontalIcon className="h-5 w-5" />}
|
||||
title={t('more')}
|
||||
>
|
||||
{/* <MenuItem
|
||||
active={pathname === '/fees'}
|
||||
collapsed={false}
|
||||
icon={<ReceiptTaxIcon className="h-5 w-5" />}
|
||||
|
@ -125,69 +126,70 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
|||
pagePath="/fees"
|
||||
hideIconBg
|
||||
/> */}
|
||||
<MenuItem
|
||||
collapsed={false}
|
||||
icon={<LightBulbIcon className="h-5 w-5" />}
|
||||
title={t('learn')}
|
||||
pagePath="https://docs.mango.markets"
|
||||
hideIconBg
|
||||
isExternal
|
||||
showTooltip={false}
|
||||
/>
|
||||
<MenuItem
|
||||
collapsed={false}
|
||||
icon={<BuildingLibraryIcon className="h-5 w-5" />}
|
||||
title={t('governance')}
|
||||
pagePath="https://dao.mango.markets"
|
||||
hideIconBg
|
||||
isExternal
|
||||
showTooltip={false}
|
||||
/>
|
||||
{connected ? (
|
||||
<button
|
||||
className="default-transition mt-1 flex items-center px-4 text-th-fgd-2 md:hover:text-th-primary"
|
||||
onClick={handleTakeTour}
|
||||
>
|
||||
<InformationCircleIcon className="mr-3 h-5 w-5" />
|
||||
<span className="text-base">Take UI Tour</span>
|
||||
</button>
|
||||
) : null}
|
||||
<MenuItem
|
||||
collapsed={false}
|
||||
icon={<LightBulbIcon className="h-5 w-5" />}
|
||||
title={t('learn')}
|
||||
pagePath="https://docs.mango.markets"
|
||||
hideIconBg
|
||||
isExternal
|
||||
showTooltip={false}
|
||||
/>
|
||||
<MenuItem
|
||||
collapsed={false}
|
||||
icon={<BuildingLibraryIcon className="h-5 w-5" />}
|
||||
title={t('governance')}
|
||||
pagePath="https://dao.mango.markets"
|
||||
hideIconBg
|
||||
isExternal
|
||||
showTooltip={false}
|
||||
/>
|
||||
{connected ? (
|
||||
<button
|
||||
className="default-transition mt-1 flex items-center px-4 text-th-fgd-2 md:hover:text-th-primary"
|
||||
onClick={handleTakeTour}
|
||||
>
|
||||
<InformationCircleIcon className="mr-3 h-5 w-5" />
|
||||
<span className="text-base">Take UI Tour</span>
|
||||
</button>
|
||||
) : null}
|
||||
</ExpandableMenuItem>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-th-bkg-3">
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={
|
||||
<HealthHeart
|
||||
health={
|
||||
mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(HealthType.maint)
|
||||
: undefined
|
||||
}
|
||||
size={32}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<div className="text-left">
|
||||
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
|
||||
<p className="whitespace-nowrap text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount
|
||||
? mangoAccount.name
|
||||
: connected
|
||||
? 'No Account'
|
||||
: 'Connect'}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
alignBottom
|
||||
hideIconBg
|
||||
>
|
||||
<div className="px-4 pb-4 pt-2">
|
||||
<MangoAccountSummary collapsed={collapsed} />
|
||||
</div>
|
||||
</ExpandableMenuItem>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-th-bkg-3">
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={
|
||||
<HealthHeart
|
||||
health={
|
||||
mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(HealthType.maint)
|
||||
: undefined
|
||||
}
|
||||
size={32}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<div className="text-left">
|
||||
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
|
||||
<p className="whitespace-nowrap text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount
|
||||
? mangoAccount.name
|
||||
: connected
|
||||
? 'No Account'
|
||||
: 'Connect'}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
alignBottom
|
||||
hideIconBg
|
||||
>
|
||||
<div className="px-4 pb-4 pt-2">
|
||||
<MangoAccountSummary collapsed={collapsed} />
|
||||
</div>
|
||||
</ExpandableMenuItem>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useMemo } from 'react'
|
||||
import { Listbox } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { isEqual } from '../../utils'
|
||||
|
||||
const GroupSize = ({
|
||||
tickSize,
|
||||
|
@ -72,6 +71,4 @@ const GroupSize = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default React.memo(GroupSize, (prevProps, nextProps) =>
|
||||
isEqual(prevProps, nextProps, ['tickSize', 'value'])
|
||||
)
|
||||
export default React.memo(GroupSize)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AccountInfo } from '@solana/web3.js'
|
||||
import Big from 'big.js'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Market, Orderbook as SpotOrderBook } from '@project-serum/serum'
|
||||
import useInterval from '@components/shared/useInterval'
|
||||
import isEqualLodash from 'lodash/isEqual'
|
||||
|
@ -152,7 +152,8 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
const { t } = useTranslation('common')
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
const [openOrderPrices, setOpenOrderPrices] = useState<any[]>([])
|
||||
// const [openOrderPrices, setOpenOrderPrices] = useState<any[]>([])
|
||||
const [isScrolled, setIsScrolled] = useState(false)
|
||||
const [orderbookData, setOrderbookData] = useState<any | null>(null)
|
||||
const [defaultLayout, setDefaultLayout] = useState(true)
|
||||
const [displayCumulativeSize, setDisplayCumulativeSize] = useState(false)
|
||||
|
@ -162,9 +163,14 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
|
||||
const currentOrderbookData = useRef<any>(null)
|
||||
const nextOrderbookData = useRef<any>(null)
|
||||
const orderbookElRef = useRef<HTMLDivElement>(null)
|
||||
const previousDepth = usePrevious(depth)
|
||||
const previousGrouping = usePrevious(grouping)
|
||||
|
||||
const depthArray = useMemo(() => {
|
||||
return Array(depth).fill(0)
|
||||
}, [depth])
|
||||
|
||||
const serum3MarketExternal = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (!group || !selectedMarket) return
|
||||
|
@ -188,6 +194,13 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
[]
|
||||
)
|
||||
|
||||
const verticallyCenterOrderbook = useCallback(() => {
|
||||
const element = orderbookElRef.current
|
||||
if (element) {
|
||||
element.scrollTop = (element.scrollHeight - element.offsetHeight) / 2
|
||||
}
|
||||
}, [])
|
||||
|
||||
useInterval(() => {
|
||||
const orderbook = mangoStore.getState().selectedMarket.orderbook
|
||||
const group = mangoStore.getState().group
|
||||
|
@ -273,6 +286,9 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
spread,
|
||||
spreadPercentage,
|
||||
})
|
||||
if (!isScrolled) {
|
||||
verticallyCenterOrderbook()
|
||||
}
|
||||
} else {
|
||||
setOrderbookData(null)
|
||||
}
|
||||
|
@ -337,9 +353,17 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
}
|
||||
}, [serum3MarketExternal])
|
||||
|
||||
const onGroupSizeChange = (groupSize: number) => {
|
||||
useEffect(() => {
|
||||
function handleResize() {
|
||||
verticallyCenterOrderbook()
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize)
|
||||
}, [verticallyCenterOrderbook])
|
||||
|
||||
const onGroupSizeChange = useCallback((groupSize: number) => {
|
||||
setGrouping(groupSize)
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (!serum3MarketExternal) return null
|
||||
|
||||
|
@ -409,35 +433,43 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
<div className="col-span-1 text-right">Size</div>
|
||||
<div className="col-span-1 text-right">Price</div>
|
||||
</div>
|
||||
<div className="hide-scroll relative h-full overflow-y-scroll">
|
||||
{showSells
|
||||
? orderbookData?.asks.map(
|
||||
({
|
||||
price,
|
||||
size,
|
||||
cumulativeSize,
|
||||
sizePercent,
|
||||
maxSizePercent,
|
||||
}: cumOrderbookSide) => (
|
||||
<MemoizedOrderbookRow
|
||||
minOrderSize={serum3MarketExternal.minOrderSize}
|
||||
tickSize={serum3MarketExternal.tickSize}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
key={price + ''}
|
||||
price={price}
|
||||
size={displayCumulativeSize ? cumulativeSize : size}
|
||||
side="sell"
|
||||
sizePercent={
|
||||
displayCumulativeSize ? maxSizePercent : sizePercent
|
||||
}
|
||||
grouping={grouping}
|
||||
/>
|
||||
<div
|
||||
className="hide-scroll relative h-full overflow-y-scroll"
|
||||
ref={orderbookElRef}
|
||||
onScroll={() => setIsScrolled(true)}
|
||||
>
|
||||
{showSells && orderbookData?.asks?.length
|
||||
? depthArray.map((_x, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
{orderbookData?.asks[index] ? (
|
||||
<MemoizedOrderbookRow
|
||||
minOrderSize={serum3MarketExternal.minOrderSize}
|
||||
tickSize={serum3MarketExternal.tickSize}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
key={orderbookData?.asks[index].price}
|
||||
price={orderbookData?.asks[index].price}
|
||||
size={
|
||||
displayCumulativeSize
|
||||
? orderbookData?.asks[index].cumulativeSize
|
||||
: orderbookData?.asks[index].size
|
||||
}
|
||||
side="sell"
|
||||
sizePercent={
|
||||
displayCumulativeSize
|
||||
? orderbookData?.asks[index].maxSizePercent
|
||||
: orderbookData?.asks[index].sizePercent
|
||||
}
|
||||
grouping={grouping}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
})
|
||||
: null}
|
||||
{showBuys && showSells ? (
|
||||
<div className="my-2 grid grid-cols-2 border-y border-th-bkg-3 py-2 px-4 text-xs text-th-fgd-4">
|
||||
|
@ -452,34 +484,35 @@ const Orderbook = ({ depth = 12 }) => {
|
|||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{showBuys
|
||||
? orderbookData?.bids.map(
|
||||
({
|
||||
price,
|
||||
size,
|
||||
cumulativeSize,
|
||||
sizePercent,
|
||||
maxSizePercent,
|
||||
}: cumOrderbookSide) => (
|
||||
<MemoizedOrderbookRow
|
||||
minOrderSize={serum3MarketExternal.minOrderSize}
|
||||
tickSize={serum3MarketExternal.tickSize}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
key={price}
|
||||
price={price}
|
||||
size={displayCumulativeSize ? cumulativeSize : size}
|
||||
side="buy"
|
||||
sizePercent={
|
||||
displayCumulativeSize ? maxSizePercent : sizePercent
|
||||
}
|
||||
grouping={grouping}
|
||||
/>
|
||||
)
|
||||
)
|
||||
{showBuys && orderbookData?.bids?.length
|
||||
? depthArray.map((_x, index) => (
|
||||
<div key={index}>
|
||||
{orderbookData?.bids[index] ? (
|
||||
<MemoizedOrderbookRow
|
||||
minOrderSize={serum3MarketExternal.minOrderSize}
|
||||
tickSize={serum3MarketExternal.tickSize}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
price={orderbookData?.bids[index].price}
|
||||
size={
|
||||
displayCumulativeSize
|
||||
? orderbookData?.bids[index].cumulativeSize
|
||||
: orderbookData?.bids[index].size
|
||||
}
|
||||
side="buy"
|
||||
sizePercent={
|
||||
displayCumulativeSize
|
||||
? orderbookData?.bids[index].maxSizePercent
|
||||
: orderbookData?.bids[index].sizePercent
|
||||
}
|
||||
grouping={grouping}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -561,7 +594,7 @@ const OrderbookRow = ({
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex cursor-pointer justify-between border-b border-b-th-bkg-1 text-sm`}
|
||||
className={`relative flex h-[24px] cursor-pointer justify-between border-b border-b-th-bkg-1 text-sm`}
|
||||
ref={element}
|
||||
>
|
||||
<>
|
||||
|
|
|
@ -49,7 +49,7 @@ const getHeight = (
|
|||
const TradeAdvancedPage = () => {
|
||||
const { height, width } = useViewport()
|
||||
const [currentBreakpoint, setCurrentBreakpoint] = useState<string>()
|
||||
const [orderbookDepth, setOrderbookDepth] = useState(6)
|
||||
const [orderbookDepth, setOrderbookDepth] = useState(60)
|
||||
const { uiLocked } = mangoStore((s) => s.settings)
|
||||
const showMobileView = width <= breakpoints.md
|
||||
|
||||
|
@ -150,29 +150,6 @@ const TradeAdvancedPage = () => {
|
|||
defaultLayouts
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const adjustOrderBook = (
|
||||
layouts: ReactGridLayout.Layouts,
|
||||
breakpoint?: string | null
|
||||
) => {
|
||||
const bp = breakpoint ? breakpoint : getCurrentBreakpoint()
|
||||
if (bp) {
|
||||
const orderbookLayout = layouts[bp].find((obj) => {
|
||||
return obj.i === 'orderbook'
|
||||
})
|
||||
let depth = (orderbookLayout!.h / 24 / 2) * 1.25
|
||||
const maxNum = Math.max(1, depth)
|
||||
if (typeof maxNum === 'number') {
|
||||
depth = Math.round(maxNum)
|
||||
}
|
||||
|
||||
setOrderbookDepth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
adjustOrderBook(defaultLayouts, currentBreakpoint)
|
||||
}, [currentBreakpoint, defaultLayouts])
|
||||
|
||||
const onLayoutChange = useCallback((layouts: ReactGridLayout.Layouts) => {
|
||||
if (layouts) {
|
||||
setSavedLayouts(layouts)
|
||||
|
|
Loading…
Reference in New Issue