Swap polish 02 (#93)
* rework swap UI * Add v2/v3 route toggle UX * improve button and progress styles * put optional route in swap header * Further refinements * Alt swap layout * clean up * Tweak route ui * merge main * update swap header * adjust currency select ui
This commit is contained in:
parent
d7785942b1
commit
4c2cb5b0c1
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { darken, lighten } from 'polished'
|
import { darken } from 'polished'
|
||||||
|
|
||||||
import { RowBetween } from '../Row'
|
import { RowBetween } from '../Row'
|
||||||
import { ChevronDown, Check } from 'react-feather'
|
import { ChevronDown, Check } from 'react-feather'
|
||||||
@ -32,6 +32,15 @@ const Base = styled(RebassButton)<{
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
will-change: transform;
|
||||||
|
transition: transform 450ms ease;
|
||||||
|
transform: perspective(1px) translateZ(0);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(0.99);
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
@ -59,14 +68,14 @@ export const ButtonPrimary = styled(Base)`
|
|||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background-color: ${({ theme, altDisabledStyle, disabled }) =>
|
background-color: ${({ theme, altDisabledStyle, disabled }) =>
|
||||||
altDisabledStyle ? (disabled ? theme.bg3 : theme.primary1) : theme.bg3};
|
altDisabledStyle ? (disabled ? theme.primary1 : theme.primary1) : theme.primary1};
|
||||||
color: ${({ theme, altDisabledStyle, disabled }) =>
|
color: white;
|
||||||
altDisabledStyle ? (disabled ? theme.text3 : 'white') : theme.text3};
|
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.5' : '1')};
|
opacity: 0.4;
|
||||||
|
opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.5' : '0.4')};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -270,12 +279,14 @@ export const ButtonWhite = styled(Base)`
|
|||||||
`
|
`
|
||||||
|
|
||||||
const ButtonConfirmedStyle = styled(Base)`
|
const ButtonConfirmedStyle = styled(Base)`
|
||||||
background-color: ${({ theme }) => lighten(0.5, theme.green1)};
|
background-color: ${({ theme }) => theme.bg3};
|
||||||
color: ${({ theme }) => theme.green1};
|
color: ${({ theme }) => theme.text1};
|
||||||
border: 1px solid ${({ theme }) => theme.green1};
|
/* border: 1px solid ${({ theme }) => theme.green1}; */
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
opacity: 50%;
|
/* opacity: 50%; */
|
||||||
|
background-color: ${({ theme }) => theme.bg2};
|
||||||
|
color: ${({ theme }) => theme.text2};
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -9,6 +9,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 { ButtonGray } from '../Button'
|
||||||
import { RowBetween, RowFixed } 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'
|
||||||
@ -52,24 +53,24 @@ const Container = styled.div<{ hideInput: boolean }>`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CurrencySelect = styled.button<{ selected: boolean; hideInput?: boolean }>`
|
const CurrencySelect = styled(ButtonGray)<{ selected: boolean; hideInput?: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 20px;
|
font-size: 24px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : theme.primary1)};
|
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : theme.primary1)};
|
||||||
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
/* box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')}; */
|
box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')};
|
||||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||||
|
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
height: ${({ hideInput }) => (hideInput ? '2.4rem' : '2.4rem')};
|
||||||
height: ${({ hideInput }) => (hideInput ? '2.8rem' : '2.4rem')};
|
|
||||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||||
|
padding: 0 8px;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-right: 12px;
|
||||||
:focus,
|
:focus,
|
||||||
:hover {
|
:hover {
|
||||||
background-color: ${({ selected, theme }) => (selected ? theme.bg3 : darken(0.05, theme.primary1))};
|
background-color: ${({ selected, theme }) => (selected ? theme.bg3 : darken(0.05, theme.primary1))};
|
||||||
@ -79,7 +80,7 @@ const CurrencySelect = styled.button<{ selected: boolean; hideInput?: boolean }>
|
|||||||
const InputRow = styled.div<{ selected: boolean }>`
|
const InputRow = styled.div<{ selected: boolean }>`
|
||||||
${({ theme }) => theme.flexRowNoWrap}
|
${({ theme }) => theme.flexRowNoWrap}
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: ${({ selected }) => (selected ? '.75rem 0.75rem .75rem 1rem' : '.75rem 0.75rem .75rem 1rem')};
|
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 0.75rem 1rem')};
|
||||||
`
|
`
|
||||||
|
|
||||||
const LabelRow = styled.div`
|
const LabelRow = styled.div`
|
||||||
@ -88,13 +89,17 @@ const LabelRow = styled.div`
|
|||||||
color: ${({ theme }) => theme.text1};
|
color: ${({ theme }) => theme.text1};
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
padding: 0rem 1rem 0.75rem 1rem;
|
padding: 0 1rem 1rem;
|
||||||
span:hover {
|
span:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${({ theme }) => darken(0.2, theme.text2)};
|
color: ${({ theme }) => darken(0.2, theme.text2)};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const FiatRow = styled(LabelRow)`
|
||||||
|
justify-content: flex-end;
|
||||||
|
`
|
||||||
|
|
||||||
const Aligner = styled.span`
|
const Aligner = styled.span`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -102,7 +107,7 @@ const Aligner = styled.span`
|
|||||||
`
|
`
|
||||||
|
|
||||||
const StyledDropDown = styled(DropDown)<{ selected: boolean }>`
|
const StyledDropDown = styled(DropDown)<{ selected: boolean }>`
|
||||||
margin: 0 0.25rem 0 0.5rem;
|
margin: 0 0.25rem 0 0.35rem;
|
||||||
height: 35%;
|
height: 35%;
|
||||||
|
|
||||||
path {
|
path {
|
||||||
@ -113,27 +118,27 @@ const StyledDropDown = styled(DropDown)<{ selected: boolean }>`
|
|||||||
|
|
||||||
const StyledTokenName = styled.span<{ active?: boolean }>`
|
const StyledTokenName = styled.span<{ active?: boolean }>`
|
||||||
${({ active }) => (active ? ' margin: 0 0.25rem 0 0.25rem;' : ' margin: 0 0.25rem 0 0.25rem;')}
|
${({ active }) => (active ? ' margin: 0 0.25rem 0 0.25rem;' : ' margin: 0 0.25rem 0 0.25rem;')}
|
||||||
font-size: ${({ active }) => (active ? '20px' : '18px')};
|
font-size: ${({ active }) => (active ? '18px' : '18px')};
|
||||||
`
|
`
|
||||||
|
|
||||||
const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
|
const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
|
||||||
background-color: ${({ theme }) => theme.primary5};
|
background-color: transparent;
|
||||||
border: 1px solid ${({ theme }) => theme.primary5};
|
border: none;
|
||||||
border-radius: 0.5rem;
|
border-radius: 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
/* margin-left: 0.5rem; */
|
padding: 0;
|
||||||
color: ${({ theme }) => theme.primary1};
|
color: ${({ theme }) => theme.primary1};
|
||||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
border: 1px solid ${({ theme }) => theme.primary1};
|
/* border: 1px solid ${({ theme }) => theme.primary1}; */
|
||||||
}
|
}
|
||||||
:focus {
|
:focus {
|
||||||
border: 1px solid ${({ theme }) => theme.primary1};
|
/* border: 1px solid ${({ theme }) => theme.primary1}; */
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +171,6 @@ export default function CurrencyInputPanel({
|
|||||||
onUserInput,
|
onUserInput,
|
||||||
onMax,
|
onMax,
|
||||||
showMaxButton,
|
showMaxButton,
|
||||||
label = 'Input',
|
|
||||||
onCurrencySelect,
|
onCurrencySelect,
|
||||||
currency,
|
currency,
|
||||||
otherCurrency,
|
otherCurrency,
|
||||||
@ -210,19 +214,6 @@ export default function CurrencyInputPanel({
|
|||||||
</FixedContainer>
|
</FixedContainer>
|
||||||
)}
|
)}
|
||||||
<Container hideInput={hideInput}>
|
<Container hideInput={hideInput}>
|
||||||
{!hideInput && (
|
|
||||||
<LabelRow style={{ padding: ' 1rem 1rem 0rem 1rem' }}>
|
|
||||||
<RowBetween>
|
|
||||||
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
|
|
||||||
{label}
|
|
||||||
</TYPE.body>
|
|
||||||
<TYPE.label>
|
|
||||||
{fiatValueOfTypedAmount ? '~' : ''}${fiatValueOfTypedAmount?.toSignificant(4) ?? '-'}
|
|
||||||
</TYPE.label>
|
|
||||||
</RowBetween>
|
|
||||||
</LabelRow>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
|
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
|
||||||
<CurrencySelect
|
<CurrencySelect
|
||||||
selected={!!currency}
|
selected={!!currency}
|
||||||
@ -261,24 +252,27 @@ export default function CurrencyInputPanel({
|
|||||||
</Aligner>
|
</Aligner>
|
||||||
</CurrencySelect>
|
</CurrencySelect>
|
||||||
{!hideInput && (
|
{!hideInput && (
|
||||||
<NumericalInput
|
<>
|
||||||
className="token-amount-input"
|
{' '}
|
||||||
value={value}
|
<NumericalInput
|
||||||
onUserInput={(val) => {
|
className="token-amount-input"
|
||||||
onUserInput(val)
|
value={value}
|
||||||
}}
|
onUserInput={(val) => {
|
||||||
/>
|
onUserInput(val)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</InputRow>
|
</InputRow>
|
||||||
{!hideInput && !hideBalance && (
|
{!hideInput && !hideBalance && (
|
||||||
<LabelRow>
|
<FiatRow>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
{account && (
|
{account && (
|
||||||
<RowFixed>
|
<RowFixed style={{ height: '17px' }}>
|
||||||
<TYPE.body
|
<TYPE.body
|
||||||
onClick={onMax}
|
onClick={onMax}
|
||||||
color={theme.text3}
|
color={theme.text2}
|
||||||
fontWeight={500}
|
fontWeight={400}
|
||||||
fontSize={14}
|
fontSize={14}
|
||||||
style={{ display: 'inline', cursor: 'pointer' }}
|
style={{ display: 'inline', cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
@ -287,17 +281,26 @@ export default function CurrencyInputPanel({
|
|||||||
selectedCurrencyBalance?.toSignificant(4) +
|
selectedCurrencyBalance?.toSignificant(4) +
|
||||||
' ' +
|
' ' +
|
||||||
currency.symbol
|
currency.symbol
|
||||||
: ' '}
|
: '-'}
|
||||||
</TYPE.body>
|
</TYPE.body>
|
||||||
|
{showMaxButton && selectedCurrencyBalance ? (
|
||||||
|
<StyledBalanceMax disabled={!showMaxButton} onClick={onMax}>
|
||||||
|
(Max)
|
||||||
|
</StyledBalanceMax>
|
||||||
|
) : (
|
||||||
|
<StyledBalanceMax disabled={!showMaxButton} onClick={onMax}>
|
||||||
|
{''}
|
||||||
|
</StyledBalanceMax>
|
||||||
|
)}
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
)}
|
)}
|
||||||
{showMaxButton && (
|
|
||||||
<StyledBalanceMax disabled={!showMaxButton} onClick={onMax}>
|
<TYPE.body fontSize={14} color={fiatValueOfTypedAmount ? theme.text2 : theme.text4}>
|
||||||
Max
|
{fiatValueOfTypedAmount ? '~' : ''}$
|
||||||
</StyledBalanceMax>
|
{fiatValueOfTypedAmount ? Number(fiatValueOfTypedAmount?.toSignificant(6)).toLocaleString('en') : '-'}
|
||||||
)}
|
</TYPE.body>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
</LabelRow>
|
</FiatRow>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
{onCurrencySelect && (
|
{onCurrencySelect && (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ChainId, TokenAmount } from '@uniswap/sdk-core'
|
import { ChainId } from '@uniswap/sdk-core'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
@ -9,11 +9,11 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import Logo from '../../assets/svg/logo.svg'
|
import Logo from '../../assets/svg/logo.svg'
|
||||||
import LogoDark from '../../assets/svg/logo_white.svg'
|
import LogoDark from '../../assets/svg/logo_white.svg'
|
||||||
|
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { useDarkModeManager } from '../../state/user/hooks'
|
import { useDarkModeManager } from '../../state/user/hooks'
|
||||||
import { useETHBalances, useAggregateUniBalance } from '../../state/wallet/hooks'
|
import { useETHBalances } from '../../state/wallet/hooks'
|
||||||
import { CardNoise } from '../earn/styled'
|
import { CardNoise } from '../earn/styled'
|
||||||
import { CountUp } from 'use-count-up'
|
|
||||||
import { TYPE, ExternalLink } from '../../theme'
|
import { TYPE, ExternalLink } from '../../theme'
|
||||||
|
|
||||||
import { YellowCard } from '../Card'
|
import { YellowCard } from '../Card'
|
||||||
@ -28,7 +28,6 @@ import { useUserHasSubmittedClaim } from '../../state/transactions/hooks'
|
|||||||
import { Dots } from '../swap/styleds'
|
import { Dots } from '../swap/styleds'
|
||||||
import Modal from '../Modal'
|
import Modal from '../Modal'
|
||||||
import UniBalanceContent from './UniBalanceContent'
|
import UniBalanceContent from './UniBalanceContent'
|
||||||
import usePrevious from '../../hooks/usePrevious'
|
|
||||||
|
|
||||||
const HeaderFrame = styled.div`
|
const HeaderFrame = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -40,10 +39,10 @@ const HeaderFrame = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
/* border-bottom: 1px solid rgba(0, 0, 0, 0.1); */
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
z-index: 21;
|
z-index: 21;
|
||||||
background-color: ${({ theme }) => theme.bg0};
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
|
|
||||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -314,14 +313,9 @@ export default function Header() {
|
|||||||
|
|
||||||
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
|
const { claimTxn } = useUserHasSubmittedClaim(account ?? undefined)
|
||||||
|
|
||||||
const aggregateBalance: TokenAmount | undefined = useAggregateUniBalance()
|
|
||||||
|
|
||||||
const [showUniBalanceModal, setShowUniBalanceModal] = useState(false)
|
const [showUniBalanceModal, setShowUniBalanceModal] = useState(false)
|
||||||
const showClaimPopup = useShowClaimPopup()
|
const showClaimPopup = useShowClaimPopup()
|
||||||
|
|
||||||
const countUpValue = aggregateBalance?.toFixed(0) ?? '0'
|
|
||||||
const countUpValuePrevious = usePrevious(countUpValue) ?? '0'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderFrame>
|
<HeaderFrame>
|
||||||
<ClaimModal />
|
<ClaimModal />
|
||||||
@ -376,33 +370,7 @@ export default function Header() {
|
|||||||
<CardNoise />
|
<CardNoise />
|
||||||
</UNIWrapper>
|
</UNIWrapper>
|
||||||
)}
|
)}
|
||||||
{/* I want to put this in the overflow menu now */}
|
|
||||||
{!availableClaim && aggregateBalance && (
|
|
||||||
<UNIWrapper onClick={() => setShowUniBalanceModal(true)}>
|
|
||||||
<UNIAmount active={!!account && !availableClaim} style={{ pointerEvents: 'auto' }}>
|
|
||||||
{account && (
|
|
||||||
<HideSmall>
|
|
||||||
<TYPE.white
|
|
||||||
style={{
|
|
||||||
paddingRight: '.4rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CountUp
|
|
||||||
key={countUpValue}
|
|
||||||
isCounting
|
|
||||||
start={parseFloat(countUpValuePrevious)}
|
|
||||||
end={parseFloat(countUpValue)}
|
|
||||||
thousandsSeparator={','}
|
|
||||||
duration={1}
|
|
||||||
/>
|
|
||||||
</TYPE.white>
|
|
||||||
</HideSmall>
|
|
||||||
)}
|
|
||||||
UNI
|
|
||||||
</UNIAmount>
|
|
||||||
<CardNoise />
|
|
||||||
</UNIWrapper>
|
|
||||||
)}
|
|
||||||
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
|
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
|
||||||
{account && userEthBalance ? (
|
{account && userEthBalance ? (
|
||||||
<BalanceText style={{ flexShrink: 0 }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
<BalanceText style={{ flexShrink: 0 }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||||
|
@ -21,7 +21,7 @@ export const Popup = styled.div`
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
background-color: ${({ theme }) => theme.bg1};
|
background-color: ${({ theme }) => theme.bg0};
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
@ -33,7 +33,7 @@ const MobilePopupInner = styled.div`
|
|||||||
|
|
||||||
const FixedPopupColumn = styled(AutoColumn)<{ extraPadding: boolean }>`
|
const FixedPopupColumn = styled(AutoColumn)<{ extraPadding: boolean }>`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: ${({ extraPadding }) => (extraPadding ? '108px' : '88px')};
|
top: ${({ extraPadding }) => (extraPadding ? '72px' : '88px')};
|
||||||
right: 1rem;
|
right: 1rem;
|
||||||
max-width: 355px !important;
|
max-width: 355px !important;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -2,26 +2,26 @@ import React, { useContext } from 'react'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { AutoColumn } from '../Column'
|
import { AutoColumn } from '../Column'
|
||||||
import { ThemeContext } from 'styled-components'
|
import { ThemeContext } from 'styled-components'
|
||||||
import { ArrowDown } from 'react-feather'
|
import { TYPE } from '../../theme'
|
||||||
|
|
||||||
const Wrapper = styled(AutoColumn)`
|
const Wrapper = styled(AutoColumn)`
|
||||||
margin-left: 8px;
|
margin-right: 8px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Grouping = styled(AutoColumn)`
|
const Grouping = styled(AutoColumn)`
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background-color: ${({ theme }) => theme.bg2};
|
/* background-color: ${({ theme }) => theme.bg2}; */
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Circle = styled.div<{ confirmed?: boolean; disabled?: boolean }>`
|
const Circle = styled.div<{ confirmed?: boolean; disabled?: boolean }>`
|
||||||
width: 100%;
|
width: 48px;
|
||||||
height: 100%;
|
height: 48px;
|
||||||
background-color: ${({ theme, confirmed, disabled }) =>
|
background-color: ${({ theme, confirmed, disabled }) =>
|
||||||
disabled ? theme.bg3 : confirmed ? theme.green1 : theme.primary1};
|
disabled ? theme.bg3 : confirmed ? theme.green1 : theme.primary1};
|
||||||
border-radius: 12px;
|
border-radius: 50%;
|
||||||
color: ${({ theme, disabled }) => (disabled ? theme.text3 : theme.text1)};
|
color: ${({ theme, disabled }) => (disabled ? theme.text3 : theme.text1)};
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -37,12 +37,6 @@ const CircleRow = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
|
|
||||||
const StyledArrowDown = styled(ArrowDown)`
|
|
||||||
margin: 0.5rem;
|
|
||||||
min-height: 14px;
|
|
||||||
/* color: ${({ theme }) => theme.text1}; */
|
|
||||||
`
|
|
||||||
|
|
||||||
interface ProgressCirclesProps {
|
interface ProgressCirclesProps {
|
||||||
steps: boolean[]
|
steps: boolean[]
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
@ -68,13 +62,13 @@ export default function ProgressCircles({ steps, disabled = false, ...rest }: Pr
|
|||||||
return (
|
return (
|
||||||
<CircleRow key={i}>
|
<CircleRow key={i}>
|
||||||
<Circle confirmed={step} disabled={disabled || (!steps[i - 1] && i !== 0)}>
|
<Circle confirmed={step} disabled={disabled || (!steps[i - 1] && i !== 0)}>
|
||||||
{step ? '✓' : i + 1}
|
{step ? '✓' : i + 1 + '.'}
|
||||||
</Circle>
|
</Circle>
|
||||||
<StyledArrowDown size="16" color={theme.text3} />
|
<TYPE.main color={theme.text4}>|</TYPE.main>
|
||||||
</CircleRow>
|
</CircleRow>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<Circle disabled={disabled || !steps[steps.length - 1]}>{steps.length + 1}</Circle>
|
<Circle disabled={disabled || !steps[steps.length - 1]}>{steps.length + 1 + '.'}</Circle>
|
||||||
</Grouping>
|
</Grouping>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
)
|
)
|
||||||
|
@ -21,8 +21,6 @@ import QuestionHelper from '../QuestionHelper'
|
|||||||
import { RowBetween, RowFixed } from '../Row'
|
import { RowBetween, RowFixed } from '../Row'
|
||||||
import Toggle from '../Toggle'
|
import Toggle from '../Toggle'
|
||||||
import TransactionSettings from '../TransactionSettings'
|
import TransactionSettings from '../TransactionSettings'
|
||||||
import { Moon, Sun } from 'react-feather'
|
|
||||||
import { useDarkModeManager } from '../../state/user/hooks'
|
|
||||||
|
|
||||||
const StyledMenuIcon = styled(Settings)`
|
const StyledMenuIcon = styled(Settings)`
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -86,6 +84,7 @@ const StyledMenu = styled.div`
|
|||||||
const MenuFlyout = styled.span`
|
const MenuFlyout = styled.span`
|
||||||
min-width: 20.125rem;
|
min-width: 20.125rem;
|
||||||
background-color: ${({ theme }) => theme.bg2};
|
background-color: ${({ theme }) => theme.bg2};
|
||||||
|
border: 1px solid ${({ theme }) => theme.bg3};
|
||||||
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),
|
||||||
0px 24px 32px rgba(0, 0, 0, 0.01);
|
0px 24px 32px rgba(0, 0, 0, 0.01);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@ -93,7 +92,7 @@ const MenuFlyout = styled.span`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3rem;
|
top: 2rem;
|
||||||
right: 0rem;
|
right: 0rem;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
@ -134,8 +133,6 @@ export default function SettingsTab() {
|
|||||||
// show confirmation view before turning on
|
// show confirmation view before turning on
|
||||||
const [showConfirmation, setShowConfirmation] = useState(false)
|
const [showConfirmation, setShowConfirmation] = useState(false)
|
||||||
|
|
||||||
const [darkMode, toggleDarkMode] = useDarkModeManager()
|
|
||||||
|
|
||||||
useOnClickOutside(node, open ? toggle : undefined)
|
useOnClickOutside(node, open ? toggle : undefined)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -245,10 +242,6 @@ export default function SettingsTab() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
{/* WIP */}
|
|
||||||
<StyledMenuButton onClick={() => toggleDarkMode()}>
|
|
||||||
{darkMode ? <Moon color={theme.text2} size={20} /> : <Sun size={20} />}
|
|
||||||
</StyledMenuButton>
|
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
)}
|
)}
|
||||||
|
@ -3,9 +3,9 @@ import styled from 'styled-components'
|
|||||||
import Popover, { PopoverProps } from '../Popover'
|
import Popover, { PopoverProps } from '../Popover'
|
||||||
|
|
||||||
const TooltipContainer = styled.div`
|
const TooltipContainer = styled.div`
|
||||||
width: 228px;
|
width: 256px;
|
||||||
padding: 0.6rem 1rem;
|
padding: 0.6rem 1rem;
|
||||||
line-height: 150%;
|
/* line-height: 150%; */
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -13,10 +13,18 @@ interface TooltipProps extends Omit<PopoverProps, 'content'> {
|
|||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
|
||||||
|
content: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
export default function Tooltip({ text, ...rest }: TooltipProps) {
|
export default function Tooltip({ text, ...rest }: TooltipProps) {
|
||||||
return <Popover content={<TooltipContainer>{text}</TooltipContainer>} {...rest} />
|
return <Popover content={<TooltipContainer>{text}</TooltipContainer>} {...rest} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function TooltipContent({ content, ...rest }: TooltipContentProps) {
|
||||||
|
return <Popover content={<TooltipContainer>{content}</TooltipContainer>} {...rest} />
|
||||||
|
}
|
||||||
|
|
||||||
export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show'>) {
|
export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show'>) {
|
||||||
const [show, setShow] = useState(false)
|
const [show, setShow] = useState(false)
|
||||||
const open = useCallback(() => setShow(true), [setShow])
|
const open = useCallback(() => setShow(true), [setShow])
|
||||||
@ -29,3 +37,16 @@ export function MouseoverTooltip({ children, ...rest }: Omit<TooltipProps, 'show
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function MouseoverTooltipContent({ content, children, ...rest }: Omit<TooltipContentProps, 'show'>) {
|
||||||
|
const [show, setShow] = useState(false)
|
||||||
|
const open = useCallback(() => setShow(true), [setShow])
|
||||||
|
const close = useCallback(() => setShow(false), [setShow])
|
||||||
|
return (
|
||||||
|
<TooltipContent {...rest} show={show} content={content}>
|
||||||
|
<div onMouseEnter={open} onMouseLeave={close}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</TooltipContent>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@ const Wrapper = styled.div`
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
`
|
`
|
||||||
const Section = styled(AutoColumn)<{ inline?: boolean }>`
|
const Section = styled(AutoColumn)<{ inline?: boolean }>`
|
||||||
padding: ${({ inline }) => (inline ? '0' : '24px')};
|
padding: ${({ inline }) => (inline ? '0' : '0')};
|
||||||
`
|
`
|
||||||
|
|
||||||
const BottomSection = styled(Section)`
|
const BottomSection = styled(Section)`
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { TradeType } from '@uniswap/sdk-core'
|
|
||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { ThemeContext } from 'styled-components'
|
import { ThemeContext } from 'styled-components'
|
||||||
import { Field } from '../../state/swap/actions'
|
|
||||||
import { useUserSlippageTolerance } from '../../state/user/hooks'
|
|
||||||
import { TYPE } from '../../theme'
|
import { TYPE } from '../../theme'
|
||||||
import { computeSlippageAdjustedAmounts, computeTradePriceBreakdown } from '../../utils/prices'
|
import { computeTradePriceBreakdown } from '../../utils/prices'
|
||||||
import { AutoColumn } from '../Column'
|
import { AutoColumn } from '../Column'
|
||||||
import QuestionHelper from '../QuestionHelper'
|
|
||||||
import { RowBetween, RowFixed } from '../Row'
|
import { RowBetween, RowFixed } from '../Row'
|
||||||
import FormattedPriceImpact from './FormattedPriceImpact'
|
import FormattedPriceImpact from './FormattedPriceImpact'
|
||||||
import SwapRoute from './SwapRoute'
|
import SwapRoute from './SwapRoute'
|
||||||
@ -16,74 +12,28 @@ import SwapRoute from './SwapRoute'
|
|||||||
function TradeSummary({ trade }: { trade: V2Trade | V3Trade }) {
|
function TradeSummary({ trade }: { trade: V2Trade | V3Trade }) {
|
||||||
const theme = useContext(ThemeContext)
|
const theme = useContext(ThemeContext)
|
||||||
const { priceImpactWithoutFee, realizedLPFee } = computeTradePriceBreakdown(trade)
|
const { priceImpactWithoutFee, realizedLPFee } = computeTradePriceBreakdown(trade)
|
||||||
const isExactIn = trade.tradeType === TradeType.EXACT_INPUT
|
|
||||||
const [allowedSlippage] = useUserSlippageTolerance()
|
|
||||||
const slippageAdjustedAmounts = computeSlippageAdjustedAmounts(trade, allowedSlippage)
|
|
||||||
const price = trade.executionPrice
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AutoColumn style={{ padding: '8px 16px' }} gap="8px">
|
<AutoColumn gap={'8px'}>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
|
||||||
Price
|
|
||||||
</TYPE.black>
|
|
||||||
</RowFixed>
|
|
||||||
<TYPE.black color={theme.text1} fontSize={14}>
|
|
||||||
{'1 ' +
|
|
||||||
price?.quoteCurrency?.symbol +
|
|
||||||
' = ' +
|
|
||||||
price?.invert()?.toSignificant(6) +
|
|
||||||
' ' +
|
|
||||||
price?.baseCurrency?.symbol}
|
|
||||||
</TYPE.black>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
|
||||||
Inverted Price
|
|
||||||
</TYPE.black>
|
|
||||||
</RowFixed>
|
|
||||||
<TYPE.black color={theme.text1} fontSize={14}>
|
|
||||||
{'1 ' + price?.baseCurrency?.symbol + ' = ' + price?.toSignificant(6) + ' ' + price?.quoteCurrency?.symbol}
|
|
||||||
</TYPE.black>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
|
||||||
{isExactIn ? 'Minimum received' : 'Maximum sold'}
|
|
||||||
</TYPE.black>
|
|
||||||
<QuestionHelper text="Your transaction will revert if there is a large, unfavorable price movement before it is confirmed." />
|
|
||||||
</RowFixed>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.black color={theme.text1} fontSize={14}>
|
|
||||||
{isExactIn
|
|
||||||
? `${slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(4)} ${trade.outputAmount.currency.symbol}` ??
|
|
||||||
'-'
|
|
||||||
: `${slippageAdjustedAmounts[Field.INPUT]?.toSignificant(4)} ${trade.inputAmount.currency.symbol}` ??
|
|
||||||
'-'}
|
|
||||||
</TYPE.black>
|
|
||||||
</RowFixed>
|
|
||||||
</RowBetween>
|
|
||||||
<RowBetween>
|
|
||||||
<RowFixed>
|
|
||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
|
||||||
Price Impact
|
Price Impact
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
<QuestionHelper text="The difference between the market price and estimated price due to trade size." />
|
{/* <QuestionHelper text="The difference between the market price and estimated price due to trade size." /> */}
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<FormattedPriceImpact priceImpact={priceImpactWithoutFee} />
|
<FormattedPriceImpact priceImpact={priceImpactWithoutFee} />
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
<TYPE.black fontSize={12} fontWeight={400} color={theme.text2}>
|
||||||
Liquidity Provider Fee
|
Liquidity Provider Fee
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
<QuestionHelper text="A portion of each trade goes to liquidity providers as a protocol incentive." />
|
{/* <QuestionHelper text="A portion of each trade goes to liquidity providers as a protocol incentive." /> */}
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
<TYPE.black fontSize={14} color={theme.text1}>
|
<TYPE.black fontSize={12} color={theme.text1}>
|
||||||
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${trade.inputAmount.currency.symbol}` : '-'}
|
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${trade.inputAmount.currency.symbol}` : '-'}
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
@ -116,7 +66,7 @@ export function AdvancedSwapDetails({ trade }: AdvancedSwapDetailsProps) {
|
|||||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
||||||
Route
|
Route
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
<QuestionHelper text="Routing through these tokens resulted in the best price for your trade." />
|
{/* <QuestionHelper text="Routing through these tokens resulted in the best price for your trade." /> */}
|
||||||
</span>
|
</span>
|
||||||
<SwapRoute trade={trade} />
|
<SwapRoute trade={trade} />
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
@ -1,28 +1,14 @@
|
|||||||
import { stringify } from 'qs'
|
import { stringify } from 'qs'
|
||||||
import React, { useContext, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { useLocation } from 'react-router'
|
import { useLocation } from 'react-router'
|
||||||
import { Text } from 'rebass'
|
import { Link } from 'react-router-dom'
|
||||||
import { ThemeContext } from 'styled-components'
|
|
||||||
import useParsedQueryString from '../../hooks/useParsedQueryString'
|
import useParsedQueryString from '../../hooks/useParsedQueryString'
|
||||||
import useToggledVersion, { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
|
import useToggledVersion, { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
|
||||||
|
import { TYPE } from '../../theme'
|
||||||
|
import { ButtonPrimary } from '../Button'
|
||||||
|
|
||||||
import { StyledInternalLink } from '../../theme'
|
import { Zap } from 'react-feather'
|
||||||
import { YellowCard } from '../Card'
|
|
||||||
import { AutoColumn } from '../Column'
|
|
||||||
|
|
||||||
function VersionLinkContainer({ children }: { children: React.ReactNode }) {
|
|
||||||
const theme = useContext(ThemeContext)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<YellowCard style={{ marginTop: '4px', padding: '0.5rem 0.5rem' }}>
|
|
||||||
<AutoColumn gap="sm" justify="center" style={{ alignItems: 'center', textAlign: 'center' }}>
|
|
||||||
<Text lineHeight="145.23%;" fontSize={14} fontWeight={400} color={theme.text1}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
</AutoColumn>
|
|
||||||
</YellowCard>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function BetterTradeLink({
|
export default function BetterTradeLink({
|
||||||
version,
|
version,
|
||||||
@ -45,12 +31,24 @@ export default function BetterTradeLink({
|
|||||||
}, [location, search, version])
|
}, [location, search, version])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VersionLinkContainer>
|
<ButtonPrimary
|
||||||
{otherTradeNonexistent ? 'This trade can be executed on ' : 'There is a better price for this trade on '}
|
as={Link}
|
||||||
<StyledInternalLink to={linkDestination}>
|
to={linkDestination}
|
||||||
<b>Uniswap {version.toUpperCase()} ↗</b>
|
style={{
|
||||||
</StyledInternalLink>
|
width: 'fit-content',
|
||||||
</VersionLinkContainer>
|
padding: '.2rem .5rem',
|
||||||
|
wordBreak: 'keep-all',
|
||||||
|
height: '24px',
|
||||||
|
marginLeft: '.25rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zap size={12} style={{ marginRight: '0.25rem' }} />
|
||||||
|
<TYPE.small style={{ lineHeight: '120%' }} fontSize={12}>
|
||||||
|
{otherTradeNonexistent
|
||||||
|
? `No liquidity! Click to trade with ${version.toUpperCase()}`
|
||||||
|
: `Get a better price on ${version.toUpperCase()}`}
|
||||||
|
</TYPE.small>
|
||||||
|
</ButtonPrimary>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,11 +68,12 @@ export function DefaultVersionLink() {
|
|||||||
}, [location, search])
|
}, [location, search])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VersionLinkContainer>
|
<ButtonPrimary
|
||||||
Showing {version.toUpperCase()} price.{' '}
|
as={Link}
|
||||||
<StyledInternalLink to={linkDestination}>
|
to={linkDestination}
|
||||||
<b>Switch to Uniswap {DEFAULT_VERSION.toUpperCase()} ↗</b>
|
style={{ width: 'fit-content', marginTop: '4px', padding: '0.5rem 0.5rem' }}
|
||||||
</StyledInternalLink>
|
>
|
||||||
</VersionLinkContainer>
|
Showing {version.toUpperCase()} price. <b>Switch to Uniswap {DEFAULT_VERSION.toUpperCase()} ↗</b>
|
||||||
|
</ButtonPrimary>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,9 @@ export default function ConfirmSwapModal({
|
|||||||
trade={trade}
|
trade={trade}
|
||||||
disabledConfirm={showAcceptChanges}
|
disabledConfirm={showAcceptChanges}
|
||||||
swapErrorMessage={swapErrorMessage}
|
swapErrorMessage={swapErrorMessage}
|
||||||
allowedSlippage={allowedSlippage}
|
|
||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}, [allowedSlippage, onConfirm, showAcceptChanges, swapErrorMessage, trade])
|
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade])
|
||||||
|
|
||||||
// text to show while loading
|
// text to show while loading
|
||||||
const pendingText = `Swapping ${trade?.maximumAmountIn(allowedSlippage)?.toSignificant(6)} ${
|
const pendingText = `Swapping ${trade?.maximumAmountIn(allowedSlippage)?.toSignificant(6)} ${
|
||||||
|
@ -9,7 +9,7 @@ import { ErrorText, ErrorPill } from './styleds'
|
|||||||
*/
|
*/
|
||||||
export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
|
export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
|
||||||
return (
|
return (
|
||||||
<ErrorText fontWeight={500} fontSize={14} severity={warningSeverity(priceImpact)}>
|
<ErrorText fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}>
|
||||||
{priceImpact
|
{priceImpact
|
||||||
? priceImpact.lessThan(ONE_BIPS)
|
? priceImpact.lessThan(ONE_BIPS)
|
||||||
? `-${priceImpact.toFixed(2)}%`
|
? `-${priceImpact.toFixed(2)}%`
|
||||||
@ -21,7 +21,7 @@ export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Pe
|
|||||||
|
|
||||||
export function SmallFormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
|
export function SmallFormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
|
||||||
return (
|
return (
|
||||||
<ErrorPill fontWeight={500} fontSize={14} severity={warningSeverity(priceImpact)}>
|
<ErrorPill fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}>
|
||||||
{priceImpact
|
{priceImpact
|
||||||
? priceImpact.lessThan(ONE_BIPS)
|
? priceImpact.lessThan(ONE_BIPS)
|
||||||
? `(-${priceImpact.toFixed(2)}%)`
|
? `(-${priceImpact.toFixed(2)}%)`
|
||||||
|
@ -1,51 +1,28 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Version } from '../../hooks/useToggledVersion'
|
|
||||||
import Settings from '../Settings'
|
import Settings from '../Settings'
|
||||||
|
|
||||||
import { RowBetween, RowFixed } from '../Row'
|
import { RowBetween, RowFixed } from '../Row'
|
||||||
import { TYPE } from '../../theme'
|
import { TYPE } from '../../theme'
|
||||||
|
|
||||||
// import { Info } from 'react-feather'
|
|
||||||
|
|
||||||
const StyledSwapHeader = styled.div`
|
const StyledSwapHeader = styled.div`
|
||||||
padding: 1rem 1.25rem 0.5rem 1.25rem;
|
padding: 1rem 1.25rem 0.5rem 1.25rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: ${({ theme }) => theme.text2};
|
color: ${({ theme }) => theme.text2};
|
||||||
`
|
`
|
||||||
//
|
|
||||||
// const InfoLink = styled(ExternalLink)`
|
|
||||||
// width: 100%;
|
|
||||||
// text-align: center;
|
|
||||||
// font-size: 14px;
|
|
||||||
// height: 20px;
|
|
||||||
// margin-right: 8px;
|
|
||||||
// color: ${({ theme }) => theme.text1};
|
|
||||||
// `
|
|
||||||
|
|
||||||
interface SwapHeaderProps {
|
export default function SwapHeader() {
|
||||||
toggledVersion: Version
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function SwapHeader({ toggledVersion }: SwapHeaderProps) {
|
|
||||||
return (
|
return (
|
||||||
<StyledSwapHeader>
|
<StyledSwapHeader>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<TYPE.black fontWeight={500} fontSize={16} style={{ opacity: '0.6' }}>
|
|
||||||
Swap ({toggledVersion})
|
|
||||||
</TYPE.black>
|
|
||||||
<RowFixed>
|
<RowFixed>
|
||||||
{/* Send icon appears here when expert mode is toggled on */}
|
<TYPE.black fontWeight={500} fontSize={16} style={{ marginRight: '8px' }}>
|
||||||
{/* <Send style={{ marginRight: '16px' }} size="20" onClick={() => onChangeRecipient('')} /> */}
|
Swap{' '}
|
||||||
{/* This info icon should open info.uniswap.org with the pair */}
|
</TYPE.black>
|
||||||
{/*{trade && (*/}
|
</RowFixed>
|
||||||
{/* <InfoLink*/}
|
<RowFixed>
|
||||||
{/* href={'https://info.uniswap.org/pair/' + trade.route.pairs[0].liquidityToken.address}*/}
|
{/* <TradeInfo disabled={!trade} trade={trade} /> */}
|
||||||
{/* target="_blank"*/}
|
{/* <div style={{ width: '8px' }}></div> */}
|
||||||
{/* >*/}
|
|
||||||
{/* <Info size="20" style={{ opacity: '0.6' }} />*/}
|
|
||||||
{/* </InfoLink>*/}
|
|
||||||
{/*)}*/}
|
|
||||||
|
|
||||||
<Settings />
|
<Settings />
|
||||||
</RowFixed>
|
</RowFixed>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
@ -1,61 +1,30 @@
|
|||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||||
import { Percent } from '@uniswap/sdk-core'
|
|
||||||
import React, { useContext, useMemo, useState } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { Repeat } from 'react-feather'
|
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { ThemeContext } from 'styled-components'
|
import { computeTradePriceBreakdown, warningSeverity } from '../../utils/prices'
|
||||||
import { computeTradePriceBreakdown, formatExecutionPrice, warningSeverity } from '../../utils/prices'
|
|
||||||
import { ButtonError } from '../Button'
|
import { ButtonError } from '../Button'
|
||||||
import { AutoColumn } from '../Column'
|
import {} from '../Column'
|
||||||
import { AutoRow, RowBetween } from '../Row'
|
import { AutoRow } from '../Row'
|
||||||
import { StyledBalanceMaxMini, SwapCallbackError } from './styleds'
|
import { SwapCallbackError } from './styleds'
|
||||||
|
|
||||||
export default function SwapModalFooter({
|
export default function SwapModalFooter({
|
||||||
trade,
|
trade,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
allowedSlippage,
|
|
||||||
swapErrorMessage,
|
swapErrorMessage,
|
||||||
disabledConfirm,
|
disabledConfirm,
|
||||||
}: {
|
}: {
|
||||||
trade: V2Trade | V3Trade
|
trade: V2Trade | V3Trade
|
||||||
allowedSlippage: Percent
|
|
||||||
onConfirm: () => void
|
onConfirm: () => void
|
||||||
swapErrorMessage: string | undefined
|
swapErrorMessage: string | undefined
|
||||||
disabledConfirm: boolean
|
disabledConfirm: boolean
|
||||||
}) {
|
}) {
|
||||||
const [showInverted, setShowInverted] = useState<boolean>(false)
|
|
||||||
const theme = useContext(ThemeContext)
|
|
||||||
const { priceImpactWithoutFee } = useMemo(() => computeTradePriceBreakdown(trade), [trade])
|
const { priceImpactWithoutFee } = useMemo(() => computeTradePriceBreakdown(trade), [trade])
|
||||||
const severity = warningSeverity(priceImpactWithoutFee)
|
const severity = warningSeverity(priceImpactWithoutFee)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AutoColumn gap="0px">
|
|
||||||
<RowBetween align="center">
|
|
||||||
<Text fontWeight={400} fontSize={14} color={theme.text2}>
|
|
||||||
Price
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
fontWeight={500}
|
|
||||||
fontSize={14}
|
|
||||||
color={theme.text1}
|
|
||||||
style={{
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
textAlign: 'right',
|
|
||||||
paddingLeft: '10px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{formatExecutionPrice(trade, showInverted, allowedSlippage)}
|
|
||||||
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
|
|
||||||
<Repeat size={14} />
|
|
||||||
</StyledBalanceMaxMini>
|
|
||||||
</Text>
|
|
||||||
</RowBetween>
|
|
||||||
</AutoColumn>
|
|
||||||
|
|
||||||
<AutoRow>
|
<AutoRow>
|
||||||
<ButtonError
|
<ButtonError
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Percent, TradeType } from '@uniswap/sdk-core'
|
import { Percent, TradeType } from '@uniswap/sdk-core'
|
||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext, useState } from 'react'
|
||||||
import { ArrowDown, AlertTriangle } from 'react-feather'
|
import { ArrowDown, AlertTriangle } from 'react-feather'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { ThemeContext } from 'styled-components'
|
import styled, { ThemeContext } from 'styled-components'
|
||||||
import { TYPE } from '../../theme'
|
import { TYPE } from '../../theme'
|
||||||
import { ButtonPrimary } from '../Button'
|
import { ButtonPrimary } from '../Button'
|
||||||
import { isAddress, shortenAddress } from '../../utils'
|
import { isAddress, shortenAddress } from '../../utils'
|
||||||
@ -13,6 +13,30 @@ import CurrencyLogo from '../CurrencyLogo'
|
|||||||
import { RowBetween, RowFixed } from '../Row'
|
import { RowBetween, RowFixed } from '../Row'
|
||||||
import { TruncatedText, SwapShowAcceptChanges } from './styleds'
|
import { TruncatedText, SwapShowAcceptChanges } from './styleds'
|
||||||
|
|
||||||
|
import { AdvancedSwapDetails } from './AdvancedSwapDetails'
|
||||||
|
import { LightCard } from '../Card'
|
||||||
|
|
||||||
|
import { DarkGreyCard } from '../Card'
|
||||||
|
import TradePrice from '../swap/TradePrice'
|
||||||
|
|
||||||
|
export const ArrowWrapper = styled.div`
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 12px;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
position: relative;
|
||||||
|
margin-top: -18px;
|
||||||
|
margin-bottom: -18px;
|
||||||
|
left: calc(50% - 16px);
|
||||||
|
/* transform: rotate(90deg); */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
|
/* border: 4px solid ${({ theme }) => theme.bg0}; */
|
||||||
|
z-index: 2;
|
||||||
|
`
|
||||||
|
|
||||||
export default function SwapModalHeader({
|
export default function SwapModalHeader({
|
||||||
trade,
|
trade,
|
||||||
allowedSlippage,
|
allowedSlippage,
|
||||||
@ -31,41 +55,82 @@ export default function SwapModalHeader({
|
|||||||
|
|
||||||
const theme = useContext(ThemeContext)
|
const theme = useContext(ThemeContext)
|
||||||
|
|
||||||
|
const [showInverted, setShowInverted] = useState<boolean>(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoColumn gap={'md'} style={{ marginTop: '20px' }}>
|
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
|
||||||
<RowBetween align="flex-end">
|
<DarkGreyCard padding="0.75rem 1rem">
|
||||||
<RowFixed gap={'0px'}>
|
<AutoColumn gap={'8px'}>
|
||||||
<CurrencyLogo currency={trade.inputAmount.currency} size={'24px'} style={{ marginRight: '12px' }} />
|
<RowBetween>
|
||||||
<TruncatedText
|
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
|
||||||
fontSize={24}
|
{'From'}
|
||||||
fontWeight={500}
|
</TYPE.body>
|
||||||
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? theme.primary1 : ''}
|
<TYPE.body fontSize={14} color={theme.text3}>
|
||||||
>
|
{'$-'}
|
||||||
{maximumAmountIn.toSignificant(6)}
|
</TYPE.body>
|
||||||
</TruncatedText>
|
</RowBetween>
|
||||||
</RowFixed>
|
<RowBetween align="center">
|
||||||
<RowFixed gap={'0px'}>
|
<RowFixed gap={'0px'}>
|
||||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
<CurrencyLogo currency={trade.inputAmount.currency} size={'20px'} style={{ marginRight: '12px' }} />
|
||||||
{trade.inputAmount.currency.symbol}
|
<Text fontSize={20} fontWeight={500}>
|
||||||
</Text>
|
{trade.inputAmount.currency.symbol}
|
||||||
</RowFixed>
|
</Text>
|
||||||
</RowBetween>
|
</RowFixed>
|
||||||
<RowFixed>
|
<RowFixed gap={'0px'}>
|
||||||
<ArrowDown size="16" color={theme.text2} style={{ marginLeft: '4px', minWidth: '16px' }} />
|
<TruncatedText
|
||||||
</RowFixed>
|
fontSize={24}
|
||||||
<RowBetween align="flex-end">
|
fontWeight={500}
|
||||||
<RowFixed gap={'0px'}>
|
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? theme.primary1 : ''}
|
||||||
<CurrencyLogo currency={trade.outputAmount.currency} size={'24px'} style={{ marginRight: '12px' }} />
|
>
|
||||||
<TruncatedText fontSize={24} fontWeight={500}>
|
{maximumAmountIn.toSignificant(6)}
|
||||||
{minimumAmountOut.toSignificant(6)}
|
</TruncatedText>
|
||||||
</TruncatedText>
|
</RowFixed>
|
||||||
</RowFixed>
|
</RowBetween>
|
||||||
<RowFixed gap={'0px'}>
|
</AutoColumn>
|
||||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
</DarkGreyCard>
|
||||||
{trade.outputAmount.currency.symbol}
|
<ArrowWrapper>
|
||||||
</Text>
|
<ArrowDown size="16" color={theme.text2} />
|
||||||
</RowFixed>
|
</ArrowWrapper>
|
||||||
|
<DarkGreyCard padding="0.75rem 1rem" style={{ marginBottom: '0.25rem' }}>
|
||||||
|
<AutoColumn gap={'8px'}>
|
||||||
|
<RowBetween>
|
||||||
|
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
|
||||||
|
{'To'}
|
||||||
|
</TYPE.body>
|
||||||
|
<TYPE.body fontSize={14} color={theme.text3}>
|
||||||
|
{'$-'}
|
||||||
|
</TYPE.body>
|
||||||
|
</RowBetween>
|
||||||
|
<RowBetween align="flex-end">
|
||||||
|
<RowFixed gap={'0px'}>
|
||||||
|
<CurrencyLogo currency={trade.outputAmount.currency} size={'20px'} style={{ marginRight: '12px' }} />
|
||||||
|
<Text fontSize={20} fontWeight={500}>
|
||||||
|
{trade.outputAmount.currency.symbol}
|
||||||
|
</Text>
|
||||||
|
</RowFixed>
|
||||||
|
<RowFixed gap={'0px'}>
|
||||||
|
<TruncatedText fontSize={24} fontWeight={500}>
|
||||||
|
{minimumAmountOut.toSignificant(6)}
|
||||||
|
</TruncatedText>
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
</AutoColumn>
|
||||||
|
</DarkGreyCard>
|
||||||
|
<RowBetween style={{ marginTop: '0.25rem', padding: '0 1rem' }}>
|
||||||
|
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
|
||||||
|
{'Price:'}
|
||||||
|
</TYPE.body>
|
||||||
|
<TradePrice
|
||||||
|
price={trade.worstExecutionPrice(allowedSlippage)}
|
||||||
|
showInverted={showInverted}
|
||||||
|
setShowInverted={setShowInverted}
|
||||||
|
/>
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
|
|
||||||
|
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
|
||||||
|
<AdvancedSwapDetails trade={trade} />
|
||||||
|
</LightCard>
|
||||||
|
|
||||||
{showAcceptChanges ? (
|
{showAcceptChanges ? (
|
||||||
<SwapShowAcceptChanges justify="flex-start" gap={'0px'}>
|
<SwapShowAcceptChanges justify="flex-start" gap={'0px'}>
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
@ -82,9 +147,10 @@ export default function SwapModalHeader({
|
|||||||
</RowBetween>
|
</RowBetween>
|
||||||
</SwapShowAcceptChanges>
|
</SwapShowAcceptChanges>
|
||||||
) : null}
|
) : null}
|
||||||
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
|
||||||
|
{/* <AutoColumn justify="flex-start" gap="sm" style={{ padding: '.75rem 1rem' }}>
|
||||||
{trade.tradeType === TradeType.EXACT_INPUT ? (
|
{trade.tradeType === TradeType.EXACT_INPUT ? (
|
||||||
<TYPE.italic textAlign="left" style={{ width: '100%' }}>
|
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||||
{`Output is estimated. You will receive at least `}
|
{`Output is estimated. You will receive at least `}
|
||||||
<b>
|
<b>
|
||||||
{minimumAmountOut.toSignificant(6)} {trade.outputAmount.currency.symbol}
|
{minimumAmountOut.toSignificant(6)} {trade.outputAmount.currency.symbol}
|
||||||
@ -92,7 +158,7 @@ export default function SwapModalHeader({
|
|||||||
{' or the transaction will revert.'}
|
{' or the transaction will revert.'}
|
||||||
</TYPE.italic>
|
</TYPE.italic>
|
||||||
) : (
|
) : (
|
||||||
<TYPE.italic textAlign="left" style={{ width: '100%' }}>
|
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||||
{`Input is estimated. You will sell at most `}
|
{`Input is estimated. You will sell at most `}
|
||||||
<b>
|
<b>
|
||||||
{maximumAmountIn.toSignificant(6)} {trade.inputAmount.currency.symbol}
|
{maximumAmountIn.toSignificant(6)} {trade.inputAmount.currency.symbol}
|
||||||
@ -100,7 +166,7 @@ export default function SwapModalHeader({
|
|||||||
{' or the transaction will revert.'}
|
{' or the transaction will revert.'}
|
||||||
</TYPE.italic>
|
</TYPE.italic>
|
||||||
)}
|
)}
|
||||||
</AutoColumn>
|
</AutoColumn> */}
|
||||||
{recipient !== null ? (
|
{recipient !== null ? (
|
||||||
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
||||||
<TYPE.main>
|
<TYPE.main>
|
||||||
|
@ -4,8 +4,6 @@ import { useContext } from 'react'
|
|||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
|
|
||||||
import styled, { ThemeContext } from 'styled-components'
|
import styled, { ThemeContext } from 'styled-components'
|
||||||
import { StyledBalanceMaxMini } from './styleds'
|
|
||||||
import Switch from '../../assets/svg/switch.svg'
|
|
||||||
|
|
||||||
interface TradePriceProps {
|
interface TradePriceProps {
|
||||||
price: Price
|
price: Price
|
||||||
@ -13,11 +11,19 @@ interface TradePriceProps {
|
|||||||
setShowInverted: (showInverted: boolean) => void
|
setShowInverted: (showInverted: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledPriceContainer = styled.div`
|
const StyledPriceContainer = styled.button`
|
||||||
justify-content: flex-end;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: fit-content;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 400;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
margin-left: 1rem;
|
||||||
|
height: 24px;
|
||||||
|
cursor: pointer;
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function TradePrice({ price, showInverted, setShowInverted }: TradePriceProps) {
|
export default function TradePrice({ price, showInverted, setShowInverted }: TradePriceProps) {
|
||||||
@ -25,7 +31,7 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
|
|||||||
|
|
||||||
let formattedPrice: string
|
let formattedPrice: string
|
||||||
try {
|
try {
|
||||||
formattedPrice = showInverted ? price.toSignificant(6) : price.invert()?.toSignificant(6)
|
formattedPrice = showInverted ? price.toSignificant(4) : price.invert()?.toSignificant(4)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
formattedPrice = '0'
|
formattedPrice = '0'
|
||||||
}
|
}
|
||||||
@ -35,14 +41,11 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
|
|||||||
const flipPrice = useCallback(() => setShowInverted(!showInverted), [setShowInverted, showInverted])
|
const flipPrice = useCallback(() => setShowInverted(!showInverted), [setShowInverted, showInverted])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledPriceContainer>
|
<StyledPriceContainer onClick={flipPrice}>
|
||||||
<div style={{ alignItems: 'center', display: 'flex', width: 'fit-content' }}>
|
<div style={{ alignItems: 'center', display: 'flex', width: 'fit-content' }}>
|
||||||
<Text fontWeight={500} fontSize={14} color={theme.text2}>
|
<Text fontWeight={500} fontSize={14} color={theme.text1}>
|
||||||
{'1 ' + labelInverted + ' = ' + formattedPrice ?? '-'} {label}
|
{'1 ' + labelInverted + ' = ' + formattedPrice ?? '-'} {label}
|
||||||
</Text>
|
</Text>
|
||||||
<StyledBalanceMaxMini style={{ marginLeft: '0.5rem' }} onClick={flipPrice}>
|
|
||||||
<img width={'16px'} src={Switch} alt="logo" />
|
|
||||||
</StyledBalanceMaxMini>
|
|
||||||
</div>
|
</div>
|
||||||
</StyledPriceContainer>
|
</StyledPriceContainer>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { transparentize } from 'polished'
|
import { transparentize } from 'polished'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
import { AlertTriangle } from 'react-feather'
|
import { AlertTriangle } from 'react-feather'
|
||||||
import styled, { css } from 'styled-components'
|
import styled, { css } from 'styled-components'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
@ -84,10 +86,11 @@ export const StyledBalanceMaxMini = styled.button`
|
|||||||
background-color: ${({ theme }) => theme.bg1};
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0.25rem 0.35rem;
|
padding: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
opacity: 0.6;
|
||||||
|
margin-right: 0.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${({ theme }) => theme.text1};
|
color: ${({ theme }) => theme.text1};
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -106,8 +109,9 @@ export const StyledBalanceMaxMini = styled.button`
|
|||||||
|
|
||||||
export const TruncatedText = styled(Text)`
|
export const TruncatedText = styled(Text)`
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
width: 220px;
|
max-width: 220px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
text-align: right;
|
||||||
`
|
`
|
||||||
|
|
||||||
// styles
|
// styles
|
||||||
@ -184,3 +188,14 @@ export const Separator = styled.div`
|
|||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: ${({ theme }) => theme.bg2};
|
background-color: ${({ theme }) => theme.bg2};
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const V2TradeAlertWrapper = styled(Link)`
|
||||||
|
background-color: ${({ theme }) => theme.bg2};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 12px;
|
||||||
|
height: 22px;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
padding: 0 0.25rem 0 0.5rem;
|
||||||
|
text-decoration: none !important;
|
||||||
|
`
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||||
|
import { AdvancedSwapDetails } from 'components/swap/AdvancedSwapDetails'
|
||||||
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
|
||||||
|
import { MouseoverTooltip, MouseoverTooltipContent } from 'components/Tooltip'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import { ArrowDown, Repeat, Unlock } from 'react-feather'
|
import { ArrowDown, HelpCircle, CheckCircle, Info, X } from 'react-feather'
|
||||||
import ReactGA from 'react-ga'
|
import ReactGA from 'react-ga'
|
||||||
import { RouteComponentProps } from 'react-router-dom'
|
import { RouteComponentProps } from 'react-router-dom'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { ThemeContext } from 'styled-components'
|
import { ThemeContext } from 'styled-components'
|
||||||
import AddressInputPanel from '../../components/AddressInputPanel'
|
import AddressInputPanel from '../../components/AddressInputPanel'
|
||||||
import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary } from '../../components/Button'
|
import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary, ButtonGray } from '../../components/Button'
|
||||||
import { GreyCard } from '../../components/Card'
|
import { GreyCard } from '../../components/Card'
|
||||||
import { AutoColumn } from '../../components/Column'
|
import { AutoColumn } from '../../components/Column'
|
||||||
import CurrencyInputPanel from '../../components/CurrencyInputPanel'
|
import CurrencyInputPanel from '../../components/CurrencyInputPanel'
|
||||||
import CurrencyLogo from '../../components/CurrencyLogo'
|
import CurrencyLogo from '../../components/CurrencyLogo'
|
||||||
import Loader from '../../components/Loader'
|
import Loader from '../../components/Loader'
|
||||||
import ProgressSteps from '../../components/ProgressSteps'
|
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
|
||||||
import { AutoRow } from '../../components/Row'
|
|
||||||
import BetterTradeLink from '../../components/swap/BetterTradeLink'
|
|
||||||
import confirmPriceImpactWithoutFee from '../../components/swap/confirmPriceImpactWithoutFee'
|
import confirmPriceImpactWithoutFee from '../../components/swap/confirmPriceImpactWithoutFee'
|
||||||
import ConfirmSwapModal from '../../components/swap/ConfirmSwapModal'
|
import ConfirmSwapModal from '../../components/swap/ConfirmSwapModal'
|
||||||
|
|
||||||
import { ArrowWrapper, BottomGrouping, Dots, SwapCallbackError, Wrapper } from '../../components/swap/styleds'
|
import { ArrowWrapper, BottomGrouping, Dots, SwapCallbackError, Wrapper } from '../../components/swap/styleds'
|
||||||
import SwapHeader from '../../components/swap/SwapHeader'
|
|
||||||
import TradePrice from '../../components/swap/TradePrice'
|
import TradePrice from '../../components/swap/TradePrice'
|
||||||
import TokenWarningModal from '../../components/TokenWarningModal'
|
import TokenWarningModal from '../../components/TokenWarningModal'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
@ -46,11 +46,15 @@ import {
|
|||||||
import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks'
|
import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks'
|
||||||
import { LinkStyledButton, TYPE } from '../../theme'
|
import { LinkStyledButton, TYPE } from '../../theme'
|
||||||
import { getTradeVersion } from '../../utils/getTradeVersion'
|
import { getTradeVersion } from '../../utils/getTradeVersion'
|
||||||
import { isTradeBetter } from '../../utils/isTradeBetter'
|
|
||||||
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
||||||
import { computeTradePriceBreakdown, warningSeverity } from '../../utils/prices'
|
import { computeTradePriceBreakdown, warningSeverity } from '../../utils/prices'
|
||||||
import AppBody from '../AppBody'
|
import AppBody from '../AppBody'
|
||||||
|
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { isTradeBetter } from '../../utils/isTradeBetter'
|
||||||
|
import BetterTradeLink from '../../components/swap/BetterTradeLink'
|
||||||
|
import SwapHeader from '../../components/swap/SwapHeader'
|
||||||
|
|
||||||
export default function Swap({ history }: RouteComponentProps) {
|
export default function Swap({ history }: RouteComponentProps) {
|
||||||
const loadedUrlParams = useDefaultsFromURLSearch()
|
const loadedUrlParams = useDefaultsFromURLSearch()
|
||||||
|
|
||||||
@ -321,7 +325,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
onDismiss={handleDismissTokenWarning}
|
onDismiss={handleDismissTokenWarning}
|
||||||
/>
|
/>
|
||||||
<AppBody>
|
<AppBody>
|
||||||
<SwapHeader toggledVersion={toggledVersion} />
|
<SwapHeader />
|
||||||
<Wrapper id="swap-page">
|
<Wrapper id="swap-page">
|
||||||
<ConfirmSwapModal
|
<ConfirmSwapModal
|
||||||
isOpen={showConfirm}
|
isOpen={showConfirm}
|
||||||
@ -353,14 +357,13 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
id="swap-currency-input"
|
id="swap-currency-input"
|
||||||
/>
|
/>
|
||||||
<ArrowWrapper clickable>
|
<ArrowWrapper clickable>
|
||||||
<Repeat
|
<ArrowDown
|
||||||
size="16"
|
size="16"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setApprovalSubmitted(false) // reset 2 step UI for approvals
|
setApprovalSubmitted(false) // reset 2 step UI for approvals
|
||||||
onSwitchTokens()
|
onSwitchTokens()
|
||||||
}}
|
}}
|
||||||
color={currencies[Field.INPUT] && currencies[Field.OUTPUT] ? theme.text1 : theme.text3}
|
color={currencies[Field.INPUT] && currencies[Field.OUTPUT] ? theme.text1 : theme.text3}
|
||||||
style={{ transform: 'rotate(90deg)' }}
|
|
||||||
/>
|
/>
|
||||||
</ArrowWrapper>
|
</ArrowWrapper>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
@ -368,7 +371,7 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
onUserInput={handleTypeOutput}
|
onUserInput={handleTypeOutput}
|
||||||
label={independentField === Field.INPUT && !showWrap ? 'To (at least)' : 'To'}
|
label={independentField === Field.INPUT && !showWrap ? 'To (at least)' : 'To'}
|
||||||
showMaxButton={false}
|
showMaxButton={false}
|
||||||
hideBalance={true}
|
hideBalance={false}
|
||||||
showFiatValue
|
showFiatValue
|
||||||
currency={currencies[Field.OUTPUT]}
|
currency={currencies[Field.OUTPUT]}
|
||||||
onCurrencySelect={handleOutputSelect}
|
onCurrencySelect={handleOutputSelect}
|
||||||
@ -391,20 +394,84 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
<AddressInputPanel id="recipient" value={recipient} onChange={onChangeRecipient} />
|
<AddressInputPanel id="recipient" value={recipient} onChange={onChangeRecipient} />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
{trade ? (
|
|
||||||
<TradePrice
|
<RowBetween style={{ justifyContent: !trade ? 'center' : 'space-between' }}>
|
||||||
price={trade.worstExecutionPrice(allowedSlippage)}
|
<RowFixed>
|
||||||
showInverted={showInverted}
|
{[V3TradeState.VALID, V3TradeState.SYNCING, V3TradeState.NO_ROUTE_FOUND].includes(v3TradeState) &&
|
||||||
setShowInverted={setShowInverted}
|
(toggledVersion === Version.v3 && isTradeBetter(v3Trade, v2Trade) ? (
|
||||||
/>
|
<BetterTradeLink version={Version.v2} otherTradeNonexistent={!v3Trade} />
|
||||||
) : null}
|
) : toggledVersion === Version.v2 && isTradeBetter(v2Trade, v3Trade) ? (
|
||||||
{[V3TradeState.VALID, V3TradeState.SYNCING, V3TradeState.NO_ROUTE_FOUND].includes(v3TradeState) ? (
|
<BetterTradeLink version={Version.v3} otherTradeNonexistent={!v2Trade} />
|
||||||
toggledVersion === Version.v3 && isTradeBetter(v3Trade, v2Trade) ? (
|
) : (
|
||||||
<BetterTradeLink version={Version.v2} otherTradeNonexistent={!v3Trade} />
|
toggledVersion === Version.v2 && (
|
||||||
) : toggledVersion === Version.v2 && isTradeBetter(v2Trade, v3Trade) ? (
|
<ButtonGray
|
||||||
<BetterTradeLink version={Version.v3} otherTradeNonexistent={!v2Trade} />
|
width="fit-content"
|
||||||
) : null
|
padding="0.1rem 0.5rem 0.1rem 0.35rem"
|
||||||
) : null}
|
as={Link}
|
||||||
|
to="/swap"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '24px',
|
||||||
|
opacity: 0.8,
|
||||||
|
lineHeight: '120%',
|
||||||
|
marginLeft: '0.25rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<X color={theme.text3} size={12} />
|
||||||
|
<TYPE.main style={{ lineHeight: '120%' }} fontSize={12}>
|
||||||
|
Routed via V2
|
||||||
|
</TYPE.main>
|
||||||
|
</ButtonGray>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
|
||||||
|
{toggledVersion === Version.v3 && trade && isTradeBetter(v2Trade, v3Trade) && (
|
||||||
|
<ButtonGray
|
||||||
|
width="fit-content"
|
||||||
|
padding="0.1rem 0.5rem"
|
||||||
|
disabled
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
height: '24px',
|
||||||
|
opacity: 0.4,
|
||||||
|
marginLeft: '0.25rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TYPE.black fontSize={12}>V3</TYPE.black>
|
||||||
|
</ButtonGray>
|
||||||
|
)}
|
||||||
|
</RowFixed>
|
||||||
|
<RowFixed>
|
||||||
|
{trade ? (
|
||||||
|
<TradePrice
|
||||||
|
price={trade.worstExecutionPrice(allowedSlippage)}
|
||||||
|
showInverted={showInverted}
|
||||||
|
setShowInverted={setShowInverted}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<TYPE.main></TYPE.main>
|
||||||
|
)}
|
||||||
|
{trade && (
|
||||||
|
<MouseoverTooltipContent content={<AdvancedSwapDetails trade={trade} />}>
|
||||||
|
<Info
|
||||||
|
size={16}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
height: '24px',
|
||||||
|
opacity: 0.4,
|
||||||
|
margin: '0 .75rem 0 .5rem',
|
||||||
|
}}
|
||||||
|
color={theme.text1}
|
||||||
|
/>
|
||||||
|
</MouseoverTooltipContent>
|
||||||
|
)}
|
||||||
|
</RowFixed>
|
||||||
|
</RowBetween>
|
||||||
|
|
||||||
<BottomGrouping>
|
<BottomGrouping>
|
||||||
{swapIsUnsupported ? (
|
{swapIsUnsupported ? (
|
||||||
<ButtonPrimary disabled={true}>
|
<ButtonPrimary disabled={true}>
|
||||||
@ -447,19 +514,29 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
<span style={{ display: 'flex', alignItems: 'center' }}>
|
<span style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<CurrencyLogo
|
<CurrencyLogo
|
||||||
currency={currencies[Field.INPUT]}
|
currency={currencies[Field.INPUT]}
|
||||||
size={'16px'}
|
size={'20px'}
|
||||||
style={{ marginRight: '8px' }}
|
style={{ marginRight: '8px' }}
|
||||||
/>
|
/>
|
||||||
{/* we need to shorten this string on mobile */}
|
{/* we need to shorten this string on mobile */}
|
||||||
{'Allow Uniswap to spend your ' + currencies[Field.INPUT]?.symbol}
|
{approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
|
||||||
|
? currencies[Field.INPUT]?.symbol + ' unlocked for trading.'
|
||||||
|
: 'Allow Uniswap to spend your ' + currencies[Field.INPUT]?.symbol}
|
||||||
</span>
|
</span>
|
||||||
{approvalState === ApprovalState.PENDING ? (
|
{approvalState === ApprovalState.PENDING ? (
|
||||||
<Loader stroke="white" />
|
<Loader stroke="white" />
|
||||||
) : (approvalSubmitted && approvalState === ApprovalState.APPROVED) ||
|
) : (approvalSubmitted && approvalState === ApprovalState.APPROVED) ||
|
||||||
signatureState === UseERC20PermitState.SIGNED ? (
|
signatureState === UseERC20PermitState.SIGNED ? (
|
||||||
<Unlock size="16" stroke="white" />
|
<CheckCircle size="20" color={theme.green1} />
|
||||||
) : (
|
) : (
|
||||||
<Unlock size="16" stroke="white" />
|
<MouseoverTooltip
|
||||||
|
text={
|
||||||
|
'You cannot swap until you give Uniswap permission to spend your ' +
|
||||||
|
currencies[Field.INPUT]?.symbol +
|
||||||
|
'. You only have to do this once per token and only when you are selling a token for the first time.'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<HelpCircle size="20" color={'white'} />
|
||||||
|
</MouseoverTooltip>
|
||||||
)}
|
)}
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
</ButtonConfirmed>
|
</ButtonConfirmed>
|
||||||
@ -491,13 +568,6 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
</Text>
|
</Text>
|
||||||
</ButtonError>
|
</ButtonError>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
{showApproveFlow && (
|
|
||||||
<ProgressSteps
|
|
||||||
steps={[
|
|
||||||
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
) : (
|
) : (
|
||||||
<ButtonError
|
<ButtonError
|
||||||
|
@ -28,7 +28,7 @@ export default createReducer(initialState, (builder) =>
|
|||||||
.addCase(setOpenModal, (state, action) => {
|
.addCase(setOpenModal, (state, action) => {
|
||||||
state.openModal = action.payload
|
state.openModal = action.payload
|
||||||
})
|
})
|
||||||
.addCase(addPopup, (state, { payload: { content, key, removeAfterMs = 15000 } }) => {
|
.addCase(addPopup, (state, { payload: { content, key, removeAfterMs = 25000 } }) => {
|
||||||
state.popupList = (key ? state.popupList.filter((popup) => popup.key !== key) : state.popupList).concat([
|
state.popupList = (key ? state.popupList.filter((popup) => popup.key !== key) : state.popupList).concat([
|
||||||
{
|
{
|
||||||
key: key || nanoid(),
|
key: key || nanoid(),
|
||||||
|
@ -47,9 +47,9 @@ export function colors(darkMode: boolean): Colors {
|
|||||||
text5: darkMode ? '#2C2F36' : '#EDEEF2',
|
text5: darkMode ? '#2C2F36' : '#EDEEF2',
|
||||||
|
|
||||||
// backgrounds / greys
|
// backgrounds / greys
|
||||||
bg0: darkMode ? '#191B1F' : '#FFFFFF',
|
bg0: darkMode ? '#191B1F' : '#F7F8FA',
|
||||||
bg1: darkMode ? '#212429' : '#F7F8FA',
|
bg1: darkMode ? '#212429' : '#EDEEF2',
|
||||||
bg2: darkMode ? '#2C2F36' : '#EDEEF2',
|
bg2: darkMode ? '#2C2F36' : '#F0F0F0',
|
||||||
bg3: darkMode ? '#40444F' : '#CED0D9',
|
bg3: darkMode ? '#40444F' : '#CED0D9',
|
||||||
bg4: darkMode ? '#565A69' : '#888D9B',
|
bg4: darkMode ? '#565A69' : '#888D9B',
|
||||||
bg5: darkMode ? '#6C7284' : '#888D9B',
|
bg5: darkMode ? '#6C7284' : '#888D9B',
|
||||||
@ -221,7 +221,7 @@ html {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
font-feature-settings: 'ss01' on, 'ss02' on, 'cv01' on, 'cv03' on;
|
font-feature-settings: 'ss01' on, 'cv01' on, 'cv03' on;
|
||||||
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user