Skip to content

Commit

Permalink
feat(tokens): new UI component for token select modal (#3166)
Browse files Browse the repository at this point in the history
* feat: skeleton for SelectTokenModal

* chore: setup SelectTokenModal cosmos

* chore: styles SelectTokenModal

* chore: select token modal styles
  • Loading branch information
shoom3301 authored Sep 30, 2023
1 parent 9b384ef commit d5b69cd
Show file tree
Hide file tree
Showing 13 changed files with 482 additions and 31 deletions.
37 changes: 24 additions & 13 deletions apps/cowswap-frontend/src/legacy/components/InfoIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import { ReactNode } from 'react'

import { MouseoverTooltipContent, TooltipContainer } from '@cowprotocol/ui'

import { Info } from 'react-feather'
import { Info, HelpCircle } from 'react-feather'
import styled from 'styled-components/macro'

import { UI } from 'common/constants/theme'

const StyledInfoIcon = styled(Info)`
opacity: 0.5;
stroke: var(${UI.COLOR_TEXT1});
line-height: 0;
vertical-align: middle;
transition: opacity 0.2s ease-in-out;
const StyledIcon = styled.div`
display: inline-block;
:hover {
opacity: 1;
> svg {
opacity: 0.5;
stroke: var(${UI.COLOR_TEXT1});
line-height: 0;
vertical-align: middle;
transition: opacity 0.2s ease-in-out;
:hover {
opacity: 1;
}
}
`

Expand All @@ -28,15 +32,22 @@ const StyledTooltipContainer = styled(TooltipContainer)`

export interface InfoIconProps {
content: ReactNode
iconType?: 'info' | 'help'
className?: string
}

export function InfoIcon(props: InfoIconProps) {
const content = <StyledTooltipContainer>{props.content}</StyledTooltipContainer>
export function InfoIcon({ content, iconType = 'info', className }: InfoIconProps) {
const tooltipContent = <StyledTooltipContainer>{content}</StyledTooltipContainer>

return (
<MouseoverTooltipContent wrap={false} content={content} placement="bottom">
<StyledInfoIcon className={props.className} size={16} />
<MouseoverTooltipContent wrap={false} content={tooltipContent} placement="bottom">
<StyledIcon>
{iconType === 'info' ? (
<Info className={className} size={16} />
) : (
<HelpCircle className={className} size={16} />
)}
</StyledIcon>
</MouseoverTooltipContent>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { Token } from '@uniswap/sdk-core'
import { useAllTokens } from 'legacy/hooks/Tokens'
import { useTokenLazy } from 'legacy/hooks/useTokenLazy'

import { TokensByAddress, TokenWithLogo } from 'modules/tokensList/state/tokensListAtom'
import { TokensByAddress } from 'modules/tokensList/state/tokensListAtom'
import { TokenWithLogo } from 'modules/tokensList/types'

import { getTokenFromMapping } from 'utils/orderUtils/getTokenFromMapping'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getRandomInt } from '@cowprotocol/common-utils'
import { CurrencyAmount } from '@uniswap/sdk-core'
import { Currency } from '@uniswap/sdk-core'

import styled from 'styled-components/macro'

import { allTokensMock, favouriteTokensMock } from './mocks'

import { SelectTokenModal } from './index'

const Wrapper = styled.div`
width: 450px;
`

const selectedToken = favouriteTokensMock[0]

const balances = allTokensMock.reduce<{ [key: string]: CurrencyAmount<Currency> }>((acc, token) => {
acc[token.address.toLowerCase()] = CurrencyAmount.fromRawAmount(
token,
getRandomInt(20_000, 120_000_000) * 10 ** token.decimals
)

return acc
}, {})

const Fixtures = {
default: (
<Wrapper>
<SelectTokenModal
selectedToken={selectedToken}
allTokens={allTokensMock}
favouriteTokens={favouriteTokensMock}
balances={balances}
/>
</Wrapper>
),
}

export default Fixtures
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'

import { Edit, X } from 'react-feather'

import * as styledEl from './styled'

import { AllTokensList } from '../../pure/AllTokensList'
import { FavouriteTokensList } from '../../pure/FavouriteTokensList'
import { TokenWithLogo } from '../../types'

export interface SelectTokenModalProps {
allTokens: TokenWithLogo[]
favouriteTokens: TokenWithLogo[]
balances: { [key: string]: CurrencyAmount<Currency> }
selectedToken?: TokenWithLogo
}

export function SelectTokenModal(props: SelectTokenModalProps) {
const { favouriteTokens, allTokens, selectedToken, balances } = props

return (
<styledEl.Wrapper>
<styledEl.Header>
<h3>Select a token</h3>
<button>
<X />
</button>
</styledEl.Header>
<styledEl.Row>
<styledEl.SearchInput type="text" placeholder="Search name or past address" />
</styledEl.Row>
<styledEl.Row>
<FavouriteTokensList selectedToken={selectedToken} tokens={favouriteTokens} />
</styledEl.Row>
<div>
<AllTokensList selectedToken={selectedToken} tokens={allTokens} balances={balances} />
</div>
<div>
<styledEl.ActionButton>
<Edit /> <span>Manage Token Lists</span>
</styledEl.ActionButton>
</div>
</styledEl.Wrapper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { TokenWithLogo } from '../../types'

export const allTokensMock: TokenWithLogo[] = [
{
name: 'Gnosis',
chainId: 5,
symbol: 'GNO',
decimals: 18,
address: '0x02abbdbaaa7b1bb64b5c878f7ac17f8dda169532',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6810e776880C02933D47DB1b9fc05908e5386b96/logo.png',
},
{
name: 'Basic Attention Token',
chainId: 5,
symbol: 'BAT',
decimals: 18,
address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png',
},
{
name: 'CoW Protocol Token',
chainId: 5,
symbol: 'COW',
decimals: 18,
address: '0x91056D4A53E1faa1A84306D4deAEc71085394bC8',
logoURI: 'https://gnosis.mypinata.cloud/ipfs/Qme9B6jRpGtZsRFcPjHvA5T4ugFuL4c3SzWfxyMPa59AMo',
},
{
name: 'USD Coin',
chainId: 5,
symbol: 'USDC',
decimals: 6,
address: '0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
},
{
name: 'DAI',
chainId: 5,
symbol: 'DAI',
decimals: 18,
address: '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png',
},
{
name: '0x',
chainId: 5,
symbol: 'ZRX',
decimals: 18,
address: '0xe4E81Fa6B16327D4B78CFEB83AAdE04bA7075165',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xE41d2489571d322189246DaFA5ebDe1F4699F498/logo.png',
},
].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name))

export const favouriteTokensMock: TokenWithLogo[] = [
{
name: 'Basic Attention Token',
chainId: 5,
symbol: 'BAT',
decimals: 18,
address: '0x70cBa46d2e933030E2f274AE58c951C800548AeF',
logoURI:
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x0D8775F648430679A709E98d2b0Cb6250d2887EF/logo.png',
},
{
name: 'Polymath Network',
chainId: 5,
symbol: 'POLY',
decimals: 18,
address: '0x9e32c0EfF886B6Ccae99350Fd5e7002dCED55F15',
logoURI: 'https://assets.coingecko.com/coins/images/2784/thumb/inKkF01.png?1605007034',
},
].map((item) => new TokenWithLogo(item.logoURI, item.chainId, item.address, item.decimals, item.symbol, item.name))
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import styled from 'styled-components/macro'

import { UI } from 'common/constants/theme'

export const Wrapper = styled.div`
display: flex;
flex-direction: column;
background: var(${UI.COLOR_CONTAINER_BG_01});
border-radius: 20px;
`

export const Row = styled.div`
margin: 0 20px 15px 20px;
`

export const Header = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 20px 20px 0 20px;
margin-bottom: 15px;
> h3 {
font-size: 16px;
font-weight: 500;
margin: 0;
}
> button {
margin: 0;
padding: 0;
border: none;
outline: none;
background: none;
cursor: pointer;
opacity: 0.6;
transition: opacity 0.2s ease-in-out;
> svg {
color: var(${UI.COLOR_TEXT1});
}
&:hover {
opacity: 1;
}
}
`

export const SearchInput = styled.input`
width: 100%;
outline: none;
border-radius: 20px;
color: var(${UI.COLOR_TEXT1});
padding: 16px;
border: 1px solid var(${UI.COLOR_GREY});
-webkit-appearance: none;
transition: border 100ms;
background: transparent;
font-size: 18px;
::placeholder {
color: var(${UI.COLOR_LINK});
}
:focus {
border: 1px solid var(${UI.COLOR_CONTAINER_BG_02});
outline: none;
}
`

export const ActionButton = styled.button`
display: flex;
width: 100%;
align-items: center;
flex-direction: row;
justify-content: center;
gap: 10px;
cursor: pointer;
padding: 20px 0;
margin: 0;
font-size: 16px;
font-weight: 500;
color: var(${UI.COLOR_TEXT1});
background: none;
border: 0;
outline: none;
&:hover {
opacity: 0.7;
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { TokenAmount, TokenSymbol } from '@cowprotocol/ui'
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'

import * as styledEl from './styled'

import { TokenWithLogo } from '../../types'

export interface AllTokensListProps {
tokens: TokenWithLogo[]
selectedToken?: TokenWithLogo
balances: { [key: string]: CurrencyAmount<Currency> }
}

export function AllTokensList(props: AllTokensListProps) {
const { tokens, selectedToken, balances } = props

return (
<styledEl.Wrapper>
{tokens.map((token) => {
const isTokenSelected = token.address.toLowerCase() === selectedToken?.address.toLowerCase()

return (
<styledEl.TokenItem key={token.address} disabled={isTokenSelected} data-address={token.address}>
<styledEl.TokenInfo>
<styledEl.TokenLogo src={token.logoURI} alt={token.name} />
<div>
<TokenSymbol token={token} />
<styledEl.TokenName>{token.name}</styledEl.TokenName>
</div>
</styledEl.TokenInfo>
<span>
<TokenAmount amount={balances[token.address.toLowerCase()]} />
</span>
</styledEl.TokenItem>
)
})}
</styledEl.Wrapper>
)
}
Loading

0 comments on commit d5b69cd

Please sign in to comment.