Morph summary (#763)
* fix: fixed mobile issues with SVGs * feat: first morphing AccountDetails * tidy: composition refresh * tidy: fine adjusting * fix: svg fixes * feat: updated summary structure * feat: overall layout adjustments * fix: fixed svg adjustments * feat: finished AccountSummary update * fix: fixed build * tidy: refactor * fix: fix enourmous APYs * fix: don’t abbreviate APYs * tidy: console.log * fix: fix borrow Rate sorting * fix: fixed scrollbars * fix: hide scrollbars * fix: resolved feedback * fix: amount not size * feat: only show credit account number outside of modals * fix: added missing Strategies to PortfolioAccount * fix: save some space
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mars-v2-frontend",
|
||||
"version": "2.2.1",
|
||||
"version": "2.2.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "yarn validate-env && next build",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import Modal from 'components/Modals/Modal'
|
||||
import CurrentAccountSummary from 'components/account/CurrentAccountSummary'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Button from 'components/common/Button'
|
||||
import Card from 'components/common/Card'
|
||||
import Divider from 'components/common/Divider'
|
||||
@ -10,6 +10,7 @@ import Text from 'components/common/Text'
|
||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { BN } from 'utils/helpers'
|
||||
@ -38,7 +39,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
} = props
|
||||
const [amount, setAmount] = useState(BN_ZERO)
|
||||
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
||||
|
||||
const account = useCurrentAccount()
|
||||
const handleAmountChange = useCallback(
|
||||
(value: BigNumber) => {
|
||||
setAmount(value)
|
||||
@ -51,6 +52,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
onAction(amount, amount.isEqualTo(maxAmount))
|
||||
}, [amount, maxAmount, onAction])
|
||||
|
||||
if (!account) return
|
||||
return (
|
||||
<Modal
|
||||
onClose={onClose}
|
||||
@ -87,7 +89,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<CurrentAccountSummary />
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -29,6 +29,7 @@ import { byDenom } from 'utils/array'
|
||||
import { formatPercent } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
@ -347,7 +348,7 @@ function BorrowModal(props: Props) {
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary account={account} />
|
||||
<AccountSummaryInModal account={account} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { ExclamationMarkTriangle } from 'components/common/Icons'
|
||||
@ -40,8 +39,10 @@ export function CollateralSubTitle(props: CollateralSubTitleProps) {
|
||||
if (!props.isOpen && props.amount.isZero()) {
|
||||
return (
|
||||
<div className='flex gap-2'>
|
||||
<ExclamationMarkTriangle width={24} className='text-warning' />
|
||||
<Text className='text-warning mt-1' size='xs' tag='span'>
|
||||
<div className='w-6'>
|
||||
<ExclamationMarkTriangle className='text-warning' />
|
||||
</div>
|
||||
<Text className='mt-1 text-warning' size='xs' tag='span'>
|
||||
You have not provided any collateral.
|
||||
</Text>
|
||||
</div>
|
||||
@ -111,8 +112,10 @@ export function SelectAccountSubTitle(props: SelectAccountSubTitleProps) {
|
||||
if (!props.selectedAccountId && props.isSummaryOpen) {
|
||||
return (
|
||||
<div className='flex gap-2'>
|
||||
<ExclamationMarkTriangle width={24} className='text-warning' />
|
||||
<Text className='text-warning mt-1' size='xs' tag='span'>
|
||||
<div className='w-6'>
|
||||
<ExclamationMarkTriangle className='text-warning' />
|
||||
</div>
|
||||
<Text className='mt-1 text-warning' size='xs' tag='span'>
|
||||
You need to {props.type} an account
|
||||
</Text>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import AccountSummary from 'components/account/AccountSummary'
|
||||
import Card from 'components/common/Card'
|
||||
import { CircularProgress } from 'components/common/CircularProgress'
|
||||
import Modal, { ModalProps } from 'components/Modals/Modal'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
|
||||
interface Props extends ModalProps {
|
||||
isHls?: boolean
|
||||
@ -46,7 +46,7 @@ export default function ModalContentWithSummary(props: Props) {
|
||||
>
|
||||
{props.subHeader && props.subHeader}
|
||||
{modalContent(props.content, props.isContentCard, props.account)}
|
||||
{props.account && <AccountSummary account={props.account} isHls={props.isHls} />}
|
||||
{props.account && <AccountSummaryInModal account={props.account} isHls={props.isHls} />}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import Accordion from 'components/common/Accordion'
|
||||
import AccountSummary from 'components/account/AccountSummary'
|
||||
import VaultBorrowings from 'components/Modals/Vault/VaultBorrowings'
|
||||
import VaultBorrowingsSubTitle from 'components/Modals/Vault/VaultBorrowingsSubTitle'
|
||||
import VaultDeposit from 'components/Modals/Vault/VaultDeposits'
|
||||
import VaultDepositSubTitle from 'components/Modals/Vault/VaultDepositsSubTitle'
|
||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||
import Accordion from 'components/common/Accordion'
|
||||
import Text from 'components/common/Text'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
@ -177,8 +177,7 @@ export default function VaultModalContent(props: Props) {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<AccountSummary account={props.account} />
|
||||
<AccountSummaryInModal account={props.account} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export default function WalletConnectButton(props: Props) {
|
||||
return (
|
||||
<Button
|
||||
variant={props.variant ?? 'solid'}
|
||||
color={props.color ?? 'tertiary'}
|
||||
color={props.color ?? 'secondary'}
|
||||
size={props.size ?? 'sm'}
|
||||
disabled={props.disabled}
|
||||
onClick={handleClick}
|
||||
|
@ -144,7 +144,7 @@ export default function WalletConnectedButton() {
|
||||
<Button
|
||||
variant='solid'
|
||||
leftIcon={<Wallet />}
|
||||
color='tertiary'
|
||||
color='secondary'
|
||||
onClick={() => {
|
||||
setShowDetails(!showDetails)
|
||||
}}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import AssetRate from 'components/common/assets/AssetRate'
|
||||
|
||||
export const APY_META = { accessorKey: 'apy', header: 'APY', meta: { className: 'w-30' } }
|
||||
@ -12,13 +14,18 @@ interface Props {
|
||||
export default function Apr(props: Props) {
|
||||
const { markets, type, denom, apy } = props
|
||||
|
||||
if (apy === 0) return <p className='w-full text-xs text-right number'>–</p>
|
||||
if (apy === 0)
|
||||
return (
|
||||
<p className={classNames('w-full text-xs text-right number', type === 'vault' && 'pb-4')}>
|
||||
–
|
||||
</p>
|
||||
)
|
||||
const isEnabled =
|
||||
markets.find((market) => market.asset.denom === props.denom)?.borrowEnabled ?? false
|
||||
|
||||
return (
|
||||
<AssetRate
|
||||
className='justify-end text-xs'
|
||||
className={classNames('justify-end text-xs', type === 'vault' && 'pb-4')}
|
||||
rate={apy}
|
||||
isEnabled={type !== 'lend' || isEnabled}
|
||||
type='apy'
|
||||
|
@ -1,5 +1,12 @@
|
||||
import Text from 'components/common/Text'
|
||||
export const ASSET_META = { accessorKey: 'symbol', header: 'Asset', id: 'symbol' }
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
export const ASSET_META = {
|
||||
accessorKey: 'symbol',
|
||||
header: 'Asset',
|
||||
id: 'symbol',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
symbol: string
|
||||
@ -8,12 +15,18 @@ interface Props {
|
||||
|
||||
export default function Asset(props: Props) {
|
||||
const { symbol, type } = props
|
||||
const assets = useAllAssets()
|
||||
const asset = assets.find((asset) => asset.symbol === symbol) ?? assets[0]
|
||||
|
||||
return (
|
||||
<Text size='xs'>
|
||||
{symbol}
|
||||
<div className='flex gap-2'>
|
||||
<AssetImage asset={asset} size={16} className='w-4 h-4' />
|
||||
<Text size='xs' className='text-white'>
|
||||
{asset.symbol}
|
||||
{type === 'borrow' && <span className='ml-1 text-loss'>(debt)</span>}
|
||||
{type === 'lend' && <span className='ml-1 text-profit'>(lent)</span>}
|
||||
{type === 'vault' && <span className='ml-1 text-profit'>(farm)</span>}
|
||||
</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { demagnify, getCoinValue } from 'utils/formatters'
|
||||
|
||||
@ -26,37 +25,6 @@ export function getAssetAccountBalanceRow(
|
||||
}
|
||||
}
|
||||
|
||||
export function getVaultAccountBalanceRow(
|
||||
vault: DepositedVault,
|
||||
apy: number,
|
||||
prev?: DepositedVault,
|
||||
): AccountBalanceRow {
|
||||
const { name } = vault
|
||||
const previous = prev || vault
|
||||
const totalLockedValue = vault.values.primary.plus(vault.values.secondary)
|
||||
const totalValue = totalLockedValue.plus(vault.values.unlocked).plus(vault.values.unlocking)
|
||||
const prevTotalValue = previous.values.primary
|
||||
.plus(previous.values.secondary)
|
||||
.plus(previous.values.unlocked)
|
||||
.plus(previous.values.unlocking)
|
||||
const amountChange = !prev ? totalValue : totalValue.minus(prevTotalValue)
|
||||
|
||||
if (totalLockedValue.isLessThan(totalValue)) {
|
||||
apy = totalLockedValue.dividedBy(totalValue).times(apy).toNumber()
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'vault',
|
||||
symbol: name,
|
||||
size: 0,
|
||||
value: totalValue.toString(),
|
||||
denom: vault.denoms.lp,
|
||||
amount: BN_ZERO,
|
||||
apy,
|
||||
amountChange,
|
||||
}
|
||||
}
|
||||
|
||||
export function getAmountChangeColor(type: PositionType, amount: BigNumber) {
|
||||
if (type === 'borrow') {
|
||||
if (amount.isGreaterThan(0)) return 'text-loss'
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import {
|
||||
getAssetAccountBalanceRow,
|
||||
getVaultAccountBalanceRow,
|
||||
} from 'components/account/AccountBalancesTable/functions'
|
||||
import { getAssetAccountBalanceRow } from 'components/account/AccountBalancesTable/functions'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
@ -54,14 +51,6 @@ export default function useAccountBalanceData(props: Props) {
|
||||
return getAssetAccountBalanceRow('lend', asset, prices, assets, lending, apy, prevLending)
|
||||
})
|
||||
|
||||
const vaults = accountVaults.map((vault) => {
|
||||
const apy = vault.apy ?? 0
|
||||
const prevVault = updatedAccount
|
||||
? account?.vaults.find((position) => position.name === vault.name)
|
||||
: vault
|
||||
return getVaultAccountBalanceRow(vault, apy, prevVault)
|
||||
})
|
||||
|
||||
const debts = accountDebts.map((debt) => {
|
||||
const asset = assets.find(byDenom(debt.denom)) ?? assets[0]
|
||||
const apy = borrowingData.find((market) => market.asset.denom === debt.denom)?.apy.borrow ?? 0
|
||||
@ -70,7 +59,7 @@ export default function useAccountBalanceData(props: Props) {
|
||||
: debt
|
||||
return getAssetAccountBalanceRow('borrow', asset, prices, assets, debt, apy, prevDebt)
|
||||
})
|
||||
return [...deposits, ...lends, ...vaults, ...debts]
|
||||
return [...deposits, ...lends, ...debts]
|
||||
}, [
|
||||
updatedAccount,
|
||||
account,
|
||||
|
@ -15,11 +15,7 @@ import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import {
|
||||
calculateAccountApr,
|
||||
calculateAccountBalanceValue,
|
||||
getAccountPositionValues,
|
||||
} from 'utils/accounts'
|
||||
import { calculateAccountApr, getAccountPositionValues } from 'utils/accounts'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
@ -70,15 +66,6 @@ export default function AccountComposition(props: Props) {
|
||||
return [updatedPositionValue, updatedDebtsBalance]
|
||||
}, [updatedAccount, prices, assets])
|
||||
|
||||
const netWorth = useMemo(
|
||||
() => calculateAccountBalanceValue(account, prices, assets),
|
||||
[account, assets, prices],
|
||||
)
|
||||
const updatedTotalBalance = useMemo(
|
||||
() => (updatedAccount ? calculateAccountBalanceValue(updatedAccount, prices, assets) : BN_ZERO),
|
||||
[updatedAccount, prices, assets],
|
||||
)
|
||||
|
||||
const apr = useMemo(
|
||||
() =>
|
||||
calculateAccountApr(
|
||||
@ -131,17 +118,11 @@ export default function AccountComposition(props: Props) {
|
||||
className='pb-3'
|
||||
isDecrease
|
||||
/>
|
||||
<Item
|
||||
title='Net worth'
|
||||
current={netWorth}
|
||||
change={hasChanged ? updatedTotalBalance : netWorth}
|
||||
className='py-3 font-bold border border-transparent border-y-white/20'
|
||||
/>
|
||||
<Item
|
||||
title='APR'
|
||||
current={apr}
|
||||
change={hasChanged ? updatedApr : apr}
|
||||
className='py-3'
|
||||
className='pb-3'
|
||||
isPercentage
|
||||
/>
|
||||
</div>
|
||||
@ -167,6 +148,7 @@ function Item(props: ItemProps) {
|
||||
suffix: '%',
|
||||
minDecimals: 2,
|
||||
maxDecimals: current.abs().isLessThan(0.1) ? MAX_AMOUNT_DECIMALS : 2,
|
||||
abbreviated: false,
|
||||
}}
|
||||
className='text-sm'
|
||||
animate
|
||||
@ -175,6 +157,7 @@ function Item(props: ItemProps) {
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, current)}
|
||||
className='text-sm'
|
||||
options={{ abbreviated: false }}
|
||||
/>
|
||||
)}
|
||||
{current.toFixed(2) !== change.toFixed(2) && (
|
||||
@ -197,6 +180,7 @@ function Item(props: ItemProps) {
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, change)}
|
||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||
options={{ abbreviated: false }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,54 +0,0 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
|
||||
interface Props {
|
||||
leverage: number
|
||||
updatedLeverage: number | null
|
||||
}
|
||||
|
||||
export default function AccountDetailsLeverage(props: Props) {
|
||||
const { leverage, updatedLeverage } = props
|
||||
|
||||
if (!updatedLeverage) {
|
||||
return (
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={isNaN(leverage) ? 0 : leverage}
|
||||
options={{
|
||||
maxDecimals: 2,
|
||||
minDecimals: 2,
|
||||
suffix: 'x',
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={isNaN(leverage) ? 1 : leverage}
|
||||
options={{
|
||||
maxDecimals: 1,
|
||||
minDecimals: 1,
|
||||
rounded: true,
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
<ArrowRight width={12} />
|
||||
<FormattedNumber
|
||||
className={classNames(
|
||||
'w-full text-center text-2xs',
|
||||
updatedLeverage > leverage && 'text-loss',
|
||||
updatedLeverage < leverage && 'text-profit',
|
||||
)}
|
||||
amount={isNaN(updatedLeverage) ? 0 : updatedLeverage}
|
||||
options={{ maxDecimals: 1, minDecimals: 1, rounded: true }}
|
||||
animate
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,17 +1,13 @@
|
||||
import classNames from 'classnames'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
import AccountBalancesTable from 'components/account/AccountBalancesTable'
|
||||
import AccountComposition from 'components/account/AccountComposition'
|
||||
import AccountDetailsLeverage from 'components/account/AccountDetails/AccountDetailsLeverage'
|
||||
import Skeleton from 'components/account/AccountDetails/Skeleton'
|
||||
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
|
||||
import AccountSummary from 'components/account/AccountSummary'
|
||||
import AccountSummaryLeverage from 'components/account/AccountSummary/AccountSummaryLeverage'
|
||||
import { HealthGauge } from 'components/account/Health/HealthGauge'
|
||||
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
|
||||
import EscButton from 'components/common/Button/EscButton'
|
||||
import { glowElement } from 'components/common/Button/utils'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ThreeDots } from 'components/common/Icons'
|
||||
@ -26,8 +22,8 @@ import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
@ -40,7 +36,7 @@ import {
|
||||
export default function AccountDetailsController() {
|
||||
const address = useStore((s) => s.address)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const { data: accounts, isLoading } = useAccounts('default', address)
|
||||
const { data: _, isLoading } = useAccounts('default', address)
|
||||
const { data: accountIds } = useAccountIds(address, false, true)
|
||||
const accountId = useAccountId()
|
||||
|
||||
@ -120,19 +116,6 @@ function AccountDetails(props: Props) {
|
||||
location.pathname === '/' ||
|
||||
location.pathname.includes('perps')
|
||||
|
||||
function AccountDetailsHeader() {
|
||||
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-between w-full p-4 bg-white/10 '>
|
||||
<Text size='lg' className='flex items-center flex-grow font-semibold'>
|
||||
{`Credit Account ${account.id}`}
|
||||
</Text>
|
||||
<EscButton onClick={onClose} hideText className='w-6 h-6' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isFullWidth && accountDetailsExpanded && (
|
||||
@ -144,20 +127,33 @@ function AccountDetails(props: Props) {
|
||||
<div
|
||||
data-testid='account-details'
|
||||
className={classNames(
|
||||
accountDetailsExpanded ? 'right-4' : '-right-90',
|
||||
'w-110 flex items-start gap-4 absolute top-6',
|
||||
!reduceMotion && 'transition-all duration-300',
|
||||
accountDetailsExpanded ? 'right-4' : '-right-74',
|
||||
'w-94 flex items-start gap-4 absolute top-6',
|
||||
!reduceMotion && 'transition-all duration-500',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-wrap min-w-16 w-16 group/accountdetail relative',
|
||||
'group/accountdetail relative min-h-75',
|
||||
'border rounded-base border-white/20',
|
||||
'bg-white/5 backdrop-blur-sticky z-2',
|
||||
!reduceMotion && 'transition-colors duration-300',
|
||||
'hover:bg-white/10 hover:cursor-pointer ',
|
||||
'backdrop-blur-sticky z-2',
|
||||
!reduceMotion && 'transition-all duration-500',
|
||||
accountDetailsExpanded
|
||||
? 'is-expanded w-full h-auto'
|
||||
: 'w-16 hover:bg-white/10 hover:cursor-pointer bg-white/5',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (accountDetailsExpanded) return
|
||||
useStore.setState({ accountDetailsExpanded: true })
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'w-16 pr-[1px]',
|
||||
accountDetailsExpanded
|
||||
? 'opacity-0 absolute inset-0 -z-1'
|
||||
: 'transition-opacity opacity-100 duration-300 delay-200',
|
||||
)}
|
||||
onClick={() => useStore.setState({ accountDetailsExpanded: !accountDetailsExpanded })}
|
||||
>
|
||||
<div className='flex flex-wrap justify-center w-full py-4'>
|
||||
<HealthGauge
|
||||
@ -171,7 +167,10 @@ function AccountDetails(props: Props) {
|
||||
</Text>
|
||||
</div>
|
||||
<div className='w-full py-4 border-t border-white/20'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50 whitespace-nowrap'>
|
||||
<Text
|
||||
size='2xs'
|
||||
className='mb-0.5 w-full text-center text-white/50 whitespace-nowrap'
|
||||
>
|
||||
Net worth
|
||||
</Text>
|
||||
<DisplayCurrency coin={coin} className='w-full text-center truncate text-2xs ' />
|
||||
@ -180,7 +179,7 @@ function AccountDetails(props: Props) {
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Leverage
|
||||
</Text>
|
||||
<AccountDetailsLeverage
|
||||
<AccountSummaryLeverage
|
||||
leverage={leverage.toNumber() || 1}
|
||||
updatedLeverage={updatedLeverage?.toNumber() || null}
|
||||
/>
|
||||
@ -196,6 +195,20 @@ function AccountDetails(props: Props) {
|
||||
animate
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'grid',
|
||||
!reduceMotion && 'transition-[grid-template-rows,opacity]',
|
||||
accountDetailsExpanded
|
||||
? 'transition-[grid-template-rows,opacity] opacity-100 delay-500 duration-600 grid-rows-[1fr]'
|
||||
: 'transition-opacity opacity-0 duration-300 grid-rows-[0fr]',
|
||||
)}
|
||||
>
|
||||
<div className='overflow-hidden'>
|
||||
<AccountSummary account={account} isAccountDetails />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex justify-center items-center w-full h-6 opacity-50',
|
||||
@ -209,24 +222,6 @@ function AccountDetails(props: Props) {
|
||||
|
||||
{glowElement(!reduceMotion)}
|
||||
</div>
|
||||
<div className='flex w-90 backdrop-blur-sticky z-2'>
|
||||
<Card className='w-90 bg-white/5' title={<AccountDetailsHeader />}>
|
||||
<AccountComposition account={account} />
|
||||
<Text className='w-full px-4 py-2 text-white bg-white/10'>Balances</Text>
|
||||
<AccountBalancesTable
|
||||
account={account}
|
||||
borrowingData={borrowAssetsData}
|
||||
lendingData={lendingAssetsData}
|
||||
hideCard
|
||||
/>
|
||||
{account.perps.length > 0 && (
|
||||
<>
|
||||
<Text className='w-full px-4 py-2 text-white bg-white/10'>Perp Positions</Text>
|
||||
<AccountPerpPositionTable account={account} hideCard />
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
@ -46,12 +46,7 @@ export default function Skeleton(props: Props) {
|
||||
<Text size='xs' className='w-auto mr-1 text-white/70'>
|
||||
Health
|
||||
</Text>
|
||||
<HealthBar
|
||||
health={health}
|
||||
healthFactor={healthFactor}
|
||||
className='w-[92px] h-0.5'
|
||||
hasLabel
|
||||
/>
|
||||
<HealthBar health={health} healthFactor={healthFactor} className='w-[92px] h-0.5' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -103,7 +103,7 @@ export default function AccountMenuContent() {
|
||||
id={ACCOUNT_MENU_BUTTON_ID}
|
||||
onClick={handleCreateAccountClick}
|
||||
leftIcon={hasCreditAccounts ? <Account /> : <PlusCircled />}
|
||||
color={hasCreditAccounts ? 'tertiary' : 'primary'}
|
||||
color={hasCreditAccounts ? 'secondary' : 'primary'}
|
||||
hasFocus={showMenu}
|
||||
hasSubmenu={hasCreditAccounts}
|
||||
>
|
||||
|
@ -4,17 +4,28 @@ import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import AssetImage from 'components/common/assets/AssetImage'
|
||||
import TradeDirection from 'components/perps/BalancesTable/Columns/TradeDirection'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePerpsEnabledAssets from 'hooks/assets/usePerpsEnabledAssets'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { demagnify } from 'utils/formatters'
|
||||
export const ASSET_META = { accessorKey: 'symbol', header: 'Asset', id: 'symbol' }
|
||||
export const ASSET_META = {
|
||||
accessorKey: 'symbol',
|
||||
header: 'Asset',
|
||||
id: 'symbol',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
row: AccountPerpRow
|
||||
}
|
||||
|
||||
interface TooltipProps {
|
||||
row: AccountPerpRow
|
||||
asset: Asset
|
||||
}
|
||||
|
||||
function LabelAndValue(props: { label: string; children: ReactNode; className?: string }) {
|
||||
const { label, children } = props
|
||||
|
||||
@ -28,11 +39,8 @@ function LabelAndValue(props: { label: string; children: ReactNode; className?:
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipContent(props: Props) {
|
||||
const { row } = props
|
||||
const assets = usePerpsEnabledAssets()
|
||||
const asset = assets.find((asset) => asset.symbol === row.symbol)
|
||||
if (!asset) return null
|
||||
function TooltipContent(props: TooltipProps) {
|
||||
const { row, asset } = props
|
||||
|
||||
return (
|
||||
<div className='flex flex-col flex-wrap gap-1 w-50'>
|
||||
@ -58,10 +66,14 @@ function TooltipContent(props: Props) {
|
||||
|
||||
export default function Asset(props: Props) {
|
||||
const { row } = props
|
||||
const assets = usePerpsEnabledAssets()
|
||||
const asset = assets.find((asset) => asset.symbol === row.symbol)
|
||||
if (!asset) return null
|
||||
|
||||
return (
|
||||
<Tooltip content={<TooltipContent row={row} />} type='info'>
|
||||
<Text size='xs' className='flex items-center gap-1 no-wrap group/asset hover:cursor-help'>
|
||||
<Tooltip content={<TooltipContent row={row} asset={asset} />} type='info'>
|
||||
<Text size='xs' className='flex items-center gap-2 no-wrap group/asset hover:cursor-help'>
|
||||
<AssetImage asset={asset} size={16} className='w-4 h-4' />
|
||||
<span className='pb-[1px] border-b border-white/20 border-dashed group-hover/asset:border-transparent'>
|
||||
{row.symbol}
|
||||
</span>
|
||||
|
@ -0,0 +1,67 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { InfoCircle } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { Tooltip } from 'components/common/Tooltip'
|
||||
import useLiquidationPrice from 'hooks/useLiquidationPrice'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { LiquidationPriceKind } from 'utils/health_computer'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const LIQ_META = {
|
||||
accessorKey: 'symbol',
|
||||
header: 'Liquidation Price',
|
||||
id: 'liqPrice',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
amount: number
|
||||
computeLiquidationPrice: (denom: string, kind: LiquidationPriceKind) => number | null
|
||||
denom: string
|
||||
type: PositionType
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function LiqPrice(props: Props) {
|
||||
const { denom, type, amount, account, computeLiquidationPrice } = props
|
||||
const [lastLiquidationPrice, setLastLiquidationPrice] = useState<number | null>(null)
|
||||
const hasDebt = account.debts.length > 0
|
||||
|
||||
const liqPrice = useMemo(() => {
|
||||
if (type === 'vault' || amount === 0) return 0
|
||||
return computeLiquidationPrice(denom, type === 'borrow' ? 'debt' : 'asset')
|
||||
}, [amount, computeLiquidationPrice, denom, type])
|
||||
|
||||
const { liquidationPrice } = useLiquidationPrice(liqPrice)
|
||||
|
||||
useEffect(() => {
|
||||
if (lastLiquidationPrice !== liqPrice && liqPrice !== null) setLastLiquidationPrice(liqPrice)
|
||||
}, [liqPrice, lastLiquidationPrice])
|
||||
|
||||
const tooltipText = useMemo(() => {
|
||||
if (type === 'vault')
|
||||
return 'Liquidation prices cannot be calculated for farm positions. But it a drop in price of the underlying assets can still cause a liquidation.'
|
||||
if (!hasDebt) return 'Your position cannot be liquidated as you currently have no debt.'
|
||||
return 'The position size is too small to liquidate the account, even if the price goes to $0.00.'
|
||||
}, [type, hasDebt])
|
||||
|
||||
if (!lastLiquidationPrice || (liquidationPrice === 0 && lastLiquidationPrice === 0))
|
||||
return (
|
||||
<Text size='xs' className='flex items-center justify-end number'>
|
||||
N/A
|
||||
<Tooltip content={tooltipText} type='info' className='ml-1'>
|
||||
<InfoCircle className='w-3.5 h-3.5 text-white/40 hover:text-inherit' />
|
||||
</Tooltip>
|
||||
</Text>
|
||||
)
|
||||
|
||||
return (
|
||||
<DisplayCurrency
|
||||
className='text-xs text-right number'
|
||||
coin={BNCoin.fromDenomAndBigNumber('usd', BN(lastLiquidationPrice))}
|
||||
options={{ abbreviated: false }}
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import classNames from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { getSizeChangeColor } from 'components/account/AccountStrategiesTable/functions'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { MAX_AMOUNT_DECIMALS, MIN_AMOUNT } from 'constants/math'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { formatAmountToPrecision } from 'utils/formatters'
|
||||
|
||||
export const SIZE_META = { header: 'Size', meta: { className: 'w-40' } }
|
||||
|
||||
interface Props {
|
||||
amount: BNCoin[]
|
||||
amountChange: BNCoin[]
|
||||
}
|
||||
|
||||
export default function Size(props: Props) {
|
||||
const { amount, amountChange } = props
|
||||
const color = useMemo(() => getSizeChangeColor(amountChange), [amountChange])
|
||||
const assets = useAllAssets()
|
||||
const className = classNames('text-xs text-right w-full', color)
|
||||
const minimumAmount = 0.0001
|
||||
|
||||
const primarySymbol = assets.find(byDenom(amount[0].denom))?.symbol
|
||||
const primarySize = amount[0].amount.toString()
|
||||
const primaryFormattedAmount = formatAmountToPrecision(primarySize, MAX_AMOUNT_DECIMALS)
|
||||
const primaryLowAmount =
|
||||
primaryFormattedAmount === 0 ? minimumAmount : Math.max(primaryFormattedAmount, MIN_AMOUNT)
|
||||
|
||||
const secondarySymbol = assets.find(byDenom(amount[1].denom))?.symbol
|
||||
const secondarySize = amount[1].amount.toString()
|
||||
const secondaryFormattedAmount = formatAmountToPrecision(secondarySize, MAX_AMOUNT_DECIMALS)
|
||||
const secondaryLowAmount =
|
||||
secondaryFormattedAmount === 0 ? minimumAmount : Math.max(secondaryFormattedAmount, MIN_AMOUNT)
|
||||
|
||||
return (
|
||||
<div className='flex flex-wrap'>
|
||||
<FormattedNumber
|
||||
className={className}
|
||||
smallerThanThreshold={primaryFormattedAmount < MIN_AMOUNT}
|
||||
amount={primaryLowAmount}
|
||||
options={{
|
||||
maxDecimals: 4,
|
||||
minDecimals: 0,
|
||||
suffix: ` ${primarySymbol}`,
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
<FormattedNumber
|
||||
className={className}
|
||||
smallerThanThreshold={secondaryFormattedAmount < MIN_AMOUNT}
|
||||
amount={secondaryLowAmount}
|
||||
options={{
|
||||
maxDecimals: 4,
|
||||
minDecimals: 0,
|
||||
suffix: ` ${secondarySymbol}`,
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { getSizeChangeColor } from 'components/account/AccountStrategiesTable/functions'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import Text from 'components/common/Text'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
export const STRATEGY_AND_VALUE_META = {
|
||||
header: 'Strategy & Value',
|
||||
id: 'name',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
name: string
|
||||
value: string
|
||||
amountChange: BNCoin[]
|
||||
}
|
||||
|
||||
export default function StrategyAndValue(props: Props) {
|
||||
const { name, value, amountChange } = props
|
||||
const color = getSizeChangeColor(amountChange)
|
||||
const coin = BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, BN(value))
|
||||
|
||||
return (
|
||||
<div className='flex flex-wrap'>
|
||||
<Text size='xs' className='text-white'>
|
||||
{`${name} LP`}
|
||||
</Text>
|
||||
<DisplayCurrency
|
||||
coin={coin}
|
||||
className={classNames('text-xs text-right', color)}
|
||||
options={{ abbreviated: false }}
|
||||
showZero
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { getAmountChangeColor } from 'components/account/AccountBalancesTable/functions'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const VALUE_META = { accessorKey: 'value', header: 'Value' }
|
||||
|
||||
interface Props {
|
||||
amountChange: BigNumber
|
||||
value: string
|
||||
type: PositionType
|
||||
}
|
||||
|
||||
export const valueBalancesSortingFn = (
|
||||
a: Row<AccountBalanceRow>,
|
||||
b: Row<AccountBalanceRow>,
|
||||
): number => {
|
||||
const valueA = BN(a.original.value)
|
||||
const valueB = BN(b.original.value)
|
||||
return valueA.minus(valueB).toNumber()
|
||||
}
|
||||
|
||||
export const valuePerpSortingFn = (a: Row<AccountPerpRow>, b: Row<AccountPerpRow>): number => {
|
||||
const valueA = BN(a.original.value)
|
||||
const valueB = BN(b.original.value)
|
||||
return valueA.minus(valueB).toNumber()
|
||||
}
|
||||
|
||||
export default function Value(props: Props) {
|
||||
const { amountChange, type, value } = props
|
||||
const color = getAmountChangeColor(type, amountChange)
|
||||
const coin = new BNCoin({
|
||||
denom: ORACLE_DENOM,
|
||||
amount: value,
|
||||
})
|
||||
|
||||
return (
|
||||
<DisplayCurrency coin={coin} className={classNames('text-xs text-right', color)} showZero />
|
||||
)
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Apy, { APY_META } from 'components/account/AccountBalancesTable/Columns/Apy'
|
||||
import Size, { SIZE_META } from 'components/account/AccountStrategiesTable/Columns/Size'
|
||||
import StrategyAndValue, {
|
||||
STRATEGY_AND_VALUE_META,
|
||||
} from 'components/account/AccountStrategiesTable/Columns/StrategyAndValue'
|
||||
import useMarkets from 'hooks/markets/useMarkets'
|
||||
|
||||
export default function useAccountStrategiesColumns(account: Account) {
|
||||
const markets = useMarkets()
|
||||
|
||||
return useMemo<ColumnDef<AccountStrategyRow>[]>(() => {
|
||||
return [
|
||||
{
|
||||
...STRATEGY_AND_VALUE_META,
|
||||
cell: ({ row }) => (
|
||||
<StrategyAndValue
|
||||
name={row.original.name}
|
||||
value={row.original.value}
|
||||
amountChange={row.original.amountChange}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
...SIZE_META,
|
||||
cell: ({ row }) => (
|
||||
<Size amount={row.original.amount} amountChange={row.original.amountChange} />
|
||||
),
|
||||
},
|
||||
{
|
||||
...APY_META,
|
||||
cell: ({ row }) => (
|
||||
<Apy apy={row.original.apy} markets={markets} denom={row.original.denom} type={'vault'} />
|
||||
),
|
||||
},
|
||||
]
|
||||
}, [markets])
|
||||
}
|
70
src/components/account/AccountStrategiesTable/functions.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { BN_ONE, BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
export function getVaultAccountStrategiesRow(
|
||||
vault: DepositedVault,
|
||||
apy: number,
|
||||
prices: BNCoin[],
|
||||
prev?: DepositedVault,
|
||||
): AccountStrategyRow {
|
||||
const { name } = vault
|
||||
const previous = prev || vault
|
||||
const totalLockedValue = vault.values.primary.plus(vault.values.secondary)
|
||||
const totalValue = totalLockedValue.plus(vault.values.unlocked).plus(vault.values.unlocking)
|
||||
const prevTotalValue = previous.values.primary
|
||||
.plus(previous.values.secondary)
|
||||
.plus(previous.values.unlocked)
|
||||
.plus(previous.values.unlocking)
|
||||
|
||||
if (totalLockedValue.isLessThan(totalValue)) {
|
||||
apy = totalLockedValue.dividedBy(totalValue).times(apy).toNumber()
|
||||
}
|
||||
|
||||
const halfValue = totalValue.dividedBy(2)
|
||||
const halfValuePrev = prevTotalValue.dividedBy(2)
|
||||
const primaryPrice =
|
||||
prices.find(byDenom(vault.denoms.primary)) ??
|
||||
BNCoin.fromDenomAndBigNumber(vault.denoms.primary, BN_ONE)
|
||||
const primaryAmount = halfValue.dividedBy(primaryPrice.amount)
|
||||
const primaryAmountPrev = halfValuePrev.dividedBy(primaryPrice.amount)
|
||||
|
||||
const secondaryPrice =
|
||||
prices.find(byDenom(vault.denoms.secondary)) ??
|
||||
BNCoin.fromDenomAndBigNumber(vault.denoms.secondary, BN_ONE)
|
||||
const secondaryAmount = halfValue.dividedBy(secondaryPrice.amount)
|
||||
const secondaryAmountPrev = halfValuePrev.dividedBy(secondaryPrice.amount)
|
||||
|
||||
const amountChange = [
|
||||
BNCoin.fromDenomAndBigNumber(
|
||||
vault.denoms.primary,
|
||||
!prev ? BN_ZERO : primaryAmount.minus(primaryAmountPrev),
|
||||
),
|
||||
BNCoin.fromDenomAndBigNumber(
|
||||
vault.denoms.secondary,
|
||||
!prev ? BN_ZERO : secondaryAmount.minus(secondaryAmountPrev),
|
||||
),
|
||||
]
|
||||
|
||||
return {
|
||||
name: name,
|
||||
denom: vault.denoms.lp,
|
||||
amount: [
|
||||
BNCoin.fromDenomAndBigNumber(vault.denoms.primary, primaryAmount),
|
||||
BNCoin.fromDenomAndBigNumber(vault.denoms.secondary, secondaryAmount),
|
||||
],
|
||||
value: totalValue.toString(),
|
||||
apy,
|
||||
amountChange: amountChange,
|
||||
}
|
||||
}
|
||||
|
||||
export function getSizeChangeColor(amountChange: BNCoin[]) {
|
||||
const primaryChange = amountChange[0].amount
|
||||
const secondaryChange = amountChange[1].amount
|
||||
|
||||
if (primaryChange.isGreaterThan(0) || secondaryChange.isGreaterThan(0)) return 'text-profit'
|
||||
if (primaryChange.isLessThan(0) || secondaryChange.isLessThan(0)) return 'text-loss'
|
||||
|
||||
return ''
|
||||
}
|
38
src/components/account/AccountStrategiesTable/index.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import useAccountStrategiesColumns from 'components/account/AccountStrategiesTable/Columns/useAccountStrategiesColumns'
|
||||
import useAccountStrategiesData from 'components/account/AccountStrategiesTable/useAccountStrategiesData'
|
||||
import Table from 'components/common/Table'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
hideCard?: boolean
|
||||
tableBodyClassName?: string
|
||||
}
|
||||
|
||||
export default function AccountStrategiesTable(props: Props) {
|
||||
const { account, tableBodyClassName, hideCard } = props
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const accountStrategiesData = useAccountStrategiesData({
|
||||
account,
|
||||
updatedAccount,
|
||||
})
|
||||
|
||||
const columns = useAccountStrategiesColumns(account)
|
||||
|
||||
if (accountStrategiesData.length === 0) return null
|
||||
|
||||
return (
|
||||
<Table
|
||||
title='Strategies'
|
||||
columns={columns}
|
||||
data={accountStrategiesData}
|
||||
tableBodyClassName={classNames(tableBodyClassName, 'text-white/60')}
|
||||
initialSorting={[]}
|
||||
spacingClassName='p-2'
|
||||
hideCard={hideCard}
|
||||
type='strategies'
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { getVaultAccountStrategiesRow } from 'components/account/AccountStrategiesTable/functions'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
updatedAccount?: Account
|
||||
}
|
||||
|
||||
export default function useAccountStategiesData(props: Props) {
|
||||
const { account, updatedAccount } = props
|
||||
const { data: prices } = usePrices()
|
||||
return useMemo<AccountStrategyRow[]>(() => {
|
||||
const usedAccount = updatedAccount ?? account
|
||||
const accountVaults = usedAccount?.vaults ?? []
|
||||
|
||||
return accountVaults.map((vault) => {
|
||||
const apy = vault.apy ?? 0
|
||||
const prevVault = updatedAccount
|
||||
? account?.vaults.find((position) => position.name === vault.name)
|
||||
: vault
|
||||
|
||||
return getVaultAccountStrategiesRow(vault, apy, prices, prevVault)
|
||||
})
|
||||
}, [account, updatedAccount, prices])
|
||||
}
|
135
src/components/account/AccountSummary/AccountSummaryHeader.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
import classNames from 'classnames'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import AccountSummaryLeverage from 'components/account/AccountSummary/AccountSummaryLeverage'
|
||||
import HealthBar from 'components/account/Health/HealthBar'
|
||||
import Button from 'components/common/Button'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { ArrowRight, ArrowRightLine } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountBalanceValue } from 'utils/accounts'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
updatedAccount?: Account
|
||||
prices: BNCoin[]
|
||||
assets: Asset[]
|
||||
leverage: number
|
||||
updatedLeverage: number | null
|
||||
apr: number
|
||||
health: number
|
||||
updatedHealth: number
|
||||
healthFactor: number
|
||||
updatedHealthFactor: number
|
||||
isAccountDetails?: boolean
|
||||
}
|
||||
|
||||
export default function AccountSummaryHeader(props: Props) {
|
||||
const {
|
||||
account,
|
||||
updatedAccount,
|
||||
prices,
|
||||
assets,
|
||||
leverage,
|
||||
updatedLeverage,
|
||||
health,
|
||||
healthFactor,
|
||||
updatedHealth,
|
||||
updatedHealthFactor,
|
||||
isAccountDetails,
|
||||
} = props
|
||||
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
||||
const accountBalance = useMemo(
|
||||
() => (account ? calculateAccountBalanceValue(account, prices, assets) : BN_ZERO),
|
||||
[account, prices, assets],
|
||||
)
|
||||
const updatedAccountBalance = useMemo(
|
||||
() =>
|
||||
updatedAccount ? calculateAccountBalanceValue(updatedAccount, prices, assets) : undefined,
|
||||
[updatedAccount, prices, assets],
|
||||
)
|
||||
const hasChanged = !updatedAccountBalance?.isEqualTo(accountBalance)
|
||||
const increase = updatedAccountBalance?.isGreaterThan(accountBalance)
|
||||
|
||||
return (
|
||||
<div className='relative flex flex-wrap w-full p-4 pb-2 border-b bg-white/10 border-white/10'>
|
||||
{isAccountDetails && (
|
||||
<Button
|
||||
onClick={onClose}
|
||||
leftIcon={<ArrowRightLine />}
|
||||
iconClassName='w-full'
|
||||
className='!absolute top-4 right-4 w-8 h-6 px-2 z-4'
|
||||
size='xs'
|
||||
color='secondary'
|
||||
/>
|
||||
)}
|
||||
{isAccountDetails && (
|
||||
<Text
|
||||
size='sm'
|
||||
className='w-full pb-1 text-white/50'
|
||||
>{`Credit Account ${account.id}`}</Text>
|
||||
)}
|
||||
<div className='flex items-end w-full gap-2 pb-2 border-b border-white/5'>
|
||||
<DisplayCurrency
|
||||
options={{ abbreviated: false }}
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalance)}
|
||||
className='text-lg -mb-[1px]'
|
||||
/>
|
||||
{hasChanged && updatedAccountBalance && (
|
||||
<>
|
||||
<span
|
||||
className={classNames(
|
||||
'w-3 flex h-full items-center',
|
||||
increase ? 'text-profit' : 'text-loss',
|
||||
)}
|
||||
>
|
||||
<ArrowRight />
|
||||
</span>
|
||||
<DisplayCurrency
|
||||
options={{ abbreviated: false }}
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, updatedAccountBalance)}
|
||||
className={classNames(
|
||||
'text-lg -mb-[1px]',
|
||||
hasChanged && increase && 'text-profit',
|
||||
hasChanged && !increase && 'text-loss',
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Text className='text-white/50' size='xs'>
|
||||
Networth
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex items-center w-full pt-2'>
|
||||
<div className='flex flex-wrap pr-4 border-r w-29 border-white/5'>
|
||||
<Text size='xs' className='mb-0.5 w-full text-white/50'>
|
||||
Leverage
|
||||
</Text>
|
||||
<AccountSummaryLeverage
|
||||
leverage={leverage}
|
||||
updatedLeverage={updatedLeverage}
|
||||
className='text-sm'
|
||||
containerClassName='flex items-center gap-1'
|
||||
enforceSuffix
|
||||
/>
|
||||
</div>
|
||||
<div className='flex flex-wrap content-start flex-grow h-full pl-2'>
|
||||
<Text size='xs' className='w-full h-4 mb-2 text-white/50'>
|
||||
Health
|
||||
</Text>
|
||||
<HealthBar
|
||||
health={health}
|
||||
healthFactor={healthFactor}
|
||||
updatedHealth={updatedHealth}
|
||||
updatedHealthFactor={updatedHealthFactor}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import AccountSummary from 'components/account/AccountSummary'
|
||||
import Card from 'components/common/Card'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
isHls?: boolean
|
||||
}
|
||||
|
||||
export default function AccountSummaryInModal(props: Props) {
|
||||
const { account, isHls } = props
|
||||
|
||||
return (
|
||||
<div className='h-[546px] max-w-screen overflow-y-scroll scrollbar-hide'>
|
||||
<Card className='w-94'>
|
||||
<AccountSummary account={account} isHls={isHls} />
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
|
||||
interface Props {
|
||||
leverage: number
|
||||
updatedLeverage: number | null
|
||||
className?: string
|
||||
containerClassName?: string
|
||||
enforceSuffix?: boolean
|
||||
}
|
||||
|
||||
export default function AccountSummaryLeverage(props: Props) {
|
||||
const { leverage, updatedLeverage } = props
|
||||
|
||||
if (!updatedLeverage) {
|
||||
return (
|
||||
<FormattedNumber
|
||||
className={classNames(props.className ? props.className : 'w-full text-center text-2xs')}
|
||||
amount={isNaN(leverage) ? 0 : leverage}
|
||||
options={{
|
||||
maxDecimals: 2,
|
||||
minDecimals: 2,
|
||||
suffix: 'x',
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
props.containerClassName
|
||||
? props.containerClassName
|
||||
: 'flex items-center w-full justify-between',
|
||||
)}
|
||||
>
|
||||
<FormattedNumber
|
||||
className={classNames(props.className ? props.className : 'w-6 text-left text-2xs pl-2')}
|
||||
amount={isNaN(leverage) ? 1 : leverage}
|
||||
options={{
|
||||
maxDecimals: props.enforceSuffix ? 2 : 1,
|
||||
minDecimals: props.enforceSuffix ? 2 : 1,
|
||||
rounded: true,
|
||||
suffix: props.enforceSuffix ? 'x' : '',
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
<div
|
||||
className={classNames(
|
||||
'w-3',
|
||||
updatedLeverage > leverage && 'text-loss',
|
||||
updatedLeverage < leverage && 'text-profit',
|
||||
)}
|
||||
>
|
||||
<ArrowRight />
|
||||
</div>
|
||||
<FormattedNumber
|
||||
className={classNames(
|
||||
props.className ? props.className : 'w-6 text-right text-2xs pr-2',
|
||||
updatedLeverage > leverage && 'text-loss',
|
||||
updatedLeverage < leverage && 'text-profit',
|
||||
)}
|
||||
amount={isNaN(updatedLeverage) ? 0 : updatedLeverage}
|
||||
options={{
|
||||
maxDecimals: props.enforceSuffix ? 2 : 1,
|
||||
minDecimals: props.enforceSuffix ? 2 : 1,
|
||||
rounded: true,
|
||||
suffix: props.enforceSuffix ? 'x' : '',
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,55 +1,49 @@
|
||||
import classNames from 'classnames'
|
||||
import { HTMLAttributes, useCallback, useMemo } from 'react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
import AccountBalancesTable from 'components/account/AccountBalancesTable'
|
||||
import AccountComposition from 'components/account/AccountComposition'
|
||||
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
|
||||
import HealthBar from 'components/account/Health/HealthBar'
|
||||
import AccountStrategiesTable from 'components/account/AccountStrategiesTable'
|
||||
import AccountSummaryHeader from 'components/account/AccountSummary/AccountSummaryHeader'
|
||||
import useBorrowMarketAssetsTableData from 'components/borrow/Table/useBorrowMarketAssetsTableData'
|
||||
import Accordion from 'components/common/Accordion'
|
||||
import Card from 'components/common/Card'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import { ArrowRight } from 'components/common/Icons'
|
||||
import Text from 'components/common/Text'
|
||||
import useLendingMarketAssetsTableData from 'components/earn/lend/Table/useLendingMarketAssetsTableData'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||
import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountBalanceValue, calculateAccountLeverage } from 'utils/accounts'
|
||||
import { calculateAccountApr, calculateAccountLeverage } from 'utils/accounts'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
isAccountDetails?: boolean
|
||||
isHls?: boolean
|
||||
}
|
||||
|
||||
export default function AccountSummary(props: Props) {
|
||||
const storageKey = props.isAccountDetails
|
||||
? LocalStorageKeys.ACCOUNT_DETAILS_TABS
|
||||
: LocalStorageKeys.ACCOUNT_SUMMARY_TABS
|
||||
const defaultSetting = props.isAccountDetails
|
||||
? DEFAULT_SETTINGS.accountDetailsTabs
|
||||
: DEFAULT_SETTINGS.accountSummaryTabs
|
||||
const [accountSummaryTabs, setAccountSummaryTabs] = useLocalStorage<boolean[]>(
|
||||
LocalStorageKeys.ACCOUNT_SUMMARY_TABS,
|
||||
DEFAULT_SETTINGS.accountSummaryTabs,
|
||||
storageKey,
|
||||
defaultSetting,
|
||||
)
|
||||
const { data: prices } = usePrices()
|
||||
const assets = useAllAssets()
|
||||
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||
const accountBalance = useMemo(
|
||||
() =>
|
||||
props.account
|
||||
? calculateAccountBalanceValue(updatedAccount ?? props.account, prices, assets)
|
||||
: BN_ZERO,
|
||||
[props.account, updatedAccount, prices, assets],
|
||||
)
|
||||
const data = useBorrowMarketAssetsTableData()
|
||||
const borrowAssetsData = useMemo(() => data?.allAssets || [], [data])
|
||||
const { availableAssets: lendingAvailableAssets, accountLentAssets } =
|
||||
useLendingMarketAssetsTableData()
|
||||
|
||||
const { data: hlsStrategies } = useHLSStakingAssets()
|
||||
const lendingAssetsData = useMemo(
|
||||
() => [...lendingAvailableAssets, ...accountLentAssets],
|
||||
[lendingAvailableAssets, accountLentAssets],
|
||||
@ -76,10 +70,32 @@ export default function AccountSummary(props: Props) {
|
||||
[accountSummaryTabs, setAccountSummaryTabs],
|
||||
)
|
||||
|
||||
const apr = useMemo(
|
||||
() =>
|
||||
calculateAccountApr(
|
||||
updatedAccount ?? props.account,
|
||||
borrowAssetsData,
|
||||
lendingAssetsData,
|
||||
prices,
|
||||
hlsStrategies,
|
||||
assets,
|
||||
props.account.kind === 'high_levered_strategy',
|
||||
),
|
||||
[
|
||||
props.account,
|
||||
assets,
|
||||
borrowAssetsData,
|
||||
hlsStrategies,
|
||||
lendingAssetsData,
|
||||
prices,
|
||||
updatedAccount,
|
||||
],
|
||||
)
|
||||
|
||||
const items = useMemo(() => {
|
||||
const itemsArray = [
|
||||
{
|
||||
title: `Credit Account ${props.account.id} Composition`,
|
||||
title: `Composition`,
|
||||
renderContent: () =>
|
||||
props.account ? <AccountComposition account={props.account} isHls={props.isHls} /> : null,
|
||||
isOpen: accountSummaryTabs[0],
|
||||
@ -103,14 +119,23 @@ export default function AccountSummary(props: Props) {
|
||||
renderSubTitle: () => <></>,
|
||||
},
|
||||
]
|
||||
|
||||
if (props.account.vaults.length > 0)
|
||||
itemsArray.push({
|
||||
title: 'Strategies',
|
||||
renderContent: () =>
|
||||
props.account ? <AccountStrategiesTable account={props.account} hideCard /> : null,
|
||||
isOpen: accountSummaryTabs[2] ?? false,
|
||||
toggleOpen: (index: number) => handleToggle(index),
|
||||
renderSubTitle: () => <></>,
|
||||
})
|
||||
|
||||
if (props.account.perps.length > 0)
|
||||
itemsArray.push({
|
||||
title: 'Perp Positions',
|
||||
renderContent: () =>
|
||||
props.account && props.account.perps.length > 0 ? (
|
||||
<AccountPerpPositionTable account={props.account} hideCard />
|
||||
) : null,
|
||||
isOpen: accountSummaryTabs[2] ?? false,
|
||||
props.account ? <AccountPerpPositionTable account={props.account} hideCard /> : null,
|
||||
isOpen: accountSummaryTabs[props.account.vaults.length > 0 ? 3 : 2] ?? false,
|
||||
toggleOpen: (index: number) => handleToggle(index),
|
||||
renderSubTitle: () => <></>,
|
||||
})
|
||||
@ -127,74 +152,22 @@ export default function AccountSummary(props: Props) {
|
||||
|
||||
if (!props.account) return null
|
||||
return (
|
||||
<div className='h-[546px] max-w-screen overflow-y-scroll scrollbar-hide w-93.5'>
|
||||
<Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'>
|
||||
<Item label='Net worth' classes='flex-1'>
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, accountBalance)}
|
||||
className='text-2xs'
|
||||
/>
|
||||
</Item>
|
||||
<Item label='Leverage' classes='flex-1 w-[93px]'>
|
||||
<FormattedNumber
|
||||
className={'w-full text-center text-2xs'}
|
||||
amount={isNaN(leverage.toNumber()) ? 0 : leverage.toNumber()}
|
||||
options={{
|
||||
maxDecimals: 2,
|
||||
minDecimals: 2,
|
||||
suffix: 'x',
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
{updatedLeverage && (
|
||||
<>
|
||||
<ArrowRight width={12} />
|
||||
<FormattedNumber
|
||||
className={classNames(
|
||||
'w-full text-center text-2xs',
|
||||
updatedLeverage?.isGreaterThan(leverage) && 'text-loss',
|
||||
updatedLeverage?.isLessThan(leverage) && 'text-profit',
|
||||
)}
|
||||
amount={isNaN(updatedLeverage.toNumber()) ? 0 : updatedLeverage?.toNumber()}
|
||||
options={{ maxDecimals: 2, minDecimals: 2, suffix: 'x' }}
|
||||
animate
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Item>
|
||||
<Item label='Account health'>
|
||||
<HealthBar
|
||||
<AccountSummaryHeader
|
||||
account={props.account}
|
||||
updatedAccount={updatedAccount}
|
||||
prices={prices}
|
||||
assets={assets}
|
||||
leverage={leverage.toNumber() || 1}
|
||||
updatedLeverage={updatedLeverage?.toNumber() || null}
|
||||
apr={apr.toNumber()}
|
||||
health={health}
|
||||
healthFactor={healthFactor}
|
||||
updatedHealth={updatedHealth}
|
||||
healthFactor={healthFactor}
|
||||
updatedHealthFactor={updatedHealthFactor}
|
||||
className='h-1'
|
||||
isAccountDetails={props.isAccountDetails}
|
||||
/>
|
||||
</Item>
|
||||
</Card>
|
||||
<Accordion items={items} allowMultipleOpen />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ItemProps extends HTMLAttributes<HTMLDivElement> {
|
||||
label: string
|
||||
classes?: string
|
||||
}
|
||||
|
||||
function Item(props: ItemProps) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-col justify-around px-3 py-1 border-r border-r-white/10',
|
||||
props.classes,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<Text size='2xs' className='text-white/50 whitespace-nowrap'>
|
||||
{props.label}
|
||||
</Text>
|
||||
<div className='flex h-4.5 w-full'>{props.children}</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import AccountSummary from 'components/account/AccountSummary'
|
||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
|
||||
function CurrentAccountSummary() {
|
||||
const account = useCurrentAccount()
|
||||
if (!account) return
|
||||
return <AccountSummary account={account} />
|
||||
}
|
||||
|
||||
export default CurrentAccountSummary
|
@ -11,13 +11,12 @@ import { getHealthIndicatorColors } from 'utils/healthIndicator'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
hasLabel?: boolean
|
||||
health: number
|
||||
healthFactor: number
|
||||
height?: string
|
||||
iconClassName?: string
|
||||
updatedHealth?: number
|
||||
updatedHealthFactor?: number
|
||||
updatedHealth?: number
|
||||
showIcon?: boolean
|
||||
}
|
||||
|
||||
@ -87,44 +86,44 @@ export default function HealthBar({
|
||||
<rect fill='#FFFFFF' x='95.5' width='88.5' height={height} />
|
||||
</mask>
|
||||
<mask id='backgroundHealthBarMask'>
|
||||
<rect fill='#FFFFFF' x='0' y='0' width='6.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='8.9' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='13.7' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='18.5' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='23.3' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='28.1' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='32.9' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='37.7' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='42.5' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='47.3' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='52.1' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='56.9' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='61.7' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='66.5' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='71.3' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='76.1' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='80.9' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='85.7' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='90.5' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='95.3' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='100.1' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='104.9' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='109.7' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='114.5' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='119.2' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='124' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='128.8' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='133.6' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='138.4' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='143.2' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='148' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='152.8' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='157.6' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='162.4' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='167.2' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='172' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='176.8' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='181.6' y='0' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='0' y='-0.45' width='6.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='8.9' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='13.7' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='18.5' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='23.3' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='28.1' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='32.9' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='37.7' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='42.7' y='-0.45' width='1.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='47.3' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='52.1' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='56.9' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='61.7' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='66.5' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='71.3' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='76.1' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='80.9' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='85.7' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='90.5' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='95.3' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='100.1' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='104.9' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='109.7' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='114.5' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='119.2' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='124' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='128.8' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='133.6' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='138.4' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='143.2' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='148' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='152.8' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='157.6' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='162.4' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='167.2' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='172' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='176.8' y='-0.45' width='2.4' height={height} />
|
||||
<rect fill='#FFFFFF' x='181.6' y='-0.45' width='2.4' height={height} />
|
||||
</mask>
|
||||
<rect
|
||||
className='fill-white/10'
|
||||
|
@ -2,7 +2,7 @@ import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import Loading from 'components/common/Loading'
|
||||
|
||||
export const BORROW_RATE_META = {
|
||||
accessorKey: 'borrowRate',
|
||||
accessorKey: 'apy.borrow',
|
||||
header: 'Borrow Rate APY',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ interface Props {
|
||||
export default function Accordion(props: Props) {
|
||||
if (props.allowMultipleOpen) {
|
||||
return (
|
||||
<Card className='w-full'>
|
||||
<>
|
||||
{props.items.map((item, index) => (
|
||||
<AccordionContent key={index} item={item} index={index} />
|
||||
))}
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -27,20 +27,29 @@ export default function AccordionContent(props: Props) {
|
||||
<div
|
||||
onClick={() => toggleOpen(props.index)}
|
||||
className={classNames(
|
||||
'mb-0 flex hover:cursor-pointer items-center justify-between bg-white/10 p-4 text-white border-b border-transparent',
|
||||
'mb-0 flex hover:cursor-pointer items-center justify-between bg-white/10 py-2 px-4 text-white border-b border-transparent',
|
||||
'[&::marker]:hidden [&::marker]:content-[""]',
|
||||
isOpen && 'border-white/20',
|
||||
isOpen && 'border-white/10',
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<Text>{title}</Text>
|
||||
<Text size='sm' className='font-semibold'>
|
||||
{title}
|
||||
</Text>
|
||||
{renderSubTitle()}
|
||||
</div>
|
||||
<div className='block pr-1 group-[[open]]/accordion:hidden'>
|
||||
{isOpen ? <ChevronDown className='h-1.5' /> : <ChevronRight className='w-1.5' />}
|
||||
</div>
|
||||
</div>
|
||||
{isOpen && <div className='bg-white/5 transition-[padding]'>{renderContent()}</div>}
|
||||
<div
|
||||
className={classNames(
|
||||
'grid transition-[grid-template-rows]',
|
||||
isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',
|
||||
)}
|
||||
>
|
||||
<div className='overflow-hidden'>{renderContent()}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ export default function EscButton(props: Props) {
|
||||
return (
|
||||
<Button
|
||||
onClick={props.onClick}
|
||||
leftIcon={<Cross size={16} />}
|
||||
leftIcon={<Cross />}
|
||||
iconClassName='w-3'
|
||||
color='tertiary'
|
||||
className={props.className ? props.className : 'h-8 w-8'}
|
||||
className='w-8 h-8'
|
||||
size='xs'
|
||||
/>
|
||||
)
|
||||
|
@ -1,3 +1,15 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.33337 8.00065H12.6667M12.6667 8.00065L8.00004 3.33398M12.6667 8.00065L8.00004 12.6673" stroke="currentColor" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M3.33337 8.00065H12.6667M12.6667 8.00065L8.00004 3.33398M12.6667 8.00065L8.00004 12.6673"
|
||||
stroke="currentColor"
|
||||
stroke-width="0.666667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 299 B After Width: | Height: | Size: 340 B |
8
src/components/common/Icons/ArrowRightLine.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13 13V1M1 7H10.3333M10.3333 7L5.66667 2.33333M10.3333 7L5.66667 11.6667"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 255 B |
@ -1,4 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 512 512">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M459.654,233.373l-90.531,90.5c-49.969,50-131.031,50-181,0c-7.875-7.844-14.031-16.688-19.438-25.813 l42.063-42.063c2-2.016,4.469-3.172,6.828-4.531c2.906,9.938,7.984,19.344,15.797,27.156c24.953,24.969,65.563,24.938,90.5,0 l90.5-90.5c24.969-24.969,24.969-65.563,0-90.516c-24.938-24.953-65.531-24.953-90.5,0l-32.188,32.219 c-26.109-10.172-54.25-12.906-81.641-8.891l68.578-68.578c50-49.984,131.031-49.984,181.031,0 C509.623,102.342,509.623,183.389,459.654,233.373z M220.326,382.186l-32.203,32.219c-24.953,24.938-65.563,24.938-90.516,0 c-24.953-24.969-24.953-65.563,0-90.531l90.516-90.5c24.969-24.969,65.547-24.969,90.5,0c7.797,7.797,12.875,17.203,15.813,27.125 c2.375-1.375,4.813-2.5,6.813-4.5l42.063-42.047c-5.375-9.156-11.563-17.969-19.438-25.828c-49.969-49.984-131.031-49.984-181.016,0 l-90.5,90.5c-49.984,50-49.984,131.031,0,181.031c49.984,49.969,131.031,49.969,181.016,0l68.594-68.594 C274.561,395.092,246.42,392.342,220.326,382.186z"
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -1,3 +1,10 @@
|
||||
<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 167 B After Width: | Height: | Size: 210 B |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 10 16">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 10 16"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M9.3,0.2C9.6,0.5,9.6,1,9.3,1.3L9.3,1.4L2.5,8l6.7,6.6c0.3,0.3,0.3,0.7,0.1,1.1l-0.1,0.1c-0.3,0.3-0.8,0.3-1.1,0.1l-0.1-0.1
|
||||
|
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 383 B |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 16 10">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 16 10"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M15.8,9.3c-0.3,0.3-0.7,0.3-1.1,0.1l-0.1-0.1L8,2.5L1.4,9.3C1.1,9.6,0.7,9.6,0.3,9.3L0.2,9.3
|
||||
|
Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 387 B |
@ -1,10 +1,15 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5007_284)">
|
||||
<path d="M8.00016 14.6654C11.6821 14.6654 14.6668 11.6806 14.6668 7.9987C14.6668 4.3168 11.6821 1.33203 8.00016 1.33203C4.31826 1.33203 1.3335 4.3168 1.3335 7.9987C1.3335 11.6806 4.31826 14.6654 8.00016 14.6654Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M8.00016 14.6654C11.6821 14.6654 14.6668 11.6806 14.6668 7.9987C14.6668 4.3168 11.6821 1.33203 8.00016 1.33203C4.31826 1.33203 1.3335 4.3168 1.3335 7.9987C1.3335 11.6806 4.31826 14.6654 8.00016 14.6654Z"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5007_284">
|
||||
<rect width="16" height="16" fill="currentColor"/>
|
||||
<rect width="16" height="16" fill="currentColor" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 567 B After Width: | Height: | Size: 571 B |
@ -1,4 +1,15 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9998 9.00023V13.0002M11.9998 17.0002H12.0098M10.6151 3.89195L2.39019 18.0986C1.93398 18.8866 1.70588 19.2806 1.73959 19.6039C1.769 19.886 1.91677 20.1423 2.14613 20.309C2.40908 20.5002 2.86435 20.5002 3.77487 20.5002H20.2246C21.1352 20.5002 21.5904 20.5002 21.8534 20.309C22.0827 20.1423 22.2305 19.886 22.2599 19.6039C22.2936 19.2806 22.0655 18.8866 21.6093 18.0986L13.3844 3.89195C12.9299 3.10679 12.7026 2.71421 12.4061 2.58235C12.1474 2.46734 11.8521 2.46734 11.5935 2.58235C11.2969 2.71421 11.0696 3.10679 10.6151 3.89195Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 9V13M12 17H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M11.9998 9.00023V13.0002M11.9998 17.0002H12.0098M10.6151 3.89195L2.39019 18.0986C1.93398 18.8866 1.70588 19.2806 1.73959 19.6039C1.769 19.886 1.91677 20.1423 2.14613 20.309C2.40908 20.5002 2.86435 20.5002 3.77487 20.5002H20.2246C21.1352 20.5002 21.5904 20.5002 21.8534 20.309C22.0827 20.1423 22.2305 19.886 22.2599 19.6039C22.2936 19.2806 22.0655 18.8866 21.6093 18.0986L13.3844 3.89195C12.9299 3.10679 12.7026 2.71421 12.4061 2.58235C12.1474 2.46734 11.8521 2.46734 11.5935 2.58235C11.2969 2.71421 11.0696 3.10679 10.6151 3.89195Z"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12 9V13M12 17H12.01"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 858 B |
@ -1,4 +1,6 @@
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 564 225">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 564 225"
|
||||
>
|
||||
<defs>
|
||||
<rect id="gridHoleRect" width="564.1" height="225.1" />
|
||||
</defs>
|
||||
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 511 225">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 511 225"
|
||||
>
|
||||
<defs>
|
||||
<rect id="gridLandscapeRect" width="511" height="225" />
|
||||
</defs>
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@ -1,4 +1,6 @@
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -1,4 +1,6 @@
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -1,4 +1,6 @@
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 242 80">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 242 80"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M23.6,14.9C22,21.3,15.5,25.2,9,23.6C2.6,22-1.3,15.5,0.3,9.1S8.4-1.2,14.8,0.4C21.3,2,25.2,8.5,23.6,14.9
|
||||
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 598 B |
@ -1,5 +1,11 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="scales-02">
|
||||
<path id="Icon" d="M2.50047 13H8.50047M15.5005 13H21.5005M12.0005 7V21M12.0005 7C13.3812 7 14.5005 5.88071 14.5005 4.5M12.0005 7C10.6198 7 9.50047 5.88071 9.50047 4.5M4.00047 21L20.0005 21M4.00047 4.50001L9.50047 4.5M9.50047 4.5C9.50047 3.11929 10.6198 2 12.0005 2C13.3812 2 14.5005 3.11929 14.5005 4.5M14.5005 4.5L20.0005 4.5M8.88091 14.3364C8.48022 15.8706 7.11858 17 5.50047 17C3.88237 17 2.52073 15.8706 2.12004 14.3364C2.0873 14.211 2.07093 14.1483 2.06935 13.8979C2.06838 13.7443 2.12544 13.3904 2.17459 13.2449C2.25478 13.0076 2.34158 12.8737 2.51519 12.6059L5.50047 8L8.48576 12.6059C8.65937 12.8737 8.74617 13.0076 8.82636 13.2449C8.87551 13.3904 8.93257 13.7443 8.9316 13.8979C8.93002 14.1483 8.91365 14.211 8.88091 14.3364ZM21.8809 14.3364C21.4802 15.8706 20.1186 17 18.5005 17C16.8824 17 15.5207 15.8706 15.12 14.3364C15.0873 14.211 15.0709 14.1483 15.0693 13.8979C15.0684 13.7443 15.1254 13.3904 15.1746 13.2449C15.2548 13.0076 15.3416 12.8737 15.5152 12.6059L18.5005 8L21.4858 12.6059C21.6594 12.8737 21.7462 13.0076 21.8264 13.2449C21.8755 13.3904 21.9326 13.7443 21.9316 13.8979C21.93 14.1483 21.9137 14.211 21.8809 14.3364Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g id="scales-02">
|
||||
<path
|
||||
id="Icon"
|
||||
d="M2.50047 13H8.50047M15.5005 13H21.5005M12.0005 7V21M12.0005 7C13.3812 7 14.5005 5.88071 14.5005 4.5M12.0005 7C10.6198 7 9.50047 5.88071 9.50047 4.5M4.00047 21L20.0005 21M4.00047 4.50001L9.50047 4.5M9.50047 4.5C9.50047 3.11929 10.6198 2 12.0005 2C13.3812 2 14.5005 3.11929 14.5005 4.5M14.5005 4.5L20.0005 4.5M8.88091 14.3364C8.48022 15.8706 7.11858 17 5.50047 17C3.88237 17 2.52073 15.8706 2.12004 14.3364C2.0873 14.211 2.07093 14.1483 2.06935 13.8979C2.06838 13.7443 2.12544 13.3904 2.17459 13.2449C2.25478 13.0076 2.34158 12.8737 2.51519 12.6059L5.50047 8L8.48576 12.6059C8.65937 12.8737 8.74617 13.0076 8.82636 13.2449C8.87551 13.3904 8.93257 13.7443 8.9316 13.8979C8.93002 14.1483 8.91365 14.211 8.88091 14.3364ZM21.8809 14.3364C21.4802 15.8706 20.1186 17 18.5005 17C16.8824 17 15.5207 15.8706 15.12 14.3364C15.0873 14.211 15.0709 14.1483 15.0693 13.8979C15.0684 13.7443 15.1254 13.3904 15.1746 13.2449C15.2548 13.0076 15.3416 12.8737 15.5152 12.6059L18.5005 8L21.4858 12.6059C21.6594 12.8737 21.7462 13.0076 21.8264 13.2449C21.8755 13.3904 21.9326 13.7443 21.9316 13.8979C21.93 14.1483 21.9137 14.211 21.8809 14.3364Z"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -1,9 +1,19 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.52193 2.30302C7.67559 1.99173 7.75242 1.83609 7.85672 1.78636C7.94746 1.74309 8.05289 1.74309 8.14363 1.78636C8.24793 1.83609 8.32476 1.99173 8.47842 2.30302L9.9362 5.25634C9.98157 5.34824 10.0042 5.39419 10.0374 5.42986C10.0667 5.46145 10.1019 5.48705 10.141 5.50523C10.1852 5.52576 10.2359 5.53317 10.3373 5.548L13.5982 6.02462C13.9415 6.07481 14.1132 6.0999 14.1927 6.18377C14.2618 6.25674 14.2943 6.35701 14.2812 6.45666C14.266 6.5712 14.1417 6.69227 13.8931 6.9344L11.5345 9.23176C11.4609 9.30338 11.4242 9.33918 11.4004 9.38179C11.3794 9.41951 11.366 9.46096 11.3608 9.50382C11.3549 9.55223 11.3636 9.60281 11.3809 9.70397L11.9375 12.9489C11.9962 13.2911 12.0255 13.4623 11.9704 13.5638C11.9224 13.6522 11.8371 13.7141 11.7382 13.7325C11.6246 13.7535 11.4709 13.6727 11.1636 13.5111L8.24841 11.978C8.15758 11.9303 8.11217 11.9064 8.06432 11.897C8.02196 11.8887 7.97839 11.8887 7.93602 11.897C7.88818 11.9064 7.84276 11.9303 7.75193 11.978L4.83678 13.5111C4.52944 13.6727 4.37577 13.7535 4.26214 13.7325C4.16328 13.7141 4.07798 13.6522 4.02999 13.5638C3.97483 13.4623 4.00418 13.2911 4.06288 12.9489L4.61942 9.70397C4.63677 9.60281 4.64545 9.55223 4.63958 9.50382C4.63438 9.46096 4.6209 9.41951 4.5999 9.38179C4.57618 9.33918 4.53941 9.30337 4.46589 9.23176L2.1072 6.9344C1.8586 6.69227 1.73431 6.5712 1.71918 6.45666C1.70602 6.35701 1.73853 6.25674 1.80766 6.18377C1.88712 6.0999 2.05881 6.07481 2.40219 6.02462L5.66304 5.548C5.76445 5.53317 5.81515 5.52576 5.85931 5.50523C5.89841 5.48705 5.9336 5.46145 5.96295 5.42986C5.9961 5.39419 6.01878 5.34824 6.06415 5.25634L7.52193 2.30302Z" fill="url(#paint0_linear_1694_217638)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1694_217638" x1="19.7824" y1="1.75391" x2="-3.19296" y2="1.7547" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#BA08BD" stop-opacity="0.764896"/>
|
||||
<stop offset="1" stop-color="#FFA0BB" stop-opacity="0.88641"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
d="M7.52193 2.30302C7.67559 1.99173 7.75242 1.83609 7.85672 1.78636C7.94746 1.74309 8.05289 1.74309 8.14363 1.78636C8.24793 1.83609 8.32476 1.99173 8.47842 2.30302L9.9362 5.25634C9.98157 5.34824 10.0042 5.39419 10.0374 5.42986C10.0667 5.46145 10.1019 5.48705 10.141 5.50523C10.1852 5.52576 10.2359 5.53317 10.3373 5.548L13.5982 6.02462C13.9415 6.07481 14.1132 6.0999 14.1927 6.18377C14.2618 6.25674 14.2943 6.35701 14.2812 6.45666C14.266 6.5712 14.1417 6.69227 13.8931 6.9344L11.5345 9.23176C11.4609 9.30338 11.4242 9.33918 11.4004 9.38179C11.3794 9.41951 11.366 9.46096 11.3608 9.50382C11.3549 9.55223 11.3636 9.60281 11.3809 9.70397L11.9375 12.9489C11.9962 13.2911 12.0255 13.4623 11.9704 13.5638C11.9224 13.6522 11.8371 13.7141 11.7382 13.7325C11.6246 13.7535 11.4709 13.6727 11.1636 13.5111L8.24841 11.978C8.15758 11.9303 8.11217 11.9064 8.06432 11.897C8.02196 11.8887 7.97839 11.8887 7.93602 11.897C7.88818 11.9064 7.84276 11.9303 7.75193 11.978L4.83678 13.5111C4.52944 13.6727 4.37577 13.7535 4.26214 13.7325C4.16328 13.7141 4.07798 13.6522 4.02999 13.5638C3.97483 13.4623 4.00418 13.2911 4.06288 12.9489L4.61942 9.70397C4.63677 9.60281 4.64545 9.55223 4.63958 9.50382C4.63438 9.46096 4.6209 9.41951 4.5999 9.38179C4.57618 9.33918 4.53941 9.30337 4.46589 9.23176L2.1072 6.9344C1.8586 6.69227 1.73431 6.5712 1.71918 6.45666C1.70602 6.35701 1.73853 6.25674 1.80766 6.18377C1.88712 6.0999 2.05881 6.07481 2.40219 6.02462L5.66304 5.548C5.76445 5.53317 5.81515 5.52576 5.85931 5.50523C5.89841 5.48705 5.9336 5.46145 5.96295 5.42986C5.9961 5.39419 6.01878 5.34824 6.06415 5.25634L7.52193 2.30302Z"
|
||||
fill="url(#paint0_linear_1694_217638)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_1694_217638"
|
||||
x1="19.7824"
|
||||
y1="1.75391"
|
||||
x2="-3.19296"
|
||||
y2="1.7547"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#BA08BD" stop-opacity="0.764896" />
|
||||
<stop offset="1" stop-color="#FFA0BB" stop-opacity="0.88641" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -1,3 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.52193 2.30302C7.67559 1.99173 7.75242 1.83609 7.85672 1.78636C7.94746 1.74309 8.05289 1.74309 8.14363 1.78636C8.24793 1.83609 8.32476 1.99173 8.47842 2.30302L9.9362 5.25634C9.98157 5.34824 10.0042 5.39419 10.0374 5.42986C10.0667 5.46145 10.1019 5.48705 10.141 5.50523C10.1852 5.52576 10.2359 5.53317 10.3373 5.548L13.5982 6.02462C13.9415 6.07481 14.1132 6.0999 14.1927 6.18377C14.2618 6.25674 14.2943 6.35701 14.2812 6.45666C14.266 6.5712 14.1417 6.69227 13.8931 6.9344L11.5345 9.23176C11.4609 9.30338 11.4242 9.33918 11.4004 9.38179C11.3794 9.41951 11.366 9.46096 11.3608 9.50382C11.3549 9.55223 11.3636 9.60281 11.3809 9.70397L11.9375 12.9489C11.9962 13.2911 12.0255 13.4623 11.9704 13.5638C11.9224 13.6522 11.8371 13.7141 11.7382 13.7325C11.6246 13.7535 11.4709 13.6727 11.1636 13.5111L8.24841 11.978C8.15758 11.9303 8.11217 11.9064 8.06432 11.897C8.02196 11.8887 7.97839 11.8887 7.93602 11.897C7.88818 11.9064 7.84276 11.9303 7.75193 11.978L4.83678 13.5111C4.52944 13.6727 4.37577 13.7535 4.26214 13.7325C4.16328 13.7141 4.07798 13.6522 4.02999 13.5638C3.97483 13.4623 4.00418 13.2911 4.06288 12.9489L4.61942 9.70397C4.63677 9.60281 4.64545 9.55223 4.63958 9.50382C4.63438 9.46096 4.6209 9.41951 4.5999 9.38179C4.57618 9.33918 4.53941 9.30337 4.46589 9.23176L2.1072 6.9344C1.8586 6.69227 1.73431 6.5712 1.71918 6.45666C1.70602 6.35701 1.73853 6.25674 1.80766 6.18377C1.88712 6.0999 2.05881 6.07481 2.40219 6.02462L5.66304 5.548C5.76445 5.53317 5.81515 5.52576 5.85931 5.50523C5.89841 5.48705 5.9336 5.46145 5.96295 5.42986C5.9961 5.39419 6.01878 5.34824 6.06415 5.25634L7.52193 2.30302Z" stroke="currentColor" stroke-opacity="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M7.52193 2.30302C7.67559 1.99173 7.75242 1.83609 7.85672 1.78636C7.94746 1.74309 8.05289 1.74309 8.14363 1.78636C8.24793 1.83609 8.32476 1.99173 8.47842 2.30302L9.9362 5.25634C9.98157 5.34824 10.0042 5.39419 10.0374 5.42986C10.0667 5.46145 10.1019 5.48705 10.141 5.50523C10.1852 5.52576 10.2359 5.53317 10.3373 5.548L13.5982 6.02462C13.9415 6.07481 14.1132 6.0999 14.1927 6.18377C14.2618 6.25674 14.2943 6.35701 14.2812 6.45666C14.266 6.5712 14.1417 6.69227 13.8931 6.9344L11.5345 9.23176C11.4609 9.30338 11.4242 9.33918 11.4004 9.38179C11.3794 9.41951 11.366 9.46096 11.3608 9.50382C11.3549 9.55223 11.3636 9.60281 11.3809 9.70397L11.9375 12.9489C11.9962 13.2911 12.0255 13.4623 11.9704 13.5638C11.9224 13.6522 11.8371 13.7141 11.7382 13.7325C11.6246 13.7535 11.4709 13.6727 11.1636 13.5111L8.24841 11.978C8.15758 11.9303 8.11217 11.9064 8.06432 11.897C8.02196 11.8887 7.97839 11.8887 7.93602 11.897C7.88818 11.9064 7.84276 11.9303 7.75193 11.978L4.83678 13.5111C4.52944 13.6727 4.37577 13.7535 4.26214 13.7325C4.16328 13.7141 4.07798 13.6522 4.02999 13.5638C3.97483 13.4623 4.00418 13.2911 4.06288 12.9489L4.61942 9.70397C4.63677 9.60281 4.64545 9.55223 4.63958 9.50382C4.63438 9.46096 4.6209 9.41951 4.5999 9.38179C4.57618 9.33918 4.53941 9.30337 4.46589 9.23176L2.1072 6.9344C1.8586 6.69227 1.73431 6.5712 1.71918 6.45666C1.70602 6.35701 1.73853 6.25674 1.80766 6.18377C1.88712 6.0999 2.05881 6.07481 2.40219 6.02462L5.66304 5.548C5.76445 5.53317 5.81515 5.52576 5.85931 5.50523C5.89841 5.48705 5.9336 5.46145 5.96295 5.42986C5.9961 5.39419 6.01878 5.34824 6.06415 5.25634L7.52193 2.30302Z"
|
||||
stroke="currentColor"
|
||||
stroke-opacity="0.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1,3 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.3334 11.3333H2.66675M2.66675 11.3333L5.33341 8.66667M2.66675 11.3333L5.33341 14M2.66675 4.66667H13.3334M13.3334 4.66667L10.6667 2M13.3334 4.66667L10.6667 7.33333" stroke="currentColor" stroke-opacity="0.6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M13.3334 11.3333H2.66675M2.66675 11.3333L5.33341 8.66667M2.66675 11.3333L5.33341 14M2.66675 4.66667H13.3334M13.3334 4.66667L10.6667 2M13.3334 4.66667L10.6667 7.33333"
|
||||
stroke="currentColor"
|
||||
stroke-opacity="0.6"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 373 B |
@ -1,5 +1,6 @@
|
||||
<svg viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.86824 5.48057C4.48435 6.15239 3.51565 6.15239 3.13176 5.48057L0 0L8 0L4.86824 5.48057Z"
|
||||
<path
|
||||
d="M4.86824 5.48057C4.48435 6.15239 3.51565 6.15239 3.13176 5.48057L0 0L8 0L4.86824 5.48057Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 213 B |
@ -1,4 +1,12 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 120 120">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 120 120"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M0.3,3.8l46.3,61.9L0,116.2h10.5l40.8-44.1l33,44.1H120L71.1,50.7l43.4-46.9H104L66.4,44.5L36,3.8
|
||||
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 334 B |
@ -1,3 +1,11 @@
|
||||
<svg viewBox="0 0 1 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="0.5" y1="0.5" x2="0.5" y2="7.5" stroke="currentColor" stroke-linecap="round" stroke-dasharray="2 2"/>
|
||||
<line
|
||||
x1="0.5"
|
||||
y1="0.5"
|
||||
x2="0.5"
|
||||
y2="7.5"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-dasharray="2 2"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 190 B After Width: | Height: | Size: 223 B |
@ -1,4 +1,11 @@
|
||||
<svg version="1.1" viewBox="0 0 18 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg
|
||||
width="100%"
|
||||
className="icon"
|
||||
version="1.1"
|
||||
viewBox="0 0 18 16"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13.7929 6.3499L15.0178 6.29599C15.2308 6.24208 15.4438 6.02644 15.4438 5.75688V4.24737H2.23669C1.97041 4.24737 1.7574 4.03172 1.7574 3.81608C1.7574 3.54652 1.97041 3.33088 2.23669 3.33088H4.68639L6.39053 2.52221H1.49112C1.1716 2.52221 0.905325 2.79177 0.905325 3.11524V14.5444C0.905325 14.8679 1.1716 15.1374 1.49112 15.1374H14.858C15.1775 15.1374 15.4438 14.8679 15.4438 14.5444V11.9028C15.4438 11.5793 15.1775 11.3097 14.858 11.3097C14.2722 11.3097 13.6864 11.3097 13.0473 11.3097C12.2485 11.3097 11.6095 10.6628 11.6095 9.80022V7.80551C11.6095 6.45773 12.7278 6.3499 13.7929 6.3499ZM6.76331 3.33088H12.6213L11.503 1.06661L6.76331 3.33088ZM13.6331 3.33088H15.4438V3.11524C15.4438 2.79177 15.1775 2.52221 14.858 2.52221H13.2071L13.6331 3.33088ZM12.7811 1.60572H14.858C15.6568 1.60572 16.2959 2.30657 16.2959 3.11524C16.2959 3.97781 16.2959 4.8943 16.2959 5.75688C16.2959 5.97253 16.2959 6.13426 16.1893 6.3499H16.5089C17.3077 6.3499 18 6.99684 18 7.80551V9.80022C18 10.6089 17.3077 11.3097 16.5089 11.3097H16.1893C16.2959 11.4715 16.2959 11.6871 16.2959 11.9028V14.5444C16.2959 15.3531 15.6568 16 14.858 16H1.49112C0.692308 16 0 15.3531 0 14.5444V3.11524C0 2.30657 0.692308 1.60572 1.49112 1.60572H8.25444L11.5562 0.0422992C11.7692 -0.0655231 12.0355 0.0422992 12.142 0.257944L12.7811 1.60572ZM16.5089 7.26639C15.3373 7.26639 14.2189 7.26639 13.0473 7.26639C12.7278 7.26639 12.5148 7.48204 12.5148 7.80551V9.80022C12.5148 10.1237 12.7278 10.3932 13.0473 10.3932C14.2189 10.3932 15.3373 10.3932 16.5089 10.3932C16.8284 10.3932 17.0947 10.1237 17.0947 9.80022V7.80551C17.0947 7.48204 16.8284 7.26639 16.5089 7.26639Z"
|
||||
/>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@ -6,6 +6,7 @@ export { default as ArrowCircle } from 'components/common/Icons/ArrowCircle.svg'
|
||||
export { default as ArrowCircledTopRight } from 'components/common/Icons/ArrowCircledTopRight.svg'
|
||||
export { default as ArrowDownLine } from 'components/common/Icons/ArrowDownLine.svg'
|
||||
export { default as ArrowRight } from 'components/common/Icons/ArrowRight.svg'
|
||||
export { default as ArrowRightLine } from 'components/common/Icons/ArrowRightLine.svg'
|
||||
export { default as ArrowUpLine } from 'components/common/Icons/ArrowUpLine.svg'
|
||||
export { default as Chain } from 'components/common/Icons/Chain.svg'
|
||||
export { default as Check } from 'components/common/Icons/Check.svg'
|
||||
|
@ -23,17 +23,41 @@ interface Props {
|
||||
function IntroBackground(props: { bg: Props['bg'] }) {
|
||||
switch (props.bg) {
|
||||
case 'borrow':
|
||||
return <GridHole className='h-55 opacity-5' />
|
||||
return (
|
||||
<div className='absolute top-0 right-0 block w-140 opacity-5'>
|
||||
<GridHole />
|
||||
</div>
|
||||
)
|
||||
case 'lend':
|
||||
return <GridTire className='h-55 opacity-5' />
|
||||
return (
|
||||
<div className='absolute top-0 right-0 block w-180 opacity-5'>
|
||||
<GridTire />
|
||||
</div>
|
||||
)
|
||||
case 'farm':
|
||||
return <GridLandscape className='h-55 opacity-5' />
|
||||
return (
|
||||
<div className='absolute top-0 right-0 block w-140 opacity-5'>
|
||||
<GridLandscape />
|
||||
</div>
|
||||
)
|
||||
case 'hls-farm':
|
||||
return <GridWeb className='h-45 opacity-5' />
|
||||
return (
|
||||
<div className='absolute bottom-0 right-0 block w-140 opacity-10'>
|
||||
<GridWeb />
|
||||
</div>
|
||||
)
|
||||
case 'hls-staking':
|
||||
return <GridPlanet className='h-55 opacity-10' />
|
||||
return (
|
||||
<div className='absolute top-0 right-0 block w-110 opacity-10'>
|
||||
<GridPlanet />
|
||||
</div>
|
||||
)
|
||||
default:
|
||||
return <GridGlobe className='h-50 opacity-5' />
|
||||
return (
|
||||
<div className='absolute bottom-0 right-0 block w-3/4 md:w-120 opacity-5'>
|
||||
<GridGlobe />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +73,7 @@ export default function Intro(props: Props) {
|
||||
)}
|
||||
contentClassName='flex w-full h-full flex-col justify-between'
|
||||
>
|
||||
<div className='absolute inset-0 flex items-end justify-end w-full h-full text-white'>
|
||||
<div className='absolute inset-0 w-full h-full overflow-hidden text-white'>
|
||||
<IntroBackground bg={props.bg} />
|
||||
</div>
|
||||
<Tooltip
|
||||
|
@ -24,10 +24,12 @@ const SearchBar = (props: Props, ref: LegacyRef<HTMLDivElement>) => {
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
<Search width={14} height={14} className='mr-2.5 text-white' />
|
||||
<div className='w-3.5 h-3.5 mr-2.5 text-white'>
|
||||
<Search />
|
||||
</div>
|
||||
<input
|
||||
value={props.value}
|
||||
className='h-full w-full bg-transparent text-xs placeholder-white/50 outline-none'
|
||||
className='w-full h-full text-xs bg-transparent outline-none placeholder-white/50'
|
||||
placeholder={props.placeholder}
|
||||
onChange={(event) => onChange(event)}
|
||||
autoFocus={props.autoFocus}
|
||||
|
@ -6,7 +6,7 @@ export default function Settings() {
|
||||
return (
|
||||
<Button
|
||||
variant='solid'
|
||||
color='tertiary'
|
||||
color='secondary'
|
||||
className='w-16'
|
||||
leftIcon={<Gear />}
|
||||
onClick={() => useStore.setState({ settingsModal: true })}
|
||||
|
@ -12,7 +12,11 @@ interface Props<T> {
|
||||
type?: TableType
|
||||
}
|
||||
|
||||
function getBorderColor(type: TableType, row: AccountBalanceRow | AccountPerpRow) {
|
||||
function getBorderColor(
|
||||
type: TableType,
|
||||
row: AccountBalanceRow | AccountStrategyRow | AccountPerpRow,
|
||||
) {
|
||||
if (type === 'strategies') return ''
|
||||
if (type === 'balances') {
|
||||
const balancesRow = row as AccountBalanceRow
|
||||
return balancesRow.type === 'borrow' ? 'border-loss' : 'border-profit'
|
||||
@ -55,8 +59,8 @@ export default function Row<T>(props: Props<T>) {
|
||||
className={classNames(
|
||||
isSymbolOrName ? 'text-left' : 'text-right',
|
||||
spacingClassName ?? 'px-3 py-4',
|
||||
type && isSymbolOrName && 'border-l',
|
||||
type && getBorderColor(type, cell.row.original as any),
|
||||
type && type !== 'strategies' && isSymbolOrName && 'border-l',
|
||||
type && type !== 'strategies' && getBorderColor(type, cell.row.original as any),
|
||||
cell.column.columnDef.meta?.className,
|
||||
)}
|
||||
>
|
||||
|
@ -87,6 +87,14 @@ export default function Table<T>(props: Props<T>) {
|
||||
'align-center',
|
||||
)}
|
||||
>
|
||||
<Text
|
||||
tag='span'
|
||||
size='xs'
|
||||
className='flex items-center font-normal text-white/60'
|
||||
>
|
||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||
</Text>
|
||||
{header.column.getCanSort() && (
|
||||
<span className='w-5 h-5 my-auto text-white'>
|
||||
{header.column.getCanSort()
|
||||
? {
|
||||
@ -96,13 +104,7 @@ export default function Table<T>(props: Props<T>) {
|
||||
}[header.column.getIsSorted() as string] ?? null
|
||||
: null}
|
||||
</span>
|
||||
<Text
|
||||
tag='span'
|
||||
size='xs'
|
||||
className='flex items-center font-normal text-white/60'
|
||||
>
|
||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</th>
|
||||
)
|
||||
|
@ -33,7 +33,9 @@ export default function WarningMessages(props: Props) {
|
||||
type='warning'
|
||||
interactive
|
||||
>
|
||||
<ExclamationMarkTriangle width={24} className='text-warning' />
|
||||
<div className='w-6'>
|
||||
<ExclamationMarkTriangle className='text-warning' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,5 +1,3 @@
|
||||
import React from 'react'
|
||||
|
||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||
import Loading from 'components/common/Loading'
|
||||
|
||||
@ -13,7 +11,6 @@ export default function Apy(props: Props) {
|
||||
const { vault } = props
|
||||
|
||||
if (vault.apy === null) return <Loading />
|
||||
|
||||
return (
|
||||
<FormattedNumber
|
||||
amount={vault.apy ?? 0}
|
||||
|
@ -60,7 +60,7 @@ export default function ChainSelect() {
|
||||
<Button
|
||||
leftIcon={<ChainLogo chainID={chainConfig.id} className='w-4' />}
|
||||
iconClassName='w-5 h-5'
|
||||
color='tertiary'
|
||||
color='secondary'
|
||||
onClick={() => setShowMenu()}
|
||||
className={classNames('!p-0 w-8 flex items-center justify-center')}
|
||||
></Button>
|
||||
|
@ -85,7 +85,7 @@ export default function RewardsCenter() {
|
||||
<div className={'relative'}>
|
||||
<Button
|
||||
variant='solid'
|
||||
color='tertiary'
|
||||
color='secondary'
|
||||
leftIcon={<Logo />}
|
||||
onClick={() => {
|
||||
setShowRewardsCenter(!showRewardsCenter)
|
||||
|
52
src/components/portfolio/Account/Strategies.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React, { Suspense } from 'react'
|
||||
|
||||
import AccountStrategiesTable from 'components/account/AccountStrategiesTable'
|
||||
import Card from 'components/common/Card'
|
||||
import TableSkeleton from 'components/common/Table/TableSkeleton'
|
||||
import Text from 'components/common/Text'
|
||||
import useAccount from 'hooks/accounts/useAccount'
|
||||
|
||||
interface Props {
|
||||
accountId: string
|
||||
}
|
||||
|
||||
function Content(props: Props) {
|
||||
const { data: account } = useAccount(props.accountId, true)
|
||||
|
||||
if (!account || account?.vaults.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Skeleton>
|
||||
<AccountStrategiesTable account={account} hideCard />
|
||||
</Skeleton>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Strategies(props: Props) {
|
||||
return (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<Content {...props} />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
interface SkeletonProps {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
function Skeleton(props: SkeletonProps) {
|
||||
return (
|
||||
<div className='flex flex-wrap w-full gap-4'>
|
||||
<Text size='2xl'>Strategies</Text>
|
||||
<Card className='w-full bg-white/5'>
|
||||
{props.children ? (
|
||||
props.children
|
||||
) : (
|
||||
<TableSkeleton labels={['Strategy & Value', 'Size', 'APY']} rowCount={1} />
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -5,7 +5,9 @@ export default function PoweredByPyth() {
|
||||
return (
|
||||
<div className='flex items-center justify-end w-full gap-2 p-2'>
|
||||
<Text className='text-2xs-caps text-white/60'>powered by</Text>
|
||||
<PythLogoType className='h-6' />
|
||||
<div className='w-[71px]'>
|
||||
<PythLogoType />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export default function AssetSelectorPair(props: Props) {
|
||||
color='quaternary'
|
||||
variant='transparent'
|
||||
onClick={() => useStore.setState({ assetOverlayState: 'pair' })}
|
||||
className='flex items-center justify-between w-full py-5 bg-white/5'
|
||||
className='flex items-center justify-between w-full py-5 bg-white/10'
|
||||
>
|
||||
<Text size='sm' className='text-white/60'>
|
||||
<span className='text-white'>{buyAsset.symbol}</span>/{sellAsset.symbol}
|
||||
|
@ -51,7 +51,7 @@ export default function AssetSelectorSingle(props: Props) {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='grid-rows-auto grid grid-cols-[1fr_min-content_1fr] gap-y-2 bg-white/5 p-3 w-full'>
|
||||
<div className='grid-rows-auto grid grid-cols-[1fr_min-content_1fr] gap-y-2 bg-white/10 p-3 w-full'>
|
||||
<Text size='sm'>Buy</Text>
|
||||
<Text size='sm' className='col-start-3'>
|
||||
Sell
|
||||
|
@ -14,7 +14,7 @@ export default function TradeModule(props: Props) {
|
||||
<div className='row-span-2'>
|
||||
<div
|
||||
className={classNames(
|
||||
'max-h-[calc(100dvh-98px)] h-[980px] min-h-[830px]',
|
||||
'min-h-[850px]',
|
||||
'relative isolate max-w-full overflow-hidden rounded-base pb-4 z-30 flex flex-wrap flex-col justify-between',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
|
||||
)}
|
||||
|
@ -9,7 +9,8 @@ const enabledMarketAssets = useStore
|
||||
.chainConfig.assets.filter((asset) => asset.isEnabled && asset.isMarket)
|
||||
|
||||
export const DEFAULT_SETTINGS: Settings = {
|
||||
accountSummaryTabs: [true, true, false],
|
||||
accountSummaryTabs: [true, true, true, false],
|
||||
accountDetailsTabs: [true, true, true, true],
|
||||
reduceMotion: false,
|
||||
enableAutoLendGlobal: true,
|
||||
tradingPairSimple: {
|
||||
|
@ -2,6 +2,7 @@ export enum LocalStorageKeys {
|
||||
TRADING_PAIR_SIMPLE = 'tradingPairSimple',
|
||||
TRADING_PAIR_ADVANCED = 'tradingPairAdvanced',
|
||||
ACCOUNT_SUMMARY_TABS = 'accountSummaryTabs',
|
||||
ACCOUNT_DETAILS_TABS = 'accountDetailsTabs',
|
||||
DISPLAY_CURRENCY = 'displayCurrency',
|
||||
REDUCE_MOTION = 'reduceMotion',
|
||||
FAVORITE_ASSETS = 'favoriteAssets',
|
||||
|
@ -5,6 +5,7 @@ import ShareBar from 'components/common/ShareBar'
|
||||
import Balances from 'components/portfolio/Account/Balances'
|
||||
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
||||
import PerpPositions from 'components/portfolio/Account/PerpPositions'
|
||||
import Strategies from 'components/portfolio/Account/Strategies'
|
||||
import Summary from 'components/portfolio/Account/Summary'
|
||||
import useAccountId from 'hooks/useAccountId'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
@ -28,6 +29,7 @@ export default function PortfolioAccountPage() {
|
||||
<BreadCrumbs accountId={accountId} />
|
||||
<Summary accountId={accountId} />
|
||||
<Balances accountId={accountId} />
|
||||
{chainConfig.farm && <Strategies accountId={accountId} />}
|
||||
{chainConfig.perps && <PerpPositions accountId={accountId} />}
|
||||
<ShareBar text={`Have a look at Credit Account ${accountId} on @mars_protocol!`} />
|
||||
</div>
|
||||
|
@ -2,13 +2,13 @@ import { Head, Html, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html className='p-0 m-0' lang='en'>
|
||||
<Html className='p-0 m-0 scrollbar-hide' lang='en'>
|
||||
<Head>
|
||||
<script defer src='/charting_library/charting_library.standalone.js' />
|
||||
<script defer src='/datafeeds/udf/dist/bundle.js' />
|
||||
<script defer src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.js' />
|
||||
</Head>
|
||||
<body className='p-0 m-0 font-sans text-white cursor-default bg-body scrollbar-hide'>
|
||||
<body className='p-0 m-0 overflow-x-hidden font-sans text-white cursor-default bg-body scrollbar-hide'>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
@ -70,7 +70,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
<DesktopHeader />
|
||||
<main
|
||||
className={classNames(
|
||||
'lg:min-h-[calc(100dvh-73px)]',
|
||||
'lg:min-h-[calc(100dvh-81px)]',
|
||||
'lg:mt-[73px]',
|
||||
'flex',
|
||||
'min-h-screen gap-6 px-4 py-6 w-full relative',
|
||||
@ -78,8 +78,8 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
address &&
|
||||
isFullWidth &&
|
||||
accountId &&
|
||||
(accountDetailsExpanded ? 'pr-118' : 'pr-24'),
|
||||
!reduceMotion && isFullWidth && 'transition-all duration-300',
|
||||
(accountDetailsExpanded ? 'pr-102' : 'pr-24'),
|
||||
!reduceMotion && isFullWidth && 'transition-all duration-500',
|
||||
'justify-center',
|
||||
focusComponent && 'items-center',
|
||||
isMobile && 'items-start',
|
||||
|
@ -61,3 +61,13 @@
|
||||
table tr:last-child td {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.rounded-full.overflow-hidden svg {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
11
src/types/interfaces/account.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
type PositionType = 'deposit' | 'borrow' | 'lend' | 'vault' | 'perp'
|
||||
type TableType = 'balances' | 'perps'
|
||||
type TableType = 'balances' | 'strategies' | 'perps'
|
||||
|
||||
interface Account {
|
||||
id: string
|
||||
@ -29,6 +29,15 @@ interface AccountBalanceRow {
|
||||
amountChange: BigNumber
|
||||
}
|
||||
|
||||
interface AccountStrategyRow {
|
||||
apy: number
|
||||
name: string
|
||||
denom: string
|
||||
amount: BNCoin[]
|
||||
value: string
|
||||
amountChange: BNCoin[]
|
||||
}
|
||||
|
||||
interface AccountPerpRow extends PerpsPosition {
|
||||
amount: BigNumber
|
||||
symbol: string
|
||||
|
1
src/types/interfaces/store/settings.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
interface Settings {
|
||||
accountSummaryTabs: boolean[]
|
||||
accountDetailsTabs: boolean[]
|
||||
displayCurrency: string
|
||||
reduceMotion: boolean
|
||||
tradingPairSimple: TradingPair
|
||||
|
@ -117,7 +117,7 @@ module.exports = {
|
||||
info: '#FDB022',
|
||||
'info-bg': '#FEDB7C',
|
||||
input: '#282a33',
|
||||
loss: '#f96363',
|
||||
loss: '#E62E05',
|
||||
mars: '#a03b45',
|
||||
'martian-red': '#FF645F',
|
||||
osmo: '#9f1ab9',
|
||||
@ -127,7 +127,7 @@ module.exports = {
|
||||
'orb-secondary-hls': '#a03b45',
|
||||
'orb-tertiary': '#ff00c7',
|
||||
'orb-tertiary-hls': '#FB9562',
|
||||
profit: '#41a4a9',
|
||||
profit: '#4CA30D',
|
||||
primary: '#FF625E',
|
||||
secondary: '#FB9562',
|
||||
success: '#32D583',
|
||||
@ -176,6 +176,7 @@ module.exports = {
|
||||
45: '180px',
|
||||
50: '200px',
|
||||
55: '220px',
|
||||
75: '300px',
|
||||
},
|
||||
hueRotate: {
|
||||
'-82': '-82deg',
|
||||
@ -235,6 +236,7 @@ module.exports = {
|
||||
10: '40px',
|
||||
14: '56px',
|
||||
30.5: '122px',
|
||||
75: '300px',
|
||||
},
|
||||
maxWidth: {
|
||||
content: '1024px',
|
||||
@ -265,8 +267,12 @@ module.exports = {
|
||||
6.5: '26px',
|
||||
24: '96px',
|
||||
35: '140px',
|
||||
70: '280px',
|
||||
74: '296px',
|
||||
80: '320px',
|
||||
90: '360px',
|
||||
98: '392px',
|
||||
102: '408px',
|
||||
118: '472px',
|
||||
},
|
||||
transitionDuration: {
|
||||
@ -284,17 +290,21 @@ module.exports = {
|
||||
13: '52px',
|
||||
15: '60px',
|
||||
18: '72px',
|
||||
25: '100px',
|
||||
29: '116px',
|
||||
30: '120px',
|
||||
35: '140px',
|
||||
40: '160px',
|
||||
50: '200px',
|
||||
60: '240px',
|
||||
90: '360px',
|
||||
92.5: '370px',
|
||||
93.5: '374px',
|
||||
94: '376px',
|
||||
100: '400px',
|
||||
110: '440px',
|
||||
120: '480px',
|
||||
140: '560px',
|
||||
180: '720px',
|
||||
},
|
||||
zIndex: {
|
||||
1: '1',
|
||||
|