feat: mobile network switcher (#4486)

* feat: mobile network switcher

* adjust bottom border radius on mobile

Co-authored-by: Charlie <charlie@uniswap.org>
This commit is contained in:
Charles Bachmeier 2022-08-25 09:31:47 -07:00 committed by GitHub
parent 33c73f4dc8
commit fdbe4b8f5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 31 deletions

@ -1,7 +1,7 @@
import { style } from '@vanilla-extract/css' import { style } from '@vanilla-extract/css'
import { lightGrayOverlayOnHover } from 'nft/css/common.css' import { lightGrayOverlayOnHover } from 'nft/css/common.css'
import { sprinkles } from '../../nft/css/sprinkles.css' import { breakpoints, sprinkles } from '../../nft/css/sprinkles.css'
export const ChainSwitcher = style([ export const ChainSwitcher = style([
lightGrayOverlayOnHover, lightGrayOverlayOnHover,
@ -26,11 +26,16 @@ export const ChainSwitcherRow = style([
cursor: 'pointer', cursor: 'pointer',
color: 'blackBlue', color: 'blackBlue',
borderRadius: '12', borderRadius: '12',
width: { sm: 'full' },
}), }),
{ {
lineHeight: '24px', lineHeight: '24px',
'@media': {
[`screen and (min-width: ${breakpoints.sm}px)`]: {
width: '204px', width: '204px',
}, },
},
},
]) ])
export const Image = style([ export const Image = style([

@ -5,10 +5,12 @@ import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useSelectChain from 'hooks/useSelectChain' import useSelectChain from 'hooks/useSelectChain'
import useSyncChainQuery from 'hooks/useSyncChainQuery' import useSyncChainQuery from 'hooks/useSyncChainQuery'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { Portal } from 'nft/components/common/Portal'
import { Column, Row } from 'nft/components/Flex' import { Column, Row } from 'nft/components/Flex'
import { CheckMarkIcon, NewChevronDownIcon, NewChevronUpIcon, TokenWarningRedIcon } from 'nft/components/icons' import { CheckMarkIcon, NewChevronDownIcon, NewChevronUpIcon, TokenWarningRedIcon } from 'nft/components/icons'
import { subhead } from 'nft/css/common.css' import { subhead } from 'nft/css/common.css'
import { themeVars, vars } from 'nft/css/sprinkles.css' import { themeVars, vars } from 'nft/css/sprinkles.css'
import { useIsMobile } from 'nft/hooks'
import { ReactNode, useReducer, useRef } from 'react' import { ReactNode, useReducer, useRef } from 'react'
import { isChainAllowed } from 'utils/switchChain' import { isChainAllowed } from 'utils/switchChain'
@ -55,12 +57,13 @@ const NETWORK_SELECTOR_CHAINS = [
] ]
interface ChainSwitcherProps { interface ChainSwitcherProps {
isMobile?: boolean leftAlign?: boolean
} }
export const ChainSwitcher = ({ isMobile }: ChainSwitcherProps) => { export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [isOpen, toggleOpen] = useReducer((s) => !s, false) const [isOpen, toggleOpen] = useReducer((s) => !s, false)
const isMobile = useIsMobile()
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
useOnClickOutside(ref, isOpen ? toggleOpen : undefined) useOnClickOutside(ref, isOpen ? toggleOpen : undefined)
@ -76,38 +79,8 @@ export const ChainSwitcher = ({ isMobile }: ChainSwitcherProps) => {
const isSupported = isChainAllowed(chainId) const isSupported = isChainAllowed(chainId)
return ( const dropdown = (
<Box position="relative" ref={ref}> <NavDropdown top={54} leftAligned={leftAlign} paddingBottom={8} paddingTop={8}>
<Row
as="button"
gap="8"
className={styles.ChainSwitcher}
background={isOpen ? 'accentActiveSoft' : 'none'}
onClick={toggleOpen}
>
{!isSupported ? (
<>
<TokenWarningRedIcon fill={themeVars.colors.darkGray} width={24} height={24} />
<Box as="span" className={subhead} style={{ lineHeight: '20px' }}>
{info?.label ?? 'Unsupported'}
</Box>
</>
) : (
<>
<img src={info.logoUrl} alt={info.label} className={styles.Image} />
<Box as="span" className={subhead} style={{ lineHeight: '20px' }}>
{info.label}
</Box>
</>
)}
{isOpen ? (
<NewChevronUpIcon width={16} height={16} color="blackBlue" />
) : (
<NewChevronDownIcon width={16} height={16} color="blackBlue" />
)}
</Row>
{isOpen && (
<NavDropdown top={60} leftAligned={isMobile} paddingBottom={8} paddingTop={8}>
<Column marginX="8"> <Column marginX="8">
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) => {NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) =>
isSupported ? ( isSupported ? (
@ -123,7 +96,39 @@ export const ChainSwitcher = ({ isMobile }: ChainSwitcherProps) => {
)} )}
</Column> </Column>
</NavDropdown> </NavDropdown>
)
return (
<Box position="relative" ref={ref}>
<Row
as="button"
gap="8"
className={styles.ChainSwitcher}
background={isOpen ? 'accentActiveSoft' : 'none'}
onClick={toggleOpen}
>
{!isSupported ? (
<>
<TokenWarningRedIcon fill={themeVars.colors.darkGray} width={24} height={24} />
<Box as="span" className={subhead} display={{ sm: 'none', xl: 'flex' }} style={{ lineHeight: '20px' }}>
{info?.label ?? 'Unsupported'}
</Box>
</>
) : (
<>
<img src={info.logoUrl} alt={info.label} className={styles.Image} />
<Box as="span" className={subhead} display={{ sm: 'none', xl: 'flex' }} style={{ lineHeight: '20px' }}>
{info.label}
</Box>
</>
)} )}
{isOpen ? (
<NewChevronUpIcon width={16} height={16} color="blackBlue" />
) : (
<NewChevronDownIcon width={16} height={16} color="blackBlue" />
)}
</Row>
{isOpen && (isMobile ? <Portal>{dropdown}</Portal> : <>{dropdown}</>)}
</Box> </Box>
) )
} }

@ -1,18 +1,25 @@
import { style } from '@vanilla-extract/css' import { style } from '@vanilla-extract/css'
import { sprinkles } from '../../nft/css/sprinkles.css' import { breakpoints, sprinkles } from '../../nft/css/sprinkles.css'
export const NavDropdown = style([ export const NavDropdown = style([
sprinkles({ sprinkles({
position: 'absolute', position: { sm: 'fixed', md: 'absolute' },
background: 'lightGray', background: 'lightGray',
borderRadius: '12', borderRadius: '12',
borderStyle: 'solid', borderStyle: 'solid',
borderColor: 'medGray', borderColor: 'medGray',
borderWidth: '1px', borderWidth: '1px',
bottom: { sm: '56', md: 'unset' },
}), }),
{ {
boxShadow: '0px 4px 12px 0px #00000026', boxShadow: '0px 4px 12px 0px #00000026',
zIndex: 10, zIndex: 10,
'@media': {
[`screen and (max-width: ${breakpoints.sm}px)`]: {
borderBottomLeftRadius: '0',
borderBottomRightRadius: '0',
},
},
}, },
]) ])

@ -1,4 +1,5 @@
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { useIsMobile } from 'nft/hooks'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import * as styles from './NavDropdown.css' import * as styles from './NavDropdown.css'
@ -23,13 +24,14 @@ export const NavDropdown = ({
paddingTop, paddingTop,
children, children,
}: NavDropdownProps) => { }: NavDropdownProps) => {
const isMobile = useIsMobile()
return ( return (
<Box <Box
paddingX={horizontalPadding ? '16' : undefined} paddingX={horizontalPadding ? '16' : undefined}
style={{ style={{
top: `${top}px`, top: isMobile ? 'unset' : `${top}px`,
left: centerHorizontally ? '50%' : leftAligned ? '0px' : 'auto', left: isMobile ? 0 : centerHorizontally ? '50%' : leftAligned ? '0px' : 'auto',
right: centerHorizontally || leftAligned ? 'auto' : '0px', right: isMobile ? 0 : centerHorizontally || leftAligned ? 'auto' : '0px',
transform: centerHorizontally ? 'translateX(-50%)' : 'unset', transform: centerHorizontally ? 'translateX(-50%)' : 'unset',
paddingBottom: paddingBottom ?? '24px', paddingBottom: paddingBottom ?? '24px',
paddingTop: paddingTop ?? '24px', paddingTop: paddingTop ?? '24px',

@ -43,7 +43,7 @@ const MobileNavbar = () => {
<Box as="a" href="#/swap" className={styles.logoContainer}> <Box as="a" href="#/swap" className={styles.logoContainer}>
<UniIconMobile width="44" height="44" className={styles.logo} /> <UniIconMobile width="44" height="44" className={styles.logo} />
</Box> </Box>
<ChainSwitcher isMobile={true} /> <ChainSwitcher leftAlign={true} />
</Box> </Box>
<Box className={styles.rightSideMobileContainer}> <Box className={styles.rightSideMobileContainer}>
<Row gap="16"> <Row gap="16">

@ -4,7 +4,6 @@ import { Box } from 'nft/components/Box'
import { Column, Row } from 'nft/components/Flex' import { Column, Row } from 'nft/components/Flex'
import { vars } from 'nft/css/sprinkles.css' import { vars } from 'nft/css/sprinkles.css'
import { useSearchHistory } from 'nft/hooks' import { useSearchHistory } from 'nft/hooks'
// import { fetchSearchCollections, fetchTrendingCollections } from 'nft/queries'
import { FungibleToken, GenieCollection } from 'nft/types' import { FungibleToken, GenieCollection } from 'nft/types'
import { ethNumberStandardFormatter } from 'nft/utils/currency' import { ethNumberStandardFormatter } from 'nft/utils/currency'
import { putCommas } from 'nft/utils/putCommas' import { putCommas } from 'nft/utils/putCommas'

@ -112,6 +112,7 @@ const spacing = {
'48': '48px', '48': '48px',
'50': '50px', '50': '50px',
'52': '52px', '52': '52px',
'56': '56px',
'60': '60px', '60': '60px',
'64': '64px', '64': '64px',
'82': '82px', '82': '82px',