Commit eeb258eb authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

improvement(Add): skeleton UI with dummy state (#29)

* start add liquidity

* update add state, add input UI

* basic add skeleton with dummy state

* refactor with preview steps on add
parent ab1538b1
...@@ -87,5 +87,28 @@ ...@@ -87,5 +87,28 @@
"forAtLeast": "for at least ", "forAtLeast": "for at least ",
"brokenToken": "The selected token is not compatible with Uniswap V1. Adding liquidity will result in locked funds.", "brokenToken": "The selected token is not compatible with Uniswap V1. Adding liquidity will result in locked funds.",
"toleranceExplanation": "Lowering this limit decreases your risk of frontrunning. However, this makes more likely that your transaction will fail due to normal price movements.", "toleranceExplanation": "Lowering this limit decreases your risk of frontrunning. However, this makes more likely that your transaction will fail due to normal price movements.",
"tokenSearchPlaceholder": "Search name or paste address" "tokenSearchPlaceholder": "Search name or paste address",
"selectFee": "Select Fee",
"selectLiquidityRange": "Select liquidity range",
"selectPool": "Select Fee Pool",
"inputTokens": "Input Tokens",
"fee": "fee",
"setLimits": "Set Limits",
"percent": "Percent",
"rate": "Rate",
"currentRate": "Current {{label}} Rate:",
"inactiveRangeWarning": "Your position will not be active or earn fees until the selected rates come into range.",
"invalidRangeWarning": "Invalid Range",
"connectWallet": "Connect Wallet",
"unsupportedAsset": "Unsupported Asset",
"feePool": "Fee Pool",
"rebalanceMessage": "Your underlying tokens will be automatically rebalanced when the rate of the pool changes and may be different when you withdraw the position.",
"addEarnHelper": "You will earn fees from trades proportional to your share of the pool.",
"learnMoreAboutFess": " Learn more about earning fees.",
"selectAPool": "Select a pool to provide liquidity to.",
"poolType": "Select a pool type based on your preferred liquidity provider fee.",
"rangeWarning": "Your liquidity will only be active and earning fees when the rate of the pool is within this price range.",
"chooseLiquidityAmount": "Choose an amount of tokens to open this liquidity position. If you don’t have enough tokens you can trade for them with a Swap.",
"selectPriceLimits": "Select Price Limits",
"inputTokenDynamic": "Input {{label}}"
} }
...@@ -3,7 +3,7 @@ import styled from 'styled-components' ...@@ -3,7 +3,7 @@ import styled from 'styled-components'
import { darken, lighten } from 'polished' import { darken, lighten } from 'polished'
import { RowBetween } from '../Row' import { RowBetween } from '../Row'
import { ChevronDown } from 'react-feather' import { ChevronDown, Check } from 'react-feather'
import { Button as RebassButton, ButtonProps } from 'rebass/styled-components' import { Button as RebassButton, ButtonProps } from 'rebass/styled-components'
const Base = styled(RebassButton)<{ const Base = styled(RebassButton)<{
...@@ -221,6 +221,26 @@ export const ButtonEmpty = styled(Base)` ...@@ -221,6 +221,26 @@ export const ButtonEmpty = styled(Base)`
} }
` `
export const ButtonText = styled(Base)`
padding: 0;
width: fit-content;
background: none;
&:focus {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
text-decoration: underline;
}
&:hover {
text-decoration: underline;
}
&:active {
text-decoration: underline;
}
&:disabled {
opacity: 50%;
cursor: auto;
}
`
export const ButtonWhite = styled(Base)` export const ButtonWhite = styled(Base)`
border: 1px solid #edeef2; border: 1px solid #edeef2;
background-color: ${({ theme }) => theme.bg1}; background-color: ${({ theme }) => theme.bg1};
...@@ -337,3 +357,48 @@ export function ButtonRadio({ active, ...rest }: { active?: boolean } & ButtonPr ...@@ -337,3 +357,48 @@ export function ButtonRadio({ active, ...rest }: { active?: boolean } & ButtonPr
return <ButtonPrimary {...rest} /> return <ButtonPrimary {...rest} />
} }
} }
const ActiveOutlined = styled(ButtonOutlined)`
border: 1px solid;
border-color: ${({ theme }) => theme.primary1};
`
const Circle = styled.div`
height: 20px;
width: 20px;
border-radius: 50%;
background-color: ${({ theme }) => theme.primary1};
display: flex;
align-items: center;
justify-content: center;
`
const CheckboxWrapper = styled.div`
width: 30px;
padding: 0 10px;
`
export function ButtonRadioChecked({ active = false, children, ...rest }: { active?: boolean } & ButtonProps) {
if (!active) {
return (
<ButtonOutlined borderRadius="12px" padding="12px 8px" {...rest}>
{<RowBetween>{children}</RowBetween>}
</ButtonOutlined>
)
} else {
return (
<ActiveOutlined {...rest} padding="12px 8px" borderRadius="12px">
{
<RowBetween>
{children}
<CheckboxWrapper>
<Circle>
<Check size={13} />
</Circle>
</CheckboxWrapper>
</RowBetween>
}
</ActiveOutlined>
)
}
}
import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { CardProps, Text } from 'rebass'
import { Box } from 'rebass/styled-components' import { Box } from 'rebass/styled-components'
const Card = styled(Box)<{ width?: string; padding?: string; border?: string; borderRadius?: string }>` const Card = styled(Box)<{ width?: string; padding?: string; border?: string; borderRadius?: string }>`
...@@ -26,13 +24,17 @@ export const GreyCard = styled(Card)` ...@@ -26,13 +24,17 @@ export const GreyCard = styled(Card)`
background-color: ${({ theme }) => theme.bg3}; background-color: ${({ theme }) => theme.bg3};
` `
export const DarkGreyCard = styled(Card)`
background-color: ${({ theme }) => theme.bg2};
`
export const OutlineCard = styled(Card)` export const OutlineCard = styled(Card)`
border: 1px solid ${({ theme }) => theme.bg3}; border: 1px solid ${({ theme }) => theme.bg3};
` `
export const YellowCard = styled(Card)` export const YellowCard = styled(Card)`
background-color: rgba(243, 132, 30, 0.05); background-color: rgba(243, 132, 30, 0.05);
color: ${({ theme }) => theme.yellow2}; color: ${({ theme }) => theme.yellow3};
font-weight: 500; font-weight: 500;
` `
...@@ -42,19 +44,9 @@ export const PinkCard = styled(Card)` ...@@ -42,19 +44,9 @@ export const PinkCard = styled(Card)`
font-weight: 500; font-weight: 500;
` `
const BlueCardStyled = styled(Card)` export const BlueCard = styled(Card)`
background-color: ${({ theme }) => theme.primary5}; background-color: ${({ theme }) => theme.primary5};
color: ${({ theme }) => theme.primary1}; color: ${({ theme }) => theme.blue2};
border-radius: 12px; border-radius: 12px;
width: fit-content; width: fit-content;
` `
export const BlueCard = ({ children }: CardProps) => {
return (
<BlueCardStyled>
<Text fontWeight={500} color="#2172E5">
{children}
</Text>
</BlueCardStyled>
)
}
...@@ -6,7 +6,7 @@ import { useCurrencyBalance } from '../../state/wallet/hooks' ...@@ -6,7 +6,7 @@ import { useCurrencyBalance } from '../../state/wallet/hooks'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal' import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
import CurrencyLogo from '../CurrencyLogo' import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo' import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween } from '../Row' import { RowBetween, RowFixed } from '../Row'
import { TYPE } from '../../theme' import { TYPE } from '../../theme'
import { Input as NumericalInput } from '../NumericalInput' import { Input as NumericalInput } from '../NumericalInput'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg' import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
...@@ -15,15 +15,24 @@ import { useActiveWeb3React } from '../../hooks' ...@@ -15,15 +15,24 @@ import { useActiveWeb3React } from '../../hooks'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useTheme from '../../hooks/useTheme' import useTheme from '../../hooks/useTheme'
const InputRow = styled.div<{ selected: boolean }>` const InputPanel = styled.div<{ hideInput?: boolean }>`
${({ theme }) => theme.flexRowNoWrap} ${({ theme }) => theme.flexColumnNoWrap}
align-items: center; position: relative;
padding: ${({ selected }) => (selected ? '0.75rem 0.5rem 0.75rem 1rem' : '0.75rem 0.75rem 0.75rem 1rem')}; border-radius: ${({ hideInput }) => (hideInput ? '12px' : '20px')};
background-color: ${({ theme }) => theme.bg2};
z-index: 1;
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
`
const Container = styled.div<{ hideInput: boolean }>`
border-radius: ${({ hideInput }) => (hideInput ? '12px' : '20px')};
border: 1px solid ${({ theme }) => theme.bg2};
background-color: ${({ theme }) => theme.bg1};
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
` `
const CurrencySelect = styled.button<{ selected: boolean }>` const CurrencySelect = styled.button<{ selected: boolean; hideInput?: boolean }>`
align-items: center; align-items: center;
height: 2.2rem;
font-size: 20px; font-size: 20px;
font-weight: 500; font-weight: 500;
background-color: ${({ selected, theme }) => (selected ? theme.bg1 : theme.primary1)}; background-color: ${({ selected, theme }) => (selected ? theme.bg1 : theme.primary1)};
...@@ -34,7 +43,9 @@ const CurrencySelect = styled.button<{ selected: boolean }>` ...@@ -34,7 +43,9 @@ const CurrencySelect = styled.button<{ selected: boolean }>`
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
border: none; border: none;
padding: 0 0.5rem;
height: ${({ hideInput }) => (hideInput ? '2.8rem' : '2.2rem')};
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
:focus, :focus,
:hover { :hover {
...@@ -42,13 +53,19 @@ const CurrencySelect = styled.button<{ selected: boolean }>` ...@@ -42,13 +53,19 @@ const CurrencySelect = styled.button<{ selected: boolean }>`
} }
` `
const InputRow = styled.div<{ selected: boolean }>`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
padding: ${({ selected }) => (selected ? '0.75rem 0.5rem 0.75rem 1rem' : '0.75rem 0.75rem 0.75rem 1rem')};
`
const LabelRow = styled.div` const LabelRow = styled.div`
${({ theme }) => theme.flexRowNoWrap} ${({ theme }) => theme.flexRowNoWrap}
align-items: center; align-items: center;
color: ${({ theme }) => theme.text1}; color: ${({ theme }) => theme.text1};
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1rem; line-height: 1rem;
padding: 0.75rem 1rem 0 1rem; padding: 0rem 1rem 0.75rem 1rem;
span:hover { span:hover {
cursor: pointer; cursor: pointer;
color: ${({ theme }) => darken(0.2, theme.text2)}; color: ${({ theme }) => darken(0.2, theme.text2)};
...@@ -71,20 +88,6 @@ const StyledDropDown = styled(DropDown)<{ selected: boolean }>` ...@@ -71,20 +88,6 @@ const StyledDropDown = styled(DropDown)<{ selected: boolean }>`
} }
` `
const InputPanel = styled.div<{ hideInput?: boolean }>`
${({ theme }) => theme.flexColumnNoWrap}
position: relative;
border-radius: ${({ hideInput }) => (hideInput ? '8px' : '20px')};
background-color: ${({ theme }) => theme.bg2};
z-index: 1;
`
const Container = styled.div<{ hideInput: boolean }>`
border-radius: ${({ hideInput }) => (hideInput ? '8px' : '20px')};
border: 1px solid ${({ theme }) => theme.bg2};
background-color: ${({ theme }) => theme.bg1};
`
const StyledTokenName = styled.span<{ active?: boolean }>` const StyledTokenName = styled.span<{ active?: boolean }>`
${({ active }) => (active ? ' margin: 0 0.25rem 0 0.75rem;' : ' margin: 0 0.25rem 0 0.25rem;')} ${({ active }) => (active ? ' margin: 0 0.25rem 0 0.75rem;' : ' margin: 0 0.25rem 0 0.25rem;')}
font-size: ${({ active }) => (active ? '20px' : '16px')}; font-size: ${({ active }) => (active ? '20px' : '16px')};
...@@ -148,6 +151,7 @@ export default function CurrencyInputPanel({ ...@@ -148,6 +151,7 @@ export default function CurrencyInputPanel({
id, id,
showCommonBases, showCommonBases,
customBalanceText, customBalanceText,
...rest
}: CurrencyInputPanelProps) { }: CurrencyInputPanelProps) {
const { t } = useTranslation() const { t } = useTranslation()
...@@ -161,30 +165,8 @@ export default function CurrencyInputPanel({ ...@@ -161,30 +165,8 @@ export default function CurrencyInputPanel({
}, [setModalOpen]) }, [setModalOpen])
return ( return (
<InputPanel id={id}> <InputPanel id={id} hideInput={hideInput} {...rest}>
<Container hideInput={hideInput}> <Container hideInput={hideInput}>
{!hideInput && (
<LabelRow>
<RowBetween>
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
{label}
</TYPE.body>
{account && (
<TYPE.body
onClick={onMax}
color={theme.text2}
fontWeight={500}
fontSize={14}
style={{ display: 'inline', cursor: 'pointer' }}
>
{!hideBalance && !!currency && selectedCurrencyBalance
? (customBalanceText ?? 'Balance: ') + selectedCurrencyBalance?.toSignificant(6)
: ' -'}
</TYPE.body>
)}
</RowBetween>
</LabelRow>
)}
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={disableCurrencySelect}> <InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={disableCurrencySelect}>
{!hideInput && ( {!hideInput && (
<> <>
...@@ -202,6 +184,7 @@ export default function CurrencyInputPanel({ ...@@ -202,6 +184,7 @@ export default function CurrencyInputPanel({
)} )}
<CurrencySelect <CurrencySelect
selected={!!currency} selected={!!currency}
hideInput={hideInput}
className="open-currency-select-button" className="open-currency-select-button"
onClick={() => { onClick={() => {
if (!disableCurrencySelect) { if (!disableCurrencySelect) {
...@@ -210,28 +193,52 @@ export default function CurrencyInputPanel({ ...@@ -210,28 +193,52 @@ export default function CurrencyInputPanel({
}} }}
> >
<Aligner> <Aligner>
{pair ? ( <RowFixed>
<DoubleCurrencyLogo currency0={pair.token0} currency1={pair.token1} size={24} margin={true} /> {pair ? (
) : currency ? ( <DoubleCurrencyLogo currency0={pair.token0} currency1={pair.token1} size={24} margin={true} />
<CurrencyLogo currency={currency} size={'24px'} /> ) : currency ? (
) : null} <CurrencyLogo currency={currency} size={'24px'} />
{pair ? ( ) : null}
<StyledTokenName className="pair-name-container"> {pair ? (
{pair?.token0.symbol}:{pair?.token1.symbol} <StyledTokenName className="pair-name-container">
</StyledTokenName> {pair?.token0.symbol}:{pair?.token1.symbol}
) : ( </StyledTokenName>
<StyledTokenName className="token-symbol-container" active={Boolean(currency && currency.symbol)}> ) : (
{(currency && currency.symbol && currency.symbol.length > 20 <StyledTokenName className="token-symbol-container" active={Boolean(currency && currency.symbol)}>
? currency.symbol.slice(0, 4) + {(currency && currency.symbol && currency.symbol.length > 20
'...' + ? currency.symbol.slice(0, 4) +
currency.symbol.slice(currency.symbol.length - 5, currency.symbol.length) '...' +
: currency?.symbol) || t('selectToken')} currency.symbol.slice(currency.symbol.length - 5, currency.symbol.length)
</StyledTokenName> : currency?.symbol) || t('selectToken')}
)} </StyledTokenName>
)}
</RowFixed>
{!disableCurrencySelect && <StyledDropDown selected={!!currency} />} {!disableCurrencySelect && <StyledDropDown selected={!!currency} />}
</Aligner> </Aligner>
</CurrencySelect> </CurrencySelect>
</InputRow> </InputRow>
{!hideInput && (
<LabelRow>
<RowBetween>
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
{label}
</TYPE.body>
{account && (
<TYPE.body
onClick={onMax}
color={theme.text2}
fontWeight={500}
fontSize={14}
style={{ display: 'inline', cursor: 'pointer' }}
>
{!hideBalance && !!currency && selectedCurrencyBalance
? (customBalanceText ?? 'Balance: ') + selectedCurrencyBalance?.toSignificant(6)
: ' -'}
</TYPE.body>
)}
</RowBetween>
</LabelRow>
)}
</Container> </Container>
{!disableCurrencySelect && onCurrencySelect && ( {!disableCurrencySelect && onCurrencySelect && (
<CurrencySearchModal <CurrencySearchModal
......
import React, { useState, useCallback, useEffect } from 'react'
import { OutlineCard } from 'components/Card'
import { RowBetween } from 'components/Row'
import { ButtonGray } from 'components/Button'
import { TYPE } from 'theme'
import { Input as NumericalInput } from '../NumericalInput'
import styled, { keyframes, css } from 'styled-components'
const pulse = (color: string) => keyframes`
0% {
box-shadow: 0 0 0 0 ${color};
}
70% {
box-shadow: 0 0 0 2px ${color};
}
100% {
box-shadow: 0 0 0 0 ${color};
}
`
const FocusedOutlineCard = styled(OutlineCard)<{ active?: boolean; pulsing?: boolean }>`
border-color: ${({ active, theme }) => active && theme.blue1};
padding: 8px 12px;
${({ pulsing, theme }) =>
pulsing &&
css`
animation: ${pulse(theme.blue1)} 0.8s linear;
`}
`
const StyledInput = styled(NumericalInput)<{ usePercent?: boolean }>`
background-color: ${({ theme }) => theme.bg0};
text-align: ${({ usePercent }) => (usePercent ? 'right' : 'center')};
margin-right: 2px;
`
const ContentWrapper = styled(RowBetween)`
padding: 0 8px;
width: 70%;
`
interface StepCounterProps {
value: string
onUserInput: (value: string) => void
onIncrement?: () => void
onDecrement?: () => void
usePercent?: boolean
prependSymbol?: string | undefined
}
const StepCounter = ({ value, onUserInput, usePercent = false, prependSymbol }: StepCounterProps) => {
// for focus state, styled components doesnt let you select input parent container
const [active, setActive] = useState(false)
// let user type value and only update parent value on blur
const [localValue, setLocalValue] = useState('')
const [useLocalValue, setUseLocalValue] = useState(false)
// animation if parent value updates local value
const [pulsing, setPulsing] = useState<boolean>(false)
const handleOnFocus = () => {
setUseLocalValue(true)
setActive(true)
}
const handleOnBlur = useCallback(() => {
setUseLocalValue(false)
setActive(false)
onUserInput(localValue) // trigger update on parent value
}, [localValue, onUserInput])
useEffect(() => {
if (localValue !== value && !useLocalValue) {
setTimeout(() => {
setLocalValue(value) // reset local value to match parent
setPulsing(true) // trigger animation
setTimeout(function () {
setPulsing(false)
}, 1800)
}, 400)
}
}, [localValue, useLocalValue, value])
const handleDeccrement = useCallback(() => {
localValue && setLocalValue((parseFloat(localValue) * 0.997).toString())
}, [localValue])
const handleIncrement = useCallback(() => {
localValue && setLocalValue((parseFloat(localValue) * 1.003).toString())
}, [localValue])
return (
<FocusedOutlineCard pulsing={pulsing} active={active} onFocus={handleOnFocus} onBlur={handleOnBlur}>
<RowBetween>
<ButtonGray padding="2px 0px" borderRadius="8px" onClick={handleDeccrement} width="50px">
<TYPE.label>-</TYPE.label>
</ButtonGray>
<ContentWrapper>
<StyledInput
className="rate-input-0"
value={localValue}
fontSize="18px"
onUserInput={(val) => {
setLocalValue(val)
}}
prependSymbol={prependSymbol}
usePercent={usePercent}
/>
{usePercent && <TYPE.main>%</TYPE.main>}
</ContentWrapper>
<ButtonGray padding="2px 0px" borderRadius="8px" onClick={handleIncrement} width="50px">
<TYPE.label>+</TYPE.label>
</ButtonGray>
</RowBetween>
</FocusedOutlineCard>
)
}
export default StepCounter
...@@ -43,6 +43,7 @@ export const Input = React.memo(function InnerInput({ ...@@ -43,6 +43,7 @@ export const Input = React.memo(function InnerInput({
value, value,
onUserInput, onUserInput,
placeholder, placeholder,
prependSymbol,
...rest ...rest
}: { }: {
value: string | number value: string | number
...@@ -50,6 +51,7 @@ export const Input = React.memo(function InnerInput({ ...@@ -50,6 +51,7 @@ export const Input = React.memo(function InnerInput({
error?: boolean error?: boolean
fontSize?: string fontSize?: string
align?: 'right' | 'left' align?: 'right' | 'left'
prependSymbol?: string | undefined
} & Omit<React.HTMLProps<HTMLInputElement>, 'ref' | 'onChange' | 'as'>) { } & Omit<React.HTMLProps<HTMLInputElement>, 'ref' | 'onChange' | 'as'>) {
const enforcer = (nextUserInput: string) => { const enforcer = (nextUserInput: string) => {
if (nextUserInput === '' || inputRegex.test(escapeRegExp(nextUserInput))) { if (nextUserInput === '' || inputRegex.test(escapeRegExp(nextUserInput))) {
...@@ -60,10 +62,21 @@ export const Input = React.memo(function InnerInput({ ...@@ -60,10 +62,21 @@ export const Input = React.memo(function InnerInput({
return ( return (
<StyledInput <StyledInput
{...rest} {...rest}
value={value} value={prependSymbol && value ? prependSymbol + value : value}
onChange={(event) => { onChange={(event) => {
// replace commas with periods, because uniswap exclusively uses period as the decimal separator if (prependSymbol) {
enforcer(event.target.value.replace(/,/g, '.')) const value = event.target.value
// cut off prepended symbol
const formattedValue = value.toString().includes(prependSymbol)
? value.toString().slice(1, value.toString().length + 1)
: value
// replace commas with periods, because uniswap exclusively uses period as the decimal separator
enforcer(formattedValue.replace(/,/g, '.'))
} else {
enforcer(event.target.value.replace(/,/g, '.'))
}
}} }}
// universal input options // universal input options
inputMode="decimal" inputMode="decimal"
......
...@@ -47,7 +47,7 @@ const QuestionMark = styled.span` ...@@ -47,7 +47,7 @@ const QuestionMark = styled.span`
font-size: 1rem; font-size: 1rem;
` `
export default function QuestionHelper({ text }: { text: string }) { export default function QuestionHelper({ text, size = 16 }: { text: string; size?: number }) {
const [show, setShow] = useState<boolean>(false) const [show, setShow] = useState<boolean>(false)
const open = useCallback(() => setShow(true), [setShow]) const open = useCallback(() => setShow(true), [setShow])
...@@ -57,7 +57,7 @@ export default function QuestionHelper({ text }: { text: string }) { ...@@ -57,7 +57,7 @@ export default function QuestionHelper({ text }: { text: string }) {
<span style={{ marginLeft: 4 }}> <span style={{ marginLeft: 4 }}>
<Tooltip text={text} show={show}> <Tooltip text={text} show={show}>
<QuestionWrapper onClick={open} onMouseEnter={open} onMouseLeave={close}> <QuestionWrapper onClick={open} onMouseEnter={open} onMouseLeave={close}>
<Question size={16} /> <Question size={size} />
</QuestionWrapper> </QuestionWrapper>
</Tooltip> </Tooltip>
</span> </span>
......
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
const ToggleElement = styled.span<{ isActive?: boolean; isOnSwitch?: boolean }>` export const ToggleWrapper = styled.button<{ width?: string }>`
width: 100%;
padding: 0.25rem 0.5rem;
border-radius: 8px;
background: ${({ theme, isActive }) => (isActive ? theme.bg2 : 'none')};
color: ${({ theme, isActive }) => (isActive ? theme.text1 : theme.text3)};
font-size: 1rem;
font-weight: 400;
padding: 0.35rem 0.6rem;
:hover {
user-select: initial;
color: ${({ theme, isActive }) => (isActive ? theme.text2 : theme.text3)};
}
`
const StyledToggle = styled.button<{ isActive?: boolean; activeElement?: boolean; width?: string }>`
display: flex; display: flex;
align-items: center;
width: ${({ width }) => width ?? '100%'} width: ${({ width }) => width ?? '100%'}
padding: 2px; padding: 1px;
background: ${({ theme }) => theme.bg0}; background: ${({ theme }) => theme.bg0};
border-radius: 8px; border-radius: 8px;
border: ${({ theme }) => '2px solid ' + theme.bg2}; border: ${({ theme }) => '2px solid ' + theme.bg2};
...@@ -27,6 +13,25 @@ const StyledToggle = styled.button<{ isActive?: boolean; activeElement?: boolean ...@@ -27,6 +13,25 @@ const StyledToggle = styled.button<{ isActive?: boolean; activeElement?: boolean
outline: none; outline: none;
` `
export const ToggleElement = styled.span<{ isActive?: boolean; fontSize?: string }>`
display: flex;
align-items: center;
width: 100%;
padding: 4px 0.5rem;
border-radius: 6px;
justify-content: center;
height: 100%;
background: ${({ theme, isActive }) => (isActive ? theme.bg2 : 'none')};
color: ${({ theme, isActive }) => (isActive ? theme.text1 : theme.text3)};
font-size: ${({ fontSize }) => fontSize ?? '1rem'};
font-weight: 500;
white-space: nowrap;
:hover {
user-select: initial;
color: ${({ theme, isActive }) => (isActive ? theme.text2 : theme.text3)};
}
`
export interface ToggleProps { export interface ToggleProps {
options: string[] options: string[]
activeIndex: number activeIndex: number
...@@ -37,17 +42,12 @@ export interface ToggleProps { ...@@ -37,17 +42,12 @@ export interface ToggleProps {
export default function MultiToggle({ id, options, activeIndex, toggle, width }: ToggleProps) { export default function MultiToggle({ id, options, activeIndex, toggle, width }: ToggleProps) {
return ( return (
<StyledToggle id={id} isActive={activeIndex === 0} width={width}> <ToggleWrapper id={id} width={width}>
{options.map((option, index) => ( {options.map((option, index) => (
<ToggleElement <ToggleElement key={id + '-' + index} isActive={index === activeIndex} onClick={() => toggle(index)}>
key={id + '-' + index}
isActive={index === activeIndex}
isOnSwitch={true}
onClick={() => toggle(index)}
>
{option} {option}
</ToggleElement> </ToggleElement>
))} ))}
</StyledToggle> </ToggleWrapper>
) )
} }
...@@ -23,7 +23,7 @@ const Section = styled(AutoColumn)` ...@@ -23,7 +23,7 @@ const Section = styled(AutoColumn)`
` `
const BottomSection = styled(Section)` const BottomSection = styled(Section)`
background-color: ${({ theme }) => theme.bg2}; // background-color: ${({ theme }) => theme.bg2};
border-bottom-left-radius: 20px; border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px; border-bottom-right-radius: 20px;
` `
...@@ -139,7 +139,7 @@ export function ConfirmationModalContent({ ...@@ -139,7 +139,7 @@ export function ConfirmationModalContent({
title: string title: string
onDismiss: () => void onDismiss: () => void
topContent: () => React.ReactNode topContent: () => React.ReactNode
bottomContent: () => React.ReactNode bottomContent?: () => React.ReactNode | undefined
}) { }) {
return ( return (
<Wrapper> <Wrapper>
...@@ -152,7 +152,7 @@ export function ConfirmationModalContent({ ...@@ -152,7 +152,7 @@ export function ConfirmationModalContent({
</RowBetween> </RowBetween>
{topContent()} {topContent()}
</Section> </Section>
<BottomSection gap="12px">{bottomContent()}</BottomSection> {bottomContent && <BottomSection gap="12px">{bottomContent()}</BottomSection>}
</Wrapper> </Wrapper>
) )
} }
......
import { Currency, CurrencyAmount, Fraction, Percent } from '@uniswap/sdk'
import React from 'react'
import { Text } from 'rebass'
import { ButtonPrimary } from '../../components/Button'
import { RowBetween, RowFixed } from '../../components/Row'
import CurrencyLogo from '../../components/CurrencyLogo'
import { Field } from '../../state/mint/actions'
import { TYPE } from '../../theme'
export function ConfirmAddModalBottom({
noLiquidity,
price,
currencies,
parsedAmounts,
poolTokenPercentage,
onAdd,
}: {
noLiquidity?: boolean
price?: Fraction
currencies: { [field in Field]?: Currency }
parsedAmounts: { [field in Field]?: CurrencyAmount }
poolTokenPercentage?: Percent
onAdd: () => void
}) {
return (
<>
<RowBetween>
<TYPE.body>{currencies[Field.CURRENCY_A]?.symbol} Deposited</TYPE.body>
<RowFixed>
<CurrencyLogo currency={currencies[Field.CURRENCY_A]} style={{ marginRight: '8px' }} />
<TYPE.body>{parsedAmounts[Field.CURRENCY_A]?.toSignificant(6)}</TYPE.body>
</RowFixed>
</RowBetween>
<RowBetween>
<TYPE.body>{currencies[Field.CURRENCY_B]?.symbol} Deposited</TYPE.body>
<RowFixed>
<CurrencyLogo currency={currencies[Field.CURRENCY_B]} style={{ marginRight: '8px' }} />
<TYPE.body>{parsedAmounts[Field.CURRENCY_B]?.toSignificant(6)}</TYPE.body>
</RowFixed>
</RowBetween>
<RowBetween>
<TYPE.body>Rates</TYPE.body>
<TYPE.body>
{`1 ${currencies[Field.CURRENCY_A]?.symbol} = ${price?.toSignificant(4)} ${
currencies[Field.CURRENCY_B]?.symbol
}`}
</TYPE.body>
</RowBetween>
<RowBetween style={{ justifyContent: 'flex-end' }}>
<TYPE.body>
{`1 ${currencies[Field.CURRENCY_B]?.symbol} = ${price?.invert().toSignificant(4)} ${
currencies[Field.CURRENCY_A]?.symbol
}`}
</TYPE.body>
</RowBetween>
<RowBetween>
<TYPE.body>Share of Pool:</TYPE.body>
<TYPE.body>{noLiquidity ? '100' : poolTokenPercentage?.toSignificant(4)}%</TYPE.body>
</RowBetween>
<ButtonPrimary style={{ margin: '20px 0 0 0' }} onClick={onAdd}>
<Text fontWeight={500} fontSize={20}>
{noLiquidity ? 'Create Pool & Supply' : 'Confirm Supply'}
</Text>
</ButtonPrimary>
</>
)
}
import { Currency, CurrencyAmount, Fraction, Percent } from '@uniswap/sdk'
import React, { useState } from 'react'
import { ButtonPrimary } from '../../components/Button'
import { RowBetween, RowFixed } from '../../components/Row'
import CurrencyLogo from '../../components/CurrencyLogo'
import { Field } from '../../state/mint/actions'
import { TYPE, ExternalLink } from '../../theme'
import { AutoColumn } from 'components/Column'
import { OutlineCard, GreyCard, BlueCard } from 'components/Card'
import styled from 'styled-components'
import { Break } from 'components/earn/styled'
import useTheme from 'hooks/useTheme'
import { AlertOctagon } from 'react-feather'
import { ToggleWrapper, ToggleElement } from 'components/Toggle/MultiToggle'
import { useTranslation } from 'react-i18next'
const Wrapper = styled(AutoColumn)`
padding: 1rem 0;
`
export function ConfirmContent({
currencies,
parsedAmounts,
onAdd,
}: {
noLiquidity?: boolean
price?: Fraction
currencies: { [field in Field]?: Currency }
parsedAmounts: { [field in Field]?: CurrencyAmount }
poolTokenPercentage?: Percent
onAdd: () => void
}) {
const currencyA: Currency | undefined = currencies[Field.CURRENCY_A]
const currencyB: Currency | undefined = currencies[Field.CURRENCY_B]
const [rateCurrency, setRateCurrency] = useState<Currency | undefined>(currencyA)
const theme = useTheme()
const { t } = useTranslation()
return (
<Wrapper gap="lg">
<OutlineCard>
<AutoColumn gap="md">
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyA} />
<TYPE.label ml="8px">{currencyA?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{parsedAmounts[Field.CURRENCY_A]?.toSignificant(6)}</TYPE.label>
<GreyCard padding="4px 8px" width="fit-content" borderRadius="12px">
<TYPE.darkGray>50%</TYPE.darkGray>
</GreyCard>
</RowFixed>
</RowBetween>
<RowBetween>
<RowFixed>
<CurrencyLogo currency={currencyB} />
<TYPE.label ml="8px">{currencyB?.symbol}</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label mr="8px">{parsedAmounts[Field.CURRENCY_B]?.toSignificant(6)}</TYPE.label>
<GreyCard padding="4px 8px" borderRadius="12px" width="fit-content">
<TYPE.darkGray>50%</TYPE.darkGray>
</GreyCard>
</RowFixed>
</RowBetween>
<Break />
<RowBetween>
<TYPE.label>{t('feePool')}</TYPE.label>
<TYPE.label>0.6%</TYPE.label>
</RowBetween>
</AutoColumn>
</OutlineCard>
<BlueCard padding="12px">
<RowBetween>
<AlertOctagon stroke={theme.primary1} width={'90px'} />
<TYPE.blue ml="12px" fontSize="14px">
{t('rebalanceMessage')}
</TYPE.blue>
</RowBetween>
</BlueCard>
<OutlineCard padding="16px">
<AutoColumn gap="md">
<RowBetween>
<TYPE.label>Position Limits</TYPE.label>
{currencyA && currencyB && (
<ToggleWrapper width="80px">
<ToggleElement
fontSize="10px"
isActive={rateCurrency === currencyA}
onClick={() => setRateCurrency(currencyA)}
>
{currencyA?.symbol}
</ToggleElement>
<ToggleElement
fontSize="10px"
isActive={rateCurrency === currencyB}
onClick={() => setRateCurrency(currencyB)}
>
{currencyB?.symbol}
</ToggleElement>
</ToggleWrapper>
)}
</RowBetween>
<RowBetween>
<AutoColumn gap="2px">
<TYPE.darkGray>Lower Limit</TYPE.darkGray>
<TYPE.label fontSize="14px">1621.82</TYPE.label>
<GreyCard padding="4px" borderRadius="4px" mt="6px">
<RowFixed>
<CurrencyLogo currency={currencyA} size="12px" />
<TYPE.label fontSize="12px" ml="6px">
100%
</TYPE.label>
<TYPE.label fontSize="12px" ml="6px">
{currencyA?.symbol}
</TYPE.label>
</RowFixed>
</GreyCard>
</AutoColumn>
<AutoColumn gap="2px">
<TYPE.darkGray>Entry Price</TYPE.darkGray>
<TYPE.label fontSize="14px">1621.82</TYPE.label>
<GreyCard padding="4px" borderRadius="4px" mt="6px">
<TYPE.label fontSize="12px" ml="6px">
50%/50%
</TYPE.label>
</GreyCard>
</AutoColumn>
<AutoColumn gap="2px">
<TYPE.darkGray>Upper Limit</TYPE.darkGray>
<TYPE.label fontSize="14px">1621.82</TYPE.label>
<GreyCard padding="4px" borderRadius="4px" mt="6px">
<RowFixed>
<CurrencyLogo currency={currencyB} size="12px" />
<TYPE.label fontSize="12px" ml="6px">
100%
</TYPE.label>
<TYPE.label fontSize="12px" ml="6px">
{currencyB?.symbol}
</TYPE.label>
</RowFixed>
</GreyCard>
</AutoColumn>
</RowBetween>
</AutoColumn>
</OutlineCard>
<TYPE.main>
{t('addEarnHelper')}
<ExternalLink href="">{t('learnMoreAboutFess')}</ExternalLink>
</TYPE.main>
<ButtonPrimary onClick={onAdd} fontSize="20px">
{t('addLiquidity')}
</ButtonPrimary>
</Wrapper>
)
}
export default ConfirmContent
This diff is collapsed.
import styled from 'styled-components'
import { AutoColumn } from 'components/Column'
import CurrencyInputPanel from 'components/CurrencyInputPanel'
import { DarkGreyCard } from 'components/Card'
export const ScrollablePage = styled.div`
position: relative;
display: flex;
flex-direction: row;
`
export const ScrollableContent = styled.div`
margin-right: 24px;
`
export const FixedPreview = styled.div`
position: relative;
padding: 8px;
width: 260px;
height: fit-content;
background: ${({ theme }) => theme.bg0};
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 12px;
`
export const DynamicSection = styled(AutoColumn)<{ disabled?: boolean }>`
opacity: ${({ disabled }) => (disabled ? '0.3' : '1')}
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'initial')}
`
export const CurrencyDropdown = styled(CurrencyInputPanel)`
width: 49%;
`
export const PreviewCard = styled(DarkGreyCard)<{ disabled?: boolean }>`
padding: 8px;
border-radius: 12px;
min-height: 40px;
opacity: ${({ disabled }) => (disabled ? '0.2' : '1')};
display: flex;
align-items: center;
justify-content: center;
`
...@@ -40,22 +40,15 @@ const AppWrapper = styled.div` ...@@ -40,22 +40,15 @@ const AppWrapper = styled.div`
overflow-x: hidden; overflow-x: hidden;
` `
const HeaderWrapper = styled.div`
${({ theme }) => theme.flexRowNoWrap}
width: 100%;
justify-content: space-between;
`
const BodyWrapper = styled.div` const BodyWrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
padding-top: 100px; padding-top: 160px;
align-items: center; align-items: center;
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
z-index: 10;
${({ theme }) => theme.mediaWidth.upToSmall` ${({ theme }) => theme.mediaWidth.upToSmall`
padding: 16px; padding: 16px;
...@@ -65,6 +58,15 @@ const BodyWrapper = styled.div` ...@@ -65,6 +58,15 @@ const BodyWrapper = styled.div`
z-index: 1; z-index: 1;
` `
const HeaderWrapper = styled.div`
${({ theme }) => theme.flexRowNoWrap}
width: 100%;
justify-content: space-between;
position: fixed;
top: 0;
z-index: 2;
`
const Marginer = styled.div` const Marginer = styled.div`
margin-top: 5rem; margin-top: 5rem;
` `
......
...@@ -3,7 +3,7 @@ import styled from 'styled-components' ...@@ -3,7 +3,7 @@ import styled from 'styled-components'
export const BodyWrapper = styled.div` export const BodyWrapper = styled.div`
position: relative; position: relative;
max-width: 420px; max-width: 460px;
width: 100%; width: 100%;
background: ${({ theme }) => theme.bg0}; background: ${({ theme }) => theme.bg0};
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
......
...@@ -3,7 +3,7 @@ import styled from 'styled-components' ...@@ -3,7 +3,7 @@ import styled from 'styled-components'
export const Wrapper = styled.div` export const Wrapper = styled.div`
position: relative; position: relative;
padding: 1rem; padding: 20px;
` `
export const ClickableText = styled(Text)` export const ClickableText = styled(Text)`
......
...@@ -5,5 +5,19 @@ export enum Field { ...@@ -5,5 +5,19 @@ export enum Field {
CURRENCY_B = 'CURRENCY_B', CURRENCY_B = 'CURRENCY_B',
} }
export enum Bound {
CURRENT = 'CURRENT',
LOWER = 'LOWER',
UPPER = 'UPPER',
}
export enum RangeType {
PERCENT = 'PERCENT',
RATE = 'RATE',
}
export const typeInput = createAction<{ field: Field; typedValue: string; noLiquidity: boolean }>('mint/typeInputMint') export const typeInput = createAction<{ field: Field; typedValue: string; noLiquidity: boolean }>('mint/typeInputMint')
export const typeLowerRangeInput = createAction<{ typedValue: string }>('mint/typeLowerRangeInput')
export const typeUpperRangeInput = createAction<{ typedValue: string }>('mint/typeUpperRangeInput')
export const updateRangeType = createAction<{ rangeType: RangeType }>('mint/updateRangeType')
export const resetMintState = createAction<void>('mint/resetMintState') export const resetMintState = createAction<void>('mint/resetMintState')
...@@ -9,7 +9,16 @@ import { wrappedCurrency, wrappedCurrencyAmount } from '../../utils/wrappedCurre ...@@ -9,7 +9,16 @@ import { wrappedCurrency, wrappedCurrencyAmount } from '../../utils/wrappedCurre
import { AppDispatch, AppState } from '../index' import { AppDispatch, AppState } from '../index'
import { tryParseAmount } from '../swap/hooks' import { tryParseAmount } from '../swap/hooks'
import { useCurrencyBalances } from '../wallet/hooks' import { useCurrencyBalances } from '../wallet/hooks'
import { Field, typeInput } from './actions' import {
Field,
Bound,
typeInput,
typeLowerRangeInput,
typeUpperRangeInput,
RangeType,
updateRangeType as updateRangeTypeAction,
} from './actions'
import { tryParseTick } from './utils'
const ZERO = JSBI.BigInt(0) const ZERO = JSBI.BigInt(0)
...@@ -22,6 +31,9 @@ export function useMintActionHandlers( ...@@ -22,6 +31,9 @@ export function useMintActionHandlers(
): { ): {
onFieldAInput: (typedValue: string) => void onFieldAInput: (typedValue: string) => void
onFieldBInput: (typedValue: string) => void onFieldBInput: (typedValue: string) => void
onLowerRangeInput: (typedValue: string) => void
onUpperRangeInput: (typedValue: string) => void
updateRangeType: (rangetype: RangeType) => void
} { } {
const dispatch = useDispatch<AppDispatch>() const dispatch = useDispatch<AppDispatch>()
...@@ -31,6 +43,7 @@ export function useMintActionHandlers( ...@@ -31,6 +43,7 @@ export function useMintActionHandlers(
}, },
[dispatch, noLiquidity] [dispatch, noLiquidity]
) )
const onFieldBInput = useCallback( const onFieldBInput = useCallback(
(typedValue: string) => { (typedValue: string) => {
dispatch(typeInput({ field: Field.CURRENCY_B, typedValue, noLiquidity: noLiquidity === true })) dispatch(typeInput({ field: Field.CURRENCY_B, typedValue, noLiquidity: noLiquidity === true }))
...@@ -38,12 +51,41 @@ export function useMintActionHandlers( ...@@ -38,12 +51,41 @@ export function useMintActionHandlers(
[dispatch, noLiquidity] [dispatch, noLiquidity]
) )
const onLowerRangeInput = useCallback(
(typedValue: string) => {
dispatch(typeLowerRangeInput({ typedValue }))
},
[dispatch]
)
const onUpperRangeInput = useCallback(
(typedValue: string) => {
dispatch(typeUpperRangeInput({ typedValue }))
},
[dispatch]
)
const updateRangeType = useCallback(
(rangeType: RangeType) => {
dispatch(updateRangeTypeAction({ rangeType }))
},
[dispatch]
)
return { return {
onFieldAInput, onFieldAInput,
onFieldBInput, onFieldBInput,
onLowerRangeInput,
onUpperRangeInput,
updateRangeType,
} }
} }
// dummy entity
export interface Tick {
rate: number
}
export function useDerivedMintInfo( export function useDerivedMintInfo(
currencyA: Currency | undefined, currencyA: Currency | undefined,
currencyB: Currency | undefined currencyB: Currency | undefined
...@@ -54,6 +96,7 @@ export function useDerivedMintInfo( ...@@ -54,6 +96,7 @@ export function useDerivedMintInfo(
pairState: PairState pairState: PairState
currencyBalances: { [field in Field]?: CurrencyAmount } currencyBalances: { [field in Field]?: CurrencyAmount }
parsedAmounts: { [field in Field]?: CurrencyAmount } parsedAmounts: { [field in Field]?: CurrencyAmount }
ticks: { [bound in Bound]?: Tick }
price?: Price price?: Price
noLiquidity?: boolean noLiquidity?: boolean
liquidityMinted?: TokenAmount liquidityMinted?: TokenAmount
...@@ -62,7 +105,7 @@ export function useDerivedMintInfo( ...@@ -62,7 +105,7 @@ export function useDerivedMintInfo(
} { } {
const { account, chainId } = useActiveWeb3React() const { account, chainId } = useActiveWeb3React()
const { independentField, typedValue, otherTypedValue } = useMintState() const { independentField, typedValue, otherTypedValue, lowerRangeTypedValue, upperRangeTypedValue } = useMintState()
const dependentField = independentField === Field.CURRENCY_A ? Field.CURRENCY_B : Field.CURRENCY_A const dependentField = independentField === Field.CURRENCY_A ? Field.CURRENCY_B : Field.CURRENCY_A
...@@ -117,10 +160,13 @@ export function useDerivedMintInfo( ...@@ -117,10 +160,13 @@ export function useDerivedMintInfo(
return undefined return undefined
} }
}, [noLiquidity, otherTypedValue, currencies, dependentField, independentAmount, currencyA, chainId, currencyB, pair]) }, [noLiquidity, otherTypedValue, currencies, dependentField, independentAmount, currencyA, chainId, currencyB, pair])
const parsedAmounts: { [field in Field]: CurrencyAmount | undefined } = {
[Field.CURRENCY_A]: independentField === Field.CURRENCY_A ? independentAmount : dependentAmount, const parsedAmounts: { [field in Field]: CurrencyAmount | undefined } = useMemo(() => {
[Field.CURRENCY_B]: independentField === Field.CURRENCY_A ? dependentAmount : independentAmount, return {
} [Field.CURRENCY_A]: independentField === Field.CURRENCY_A ? independentAmount : dependentAmount,
[Field.CURRENCY_B]: independentField === Field.CURRENCY_A ? dependentAmount : independentAmount,
}
}, [dependentAmount, independentAmount, independentField])
const price = useMemo(() => { const price = useMemo(() => {
if (noLiquidity) { if (noLiquidity) {
...@@ -135,6 +181,17 @@ export function useDerivedMintInfo( ...@@ -135,6 +181,17 @@ export function useDerivedMintInfo(
} }
}, [chainId, currencyA, noLiquidity, pair, parsedAmounts]) }, [chainId, currencyA, noLiquidity, pair, parsedAmounts])
// parse typed range values and determine closest ticks, dummy rn
const ticks = {
[Bound.CURRENT]: {
rate: parseFloat(
independentField === Field.CURRENCY_A ? price?.toFixed(6) ?? '0' : price?.invert().toFixed(6) ?? '0'
),
},
[Bound.LOWER]: tryParseTick(lowerRangeTypedValue),
[Bound.UPPER]: tryParseTick(upperRangeTypedValue),
}
// liquidity minted // liquidity minted
const liquidityMinted = useMemo(() => { const liquidityMinted = useMemo(() => {
const { [Field.CURRENCY_A]: currencyAAmount, [Field.CURRENCY_B]: currencyBAmount } = parsedAmounts const { [Field.CURRENCY_A]: currencyAAmount, [Field.CURRENCY_B]: currencyBAmount } = parsedAmounts
...@@ -187,6 +244,7 @@ export function useDerivedMintInfo( ...@@ -187,6 +244,7 @@ export function useDerivedMintInfo(
pairState, pairState,
currencyBalances, currencyBalances,
parsedAmounts, parsedAmounts,
ticks,
price, price,
noLiquidity, noLiquidity,
liquidityMinted, liquidityMinted,
......
import { createReducer } from '@reduxjs/toolkit' import { createReducer } from '@reduxjs/toolkit'
import { Field, resetMintState, typeInput } from './actions' import {
Field,
resetMintState,
typeInput,
typeLowerRangeInput,
typeUpperRangeInput,
RangeType,
updateRangeType,
} from './actions'
export interface MintState { export interface MintState {
readonly independentField: Field readonly independentField: Field
readonly typedValue: string readonly typedValue: string
readonly otherTypedValue: string // for the case when there's no liquidity readonly otherTypedValue: string // for the case when there's no liquidity
readonly lowerRangeTypedValue: string
readonly upperRangeTypedValue: string
readonly rangeType: RangeType
} }
const initialState: MintState = { const initialState: MintState = {
independentField: Field.CURRENCY_A, independentField: Field.CURRENCY_A,
typedValue: '', typedValue: '',
otherTypedValue: '', otherTypedValue: '',
lowerRangeTypedValue: '',
upperRangeTypedValue: '',
rangeType: RangeType.RATE,
} }
export default createReducer<MintState>(initialState, (builder) => export default createReducer<MintState>(initialState, (builder) =>
builder builder
.addCase(resetMintState, () => initialState) .addCase(resetMintState, () => initialState)
.addCase(updateRangeType, (state, { payload: { rangeType } }) => {
return {
...state,
rangeType,
}
})
.addCase(typeLowerRangeInput, (state, { payload: { typedValue } }) => {
return {
...state,
lowerRangeTypedValue: typedValue,
}
})
.addCase(typeUpperRangeInput, (state, { payload: { typedValue } }) => {
return {
...state,
upperRangeTypedValue: typedValue,
}
})
.addCase(typeInput, (state, { payload: { field, typedValue, noLiquidity } }) => { .addCase(typeInput, (state, { payload: { field, typedValue, noLiquidity } }) => {
if (noLiquidity) { if (noLiquidity) {
// they're typing into the field they've last typed in // they're typing into the field they've last typed in
......
import { Tick } from './hooks'
/**
* @todo
* udpate to actually parse input and calculate next tick
*/
export function tryParseTick(value?: string): Tick | undefined {
if (!value) {
return undefined
}
try {
return { rate: parseFloat(value) * 0.999 }
} catch (error) {
console.debug(`Failed to parse range amount: "${value}"`, error)
}
return undefined
}
...@@ -162,7 +162,7 @@ export function useUserAddedTokens(): Token[] { ...@@ -162,7 +162,7 @@ export function useUserAddedTokens(): Token[] {
return useMemo(() => { return useMemo(() => {
if (!chainId) return [] if (!chainId) return []
return Object.values(serializedTokensMap[chainId as ChainId] ?? {}).map(deserializeToken) return Object.values(serializedTokensMap?.[chainId as ChainId] ?? {}).map(deserializeToken)
}, [serializedTokensMap, chainId]) }, [serializedTokensMap, chainId])
} }
......
...@@ -80,7 +80,9 @@ export function colors(darkMode: boolean): Colors { ...@@ -80,7 +80,9 @@ export function colors(darkMode: boolean): Colors {
green1: '#27AE60', green1: '#27AE60',
yellow1: '#FFE270', yellow1: '#FFE270',
yellow2: '#F3841E', yellow2: '#F3841E',
yellow3: '#F3B71E',
blue1: '#2172E5', blue1: '#2172E5',
blue2: '#5199FF',
error: '#FD4040', error: '#FD4040',
success: '#27AE60', success: '#27AE60',
...@@ -139,6 +141,9 @@ export const TYPE = { ...@@ -139,6 +141,9 @@ export const TYPE = {
link(props: TextProps) { link(props: TextProps) {
return <TextWrapper fontWeight={500} color={'primary1'} {...props} /> return <TextWrapper fontWeight={500} color={'primary1'} {...props} />
}, },
label(props: TextProps) {
return <TextWrapper fontWeight={600} color={'text1'} {...props} />
},
black(props: TextProps) { black(props: TextProps) {
return <TextWrapper fontWeight={500} color={'text1'} {...props} /> return <TextWrapper fontWeight={500} color={'text1'} {...props} />
}, },
...@@ -164,7 +169,7 @@ export const TYPE = { ...@@ -164,7 +169,7 @@ export const TYPE = {
return <TextWrapper fontWeight={500} color={'blue1'} {...props} /> return <TextWrapper fontWeight={500} color={'blue1'} {...props} />
}, },
yellow(props: TextProps) { yellow(props: TextProps) {
return <TextWrapper fontWeight={500} color={'yellow1'} {...props} /> return <TextWrapper fontWeight={500} color={'yellow3'} {...props} />
}, },
darkGray(props: TextProps) { darkGray(props: TextProps) {
return <TextWrapper fontWeight={500} color={'text3'} {...props} /> return <TextWrapper fontWeight={500} color={'text3'} {...props} />
......
...@@ -45,7 +45,9 @@ export interface Colors { ...@@ -45,7 +45,9 @@ export interface Colors {
green1: Color green1: Color
yellow1: Color yellow1: Color
yellow2: Color yellow2: Color
yellow3: Color
blue1: Color blue1: Color
blue2: Color
error: Color error: Color
success: Color success: Color
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment