From c0d62cd8f09974a0bf7f7a0cb6b6f284a037db4f Mon Sep 17 00:00:00 2001 From: Yusuf Seyrek Date: Fri, 7 Jul 2023 18:19:00 +0300 Subject: [PATCH] feat: trade range input implementation (#287) --- .../Modals/Unlock/UnlockModal.test.tsx | 4 +- src/components/Icons/VerticalThreeLine.svg | 3 + src/components/Icons/index.ts | 1 + src/components/RangeInput/InputOverlay.tsx | 69 ++++++++++++++++ src/components/RangeInput/index.tsx | 80 +++++++++++++++++++ src/components/Trade/TradeModule/index.tsx | 11 ++- tailwind.config.js | 1 + 7 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 src/components/Icons/VerticalThreeLine.svg create mode 100644 src/components/RangeInput/InputOverlay.tsx create mode 100644 src/components/RangeInput/index.tsx diff --git a/__tests__/components/Modals/Unlock/UnlockModal.test.tsx b/__tests__/components/Modals/Unlock/UnlockModal.test.tsx index 023b363a..af7d2335 100644 --- a/__tests__/components/Modals/Unlock/UnlockModal.test.tsx +++ b/__tests__/components/Modals/Unlock/UnlockModal.test.tsx @@ -30,8 +30,8 @@ const mockedDepositedVault: DepositedVault = { }, cap: { denom: 'mock', - max: 10, - used: 1, + max: BN(10), + used: BN(1), }, } diff --git a/src/components/Icons/VerticalThreeLine.svg b/src/components/Icons/VerticalThreeLine.svg new file mode 100644 index 00000000..9c9d7c31 --- /dev/null +++ b/src/components/Icons/VerticalThreeLine.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icons/index.ts b/src/components/Icons/index.ts index 7c3880f9..1cb50ee6 100644 --- a/src/components/Icons/index.ts +++ b/src/components/Icons/index.ts @@ -41,4 +41,5 @@ export { default as Subtract } from 'components/Icons/Subtract.svg' export { default as SwapIcon } from 'components/Icons/SwapIcon.svg' export { default as TrashBin } from 'components/Icons/TrashBin.svg' export { default as Wallet } from 'components/Icons/Wallet.svg' +export { default as VerticalThreeLine } from 'components/Icons/VerticalThreeLine.svg' // @endindex diff --git a/src/components/RangeInput/InputOverlay.tsx b/src/components/RangeInput/InputOverlay.tsx new file mode 100644 index 00000000..c99dc1d5 --- /dev/null +++ b/src/components/RangeInput/InputOverlay.tsx @@ -0,0 +1,69 @@ +import { VerticalThreeLine } from 'components/Icons' + +interface Props { + value: number + marginThreshold?: number + max: number +} + +function InputOverlay({ max, value, marginThreshold }: Props) { + // 33 is the thumb width + const thumbPosPercent = 100 / (max / value) + const thumbPadRight = (thumbPosPercent / 100) * 33 + const markPosPercent = 100 / (max / (marginThreshold ?? 1)) + const markPadRight = (markPosPercent / 100) * 33 + const hasPastMarginThreshold = marginThreshold ? value >= marginThreshold : undefined + + return ( + <> +
+ {Array.from(Array(9).keys()).map((i) => ( +
+ ))} + {marginThreshold && ( +
+
+
+ +
Margin
+
+
+ )} +
+
+ {value} +
+ + ) +} + +const className = { + inputThumbOverlay: ` + w-[33px] h-4 absolute text-[10px] top-[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 + `, + mark: `w-1 h-1 bg-black rounded-full bg-opacity-30`, + marginMark: `w-1 h-1 bg-white rounded-full`, + marginMarkContainer: 'absolute w-[33px] flex justify-center', + marginMarkOverlay: 'absolute top-2.5 flex-col text-xs w-[33px] items-center flex', + marksWrapper: `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`, +} + +export default InputOverlay diff --git a/src/components/RangeInput/index.tsx b/src/components/RangeInput/index.tsx new file mode 100644 index 00000000..fcd01c41 --- /dev/null +++ b/src/components/RangeInput/index.tsx @@ -0,0 +1,80 @@ +import { ChangeEvent, useCallback } from 'react' +import classNames from 'classnames' + +import InputOverlay from 'components/RangeInput/InputOverlay' + +type Props = { + value: number + onChange: (value: number) => void + wrapperClassName?: string + disabled?: boolean + max: number + marginThreshold?: number +} + +function RangeInput(props: Props) { + const { value, max, onChange, wrapperClassName, disabled, marginThreshold } = props + + const handleOnChange = useCallback( + (event: ChangeEvent) => { + onChange(parseInt(event.target.value)) + }, + [onChange], + ) + + return ( +
+
+ + +
+
+ 0 + {max} +
+
+ ) +} + +const className = { + containerDefault: 'relative min-h-3 w-full transition-opacity', + disabled: 'pointer-events-none opacity-50', + legendWrapper: 'flex w-full justify-between text-xs text-opacity-50 text-white font-bold', + inputWrapper: 'relative h-[30px]', + input: ` + relative w-full appearance-none bg-transparent cursor-pointer + + [&::-webkit-slider-runnable-track]:bg-white + [&::-webkit-slider-runnable-track]:bg-opacity-20 + [&::-webkit-slider-runnable-track]:h-[9px] + [&::-webkit-slider-runnable-track]:rounded-lg + + [&::-moz-range-track]:bg-white + [&::-moz-range-track]:bg-opacity-20 + [&::-moz-range-track]:h-1 + [&::-moz-range-track]:pb-[5px] + [&::-moz-range-track]:rounded-lg + + [&::-webkit-slider-thumb]:appearance-none + [&::-webkit-slider-thumb]:-mt-1 + [&::-webkit-slider-thumb]:w-[33px] + [&::-webkit-slider-thumb]:h-4 + + [&::-moz-range-thumb]:appearance-none + [&::-moz-range-thumb]:opacity-0 + [&::-moz-range-thumb]:w-[33px] + [&::-moz-range-thumb]:h-4 + `, +} + +export default RangeInput diff --git a/src/components/Trade/TradeModule/index.tsx b/src/components/Trade/TradeModule/index.tsx index d3e85edb..d7b478d3 100644 --- a/src/components/Trade/TradeModule/index.tsx +++ b/src/components/Trade/TradeModule/index.tsx @@ -1,11 +1,12 @@ +import { useState } from 'react' import { useParams } from 'react-router-dom' import classNames from 'classnames' import Loading from 'components/Loading' import Text from 'components/Text' import Divider from 'components/Divider' - -import AssetSelector from './AssetSelector/AssetSelector' +import RangeInput from 'components/RangeInput' +import AssetSelector from 'components/Trade/TradeModule/AssetSelector/AssetSelector' function Content() { const params = useParams() @@ -25,6 +26,8 @@ function Fallback() { } export default function TradeModule() { + const [value, setValue] = useState(0) + return (
+ +
+ +
) } diff --git a/tailwind.config.js b/tailwind.config.js index 22ec4af1..12aeeb3d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -102,6 +102,7 @@ module.exports = { warning: '#F79009', 'warning-bg': '#FEC84B', white: '#FFF', + pink: '#de587f', }, fontFamily: { sans: ['Inter', 'sans-serif'],