Compare commits

...

1 Commits

Author SHA1 Message Date
Bob van der Helm
03be48c69a
margin slider variations 2024-01-15 16:29:46 +01:00
7 changed files with 52 additions and 25 deletions

View File

@ -1,17 +1,19 @@
import classNames from 'classnames'
import { VerticalThreeLine } from 'components/Icons'
import { MarginSliderType } from 'components/MarginSlider'
import { formatValue } from 'utils/formatters'
interface Props {
value: number
marginThreshold?: number
max: number
type: MarginSliderType
}
const THUMB_WIDTH = 33
function InputOverlay({ max, value, marginThreshold }: Props) {
function InputOverlay({ max, value, marginThreshold, type }: Props) {
const thumbPosPercent = max === 0 ? 0 : 100 / (max / value)
const thumbPadRight = (thumbPosPercent / 100) * THUMB_WIDTH
const markPosPercent = 100 / (max / (marginThreshold ?? 1))
@ -21,12 +23,16 @@ function InputOverlay({ max, value, marginThreshold }: Props) {
return (
<>
<div
className='absolute flex-1 flex w-full justify-evenly bg-no-repeat top-[8.5px] pointer-events-none pt-[2.5px] pb-[2.5px] rounded-lg'
style={{
backgroundImage:
'linear-gradient(270deg, rgba(255, 97, 141, 0.89) 0%, rgba(66, 58, 70, 0.05) 100%)',
backgroundSize: `${thumbPosPercent}%`,
}}
className={classNames(
'absolute flex-1 flex w-full justify-evenly top-[8.5px] pointer-events-none pt-[2.5px] pb-[2.5px] rounded-lg',
'before:absolute',
'before:top-0 before:bottom-0 before:right-0 before:left-0',
'slider-mask',
type === 'long' && 'before:gradient-slider-green',
type === 'short' && 'before:gradient-slider-red',
type === 'trade' && 'before:gradient-slider-pink',
)}
style={{ width: `${thumbPosPercent}%` }}
>
{Array.from(Array(9).keys()).map((i) => (
<div key={`mark-${i}`} className='w-1 h-1 bg-black rounded-full bg-opacity-30' />
@ -47,14 +53,21 @@ function InputOverlay({ max, value, marginThreshold }: Props) {
</div>
<div
className={classNames(
'w-[33px] h-4 absolute text-[10px] top-[5px]',
'w-[36px] h-4.5 absolute text-[10px] top-[3.5px]',
'pointer-events-none text-center font-bold',
'bg-pink shadow-md border-b-0 border-1',
'border-solid rounded-sm backdrop-blur-sm border-white/10',
'border rounded-sm border-white/20',
type === 'long' && 'bg-green',
type === 'short' && 'bg-error',
type === 'trade' && 'bg-pink',
)}
style={{ left: `calc(${thumbPosPercent}% - ${thumbPadRight}px)` }}
>
{formatValue(value, { maxDecimals: 2, abbreviated: true, rounded: true })}
{formatValue(value, {
maxDecimals: 2,
abbreviated: true,
rounded: true,
suffix: type !== 'trade' ? 'x' : '',
})}
</div>
</>
)

View File

@ -1,13 +1,14 @@
import classNames from 'classnames'
import { ChangeEvent, useCallback } from 'react'
import InputOverlay from 'components/RangeInput/InputOverlay'
import InputOverlay from 'components/MarginSlider/InputOverlay'
const LEFT_MARGIN = 5
type Props = {
max: number
value: number
type: MarginSliderType
disabled?: boolean
marginThreshold?: number
wrapperClassName?: string
@ -15,8 +16,10 @@ type Props = {
onBlur?: () => void
}
function RangeInput(props: Props) {
const { value, max, onChange, wrapperClassName, disabled, marginThreshold, onBlur } = props
export type MarginSliderType = 'trade' | 'long' | 'short'
function MarginSlider(props: Props) {
const { value, max, onChange, wrapperClassName, disabled, marginThreshold, onBlur, type } = props
const handleOnChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
@ -52,7 +55,7 @@ function RangeInput(props: Props) {
onChange={handleOnChange}
onBlur={onBlur}
/>
<InputOverlay max={max} marginThreshold={marginThreshold} value={value} />
<InputOverlay max={max} marginThreshold={marginThreshold} value={value} type={type} />
</div>
<div className={'flex w-full justify-between text-xs text-opacity-50 text-white font-bold'}>
<span>{markPosPercent > LEFT_MARGIN ? 0 : ''}</span>
@ -62,4 +65,4 @@ function RangeInput(props: Props) {
)
}
export default RangeInput
export default MarginSlider

View File

@ -2,11 +2,11 @@ import classNames from 'classnames'
import { useState } from 'react'
import { Cross } from 'components/Icons'
import MarginSlider from 'components/MarginSlider'
import { LeverageButtons } from 'components/Perps/Module/LeverageButtons'
import { Or } from 'components/Perps/Module/Or'
import usePerpsManageModule from 'components/Perps/Module/PerpsManageModule/usePerpsManageModule'
import PerpsSummary from 'components/Perps/Module/Summary'
import RangeInput from 'components/RangeInput'
import { Spacer } from 'components/Spacer'
import Text from 'components/Text'
import AssetAmountInput from 'components/Trade/TradeModule/SwapForm/AssetAmountInput'
@ -56,7 +56,7 @@ export function PerpsManageModule() {
/>
<Or />
<Text size='sm'>Position Leverage</Text>
<RangeInput max={0} value={0} onChange={() => {}} />
<MarginSlider max={0} value={0} onChange={() => {}} type={tradeDirection || 'long'} />
<LeverageButtons />
<Spacer />
<PerpsSummary

View File

@ -1,10 +1,10 @@
import { useState } from 'react'
import Card from 'components/Card'
import MarginSlider from 'components/MarginSlider'
import { LeverageButtons } from 'components/Perps/Module/LeverageButtons'
import { Or } from 'components/Perps/Module/Or'
import PerpsSummary from 'components/Perps/Module/Summary'
import RangeInput from 'components/RangeInput'
import { Spacer } from 'components/Spacer'
import Text from 'components/Text'
import AssetSelectorPerps from 'components/Trade/TradeModule/AssetSelector/AssetSelectorPerps'
@ -46,7 +46,7 @@ export function PerpsModule() {
/>
<Or />
<Text size='sm'>Position Leverage</Text>
<RangeInput max={0} value={0} onChange={() => {}} />
<MarginSlider max={10} value={leverage} onChange={setLeverage} type={tradeDirection} />
<LeverageButtons />
<Spacer />
<PerpsSummary

View File

@ -31,9 +31,9 @@ export default function FundingRate() {
if (!market) return '-'
return (
<div className='flex gap-1'>
<div className='flex gap-1 items-center'>
<FormattedNumber
className='text-sm inline'
className='text-xs inline'
amount={fundingRate.toNumber()}
options={{ minDecimals: 6, maxDecimals: 6, suffix: '%' }}
/>
@ -49,7 +49,7 @@ export default function FundingRate() {
setInterval(key as Interval)
toggleShow(false)
}}
className='w-full text-left px-4 py-2 flex gap-2 items-center hover:bg-white/5 [&:not(:last-child)]:border-b border-white/10'
className='w-full text-center px-3 py-1.5 flex gap-2 items-center hover:bg-white/5 text-[10px]'
>
{key}
</button>

View File

@ -5,7 +5,7 @@ import estimateExactIn from 'api/swap/estimateExactIn'
import AvailableLiquidityMessage from 'components/AvailableLiquidityMessage'
import DepositCapMessage from 'components/DepositCapMessage'
import Divider from 'components/Divider'
import RangeInput from 'components/RangeInput'
import MarginSlider from 'components/MarginSlider'
import Text from 'components/Text'
import AssetSelectorPair from 'components/Trade/TradeModule/AssetSelector/AssetSelectorPair'
import AssetSelectorSingle from 'components/Trade/TradeModule/AssetSelector/AssetSelectorSingle'
@ -393,7 +393,7 @@ export default function SwapForm(props: Props) {
)}
{!isAdvanced && <Divider />}
<RangeInput
<MarginSlider
disabled={isConfirming || maxOutputAmountEstimation.isZero()}
onChange={handleRangeInputChange}
value={outputAssetAmount.shiftedBy(-outputAsset.decimals).toNumber()}
@ -403,6 +403,7 @@ export default function SwapForm(props: Props) {
? outputSideMarginThreshold.shiftedBy(-outputAsset.decimals).toNumber()
: undefined
}
type='trade'
/>
<DepositCapMessage
action='buy'

View File

@ -399,6 +399,16 @@ module.exports = {
'.gradient-slider-4': {
background: 'linear-gradient(to right, #961293, #B3419B)',
},
'.gradient-slider-pink': {
background:
'linear-gradient(270deg, rgba(255, 97, 141, 0.89) 0%, rgba(66, 58, 70, 0.05) 100%)',
},
'.gradient-slider-green': {
background: 'linear-gradient(270deg, #61FF71E2 0%, #423A460D 100%)',
},
'.gradient-slider-red': {
background: 'linear-gradient(270deg, #F04438E2 0%, #423A460D 100%)',
},
'.gradient-tooltip': {
background:
'linear-gradient(77.47deg, rgba(20, 24, 57, 0.9) 11.58%, rgba(34, 16, 57, 0.9) 93.89%)',