Style updates, Approve UI updates (#841)
improvements(approvals): match approve flow to add/remove, update UI styles
This commit is contained in:
parent
c133c472be
commit
0004db3d4a
@ -1,4 +1,4 @@
|
|||||||
import { TEST_ADDRESS_NEVER_USE } from '../support/commands'
|
import { TEST_ADDRESS_NEVER_USE_SHORTENED } from '../support/commands'
|
||||||
|
|
||||||
describe('Landing Page', () => {
|
describe('Landing Page', () => {
|
||||||
beforeEach(() => cy.visit('/'))
|
beforeEach(() => cy.visit('/'))
|
||||||
@ -22,6 +22,6 @@ describe('Landing Page', () => {
|
|||||||
|
|
||||||
it('is connected', () => {
|
it('is connected', () => {
|
||||||
cy.get('#web3-status-connected').click()
|
cy.get('#web3-status-connected').click()
|
||||||
cy.get('#web3-account-identifier-row').contains(TEST_ADDRESS_NEVER_USE)
|
cy.get('#web3-account-identifier-row').contains(TEST_ADDRESS_NEVER_USE_SHORTENED)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
2
cypress/support/commands.d.ts
vendored
2
cypress/support/commands.d.ts
vendored
@ -1,5 +1,7 @@
|
|||||||
export const TEST_ADDRESS_NEVER_USE: string
|
export const TEST_ADDRESS_NEVER_USE: string
|
||||||
|
|
||||||
|
export const TEST_ADDRESS_NEVER_USE_SHORTENED: string
|
||||||
|
|
||||||
// declare namespace Cypress {
|
// declare namespace Cypress {
|
||||||
// // eslint-disable-next-line @typescript-eslint/class-name-casing
|
// // eslint-disable-next-line @typescript-eslint/class-name-casing
|
||||||
// interface cy {
|
// interface cy {
|
||||||
|
@ -14,6 +14,8 @@ const PRIVATE_KEY_TEST_NEVER_USE = '0xad20c82497421e9784f18460ad2fe84f73569068e9
|
|||||||
// address of the above key
|
// address of the above key
|
||||||
export const TEST_ADDRESS_NEVER_USE = '0x0fF2D1eFd7A57B7562b2bf27F3f37899dB27F4a5'
|
export const TEST_ADDRESS_NEVER_USE = '0x0fF2D1eFd7A57B7562b2bf27F3f37899dB27F4a5'
|
||||||
|
|
||||||
|
export const TEST_ADDRESS_NEVER_USE_SHORTENED = '0x0fF2...F4a5'
|
||||||
|
|
||||||
class CustomizedBridge extends _Eip1193Bridge {
|
class CustomizedBridge extends _Eip1193Bridge {
|
||||||
async sendAsync(...args) {
|
async sendAsync(...args) {
|
||||||
console.debug('sendAsync called', ...args)
|
console.debug('sendAsync called', ...args)
|
||||||
|
@ -6,21 +6,21 @@ import { LinkStyledButton } from '../../theme'
|
|||||||
import { CheckCircle, Copy } from 'react-feather'
|
import { CheckCircle, Copy } from 'react-feather'
|
||||||
|
|
||||||
const CopyIcon = styled(LinkStyledButton)`
|
const CopyIcon = styled(LinkStyledButton)`
|
||||||
color: ${({ theme }) => theme.text4};
|
color: ${({ theme }) => theme.text3};
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-right: 1rem;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
font-size: 0.825rem;
|
||||||
:hover,
|
:hover,
|
||||||
:active,
|
:active,
|
||||||
:focus {
|
:focus {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: ${({ theme }) => theme.text3};
|
color: ${({ theme }) => theme.text2};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
const TransactionStatusText = styled.span`
|
const TransactionStatusText = styled.span`
|
||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
|
font-size: 0.825rem;
|
||||||
${({ theme }) => theme.flexRowNoWrap};
|
${({ theme }) => theme.flexRowNoWrap};
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
@ -30,7 +30,6 @@ export default function CopyHelper(props: { toCopy: string; children?: React.Rea
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CopyIcon onClick={() => setCopied(props.toCopy)}>
|
<CopyIcon onClick={() => setCopied(props.toCopy)}>
|
||||||
{props.children}
|
|
||||||
{isCopied ? (
|
{isCopied ? (
|
||||||
<TransactionStatusText>
|
<TransactionStatusText>
|
||||||
<CheckCircle size={'16'} />
|
<CheckCircle size={'16'} />
|
||||||
@ -41,6 +40,7 @@ export default function CopyHelper(props: { toCopy: string; children?: React.Rea
|
|||||||
<Copy size={'16'} />
|
<Copy size={'16'} />
|
||||||
</TransactionStatusText>
|
</TransactionStatusText>
|
||||||
)}
|
)}
|
||||||
|
{isCopied ? '' : props.children}
|
||||||
</CopyIcon>
|
</CopyIcon>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,39 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Check, Triangle } from 'react-feather'
|
import { CheckCircle, Triangle, ExternalLink as LinkIcon } from 'react-feather'
|
||||||
|
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { getEtherscanLink } from '../../utils'
|
import { getEtherscanLink } from '../../utils'
|
||||||
import { ExternalLink, Spinner } from '../../theme'
|
import { ExternalLink } from '../../theme'
|
||||||
import Circle from '../../assets/images/circle.svg'
|
|
||||||
|
|
||||||
import { transparentize } from 'polished'
|
|
||||||
import { useAllTransactions } from '../../state/transactions/hooks'
|
import { useAllTransactions } from '../../state/transactions/hooks'
|
||||||
|
import { RowFixed } from '../Row'
|
||||||
|
import Loader from '../Loader'
|
||||||
|
|
||||||
const TransactionWrapper = styled.div`
|
const TransactionWrapper = styled.div``
|
||||||
margin-top: 0.75rem;
|
|
||||||
`
|
|
||||||
|
|
||||||
const TransactionStatusText = styled.div`
|
const TransactionStatusText = styled.div`
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const TransactionState = styled(ExternalLink)<{ pending: boolean; success?: boolean }>`
|
const TransactionState = styled(ExternalLink)<{ pending: boolean; success?: boolean }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.25rem 0rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.75rem;
|
font-size: 0.825rem;
|
||||||
border: 1px solid;
|
color: ${({ theme }) => theme.primary1};
|
||||||
|
|
||||||
color: ${({ pending, success, theme }) => (pending ? theme.primary1 : success ? theme.green1 : theme.red1)};
|
|
||||||
|
|
||||||
border-color: ${({ pending, success, theme }) =>
|
|
||||||
pending
|
|
||||||
? transparentize(0.75, theme.primary1)
|
|
||||||
: success
|
|
||||||
? transparentize(0.75, theme.green1)
|
|
||||||
: transparentize(0.75, theme.red1)};
|
|
||||||
|
|
||||||
:hover {
|
|
||||||
border-color: ${({ pending, success, theme }) =>
|
|
||||||
pending
|
|
||||||
? transparentize(0, theme.primary1)
|
|
||||||
: success
|
|
||||||
? transparentize(0, theme.green1)
|
|
||||||
: transparentize(0, theme.red1)};
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const IconWrapper = styled.div`
|
const IconWrapper = styled.div<{ pending: boolean; success?: boolean }>`
|
||||||
flex-shrink: 0;
|
color: ${({ pending, success, theme }) => (pending ? theme.primary1 : success ? theme.green1 : theme.red1)};
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function Transaction({ hash }: { hash: string }) {
|
export default function Transaction({ hash }: { hash: string }) {
|
||||||
@ -65,9 +49,12 @@ export default function Transaction({ hash }: { hash: string }) {
|
|||||||
return (
|
return (
|
||||||
<TransactionWrapper>
|
<TransactionWrapper>
|
||||||
<TransactionState href={getEtherscanLink(chainId, hash, 'transaction')} pending={pending} success={success}>
|
<TransactionState href={getEtherscanLink(chainId, hash, 'transaction')} pending={pending} success={success}>
|
||||||
<TransactionStatusText>{summary ? summary : hash}</TransactionStatusText>
|
<RowFixed>
|
||||||
<IconWrapper>
|
<TransactionStatusText>{summary ? summary : hash}</TransactionStatusText>
|
||||||
{pending ? <Spinner src={Circle} /> : success ? <Check size="16" /> : <Triangle size="16" />}
|
<LinkIcon size={16} />
|
||||||
|
</RowFixed>
|
||||||
|
<IconWrapper pending={pending} success={success}>
|
||||||
|
{pending ? <Loader /> : success ? <CheckCircle size="16" /> : <Triangle size="16" />}
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
</TransactionState>
|
</TransactionState>
|
||||||
</TransactionWrapper>
|
</TransactionWrapper>
|
||||||
|
@ -2,9 +2,9 @@ import React, { useCallback, useContext } from 'react'
|
|||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
import styled, { ThemeContext } from 'styled-components'
|
import styled, { ThemeContext } from 'styled-components'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { isMobile } from 'react-device-detect'
|
|
||||||
import { AppDispatch } from '../../state'
|
import { AppDispatch } from '../../state'
|
||||||
import { clearAllTransactions } from '../../state/transactions/actions'
|
import { clearAllTransactions } from '../../state/transactions/actions'
|
||||||
|
import { shortenAddress } from '../../utils'
|
||||||
import { AutoRow } from '../Row'
|
import { AutoRow } from '../Row'
|
||||||
import Copy from './Copy'
|
import Copy from './Copy'
|
||||||
import Transaction from './Transaction'
|
import Transaction from './Transaction'
|
||||||
@ -18,9 +18,8 @@ import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
|||||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||||
import Identicon from '../Identicon'
|
import Identicon from '../Identicon'
|
||||||
|
import { ButtonSecondary } from '../Button'
|
||||||
import { ButtonEmpty } from '../Button'
|
import { ExternalLink as LinkIcon } from 'react-feather'
|
||||||
|
|
||||||
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
|
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
|
||||||
|
|
||||||
const HeaderRow = styled.div`
|
const HeaderRow = styled.div`
|
||||||
@ -55,31 +54,31 @@ const UpperSection = styled.div`
|
|||||||
|
|
||||||
const InfoCard = styled.div`
|
const InfoCard = styled.div`
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: ${({ theme }) => theme.bg2};
|
border: 1px solid ${({ theme }) => theme.bg3};
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-row-gap: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const AccountGroupingRow = styled.div`
|
const AccountGroupingRow = styled.div`
|
||||||
${({ theme }) => theme.flexRowNoWrap};
|
${({ theme }) => theme.flexRowNoWrap};
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: 500;
|
font-weight: 400;
|
||||||
color: ${({ theme }) => theme.text1};
|
color: ${({ theme }) => theme.text1};
|
||||||
|
|
||||||
div {
|
div {
|
||||||
${({ theme }) => theme.flexRowNoWrap}
|
${({ theme }) => theme.flexRowNoWrap}
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:first-of-type {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const AccountSection = styled.div`
|
const AccountSection = styled.div`
|
||||||
background-color: ${({ theme }) => theme.bg1};
|
background-color: ${({ theme }) => theme.bg1};
|
||||||
padding: 0rem 1rem;
|
padding: 0rem 1rem;
|
||||||
${({ theme }) => theme.mediaWidth.upToMedium`padding: 0rem 1rem 1rem 1rem;`};
|
${({ theme }) => theme.mediaWidth.upToMedium`padding: 0rem 1rem 1.5rem 1rem;`};
|
||||||
`
|
`
|
||||||
|
|
||||||
const YourAccount = styled.div`
|
const YourAccount = styled.div`
|
||||||
@ -94,28 +93,6 @@ const YourAccount = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const GreenCircle = styled.div`
|
|
||||||
${({ theme }) => theme.flexRowNoWrap}
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
height: 8px;
|
|
||||||
width: 8px;
|
|
||||||
margin-left: 12px;
|
|
||||||
margin-right: 2px;
|
|
||||||
background-color: ${({ theme }) => theme.green1};
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const CircleWrapper = styled.div`
|
|
||||||
color: ${({ theme }) => theme.green1};
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
const LowerSection = styled.div`
|
const LowerSection = styled.div`
|
||||||
${({ theme }) => theme.flexColumnNoWrap}
|
${({ theme }) => theme.flexColumnNoWrap}
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
@ -132,13 +109,14 @@ const LowerSection = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const AccountControl = styled.div<{ hasENS: boolean; isENS: boolean }>`
|
const AccountControl = styled.div`
|
||||||
${({ theme }) => theme.flexRowNoWrap};
|
display: flex;
|
||||||
align-items: center;
|
justify-content: space-between;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
font-weight: ${({ hasENS, isENS }) => (hasENS ? (isENS ? 500 : 400) : 500)};
|
font-weight: 500;
|
||||||
font-size: ${({ hasENS, isENS }) => (hasENS ? (isENS ? '1rem' : '0.8rem') : '1rem')};
|
font-size: 1.25rem;
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -146,22 +124,22 @@ const AccountControl = styled.div<{ hasENS: boolean; isENS: boolean }>`
|
|||||||
|
|
||||||
p {
|
p {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
margin: 0.5rem 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const ConnectButtonRow = styled.div`
|
|
||||||
${({ theme }) => theme.flexRowNoWrap}
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 10px 0;
|
|
||||||
`
|
|
||||||
|
|
||||||
const AddressLink = styled(ExternalLink)<{ hasENS: boolean; isENS: boolean }>`
|
const AddressLink = styled(ExternalLink)<{ hasENS: boolean; isENS: boolean }>`
|
||||||
color: ${({ hasENS, isENS, theme }) => (hasENS ? (isENS ? theme.primary1 : theme.text3) : theme.primary1)};
|
font-size: 0.825rem;
|
||||||
|
color: ${({ theme }) => theme.text3};
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
display: flex;
|
||||||
|
:hover {
|
||||||
|
color: ${({ theme }) => theme.text2};
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CloseIcon = styled.div`
|
const CloseIcon = styled.div`
|
||||||
@ -181,14 +159,17 @@ const CloseColor = styled(Close)`
|
|||||||
`
|
`
|
||||||
|
|
||||||
const WalletName = styled.div`
|
const WalletName = styled.div`
|
||||||
padding-left: 0.5rem;
|
|
||||||
width: initial;
|
width: initial;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: ${({ theme }) => theme.text3};
|
||||||
`
|
`
|
||||||
|
|
||||||
const IconWrapper = styled.div<{ size?: number }>`
|
const IconWrapper = styled.div<{ size?: number }>`
|
||||||
${({ theme }) => theme.flexColumnNoWrap};
|
${({ theme }) => theme.flexColumnNoWrap};
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin-right: 8px;
|
||||||
& > img,
|
& > img,
|
||||||
span {
|
span {
|
||||||
height: ${({ size }) => (size ? size + 'px' : '32px')};
|
height: ${({ size }) => (size ? size + 'px' : '32px')};
|
||||||
@ -203,10 +184,12 @@ const TransactionListWrapper = styled.div`
|
|||||||
${({ theme }) => theme.flexColumnNoWrap};
|
${({ theme }) => theme.flexColumnNoWrap};
|
||||||
`
|
`
|
||||||
|
|
||||||
const WalletAction = styled.div`
|
const WalletAction = styled(ButtonSecondary)`
|
||||||
color: ${({ theme }) => theme.text4};
|
width: fit-content;
|
||||||
margin-left: 16px;
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
padding: 4px 6px;
|
||||||
:hover {
|
:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -255,39 +238,39 @@ export default function AccountDetails({
|
|||||||
SUPPORTED_WALLETS[k].connector === connector && (connector !== injected || isMetaMask === (k === 'METAMASK'))
|
SUPPORTED_WALLETS[k].connector === connector && (connector !== injected || isMetaMask === (k === 'METAMASK'))
|
||||||
)
|
)
|
||||||
.map(k => SUPPORTED_WALLETS[k].name)[0]
|
.map(k => SUPPORTED_WALLETS[k].name)[0]
|
||||||
return <WalletName>{name}</WalletName>
|
return <WalletName>Connected with {name}</WalletName>
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusIcon() {
|
function getStatusIcon() {
|
||||||
if (connector === injected) {
|
if (connector === injected) {
|
||||||
return (
|
return (
|
||||||
<IconWrapper size={16}>
|
<IconWrapper size={16}>
|
||||||
<Identicon /> {formatConnectorName()}
|
<Identicon />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
} else if (connector === walletconnect) {
|
} else if (connector === walletconnect) {
|
||||||
return (
|
return (
|
||||||
<IconWrapper size={16}>
|
<IconWrapper size={16}>
|
||||||
<img src={WalletConnectIcon} alt={''} /> {formatConnectorName()}
|
<img src={WalletConnectIcon} alt={''} />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
} else if (connector === walletlink) {
|
} else if (connector === walletlink) {
|
||||||
return (
|
return (
|
||||||
<IconWrapper size={16}>
|
<IconWrapper size={16}>
|
||||||
<img src={CoinbaseWalletIcon} alt={''} /> {formatConnectorName()}
|
<img src={CoinbaseWalletIcon} alt={''} />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
} else if (connector === fortmatic) {
|
} else if (connector === fortmatic) {
|
||||||
return (
|
return (
|
||||||
<IconWrapper size={16}>
|
<IconWrapper size={16}>
|
||||||
<img src={FortmaticIcon} alt={''} /> {formatConnectorName()}
|
<img src={FortmaticIcon} alt={''} />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)
|
)
|
||||||
} else if (connector === portis) {
|
} else if (connector === portis) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconWrapper size={16}>
|
<IconWrapper size={16}>
|
||||||
<img src={PortisIcon} alt={''} /> {formatConnectorName()}
|
<img src={PortisIcon} alt={''} />
|
||||||
<MainWalletAction
|
<MainWalletAction
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
portis.portis.showPortis()
|
portis.portis.showPortis()
|
||||||
@ -320,10 +303,11 @@ export default function AccountDetails({
|
|||||||
<YourAccount>
|
<YourAccount>
|
||||||
<InfoCard>
|
<InfoCard>
|
||||||
<AccountGroupingRow>
|
<AccountGroupingRow>
|
||||||
{getStatusIcon()}
|
{formatConnectorName()}
|
||||||
<div>
|
<div>
|
||||||
{connector !== injected && connector !== walletlink && (
|
{connector !== injected && connector !== walletlink && (
|
||||||
<WalletAction
|
<WalletAction
|
||||||
|
style={{ fontSize: '.825rem', fontWeight: 400, marginRight: '8px' }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
;(connector as any).close()
|
;(connector as any).close()
|
||||||
}}
|
}}
|
||||||
@ -331,73 +315,82 @@ export default function AccountDetails({
|
|||||||
Disconnect
|
Disconnect
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
)}
|
)}
|
||||||
<CircleWrapper>
|
<WalletAction
|
||||||
<GreenCircle>
|
style={{ fontSize: '.825rem', fontWeight: 400 }}
|
||||||
<div />
|
onClick={() => {
|
||||||
</GreenCircle>
|
openOptions()
|
||||||
</CircleWrapper>
|
}}
|
||||||
|
>
|
||||||
|
Change
|
||||||
|
</WalletAction>
|
||||||
</div>
|
</div>
|
||||||
</AccountGroupingRow>
|
</AccountGroupingRow>
|
||||||
<AccountGroupingRow id="web3-account-identifier-row">
|
<AccountGroupingRow id="web3-account-identifier-row">
|
||||||
{ENSName ? (
|
<AccountControl>
|
||||||
<>
|
{ENSName ? (
|
||||||
<AccountControl hasENS={!!ENSName} isENS={true}>
|
<>
|
||||||
<p>{ENSName}</p> <Copy toCopy={account} />
|
<div>
|
||||||
</AccountControl>
|
{getStatusIcon()}
|
||||||
</>
|
<p> {ENSName}</p>
|
||||||
) : (
|
</div>
|
||||||
<>
|
</>
|
||||||
<AccountControl hasENS={!!ENSName} isENS={false}>
|
) : (
|
||||||
<p>{account}</p> <Copy toCopy={account} />
|
<>
|
||||||
</AccountControl>
|
<div>
|
||||||
</>
|
{getStatusIcon()}
|
||||||
)}
|
<p> {shortenAddress(account)}</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</AccountControl>
|
||||||
</AccountGroupingRow>
|
</AccountGroupingRow>
|
||||||
<AccountGroupingRow>
|
<AccountGroupingRow>
|
||||||
{ENSName ? (
|
{ENSName ? (
|
||||||
<>
|
<>
|
||||||
<AccountControl hasENS={!!ENSName} isENS={false}>
|
<AccountControl>
|
||||||
<AddressLink hasENS={!!ENSName} isENS={true} href={getEtherscanLink(chainId, ENSName, 'address')}>
|
<div>
|
||||||
View on Etherscan ↗
|
<Copy toCopy={account}>
|
||||||
</AddressLink>
|
<span style={{ marginLeft: '4px' }}>Copy Address</span>
|
||||||
|
</Copy>
|
||||||
|
<AddressLink
|
||||||
|
hasENS={!!ENSName}
|
||||||
|
isENS={true}
|
||||||
|
href={getEtherscanLink(chainId, ENSName, 'address')}
|
||||||
|
>
|
||||||
|
<LinkIcon size={16} />
|
||||||
|
<span style={{ marginLeft: '4px' }}>View on Etherscan</span>
|
||||||
|
</AddressLink>
|
||||||
|
</div>
|
||||||
</AccountControl>
|
</AccountControl>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<AccountControl hasENS={!!ENSName} isENS={false}>
|
<AccountControl>
|
||||||
<AddressLink
|
<div>
|
||||||
hasENS={!!ENSName}
|
<Copy toCopy={account}>
|
||||||
isENS={false}
|
<span style={{ marginLeft: '4px' }}>Copy Address</span>
|
||||||
href={getEtherscanLink(chainId, account, 'address')}
|
</Copy>
|
||||||
>
|
<AddressLink
|
||||||
View on Etherscan ↗
|
hasENS={!!ENSName}
|
||||||
</AddressLink>
|
isENS={false}
|
||||||
|
href={getEtherscanLink(chainId, account, 'address')}
|
||||||
|
>
|
||||||
|
<LinkIcon size={16} />
|
||||||
|
<span style={{ marginLeft: '4px' }}>View on Etherscan</span>
|
||||||
|
</AddressLink>
|
||||||
|
</div>
|
||||||
</AccountControl>
|
</AccountControl>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{/* {formatConnectorName()} */}
|
||||||
</AccountGroupingRow>
|
</AccountGroupingRow>
|
||||||
</InfoCard>
|
</InfoCard>
|
||||||
</YourAccount>
|
</YourAccount>
|
||||||
|
|
||||||
{!(isMobile && (window.web3 || window.ethereum)) && (
|
|
||||||
<ConnectButtonRow>
|
|
||||||
<ButtonEmpty
|
|
||||||
style={{ fontWeight: 400 }}
|
|
||||||
padding={'12px'}
|
|
||||||
width={'260px'}
|
|
||||||
onClick={() => {
|
|
||||||
openOptions()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Connect to a different wallet
|
|
||||||
</ButtonEmpty>
|
|
||||||
</ConnectButtonRow>
|
|
||||||
)}
|
|
||||||
</AccountSection>
|
</AccountSection>
|
||||||
</UpperSection>
|
</UpperSection>
|
||||||
{!!pendingTransactions.length || !!confirmedTransactions.length ? (
|
{!!pendingTransactions.length || !!confirmedTransactions.length ? (
|
||||||
<LowerSection>
|
<LowerSection>
|
||||||
<AutoRow style={{ justifyContent: 'space-between' }}>
|
<AutoRow mb={'1rem'} style={{ justifyContent: 'space-between' }}>
|
||||||
<TYPE.body>Recent Transactions</TYPE.body>
|
<TYPE.body>Recent Transactions</TYPE.body>
|
||||||
<LinkStyledButton onClick={clearAllTransactionsCallback}>(clear all)</LinkStyledButton>
|
<LinkStyledButton onClick={clearAllTransactionsCallback}>(clear all)</LinkStyledButton>
|
||||||
</AutoRow>
|
</AutoRow>
|
||||||
|
@ -6,7 +6,12 @@ import { RowBetween } from '../Row'
|
|||||||
import { ChevronDown } from 'react-feather'
|
import { ChevronDown } 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)<{ padding?: string; width?: string; borderRadius?: string }>`
|
const Base = styled(RebassButton)<{
|
||||||
|
padding?: string
|
||||||
|
width?: string
|
||||||
|
borderRadius?: string
|
||||||
|
altDisbaledStyle?: boolean
|
||||||
|
}>`
|
||||||
padding: ${({ padding }) => (padding ? padding : '18px')};
|
padding: ${({ padding }) => (padding ? padding : '18px')};
|
||||||
width: ${({ width }) => (width ? width : '100%')};
|
width: ${({ width }) => (width ? width : '100%')};
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -45,10 +50,12 @@ export const ButtonPrimary = styled(Base)`
|
|||||||
background-color: ${({ theme }) => darken(0.1, theme.primary1)};
|
background-color: ${({ theme }) => darken(0.1, theme.primary1)};
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
background-color: ${({ theme }) => theme.bg3};
|
background-color: ${({ theme, altDisbaledStyle }) => (altDisbaledStyle ? theme.primary1 : theme.bg3)};
|
||||||
color: ${({ theme }) => theme.text3}
|
color: ${({ theme, altDisbaledStyle }) => (altDisbaledStyle ? 'white' : theme.text3)}
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
border: 1px solid transparent;;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -68,6 +75,16 @@ export const ButtonLight = styled(Base)`
|
|||||||
box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && darken(0.05, theme.primary5)};
|
box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && darken(0.05, theme.primary5)};
|
||||||
background-color: ${({ theme, disabled }) => !disabled && darken(0.05, theme.primary5)};
|
background-color: ${({ theme, disabled }) => !disabled && darken(0.05, theme.primary5)};
|
||||||
}
|
}
|
||||||
|
:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
:hover {
|
||||||
|
cursor: auto;
|
||||||
|
background-color: ${({ theme }) => theme.primary5};
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const ButtonGray = styled(Base)`
|
export const ButtonGray = styled(Base)`
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import styled, { ThemeContext } from 'styled-components'
|
import styled, { ThemeContext } from 'styled-components'
|
||||||
import Modal from '../Modal'
|
import Modal from '../Modal'
|
||||||
import Loader from '../Loader'
|
|
||||||
import { ExternalLink } from '../../theme'
|
import { ExternalLink } from '../../theme'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { CloseIcon } from '../../theme/components'
|
import { CloseIcon, Spinner } from '../../theme/components'
|
||||||
import { RowBetween } from '../Row'
|
import { RowBetween } from '../Row'
|
||||||
import { ArrowUpCircle } from 'react-feather'
|
import { ArrowUpCircle } from 'react-feather'
|
||||||
import { ButtonPrimary } from '../Button'
|
import { ButtonPrimary } from '../Button'
|
||||||
import { AutoColumn, ColumnCenter } from '../Column'
|
import { AutoColumn, ColumnCenter } from '../Column'
|
||||||
|
import Circle from '../../assets/images/blue-loader.svg'
|
||||||
|
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { getEtherscanLink } from '../../utils'
|
import { getEtherscanLink } from '../../utils'
|
||||||
@ -30,6 +30,11 @@ const ConfirmedIcon = styled(ColumnCenter)`
|
|||||||
padding: 60px 0;
|
padding: 60px 0;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const CustomLightSpinner = styled(Spinner)<{ size: string }>`
|
||||||
|
height: ${({ size }) => size};
|
||||||
|
width: ${({ size }) => size};
|
||||||
|
`
|
||||||
|
|
||||||
interface ConfirmationModalProps {
|
interface ConfirmationModalProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onDismiss: () => void
|
onDismiss: () => void
|
||||||
@ -80,7 +85,7 @@ export default function ConfirmationModal({
|
|||||||
</RowBetween>
|
</RowBetween>
|
||||||
<ConfirmedIcon>
|
<ConfirmedIcon>
|
||||||
{pendingConfirmation ? (
|
{pendingConfirmation ? (
|
||||||
<Loader size="90px" />
|
<CustomLightSpinner src={Circle} alt="loader" size={'90px'} />
|
||||||
) : (
|
) : (
|
||||||
<ArrowUpCircle strokeWidth={0.5} size={90} color={theme.primary1} />
|
<ArrowUpCircle strokeWidth={0.5} size={90} color={theme.primary1} />
|
||||||
)}
|
)}
|
||||||
|
@ -49,7 +49,6 @@ const LabelRow = styled.div`
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
padding: 0.75rem 1rem 0 1rem;
|
padding: 0.75rem 1rem 0 1rem;
|
||||||
height: 20px;
|
|
||||||
span:hover {
|
span:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: ${({ theme }) => darken(0.2, theme.text2)};
|
color: ${({ theme }) => darken(0.2, theme.text2)};
|
||||||
|
@ -138,7 +138,8 @@ const VersionLabel = styled.span<{ isV2?: boolean }>`
|
|||||||
|
|
||||||
const VersionToggle = styled.a`
|
const VersionToggle = styled.a`
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: 1px solid ${({ theme }) => theme.primary1};
|
background: ${({ theme }) => theme.primary5};
|
||||||
|
border: 1px solid ${({ theme }) => theme.primary4};
|
||||||
color: ${({ theme }) => theme.primary1};
|
color: ${({ theme }) => theme.primary1};
|
||||||
display: flex;
|
display: flex;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
@ -204,7 +205,7 @@ export default function Header() {
|
|||||||
</TestnetWrapper>
|
</TestnetWrapper>
|
||||||
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
|
<AccountElement active={!!account} style={{ pointerEvents: 'auto' }}>
|
||||||
{account && userEthBalance ? (
|
{account && userEthBalance ? (
|
||||||
<Text style={{ flexShrink: 0 }} px="0.5rem" fontWeight={500}>
|
<Text style={{ flexShrink: 0 }} pl="0.75rem" pr="0.5rem" fontWeight={500}>
|
||||||
{userEthBalance?.toSignificant(4)} ETH
|
{userEthBalance?.toSignificant(4)} ETH
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -1,15 +1,38 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import styled from 'styled-components'
|
import styled, { keyframes } from 'styled-components'
|
||||||
|
|
||||||
import { Spinner } from '../../theme'
|
const rotate = keyframes`
|
||||||
import Circle from '../../assets/images/blue-loader.svg'
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
const SpinnerWrapper = styled(Spinner)<{ size: string }>`
|
}
|
||||||
height: ${({ size }) => size};
|
to {
|
||||||
width: ${({ size }) => size};
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function Loader({ size }: { size: string }) {
|
const StyledSVG = styled.svg<{ size: string; stroke?: string }>`
|
||||||
return <SpinnerWrapper src={Circle} alt="loader" size={size} />
|
animation: 2s ${rotate} linear infinite;
|
||||||
|
height: ${({ size }) => size};
|
||||||
|
width: ${({ size }) => size};
|
||||||
|
path {
|
||||||
|
stroke: ${({ stroke, theme }) => stroke ?? theme.primary1};
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes in custom size and stroke for circle color, default to primary color as fill,
|
||||||
|
* need ...rest for layered styles on top
|
||||||
|
*/
|
||||||
|
export default function Loader({ size = '16px', stroke = null, ...rest }: { size?: string; stroke?: string }) {
|
||||||
|
return (
|
||||||
|
<StyledSVG viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" size={size} stroke={stroke} {...rest}>
|
||||||
|
<path
|
||||||
|
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 9.27455 20.9097 6.80375 19.1414 5"
|
||||||
|
strokeWidth="2.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</StyledSVG>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,10 @@ const StyledDialogOverlay = styled(({ mobile, ...rest }) => <AnimatedDialogOverl
|
|||||||
// destructure to not pass custom props to Dialog DOM element
|
// destructure to not pass custom props to Dialog DOM element
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const StyledDialogContent = styled(({ minHeight, maxHeight, mobile, isOpen, ...rest }) => (
|
const StyledDialogContent = styled(({ minHeight, maxHeight, mobile, isOpen, ...rest }) => (
|
||||||
<DialogContent aria-label="content" {...rest} />
|
<DialogContent {...rest} />
|
||||||
))`
|
)).attrs({
|
||||||
|
'aria-label': 'dialog'
|
||||||
|
})`
|
||||||
&[data-reach-dialog-content] {
|
&[data-reach-dialog-content] {
|
||||||
margin: 0 0 2rem 0;
|
margin: 0 0 2rem 0;
|
||||||
border: 1px solid ${({ theme }) => theme.bg1};
|
border: 1px solid ${({ theme }) => theme.bg1};
|
||||||
@ -170,7 +172,7 @@ export default function Modal({
|
|||||||
hidden={true}
|
hidden={true}
|
||||||
minHeight={minHeight}
|
minHeight={minHeight}
|
||||||
maxHeight={maxHeight}
|
maxHeight={maxHeight}
|
||||||
mobile={isMobile}
|
mobile={isMobile ?? undefined}
|
||||||
>
|
>
|
||||||
<HiddenCloseButton onClick={onDismiss} />
|
<HiddenCloseButton onClick={onDismiss} />
|
||||||
{children}
|
{children}
|
||||||
@ -189,13 +191,7 @@ export default function Modal({
|
|||||||
{transitions.map(
|
{transitions.map(
|
||||||
({ item, key, props }) =>
|
({ item, key, props }) =>
|
||||||
item && (
|
item && (
|
||||||
<StyledDialogOverlay
|
<StyledDialogOverlay key={key} style={props} onDismiss={onDismiss} initialFocusRef={initialFocusRef}>
|
||||||
key={key}
|
|
||||||
style={props}
|
|
||||||
onDismiss={onDismiss}
|
|
||||||
initialFocusRef={initialFocusRef}
|
|
||||||
mobile={false}
|
|
||||||
>
|
|
||||||
<StyledDialogContent hidden={true} minHeight={minHeight} maxHeight={maxHeight} isOpen={isOpen}>
|
<StyledDialogContent hidden={true} minHeight={minHeight} maxHeight={maxHeight} isOpen={isOpen}>
|
||||||
<HiddenCloseButton onClick={onDismiss} />
|
<HiddenCloseButton onClick={onDismiss} />
|
||||||
{children}
|
{children}
|
||||||
|
@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { FixedSizeList } from 'react-window'
|
import { FixedSizeList } from 'react-window'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { ThemeContext } from 'styled-components'
|
import { ThemeContext } from 'styled-components'
|
||||||
import Circle from '../../assets/images/circle.svg'
|
|
||||||
import { ALL_TOKENS } from '../../constants/tokens'
|
import { ALL_TOKENS } from '../../constants/tokens'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { LinkStyledButton, TYPE } from '../../theme'
|
import { LinkStyledButton, TYPE } from '../../theme'
|
||||||
@ -13,7 +12,8 @@ import { ButtonSecondary } from '../Button'
|
|||||||
import Column, { AutoColumn } from '../Column'
|
import Column, { AutoColumn } from '../Column'
|
||||||
import { RowFixed } from '../Row'
|
import { RowFixed } from '../Row'
|
||||||
import TokenLogo from '../TokenLogo'
|
import TokenLogo from '../TokenLogo'
|
||||||
import { FadedSpan, GreySpan, MenuItem, SpinnerWrapper, ModalInfo } from './styleds'
|
import { FadedSpan, GreySpan, MenuItem, ModalInfo } from './styleds'
|
||||||
|
import Loader from '../Loader'
|
||||||
|
|
||||||
function isDefaultToken(tokenAddress: string, chainId?: number): boolean {
|
function isDefaultToken(tokenAddress: string, chainId?: number): boolean {
|
||||||
const address = isAddress(tokenAddress)
|
const address = isAddress(tokenAddress)
|
||||||
@ -112,7 +112,7 @@ export default function TokenList({
|
|||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
) : account ? (
|
) : account ? (
|
||||||
<SpinnerWrapper src={Circle} alt="loader" />
|
<Loader />
|
||||||
) : (
|
) : (
|
||||||
'-'
|
'-'
|
||||||
)}
|
)}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Spinner } from '../../theme'
|
|
||||||
import { AutoColumn } from '../Column'
|
import { AutoColumn } from '../Column'
|
||||||
import { AutoRow, RowBetween, RowFixed } from '../Row'
|
import { AutoRow, RowBetween, RowFixed } from '../Row'
|
||||||
|
|
||||||
@ -23,12 +22,6 @@ export const GreySpan = styled.span`
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
`
|
`
|
||||||
|
|
||||||
export const SpinnerWrapper = styled(Spinner)`
|
|
||||||
margin: 0 0.25rem 0 0.25rem;
|
|
||||||
color: ${({ theme }) => theme.text4};
|
|
||||||
opacity: 0.6;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const Input = styled.input`
|
export const Input = styled.input`
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -224,7 +224,7 @@ export default function SlippageTabs({ rawSlippage, setRawSlippage, deadline, se
|
|||||||
|
|
||||||
<AutoColumn gap="sm">
|
<AutoColumn gap="sm">
|
||||||
<RowFixed padding={'0 20px'}>
|
<RowFixed padding={'0 20px'}>
|
||||||
<TYPE.black fontSize={14} color={theme.text2}>
|
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
||||||
Deadline
|
Deadline
|
||||||
</TYPE.black>
|
</TYPE.black>
|
||||||
<QuestionHelper text="Your transaction will revert if it is pending for more than this long." />
|
<QuestionHelper text="Your transaction will revert if it is pending for more than this long." />
|
||||||
|
@ -18,11 +18,11 @@ const Wrapper = styled.div<{ error: boolean }>`
|
|||||||
background: ${({ theme, error }) => transparentize(0.9, error ? theme.red1 : theme.yellow1)};
|
background: ${({ theme, error }) => transparentize(0.9, error ? theme.red1 : theme.yellow1)};
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border: 0.5px solid ${({ theme, error }) => transparentize(0.4, error ? theme.red1 : theme.yellow1)};
|
/* border: 0.5px solid ${({ theme, error }) => transparentize(0.4, error ? theme.red1 : theme.yellow1)}; */
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto auto auto;
|
grid-template-rows: 14px auto auto;
|
||||||
grid-row-gap: 14px;
|
grid-row-gap: 14px;
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -42,15 +42,15 @@ const CloseColor = styled(Close)`
|
|||||||
const CloseIcon = styled.div`
|
const CloseIcon = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 1rem;
|
right: 1rem;
|
||||||
top: 14px;
|
top: 12px;
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
height: 14px;
|
height: 16px;
|
||||||
width: 14px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -5,9 +5,8 @@ import Option from './Option'
|
|||||||
import { SUPPORTED_WALLETS } from '../../constants'
|
import { SUPPORTED_WALLETS } from '../../constants'
|
||||||
import WalletConnectData from './WalletConnectData'
|
import WalletConnectData from './WalletConnectData'
|
||||||
import { walletconnect, injected } from '../../connectors'
|
import { walletconnect, injected } from '../../connectors'
|
||||||
import { Spinner } from '../../theme'
|
|
||||||
import Circle from '../../assets/images/circle.svg'
|
|
||||||
import { darken } from 'polished'
|
import { darken } from 'polished'
|
||||||
|
import Loader from '../Loader'
|
||||||
|
|
||||||
const PendingSection = styled.div`
|
const PendingSection = styled.div`
|
||||||
${({ theme }) => theme.flexColumnNoWrap};
|
${({ theme }) => theme.flexColumnNoWrap};
|
||||||
@ -19,14 +18,8 @@ const PendingSection = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const SpinnerWrapper = styled(Spinner)`
|
const StyledLoader = styled(Loader)`
|
||||||
font-size: 4rem;
|
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
svg {
|
|
||||||
path {
|
|
||||||
color: ${({ theme }) => theme.bg4};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const LoadingMessage = styled.div<{ error?: boolean }>`
|
const LoadingMessage = styled.div<{ error?: boolean }>`
|
||||||
@ -93,7 +86,7 @@ export default function PendingView({
|
|||||||
{!error && connector === walletconnect && <WalletConnectData size={size} uri={uri} />}
|
{!error && connector === walletconnect && <WalletConnectData size={size} uri={uri} />}
|
||||||
<LoadingMessage error={error}>
|
<LoadingMessage error={error}>
|
||||||
<LoadingWrapper>
|
<LoadingWrapper>
|
||||||
{!error && <SpinnerWrapper src={Circle} />}
|
{!error && <StyledLoader />}
|
||||||
{error ? (
|
{error ? (
|
||||||
<ErrorGroup>
|
<ErrorGroup>
|
||||||
<div>Error connecting.</div>
|
<div>Error connecting.</div>
|
||||||
|
@ -5,9 +5,8 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
import { network } from '../../connectors'
|
import { network } from '../../connectors'
|
||||||
import { useEagerConnect, useInactiveListener } from '../../hooks'
|
import { useEagerConnect, useInactiveListener } from '../../hooks'
|
||||||
import { Spinner } from '../../theme'
|
|
||||||
import Circle from '../../assets/images/circle.svg'
|
|
||||||
import { NetworkContextName } from '../../constants'
|
import { NetworkContextName } from '../../constants'
|
||||||
|
import Loader from '../Loader'
|
||||||
|
|
||||||
const MessageWrapper = styled.div`
|
const MessageWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -20,16 +19,6 @@ const Message = styled.h2`
|
|||||||
color: ${({ theme }) => theme.secondary1};
|
color: ${({ theme }) => theme.secondary1};
|
||||||
`
|
`
|
||||||
|
|
||||||
const SpinnerWrapper = styled(Spinner)`
|
|
||||||
font-size: 4rem;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
path {
|
|
||||||
color: ${({ theme }) => theme.secondary1};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function Web3ReactManager({ children }) {
|
export default function Web3ReactManager({ children }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { active } = useWeb3React()
|
const { active } = useWeb3React()
|
||||||
@ -78,7 +67,7 @@ export default function Web3ReactManager({ children }) {
|
|||||||
if (!active && !networkActive) {
|
if (!active && !networkActive) {
|
||||||
return showLoader ? (
|
return showLoader ? (
|
||||||
<MessageWrapper>
|
<MessageWrapper>
|
||||||
<SpinnerWrapper src={Circle} />
|
<Loader />
|
||||||
</MessageWrapper>
|
</MessageWrapper>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,12 @@ import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
|||||||
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||||
|
|
||||||
import { Spinner } from '../../theme'
|
|
||||||
import LightCircle from '../../assets/svg/lightcircle.svg'
|
|
||||||
|
|
||||||
import { RowBetween } from '../Row'
|
import { RowBetween } from '../Row'
|
||||||
import { shortenAddress } from '../../utils'
|
import { shortenAddress } from '../../utils'
|
||||||
import { useAllTransactions } from '../../state/transactions/hooks'
|
import { useAllTransactions } from '../../state/transactions/hooks'
|
||||||
import { NetworkContextName } from '../../constants'
|
import { NetworkContextName } from '../../constants'
|
||||||
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
|
import { injected, walletconnect, walletlink, fortmatic, portis } from '../../connectors'
|
||||||
|
import Loader from '../Loader'
|
||||||
const SpinnerWrapper = styled(Spinner)`
|
|
||||||
margin: 0 0.25rem 0 0.25rem;
|
|
||||||
`
|
|
||||||
|
|
||||||
const IconWrapper = styled.div<{ size?: number }>`
|
const IconWrapper = styled.div<{ size?: number }>`
|
||||||
${({ theme }) => theme.flexColumnNoWrap};
|
${({ theme }) => theme.flexColumnNoWrap};
|
||||||
@ -189,7 +183,7 @@ export default function Web3Status() {
|
|||||||
<Web3StatusConnected id="web3-status-connected" onClick={toggleWalletModal} pending={hasPendingTransactions}>
|
<Web3StatusConnected id="web3-status-connected" onClick={toggleWalletModal} pending={hasPendingTransactions}>
|
||||||
{hasPendingTransactions ? (
|
{hasPendingTransactions ? (
|
||||||
<RowBetween>
|
<RowBetween>
|
||||||
<Text>{pending?.length} Pending</Text> <SpinnerWrapper src={LightCircle} alt="loader" />
|
<Text>{pending?.length} Pending</Text> <Loader stroke="white" />
|
||||||
</RowBetween>
|
</RowBetween>
|
||||||
) : (
|
) : (
|
||||||
<Text>{ENSName || shortenAddress(account)}</Text>
|
<Text>{ENSName || shortenAddress(account)}</Text>
|
||||||
|
@ -95,6 +95,16 @@ export default function Send({ location: { search } }: RouteComponentProps) {
|
|||||||
// check whether the user has approved the router on the input token
|
// check whether the user has approved the router on the input token
|
||||||
const [approval, approveCallback] = useApproveCallbackFromTrade(bestTrade, allowedSlippage)
|
const [approval, approveCallback] = useApproveCallbackFromTrade(bestTrade, allowedSlippage)
|
||||||
|
|
||||||
|
// check if user has gone through approval process, used to show two step buttons, reset on token change
|
||||||
|
const [approvalSubmitted, setApprovalSubmitted] = useState<boolean>(false)
|
||||||
|
|
||||||
|
// mark when a user has submitted an approval, reset onTokenSelection for input field
|
||||||
|
useEffect(() => {
|
||||||
|
if (approval === ApprovalState.PENDING) {
|
||||||
|
setApprovalSubmitted(true)
|
||||||
|
}
|
||||||
|
}, [approval, approvalSubmitted])
|
||||||
|
|
||||||
const formattedAmounts = {
|
const formattedAmounts = {
|
||||||
[independentField]: typedValue,
|
[independentField]: typedValue,
|
||||||
[dependentField]: parsedAmounts[dependentField] ? parsedAmounts[dependentField].toSignificant(6) : ''
|
[dependentField]: parsedAmounts[dependentField] ? parsedAmounts[dependentField].toSignificant(6) : ''
|
||||||
@ -181,6 +191,13 @@ export default function Send({ location: { search } }: RouteComponentProps) {
|
|||||||
// warnings on slippage
|
// warnings on slippage
|
||||||
const severity = !sendingWithSwap ? 0 : warningSeverity(priceImpactWithoutFee)
|
const severity = !sendingWithSwap ? 0 : warningSeverity(priceImpactWithoutFee)
|
||||||
|
|
||||||
|
// show approval buttons when: no errors on input, not approved or pending, or has been approved in this session
|
||||||
|
const showApproveFlow =
|
||||||
|
((sendingWithSwap && isSwapValid) || (!sendingWithSwap && isSendValid)) &&
|
||||||
|
(approval === ApprovalState.NOT_APPROVED ||
|
||||||
|
approval === ApprovalState.PENDING ||
|
||||||
|
(approvalSubmitted && approval === ApprovalState.APPROVED))
|
||||||
|
|
||||||
function modalHeader() {
|
function modalHeader() {
|
||||||
if (!sendingWithSwap) {
|
if (!sendingWithSwap) {
|
||||||
return <TransferModalHeader amount={parsedAmounts?.[Field.INPUT]} ENSName={ENS} recipient={recipient} />
|
return <TransferModalHeader amount={parsedAmounts?.[Field.INPUT]} ENSName={ENS} recipient={recipient} />
|
||||||
@ -363,11 +380,13 @@ export default function Send({ location: { search } }: RouteComponentProps) {
|
|||||||
onMax={() => {
|
onMax={() => {
|
||||||
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact())
|
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact())
|
||||||
}}
|
}}
|
||||||
onTokenSelection={address => onTokenSelection(Field.INPUT, address)}
|
onTokenSelection={address => {
|
||||||
|
setApprovalSubmitted(false)
|
||||||
|
onTokenSelection(Field.INPUT, address)
|
||||||
|
}}
|
||||||
otherSelectedTokenAddress={tokens[Field.OUTPUT]?.address}
|
otherSelectedTokenAddress={tokens[Field.OUTPUT]?.address}
|
||||||
id="swap-currency-input"
|
id="swap-currency-input"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{sendingWithSwap ? (
|
{sendingWithSwap ? (
|
||||||
<ColumnCenter>
|
<ColumnCenter>
|
||||||
<RowBetween padding="0 1rem 0 12px">
|
<RowBetween padding="0 1rem 0 12px">
|
||||||
@ -431,7 +450,7 @@ export default function Send({ location: { search } }: RouteComponentProps) {
|
|||||||
/>
|
/>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
|
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
|
||||||
<Card padding={'.25rem 1.25rem 0 .75rem'} borderRadius={'20px'}>
|
<Card padding={'.25rem .75rem 0 .75rem'} borderRadius={'20px'}>
|
||||||
<AutoColumn gap="4px">
|
<AutoColumn gap="4px">
|
||||||
<RowBetween align="center">
|
<RowBetween align="center">
|
||||||
<Text fontWeight={500} fontSize={14} color={theme.text2}>
|
<Text fontWeight={500} fontSize={14} color={theme.text2}>
|
||||||
@ -471,14 +490,36 @@ export default function Send({ location: { search } }: RouteComponentProps) {
|
|||||||
<GreyCard style={{ textAlign: 'center' }}>
|
<GreyCard style={{ textAlign: 'center' }}>
|
||||||
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
|
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
|
||||||
</GreyCard>
|
</GreyCard>
|
||||||
) : approval === ApprovalState.NOT_APPROVED || approval === ApprovalState.PENDING ? (
|
) : showApproveFlow ? (
|
||||||
<ButtonLight onClick={approveCallback} disabled={approval === ApprovalState.PENDING}>
|
<RowBetween>
|
||||||
{approval === ApprovalState.PENDING ? (
|
<ButtonPrimary
|
||||||
<Dots>Approving {tokens[Field.INPUT]?.symbol}</Dots>
|
onClick={approveCallback}
|
||||||
) : (
|
disabled={approval !== ApprovalState.NOT_APPROVED || approvalSubmitted}
|
||||||
'Approve ' + tokens[Field.INPUT]?.symbol
|
width="48%"
|
||||||
)}
|
altDisbaledStyle={approval === ApprovalState.PENDING} // show solid button while waiting
|
||||||
</ButtonLight>
|
>
|
||||||
|
{approval === ApprovalState.PENDING ? (
|
||||||
|
<Dots>Approving</Dots>
|
||||||
|
) : approvalSubmitted && approval === ApprovalState.APPROVED ? (
|
||||||
|
'Approved'
|
||||||
|
) : (
|
||||||
|
'Approve ' + tokens[Field.INPUT]?.symbol
|
||||||
|
)}
|
||||||
|
</ButtonPrimary>
|
||||||
|
<ButtonError
|
||||||
|
onClick={() => {
|
||||||
|
setShowConfirm(true)
|
||||||
|
}}
|
||||||
|
width="48%"
|
||||||
|
id="send-button"
|
||||||
|
disabled={approval !== ApprovalState.APPROVED}
|
||||||
|
error={sendingWithSwap && isSwapValid && severity > 2}
|
||||||
|
>
|
||||||
|
<Text fontSize={16} fontWeight={500}>
|
||||||
|
{`Send${severity > 2 ? ' Anyway' : ''}`}
|
||||||
|
</Text>
|
||||||
|
</ButtonError>
|
||||||
|
</RowBetween>
|
||||||
) : (
|
) : (
|
||||||
<ButtonError
|
<ButtonError
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { JSBI, TokenAmount, WETH } from '@uniswap/sdk'
|
import { JSBI, TokenAmount, WETH } from '@uniswap/sdk'
|
||||||
import React, { useContext, useState } from 'react'
|
import React, { useContext, useState, useEffect } from 'react'
|
||||||
import { ArrowDown } from 'react-feather'
|
import { ArrowDown } 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 { ButtonError, ButtonLight } from '../../components/Button'
|
import { ButtonError, ButtonLight, ButtonPrimary } from '../../components/Button'
|
||||||
import Card, { GreyCard } from '../../components/Card'
|
import Card, { GreyCard } from '../../components/Card'
|
||||||
import { AutoColumn } from '../../components/Column'
|
import { AutoColumn } from '../../components/Column'
|
||||||
import ConfirmationModal from '../../components/ConfirmationModal'
|
import ConfirmationModal from '../../components/ConfirmationModal'
|
||||||
@ -81,6 +81,23 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
|
|||||||
// check whether the user has approved the router on the input token
|
// check whether the user has approved the router on the input token
|
||||||
const [approval, approveCallback] = useApproveCallbackFromTrade(bestTrade, allowedSlippage)
|
const [approval, approveCallback] = useApproveCallbackFromTrade(bestTrade, allowedSlippage)
|
||||||
|
|
||||||
|
// check if user has gone through approval process, used to show two step buttons, reset on token change
|
||||||
|
const [approvalSubmitted, setApprovalSubmitted] = useState<boolean>(false)
|
||||||
|
|
||||||
|
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
|
||||||
|
const showApproveFlow =
|
||||||
|
!error &&
|
||||||
|
(approval === ApprovalState.NOT_APPROVED ||
|
||||||
|
approval === ApprovalState.PENDING ||
|
||||||
|
(approvalSubmitted && approval === ApprovalState.APPROVED))
|
||||||
|
|
||||||
|
// mark when a user has submitted an approval, reset onTokenSelection for input field
|
||||||
|
useEffect(() => {
|
||||||
|
if (approval === ApprovalState.PENDING) {
|
||||||
|
setApprovalSubmitted(true)
|
||||||
|
}
|
||||||
|
}, [approval, approvalSubmitted])
|
||||||
|
|
||||||
const maxAmountInput: TokenAmount =
|
const maxAmountInput: TokenAmount =
|
||||||
!!tokenBalances[Field.INPUT] &&
|
!!tokenBalances[Field.INPUT] &&
|
||||||
!!tokens[Field.INPUT] &&
|
!!tokens[Field.INPUT] &&
|
||||||
@ -203,7 +220,10 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
|
|||||||
onMax={() => {
|
onMax={() => {
|
||||||
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact())
|
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact())
|
||||||
}}
|
}}
|
||||||
onTokenSelection={address => onTokenSelection(Field.INPUT, address)}
|
onTokenSelection={address => {
|
||||||
|
setApprovalSubmitted(false) // reset 2 step UI for approvals
|
||||||
|
onTokenSelection(Field.INPUT, address)
|
||||||
|
}}
|
||||||
otherSelectedTokenAddress={tokens[Field.OUTPUT]?.address}
|
otherSelectedTokenAddress={tokens[Field.OUTPUT]?.address}
|
||||||
id="swap-currency-input"
|
id="swap-currency-input"
|
||||||
/>
|
/>
|
||||||
@ -213,13 +233,15 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
|
|||||||
<ArrowWrapper>
|
<ArrowWrapper>
|
||||||
<ArrowDown
|
<ArrowDown
|
||||||
size="16"
|
size="16"
|
||||||
onClick={onSwitchTokens}
|
onClick={() => {
|
||||||
|
setApprovalSubmitted(false) // reset 2 step UI for approvals
|
||||||
|
onSwitchTokens()
|
||||||
|
}}
|
||||||
color={tokens[Field.INPUT] && tokens[Field.OUTPUT] ? theme.primary1 : theme.text2}
|
color={tokens[Field.INPUT] && tokens[Field.OUTPUT] ? theme.primary1 : theme.text2}
|
||||||
/>
|
/>
|
||||||
</ArrowWrapper>
|
</ArrowWrapper>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
</CursorPointer>
|
</CursorPointer>
|
||||||
|
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
field={Field.OUTPUT}
|
field={Field.OUTPUT}
|
||||||
value={formattedAmounts[Field.OUTPUT]}
|
value={formattedAmounts[Field.OUTPUT]}
|
||||||
@ -235,7 +257,7 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
|
|||||||
</>
|
</>
|
||||||
|
|
||||||
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
|
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
|
||||||
<Card padding={'.25rem 1.25rem 0 .75rem'} borderRadius={'20px'}>
|
<Card padding={'.25rem .75rem 0 .75rem'} borderRadius={'20px'}>
|
||||||
<AutoColumn gap="4px">
|
<AutoColumn gap="4px">
|
||||||
<RowBetween align="center">
|
<RowBetween align="center">
|
||||||
<Text fontWeight={500} fontSize={14} color={theme.text2}>
|
<Text fontWeight={500} fontSize={14} color={theme.text2}>
|
||||||
@ -269,14 +291,36 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
|
|||||||
<GreyCard style={{ textAlign: 'center' }}>
|
<GreyCard style={{ textAlign: 'center' }}>
|
||||||
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
|
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
|
||||||
</GreyCard>
|
</GreyCard>
|
||||||
) : approval === ApprovalState.NOT_APPROVED || approval === ApprovalState.PENDING ? (
|
) : showApproveFlow ? (
|
||||||
<ButtonLight onClick={approveCallback} disabled={approval === ApprovalState.PENDING}>
|
<RowBetween>
|
||||||
{approval === ApprovalState.PENDING ? (
|
<ButtonPrimary
|
||||||
<Dots>Approving {tokens[Field.INPUT]?.symbol}</Dots>
|
onClick={approveCallback}
|
||||||
) : (
|
disabled={approval !== ApprovalState.NOT_APPROVED || approvalSubmitted}
|
||||||
'Approve ' + tokens[Field.INPUT]?.symbol
|
width="48%"
|
||||||
)}
|
altDisbaledStyle={approval === ApprovalState.PENDING} // show solid button while waiting
|
||||||
</ButtonLight>
|
>
|
||||||
|
{approval === ApprovalState.PENDING ? (
|
||||||
|
<Dots>Approving</Dots>
|
||||||
|
) : approvalSubmitted && approval === ApprovalState.APPROVED ? (
|
||||||
|
'Approved'
|
||||||
|
) : (
|
||||||
|
'Approve ' + tokens[Field.INPUT]?.symbol
|
||||||
|
)}
|
||||||
|
</ButtonPrimary>
|
||||||
|
<ButtonError
|
||||||
|
onClick={() => {
|
||||||
|
setShowConfirm(true)
|
||||||
|
}}
|
||||||
|
width="48%"
|
||||||
|
id="swap-button"
|
||||||
|
disabled={!isValid || approval !== ApprovalState.APPROVED}
|
||||||
|
error={isValid && priceImpactSeverity > 2}
|
||||||
|
>
|
||||||
|
<Text fontSize={16} fontWeight={500}>
|
||||||
|
{`Swap${priceImpactSeverity > 2 ? ' Anyway' : ''}`}
|
||||||
|
</Text>
|
||||||
|
</ButtonError>
|
||||||
|
</RowBetween>
|
||||||
) : (
|
) : (
|
||||||
<ButtonError
|
<ButtonError
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -168,9 +168,9 @@ export const TYPE = {
|
|||||||
|
|
||||||
export const FixedGlobalStyle = createGlobalStyle`
|
export const FixedGlobalStyle = createGlobalStyle`
|
||||||
@import url('https://rsms.me/inter/inter.css');
|
@import url('https://rsms.me/inter/inter.css');
|
||||||
html { font-family: 'Inter', sans-serif; letter-spacing: -0.018em;}
|
html, body, input, textarea, button { font-family: 'Inter', sans-serif; letter-spacing: -0.018em;}
|
||||||
@supports (font-variation-settings: normal) {
|
@supports (font-variation-settings: normal) {
|
||||||
html { font-family: 'Inter var', sans-serif; }
|
html, body, input, textarea, button { font-family: 'Inter var', sans-serif; }
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
|
Loading…
Reference in New Issue
Block a user