feat: add the phase0 chain switcher (#4376)

* feat: add phase0 chain switcher

* update styles

* add chain switcher files

* remove unneeded eslint disable

* add Celo and remove unneeded null check

* remove old comment

* fix mobile routing

Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
This commit is contained in:
Charles Bachmeier 2022-08-17 11:24:56 -07:00 committed by GitHub
parent de0a716f41
commit 1636786af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 161 additions and 3 deletions

@ -0,0 +1,49 @@
import { style } from '@vanilla-extract/css'
import { sprinkles } from '../../nft/css/sprinkles.css'
export const ChainSwitcher = style([
sprinkles({
background: 'lightGrayContainer',
borderRadius: '8',
paddingY: '8',
paddingX: '12',
cursor: 'pointer',
border: 'none',
}),
])
export const ChainSwitcherRow = style([
sprinkles({
border: 'none',
color: 'blackBlue',
justifyContent: 'space-between',
paddingX: '16',
paddingY: '12',
cursor: 'pointer',
}),
{
lineHeight: '24px',
width: '308px',
},
])
export const Image = style([
sprinkles({
width: '28',
height: '28',
}),
])
export const Icon = style([
Image,
sprinkles({
marginRight: '12',
}),
])
export const Indicator = style([
sprinkles({
marginLeft: '8',
}),
])

@ -0,0 +1,108 @@
import { useWeb3React } from '@web3-react/core'
import { getChainInfo } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useSelectChain from 'hooks/useSelectChain'
import useSyncChainQuery from 'hooks/useSyncChainQuery'
import { Box } from 'nft/components/Box'
import { Column, Row } from 'nft/components/Flex'
import { NewChevronDownIcon, NewChevronUpIcon } from 'nft/components/icons'
import { CheckMarkIcon } from 'nft/components/icons'
import { subhead } from 'nft/css/common.css'
import { ReactNode, useReducer, useRef } from 'react'
import { isChainAllowed } from 'utils/switchChain'
import * as styles from './ChainSwitcher.css'
import { NavDropdown } from './NavDropdown'
const ChainRow = ({
targetChain,
onSelectChain,
}: {
targetChain: SupportedChainId
onSelectChain: (targetChain: number) => void
}) => {
const { chainId } = useWeb3React()
const active = chainId === targetChain
const { label, logoUrl } = getChainInfo(targetChain)
return (
<Row
as="button"
background={active ? 'lightGrayContainer' : 'none'}
className={`${styles.ChainSwitcherRow} ${subhead}`}
onClick={() => onSelectChain(targetChain)}
>
<ChainDetails>
<img src={logoUrl} alt={label} className={styles.Icon} />
{label}
</ChainDetails>
{active && <CheckMarkIcon width={20} height={20} />}
</Row>
)
}
const ChainDetails = ({ children }: { children: ReactNode }) => <Row>{children}</Row>
const NETWORK_SELECTOR_CHAINS = [
SupportedChainId.MAINNET,
SupportedChainId.POLYGON,
SupportedChainId.OPTIMISM,
SupportedChainId.ARBITRUM_ONE,
SupportedChainId.CELO,
]
interface ChainSwitcherProps {
isMobile?: boolean
}
export const ChainSwitcher = ({ isMobile }: ChainSwitcherProps) => {
const { chainId, connector } = useWeb3React()
const [isOpen, toggleOpen] = useReducer((s) => !s, false)
const ref = useRef<HTMLDivElement>(null)
useOnClickOutside(ref, isOpen ? toggleOpen : undefined)
const info = chainId ? getChainInfo(chainId) : undefined
const selectChain = useSelectChain()
useSyncChainQuery()
if (!chainId || !info) {
return null
}
return (
<Box position="relative" ref={ref}>
<Row as="button" gap="8" className={styles.ChainSwitcher} onClick={toggleOpen}>
<img src={info.logoUrl} alt={info.label} className={styles.Image} />
<Box as="span" className={subhead} color="explicitWhite" style={{ lineHeight: '20px' }}>
{info.label}
</Box>
{isOpen ? (
<NewChevronUpIcon width={16} height={16} color="darkGray" />
) : (
<NewChevronDownIcon width={16} height={16} color="darkGray" />
)}
</Row>
{isOpen && (
<NavDropdown top={60} leftAligned={isMobile}>
<Column gap="4">
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) =>
isChainAllowed(connector, chainId) ? (
<ChainRow
onSelectChain={async (targetChainId: SupportedChainId) => {
await selectChain(targetChainId)
toggleOpen()
}}
targetChain={chainId}
key={chainId}
/>
) : null
)}
</Column>
</NavDropdown>
)}
</Box>
)
}

@ -159,7 +159,7 @@ export const MobileSideBar = () => {
<NavLinkRow href="/swap" close={toggleOpen} isActive={pathname.startsWith('/swap')}>
Swap
</NavLinkRow>
<NavLinkRow href="/explore" close={toggleOpen} isActive={pathname.startsWith('/explore')}>
<NavLinkRow href="/tokens" close={toggleOpen} isActive={pathname.startsWith('/tokens')}>
Tokens
</NavLinkRow>
<NavLinkRow href="/pool" id={'pool-nav-link'} isActive={isPoolActive} close={toggleOpen}>

@ -7,6 +7,7 @@ import { Box } from '../../nft/components/Box'
import { Row } from '../../nft/components/Flex'
import { UniIcon, UniIconMobile } from '../../nft/components/icons'
import { breakpoints } from '../../nft/css/sprinkles.css'
import { ChainSwitcher } from './ChainSwitcher'
import { MenuDropdown } from './MenuDropdown'
import { MobileSideBar } from './MobileSidebar'
import * as styles from './Navbar.css'
@ -40,7 +41,7 @@ const MobileNavbar = () => {
<Box as="a" href="#/swap" className={styles.logoContainer}>
<UniIconMobile width="44" height="44" className={styles.logo} />
</Box>
{/* TODO add ChainSwitcher */}
<ChainSwitcher isMobile={true} />
</Box>
<Box className={styles.rightSideMobileContainer}>
<Row gap="16">
@ -95,7 +96,7 @@ const Navbar = () => {
<Box className={styles.rightSideContainer}>
<Row gap="12">
<MenuDropdown />
{/* TODO add ChainSwitcher */}
<ChainSwitcher />
<Web3Status />
</Row>
</Box>