Skip to content

Commit

Permalink
feat(tokens): new UI for tokens management (#3174)
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

* feat: html of ManageListsAndTokens

* chore: manage lists styles

* chore: manage tokens styles

* chore: import token from blockchain UI

* chore: search tokens sources

* chore: extract ModalHeader component

* chore: component ImportTokenModal

* chore: manage lists states

* chore: component ImportListModal

* chore: fix build
  • Loading branch information
shoom3301 authored Oct 2, 2023
1 parent 4b3fbc0 commit 6c2c253
Show file tree
Hide file tree
Showing 42 changed files with 1,452 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Column, { AutoColumn } from 'legacy/components/Column'
import ListLogo from 'legacy/components/ListLogo'
import { CurrencyModalView } from 'legacy/components/SearchModal/CurrencySearchModal'
import { PaddedColumn, SearchInput, Separator, SeparatorDark } from 'legacy/components/SearchModal/styleds'
import Toggle from 'legacy/components/Toggle'
import { Toggle } from 'legacy/components/Toggle'
import { useFetchListCallback } from 'legacy/hooks/useFetchListCallback'
import { useAppDispatch, useAppSelector } from 'legacy/state/hooks'
import { useActiveListUrls, useAllLists, useIsListActive } from 'legacy/state/lists/hooks'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import styled, { ThemeContext } from 'styled-components/macro'

import { AutoColumn } from 'legacy/components/Column'
import QuestionHelper from 'legacy/components/QuestionHelper'
import Toggle from 'legacy/components/Toggle'
import { Toggle } from 'legacy/components/Toggle'
import TransactionSettings from 'legacy/components/TransactionSettings'
import { useModalIsOpen, useToggleSettingsMenu } from 'legacy/state/application/hooks'
import { ApplicationModal } from 'legacy/state/application/reducer'
Expand Down
10 changes: 5 additions & 5 deletions apps/cowswap-frontend/src/legacy/components/Toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import { UI } from 'common/constants/theme'

const turnOnToggle = keyframes`
from {
margin-left: 0em;
margin-left: 0;
margin-right: 2.2em;
}
to {
margin-left: 2.2em;
margin-right: 0em;
margin-right: 0;
}
`

const turnOffToggle = keyframes`
from {
margin-left: 2.2em;
margin-right: 0em;
margin-right: 0;
}
to {
margin-left: 0em;
margin-left: 0;
margin-right: 2.2em;
}
`
Expand Down Expand Up @@ -99,7 +99,7 @@ export interface ToggleProps extends WithClassName {
isDisabled?: boolean // Mod
}

export default function Toggle({ id, bgColor, isActive, toggle, className, isDisabled }: ToggleProps) {
export function Toggle({ id, bgColor, isActive, toggle, className, isDisabled }: ToggleProps) {
const [isInitialToggleLoad, setIsInitialToggleLoad] = useState(true)

const switchToggle = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import styled from 'styled-components/macro'

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

import { importListsMock, listsMock } from '../../mocks'

import { ManageLists } from './index'

const Wrapper = styled.div`
width: 450px;
background: var(${UI.COLOR_CONTAINER_BG_01});
`

const Fixtures = {
default: (
<Wrapper>
<ManageLists lists={listsMock} />
</Wrapper>
),
importList: (
<Wrapper>
<ManageLists lists={listsMock} listsToImport={importListsMock} />
</Wrapper>
),
loadedLists: (
<Wrapper>
<ManageLists lists={listsMock} loadedLists={importListsMock} />
</Wrapper>
),
}

export default Fixtures
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as styledEl from './styled'

import { PrimaryInput, PrimaryInputBox } from '../../pure/commonElements'
import { ImportTokenListItem } from '../../pure/ImportTokenListItem'
import { LoadedTokenListItem } from '../../pure/LoadedTokenListItem'
import { TokenListItem } from '../../pure/TokenListItem'
import { TokenList } from '../../types'

export interface ManageListsProps {
lists: TokenList[]
loadedLists?: TokenList[]
listsToImport?: TokenList[]
}

export function ManageLists(props: ManageListsProps) {
const { lists, loadedLists, listsToImport } = props

const viewList = (id: string) => {
console.log('TODO viewList', id)
}

const removeList = (id: string) => {
console.log('TODO removeList', id)
}

const importList = (list: TokenList) => {
console.log('TODO importList', list.id)
}

return (
<styledEl.Wrapper>
<PrimaryInputBox>
<PrimaryInput type="text" placeholder="https:// or ipfs:// or ENS name" />
</PrimaryInputBox>
{!!loadedLists?.length && (
<styledEl.ImportListsContainer>
{loadedLists.map((list) => (
<LoadedTokenListItem key={list.id} list={list} />
))}
</styledEl.ImportListsContainer>
)}
{!!listsToImport?.length && (
<styledEl.ImportListsContainer>
{listsToImport.map((list) => (
<ImportTokenListItem key={list.id} list={list} importList={importList} />
))}
</styledEl.ImportListsContainer>
)}
<styledEl.ListsContainer>
{lists.map((list) => (
<TokenListItem key={list.id} list={list} viewList={viewList} removeList={removeList} />
))}
</styledEl.ListsContainer>
</styledEl.Wrapper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import styled from 'styled-components/macro'

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

export const Wrapper = styled.div`
display: block;
width: 100%;
`

export const ListsContainer = styled.div`
padding-bottom: 20px;
`

export const ImportListsContainer = styled.div`
border-bottom: 1px solid var(${UI.COLOR_BORDER});
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import styled from 'styled-components/macro'

import { customTokensMock, listsMock } from '../../mocks'

import { ManageListsAndTokens } from './index'

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

const Fixtures = {
default: (
<Wrapper>
<ManageListsAndTokens customTokens={customTokensMock} lists={listsMock} />
</Wrapper>
),
}

export default Fixtures
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useState } from 'react'

import * as styledEl from './styled'

import { ModalHeader } from '../../pure/ModalHeader'
import { TokenList, TokenWithLogo } from '../../types'
import { ManageLists } from '../ManageLists'
import { ManageTokens } from '../ManageTokens'

export interface ManageListsAndTokensProps {
lists: TokenList[]
customTokens: TokenWithLogo[]
}

export function ManageListsAndTokens(props: ManageListsAndTokensProps) {
const { lists, customTokens } = props

const [currentTab, setCurrentTab] = useState<'tokens' | 'lists'>('lists')

const onBack = () => {
console.log('TODO onBack')
}

const onClose = () => {
console.log('TODO onClose')
}

return (
<styledEl.Wrapper>
<ModalHeader onBack={onBack} onClose={onClose}>
Manage
</ModalHeader>
<styledEl.TabsContainer>
<styledEl.Tab active$={currentTab === 'lists'} onClick={() => setCurrentTab('lists')}>
Lists
</styledEl.Tab>
<styledEl.Tab active$={currentTab === 'tokens'} onClick={() => setCurrentTab('tokens')}>
Tokens
</styledEl.Tab>
</styledEl.TabsContainer>
{currentTab === 'lists' ? <ManageLists lists={lists} /> : <ManageTokens tokens={customTokens} />}
</styledEl.Wrapper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from 'styled-components/macro'

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

import { blankButtonMixin } from '../../pure/commonElements'

export const Wrapper = styled.div`
display: block;
width: 100%;
background: var(${UI.COLOR_CONTAINER_BG_01});
border-radius: 20px;
`

export const TabsContainer = styled.div`
display: flex;
flex-direction: row;
flex-shrink: 0;
margin-top: 10px;
> button {
width: 50%;
}
`

export const Tab = styled.button<{ active$: boolean }>`
${blankButtonMixin};
color: var(${UI.COLOR_TEXT1});
opacity: ${({ active$ }) => (active$ ? 1 : 0.5)};
padding: 10px;
font-size: 16px;
font-weight: 600;
&:hover {
color: var(${UI.COLOR_TEXT2});
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ExplorerDataType, getExplorerLink } from '@cowprotocol/common-utils'
import { TokenSymbol } from '@cowprotocol/ui'

import { ExternalLink, Trash } from 'react-feather'

import * as styledEl from './styled'

import { PrimaryInput, PrimaryInputBox } from '../../pure/commonElements'
import { TokenLogo } from '../../pure/TokenLogo'
import { TokenWithLogo } from '../../types'

export interface ManageTokensProps {
tokens: TokenWithLogo[]
}

export function ManageTokens(props: ManageTokensProps) {
const { tokens } = props

const clearAll = () => {
console.log('TODO clearAll')
}

const removeToken = (token: TokenWithLogo) => {
console.log('TODO removeToken', token.symbol)
}

return (
<div>
<PrimaryInputBox>
<PrimaryInput type="text" placeholder="0x0000" />
</PrimaryInputBox>
<div>
<styledEl.Header>
<styledEl.Title>{tokens.length} Custom Tokens</styledEl.Title>
<styledEl.LinkButton onClick={clearAll}>Clear all</styledEl.LinkButton>
</styledEl.Header>
<div>
{tokens.map((token) => {
return (
<styledEl.TokenItem key={token.address}>
<styledEl.TokenInfo>
<TokenLogo logoURI={token.logoURI} size={20} />
<TokenSymbol token={token} />
</styledEl.TokenInfo>
<div>
<styledEl.LinkButton onClick={() => removeToken(token)}>
<Trash size={16} />
</styledEl.LinkButton>
<styledEl.LinkButton>
<a
target="_blank"
href={getExplorerLink(token.chainId, token.address, ExplorerDataType.TOKEN)}
rel="noreferrer"
>
<ExternalLink size={16} />
</a>
</styledEl.LinkButton>
</div>
</styledEl.TokenItem>
)
})}
</div>
<styledEl.TipText>Tip: Custom tokens are stored locally in your browser</styledEl.TipText>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import styled from 'styled-components/macro'

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

import { blankButtonMixin } from '../../pure/commonElements'

const RowBox = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`

export const Header = styled(RowBox)`
padding: 20px;
`

export const Title = styled.div`
font-weight: 600;
opacity: 0.65;
`

export const LinkButton = styled.button`
${blankButtonMixin};
font-size: 16px;
font-weight: 500;
color: var(${UI.COLOR_LINK});
margin-left: 10px;
&:hover {
opacity: 0.8;
}
`

export const TokenItem = styled(RowBox)`
padding: 0 20px;
margin-bottom: 20px;
`

export const TokenInfo = styled(RowBox)`
gap: 10px;
font-weight: 600;
`

export const TipText = styled.div`
font-size: 13px;
font-weight: 500;
color: var(${UI.COLOR_LINK});
text-align: center;
padding: 20px 0;
border-top: 1px solid var(${UI.COLOR_GREY});
margin-top: 20px;
`
Loading

0 comments on commit 6c2c253

Please sign in to comment.