Merge branch 'serum' into main
This commit is contained in:
commit
007c3c2fa2
|
@ -3,7 +3,7 @@ import { ReactNode, useEffect } from 'react'
|
|||
import { ChevronRightIcon } from '@heroicons/react/20/solid'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
import { breakpoints } from '../utils/theme'
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import BottomBar from './mobile/BottomBar'
|
||||
import BounceLoader from './shared/BounceLoader'
|
||||
import TopBar from './TopBar'
|
||||
|
@ -71,7 +71,9 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||
/>
|
||||
<TopBar />
|
||||
</div>
|
||||
<div className="min-h-screen p-6 pb-20 md:p-8">{children}</div>
|
||||
<div className="hide-scroll max-h-screen overflow-y-scroll">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
} from '@heroicons/react/20/solid'
|
||||
import { Popover, Transition } from '@headlessui/react'
|
||||
import { MangoAccount } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { LinkButton } from './shared/Button'
|
||||
import CreateAccountModal from './modals/CreateAccountModal'
|
||||
import { useLocalStorageStringState } from '../hooks/useLocalStorageState'
|
||||
|
|
|
@ -9,20 +9,17 @@ import {
|
|||
CurrencyDollarIcon,
|
||||
ChartBarIcon,
|
||||
Cog8ToothIcon,
|
||||
ArrowsRightLeftIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { Fragment, ReactNode, useEffect, useState } from 'react'
|
||||
import { Disclosure, Popover, Transition } from '@headlessui/react'
|
||||
import MangoAccountSummary from './account/MangoAccountSummary'
|
||||
import HealthHeart from './account/HealthHeart'
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import Tooltip from './shared/Tooltip'
|
||||
import { HealthType } from '@blockworks-foundation/mango-v4'
|
||||
|
||||
const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const router = useRouter()
|
||||
const { pathname } = router
|
||||
|
||||
|
@ -70,6 +67,13 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
|||
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}
|
||||
|
@ -125,33 +129,7 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
|||
</ExpandableMenuItem>
|
||||
</div>
|
||||
</div>
|
||||
{mangoAccount ? (
|
||||
<div className="border-t border-th-bkg-3">
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={
|
||||
<HealthHeart
|
||||
health={mangoAccount.getHealthRatioUi(HealthType.maint)!}
|
||||
size={32}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<div className="text-left">
|
||||
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount.name}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
alignBottom
|
||||
hideIconBg
|
||||
>
|
||||
<div className="px-4 pb-4 pt-2">
|
||||
<MangoAccountSummary />
|
||||
</div>
|
||||
</ExpandableMenuItem>
|
||||
</div>
|
||||
) : null}
|
||||
<MangoAccountSummary collapsed={collapsed} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -219,7 +197,7 @@ const MenuItem = ({
|
|||
)
|
||||
}
|
||||
|
||||
const ExpandableMenuItem = ({
|
||||
export const ExpandableMenuItem = ({
|
||||
alignBottom,
|
||||
children,
|
||||
collapsed,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
|
|||
// import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { COLORS } from '../styles/colors'
|
||||
// import { SHOW_ZERO_BALANCES_KEY } from '../utils/constants'
|
||||
import { formatDecimal, formatFixedDecimals } from '../utils/numbers'
|
||||
|
@ -46,12 +46,6 @@ const TokenList = () => {
|
|||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
||||
useEffect(() => {
|
||||
if (coingeckoPrices.length === 0) {
|
||||
actions.fetchCoingeckoPrices()
|
||||
}
|
||||
}, [coingeckoPrices, actions])
|
||||
|
||||
const banks = useMemo(() => {
|
||||
if (group) {
|
||||
const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({
|
||||
|
@ -424,7 +418,7 @@ const ActionsMenu = ({
|
|||
s.swap.outputTokenInfo = outputTokenInfo
|
||||
})
|
||||
if (asPath === '/') {
|
||||
router.push('/trade', undefined, { shallow: true })
|
||||
router.push('/swap', undefined, { shallow: true })
|
||||
}
|
||||
}, [bank, router, asPath, set, jupiterTokens])
|
||||
|
||||
|
@ -437,7 +431,7 @@ const ActionsMenu = ({
|
|||
s.swap.inputTokenInfo = inputTokenInfo
|
||||
})
|
||||
if (asPath === '/') {
|
||||
router.push('/trade', undefined, { shallow: true })
|
||||
router.push('/swap', undefined, { shallow: true })
|
||||
}
|
||||
}, [router, asPath, set, bank, jupiterTokens])
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'
|
|||
import { ArrowRightIcon } from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import WalletIcon from './icons/WalletIcon'
|
||||
import MangoAccountsList from './MangoAccountsList'
|
||||
import { LinkButton } from './shared/Button'
|
||||
|
|
|
@ -15,7 +15,7 @@ import { IconButton } from './shared/Button'
|
|||
import { Transition } from '@headlessui/react'
|
||||
import SheenLoader from './shared/SheenLoader'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { TradeHistoryItem } from '../store/mangoStore'
|
||||
import { TradeHistoryItem } from '@store/mangoStore'
|
||||
import {
|
||||
countLeadingZeros,
|
||||
formatFixedDecimals,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { MangoAccount } from '@blockworks-foundation/mango-v4'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import DetailedAreaChart from '../shared/DetailedAreaChart'
|
||||
|
||||
const AccountChart = ({
|
||||
|
|
|
@ -10,7 +10,7 @@ import { useEffect, useMemo, useState } from 'react'
|
|||
import AccountActions from './AccountActions'
|
||||
import DepositModal from '../modals/DepositModal'
|
||||
import WithdrawModal from '../modals/WithdrawModal'
|
||||
import mangoStore, { PerformanceDataItem } from '../../store/mangoStore'
|
||||
import mangoStore, { PerformanceDataItem } from '@store/mangoStore'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
import { DownTriangle, UpTriangle } from '../shared/DirectionTriangles'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import TabButtons from '../shared/TabButtons'
|
||||
import TokenList from '../TokenList'
|
||||
import TradeHistoryTable from '../TradeHistoryTable'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import Image from 'next/image'
|
||||
import { useMemo } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
|
||||
const ActionTokenItem = ({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import ActionTokenItem from './ActionTokenItem'
|
||||
|
||||
type BankParams = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import {
|
||||
HealthType,
|
||||
toUiDecimalsForQuote,
|
||||
|
@ -10,8 +10,10 @@ import DepositModal from '../modals/DepositModal'
|
|||
import WithdrawModal from '../modals/WithdrawModal'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { ArrowDownTrayIcon } from '@heroicons/react/20/solid'
|
||||
import HealthHeart from './HealthHeart'
|
||||
import { ExpandableMenuItem } from '../SideNav'
|
||||
|
||||
const MangoAccountSummary = () => {
|
||||
const MangoAccountSummary = ({ collapsed }: { collapsed: boolean }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const [showDepositModal, setShowDepositModal] = useState(false)
|
||||
|
@ -19,59 +21,90 @@ const MangoAccountSummary = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-4 space-y-2">
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('health')}</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(HealthType.maint)
|
||||
: 100}
|
||||
%
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('account-value')}</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
$
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
toUiDecimalsForQuote(mangoAccount.getEquity()!.toNumber()),
|
||||
2
|
||||
)
|
||||
: (0).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('free-collateral')}</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
$
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue()!.toNumber()
|
||||
),
|
||||
2
|
||||
)
|
||||
: (0).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
className="flex w-full items-center justify-center"
|
||||
onClick={() => setShowDepositModal(true)}
|
||||
>
|
||||
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('deposit')}
|
||||
</Button>
|
||||
{/* <Button
|
||||
{mangoAccount ? (
|
||||
<div className="border-t border-th-bkg-3">
|
||||
<ExpandableMenuItem
|
||||
collapsed={collapsed}
|
||||
icon={
|
||||
<HealthHeart
|
||||
health={mangoAccount.getHealthRatioUi(HealthType.maint)!}
|
||||
size={32}
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<div className="text-left">
|
||||
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount.name}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
alignBottom
|
||||
hideIconBg
|
||||
>
|
||||
<div className="px-4 pb-4 pt-2">
|
||||
<div className="mb-4 space-y-2">
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('health')}</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
{mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(HealthType.maint)
|
||||
: 100}
|
||||
%
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('account-value')}</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
$
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getEquity()!.toNumber()
|
||||
),
|
||||
2
|
||||
)
|
||||
: (0).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">
|
||||
{t('free-collateral')}
|
||||
</p>
|
||||
<p className="text-sm font-bold text-th-fgd-1">
|
||||
$
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
toUiDecimalsForQuote(
|
||||
mangoAccount.getCollateralValue()!.toNumber()
|
||||
),
|
||||
2
|
||||
)
|
||||
: (0).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
className="flex w-full items-center justify-center"
|
||||
onClick={() => setShowDepositModal(true)}
|
||||
>
|
||||
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('deposit')}
|
||||
</Button>
|
||||
{/* <Button
|
||||
className="w-full"
|
||||
onClick={() => setShowWithdrawModal(true)}
|
||||
secondary
|
||||
>
|
||||
{t('withdraw')}
|
||||
</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ExpandableMenuItem>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
isOpen={showDepositModal}
|
||||
|
|
|
@ -49,13 +49,13 @@ const BottomBar = () => {
|
|||
</Link>
|
||||
<Link
|
||||
href={{
|
||||
pathname: '/trade',
|
||||
pathname: '/swap',
|
||||
}}
|
||||
shallow={true}
|
||||
>
|
||||
<a
|
||||
className={`${
|
||||
asPath === '/trade' ? 'text-th-primary' : 'text-th-fgd-3'
|
||||
asPath === '/swap' ? 'text-th-primary' : 'text-th-fgd-3'
|
||||
} col-span-1 flex cursor-pointer flex-col items-center`}
|
||||
>
|
||||
<TradeIcon className="mb-1 h-4 w-4" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import Button from '../shared/Button'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useTranslation } from 'next-i18next'
|
|||
import Image from 'next/image'
|
||||
import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import { INPUT_TOKEN_DEFAULT } from '../../utils/constants'
|
||||
import { notify } from '../../utils/notifications'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import Button from '../shared/Button'
|
||||
|
|
|
@ -2,7 +2,7 @@ import { ChangeEvent, useState } from 'react'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import Button from '../shared/Button'
|
||||
import BounceLoader from '../shared/BounceLoader'
|
||||
|
|
|
@ -17,7 +17,7 @@ import React, {
|
|||
useState,
|
||||
} from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import { ALPHA_DEPOSIT_LIMIT, INPUT_TOKEN_DEFAULT } from '../../utils/constants'
|
||||
import { notify } from '../../utils/notifications'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { PhotoIcon } from '@heroicons/react/20/solid'
|
||||
import Modal from '../shared/Modal'
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
XMarkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { EnterRightExitLeft, FadeInFadeOut } from '../shared/Transitions'
|
||||
import Image from 'next/image'
|
||||
import BounceLoader from '../shared/BounceLoader'
|
||||
|
|
|
@ -10,7 +10,7 @@ import Image from 'next/image'
|
|||
import { ChangeEvent, useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import { INPUT_TOKEN_DEFAULT } from '../../utils/constants'
|
||||
import { notify } from '../../utils/notifications'
|
||||
|
|
|
@ -15,7 +15,7 @@ const ContentBox = ({
|
|||
}: ContentBoxProps) => {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-lg ${hideBorder ? '' : 'border border-th-bkg-3'} ${
|
||||
className={`rounded ${hideBorder ? '' : 'border border-th-bkg-3'} ${
|
||||
showBackground ? 'bg-th-bkg-2' : ''
|
||||
} ${hidePadding ? '' : 'p-6'} ${className}`}
|
||||
>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ArrowRightIcon } from '@heroicons/react/20/solid'
|
|||
import { PublicKey } from '@solana/web3.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useMemo } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
const HealthImpact = ({
|
||||
uiAmount,
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
InformationCircleIcon,
|
||||
XCircleIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import mangoStore, { CLUSTER } from '../../store/mangoStore'
|
||||
import mangoStore, { CLUSTER } from '@store/mangoStore'
|
||||
import { Notification, notify } from '../../utils/notifications'
|
||||
import Loading from './Loading'
|
||||
import { Transition } from '@headlessui/react'
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useWallet } from '@solana/wallet-adapter-react'
|
|||
import { PublicKey } from '@solana/web3.js'
|
||||
import { getProfilePicture } from '@solflare-wallet/pfp'
|
||||
import { useEffect, useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import ProfileIcon from '../icons/ProfileIcon'
|
||||
|
||||
const ProfileImage = ({
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React, { FunctionComponent } from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
type SideBadgeProps = {
|
||||
side: string
|
||||
}
|
||||
|
||||
const SideBadge: FunctionComponent<SideBadgeProps> = ({ side }) => {
|
||||
const { t } = useTranslation('common')
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`inline-block rounded uppercase ${
|
||||
side === 'buy' || side === 'long'
|
||||
? 'border border-th-green text-th-green'
|
||||
: 'border border-th-red text-th-red'
|
||||
}
|
||||
-my-0.5 px-1.5 py-0.5 text-xs uppercase`}
|
||||
>
|
||||
{t(side)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SideBadge
|
|
@ -1,5 +1,5 @@
|
|||
import { MangoAccount } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
export default function useMangoAccount(): {
|
||||
mangoAccount: MangoAccount | undefined
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { useEffect, useRef } from 'react'
|
||||
|
||||
export default function usePrevious(value: any): any {
|
||||
// The ref object is a generic container whose current property is mutable ...
|
||||
// ... and can hold any value, similar to an instance property on a class
|
||||
const ref = useRef()
|
||||
|
||||
// Store current value in ref
|
||||
useEffect(() => {
|
||||
ref.current = value
|
||||
}, [value]) // Only re-run if value changes
|
||||
|
||||
// Return previous value (happens before update in useEffect above)
|
||||
return ref.current
|
||||
}
|
|
@ -8,7 +8,7 @@ import Image from 'next/image'
|
|||
import { Fragment, useMemo, useState } from 'react'
|
||||
import { useViewport } from '../../hooks/useViewport'
|
||||
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import { IconButton } from '../shared/Button'
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Jupiter, RouteInfo, TransactionFeeInfo } from '@jup-ag/core'
|
|||
import JSBI from 'jsbi'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import RoutesModal from './RoutesModal'
|
||||
import Button, { IconButton } from '../shared/Button'
|
||||
import Loading from '../shared/Loading'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Decimal from 'decimal.js'
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useTokenMax } from './useTokenMax'
|
||||
|
||||
const LeverageSlider = ({
|
||||
|
|
|
@ -2,7 +2,7 @@ import { RouteInfo } from '@jup-ag/core'
|
|||
import { Dispatch, SetStateAction } from 'react'
|
||||
import JSBI from 'jsbi'
|
||||
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
import Modal from '../shared/Modal'
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { RouteInfo } from '@jup-ag/core'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import Decimal from 'decimal.js'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import JupiterRouteInfo from './JupiterRouteInfo'
|
||||
import TokenSelect from './TokenSelect'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { memo, useMemo, useState, useEffect, ChangeEvent } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Input from '../forms/Input'
|
||||
import { IconButton } from '../shared/Button'
|
||||
import {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { XMarkIcon } from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import ButtonGroup from '../forms/ButtonGroup'
|
||||
import Input from '../forms/Input'
|
||||
import Switch from '../forms/Switch'
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
QuestionMarkCircleIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import Image from 'next/image'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
type TokenSelectProps = {
|
||||
tokenSymbol: string | undefined
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Swap from './SwapForm'
|
||||
import SwapTokenChart from './SwapTokenChart'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import AccountTabs from '../account/AccountTabs'
|
||||
|
||||
const TradeSimplePage = () => {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'
|
|||
import JSBI from 'jsbi'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
import mangoStore, { CLUSTER } from '../../store/mangoStore'
|
||||
import mangoStore, { CLUSTER } from '@store/mangoStore'
|
||||
import { Token } from '../../types/jupiter'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Bank, Group, MangoAccount } from '@blockworks-foundation/mango-v4'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useMemo } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { floorToDecimal } from '../../utils/numbers'
|
||||
import useMangoAccount from '../shared/useMangoAccount'
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import { Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import PercentageChange from '@components/shared/PercentageChange'
|
||||
import { Popover } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { DEFAULT_MARKET_NAME } from 'utils/constants'
|
||||
import { formatFixedDecimals } from 'utils/numbers'
|
||||
|
||||
const MarketSelectDropdown = () => {
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const set = mangoStore((s) => s.set)
|
||||
|
||||
const handleSelectMarket = useCallback(
|
||||
(market: Serum3Market, close: any) => {
|
||||
set((s) => {
|
||||
s.selectedMarket.current = market
|
||||
})
|
||||
close()
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
{({ close, open }) => (
|
||||
<div className="relative flex flex-col overflow-visible">
|
||||
<Popover.Button className="flex w-full items-center hover:text-th-primary">
|
||||
<div className="p-4">
|
||||
<div className="text-lg">
|
||||
{selectedMarket?.name || DEFAULT_MARKET_NAME}
|
||||
</div>
|
||||
</div>
|
||||
<ChevronDownIcon
|
||||
className={`${
|
||||
open ? 'rotate-180' : 'rotate-360'
|
||||
} mt-0.5 h-6 w-6 flex-shrink-0 text-th-fgd-3`}
|
||||
/>
|
||||
</Popover.Button>
|
||||
|
||||
<Popover.Panel className="absolute top-16 z-50 mr-4 w-56 border border-th-bkg-3 bg-th-bkg-1">
|
||||
{serumMarkets?.length
|
||||
? serumMarkets.map((m) => (
|
||||
<div
|
||||
key={m.publicKey.toString()}
|
||||
className="bg-th-bkg-1 py-2 px-4 hover:cursor-pointer hover:bg-th-bkg-2"
|
||||
onClick={() => handleSelectMarket(m, close)}
|
||||
>
|
||||
{m.name}
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
</Popover.Panel>
|
||||
</div>
|
||||
)}
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
const OraclePrice = () => {
|
||||
const group = mangoStore((s) => s.group)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
if (!group || !selectedMarket) return null
|
||||
|
||||
const baseTokenBank = group.getFirstBankByTokenIndex(
|
||||
selectedMarket?.baseTokenIndex
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="text-th-fgd-1 md:text-xs">
|
||||
$
|
||||
{baseTokenBank.uiPrice
|
||||
? formatFixedDecimals(baseTokenBank.uiPrice)
|
||||
: null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const AdvancedMarketHeader = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
|
||||
const baseSymbol = useMemo(() => {
|
||||
return selectedMarket?.name.split('/')[0]
|
||||
}, [selectedMarket])
|
||||
|
||||
const coingeckoData = coingeckoPrices.find((asset) =>
|
||||
baseSymbol === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === baseSymbol
|
||||
)
|
||||
|
||||
const change = coingeckoData
|
||||
? ((coingeckoData.prices[coingeckoData.prices.length - 1][1] -
|
||||
coingeckoData.prices[0][1]) /
|
||||
coingeckoData.prices[0][1]) *
|
||||
100
|
||||
: 0
|
||||
|
||||
return (
|
||||
<div className="flex items-center border border-th-bkg-3 bg-th-bkg-1">
|
||||
<div className="hidden md:block md:pr-6 lg:pb-0">
|
||||
<div className="flex items-center">
|
||||
<MarketSelectDropdown />
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-6 flex-col">
|
||||
<div className="text-th-fgd-4 md:pb-0.5 md:text-xs">
|
||||
{t('oracle-price')}
|
||||
</div>
|
||||
<OraclePrice />
|
||||
</div>
|
||||
<div className="ml-6 flex-col">
|
||||
<div className="text-th-fgd-4 md:pb-0.5 md:text-xs">
|
||||
{t('rolling-change')}
|
||||
</div>
|
||||
<div
|
||||
className={`text-xs ${change < 0 ? 'text-th-red' : 'text-th-gree'}`}
|
||||
>
|
||||
{isNaN(change) ? '0.00' : change.toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdvancedMarketHeader
|
|
@ -0,0 +1,311 @@
|
|||
import {
|
||||
Serum3OrderType,
|
||||
Serum3SelfTradeBehavior,
|
||||
Serum3Side,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
import Checkbox from '@components/forms/Checkbox'
|
||||
import Button from '@components/shared/Button'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import { notify } from 'utils/notifications'
|
||||
|
||||
const AdvancedTradeForm = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const set = mangoStore.getState().set
|
||||
const tradeForm = mangoStore((s) => s.tradeForm)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const [useMargin, setUseMargin] = useState(true)
|
||||
|
||||
const baseSymbol = useMemo(() => {
|
||||
return selectedMarket?.name.split('/')[0]
|
||||
}, [selectedMarket])
|
||||
|
||||
const quoteSymbol = useMemo(() => {
|
||||
return selectedMarket?.name.split('/')[1]
|
||||
}, [selectedMarket])
|
||||
|
||||
const setTradeType = useCallback(
|
||||
(tradeType: 'Limit' | 'Market') => {
|
||||
set((s) => {
|
||||
s.tradeForm.tradeType = tradeType
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handlePriceChange = useCallback(
|
||||
(e: NumberFormatValues) => {
|
||||
set((s) => {
|
||||
s.tradeForm.price = e.value
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handleBaseSizeChange = useCallback(
|
||||
(e: NumberFormatValues) => {
|
||||
set((s) => {
|
||||
s.tradeForm.baseSize = e.value
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handlePostOnlyChange = useCallback(
|
||||
(postOnly: boolean) => {
|
||||
set((s) => {
|
||||
s.tradeForm.postOnly = postOnly
|
||||
if (s.tradeForm.ioc === true) {
|
||||
s.tradeForm.ioc = !postOnly
|
||||
}
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handleIocChange = useCallback(
|
||||
(ioc: boolean) => {
|
||||
set((s) => {
|
||||
s.tradeForm.ioc = ioc
|
||||
if (s.tradeForm.postOnly === true) {
|
||||
s.tradeForm.postOnly = !ioc
|
||||
}
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handleSetSide = useCallback(
|
||||
(side: 'buy' | 'sell') => {
|
||||
set((s) => {
|
||||
s.tradeForm.side = side
|
||||
})
|
||||
},
|
||||
[set]
|
||||
)
|
||||
|
||||
const handlePlaceOrder = useCallback(async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
const tradeForm = mangoStore.getState().tradeForm
|
||||
const actions = mangoStore.getState().actions
|
||||
|
||||
if (!group || !mangoAccount) return
|
||||
|
||||
try {
|
||||
const orderType = tradeForm.ioc
|
||||
? Serum3OrderType.immediateOrCancel
|
||||
: tradeForm.postOnly
|
||||
? Serum3OrderType.postOnly
|
||||
: Serum3OrderType.limit
|
||||
|
||||
const tx = await client.serum3PlaceOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
selectedMarket!.serumMarketExternal,
|
||||
tradeForm.side === 'buy' ? Serum3Side.bid : Serum3Side.ask,
|
||||
new Decimal(tradeForm.price).toNumber(),
|
||||
new Decimal(tradeForm.baseSize).toNumber(),
|
||||
Serum3SelfTradeBehavior.decrementTake,
|
||||
orderType,
|
||||
Date.now(),
|
||||
10
|
||||
)
|
||||
actions.reloadMangoAccount()
|
||||
notify({
|
||||
type: 'success',
|
||||
title: 'Transaction successful',
|
||||
txid: tx,
|
||||
})
|
||||
} catch (e: any) {
|
||||
notify({
|
||||
title: t('order-error'),
|
||||
description: e.message,
|
||||
txid: e.txid,
|
||||
type: 'error',
|
||||
})
|
||||
console.error('Place trade error:', e)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="grid select-none grid-cols-2 justify-between border-b border-th-bkg-3 text-base">
|
||||
<div
|
||||
onClick={() => setTradeType('Limit')}
|
||||
className={`py-3 px-4 text-center text-sm hover:cursor-pointer ${
|
||||
tradeForm.tradeType === 'Limit'
|
||||
? 'bg-th-bkg-2 text-th-primary'
|
||||
: 'text-th-fgd-4 hover:text-th-fgd-2'
|
||||
}`}
|
||||
>
|
||||
Limit
|
||||
</div>
|
||||
<div
|
||||
onClick={() => setTradeType('Market')}
|
||||
className={`py-3 px-4 text-center text-sm hover:cursor-pointer ${
|
||||
tradeForm.tradeType === 'Market'
|
||||
? 'bg-th-bkg-2 text-th-primary'
|
||||
: 'text-th-fgd-4 hover:text-th-fgd-2'
|
||||
}`}
|
||||
>
|
||||
Market
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 px-6">
|
||||
<div
|
||||
className={`relative mb-3 md:-mt-2.5 md:border-b md:border-th-bkg-3`}
|
||||
>
|
||||
<div
|
||||
className={`absolute hidden md:block ${
|
||||
tradeForm.side === 'buy'
|
||||
? 'translate-x-0 bg-th-green'
|
||||
: 'translate-x-full bg-th-red'
|
||||
} default-transition bottom-[-1px] left-0 h-0.5 w-1/2 transform`}
|
||||
/>
|
||||
<nav className="-mb-px flex space-x-2" aria-label="Tabs">
|
||||
<button
|
||||
onClick={() => handleSetSide('buy')}
|
||||
className={`default-transition relative flex w-1/2 cursor-pointer
|
||||
items-center justify-center whitespace-nowrap py-1 text-sm font-semibold md:text-base md:hover:opacity-100
|
||||
${
|
||||
tradeForm.side === 'buy'
|
||||
? `border border-th-green text-th-green md:border-0`
|
||||
: `border border-th-fgd-4 text-th-fgd-4 md:border-0 md:hover:border-th-green md:hover:text-th-green`
|
||||
}
|
||||
`}
|
||||
>
|
||||
{t('buy')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleSetSide('sell')}
|
||||
className={`default-transition relative flex w-1/2 cursor-pointer
|
||||
items-center justify-center whitespace-nowrap py-1 text-sm font-semibold md:text-base md:hover:opacity-100
|
||||
${
|
||||
tradeForm.side === 'sell'
|
||||
? `border border-th-red text-th-red md:border-0`
|
||||
: `border border-th-fgd-4 text-th-fgd-4 md:border-0 md:hover:border-th-red md:hover:text-th-red`
|
||||
}
|
||||
`}
|
||||
>
|
||||
{t('sell')}
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 px-4">
|
||||
<div className="my-2 flex items-center justify-between">
|
||||
<p className="text-xs text-th-fgd-3">{t('amount')}</p>
|
||||
</div>
|
||||
<div className="flex items-center rounded-md bg-th-bkg-2 p-2 text-lg font-bold text-th-fgd-1">
|
||||
<NumberFormat
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={6}
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className="w-full bg-th-bkg-2 text-right font-mono focus:outline-none"
|
||||
placeholder="0.00"
|
||||
value={tradeForm.baseSize}
|
||||
onValueChange={handleBaseSizeChange}
|
||||
/>
|
||||
<div className="ml-2 text-sm text-th-fgd-4">{baseSymbol}</div>
|
||||
</div>
|
||||
<div className="my-2 flex items-center justify-between">
|
||||
<p className="text-xs text-th-fgd-3">Limit Price</p>
|
||||
</div>
|
||||
<div className="flex items-center rounded-md bg-th-bkg-2 p-2 text-lg font-bold text-th-fgd-1">
|
||||
<NumberFormat
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={6}
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className="w-full bg-th-bkg-2 text-right font-mono focus:outline-none"
|
||||
placeholder="0.00"
|
||||
value={tradeForm.price}
|
||||
onValueChange={handlePriceChange}
|
||||
/>
|
||||
<div className="ml-2 text-sm text-th-fgd-4">{quoteSymbol}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 flex px-5">
|
||||
{tradeForm.tradeType === 'Limit' ? (
|
||||
<div className="flex">
|
||||
<div className="mr-4 ">
|
||||
<Tooltip
|
||||
className="hidden md:block"
|
||||
delay={250}
|
||||
placement="left"
|
||||
content={t('tooltip-post')}
|
||||
>
|
||||
<Checkbox
|
||||
checked={tradeForm.postOnly}
|
||||
onChange={(e) => handlePostOnlyChange(e.target.checked)}
|
||||
>
|
||||
Post
|
||||
</Checkbox>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="mr-4 ">
|
||||
<Tooltip
|
||||
className="hidden md:block"
|
||||
delay={250}
|
||||
placement="top"
|
||||
content={t('tooltip-ioc')}
|
||||
>
|
||||
<div className="flex items-center text-xs text-th-fgd-3">
|
||||
<Checkbox
|
||||
checked={tradeForm.ioc}
|
||||
onChange={(e) => handleIocChange(e.target.checked)}
|
||||
>
|
||||
IOC
|
||||
</Checkbox>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="">
|
||||
<Tooltip
|
||||
delay={250}
|
||||
placement="left"
|
||||
content={t('tooltip-enable-margin')}
|
||||
>
|
||||
<Checkbox
|
||||
checked={useMargin}
|
||||
onChange={(e) => setUseMargin(e.target.checked)}
|
||||
>
|
||||
{t('margin')}
|
||||
</Checkbox>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 flex px-4">
|
||||
<Button
|
||||
onClick={handlePlaceOrder}
|
||||
className={`flex w-full items-center justify-center text-base ${
|
||||
tradeForm.side === 'buy'
|
||||
? 'bg-th-green-dark text-white'
|
||||
: 'bg-th-red-dark text-th-fgd-1'
|
||||
}`}
|
||||
disabled={false}
|
||||
size="medium"
|
||||
>
|
||||
<span className="capitalize">Place {tradeForm.side} Order</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdvancedTradeForm
|
|
@ -0,0 +1,216 @@
|
|||
import { Serum3Side } from '@blockworks-foundation/mango-v4'
|
||||
import Button from '@components/shared/Button'
|
||||
import SideBadge from '@components/shared/SideBadge'
|
||||
import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
|
||||
import { Order } from '@project-serum/serum/lib/market'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/image'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { notify } from 'utils/notifications'
|
||||
import { formatDecimal, formatFixedDecimals } from 'utils/numbers'
|
||||
|
||||
const TABS = ['Balances', 'Open Orders']
|
||||
|
||||
const BalanceAndOpenOrders = () => {
|
||||
const [selectedTab, setSelectedTab] = useState('Open Orders')
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
useEffect(() => {
|
||||
const actions = mangoStore.getState().actions
|
||||
|
||||
if (mangoAccount && selectedMarket) {
|
||||
actions.fetchOpenOrdersForMarket(selectedMarket)
|
||||
}
|
||||
}, [mangoAccount, selectedMarket])
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-y-scroll">
|
||||
<div className="sticky top-0 flex select-none border-b border-th-bkg-3 bg-th-bkg-1 text-th-fgd-3">
|
||||
{TABS.map((tab) => {
|
||||
return (
|
||||
<div
|
||||
key={tab}
|
||||
onClick={() => setSelectedTab(tab)}
|
||||
className={`border-r border-th-bkg-3 px-4 py-4 ${
|
||||
selectedTab === tab
|
||||
? 'bg-th-bkg-2 text-th-primary'
|
||||
: 'hover:cursor-pointer hover:text-th-fgd-2'
|
||||
}`}
|
||||
>
|
||||
{tab}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{selectedTab === 'Balances' ? <Balances /> : null}
|
||||
{selectedTab === 'Open Orders' ? <OpenOrders /> : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Balances = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const jupiterTokens = mangoStore((s) => s.jupiterTokens)
|
||||
|
||||
const banks = useMemo(() => {
|
||||
if (group) {
|
||||
const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({
|
||||
key,
|
||||
value,
|
||||
}))
|
||||
const sortedBanks = mangoAccount
|
||||
? rawBanks.sort(
|
||||
(a, b) =>
|
||||
Math.abs(
|
||||
mangoAccount?.getTokenBalanceUi(b.value[0]) *
|
||||
b.value[0].uiPrice!
|
||||
) -
|
||||
Math.abs(
|
||||
mangoAccount?.getTokenBalanceUi(a.value[0]) *
|
||||
a.value[0].uiPrice!
|
||||
)
|
||||
)
|
||||
: rawBanks
|
||||
|
||||
return mangoAccount
|
||||
? sortedBanks.filter(
|
||||
(b) => mangoAccount?.getTokenBalanceUi(b.value[0]) !== 0
|
||||
)
|
||||
: sortedBanks
|
||||
}
|
||||
return []
|
||||
}, [group, mangoAccount])
|
||||
|
||||
return (
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="bg-th-bkg-1 text-left">{t('token')}</th>
|
||||
<th className="bg-th-bkg-1 text-right">{t('balance')}</th>
|
||||
<th className="bg-th-bkg-1 text-right">In Orders</th>
|
||||
<th className="bg-th-bkg-1 text-right">Unsettled</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{banks.map(({ key, value }) => {
|
||||
const bank = value[0]
|
||||
const oraclePrice = bank.uiPrice
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
(t) => t.address === bank.mint.toString()
|
||||
)!.logoURI
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={key} className="text-sm">
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<div className="mr-2.5 flex flex-shrink-0 items-center">
|
||||
{logoURI ? (
|
||||
<Image alt="" width="20" height="20" src={logoURI} />
|
||||
) : (
|
||||
<QuestionMarkCircleIcon className="h-7 w-7 text-th-fgd-3" />
|
||||
)}
|
||||
</div>
|
||||
<span>{bank.name}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pt-4 text-right font-mono text-sm">
|
||||
<p>
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
mangoAccount.getTokenBalanceUi(bank),
|
||||
bank.mintDecimals
|
||||
)
|
||||
: 0}
|
||||
</p>
|
||||
</td>
|
||||
<td className="text-right font-mono text-sm">0.00</td>
|
||||
<td className="text-right font-mono text-sm">0.00</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
const OpenOrders = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const openOrders = mangoStore((s) => s.mangoAccount.openOrders)
|
||||
|
||||
const handleCancelOrder = useCallback(
|
||||
async (o: Order) => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
const selectedMarket = mangoStore.getState().selectedMarket.current
|
||||
|
||||
if (!group || !mangoAccount) return
|
||||
|
||||
try {
|
||||
const tx = await client.serum3CancelOrder(
|
||||
group,
|
||||
mangoAccount,
|
||||
selectedMarket!.serumMarketExternal,
|
||||
o.side === 'buy' ? Serum3Side.bid : Serum3Side.ask,
|
||||
o.orderId
|
||||
)
|
||||
notify({
|
||||
type: 'success',
|
||||
title: 'Transaction successful',
|
||||
txid: tx,
|
||||
})
|
||||
} catch (e: any) {
|
||||
console.error('Error canceling', e)
|
||||
notify({
|
||||
title: t('order-error'),
|
||||
description: e.message,
|
||||
txid: e.txid,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
},
|
||||
[t]
|
||||
)
|
||||
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr className="">
|
||||
<th className="text-right">Side</th>
|
||||
<th className="text-right">Size</th>
|
||||
<th className="text-right">Price</th>
|
||||
<th className="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{openOrders.map((o) => {
|
||||
return (
|
||||
<tr key={`${o.side}${o.size}${o.price}`} className="my-1 p-2">
|
||||
<td className="text-right">
|
||||
<SideBadge side={o.side} />
|
||||
</td>
|
||||
<td className="text-right">{o.size}</td>
|
||||
<td className="text-right">{o.price}</td>
|
||||
<td className="text-right">
|
||||
<Button size="small" onClick={() => handleCancelOrder(o)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
export default BalanceAndOpenOrders
|
|
@ -0,0 +1,516 @@
|
|||
import { AccountInfo } from '@solana/web3.js'
|
||||
import Big from 'big.js'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { 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'
|
||||
import usePrevious from '@components/shared/usePrevious'
|
||||
import { PerpMarket } from '@blockworks-foundation/mango-v4/dist/types/src/accounts/perp'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { floorToDecimal, formatDecimal, getDecimalCount } from 'utils/numbers'
|
||||
import { ORDERBOOK_FLASH_KEY } from 'utils/constants'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
function decodeBookL2(
|
||||
market: Market,
|
||||
accInfo: AccountInfo<Buffer>
|
||||
): number[][] {
|
||||
if (market && accInfo?.data) {
|
||||
const depth = 40
|
||||
if (market instanceof Market) {
|
||||
const book = SpotOrderBook.decode(market, accInfo.data)
|
||||
return book.getL2(depth).map(([price, size]) => [price, size])
|
||||
}
|
||||
// else if (market instanceof PerpMarket) {
|
||||
// // FIXME: Review the null being passed here
|
||||
// const book = new BookSide(
|
||||
// // @ts-ignore
|
||||
// null,
|
||||
// market,
|
||||
// BookSideLayout.decode(accInfo.data),
|
||||
// undefined,
|
||||
// 100000
|
||||
// )
|
||||
// return book.getL2Ui(depth)
|
||||
// }
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export function decodeBook(
|
||||
market: Market,
|
||||
accInfo: AccountInfo<Buffer>
|
||||
): SpotOrderBook | undefined {
|
||||
if (market && accInfo?.data) {
|
||||
if (market instanceof Market) {
|
||||
return SpotOrderBook.decode(market, accInfo.data)
|
||||
}
|
||||
// else if (market instanceof PerpMarket) {
|
||||
// // FIXME: Review the null being passed here
|
||||
// return new BookSide(
|
||||
// // @ts-ignore
|
||||
// null,
|
||||
// market,
|
||||
// BookSideLayout.decode(accInfo.data),
|
||||
// undefined,
|
||||
// 100000
|
||||
// )
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
type cumOrderbookSide = {
|
||||
price: number
|
||||
size: number
|
||||
cumulativeSize: number
|
||||
sizePercent: number
|
||||
maxSizePercent: number
|
||||
}
|
||||
|
||||
const getCumulativeOrderbookSide = (
|
||||
orders: any[],
|
||||
totalSize: number,
|
||||
maxSize: number,
|
||||
depth: number,
|
||||
backwards = false
|
||||
): cumOrderbookSide[] => {
|
||||
let cumulative = orders
|
||||
.slice(0, depth)
|
||||
.reduce((cumulative, [price, size], i) => {
|
||||
const cumulativeSize = (cumulative[i - 1]?.cumulativeSize || 0) + size
|
||||
cumulative.push({
|
||||
price,
|
||||
size,
|
||||
cumulativeSize,
|
||||
sizePercent: Math.round((cumulativeSize / (totalSize || 1)) * 100),
|
||||
maxSizePercent: Math.round((size / (maxSize || 1)) * 100),
|
||||
})
|
||||
return cumulative
|
||||
}, [])
|
||||
if (backwards) {
|
||||
cumulative = cumulative.reverse()
|
||||
}
|
||||
return cumulative
|
||||
}
|
||||
|
||||
const groupBy = (
|
||||
ordersArray: number[][],
|
||||
market: Market,
|
||||
grouping: number,
|
||||
isBids: boolean
|
||||
) => {
|
||||
if (!ordersArray || !market || !grouping || grouping == market?.tickSize) {
|
||||
return ordersArray || []
|
||||
}
|
||||
const groupFloors: Record<number, number> = {}
|
||||
for (let i = 0; i < ordersArray.length; i++) {
|
||||
if (typeof ordersArray[i] == 'undefined') {
|
||||
break
|
||||
}
|
||||
const bigGrouping = Big(grouping)
|
||||
const bigOrder = Big(ordersArray[i][0])
|
||||
|
||||
const floor = isBids
|
||||
? bigOrder
|
||||
.div(bigGrouping)
|
||||
.round(0, Big.roundDown)
|
||||
.times(bigGrouping)
|
||||
.toNumber()
|
||||
: bigOrder
|
||||
.div(bigGrouping)
|
||||
.round(0, Big.roundUp)
|
||||
.times(bigGrouping)
|
||||
.toNumber()
|
||||
if (typeof groupFloors[floor] == 'undefined') {
|
||||
groupFloors[floor] = ordersArray[i][1]
|
||||
} else {
|
||||
groupFloors[floor] = ordersArray[i][1] + groupFloors[floor]
|
||||
}
|
||||
}
|
||||
const sortedGroups = Object.entries(groupFloors)
|
||||
.map((entry) => {
|
||||
return [
|
||||
+parseFloat(entry[0]).toFixed(getDecimalCount(grouping)),
|
||||
entry[1],
|
||||
]
|
||||
})
|
||||
.sort((a: number[], b: number[]) => {
|
||||
if (!a || !b) {
|
||||
return -1
|
||||
}
|
||||
return isBids ? b[0] - a[0] : a[0] - b[0]
|
||||
})
|
||||
return sortedGroups
|
||||
}
|
||||
|
||||
const Orderbook = ({ depth = 12 }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
|
||||
const [openOrderPrices, setOpenOrderPrices] = useState<any[]>([])
|
||||
const [orderbookData, setOrderbookData] = useState<any | null>(null)
|
||||
const [defaultLayout, setDefaultLayout] = useState(true)
|
||||
const [displayCumulativeSize, setDisplayCumulativeSize] = useState(false)
|
||||
const [grouping, setGrouping] = useState(0.01)
|
||||
|
||||
const currentOrderbookData = useRef<any>(null)
|
||||
const nextOrderbookData = useRef<any>(null)
|
||||
const previousDepth = usePrevious(depth)
|
||||
const previousGrouping = usePrevious(grouping)
|
||||
|
||||
const serum3MarketExternal = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
if (!group || !selectedMarket) return
|
||||
return group.serum3MarketExternalsMap.get(
|
||||
selectedMarket.serumMarketExternal.toBase58()
|
||||
)
|
||||
}, [selectedMarket])
|
||||
|
||||
useEffect(() => {
|
||||
if (serum3MarketExternal) {
|
||||
setGrouping(serum3MarketExternal.tickSize)
|
||||
}
|
||||
}, [serum3MarketExternal])
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
mangoStore.subscribe(
|
||||
(state) => [state.selectedMarket.orderbook],
|
||||
(orderbook) => (nextOrderbookData.current = orderbook)
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
useInterval(() => {
|
||||
const orderbook = mangoStore.getState().selectedMarket.orderbook
|
||||
const group = mangoStore.getState().group
|
||||
if (!selectedMarket || !group) return
|
||||
const serum3MarketExternal = group.serum3MarketExternalsMap.get(
|
||||
selectedMarket.serumMarketExternal.toBase58()
|
||||
)
|
||||
if (
|
||||
nextOrderbookData?.current &&
|
||||
(!isEqualLodash(
|
||||
currentOrderbookData.current,
|
||||
nextOrderbookData.current
|
||||
) ||
|
||||
previousDepth !== depth ||
|
||||
previousGrouping !== grouping)
|
||||
) {
|
||||
// check if user has open orders so we can highlight them on orderbook
|
||||
// const openOrders = mangoStore.getState().mangoAccount.openOrders
|
||||
// const newOpenOrderPrices = openOrders?.length
|
||||
// ? openOrders
|
||||
// .filter(({ market }) =>
|
||||
// market.account.publicKey.equals(marketConfig.publicKey)
|
||||
// )
|
||||
// .map(({ order }) => order.price)
|
||||
// : []
|
||||
// if (!isEqualLodash(newOpenOrderPrices, openOrderPrices)) {
|
||||
// setOpenOrderPrices(newOpenOrderPrices)
|
||||
// }
|
||||
|
||||
// updated orderbook data
|
||||
const bids =
|
||||
groupBy(orderbook?.bids, serum3MarketExternal!, grouping, true) || []
|
||||
const asks =
|
||||
groupBy(orderbook?.asks, serum3MarketExternal!, grouping, false) || []
|
||||
|
||||
const sum = (total: number, [, size]: number[], index: number) =>
|
||||
index < depth ? total + size : total
|
||||
const totalSize = bids.reduce(sum, 0) + asks.reduce(sum, 0)
|
||||
const maxSize =
|
||||
Math.max(
|
||||
...asks.map((a: number[]) => {
|
||||
return a[1]
|
||||
})
|
||||
) +
|
||||
Math.max(
|
||||
...bids.map((b: number[]) => {
|
||||
return b[1]
|
||||
})
|
||||
)
|
||||
|
||||
const bidsToDisplay = defaultLayout
|
||||
? getCumulativeOrderbookSide(bids, totalSize, maxSize, depth, false)
|
||||
: getCumulativeOrderbookSide(bids, totalSize, maxSize, depth / 2, false)
|
||||
const asksToDisplay = defaultLayout
|
||||
? getCumulativeOrderbookSide(asks, totalSize, maxSize, depth, false)
|
||||
: getCumulativeOrderbookSide(
|
||||
asks,
|
||||
totalSize,
|
||||
maxSize,
|
||||
(depth + 1) / 2,
|
||||
true
|
||||
)
|
||||
|
||||
currentOrderbookData.current = {
|
||||
bids: orderbook?.bids,
|
||||
asks: orderbook?.asks,
|
||||
}
|
||||
if (bidsToDisplay[0] || asksToDisplay[0]) {
|
||||
const bid = bidsToDisplay[0]?.price
|
||||
const ask = defaultLayout
|
||||
? asksToDisplay[0]?.price
|
||||
: asksToDisplay[asksToDisplay.length - 1]?.price
|
||||
let spread = 0,
|
||||
spreadPercentage = 0
|
||||
if (bid && ask) {
|
||||
spread = ask - bid
|
||||
spreadPercentage = (spread / ask) * 100
|
||||
}
|
||||
|
||||
setOrderbookData({
|
||||
bids: bidsToDisplay,
|
||||
asks: asksToDisplay.reverse(),
|
||||
spread,
|
||||
spreadPercentage,
|
||||
})
|
||||
} else {
|
||||
setOrderbookData(null)
|
||||
}
|
||||
}
|
||||
}, 400)
|
||||
|
||||
useEffect(() => {
|
||||
const connection = mangoStore.getState().connection
|
||||
const group = mangoStore.getState().group
|
||||
const set = mangoStore.getState().set
|
||||
|
||||
let previousBidInfo: AccountInfo<Buffer> | null = null
|
||||
let previousAskInfo: AccountInfo<Buffer> | null = null
|
||||
if (!serum3MarketExternal || !group) return
|
||||
console.log('in orderbook WS useEffect')
|
||||
|
||||
const bidsPk = serum3MarketExternal['_decoded'].bids
|
||||
const bidSubscriptionId = connection.onAccountChange(
|
||||
bidsPk,
|
||||
(info, context) => {
|
||||
if (
|
||||
!previousBidInfo ||
|
||||
!previousBidInfo.data.equals(info.data) ||
|
||||
previousBidInfo.lamports !== info.lamports
|
||||
) {
|
||||
previousBidInfo = info
|
||||
// info['parsed'] = decodeBook(serum3MarketExternal, info)
|
||||
set((state) => {
|
||||
// state.accountInfos[bidsPk.toString()] = info
|
||||
state.selectedMarket.orderbook.bids = decodeBookL2(
|
||||
serum3MarketExternal,
|
||||
info
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
const asksPk = serum3MarketExternal['_decoded'].asks
|
||||
const askSubscriptionId = connection.onAccountChange(
|
||||
asksPk,
|
||||
(info, context) => {
|
||||
if (
|
||||
!previousAskInfo ||
|
||||
!previousAskInfo.data.equals(info.data) ||
|
||||
previousAskInfo.lamports !== info.lamports
|
||||
) {
|
||||
previousAskInfo = info
|
||||
// info['parsed'] = decodeBook(serum3MarketExternal, info)
|
||||
set((state) => {
|
||||
// state.accountInfos[asksPk.toString()] = info
|
||||
state.selectedMarket.orderbook.asks = decodeBookL2(
|
||||
serum3MarketExternal,
|
||||
info
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
return () => {
|
||||
connection.removeAccountChangeListener(bidSubscriptionId)
|
||||
connection.removeAccountChangeListener(askSubscriptionId)
|
||||
}
|
||||
}, [serum3MarketExternal])
|
||||
|
||||
if (!serum3MarketExternal) return null
|
||||
|
||||
return (
|
||||
<div>
|
||||
{orderbookData?.asks.map(
|
||||
({
|
||||
price,
|
||||
size,
|
||||
cumulativeSize,
|
||||
sizePercent,
|
||||
maxSizePercent,
|
||||
}: cumOrderbookSide) => (
|
||||
<OrderbookRow
|
||||
market={serum3MarketExternal}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
key={price + ''}
|
||||
price={price}
|
||||
size={displayCumulativeSize ? cumulativeSize : size}
|
||||
side="sell"
|
||||
sizePercent={displayCumulativeSize ? maxSizePercent : sizePercent}
|
||||
grouping={grouping}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<div className="my-2 flex justify-between border-y border-th-bkg-2 py-2 px-4 text-xs">
|
||||
<div className="text-th-fgd-3">{t('spread')}</div>
|
||||
<div className="text-th-fgd-1">{orderbookData?.spread.toFixed(2)}</div>
|
||||
<div className="text-th-fgd-1">
|
||||
{orderbookData?.spreadPercentage.toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
{orderbookData?.bids.map(
|
||||
({
|
||||
price,
|
||||
size,
|
||||
cumulativeSize,
|
||||
sizePercent,
|
||||
maxSizePercent,
|
||||
}: cumOrderbookSide) => (
|
||||
<OrderbookRow
|
||||
market={serum3MarketExternal}
|
||||
// hasOpenOrder={hasOpenOrderForPriceGroup(
|
||||
// openOrderPrices,
|
||||
// price,
|
||||
// grouping
|
||||
// )}
|
||||
key={price + ''}
|
||||
price={price}
|
||||
size={displayCumulativeSize ? cumulativeSize : size}
|
||||
side="buy"
|
||||
sizePercent={displayCumulativeSize ? maxSizePercent : sizePercent}
|
||||
grouping={grouping}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OrderbookRow = ({
|
||||
side,
|
||||
price,
|
||||
size,
|
||||
sizePercent,
|
||||
// invert,
|
||||
// hasOpenOrder,
|
||||
market,
|
||||
grouping,
|
||||
}: {
|
||||
side: 'buy' | 'sell'
|
||||
price: number
|
||||
size: number
|
||||
sizePercent: number
|
||||
// hasOpenOrder: boolean
|
||||
// invert: boolean
|
||||
grouping: number
|
||||
market: Market
|
||||
}) => {
|
||||
const element = useRef<HTMLDivElement>(null)
|
||||
// const set = mangoStore.getState().set
|
||||
const [showOrderbookFlash] = useLocalStorageState(ORDERBOOK_FLASH_KEY, true)
|
||||
const flashClassName = side === 'sell' ? 'red-flash' : 'green-flash'
|
||||
|
||||
useEffect(() => {
|
||||
showOrderbookFlash &&
|
||||
!element.current?.classList.contains(`${flashClassName}`) &&
|
||||
element.current?.classList.add(`${flashClassName}`)
|
||||
const id = setTimeout(
|
||||
() =>
|
||||
element.current?.classList.contains(`${flashClassName}`) &&
|
||||
element.current?.classList.remove(`${flashClassName}`),
|
||||
250
|
||||
)
|
||||
return () => clearTimeout(id)
|
||||
}, [price, size])
|
||||
|
||||
const formattedSize =
|
||||
market!.minOrderSize && !isNaN(size)
|
||||
? floorToDecimal(size, getDecimalCount(market.minOrderSize))
|
||||
: new Decimal(size)
|
||||
|
||||
const formattedPrice =
|
||||
market!.tickSize && !isNaN(price)
|
||||
? floorToDecimal(price, getDecimalCount(market.tickSize))
|
||||
: new Decimal(price)
|
||||
|
||||
// const handlePriceClick = () => {
|
||||
// set((state) => {
|
||||
// state.tradeForm.price = Number(formattedPrice)
|
||||
// })
|
||||
// }
|
||||
|
||||
// const handleSizeClick = () => {
|
||||
// set((state) => {
|
||||
// state.tradeForm.baseSize = Number(formattedSize)
|
||||
// })
|
||||
// }
|
||||
|
||||
const groupingDecimalCount = useMemo(
|
||||
() => getDecimalCount(grouping),
|
||||
[grouping]
|
||||
)
|
||||
const minOrderSizeDecimals = useMemo(
|
||||
() => getDecimalCount(market.minOrderSize),
|
||||
[market.minOrderSize]
|
||||
)
|
||||
|
||||
if (!market) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex cursor-pointer justify-between border-b border-b-th-bkg-1 text-sm`}
|
||||
ref={element}
|
||||
>
|
||||
<>
|
||||
<div className="flex w-full items-center justify-between hover:bg-th-bkg-2">
|
||||
<div
|
||||
style={{ fontFeatureSettings: 'zero 1' }}
|
||||
className={`z-10 text-right font-mono text-xs tabular-nums leading-5 md:ml-4 md:leading-6 ${
|
||||
/*hasOpenOrder*/ false ? 'text-th-primary' : 'text-th-fgd-3'
|
||||
}`}
|
||||
// onClick={handleSizeClick}
|
||||
>
|
||||
{formattedSize.toFixed(minOrderSizeDecimals)}
|
||||
</div>
|
||||
<div
|
||||
className={`z-10 font-mono text-xs tabular-nums leading-5 text-th-fgd-3 hover:normal-nums md:pr-4 md:leading-6`}
|
||||
// onClick={handlePriceClick}
|
||||
>
|
||||
{formattedPrice.toFixed(groupingDecimalCount)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Line
|
||||
className={`absolute right-0 opacity-90 ${
|
||||
side === 'buy' ? `bg-th-green-muted` : `bg-th-red-muted`
|
||||
}`}
|
||||
data-width={sizePercent + '%'}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Line = (props: any) => {
|
||||
return (
|
||||
<div
|
||||
className={`${props.className}`}
|
||||
style={{
|
||||
textAlign: props.invert ? 'left' : 'right',
|
||||
height: '100%',
|
||||
width: `${props['data-width'] ? props['data-width'] : ''}`,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Orderbook
|
|
@ -0,0 +1,157 @@
|
|||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import ReactGridLayout, { Responsive, WidthProvider } from 'react-grid-layout'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { GRID_LAYOUT_KEY } from 'utils/constants'
|
||||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
import Orderbook from './Orderbook'
|
||||
import AdvancedMarketHeader from './AdvancedMarketHeader'
|
||||
import AdvancedTradeForm from './AdvancedTradeForm'
|
||||
import BalanceAndOpenOrders from './BalanceAndOpenOrders'
|
||||
|
||||
const ResponsiveGridLayout = WidthProvider(Responsive)
|
||||
|
||||
const TradingViewChart = dynamic(() => import('./TradingViewChart'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
const gridBreakpoints = {
|
||||
// sm: breakpoints.sm,
|
||||
// md: breakpoints.md,
|
||||
// lg: breakpoints.lg,
|
||||
xl: breakpoints.xl,
|
||||
xxl: breakpoints['2xl'],
|
||||
xxxl: breakpoints['3xl'],
|
||||
}
|
||||
const totalCols = 24
|
||||
const TradeAdvancedPage = () => {
|
||||
const { height } = useViewport()
|
||||
const [currentBreakpoint, setCurrentBreakpoint] = useState<string>()
|
||||
const [orderbookDepth, setOrderbookDepth] = useState(12)
|
||||
const { uiLocked } = mangoStore((s) => s.settings)
|
||||
|
||||
const defaultLayouts: ReactGridLayout.Layouts = useMemo(() => {
|
||||
const innerHeight = Math.max(height - 36, 800)
|
||||
const tvChartHeight = 432
|
||||
const headerHeight = 60
|
||||
const balancesHeight = innerHeight - tvChartHeight - headerHeight
|
||||
|
||||
return {
|
||||
xxxl: [
|
||||
{ i: 'market-header', x: 0, y: 0, w: 16, h: headerHeight },
|
||||
{ i: 'tv-chart', x: 0, y: 1, w: 16, h: tvChartHeight },
|
||||
{ i: 'balances', x: 0, y: 2, w: 16, h: balancesHeight },
|
||||
{ i: 'orderbook', x: 16, y: 1, w: 4, h: innerHeight },
|
||||
{ i: 'trade-form', x: 20, y: 1, w: 4, h: innerHeight },
|
||||
],
|
||||
xxl: [
|
||||
{ i: 'market-header', x: 0, y: 0, w: 14, h: headerHeight },
|
||||
{ i: 'tv-chart', x: 0, y: 1, w: 14, h: tvChartHeight },
|
||||
{ i: 'balances', x: 0, y: 2, w: 14, h: balancesHeight },
|
||||
{ i: 'orderbook', x: 14, y: 1, w: 5, h: innerHeight },
|
||||
{ i: 'trade-form', x: 20, y: 1, w: 5, h: innerHeight },
|
||||
],
|
||||
xl: [
|
||||
{ i: 'market-header', x: 0, y: 0, w: 14, h: headerHeight },
|
||||
{ i: 'tv-chart', x: 0, y: 1, w: 14, h: tvChartHeight },
|
||||
{ i: 'balances', x: 0, y: 2, w: 14, h: balancesHeight },
|
||||
{ i: 'orderbook', x: 14, y: 1, w: 5, h: innerHeight },
|
||||
{ i: 'trade-form', x: 20, y: 1, w: 5, h: innerHeight },
|
||||
],
|
||||
}
|
||||
}, [height])
|
||||
|
||||
const [savedLayouts, setSavedLayouts] = useLocalStorageState(
|
||||
GRID_LAYOUT_KEY,
|
||||
defaultLayouts
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const adjustOrderBook = (
|
||||
layouts: ReactGridLayout.Layouts,
|
||||
breakpoint?: string | null
|
||||
) => {
|
||||
const bp = 'xxl'
|
||||
const orderbookLayout = layouts[bp].find((obj) => {
|
||||
return obj.i === 'orderbook'
|
||||
})
|
||||
let depth = orderbookLayout!.h / 24 / 2 - 2
|
||||
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)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onBreakpointChange = useCallback((newBreakpoint: string) => {
|
||||
setCurrentBreakpoint(newBreakpoint)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<ResponsiveGridLayout
|
||||
// layouts={savedLayouts ? savedLayouts : defaultLayouts}
|
||||
layouts={defaultLayouts}
|
||||
breakpoints={gridBreakpoints}
|
||||
cols={{
|
||||
xxxl: totalCols,
|
||||
xxl: totalCols,
|
||||
xl: totalCols,
|
||||
lg: totalCols,
|
||||
md: totalCols,
|
||||
sm: totalCols,
|
||||
}}
|
||||
rowHeight={1}
|
||||
isDraggable={!uiLocked}
|
||||
isResizable={!uiLocked}
|
||||
onBreakpointChange={(newBreakpoint) =>
|
||||
onBreakpointChange(newBreakpoint)
|
||||
}
|
||||
onLayoutChange={(layout, layouts) => onLayoutChange(layouts)}
|
||||
measureBeforeMount
|
||||
containerPadding={{ xxl: [0, 0] }}
|
||||
margin={[0, 0]}
|
||||
>
|
||||
<div key="market-header" className="z-10">
|
||||
<AdvancedMarketHeader />
|
||||
</div>
|
||||
<div key="tv-chart" className="h-full border border-th-bkg-3">
|
||||
<div className={`relative h-full overflow-auto`}>
|
||||
<TradingViewChart />
|
||||
</div>
|
||||
</div>
|
||||
<div key="balances" className="h-full border border-th-bkg-3">
|
||||
<BalanceAndOpenOrders />
|
||||
</div>
|
||||
<div key="orderbook" className="border border-th-bkg-3">
|
||||
<div className="flex items-center justify-between px-4 py-2 text-xs text-th-fgd-4">
|
||||
<div>Size</div>
|
||||
<div>Price</div>
|
||||
</div>
|
||||
<div className="hide-scroll h-full overflow-y-scroll">
|
||||
<Orderbook depth={orderbookDepth} />
|
||||
</div>
|
||||
</div>
|
||||
<div key="trade-form" className="border border-th-bkg-3">
|
||||
<AdvancedTradeForm />
|
||||
</div>
|
||||
</ResponsiveGridLayout>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TradeAdvancedPage
|
|
@ -0,0 +1,189 @@
|
|||
import { useEffect, useRef, useMemo, useState } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import {
|
||||
widget,
|
||||
ChartingLibraryWidgetOptions,
|
||||
IChartingLibraryWidget,
|
||||
ResolutionString,
|
||||
} from '@public/charting_library'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
import { CHART_DATA_FEED, DEFAULT_MARKET_NAME } from 'utils/constants'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import { COLORS } from 'styles/colors'
|
||||
|
||||
export interface ChartContainerProps {
|
||||
container: ChartingLibraryWidgetOptions['container']
|
||||
symbol: ChartingLibraryWidgetOptions['symbol']
|
||||
interval: ChartingLibraryWidgetOptions['interval']
|
||||
datafeedUrl: string
|
||||
libraryPath: ChartingLibraryWidgetOptions['library_path']
|
||||
chartsStorageUrl: ChartingLibraryWidgetOptions['charts_storage_url']
|
||||
chartsStorageApiVersion: ChartingLibraryWidgetOptions['charts_storage_api_version']
|
||||
clientId: ChartingLibraryWidgetOptions['client_id']
|
||||
userId: ChartingLibraryWidgetOptions['user_id']
|
||||
fullscreen: ChartingLibraryWidgetOptions['fullscreen']
|
||||
autosize: ChartingLibraryWidgetOptions['autosize']
|
||||
studiesOverrides: ChartingLibraryWidgetOptions['studies_overrides']
|
||||
theme: string
|
||||
}
|
||||
|
||||
const TradingViewChart = () => {
|
||||
const { theme } = useTheme()
|
||||
const { width } = useViewport()
|
||||
const { publicKey } = useWallet()
|
||||
|
||||
const [chartReady, setChartReady] = useState(false)
|
||||
const selectedMarketName = mangoStore((s) => s.selectedMarket.current?.name)
|
||||
const isMobile = width ? width < breakpoints.sm : false
|
||||
|
||||
// @ts-ignore
|
||||
const defaultProps: ChartContainerProps = useMemo(
|
||||
() => ({
|
||||
symbol: DEFAULT_MARKET_NAME,
|
||||
interval: '60' as ResolutionString,
|
||||
theme: 'Dark',
|
||||
container: 'tv_chart_container',
|
||||
datafeedUrl: CHART_DATA_FEED,
|
||||
libraryPath: '/charting_library/',
|
||||
fullscreen: false,
|
||||
autosize: true,
|
||||
studiesOverrides: {
|
||||
'volume.volume.color.0': theme === 'Mango' ? '#E54033' : '#CC2929',
|
||||
'volume.volume.color.1': theme === 'Mango' ? '#AFD803' : '#5EBF4D',
|
||||
'volume.precision': 4,
|
||||
},
|
||||
}),
|
||||
[theme]
|
||||
)
|
||||
|
||||
const tvWidgetRef = useRef<IChartingLibraryWidget | null>(null)
|
||||
|
||||
let chartStyleOverrides = {
|
||||
'paneProperties.background': 'rgba(0,0,0,0)',
|
||||
'paneProperties.backgroundType': 'solid',
|
||||
'paneProperties.legendProperties.showBackground': false,
|
||||
'paneProperties.vertGridProperties.color': 'rgba(0,0,0,0)',
|
||||
'paneProperties.horzGridProperties.color': 'rgba(0,0,0,0)',
|
||||
'paneProperties.legendProperties.showStudyTitles': false,
|
||||
'scalesProperties.showStudyLastValue': false,
|
||||
}
|
||||
|
||||
const mainSeriesProperties = [
|
||||
'candleStyle',
|
||||
'hollowCandleStyle',
|
||||
'haStyle',
|
||||
'barStyle',
|
||||
]
|
||||
mainSeriesProperties.forEach((prop) => {
|
||||
chartStyleOverrides = {
|
||||
...chartStyleOverrides,
|
||||
[`mainSeriesProperties.${prop}.barColorsOnPrevClose`]: true,
|
||||
[`mainSeriesProperties.${prop}.drawWick`]: true,
|
||||
[`mainSeriesProperties.${prop}.drawBorder`]: true,
|
||||
[`mainSeriesProperties.${prop}.upColor`]:
|
||||
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
|
||||
[`mainSeriesProperties.${prop}.downColor`]:
|
||||
theme === 'Mango' ? '#E54033' : '#CC2929',
|
||||
[`mainSeriesProperties.${prop}.borderColor`]:
|
||||
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
|
||||
[`mainSeriesProperties.${prop}.borderUpColor`]:
|
||||
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
|
||||
[`mainSeriesProperties.${prop}.borderDownColor`]:
|
||||
theme === 'Mango' ? '#E54033' : '#CC2929',
|
||||
[`mainSeriesProperties.${prop}.wickUpColor`]:
|
||||
theme === 'Mango' ? '#AFD803' : '#5EBF4D',
|
||||
[`mainSeriesProperties.${prop}.wickDownColor`]:
|
||||
theme === 'Mango' ? '#E54033' : '#CC2929',
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (tvWidgetRef.current && chartReady && selectedMarketName) {
|
||||
console.log('selectedMarketName', selectedMarketName)
|
||||
console.log(
|
||||
'tvWidgetRef.current?.activeChart()?.symbol()',
|
||||
tvWidgetRef.current?.activeChart()?.symbol()
|
||||
)
|
||||
|
||||
tvWidgetRef.current.setSymbol(
|
||||
selectedMarketName!,
|
||||
tvWidgetRef.current.activeChart().resolution(),
|
||||
() => {}
|
||||
)
|
||||
}
|
||||
}, [selectedMarketName, chartReady])
|
||||
|
||||
useEffect(() => {
|
||||
if (window) {
|
||||
const widgetOptions: ChartingLibraryWidgetOptions = {
|
||||
// debug: true,
|
||||
symbol: defaultProps.symbol,
|
||||
// BEWARE: no trailing slash is expected in feed URL
|
||||
// tslint:disable-next-line:no-any
|
||||
datafeed: new (window as any).Datafeeds.UDFCompatibleDatafeed(
|
||||
defaultProps.datafeedUrl
|
||||
),
|
||||
interval:
|
||||
defaultProps.interval as ChartingLibraryWidgetOptions['interval'],
|
||||
container:
|
||||
defaultProps.container as ChartingLibraryWidgetOptions['container'],
|
||||
library_path: defaultProps.libraryPath as string,
|
||||
locale: 'en',
|
||||
enabled_features: ['hide_left_toolbar_by_default'],
|
||||
disabled_features: [
|
||||
'use_localstorage_for_settings',
|
||||
'timeframes_toolbar',
|
||||
isMobile ? 'left_toolbar' : '',
|
||||
'show_logo_on_all_charts',
|
||||
'caption_buttons_text_if_possible',
|
||||
'header_settings',
|
||||
// 'header_chart_type',
|
||||
'header_compare',
|
||||
'compare_symbol',
|
||||
'header_screenshot',
|
||||
// 'header_widget_dom_node',
|
||||
// 'header_widget',
|
||||
!publicKey ? 'header_saveload' : '',
|
||||
'header_undo_redo',
|
||||
'header_interval_dialog_button',
|
||||
'show_interval_dialog_on_key_press',
|
||||
'header_symbol_search',
|
||||
],
|
||||
fullscreen: defaultProps.fullscreen,
|
||||
autosize: defaultProps.autosize,
|
||||
studies_overrides: defaultProps.studiesOverrides,
|
||||
theme: theme === 'Light' ? 'Light' : 'Dark',
|
||||
custom_css_url: '/styles/tradingview.css',
|
||||
loading_screen: {
|
||||
backgroundColor:
|
||||
theme === 'Dark'
|
||||
? COLORS.BKG1.Dark
|
||||
: theme === 'Light'
|
||||
? COLORS.BKG1.Light
|
||||
: COLORS.BKG1.Mango,
|
||||
},
|
||||
overrides: {
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
|
||||
...chartStyleOverrides,
|
||||
},
|
||||
}
|
||||
|
||||
const tvWidget = new widget(widgetOptions)
|
||||
tvWidgetRef.current = tvWidget
|
||||
|
||||
tvWidgetRef.current.onChartReady(function () {
|
||||
setChartReady(true)
|
||||
})
|
||||
//eslint-disable-next-line
|
||||
}
|
||||
}, [theme, isMobile, publicKey, defaultProps])
|
||||
|
||||
return (
|
||||
<div id={defaultProps.container as string} className="tradingview-chart" />
|
||||
)
|
||||
}
|
||||
|
||||
export default TradingViewChart
|
|
@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next'
|
|||
// import AccountsModal from './AccountsModal'
|
||||
import uniqBy from 'lodash/uniqBy'
|
||||
import WalletSelect from './WalletSelect'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { Wallet as AnchorWallet } from '@project-serum/anchor'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import Loading from '../shared/Loading'
|
||||
|
@ -100,7 +100,7 @@ export const ConnectWalletButton: React.FC = () => {
|
|||
disabled={!group}
|
||||
className={` text-white focus:outline-none disabled:cursor-wait disabled:opacity-25`}
|
||||
>
|
||||
<div className="relative flex h-16 w-44 bg-gradient-to-bl from-mango-theme-yellow to-mango-theme-red-dark before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-[rgba(255,255,255,0.25)] before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100">
|
||||
<div className="relative flex w-44 rounded bg-gradient-to-bl from-mango-theme-yellow to-mango-theme-red-dark py-2 before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-[rgba(255,255,255,0.25)] before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100">
|
||||
<div className="default-transition flex h-full flex-row items-center justify-center space-x-3 px-4">
|
||||
<div
|
||||
className={`flex h-[28px] w-[28px] items-center justify-center rounded-full ${
|
||||
|
@ -118,7 +118,7 @@ export const ConnectWalletButton: React.FC = () => {
|
|||
/>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="mb-1.5 flex justify-center text-base font-bold leading-none">
|
||||
<div className="mb-0.5 flex justify-center text-base font-bold leading-none">
|
||||
{connecting ? <Loading className="h-4 w-4" /> : t('connect')}
|
||||
</div>
|
||||
{wallet?.adapter?.name && (
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ArrowRightOnRectangleIcon } from '@heroicons/react/20/solid'
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { Fragment, useCallback, useState } from 'react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import ProfileImage from '../shared/ProfileImage'
|
||||
import { abbreviateAddress } from '../../utils/formatting'
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { Fragment } from 'react'
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { Menu, Transition } from '@headlessui/react'
|
||||
import mangoStore from '../../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
|
||||
const WalletSelect = () => {
|
||||
const { wallets, select } = useWallet()
|
||||
|
@ -13,7 +13,7 @@ const WalletSelect = () => {
|
|||
{({ open }) => (
|
||||
<>
|
||||
<Menu.Button
|
||||
className={`flex h-full w-14 cursor-pointer items-center justify-center rounded-none bg-transparent text-white hover:brightness-[1.1] focus:outline-none disabled:opacity-25`}
|
||||
className={`flex h-full w-12 cursor-pointer items-center justify-center rounded-none bg-transparent text-white hover:brightness-[1.1] focus:outline-none disabled:opacity-25`}
|
||||
disabled={!group}
|
||||
>
|
||||
<ChevronDownIcon
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
createContext,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
|
@ -8,6 +9,7 @@ import {
|
|||
|
||||
type ViewportContextProps = {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
const ViewportContext = createContext({} as ViewportContextProps)
|
||||
|
@ -15,30 +17,32 @@ const ViewportContext = createContext({} as ViewportContextProps)
|
|||
export const ViewportProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const [width, setWidth] = useState<number>(0)
|
||||
const [height, setHeight] = useState<number>(0)
|
||||
|
||||
const handleWindowResize = () => {
|
||||
const handleWindowResize = useCallback(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
setWidth(window.innerWidth)
|
||||
setHeight(window.innerHeight)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
handleWindowResize()
|
||||
window.addEventListener('resize', handleWindowResize)
|
||||
return () => window.removeEventListener('resize', handleWindowResize)
|
||||
}, [])
|
||||
}, [handleWindowResize])
|
||||
|
||||
useEffect(() => setMounted(true), [])
|
||||
if (!mounted) return null
|
||||
|
||||
return (
|
||||
<ViewportContext.Provider value={{ width }}>
|
||||
<ViewportContext.Provider value={{ width, height }}>
|
||||
{children}
|
||||
</ViewportContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useViewport = () => {
|
||||
const { width } = useContext(ViewportContext)
|
||||
return { width }
|
||||
const { width, height } = useContext(ViewportContext)
|
||||
return { width, height }
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"typecheck": "tsc",
|
||||
"prepare": "husky install"
|
||||
"prepare": "husky install",
|
||||
"postinstall": "tar -xzC public -f vendor/charting_library.tgz;tar -xzC public -f vendor/datafeeds.tgz"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-v4": "git+https://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:x-oauth-basic@github.com/blockworks-foundation/mango-v4.git#main",
|
||||
|
@ -22,10 +23,12 @@
|
|||
"@solflare-wallet/pfp": "^0.0.6",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"assert": "^2.0.0",
|
||||
"big.js": "^6.2.1",
|
||||
"dayjs": "^1.11.3",
|
||||
"decimal.js": "^10.4.0",
|
||||
"immer": "^9.0.12",
|
||||
"jsbi": "^4.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"next": "12.2.2",
|
||||
"next-i18next": "^11.1.1",
|
||||
|
@ -34,6 +37,7 @@
|
|||
"react": "18.0.0",
|
||||
"react-dom": "18.0.0",
|
||||
"react-flip-numbers": "^3.0.5",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-number-format": "^4.9.2",
|
||||
"react-tsparticles": "^2.2.4",
|
||||
"react-window": "^1.8.7",
|
||||
|
@ -49,6 +53,7 @@
|
|||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.3",
|
||||
"@types/react-dom": "18.0.0",
|
||||
"@types/react-grid-layout": "^1.3.2",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"eslint": "^8.13.0",
|
||||
|
@ -60,7 +65,7 @@
|
|||
"postcss": "^8.4.12",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.1.8",
|
||||
"tailwindcss": "^3.0.24",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"typescript": "4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { clusterApiUrl } from '@solana/web3.js'
|
||||
|
||||
import '../styles/globals.css'
|
||||
import mangoStore from '../store/mangoStore'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useInterval from '../components/shared/useInterval'
|
||||
import Notifications from '../components/shared/Notification'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
|
@ -19,7 +19,7 @@ import Layout from '../components/Layout'
|
|||
import { ViewportProvider } from '../hooks/useViewport'
|
||||
import { WalletProvider } from '../components/wallet/WalletProvider'
|
||||
|
||||
const hydrateStore = async () => {
|
||||
const rehydrateStore = async () => {
|
||||
const actions = mangoStore.getState().actions
|
||||
actions.fetchGroup()
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
|
@ -30,7 +30,7 @@ const hydrateStore = async () => {
|
|||
|
||||
const HydrateStore = () => {
|
||||
useInterval(() => {
|
||||
hydrateStore()
|
||||
rehydrateStore()
|
||||
}, 5000)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -38,6 +38,7 @@ const HydrateStore = () => {
|
|||
actions.fetchGroup().then(() => {
|
||||
actions.fetchJupiterTokens()
|
||||
})
|
||||
actions.fetchCoingeckoPrices()
|
||||
}, [])
|
||||
|
||||
return null
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import Script from 'next/script'
|
||||
|
||||
class MyDocument extends Document {
|
||||
render() {
|
||||
|
@ -9,8 +10,16 @@ class MyDocument extends Document {
|
|||
href="https://fonts.googleapis.com/css2?family=Lato:wght@200;300;400;500;600;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Roboto Mono&display=swap"
|
||||
rel="stylesheet"
|
||||
></link>
|
||||
<Script
|
||||
src="/datafeeds/udf/dist/bundle.js"
|
||||
strategy="beforeInteractive"
|
||||
></Script>
|
||||
</Head>
|
||||
<body>
|
||||
<body className="overflow-hidden bg-th-bkg-1">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
|
|
@ -15,7 +15,11 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
}
|
||||
|
||||
const Index: NextPage = () => {
|
||||
return <AccountPage />
|
||||
return (
|
||||
<div className="p-8 pb-20 md:p-12">
|
||||
<AccountPage />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Index
|
||||
|
|
|
@ -47,30 +47,32 @@ const Settings: NextPage = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12 border-b border-th-bkg-3 lg:col-span-8 lg:col-start-3">
|
||||
<h1 className="mb-4">{t('settings')}</h1>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
|
||||
<p className="mb-2 lg:mb-0">{t('theme')}</p>
|
||||
<div className="w-full min-w-[220px] md:w-auto">
|
||||
<ButtonGroup
|
||||
activeValue={theme}
|
||||
onChange={(t) => setTheme(t)}
|
||||
values={THEMES}
|
||||
large
|
||||
/>
|
||||
<div className="p-8 pb-20 md:p-12">
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12 border-b border-th-bkg-3 lg:col-span-8 lg:col-start-3">
|
||||
<h1 className="mb-4">{t('settings')}</h1>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
|
||||
<p className="mb-2 lg:mb-0">{t('theme')}</p>
|
||||
<div className="w-full min-w-[220px] md:w-auto">
|
||||
<ButtonGroup
|
||||
activeValue={theme}
|
||||
onChange={(t) => setTheme(t)}
|
||||
values={THEMES}
|
||||
large
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
|
||||
<p className="mb-2 lg:mb-0">{t('language')}</p>
|
||||
<div className="w-full min-w-[330px] md:w-auto">
|
||||
<ButtonGroup
|
||||
activeValue={savedLanguage}
|
||||
onChange={(l) => handleLangChange(l)}
|
||||
values={LANGS.map((val) => val.locale)}
|
||||
names={LANGS.map((val) => t(val.name))}
|
||||
large
|
||||
/>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 p-4 md:flex-row md:items-center md:justify-between">
|
||||
<p className="mb-2 lg:mb-0">{t('language')}</p>
|
||||
<div className="w-full min-w-[330px] md:w-auto">
|
||||
<ButtonGroup
|
||||
activeValue={savedLanguage}
|
||||
onChange={(l) => handleLangChange(l)}
|
||||
values={LANGS.map((val) => val.locale)}
|
||||
names={LANGS.map((val) => t(val.name))}
|
||||
large
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -18,10 +18,12 @@ const Stats: NextPage = () => {
|
|||
const { pathname, asPath, query } = router
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12">
|
||||
<h1 className="mb-4">{t('stats')}</h1>
|
||||
<TokenStats />
|
||||
<div className="p-8 pb-20 md:p-12">
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12">
|
||||
<h1 className="mb-4">{t('stats')}</h1>
|
||||
<TokenStats />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import type { NextPage } from 'next'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import TradeSimplePage from '../components/swap/TradeSimplePage'
|
||||
|
||||
export async function getStaticProps({ locale }: { locale: string }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, ['common', 'trade'])),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const Trade: NextPage = () => {
|
||||
return (
|
||||
<div className="p-8 pb-20 md:p-12">
|
||||
<TradeSimplePage />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Trade
|
|
@ -1,6 +1,6 @@
|
|||
import TradeAdvancedPage from '@components/trade/TradeAdvancedPage'
|
||||
import type { NextPage } from 'next'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import TradeSimplePage from '../components/swap/TradeSimplePage'
|
||||
|
||||
export async function getStaticProps({ locale }: { locale: string }) {
|
||||
return {
|
||||
|
@ -11,7 +11,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
}
|
||||
|
||||
const Trade: NextPage = () => {
|
||||
return <TradeSimplePage />
|
||||
return <TradeAdvancedPage />
|
||||
}
|
||||
|
||||
export default Trade
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,3 @@
|
|||
"use strict";(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[1529],{1529:(t,e,n)=>{n.r(e),n.d(e,{default:()=>M});var r=function(){if("undefined"!=typeof Map)return Map;function t(t,e){var n=-1;return t.some((function(t,r){return t[0]===e&&(n=r,!0)})),n}return function(){function e(){this.__entries__=[]}return Object.defineProperty(e.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),e.prototype.get=function(e){var n=t(this.__entries__,e),r=this.__entries__[n];return r&&r[1]},e.prototype.set=function(e,n){var r=t(this.__entries__,e);~r?this.__entries__[r][1]=n:this.__entries__.push([e,n])},e.prototype.delete=function(e){var n=this.__entries__,r=t(n,e);~r&&n.splice(r,1)},e.prototype.has=function(e){return!!~t(this.__entries__,e)},e.prototype.clear=function(){this.__entries__.splice(0)},e.prototype.forEach=function(t,e){void 0===e&&(e=null);for(var n=0,r=this.__entries__;n<r.length;n++){var i=r[n];t.call(e,i[1],i[0])}},e}()}(),i="undefined"!=typeof window&&"undefined"!=typeof document&&window.document===document,o=void 0!==n.g&&n.g.Math===Math?n.g:"undefined"!=typeof self&&self.Math===Math?self:"undefined"!=typeof window&&window.Math===Math?window:Function("return this")(),s="function"==typeof requestAnimationFrame?requestAnimationFrame.bind(o):function(t){return setTimeout((function(){return t(Date.now())}),1e3/60)};var c=["top","right","bottom","left","width","height","size","weight"],a="undefined"!=typeof MutationObserver,h=function(){function t(){this.connected_=!1,this.mutationEventsAdded_=!1,this.mutationsObserver_=null,this.observers_=[],this.onTransitionEnd_=this.onTransitionEnd_.bind(this),this.refresh=function(t,e){var n=!1,r=!1,i=0;function o(){n&&(n=!1,t()),r&&a()}function c(){s(o)}function a(){var t=Date.now();if(n){if(t-i<2)return;r=!0}else n=!0,r=!1,setTimeout(c,e);i=t}return a}(this.refresh.bind(this),20)}return t.prototype.addObserver=function(t){~this.observers_.indexOf(t)||this.observers_.push(t),this.connected_||this.connect_()},t.prototype.removeObserver=function(t){var e=this.observers_,n=e.indexOf(t);~n&&e.splice(n,1),!e.length&&this.connected_&&this.disconnect_()},t.prototype.refresh=function(){this.updateObservers_()&&this.refresh()},t.prototype.updateObservers_=function(){var t=this.observers_.filter((function(t){return t.gatherActive(),t.hasActive()}));return t.forEach((function(t){return t.broadcastActive()})),t.length>0},t.prototype.connect_=function(){i&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),a?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},t.prototype.disconnect_=function(){i&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),
|
||||
window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},t.prototype.onTransitionEnd_=function(t){var e=t.propertyName,n=void 0===e?"":e;c.some((function(t){return!!~n.indexOf(t)}))&&this.refresh()},t.getInstance=function(){return this.instance_||(this.instance_=new t),this.instance_},t.instance_=null,t}(),u=function(t,e){for(var n=0,r=Object.keys(e);n<r.length;n++){var i=r[n];Object.defineProperty(t,i,{value:e[i],enumerable:!1,writable:!1,configurable:!0})}return t},f=function(t){return t&&t.ownerDocument&&t.ownerDocument.defaultView||o},d=m(0,0,0,0);function p(t){return parseFloat(t)||0}function v(t){for(var e=[],n=1;n<arguments.length;n++)e[n-1]=arguments[n];return e.reduce((function(e,n){return e+p(t["border-"+n+"-width"])}),0)}function _(t){var e=t.clientWidth,n=t.clientHeight;if(!e&&!n)return d;var r=f(t).getComputedStyle(t),i=function(t){for(var e={},n=0,r=["top","right","bottom","left"];n<r.length;n++){var i=r[n],o=t["padding-"+i];e[i]=p(o)}return e}(r),o=i.left+i.right,s=i.top+i.bottom,c=p(r.width),a=p(r.height);if("border-box"===r.boxSizing&&(Math.round(c+o)!==e&&(c-=v(r,"left","right")+o),Math.round(a+s)!==n&&(a-=v(r,"top","bottom")+s)),!function(t){return t===f(t).document.documentElement}(t)){var h=Math.round(c+o)-e,u=Math.round(a+s)-n;1!==Math.abs(h)&&(c-=h),1!==Math.abs(u)&&(a-=u)}return m(i.left,i.top,c,a)}var l="undefined"!=typeof SVGGraphicsElement?function(t){return t instanceof f(t).SVGGraphicsElement}:function(t){return t instanceof f(t).SVGElement&&"function"==typeof t.getBBox};function b(t){return i?l(t)?function(t){var e=t.getBBox();return m(0,0,e.width,e.height)}(t):_(t):d}function m(t,e,n,r){return{x:t,y:e,width:n,height:r}}var y=function(){function t(t){this.broadcastWidth=0,this.broadcastHeight=0,this.contentRect_=m(0,0,0,0),this.target=t}return t.prototype.isActive=function(){var t=b(this.target);return this.contentRect_=t,t.width!==this.broadcastWidth||t.height!==this.broadcastHeight},t.prototype.broadcastRect=function(){var t=this.contentRect_;return this.broadcastWidth=t.width,this.broadcastHeight=t.height,t},t}(),w=function(t,e){var n,r,i,o,s,c,a,h=(r=(n=e).x,i=n.y,o=n.width,s=n.height,c="undefined"!=typeof DOMRectReadOnly?DOMRectReadOnly:Object,a=Object.create(c.prototype),u(a,{x:r,y:i,width:o,height:s,top:i,right:r+o,bottom:s+i,left:r}),a);u(this,{target:t,contentRect:h})},g=function(){function t(t,e,n){if(this.activeObservations_=[],this.observations_=new r,"function"!=typeof t)throw new TypeError("The callback provided as parameter 1 is not a function.");this.callback_=t,this.controller_=e,this.callbackCtx_=n}return t.prototype.observe=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if("undefined"!=typeof Element&&Element instanceof Object){
|
||||
if(!(t instanceof f(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var e=this.observations_;e.has(t)||(e.set(t,new y(t)),this.controller_.addObserver(this),this.controller_.refresh())}},t.prototype.unobserve=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if("undefined"!=typeof Element&&Element instanceof Object){if(!(t instanceof f(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var e=this.observations_;e.has(t)&&(e.delete(t),e.size||this.controller_.removeObserver(this))}},t.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},t.prototype.gatherActive=function(){var t=this;this.clearActive(),this.observations_.forEach((function(e){e.isActive()&&t.activeObservations_.push(e)}))},t.prototype.broadcastActive=function(){if(this.hasActive()){var t=this.callbackCtx_,e=this.activeObservations_.map((function(t){return new w(t.target,t.broadcastRect())}));this.callback_.call(t,e,t),this.clearActive()}},t.prototype.clearActive=function(){this.activeObservations_.splice(0)},t.prototype.hasActive=function(){return this.activeObservations_.length>0},t}(),E="undefined"!=typeof WeakMap?new WeakMap:new r,O=function t(e){if(!(this instanceof t))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=h.getInstance(),r=new g(e,n,this);E.set(this,r)};["observe","unobserve","disconnect"].forEach((function(t){O.prototype[t]=function(){var e;return(e=E.get(this))[t].apply(e,arguments)}}));const M=void 0!==o.ResizeObserver?o.ResizeObserver:O}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
.tabs-3I2ohC86{display:flex;position:relative;width:100%}.tab-3I2ohC86{border-bottom:1px solid;border-color:#e0e3eb;color:var(--tv-tabs-slider-text-color,#131722);flex:1 1;padding:13px 0;text-align:center;transition:color .35s ease;-webkit-user-select:none;user-select:none}html.theme-dark .tab-3I2ohC86{border-color:#434651;color:var(--tv-tabs-slider-text-color,#d1d4dc)}.tab-3I2ohC86.noBorder-3I2ohC86{border-bottom:0}.tab-3I2ohC86.disabled-3I2ohC86{color:#eceff2}.tab-3I2ohC86.active-3I2ohC86,html.theme-dark .tab-3I2ohC86.active-3I2ohC86{color:#2962ff}.defaultCursor-3I2ohC86{cursor:default}.slider-3I2ohC86{bottom:0;height:3px;left:0;position:absolute;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.slider-3I2ohC86,html.theme-dark .slider-3I2ohC86{background-color:#2962ff}.content-3I2ohC86{width:100%}
|
|
@ -0,0 +1 @@
|
|||
.tabs-3I2ohC86{display:flex;position:relative;width:100%}.tab-3I2ohC86{border-bottom:1px solid;border-color:#e0e3eb;color:var(--tv-tabs-slider-text-color,#131722);flex:1 1;padding:13px 0;text-align:center;transition:color .35s ease;-webkit-user-select:none;user-select:none}html.theme-dark .tab-3I2ohC86{border-color:#434651;color:var(--tv-tabs-slider-text-color,#d1d4dc)}.tab-3I2ohC86.noBorder-3I2ohC86{border-bottom:0}.tab-3I2ohC86.disabled-3I2ohC86{color:#eceff2}.tab-3I2ohC86.active-3I2ohC86,html.theme-dark .tab-3I2ohC86.active-3I2ohC86{color:#2962ff}.defaultCursor-3I2ohC86{cursor:default}.slider-3I2ohC86{bottom:0;height:3px;left:0;position:absolute;transition-timing-function:cubic-bezier(.215,.61,.355,1)}.slider-3I2ohC86,html.theme-dark .slider-3I2ohC86{background-color:#2962ff}.content-3I2ohC86{width:100%}
|
|
@ -0,0 +1,3 @@
|
|||
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[1829],{40266:e=>{e.exports={container:"container-QDd7xRJ1","intent-default":"intent-default-QDd7xRJ1",focused:"focused-QDd7xRJ1",readonly:"readonly-QDd7xRJ1",disabled:"disabled-QDd7xRJ1","with-highlight":"with-highlight-QDd7xRJ1",grouped:"grouped-QDd7xRJ1","adjust-position":"adjust-position-QDd7xRJ1","first-row":"first-row-QDd7xRJ1","first-col":"first-col-QDd7xRJ1",stretch:"stretch-QDd7xRJ1","font-size-medium":"font-size-medium-QDd7xRJ1","font-size-large":"font-size-large-QDd7xRJ1","size-small":"size-small-QDd7xRJ1","size-medium":"size-medium-QDd7xRJ1","size-large":"size-large-QDd7xRJ1","intent-success":"intent-success-QDd7xRJ1","intent-warning":"intent-warning-QDd7xRJ1","intent-danger":"intent-danger-QDd7xRJ1","intent-primary":"intent-primary-QDd7xRJ1","border-none":"border-none-QDd7xRJ1","border-thin":"border-thin-QDd7xRJ1","border-thick":"border-thick-QDd7xRJ1","no-corner-top-left":"no-corner-top-left-QDd7xRJ1","no-corner-top-right":"no-corner-top-right-QDd7xRJ1","no-corner-bottom-right":"no-corner-bottom-right-QDd7xRJ1","no-corner-bottom-left":"no-corner-bottom-left-QDd7xRJ1",highlight:"highlight-QDd7xRJ1",shown:"shown-QDd7xRJ1"}},16321:e=>{e.exports={"inner-slot":"inner-slot-1cMNQxXi",interactive:"interactive-1cMNQxXi",icon:"icon-1cMNQxXi","inner-middle-slot":"inner-middle-slot-1cMNQxXi","before-slot":"before-slot-1cMNQxXi","after-slot":"after-slot-1cMNQxXi"}},93463:e=>{e.exports={input:"input-saRppuvn","with-start-slot":"with-start-slot-saRppuvn","with-end-slot":"with-end-slot-saRppuvn"}},94618:(e,t,n)=>{"use strict";n.d(t,{ControlGroupContext:()=>o});const o=n(67294).createContext({isGrouped:!1,cellState:{isTop:!0,isRight:!0,isBottom:!0,isLeft:!0}})},48413:(e,t,n)=>{"use strict";function o(e){let t=0;return e.isTop&&e.isLeft||(t+=1),e.isTop&&e.isRight||(t+=2),e.isBottom&&e.isLeft||(t+=8),e.isBottom&&e.isRight||(t+=4),t}n.d(t,{getGroupCellRemoveRoundBorders:()=>o})},11888:(e,t,n)=>{"use strict";n.d(t,{ControlSkeleton:()=>x,InputClasses:()=>m});var o=n(67294),r=n(94184),s=n(16282),i=n(66364),l=n(74818),u=n(94618),a=n(48413);var c=n(40266),d=n.n(c);function f(e){let t="";return 0!==e&&(1&e&&(t=r(t,d()["no-corner-top-left"])),2&e&&(t=r(t,d()["no-corner-top-right"])),4&e&&(t=r(t,d()["no-corner-bottom-right"])),8&e&&(t=r(t,d()["no-corner-bottom-left"]))),t}function h(e,t,n,o){const{removeRoundBorder:s,className:i,intent:l="default",borderStyle:u="thin",size:c,highlight:h,disabled:p,readonly:m,stretch:g,noReadonlyStyles:R,isFocused:x}=e,b=f(null!=s?s:(0,a.getGroupCellRemoveRoundBorders)(n));return r(d().container,d()["intent-"+l],d()["border-"+u],c&&d()["size-"+c],b,h&&d()["with-highlight"],p&&d().disabled,m&&!R&&d().readonly,x&&d().focused,g&&d().stretch,t&&d().grouped,!o&&d()["adjust-position"],n.isTop&&d()["first-row"],n.isLeft&&d()["first-col"],i)}function p(e,t){const{highlight:n,highlightRemoveRoundBorder:o}=e;if(!n)return d().highlight;const s=f(null!=o?o:(0,a.getGroupCellRemoveRoundBorders)(t));return r(d().highlight,d().shown,s)}const m={
|
||||
FontSizeMedium:(0,s.ensureDefined)(d()["font-size-medium"]),FontSizeLarge:(0,s.ensureDefined)(d()["font-size-large"])},g={passive:!1};function R(e,t){const{id:n,role:r,onFocus:s,onBlur:a,onMouseOver:c,onMouseOut:d,onMouseDown:f,onMouseUp:m,onKeyDown:R,onClick:x,tabIndex:b,startSlot:D,middleSlot:v,endSlot:C,onWheel:M,onWheelNoPassive:w=null}=e,{isGrouped:Q,cellState:S,disablePositionAdjustment:J=!1}=(0,o.useContext)(u.ControlGroupContext),y=function(e,t=null,n){const r=(0,o.useRef)(null),s=(0,o.useRef)(null),i=(0,o.useCallback)(()=>{if(null===r.current||null===s.current)return;const[e,t,n]=s.current;null!==t&&r.current.addEventListener(e,t,n)},[]),l=(0,o.useCallback)(()=>{if(null===r.current||null===s.current)return;const[e,t,n]=s.current;null!==t&&r.current.removeEventListener(e,t,n)},[]),u=(0,o.useCallback)(e=>{l(),r.current=e,i()},[]);return(0,o.useEffect)(()=>(s.current=[e,t,n],i(),l),[e,t,n]),u}("wheel",w,g);return o.createElement("span",{id:n,role:r,className:h(e,Q,S,J),tabIndex:b,ref:(0,i.useMergedRefs)([t,y]),onFocus:s,onBlur:a,onMouseOver:c,onMouseOut:d,onMouseDown:f,onMouseUp:m,onKeyDown:R,onClick:x,onWheel:M,...(0,l.filterDataProps)(e),...(0,l.filterAriaProps)(e)},D,v,C,o.createElement("span",{className:p(e,S)}))}R.displayName="ControlSkeleton";const x=o.forwardRef(R)},92136:(e,t,n)=>{"use strict";n.d(t,{StartSlot:()=>l,MiddleSlot:()=>u,EndSlot:()=>a,AfterSlot:()=>c});var o=n(67294),r=n(94184),s=n(16321),i=n.n(s);function l(e){const{className:t,interactive:n=!0,icon:s=!1,children:l}=e;return o.createElement("span",{className:r(i()["inner-slot"],n&&i().interactive,s&&i().icon,t)},l)}function u(e){const{className:t,children:n}=e;return o.createElement("span",{className:r(i()["inner-slot"],i()["inner-middle-slot"],t)},n)}function a(e){const{className:t,interactive:n=!0,icon:s=!1,children:l}=e;return o.createElement("span",{className:r(i()["inner-slot"],n&&i().interactive,s&&i().icon,t)},l)}function c(e){const{className:t,children:n}=e;return o.createElement("span",{className:r(i()["after-slot"],t)},n)}},81829:(e,t,n)=>{"use strict";n.d(t,{InputControl:()=>x});var o=n(67294),r=n(94184),s=n(74818),i=n(66213),l=n(1130),u=n(66364),a=n(65686),c=n(15965),d=n(53563),f=n(11888),h=n(92136),p=n(93463),m=n.n(p);function g(e){return!(0,s.isAriaAttribute)(e)&&!(0,s.isDataAttribute)(e)}function R(e){const{id:t,title:n,role:i,tabIndex:l,placeholder:u,name:a,type:c,value:d,defaultValue:p,draggable:R,autoComplete:x,autoFocus:b,maxLength:D,min:v,max:C,step:M,pattern:w,inputMode:Q,onSelect:S,onFocus:J,onBlur:y,onKeyDown:F,onKeyUp:N,onKeyPress:k,onChange:E,onDragStart:B,size:z="medium",className:I,inputClassName:A,disabled:L,readonly:P,containerTabIndex:K,startSlot:G,endSlot:T,reference:U,containerReference:O,onContainerFocus:X,...j}=e,H=(0,s.filterProps)(j,g),W={...(0,s.filterAriaProps)(j),...(0,s.filterDataProps)(j),id:t,title:n,role:i,tabIndex:l,placeholder:u,name:a,type:c,value:d,defaultValue:p,draggable:R,autoComplete:x,autoFocus:b,maxLength:D,min:v,max:C,step:M,pattern:w,inputMode:Q,onSelect:S,onFocus:J,onBlur:y,
|
||||
onKeyDown:F,onKeyUp:N,onKeyPress:k,onChange:E,onDragStart:B};return o.createElement(f.ControlSkeleton,{...H,disabled:L,readonly:P,tabIndex:K,className:r(m().container,I),size:z,ref:O,onFocus:X,startSlot:G,middleSlot:o.createElement(h.MiddleSlot,null,o.createElement("input",{...W,className:r(m().input,A,G&&m()["with-start-slot"],T&&m()["with-end-slot"]),disabled:L,readOnly:P,ref:U})),endSlot:T})}function x(e){e=(0,a.useControl)(e);const{disabled:t,autoSelectOnFocus:n,tabIndex:r=0,onFocus:s,onBlur:f,reference:h,containerReference:p=null}=e,m=(0,o.useRef)(null),g=(0,o.useRef)(null),[x,b]=(0,c.useFocus)(),D=t?void 0:x?-1:r,v=t?void 0:x?r:-1,{isMouseDown:C,handleMouseDown:M,handleMouseUp:w}=(0,d.useIsMouseDown)(),Q=(0,i.createSafeMulticastEventHandler)(b.onFocus,(function(e){n&&!C.current&&(0,l.selectAllContent)(e.currentTarget)}),s),S=(0,i.createSafeMulticastEventHandler)(b.onBlur,f),J=(0,o.useCallback)(e=>{m.current=e,h&&("function"==typeof h&&h(e),"object"==typeof h&&(h.current=e))},[m,h]);return o.createElement(R,{...e,isFocused:x,containerTabIndex:D,tabIndex:v,onContainerFocus:function(e){g.current===e.target&&null!==m.current&&m.current.focus()},onFocus:Q,onBlur:S,reference:J,containerReference:(0,u.useMergedRefs)([g,p]),onMouseDown:M,onMouseUp:w})}},65686:(e,t,n)=>{"use strict";n.d(t,{useControl:()=>s});var o=n(66213),r=n(15965);function s(e){const{onFocus:t,onBlur:n,intent:s,highlight:i,disabled:l}=e,[u,a]=(0,r.useFocus)(),c=(0,o.createSafeMulticastEventHandler)(l?void 0:a.onFocus,t),d=(0,o.createSafeMulticastEventHandler)(l?void 0:a.onBlur,n);return{...e,intent:s||(u?"primary":"default"),highlight:null!=i?i:u,onFocus:c,onBlur:d}}},15965:(e,t,n)=>{"use strict";n.d(t,{useFocus:()=>r});var o=n(67294);function r(e){const[t,n]=(0,o.useState)(!1);return[t,{onFocus:(0,o.useCallback)((function(t){void 0!==e&&e.current!==t.target||n(!0)}),[e]),onBlur:(0,o.useCallback)((function(t){void 0!==e&&e.current!==t.target||n(!1)}),[e])}]}},53563:(e,t,n)=>{"use strict";n.d(t,{useIsMouseDown:()=>r});var o=n(67294);function r(){const e=(0,o.useRef)(!1),t=(0,o.useCallback)(()=>{e.current=!0},[e]),n=(0,o.useCallback)(()=>{e.current=!1},[e]);return{isMouseDown:e,handleMouseDown:t,handleMouseUp:n}}},66364:(e,t,n)=>{"use strict";n.d(t,{useMergedRefs:()=>r});var o=n(67294);function r(e){return(0,o.useCallback)(function(e){return t=>{e.forEach(e=>{"function"==typeof e?e(t):null!==e&&(e.current=t)})}}(e),e)}},1130:(e,t,n)=>{"use strict";function o(e){null!==e&&e.setSelectionRange(0,e.value.length)}n.d(t,{selectAllContent:()=>o})},66213:(e,t,n)=>{"use strict";function o(...e){return t=>{for(const n of e)void 0!==n&&n(t)}}n.d(t,{createSafeMulticastEventHandler:()=>o})}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
|
@ -0,0 +1 @@
|
|||
.defaultsButtonText-3mn75BN0{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3mn75BN0{color:#b2b5be}.defaultsButtonItem-3mn75BN0{min-width:100px}.defaultsButtonIcon-3mn75BN0{display:flex}.themesButtonText-3nid3QQp{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3nid3QQp{color:#b2b5be}.themesButtonIcon-3nid3QQp{display:flex}.defaultsButtonText-3nid3QQp{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3nid3QQp{color:#b2b5be}.defaultsButtonItem-3nid3QQp{min-width:100px}
|
|
@ -0,0 +1 @@
|
|||
.defaultsButtonText-3mn75BN0{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3mn75BN0{color:#b2b5be}.defaultsButtonItem-3mn75BN0{min-width:100px}.defaultsButtonIcon-3mn75BN0{display:flex}.themesButtonText-3nid3QQp{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3nid3QQp{color:#b2b5be}.themesButtonIcon-3nid3QQp{display:flex}.defaultsButtonText-3nid3QQp{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3nid3QQp{color:#b2b5be}.defaultsButtonItem-3nid3QQp{min-width:100px}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
.themesButtonText-3vn5WLwC{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3vn5WLwC{color:#b2b5be}.themesButtonIcon-3vn5WLwC{display:flex}.defaultsButtonText-3vn5WLwC{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3vn5WLwC{color:#b2b5be}.defaultsButtonItem-3vn5WLwC{min-width:100px}.backButton-ukxmTk5_{align-items:center;color:#131722;display:flex;height:100%;padding-right:20px;width:28px}html.theme-dark .backButton-ukxmTk5_{color:#b2b5be}.withSidebar-1e-cIUlp{display:block;max-width:750px;min-width:610px;width:auto}@media screen and (max-width:768px){.withSidebar-1e-cIUlp{max-width:610px;min-width:420px;width:auto}}@media screen and (max-width:428px){.withSidebar-1e-cIUlp{min-height:auto;min-width:100%}}.withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex-direction:row;overflow:hidden}html.theme-dark .withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #434651}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{-webkit-overflow-scrolling:touch;flex:1 1 auto;min-height:145px;overflow-x:hidden;overflow-y:auto;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:auto}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp{scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{min-height:auto}}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar{height:5px;width:5px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-corner{display:none}.withSidebar-1e-cIUlp .applyToAllButton-1e-cIUlp{padding-right:12px}
|
|
@ -0,0 +1 @@
|
|||
.themesButtonText-3vn5WLwC{color:#131722;font-size:14px;width:100px}html.theme-dark .themesButtonText-3vn5WLwC{color:#b2b5be}.themesButtonIcon-3vn5WLwC{display:flex}.defaultsButtonText-3vn5WLwC{color:#131722;font-size:16px;width:100px}html.theme-dark .defaultsButtonText-3vn5WLwC{color:#b2b5be}.defaultsButtonItem-3vn5WLwC{min-width:100px}.backButton-ukxmTk5_{align-items:center;color:#131722;display:flex;height:100%;padding-left:20px;width:28px}html.theme-dark .backButton-ukxmTk5_{color:#b2b5be}.backButton-ukxmTk5_ svg{transform:rotate(180deg)}.withSidebar-1e-cIUlp{display:block;max-width:750px;min-width:610px;width:auto}@media screen and (max-width:768px){.withSidebar-1e-cIUlp{max-width:610px;min-width:420px;width:auto}}@media screen and (max-width:428px){.withSidebar-1e-cIUlp{min-height:auto;min-width:100%}}.withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex-direction:row;overflow:hidden}html.theme-dark .withSidebar-1e-cIUlp .content-1e-cIUlp{border-top:1px solid #434651}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{-webkit-overflow-scrolling:touch;flex:1 1 auto;min-height:145px;overflow-x:hidden;overflow-y:auto;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:auto}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp{scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.withSidebar-1e-cIUlp .tabContent-1e-cIUlp{min-height:auto}}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar{height:5px;width:5px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.withSidebar-1e-cIUlp .tabContent-1e-cIUlp::-webkit-scrollbar-corner{display:none}.withSidebar-1e-cIUlp .applyToAllButton-1e-cIUlp{padding-left:12px}
|
|
@ -0,0 +1 @@
|
|||
.loader-38qh0l_K{bottom:0;font-size:0;height:100%;left:0;margin:0 auto;opacity:1;position:absolute;right:0;text-align:center;top:0;transition:opacity .35s ease}.loader-38qh0l_K.static-38qh0l_K{display:inline-flex;position:static}.loader-38qh0l_K:after{content:" ";display:inline-block;height:100%;vertical-align:middle}.loader-38qh0l_K .item-38qh0l_K{--ui-lib-loader-color-default:currentColor;animation:tv-button-loader-38qh0l_K .96s ease-in-out infinite both;background-color:var(--ui-lib-loader-color,var(--ui-lib-loader-color-default));border-radius:100%;display:inline-block;height:10px;margin-left:2px;margin-right:2px;opacity:1;transform:translateY(0) scale(.6);transition:transform .35s cubic-bezier(.68,-.55,.265,1.55);vertical-align:middle;width:10px}.loader-38qh0l_K .item-38qh0l_K:nth-child(2){animation-delay:.151s;transition-delay:.11666667s}.loader-38qh0l_K .item-38qh0l_K:nth-child(3){animation-delay:.32s;transition-delay:233.33333ms}.loader-38qh0l_K .item-38qh0l_K.black-38qh0l_K{--ui-lib-loader-color-default:#787b86}.loader-38qh0l_K .item-38qh0l_K.white-38qh0l_K{--ui-lib-loader-color-default:#fff}.loader-38qh0l_K .item-38qh0l_K.gray-38qh0l_K{--ui-lib-loader-color-default:#b2b5be}.loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#131722}html.theme-dark .loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#d1d4dc}.loader-38qh0l_K.loader-initial-38qh0l_K{opacity:.1}.loader-38qh0l_K.loader-initial-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(12px) scale(.6)}.loader-38qh0l_K.loader-appear-38qh0l_K{opacity:1;transition:opacity .7s ease}.loader-38qh0l_K.loader-appear-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(0) scale(.6)}@keyframes tv-button-loader-38qh0l_K{0%,to{transform:scale(.6)}50%{transform:scale(.9)}}
|
|
@ -0,0 +1 @@
|
|||
.loader-38qh0l_K{bottom:0;font-size:0;height:100%;left:0;margin:0 auto;opacity:1;position:absolute;right:0;text-align:center;top:0;transition:opacity .35s ease}.loader-38qh0l_K.static-38qh0l_K{display:inline-flex;position:static}.loader-38qh0l_K:after{content:" ";display:inline-block;height:100%;vertical-align:middle}.loader-38qh0l_K .item-38qh0l_K{--ui-lib-loader-color-default:currentColor;animation:tv-button-loader-38qh0l_K .96s ease-in-out infinite both;background-color:var(--ui-lib-loader-color,var(--ui-lib-loader-color-default));border-radius:100%;display:inline-block;height:10px;margin-left:2px;margin-right:2px;opacity:1;transform:translateY(0) scale(.6);transition:transform .35s cubic-bezier(.68,-.55,.265,1.55);vertical-align:middle;width:10px}.loader-38qh0l_K .item-38qh0l_K:nth-child(2){animation-delay:.151s;transition-delay:.11666667s}.loader-38qh0l_K .item-38qh0l_K:nth-child(3){animation-delay:.32s;transition-delay:233.33333ms}.loader-38qh0l_K .item-38qh0l_K.black-38qh0l_K{--ui-lib-loader-color-default:#787b86}.loader-38qh0l_K .item-38qh0l_K.white-38qh0l_K{--ui-lib-loader-color-default:#fff}.loader-38qh0l_K .item-38qh0l_K.gray-38qh0l_K{--ui-lib-loader-color-default:#b2b5be}.loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#131722}html.theme-dark .loader-38qh0l_K .item-38qh0l_K.primary-38qh0l_K{--ui-lib-loader-color-default:#d1d4dc}.loader-38qh0l_K.loader-initial-38qh0l_K{opacity:.1}.loader-38qh0l_K.loader-initial-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(12px) scale(.6)}.loader-38qh0l_K.loader-appear-38qh0l_K{opacity:1;transition:opacity .7s ease}.loader-38qh0l_K.loader-appear-38qh0l_K .item-38qh0l_K{animation:none;transform:translateY(0) scale(.6)}@keyframes tv-button-loader-38qh0l_K{0%,to{transform:scale(.6)}50%{transform:scale(.9)}}
|
|
@ -0,0 +1 @@
|
|||
.icon-26rGYU-z{display:flex}.wrap-3JkbcgoB{position:relative}.input-3JkbcgoB{bottom:0;left:0;margin:0;max-width:100%;min-width:100%;opacity:0;position:absolute;top:0}
|
|
@ -0,0 +1 @@
|
|||
.icon-26rGYU-z{display:flex}.wrap-3JkbcgoB{position:relative}.input-3JkbcgoB{bottom:0;margin:0;max-width:100%;min-width:100%;opacity:0;position:absolute;right:0;top:0}
|
|
@ -0,0 +1 @@
|
|||
.favorite-I_fAY9V2{align-items:center;background-color:var(--tv-list-item-button-background-color);border-radius:4px;color:#787b86;display:inline-flex;font-size:0;height:22px;justify-content:center;min-width:22px;width:22px}.favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}}html.theme-dark .favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}}html.theme-dark .favorite-I_fAY9V2:active{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{color:#b2b5be}}.favorite-I_fAY9V2.disabled-I_fAY9V2,.favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}.favorite-I_fAY9V2.active-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2{color:#90bff9}.favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}.favorite-I_fAY9V2.checked-I_fAY9V2{color:#fbc02d}html.theme-dark .favorite-I_fAY9V2.checked-I_fAY9V2{color:#f9a825}
|
|
@ -0,0 +1 @@
|
|||
.favorite-I_fAY9V2{align-items:center;background-color:var(--tv-list-item-button-background-color);border-radius:4px;color:#787b86;display:inline-flex;font-size:0;height:22px;justify-content:center;min-width:22px;width:22px}.favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#e0e3eb);color:#131722}}html.theme-dark .favorite-I_fAY9V2:active{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{background-color:var(--tv-list-item-button-background-hover-color,#363a45)}}html.theme-dark .favorite-I_fAY9V2:active{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2:hover{color:#b2b5be}}.favorite-I_fAY9V2.disabled-I_fAY9V2,.favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:active{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.disabled-I_fAY9V2:hover{background-color:var(--tv-list-item-button-disabled-background-color,#0000)}}.favorite-I_fAY9V2.active-I_fAY9V2,html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2{color:#90bff9}.favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:active{background-color:#1848cc}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){html.theme-dark .favorite-I_fAY9V2.active-I_fAY9V2:hover{background-color:#1848cc}}.favorite-I_fAY9V2.checked-I_fAY9V2{color:#fbc02d}html.theme-dark .favorite-I_fAY9V2.checked-I_fAY9V2{color:#f9a825}
|
|
@ -0,0 +1,5 @@
|
|||
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2391],{80152:e=>{e.exports={button:"button-14c_DKWJ",disabled:"disabled-14c_DKWJ",hidden:"hidden-14c_DKWJ",icon:"icon-14c_DKWJ",dropped:"dropped-14c_DKWJ"}},31722:e=>{e.exports={button:"button-1WqyvKNY","button-children":"button-children-1WqyvKNY",hiddenArrow:"hiddenArrow-1WqyvKNY",invisibleFocusHandler:"invisibleFocusHandler-1WqyvKNY"}},31199:e=>{e.exports={placeholder:"placeholder-1J6emFeA"}},41615:(e,t,n)=>{"use strict";n.d(t,{createDomId:()=>a,joinDomIds:()=>c});const l=/\s/g;function o(e){return"string"==typeof e}function r(e){switch(typeof e){case"string":return e;case"number":case"bigint":return e.toString(10);case"boolean":case"symbol":return e.toString();default:return null}}function i(e){return e.trim().length>0}function s(e){return e.replace(l,"-")}function a(...e){const t=e.map(r).filter(o).filter(i).map(s);return(t.length>0&&t[0].startsWith("id_")?t:["id",...t]).join("_")}function c(...e){return e.map(r).filter(o).filter(i).join(" ")}},5862:(e,t,n)=>{"use strict";n.d(t,{useKeyboardToggle:()=>r,useKeyboardClose:()=>i,useKeyboardOpen:()=>s});var l=n(67294),o=n(42998);function r(e){return(0,l.useCallback)(t=>{switch(t){case 13:case 32:return e(),!0;default:return!1}},[e])}function i(e,t){return(0,l.useCallback)(n=>{if(!e)return!1;switch(n){case 9:case o.Modifiers.Shift+9:case 27:return t(),!0;default:return!1}},[e,t])}function s(e,t){return(0,l.useCallback)(n=>{if(e)return!1;switch(n){case 40:case 38:return t(),!0;default:return!1}},[e,t])}},98981:(e,t,n)=>{"use strict";n.d(t,{DisclosureMenuView:()=>v});var l=n(67294),o=n(94184),r=n.n(o),i=n(16282),s=n(66364),a=n(11888),c=n(92136),u=n(49775),d=n(20914),h=n(80152);function f(e){const{isDropped:t}=e;return l.createElement(u.Icon,{className:r()(h.icon,t&&h.dropped),icon:d})}function p(e){const{className:t,disabled:n,isDropped:o}=e;return l.createElement("span",{className:r()(h.button,n&&h.disabled,t)},l.createElement(f,{isDropped:o}))}var b=n(76420),m=n(31722);const v=l.forwardRef((e,t)=>{const{listboxId:n,className:o,listboxClassName:u,listboxTabIndex:d,hideArrowButton:h,matchButtonAndListboxWidths:f,disabled:v,isOpened:g,scrollWrapReference:C,listboxReference:S,size:w="medium",onClose:y,onOpen:k,onListboxFocus:_,onListboxBlur:E,onListboxKeyDown:x,buttonChildren:N,children:M,caretClassName:R,listboxAria:z,...D}=e,B=(0,l.useRef)(null),F=(0,l.useCallback)(()=>{const e=(0,i.ensureNotNull)(B.current).getBoundingClientRect(),t={x:e.left,y:e.top+e.height};return f&&(t.overrideWidth=e.width),t},[]),I=!h&&l.createElement(c.EndSlot,null,l.createElement(p,{isDropped:g,disabled:v,className:R}));return l.createElement(l.Fragment,null,l.createElement(a.ControlSkeleton,{...D,"data-role":"listbox","aria-expanded":g,"aria-owns":g?n:void 0,"aria-controls":g?n:void 0,"aria-disabled":v,disabled:v,className:r()(m.button,o),size:w,ref:(0,s.useMergedRefs)([B,t]),middleSlot:l.createElement(c.MiddleSlot,null,l.createElement("span",{className:r()(m["button-children"],h&&m.hiddenArrow)},N)),endSlot:I
|
||||
}),l.createElement(b.PopupMenu,{...z,id:n,className:u,tabIndex:d,isOpened:g,position:F,onClose:y,onOpen:k,doNotCloseOn:B.current,reference:S,scrollWrapReference:C,onFocus:_,onBlur:E,onKeyDown:x},M))});v.displayName="DisclosureMenuView"},22904:(e,t,n)=>{"use strict";n.d(t,{useDisclosureMenuControl:()=>a});var l=n(67294),o=n(16282),r=n(15965),i=n(66213),s=n(15738);function a(e){const{disabled:t,intent:n,highlight:a,onFocus:c,onBlur:u,onClick:d}=e,[h,f]=(0,l.useState)(!1),[p,b]=(0,r.useFocus)(),m=p||h,v=null!=a?a:m,g=null!=n?n:m?"primary":"default",C=(0,l.useRef)(null),S=(0,l.useCallback)(()=>(0,o.ensureNotNull)(C.current).focus(),[C]),w=(0,l.useRef)(null),y=(0,l.useCallback)(()=>(0,o.ensureNotNull)(w.current).focus(),[w]),k=(0,l.useCallback)(()=>f(!0),[f]),_=(0,l.useCallback)(()=>{f(!1);const{activeElement:e}=document;e&&(0,s.isTextEditingField)(e)||S()},[f,S]),E=(0,l.useCallback)(()=>{h?_():k()},[h,_,k]),x=t?[]:[c,b.onFocus],N=t?[]:[u,b.onBlur],M=t?[]:[d,E],R=(0,i.createSafeMulticastEventHandler)(...x),z=(0,i.createSafeMulticastEventHandler)(...N),D=(0,i.createSafeMulticastEventHandler)(...M);return{isOpened:h,isFocused:m,highlight:v,intent:g,open:k,onOpen:y,close:_,toggle:E,buttonFocusBindings:{onFocus:R,onBlur:z},onButtonClick:D,buttonRef:C,listboxRef:w}}},45221:(e,t,n)=>{"use strict";n.d(t,{Select:()=>_});var l=n(67294),o=n(16282),r=n(41615),i=n(8596);const s={duration:200},a={vertical:{scrollSize:"scrollHeight",clientSize:"clientHeight",start:"top",end:"bottom",size:"height"},horizontal:{scrollSize:"scrollWidth",clientSize:"clientWidth",start:"left",end:"right",size:"width"}};function c(e,t){const n=a[e];return t[n.scrollSize]>t[n.clientSize]}function u(e,t,n,l,o,r){const s=function(e,t,n){const l=a[e];return{start:0,middle:-1*(Math.floor(n[l.size]/2)-Math.floor(t[l.size]/2)),end:-1*(n[l.size]-t[l.size])}}(e,l,o);let c=0;if(function(e,t,n){const l=a[e];return t[l.start]<n[l.start]-n[l.size]/2||t[l.end]>n[l.end]+n[l.size]/2}(e,l,o))c=s.middle;else{const t=function(e){const{start:t,middle:n,end:l}=e,o=new Map([[Math.abs(t),{key:"start",value:Math.sign(t)}],[Math.abs(n),{key:"middle",value:Math.sign(n)}],[Math.abs(l),{key:"end",value:Math.sign(l)}]]),r=Math.min(...o.keys());return o.get(r)}(function(e,t,n){const l=a[e],o=t[l.start]+Math.floor(t[l.size]/2),r=n[l.start]+Math.floor(n[l.size]/2);return{start:t[l.start]-n[l.start],middle:o-r,end:t[l.end]-n[l.end]}}(e,l,o));c=void 0!==t?s[t.key]:0}return function(e){const{additionalScroll:t=0,duration:n=i.dur,func:l=i.easingFunc.easeInOutCubic,onScrollEnd:o,target:r,wrap:s,direction:a="vertical"}=e;let{targetRect:c,wrapRect:u}=e;c=null!=c?c:r.getBoundingClientRect(),u=null!=u?u:s.getBoundingClientRect();const d=("vertical"===a?c.top-u.top:c.left-u.left)+t,h="vertical"===a?"scrollTop":"scrollLeft",f=s?s[h]:0;let p,b=0;return b=window.requestAnimationFrame((function e(t){let r;if(p?r=t-p:(r=0,p=t),r>=n)return s[h]=f+d,void(o&&o());const i=f+d*l(r/n);s[h]=Math.floor(i),b=window.requestAnimationFrame(e)})),function(){window.cancelAnimationFrame(b),o&&o()}}({...r,target:t,
|
||||
targetRect:l,wrap:n,wrapRect:o,additionalScroll:c,direction:e})}class d{constructor(e=null){this._container=null,this._lastScrolledElement=null,this._stopVerticalScroll=null,this._stopHorizontalScroll=null,this._container=e}scrollTo(e,t=s){if(null!==this._container&&null!==e&&!function(e,t){const n=e.getBoundingClientRect(),l=t.getBoundingClientRect();return n.top>=l.top&&n.bottom<=l.bottom&&n.left>=l.left&&n.right<=l.right}(e,this._container)){const n=e.getBoundingClientRect(),l=this._container.getBoundingClientRect();this.stopScroll(),c("vertical",this._container)&&(this._stopVerticalScroll=u("vertical",e,this._container,n,l,this._modifyOptions("vertical",t))),c("horizontal",this._container)&&(this._stopHorizontalScroll=u("horizontal",e,this._container,n,l,this._modifyOptions("horizontal",t)))}this._lastScrolledElement=e}scrollToLastElement(e){this.scrollTo(this._lastScrolledElement,e)}stopScroll(){null!==this._stopVerticalScroll&&this._stopVerticalScroll(),null!==this._stopHorizontalScroll&&this._stopHorizontalScroll()}setContainer(e){var t;this._container=e,(null===(t=this._container)||void 0===t?void 0:t.contains(this._lastScrolledElement))||(this._lastScrolledElement=null)}destroy(){this.stopScroll(),this._container=null,this._lastScrolledElement=null}_handleScrollEnd(e){"vertical"===e?this._stopVerticalScroll=null:this._stopHorizontalScroll=null}_modifyOptions(e,t){return Object.assign({},t,{onScrollEnd:()=>{this._handleScrollEnd(e),void 0!==t.onScrollEnd&&t.onScrollEnd()}})}}var h=n(66364),f=n(95860),p=n(99479),b=n(58848);var m=n(98981),v=n(5862),g=n(22904),C=n(42998),S=n(31199);function w(e){return!e.readonly}function y(e,t){var n;return null!==(n=null==t?void 0:t.id)&&void 0!==n?n:(0,r.createDomId)(e,"item",null==t?void 0:t.value)}function k(e){var t,n;const{selectedItem:o,placeholder:r}=e;if(!o)return l.createElement("span",{className:S.placeholder},r);const i=null!==(n=null!==(t=o.selectedContent)&&void 0!==t?t:o.content)&&void 0!==n?n:o.value;return l.createElement("span",null,i)}const _=l.forwardRef((e,t)=>{const{id:n,menuClassName:i,menuItemClassName:s,tabIndex:a=0,disabled:c,highlight:u,intent:S,hideArrowButton:_,placeholder:E,addPlaceholderToItems:x=!0,value:N,"aria-labelledby":M,onFocus:R,onBlur:z,onClick:D,onChange:B,...F}=e;let{items:I}=e;if(E&&x){I=[{value:void 0,content:E,id:(0,r.createDomId)(n,"placeholder")},...I]}const{isOpened:W,isFocused:K,highlight:O,intent:A,open:T,onOpen:H,close:L,toggle:V,buttonFocusBindings:q,onButtonClick:J,buttonRef:j,listboxRef:P}=(0,g.useDisclosureMenuControl)({disabled:c,intent:S,highlight:u,onFocus:R,onBlur:z,onClick:D}),Y=function(e){const t=(0,l.useRef)(null);return(0,l.useEffect)(()=>(t.current=new d(e),()=>(0,o.ensureNotNull)(t.current).destroy()),[]),t}(),G=(0,l.useRef)(null),Q=(0,l.useRef)(new WeakMap),U=I.filter(w),X=U.find(e=>e.value===N);(0,l.useEffect)(()=>ae(),[X,ae]);const Z=(0,r.joinDomIds)(M,n),$=Z.length>0?Z:void 0,ee=(0,r.createDomId)(n,"listbox"),te=(0,l.useMemo)(()=>({role:"listbox","aria-labelledby":M,"aria-activedescendant":y(n,X)
|
||||
}),[M,X]),ne=function(e,t,n){const o=(0,l.useCallback)(()=>{const l=e.findIndex(e=>e.value===t);l!==e.length-1&&n&&n(e[l+1].value)},[e,t,n]),r=(0,l.useCallback)(()=>{const l=e.findIndex(e=>e.value===t);if(0===l)return;n&&n(e[l>0?l-1:0].value)},[e,t,n]),i=(0,l.useCallback)(()=>{n&&n(e[0].value)},[n,e]),s=(0,l.useCallback)(()=>{n&&n(e[e.length-1].value)},[n,e]);return(0,l.useCallback)(e=>{switch(e){case 40:return o(),!0;case 38:return r(),!0;case 34:return s(),!0;case 33:return i(),!0;default:return!1}},[o,r,i,s])}(U,N,B),le=(0,v.useKeyboardToggle)(V),oe=(0,v.useKeyboardClose)(W,L),re=(0,v.useKeyboardOpen)(W,T),ie=function(e){const t=(0,l.useRef)(""),n=(0,l.useMemo)(()=>(0,p.default)(()=>{t.current=""},500),[]),o=(0,l.useMemo)(()=>(0,b.default)(e,200),[e]);return(0,l.useCallback)(e=>{e.key.length>0&&e.key.length<3&&(t.current+=e.key,o(t.current,e),n())},[n,o])}((e,t)=>{const n=function(e,t){return e.find(e=>{var n;const l=t.toLowerCase();return!e.readonly&&(!e.readonly&&("string"==typeof e.content&&e.content.toLowerCase().startsWith(l)||String(null!==(n=e.value)&&void 0!==n?n:"").toLowerCase().startsWith(l)))})}(U,e);void 0!==n&&B&&(t.stopPropagation(),W||T(),B(n.value))});return l.createElement(m.DisclosureMenuView,{...F,...q,id:n,role:"button",tabIndex:c?-1:a,"aria-haspopup":"listbox","aria-labelledby":$,disabled:c,hideArrowButton:_,isFocused:K,isOpened:W,highlight:O,intent:A,ref:(0,h.useMergedRefs)([j,t]),onClick:J,onOpen:function(){ae({duration:0}),H()},onClose:L,onKeyDown:function(e){const t=(0,C.hashFromEvent)(e);if(le(t)||oe(t)||re(t))return void e.preventDefault();ie(e)},listboxId:ee,listboxTabIndex:-1,listboxClassName:i,listboxAria:te,listboxReference:P,scrollWrapReference:function(e){G.current=e,(0,o.ensureNotNull)(Y.current).setContainer(e)},onListboxKeyDown:function(e){const t=(0,C.hashFromEvent)(e);if(ne(t)||le(t)||oe(t))return void e.preventDefault();ie(e)},buttonChildren:l.createElement(k,{selectedItem:X,placeholder:E})},I.map((e,t)=>{var o;if(e.readonly)return l.createElement(l.Fragment,{key:"readonly_item_"+t},e.content);const r=y(n,e);return l.createElement(f.PopupMenuItem,{key:r,id:r,className:s,role:"option","aria-selected":N===e.value,isActive:N===e.value,label:null!==(o=e.content)&&void 0!==o?o:e.value,onClick:se,onClickArg:e.value,isDisabled:e.disabled,reference:t=>function(e,t){Q.current.set(e,t)}(e,t)})}));function se(e){B&&B(e)}function ae(e){if(W&&void 0!==X){const t=Q.current.get(X);null!=t&&(0,o.ensureNotNull)(Y.current).scrollTo(t,e)}}});_.displayName="Select"},73991:(e,t,n)=>{"use strict";n.d(t,{TouchScrollContainer:()=>s});var l=n(67294),o=n(67891),r=n(16282),i=n(43367);function s(e){const{reference:t,children:n,...r}=e,s=(0,l.useRef)(null),c=(0,l.useCallback)(e=>{t&&(t.current=e),i.CheckMobile.iOS()&&(null!==s.current&&(0,o.enableBodyScroll)(s.current),s.current=e,null!==s.current&&(0,o.disableBodyScroll)(s.current,{allowTouchMove:a(s)}))},[t]);return l.createElement("div",{ref:c,...r},n)}function a(e){return t=>{const n=(0,r.ensureNotNull)(e.current),l=document.activeElement
|
||||
;return!n.contains(t)||null!==l&&n.contains(l)&&l.contains(t)}}},20914:e=>{e.exports='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 7" width="11" height="7" fill="none"><path stroke="currentColor" stroke-width="1.3" d="M.5 1.5l5 4 5-4"/></svg>'}}]);
|
|
@ -0,0 +1,4 @@
|
|||
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2402],{66541:t=>{t.exports={dialog:"dialog-UM6w7sFp",rounded:"rounded-UM6w7sFp",shadowed:"shadowed-UM6w7sFp",fullscreen:"fullscreen-UM6w7sFp",darker:"darker-UM6w7sFp",backdrop:"backdrop-UM6w7sFp"}},27898:t=>{t.exports={"tablet-normal-breakpoint":"screen and (max-width: 768px)","tooltip-offset":"20px",dialog:"dialog-2AogBbC7",dragging:"dragging-2AogBbC7",dialogAnimatedAppearance:"dialogAnimatedAppearance-2AogBbC7",dialogAnimation:"dialogAnimation-2AogBbC7",dialogTooltip:"dialogTooltip-2AogBbC7"}},90714:(t,e,i)=>{"use strict";i.d(e,{PopupContext:()=>s});const s=i(67294).createContext(null)},32402:(t,e,i)=>{"use strict";i.d(e,{PopupDialog:()=>T});var s=i(67294),o=i(94184),n=i(16282),a=i(78106),r=i(90071),l=i(74818),h=i(66541);class d extends s.PureComponent{constructor(){super(...arguments),this._manager=new r.OverlapManager,this._handleSlot=t=>{this._manager.setContainer(t)}}render(){const{rounded:t=!0,shadowed:e=!0,fullscreen:i=!1,darker:n=!1,className:r,backdrop:d}=this.props,c=o(r,h.dialog,t&&h.rounded,e&&h.shadowed,i&&h.fullscreen,n&&h.darker),u=(0,l.filterDataProps)(this.props),g=this.props.style?{...this._createStyles(),...this.props.style}:this._createStyles();return s.createElement(s.Fragment,null,s.createElement(a.SlotContext.Provider,{value:this._manager},d&&s.createElement("div",{onClick:this.props.onClickBackdrop,className:h.backdrop}),s.createElement("div",{...u,className:c,style:g,ref:this.props.reference,onFocus:this.props.onFocus,onMouseDown:this.props.onMouseDown,onMouseUp:this.props.onMouseUp,onClick:this.props.onClick,onKeyDown:this.props.onKeyDown,tabIndex:-1},this.props.children)),s.createElement(a.Slot,{reference:this._handleSlot}))}_createStyles(){const{bottom:t,left:e,width:i,right:s,top:o,zIndex:n,height:a}=this.props;return{bottom:t,left:e,right:s,top:o,zIndex:n,maxWidth:i,height:a}}}var c=i(36668),u=i(13894),g=i(57968);function p(t,e,i,s){return t+e>s&&(t=s-e),t<i&&(t=i),t}function _(t){return{x:(0,g.clamp)(t.x,20,document.documentElement.clientWidth-20),y:(0,g.clamp)(t.y,20,window.innerHeight-20)}}function m(t){return{x:t.clientX,y:t.clientY}}function f(t){return{x:t.touches[0].clientX,y:t.touches[0].clientY}}class v{constructor(t,e,i={boundByScreen:!0}){this._drag=null,this._canBeTouchClick=!1,this._frame=null,this._onMouseDragStart=t=>{if(0!==t.button)return;t.preventDefault(),document.addEventListener("mousemove",this._onMouseDragMove),document.addEventListener("mouseup",this._onMouseDragEnd);const e=_(m(t));this._dragStart(e)},this._onTouchDragStart=t=>{this._canBeTouchClick=!0,t.preventDefault(),this._header.addEventListener("touchmove",this._onTouchDragMove,{passive:!1});const e=_(f(t));this._dragStart(e)},this._onMouseDragEnd=t=>{t.target instanceof Node&&this._header.contains(t.target)&&t.preventDefault(),document.removeEventListener("mousemove",this._onMouseDragMove),document.removeEventListener("mouseup",this._onMouseDragEnd),this._onDragStop()},this._onTouchDragEnd=t=>{
|
||||
this._header.removeEventListener("touchmove",this._onTouchDragMove),this._onDragStop(),this._canBeTouchClick&&(this._canBeTouchClick=!1,function(t){if(t instanceof SVGElement){const e=document.createEvent("SVGEvents");e.initEvent("click",!0,!0),t.dispatchEvent(e)}t instanceof HTMLElement&&t.click()}(t.target))},this._onMouseDragMove=t=>{const e=_(m(t));this._dragMove(e)},this._onTouchDragMove=t=>{this._canBeTouchClick=!1,t.preventDefault();const e=_(f(t));this._dragMove(e)},this._onDragStop=()=>{this._drag=null,this._header.classList.remove("dragging")},this._dialog=t,this._header=e,this._options=i,this._header.addEventListener("mousedown",this._onMouseDragStart),this._header.addEventListener("touchstart",this._onTouchDragStart),this._header.addEventListener("touchend",this._onTouchDragEnd)}destroy(){null!==this._frame&&cancelAnimationFrame(this._frame),this._header.removeEventListener("mousedown",this._onMouseDragStart),document.removeEventListener("mouseup",this._onMouseDragEnd),this._header.removeEventListener("touchstart",this._onTouchDragStart),this._header.removeEventListener("touchend",this._onTouchDragEnd),document.removeEventListener("mouseleave",this._onMouseDragEnd)}updateOptions(t){this._options=t}_dragStart(t){const e=this._dialog.getBoundingClientRect();this._drag={startX:t.x,startY:t.y,finishX:t.x,finishY:t.y,dialogX:e.left,dialogY:e.top};const i=Math.round(e.left),s=Math.round(e.top);this._dialog.style.transform=`translate(${i}px, ${s}px)`,this._header.classList.add("dragging"),this._options.onDragStart&&this._options.onDragStart()}_dragMove(t){if(this._drag){if(this._drag.finishX=t.x,this._drag.finishY=t.y,null!==this._frame)return;this._frame=requestAnimationFrame(()=>{if(this._drag){const e=t.x-this._drag.startX,i=t.y-this._drag.startY;this._moveDialog(this._drag.dialogX+e,this._drag.dialogY+i)}this._frame=null})}}_moveDialog(t,e){const i=this._dialog.getBoundingClientRect(),{boundByScreen:s}=this._options,o=p(t,i.width,s?0:-1/0,s?window.innerWidth:1/0),n=p(e,i.height,s?0:-1/0,s?window.innerHeight:1/0);this._dialog.style.transform=`translate(${Math.round(o)}px, ${Math.round(n)}px)`}}const y={vertical:0};class D{constructor(t,e){this._frame=null,this._isFullscreen=!1,this._handleResize=()=>{null===this._frame&&(this._frame=requestAnimationFrame(()=>{this.recalculateBounds(),this._frame=null}))},this._dialog=t,this._guard=e.guard||y,this._calculateDialogPosition=e.calculateDialogPosition,this._initialHeight=t.style.height,window.addEventListener("resize",this._handleResize)}updateOptions(t){this._guard=t.guard||y,this._calculateDialogPosition=t.calculateDialogPosition}setFullscreen(t){this._isFullscreen!==t&&(this._isFullscreen=t,this.recalculateBounds())}centerAndFit(){const{x:t,y:e}=this.getDialogsTopLeftCoordinates(),i=this._calcAvailableHeight(),s=this._calcDialogHeight();i===s&&(this._dialog.style.height=s+"px"),this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.transform=`translate(${t}px, ${e}px)`}getDialogsTopLeftCoordinates(){
|
||||
const{clientHeight:t,clientWidth:e}=document.documentElement,i=this._calcDialogHeight(),s=e/2-this._dialog.clientWidth/2,o=t/2-i/2;return{x:Math.round(s),y:Math.round(o)}}recalculateBounds(){const{clientHeight:t,clientWidth:e}=document.documentElement;if(this._isFullscreen)this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.width="100%",this._dialog.style.height="100%",this._dialog.style.transform="none";else{const{vertical:i}=this._guard;if(this._calculateDialogPosition){const s=this._calculateDialogPosition(this._dialog,{clientWidth:e,clientHeight:t},{vertical:i}),{left:o,top:n}=s;this._dialog.style.transform=`translate(${Math.round(o)}px, ${Math.round(n)}px)`}else{this._dialog.style.width="",this._dialog.style.height="";const s=this._dialog.getBoundingClientRect(),o=t-2*i,n=p(s.left,s.width,0,e),a=p(s.top,s.height,i,t);this._dialog.style.top="0px",this._dialog.style.left="0px",this._dialog.style.transform=`translate(${Math.round(n)}px, ${Math.round(a)}px)`,this._dialog.style.height=o<s.height?o+"px":this._initialHeight}}}destroy(){window.removeEventListener("resize",this._handleResize),null!==this._frame&&(cancelAnimationFrame(this._frame),this._frame=null)}_calcDialogHeight(){const t=this._calcAvailableHeight();return t<this._dialog.clientHeight?t:this._dialog.clientHeight}_calcAvailableHeight(){return document.documentElement.clientHeight-2*this._guard.vertical}}var x=i(4735),E=i(90714),S=i(75761),M=i(27898);M["tooltip-offset"];class w extends s.PureComponent{constructor(t){super(t),this._dialog=null,this._handleDialogRef=t=>{const{reference:e}=this.props;this._dialog=t,"function"==typeof e&&e(t)},this._handleFocus=t=>{this._moveToTop()},this._handleMouseDown=t=>{this._moveToTop()},this._handleTouchStart=t=>{this._moveToTop()},this.state={canFitTooltip:!1}}render(){return s.createElement(E.PopupContext.Provider,{value:this},s.createElement(u.OutsideEvent,{mouseDown:!0,touchStart:!0,handler:this.props.onClickOutside},t=>s.createElement("div",{ref:t,"data-outside-boundary-for":this.props.name,onFocus:this._handleFocus,onMouseDown:this._handleMouseDown,onTouchStart:this._handleTouchStart,"data-dialog-name":this.props["data-dialog-name"]},s.createElement(d,{style:this._applyAnimationCSSVariables(),...this.props,reference:this._handleDialogRef,className:o(M.dialog,this.props.className)},!1,this.props.children))))}componentDidMount(){const{draggable:t,boundByScreen:e,onDragStart:i}=this.props,s=(0,n.ensureNotNull)(this._dialog);if(t){const t=s.querySelector("[data-dragg-area]");t&&t instanceof HTMLElement&&(this._drag=new v(s,t,{boundByScreen:Boolean(e),onDragStart:i}))}this.props.autofocus&&!s.contains(document.activeElement)&&s.focus(),(this._isFullScreen()||this.props.fixedBody)&&(0,S.setFixedBodyState)(!0);const{guard:o,calculateDialogPosition:a}=this.props;this._resize=new D(s,{guard:o,calculateDialogPosition:a}),this.props.isAnimationEnabled&&this.props.growPoint&&this._applyAppearanceAnimation(this.props.growPoint),this.props.centeredOnMount&&this._resize.centerAndFit(),
|
||||
this._resize.setFullscreen(this._isFullScreen()),this.props.shouldForceFocus&&s.focus()}componentDidUpdate(){if(this._resize){const{guard:t,calculateDialogPosition:e}=this.props;this._resize.updateOptions({guard:t,calculateDialogPosition:e}),this._resize.setFullscreen(this._isFullScreen())}this._drag&&this._drag.updateOptions({boundByScreen:Boolean(this.props.boundByScreen),onDragStart:this.props.onDragStart})}componentWillUnmount(){this._drag&&this._drag.destroy(),this._resize&&this._resize.destroy(),(this._isFullScreen()||this.props.fixedBody)&&(0,S.setFixedBodyState)(!1)}focus(){this._dialog&&this._dialog.focus()}centerAndFit(){this._resize&&this._resize.centerAndFit()}recalculateBounds(){this._resize&&this._resize.recalculateBounds()}_moveToTop(){null!==this.context&&this.context.moveToTop()}_applyAnimationCSSVariables(){return{"--animationTranslateStartX":null,"--animationTranslateStartY":null,"--animationTranslateEndX":null,"--animationTranslateEndY":null}}_applyAppearanceAnimation(t){if(this._resize&&this._dialog){const{x:e,y:i}=t,{x:s,y:o}=this._resize.getDialogsTopLeftCoordinates();this._dialog.style.setProperty("--animationTranslateStartX",e+"px"),this._dialog.style.setProperty("--animationTranslateStartY",i+"px"),this._dialog.style.setProperty("--animationTranslateEndX",s+"px"),this._dialog.style.setProperty("--animationTranslateEndY",o+"px"),this._dialog.classList.add(M.dialogAnimatedAppearance)}}_handleTooltipFit(){0}_isFullScreen(){return Boolean(this.props.fullscreen)}}w.contextType=x.PortalContext,w.defaultProps={boundByScreen:!0,draggable:!0,centeredOnMount:!0};const T=(0,c.makeOverlapable)(w)},13894:(t,e,i)=>{"use strict";i.d(e,{OutsideEvent:()=>o});var s=i(47165);function o(t){const{children:e,...i}=t;return e((0,s.useOutsideEvent)(i))}},36668:(t,e,i)=>{"use strict";i.d(e,{makeOverlapable:()=>n});var s=i(67294),o=i(4735);function n(t){return class extends s.PureComponent{render(){const{isOpened:e,root:i}=this.props;if(!e)return null;const n=s.createElement(t,{...this.props,zIndex:150});return"parent"===i?n:s.createElement(o.Portal,null,n)}}}}}]);
|
|
@ -0,0 +1,2 @@
|
|||
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[2444],{36677:t=>{t.exports={wrap:"wrap-3obNZqvj",wrapWithArrowsOuting:"wrapWithArrowsOuting-3obNZqvj",wrapOverflow:"wrapOverflow-3obNZqvj",scrollWrap:"scrollWrap-3obNZqvj",noScrollBar:"noScrollBar-3obNZqvj",icon:"icon-3obNZqvj",scrollLeft:"scrollLeft-3obNZqvj",scrollRight:"scrollRight-3obNZqvj",isVisible:"isVisible-3obNZqvj",iconWrap:"iconWrap-3obNZqvj",fadeLeft:"fadeLeft-3obNZqvj",fadeRight:"fadeRight-3obNZqvj"}},52444:(t,e,s)=>{"use strict";s.d(e,{HorizontalScroll:()=>R});var i=s(67294),r=s(94184),o=s(5383),n=s(16282),l=s(49775),a=s(99432),h=s(83939),c=s(76553),u=s(38508),d=s(36677);const p={isVisibleScrollbar:!0,shouldMeasure:!0,hideButtonsFrom:1};function f(t){return i.createElement("div",{className:r(d.fadeLeft,t.className,{[d.isVisible]:t.isVisible})})}function w(t){return i.createElement("div",{className:r(d.fadeRight,t.className,{[d.isVisible]:t.isVisible})})}function b(t){return i.createElement(v,{...t,className:d.scrollLeft})}function m(t){return i.createElement(v,{...t,className:d.scrollRight})}function v(t){return i.createElement("div",{className:r(t.className,{[d.isVisible]:t.isVisible}),onClick:t.onClick},i.createElement("div",{className:d.iconWrap},i.createElement(l.Icon,{icon:u,className:d.icon})))}const R=function(t=b,e=m,s=f,l=w){var u;return(u=class extends i.PureComponent{constructor(t){super(t),this._scroll=i.createRef(),this._wrapMeasureRef=i.createRef(),this._contentMeasureRef=i.createRef(),this._handleScrollLeft=()=>{if(this.props.onScrollButtonClick)return void this.props.onScrollButtonClick("left");const t=this.props.scrollStepSize||this.state.widthWrap-50;this.animateTo(Math.max(0,this.currentPosition()-t))},this._handleScrollRight=()=>{if(this.props.onScrollButtonClick)return void this.props.onScrollButtonClick("right");const t=this.props.scrollStepSize||this.state.widthWrap-50;this.animateTo(Math.min((this.state.widthContent||0)-(this.state.widthWrap||0),this.currentPosition()+t))},this._handleResizeWrap=t=>{this.props.onMeasureWrap&&this.props.onMeasureWrap(t),this.setState({widthWrap:t.width}),this._checkButtonsVisibility()},this._handleResizeContent=t=>{this.props.onMeasureContent&&this.props.onMeasureContent(t);const{shouldDecreaseWidthContent:e,buttonsWidthIfDecreasedWidthContent:s}=this.props;e&&s?this.setState({widthContent:t.width+2*s}):this.setState({widthContent:t.width})},this._handleScroll=()=>{const{onScroll:t}=this.props;t&&t(this.currentPosition(),this.isAtLeft(),this.isAtRight()),this._checkButtonsVisibility()},this._checkButtonsVisibility=()=>{const{isVisibleLeftButton:t,isVisibleRightButton:e}=this.state,s=this.isAtLeft(),i=this.isAtRight();s||t?s&&t&&this.setState({isVisibleLeftButton:!1}):this.setState({isVisibleLeftButton:!0}),i||e?i&&e&&this.setState({isVisibleRightButton:!1}):this.setState({isVisibleRightButton:!0})},this.state={widthContent:0,widthWrap:0,isVisibleRightButton:!1,isVisibleLeftButton:!1}}componentDidMount(){this._checkButtonsVisibility()}componentDidUpdate(t,e){
|
||||
e.widthWrap===this.state.widthWrap&&e.widthContent===this.state.widthContent||this._handleScroll(),this.props.shouldMeasure&&this._wrapMeasureRef.current&&this._contentMeasureRef.current&&(this._wrapMeasureRef.current.measure(),this._contentMeasureRef.current.measure())}currentPosition(){return this._scroll.current?(0,c.isRtl)()?(0,c.getLTRScrollLeft)(this._scroll.current):this._scroll.current.scrollLeft:0}isAtLeft(){return!this._isOverflowed()||this.currentPosition()<=(0,n.ensureDefined)(this.props.hideButtonsFrom)}isAtRight(){return!this._isOverflowed()||this.currentPosition()+this.state.widthWrap>=this.state.widthContent-(0,n.ensureDefined)(this.props.hideButtonsFrom)}animateTo(t,e=h.dur){const s=this._scroll.current;s&&((0,c.isRtl)()&&(t=(0,c.getLTRScrollLeftOffset)(s,t)),e<=0?s.scrollLeft=Math.round(t):(0,a.doAnimate)({onStep(t,e){s.scrollLeft=Math.round(e)},from:s.scrollLeft,to:Math.round(t),easing:h.easingFunc.easeInOutCubic,duration:e}))}render(){const{children:n,isVisibleScrollbar:a,isVisibleFade:h,isVisibleButtons:c,shouldMeasure:u,shouldDecreaseWidthContent:p,buttonsWidthIfDecreasedWidthContent:f,onMouseOver:w,onMouseOut:b,scrollWrapClassName:m,fadeClassName:v}=this.props,{isVisibleRightButton:R,isVisibleLeftButton:S}=this.state,_=p&&f;return i.createElement(o,{whitelist:["width"],onMeasure:this._handleResizeWrap,shouldMeasure:u,ref:this._wrapMeasureRef},i.createElement("div",{className:d.wrapOverflow,onMouseOver:w,onMouseOut:b},i.createElement("div",{className:r(d.wrap,_?d.wrapWithArrowsOuting:"")},i.createElement("div",{className:r(d.scrollWrap,m,{[d.noScrollBar]:!a}),onScroll:this._handleScroll,ref:this._scroll},i.createElement(o,{onMeasure:this._handleResizeContent,whitelist:["width"],shouldMeasure:u,ref:this._contentMeasureRef},n)),h&&i.createElement(s,{isVisible:S,className:v}),h&&i.createElement(l,{isVisible:R,className:v}),c&&i.createElement(t,{onClick:this._handleScrollLeft,isVisible:S}),c&&i.createElement(e,{onClick:this._handleScrollRight,isVisible:R}))))}_isOverflowed(){const{widthContent:t,widthWrap:e}=this.state;return t>e}}).defaultProps=p,u}(b,m,f,w)},38508:t=>{t.exports='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 10" width="20" height="10"><path fill="none" stroke="currentColor" stroke-width="1.5" d="M2 1l8 8 8-8"/></svg>'}}]);
|
|
@ -0,0 +1 @@
|
|||
.dialog-23lGwisF{min-width:254px;padding:40px;width:auto}.dialogInner-23lGwisF{align-items:center;display:flex;flex-direction:column}.titleWrapper-23lGwisF{align-items:center;display:flex;justify-content:center;margin-bottom:16px;max-width:100%}.title-23lGwisF{color:#131722;cursor:default;font-size:20px;font-weight:700;line-height:28px;overflow:hidden;white-space:nowrap}html.theme-dark .title-23lGwisF{color:#b2b5be}.infoHint-23lGwisF{color:#787b86;height:18px;margin-left:8px;width:18px}.form-23lGwisF{display:flex;max-width:200px;width:100%}.inputWrapper-23lGwisF{flex-grow:1}.input-23lGwisF{font-size:24px;text-align:center}.hint-23lGwisF{color:#787b86;cursor:default;font-size:12px;line-height:18px;margin-top:3px;max-width:100%;overflow:hidden;white-space:nowrap}.error-23lGwisF{color:#f23645}
|
|
@ -0,0 +1 @@
|
|||
.dialog-23lGwisF{min-width:254px;padding:40px;width:auto}.dialogInner-23lGwisF{align-items:center;display:flex;flex-direction:column}.titleWrapper-23lGwisF{align-items:center;display:flex;justify-content:center;margin-bottom:16px;max-width:100%}.title-23lGwisF{color:#131722;cursor:default;font-size:20px;font-weight:700;line-height:28px;overflow:hidden;white-space:nowrap}html.theme-dark .title-23lGwisF{color:#b2b5be}.infoHint-23lGwisF{color:#787b86;height:18px;margin-right:8px;width:18px}.form-23lGwisF{display:flex;max-width:200px;width:100%}.inputWrapper-23lGwisF{flex-grow:1}.input-23lGwisF{font-size:24px;text-align:center}.hint-23lGwisF{color:#787b86;cursor:default;font-size:12px;line-height:18px;margin-top:3px;max-width:100%;overflow:hidden;white-space:nowrap}.error-23lGwisF{color:#f23645}
|
|
@ -0,0 +1 @@
|
|||
.button-14c_DKWJ{align-items:center;background-color:initial;border:none;border-radius:2px;box-sizing:border-box;cursor:default;display:flex;flex:none;height:100%;justify-content:center;margin:0;outline:none!important;padding:0;width:21px}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#f0f3fa}html.theme-dark .button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#363a45}}.button-14c_DKWJ.hidden-14c_DKWJ{display:none}.icon-14c_DKWJ{align-items:center;display:flex;flex:none;justify-content:center;transition:transform .35s ease}.icon-14c_DKWJ.dropped-14c_DKWJ{transform:rotate(180deg)}.button-1WqyvKNY{cursor:default;-webkit-user-select:none;user-select:none}.button-children-1WqyvKNY{display:block;overflow:hidden;padding:0 2px 0 6px;text-overflow:ellipsis;white-space:nowrap;width:100%}.button-children-1WqyvKNY.hiddenArrow-1WqyvKNY{padding-right:6px}.invisibleFocusHandler-1WqyvKNY{height:0;opacity:0;pointer-events:none;width:0}.placeholder-1J6emFeA{-webkit-text-fill-color:currentColor;color:#a3a6af;opacity:1}html.theme-dark .placeholder-1J6emFeA{color:#434651}
|
|
@ -0,0 +1 @@
|
|||
.button-14c_DKWJ{align-items:center;background-color:initial;border:none;border-radius:2px;box-sizing:border-box;cursor:default;display:flex;flex:none;height:100%;justify-content:center;margin:0;outline:none!important;padding:0;width:21px}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#f0f3fa}html.theme-dark .button-14c_DKWJ:hover:not(.disabled-14c_DKWJ){background-color:#363a45}}.button-14c_DKWJ.hidden-14c_DKWJ{display:none}.icon-14c_DKWJ{align-items:center;display:flex;flex:none;justify-content:center;transition:transform .35s ease}.icon-14c_DKWJ.dropped-14c_DKWJ{transform:rotate(-180deg)}.button-1WqyvKNY{cursor:default;-webkit-user-select:none;user-select:none}.button-children-1WqyvKNY{display:block;overflow:hidden;padding:0 6px 0 2px;text-overflow:ellipsis;white-space:nowrap;width:100%}.button-children-1WqyvKNY.hiddenArrow-1WqyvKNY{padding-left:6px}.invisibleFocusHandler-1WqyvKNY{height:0;opacity:0;pointer-events:none;width:0}.placeholder-1J6emFeA{-webkit-text-fill-color:currentColor;color:#a3a6af;opacity:1}html.theme-dark .placeholder-1J6emFeA{color:#434651}
|
|
@ -0,0 +1 @@
|
|||
.wrapper-DggvOZTm{display:flex;flex:1 1 auto;height:100%;overflow:hidden}.container-DggvOZTm{-webkit-overflow-scrolling:touch;border-right:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex:none;flex-direction:column;min-height:145px;overflow-x:hidden;overflow-y:auto;padding-bottom:6px;padding-top:6px;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:200px}html.theme-dark .container-DggvOZTm{border-right:1px solid #434651;scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.container-DggvOZTm{min-height:auto}}.container-DggvOZTm::-webkit-scrollbar{height:5px;width:5px}.container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.container-DggvOZTm::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.container-DggvOZTm::-webkit-scrollbar-corner{display:none}.tab-DggvOZTm{align-items:center;color:#131722;display:flex;padding:6px 0 6px 20px}html.theme-dark .tab-DggvOZTm{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.tab-DggvOZTm:hover{background-color:#f0f3fa}html.theme-dark .tab-DggvOZTm:hover{background-color:#2a2e39}}.tab-DggvOZTm.active-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm{background-color:#2962ff}.tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,.tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#fff}html.theme-dark .tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#d1d4dc}.icon-DggvOZTm{height:28px;width:28px}.title-DggvOZTm{cursor:default;display:flex;font-size:14px;margin-left:8px;min-width:0;white-space:nowrap}.titleText-DggvOZTm{flex:0 100%;min-width:0;overflow:hidden;text-overflow:ellipsis}.nested-DggvOZTm{align-items:center;color:#787b86;display:flex;flex:1 1 auto;height:0;justify-content:flex-end;padding-right:8px}.isTablet-DggvOZTm.container-DggvOZTm{width:48px}.isTablet-DggvOZTm.tab-DggvOZTm{justify-content:center;padding-left:0}.isMobile-DggvOZTm.container-DggvOZTm{width:100%}.isMobile-DggvOZTm.tab-DggvOZTm{justify-content:flex-start;padding:0 0 0 20px}.isMobile-DggvOZTm.tab-DggvOZTm:last-child .title-DggvOZTm{border-bottom-width:0}.isMobile-DggvOZTm .title-DggvOZTm{align-items:center;border-bottom:1px solid #e0e3eb;display:flex;flex:1 1 auto;font-size:18px;padding-bottom:17px;padding-top:17px}html.theme-dark .isMobile-DggvOZTm .title-DggvOZTm{border-bottom-color:#434651}
|
|
@ -0,0 +1 @@
|
|||
.wrapper-DggvOZTm{display:flex;flex:1 1 auto;height:100%;overflow:hidden}.container-DggvOZTm{-webkit-overflow-scrolling:touch;border-left:1px solid #e0e3eb;display:flex;flex:1 1 auto;flex:none;flex-direction:column;min-height:145px;overflow-x:hidden;overflow-y:auto;padding-bottom:6px;padding-top:6px;scrollbar-color:#9598a1 #0000;scrollbar-width:thin;width:200px}html.theme-dark .container-DggvOZTm{border-left:1px solid #434651;scrollbar-color:#363a45 #0000}@media screen and (max-height:290px){.container-DggvOZTm{min-height:auto}}.container-DggvOZTm::-webkit-scrollbar{height:5px;width:5px}.container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#9598a1;border:1px solid #f0f3fa;border-radius:3px}html.theme-dark .container-DggvOZTm::-webkit-scrollbar-thumb{background-color:#363a45;border-color:#1e222d}.container-DggvOZTm::-webkit-scrollbar-track{background-color:initial;border-radius:3px}.container-DggvOZTm::-webkit-scrollbar-corner{display:none}.tab-DggvOZTm{align-items:center;color:#131722;display:flex;padding:6px 20px 6px 0}html.theme-dark .tab-DggvOZTm{color:#b2b5be}@media (any-hover:hover),(min--moz-device-pixel-ratio:0){.tab-DggvOZTm:hover{background-color:#f0f3fa}html.theme-dark .tab-DggvOZTm:hover{background-color:#2a2e39}}.tab-DggvOZTm.active-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm{background-color:#2962ff}.tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,.tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#fff}html.theme-dark .tab-DggvOZTm.active-DggvOZTm .icon-DggvOZTm,html.theme-dark .tab-DggvOZTm.active-DggvOZTm .title-DggvOZTm{color:#d1d4dc}.icon-DggvOZTm{height:28px;width:28px}.title-DggvOZTm{cursor:default;display:flex;font-size:14px;margin-right:8px;min-width:0;white-space:nowrap}.titleText-DggvOZTm{flex:0 100%;min-width:0;overflow:hidden;text-overflow:ellipsis}.nested-DggvOZTm{align-items:center;color:#787b86;display:flex;flex:1 1 auto;height:0;justify-content:flex-end;padding-left:8px}.nested-DggvOZTm svg{transform:rotate(180deg)}.isTablet-DggvOZTm.container-DggvOZTm{width:48px}.isTablet-DggvOZTm.tab-DggvOZTm{justify-content:center;padding-right:0}.isMobile-DggvOZTm.container-DggvOZTm{width:100%}.isMobile-DggvOZTm.tab-DggvOZTm{justify-content:flex-start;padding:0 20px 0 0}.isMobile-DggvOZTm.tab-DggvOZTm:last-child .title-DggvOZTm{border-bottom-width:0}.isMobile-DggvOZTm .title-DggvOZTm{align-items:center;border-bottom:1px solid #e0e3eb;display:flex;flex:1 1 auto;font-size:18px;padding-bottom:17px;padding-top:17px}html.theme-dark .isMobile-DggvOZTm .title-DggvOZTm{border-bottom-color:#434651}
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[306],{49775:(e,t,n)=>{n.d(t,{Icon:()=>i});var o=n(67294);const i=o.forwardRef((e,t)=>{const{icon:n="",...i}=e;return o.createElement("span",{...i,ref:t,dangerouslySetInnerHTML:{__html:n}})})},75761:(e,t,n)=>{n.d(t,{setFixedBodyState:()=>a});const o=(()=>{let e;return()=>{var t;if(void 0===e){const n=document.createElement("div"),o=n.style;o.visibility="hidden",o.width="100px",o.msOverflowStyle="scrollbar",document.body.appendChild(n);const i=n.offsetWidth;n.style.overflow="scroll";const s=document.createElement("div");s.style.width="100%",n.appendChild(s);const r=s.offsetWidth;null===(t=n.parentNode)||void 0===t||t.removeChild(n),e=i-r}return e}})();function i(e,t,n){null!==e&&e.style.setProperty(t,n)}function s(e,t){return getComputedStyle(e,null).getPropertyValue(t)}function r(e,t){return parseInt(s(e,t))}let d=0,l=!1;function a(e){const{body:t}=document,n=t.querySelector(".widgetbar-wrap");if(e&&1==++d){const e=s(t,"overflow"),d=r(t,"padding-right");"hidden"!==e.toLowerCase()&&t.scrollHeight>t.offsetHeight&&(i(n,"right",o()+"px"),t.style.paddingRight=d+o()+"px",l=!0),t.classList.add("i-no-scroll")}else if(!e&&d>0&&0==--d&&(t.classList.remove("i-no-scroll"),l)){i(n,"right","0px");let e=0;0,t.scrollHeight<=t.clientHeight&&(e-=o()),t.style.paddingRight=(e<0?0:e)+"px",l=!1}}},47165:(e,t,n)=>{n.d(t,{useOutsideEvent:()=>s});var o=n(67294),i=n(59726);function s(e){const{click:t,mouseDown:n,touchEnd:s,touchStart:r,handler:d,reference:l,ownerDocument:a=document}=e,c=(0,o.useRef)(null),h=(0,o.useRef)(new CustomEvent("timestamp").timeStamp);return(0,o.useLayoutEffect)(()=>{const e={click:t,mouseDown:n,touchEnd:s,touchStart:r},o=l?l.current:c.current;return(0,i.addOutsideEventListener)(h.current,o,d,a,e)},[t,n,s,r,d]),l||c}},90071:(e,t,n)=>{n.d(t,{OverlapManager:()=>s,getRootOverlapManager:()=>d});var o=n(16282);class i{constructor(){this._storage=[]}add(e){this._storage.push(e)}remove(e){this._storage=this._storage.filter(t=>e!==t)}has(e){return this._storage.includes(e)}getItems(){return this._storage}}class s{constructor(e=document){this._storage=new i,this._windows=new Map,this._index=0,this._document=e,this._container=e.createDocumentFragment()}setContainer(e){const t=this._container,n=null===e?this._document.createDocumentFragment():e;!function(e,t){Array.from(e.childNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&t.appendChild(e)})}(t,n),this._container=n}registerWindow(e){this._storage.has(e)||this._storage.add(e)}ensureWindow(e,t={position:"fixed",direction:"normal"}){const n=this._windows.get(e);if(void 0!==n)return n;this.registerWindow(e);const o=this._document.createElement("div");if(o.style.position=t.position,o.style.zIndex=this._index.toString(),o.dataset.id=e,void 0!==t.index){const e=this._container.childNodes.length;if(t.index>=e)this._container.appendChild(o);else if(t.index<=0)this._container.insertBefore(o,this._container.firstChild);else{const e=this._container.childNodes[t.index];this._container.insertBefore(o,e)}
|
||||
}else"reverse"===t.direction?this._container.insertBefore(o,this._container.firstChild):this._container.appendChild(o);return this._windows.set(e,o),++this._index,o}unregisterWindow(e){this._storage.remove(e);const t=this._windows.get(e);void 0!==t&&(null!==t.parentElement&&t.parentElement.removeChild(t),this._windows.delete(e))}getZindex(e){const t=this.ensureWindow(e);return parseInt(t.style.zIndex||"0")}moveToTop(e){if(this.getZindex(e)!==this._index){this.ensureWindow(e).style.zIndex=(++this._index).toString()}}removeWindow(e){this.unregisterWindow(e)}}const r=new WeakMap;function d(e=document){const t=e.getElementById("overlap-manager-root");if(null!==t)return(0,o.ensureDefined)(r.get(t));{const t=new s(e),n=function(e){const t=e.createElement("div");return t.style.position="absolute",t.style.zIndex=150..toString(),t.style.top="0px",t.style.left="0px",t.id="overlap-manager-root",t}(e);return r.set(n,t),t.setContainer(n),e.body.appendChild(n),t}}},4735:(e,t,n)=>{n.d(t,{Portal:()=>l,PortalContext:()=>a});var o=n(67294),i=n(73935),s=n(45259),r=n(90071),d=n(78106);class l extends o.PureComponent{constructor(){super(...arguments),this._uuid=(0,s.guid)()}componentWillUnmount(){this._manager().removeWindow(this._uuid)}render(){const e=this._manager().ensureWindow(this._uuid,this.props.layerOptions);return e.style.top=this.props.top||"",e.style.bottom=this.props.bottom||"",e.style.left=this.props.left||"",e.style.right=this.props.right||"",e.style.pointerEvents=this.props.pointerEvents||"",i.createPortal(o.createElement(a.Provider,{value:this},this.props.children),e)}moveToTop(){this._manager().moveToTop(this._uuid)}_manager(){return null===this.context?(0,r.getRootOverlapManager)():this.context}}l.contextType=d.SlotContext;const a=o.createContext(null)},78106:(e,t,n)=>{n.d(t,{Slot:()=>i,SlotContext:()=>s});var o=n(67294);class i extends o.Component{shouldComponentUpdate(){return!1}render(){return o.createElement("div",{style:{position:"fixed",zIndex:150,left:0,top:0},ref:this.props.reference})}}const s=o.createContext(null)}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,3 @@
|
|||
(self.webpackChunktradingview=self.webpackChunktradingview||[]).push([[3463],{67891:function(e,t){var o,n,r;n=[t],void 0===(r="function"==typeof(o=function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,o=Array(e.length);t<e.length;t++)o[t]=e[t];return o}return Array.from(e)}Object.defineProperty(e,"__esModule",{value:!0});var o=!1;if("undefined"!=typeof window){var n={get passive(){o=!0}};window.addEventListener("testPassive",null,n),window.removeEventListener("testPassive",null,n)}var r="undefined"!=typeof window&&window.navigator&&window.navigator.platform&&/iP(ad|hone|od)/.test(window.navigator.platform),l=[],i=!1,c=-1,a=void 0,s=void 0,u=function(e){return l.some((function(t){return!(!t.options.allowTouchMove||!t.options.allowTouchMove(e))}))},d=function(e){var t=e||window.event;return!!u(t.target)||1<t.touches.length||(t.preventDefault&&t.preventDefault(),!1)},v=function(){setTimeout((function(){void 0!==s&&(document.body.style.paddingRight=s,s=void 0),void 0!==a&&(document.body.style.overflow=a,a=void 0)}))};e.disableBodyScroll=function(e,n){if(r){if(!e)return void console.error("disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.");if(e&&!l.some((function(t){return t.targetElement===e}))){var v={targetElement:e,options:n||{}};l=[].concat(t(l),[v]),e.ontouchstart=function(e){1===e.targetTouches.length&&(c=e.targetTouches[0].clientY)},e.ontouchmove=function(t){var o,n,r,l;1===t.targetTouches.length&&(n=e,l=(o=t).targetTouches[0].clientY-c,!u(o.target)&&(n&&0===n.scrollTop&&0<l||(r=n)&&r.scrollHeight-r.scrollTop<=r.clientHeight&&l<0?d(o):o.stopPropagation()))},i||(document.addEventListener("touchmove",d,o?{passive:!1}:void 0),i=!0)}}else{m=n,setTimeout((function(){if(void 0===s){var e=!!m&&!0===m.reserveScrollBarGap,t=window.innerWidth-document.documentElement.clientWidth;e&&0<t&&(s=document.body.style.paddingRight,document.body.style.paddingRight=t+"px")}void 0===a&&(a=document.body.style.overflow,document.body.style.overflow="hidden")}));var f={targetElement:e,options:n||{}};l=[].concat(t(l),[f])}var m},e.clearAllBodyScrollLocks=function(){r?(l.forEach((function(e){e.targetElement.ontouchstart=null,e.targetElement.ontouchmove=null})),i&&(document.removeEventListener("touchmove",d,o?{passive:!1}:void 0),i=!1),l=[],c=-1):(v(),l=[])},e.enableBodyScroll=function(e){if(r){if(!e)return void console.error("enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.");e.ontouchstart=null,e.ontouchmove=null,l=l.filter((function(t){return t.targetElement!==e})),i&&0===l.length&&(document.removeEventListener("touchmove",d,o?{passive:!1}:void 0),i=!1)}else 1===l.length&&l[0].targetElement===e?(v(),l=[]):l=l.filter((function(t){return t.targetElement!==e}))}})?o.apply(t,n):o)||(e.exports=r)},32550:e=>{e.exports={item:"item-21ifTYt7",label:"label-21ifTYt7",labelRow:"labelRow-21ifTYt7",toolbox:"toolbox-21ifTYt7"}},66549:e=>{e.exports={"tablet-small-breakpoint":"screen and (max-width: 428px)",
|
||||
item:"item-2IihgTnv",hovered:"hovered-2IihgTnv",isDisabled:"isDisabled-2IihgTnv",isActive:"isActive-2IihgTnv",shortcut:"shortcut-2IihgTnv",toolbox:"toolbox-2IihgTnv",withIcon:"withIcon-2IihgTnv",icon:"icon-2IihgTnv",labelRow:"labelRow-2IihgTnv",label:"label-2IihgTnv",showOnHover:"showOnHover-2IihgTnv"}},78706:e=>{e.exports={separator:"separator-eqcGT_ow",small:"small-eqcGT_ow",normal:"normal-eqcGT_ow",large:"large-eqcGT_ow"}},53178:(e,t,o)=>{"use strict";o.d(t,{validateRegistry:()=>c,RegistryProvider:()=>a,registryContextType:()=>s});var n=o(67294),r=o(45697),l=o.n(r);const i=n.createContext({});function c(e,t){l().checkPropTypes(t,e,"context","RegistryContext")}function a(e){const{validation:t,value:o}=e;return c(o,t),n.createElement(i.Provider,{value:o},e.children)}function s(){return i}},11086:(e,t,o)=>{"use strict";o.d(t,{hoverMouseEventFilter:()=>l,useAccurateHover:()=>i,useHover:()=>r});var n=o(67294);function r(){const[e,t]=(0,n.useState)(!1);return[e,{onMouseOver:function(e){l(e)&&t(!0)},onMouseOut:function(e){l(e)&&t(!1)}}]}function l(e){return!e.currentTarget.contains(e.relatedTarget)}function i(e){const[t,o]=(0,n.useState)(!1);return(0,n.useEffect)(()=>{const t=t=>{if(null===e.current)return;const n=e.current.contains(t.target);o(n)};return document.addEventListener("mouseover",t),()=>document.removeEventListener("mouseover",t)},[]),t}},95860:(e,t,o)=>{"use strict";o.d(t,{DEFAULT_POPUP_MENU_ITEM_THEME:()=>s,PopupMenuItem:()=>v});var n=o(67294),r=o(94184),l=o(79424),i=o(87438),c=o(74818),a=o(66549);const s=a;function u(e){const{reference:t,...o}=e,r={...o,ref:t};return n.createElement(e.href?"a":"div",r)}function d(e){e.stopPropagation()}function v(e){const{id:t,role:o,"aria-selected":s,className:v,title:f,labelRowClassName:m,labelClassName:h,shortcut:g,forceShowShortcuts:p,icon:b,isActive:w,isDisabled:E,isHovered:T,appearAsDisabled:y,label:C,link:k,showToolboxOnHover:O,target:x,rel:M,toolbox:I,reference:S,onMouseOut:P,onMouseOver:N,suppressToolboxClick:A=!0,theme:R=a}=e,_=(0,c.filterDataProps)(e),D=(0,n.useRef)(null);return n.createElement(u,{..._,id:t,role:o,"aria-selected":s,className:r(v,R.item,b&&R.withIcon,{[R.isActive]:w,[R.isDisabled]:E||y,[R.hovered]:T}),title:f,href:k,target:x,rel:M,reference:function(e){D.current=e,"function"==typeof S&&S(e);"object"==typeof S&&(S.current=e)},onClick:function(t){const{dontClosePopup:o,onClick:n,onClickArg:r,trackEventObject:c}=e;if(E)return;c&&(0,i.trackEvent)(c.category,c.event,c.label);n&&n(r,t);o||(0,l.globalCloseMenu)()},onContextMenu:function(t){const{trackEventObject:o,trackRightClick:n}=e;o&&n&&(0,i.trackEvent)(o.category,o.event,o.label+"_rightClick")},onMouseUp:function(t){const{trackEventObject:o,trackMouseWheelClick:n}=e;if(1===t.button&&k&&o){let e=o.label;n&&(e+="_mouseWheelClick"),(0,i.trackEvent)(o.category,o.event,e)}},onMouseOver:N,onMouseOut:P},void 0!==b&&n.createElement("div",{className:R.icon,dangerouslySetInnerHTML:{__html:b}}),n.createElement("div",{className:r(R.labelRow,m)},n.createElement("div",{className:r(R.label,h)
|
||||
},C)),(void 0!==g||p)&&n.createElement("div",{className:R.shortcut},(H=g)&&H.split("+").join(" + ")),void 0!==I&&n.createElement("div",{onClick:A?d:void 0,className:r(R.toolbox,{[R.showOnHover]:O})},I));var H}},82879:(e,t,o)=>{"use strict";o.d(t,{multilineLabelWithIconAndToolboxTheme:()=>i});var n=o(4598),r=o(66549),l=o(32550);const i=(0,n.mergeThemes)(r,l)},10869:(e,t,o)=>{"use strict";o.d(t,{PopupMenuSeparator:()=>c});var n=o(67294),r=o(94184),l=o.n(r),i=o(78706);function c(e){const{size:t="normal",className:o}=e;return n.createElement("div",{className:l()(i.separator,"small"===t&&i.small,"normal"===t&&i.normal,"large"===t&&i.large,o)})}},76420:(e,t,o)=>{"use strict";o.d(t,{PopupMenu:()=>s});var n=o(67294),r=o(73935),l=o(4735),i=o(90901),c=o(94884),a=o(47165);function s(e){const{controller:t,children:o,isOpened:s,closeOnClickOutside:u=!0,doNotCloseOn:d,onClickOutside:v,onClose:f,...m}=e,h=(0,n.useContext)(c.CloseDelegateContext),g=(0,a.useOutsideEvent)({handler:function(e){v&&v(e);if(!u)return;if(d&&e.target instanceof Node){const t=r.findDOMNode(d);if(t instanceof Node&&t.contains(e.target))return}f()},mouseDown:!0,touchStart:!0});return s?n.createElement(l.Portal,{top:"0",left:"0",right:"0",bottom:"0",pointerEvents:"none"},n.createElement("span",{ref:g,style:{pointerEvents:"auto"}},n.createElement(i.Menu,{...m,onClose:f,onScroll:function(t){const{onScroll:o}=e;o&&o(t)},customCloseDelegate:h,ref:t},o))):null}}}]);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue