feat: Mobile Nav (#4501)

* working and cleaned up mobile nav

* delete old files

* fix wallet position

* update searchbar breakpoint

* update full screen search

* delete old comments

* cleanup eslint

* Update MenuDropdown.tsx

* Update SearchBar.tsx

Co-authored-by: Charlie <charlie@uniswap.org>
This commit is contained in:
Charles Bachmeier 2022-08-26 04:39:58 -07:00 committed by GitHub
parent 748a5eadc0
commit 751ce8e6d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 151 additions and 552 deletions

@ -79,7 +79,7 @@ export const ChainSwitcher = ({ leftAlign }: ChainSwitcherProps) => {
const isSupported = !!info const isSupported = !!info
const dropdown = ( const dropdown = (
<NavDropdown top={54} leftAligned={leftAlign} paddingBottom={8} paddingTop={8}> <NavDropdown top="56" left="0">
<Column marginX="8"> <Column marginX="8">
{NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) => ( {NETWORK_SELECTOR_CHAINS.map((chainId: SupportedChainId) => (
<ChainRow <ChainRow

@ -62,6 +62,6 @@ export const Separator = style([
export const IconRow = style([ export const IconRow = style([
sprinkles({ sprinkles({
paddingX: '16', paddingX: '16',
marginTop: '4', justifyContent: { sm: 'center', md: 'flex-start' },
}), }),
]) ])

@ -129,7 +129,7 @@ export const MenuDropdown = () => {
</NavIcon> </NavIcon>
{isOpen && ( {isOpen && (
<NavDropdown top={60}> <NavDropdown top={{ sm: 'unset', xxl: '56' }} bottom={{ sm: '56', xxl: 'unset' }} right="0">
<Column gap="16"> <Column gap="16">
<Column paddingX="8" gap="4"> <Column paddingX="8" gap="4">
{nftFlag === NftVariant.Enabled && ( {nftFlag === NftVariant.Enabled && (
@ -154,7 +154,13 @@ export const MenuDropdown = () => {
</PrimaryMenuRow> </PrimaryMenuRow>
</Column> </Column>
<Separator /> <Separator />
<Column paddingX="8"> <Box
display="flex"
flexDirection={{ sm: 'row', md: 'column' }}
flexWrap="wrap"
alignItems={{ sm: 'center', md: 'flex-start' }}
paddingX="8"
>
<SecondaryLinkedText href="https://help.uniswap.org/en/">Help center </SecondaryLinkedText> <SecondaryLinkedText href="https://help.uniswap.org/en/">Help center </SecondaryLinkedText>
<SecondaryLinkedText href="https://docs.uniswap.org/">Documentation </SecondaryLinkedText> <SecondaryLinkedText href="https://docs.uniswap.org/">Documentation </SecondaryLinkedText>
<SecondaryLinkedText <SecondaryLinkedText
@ -166,7 +172,7 @@ export const MenuDropdown = () => {
{(isDevelopmentEnv() || isStagingEnv()) && ( {(isDevelopmentEnv() || isStagingEnv()) && (
<SecondaryLinkedText onClick={openFeatureFlagsModal}>{`Feature Flags`}</SecondaryLinkedText> <SecondaryLinkedText onClick={openFeatureFlagsModal}>{`Feature Flags`}</SecondaryLinkedText>
)} )}
</Column> </Box>
<IconRow> <IconRow>
<Icon href="https://discord.com/invite/FCfyBSbCU5"> <Icon href="https://discord.com/invite/FCfyBSbCU5">
<DiscordIconMenu className={styles.hover} width={24} height={24} color={themeVars.colors.darkGray} /> <DiscordIconMenu className={styles.hover} width={24} height={24} color={themeVars.colors.darkGray} />

@ -1,121 +0,0 @@
import { style } from '@vanilla-extract/css'
import { subhead } from 'nft/css/common.css'
import { sprinkles } from '../../nft/css/sprinkles.css'
export const sidebar = style([
sprinkles({
display: 'flex',
position: 'fixed',
background: 'white',
height: 'full',
top: '0',
left: '0',
right: '0',
bottom: '0',
paddingBottom: '16',
justifyContent: 'space-between',
}),
{
zIndex: 20,
},
])
export const icon = style([
sprinkles({
width: '32',
height: '32',
}),
])
export const iconContainer = style([
sprinkles({
position: 'relative',
display: 'flex',
flexDirection: 'column',
color: 'darkGray',
background: 'none',
border: 'none',
justifyContent: 'flex-end',
textAlign: 'center',
cursor: 'pointer',
padding: '6',
}),
])
export const linkRow = style([
subhead,
sprinkles({
color: 'blackBlue',
width: 'full',
paddingLeft: '16',
paddingY: '12',
cursor: 'pointer',
}),
{
lineHeight: '24px',
textDecoration: 'none',
},
])
export const activeLinkRow = style([
linkRow,
sprinkles({
background: 'lightGrayButton',
}),
])
export const separator = style([
sprinkles({
height: '0',
borderStyle: 'solid',
borderColor: 'medGray',
borderWidth: '1px',
marginY: '8',
marginX: '16',
}),
])
export const extraLinkRow = style([
subhead,
sprinkles({
width: 'full',
color: 'blackBlue',
paddingY: '12',
paddingLeft: '16',
cursor: 'pointer',
}),
{
lineHeight: '24px',
textDecoration: 'none',
},
])
export const bottomExternalLinks = style([
sprinkles({
gap: '4',
paddingX: '4',
width: 'max',
flexWrap: 'wrap',
}),
])
export const bottomJointExternalLinksContainer = style([
sprinkles({
paddingX: '8',
paddingY: '4',
color: 'darkGray',
fontWeight: 'medium',
fontSize: '12',
}),
{
lineHeight: '20px',
},
])
export const IconRow = style([
sprinkles({
gap: '12',
width: 'max',
}),
])

@ -1,249 +0,0 @@
import FeatureFlagModal from 'components/FeatureFlagModal/FeatureFlagModal'
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { Box } from 'nft/components/Box'
import { Portal } from 'nft/components/common/Portal'
import { Column, Row } from 'nft/components/Flex'
import {
BarChartIconMobile,
BulletIcon,
CloseIcon,
DiscordIconMenuMobile,
GithubIconMenuMobile,
GovernanceIconMobile,
HamburgerIcon,
ThinTagIconMobile,
TwitterIconMenuMobile,
} from 'nft/components/icons'
import { themeVars } from 'nft/css/sprinkles.css'
import { ReactNode, useReducer } from 'react'
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'
import { useToggleModal, useTogglePrivacyPolicy } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer'
import { isDevelopmentEnv, isStagingEnv } from 'utils/env'
import * as styles from './MobileSidebar.css'
import { NavIcon } from './NavIcon'
interface NavLinkRowProps {
href: string
id?: NavLinkProps['id']
isActive?: boolean
close: () => void
children: ReactNode
}
const NavLinkRow = ({ href, id, isActive, close, children }: NavLinkRowProps) => {
return (
<NavLink to={href} className={isActive ? styles.activeLinkRow : styles.linkRow} id={id} onClick={close}>
{children}
</NavLink>
)
}
const ExtraLinkRow = ({
to,
href,
close,
children,
}: {
to?: NavLinkProps['to']
href?: string
close: () => void
children: ReactNode
}) => {
return (
<>
{to ? (
<NavLink to={to} className={styles.extraLinkRow}>
<Row gap="12" onClick={close}>
{children}
</Row>
</NavLink>
) : (
<Row
as="a"
href={href}
target={'_blank'}
rel={'noopener noreferrer'}
gap="12"
onClick={close}
className={styles.extraLinkRow}
>
{children}
</Row>
)}
</>
)
}
const BottomExternalLink = ({
href,
onClick,
children,
}: {
href?: string
onClick?: () => void
children: ReactNode
}) => {
return (
<Box
as={href ? 'a' : 'div'}
href={href ?? undefined}
target={href ? '_blank' : undefined}
rel={href ? 'noopener noreferrer' : undefined}
className={`${styles.bottomJointExternalLinksContainer}`}
onClick={onClick}
cursor="pointer"
>
{children}
</Box>
)
}
const Icon = ({ href, children }: { href?: string; children: ReactNode }) => {
return (
<>
<Box
as={href ? 'a' : 'div'}
href={href ?? undefined}
target={href ? '_blank' : undefined}
rel={href ? 'noopener noreferrer' : undefined}
display="flex"
flexDirection="column"
color="blackBlue"
background="none"
border="none"
justifyContent="center"
textAlign="center"
>
{children}
</Box>
</>
)
}
const IconRow = ({ children }: { children: ReactNode }) => {
return <Row className={styles.IconRow}>{children}</Row>
}
const Seperator = () => {
return <Box className={styles.separator} />
}
export const MobileSideBar = () => {
const [isOpen, toggleOpen] = useReducer((s) => !s, false)
const togglePrivacyPolicy = useTogglePrivacyPolicy()
const openFeatureFlagsModal = useToggleModal(ApplicationModal.FEATURE_FLAGS)
const { pathname } = useLocation()
const nftFlag = useNftFlag()
const isPoolActive =
pathname.startsWith('/pool') ||
pathname.startsWith('/add') ||
pathname.startsWith('/remove') ||
pathname.startsWith('/increase') ||
pathname.startsWith('/find')
return (
<>
<NavIcon isActive={isOpen} onClick={toggleOpen}>
<HamburgerIcon width={28} height={28} />
</NavIcon>
{isOpen && (
<Portal>
<Column className={styles.sidebar}>
<Column>
<Row justifyContent="flex-end" marginTop="14" marginBottom="20" marginRight="8">
<Box as="button" onClick={toggleOpen} className={styles.iconContainer}>
<CloseIcon className={styles.icon} />
</Box>
</Row>
<Column gap="4">
<NavLinkRow href="/swap" close={toggleOpen} isActive={pathname.startsWith('/swap')}>
Swap
</NavLinkRow>
<NavLinkRow href="/tokens" close={toggleOpen} isActive={pathname.startsWith('/tokens')}>
Tokens
</NavLinkRow>
{nftFlag === NftVariant.Enabled && (
<NavLinkRow href="/nfts" close={toggleOpen} isActive={pathname.startsWith('/nfts')}>
NFTs
</NavLinkRow>
)}
<NavLinkRow href="/pool" id={'pool-nav-link'} isActive={isPoolActive} close={toggleOpen}>
Pool
</NavLinkRow>
</Column>
<Seperator />
<Column gap="4">
{nftFlag === NftVariant.Enabled && (
<ExtraLinkRow to="/nft/sell" close={toggleOpen}>
<Icon>
<ThinTagIconMobile width={24} height={24} />
</Icon>
Sell NFTs
</ExtraLinkRow>
)}
<ExtraLinkRow to="/vote" close={toggleOpen}>
<Icon>
<GovernanceIconMobile width={24} height={24} />
</Icon>
Vote in governance
</ExtraLinkRow>
<ExtraLinkRow href="https://info.uniswap.org/#/" close={toggleOpen}>
<Icon>
<BarChartIconMobile width={24} height={24} />
</Icon>
View token analytics
</ExtraLinkRow>
</Column>
</Column>
<Column>
<Row justifyContent="center" marginBottom="12" flexWrap="wrap">
<Row className={styles.bottomExternalLinks}>
<BottomExternalLink href="https://help.uniswap.org/en/" onClick={toggleOpen}>
Help center
</BottomExternalLink>
<BulletIcon />
<BottomExternalLink href="https://docs.uniswap.org/" onClick={toggleOpen}>
Documentation
</BottomExternalLink>
<BulletIcon />
<BottomExternalLink
onClick={() => {
toggleOpen()
togglePrivacyPolicy()
}}
>
{`Legal & Privacy`}
</BottomExternalLink>
</Row>
{(isDevelopmentEnv() || isStagingEnv()) && (
<>
<BulletIcon />
<BottomExternalLink onClick={openFeatureFlagsModal}>{`Feature Flags`}</BottomExternalLink>
</>
)}
</Row>
<Row justifyContent="center">
<IconRow>
<Icon href="https://discord.com/invite/FCfyBSbCU5">
<DiscordIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
</Icon>
<Icon href="https://twitter.com/Uniswap">
<TwitterIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
</Icon>
<Icon href="https://github.com/Uniswap">
<GithubIconMenuMobile width={32} height={32} color={themeVars.colors.darkGray} />
</Icon>
</IconRow>
</Row>
</Column>
</Column>
</Portal>
)}
<PrivacyPolicyModal />
<FeatureFlagModal />
</>
)
}

@ -1,25 +1,40 @@
import { style } from '@vanilla-extract/css' import { style } from '@vanilla-extract/css'
import { breakpoints, sprinkles } from '../../nft/css/sprinkles.css' import { sprinkles } from '../../nft/css/sprinkles.css'
export const NavDropdown = style([ const baseNavDropdown = style([
sprinkles({ sprinkles({
position: { sm: 'fixed', md: 'absolute' },
background: 'lightGray', background: 'lightGray',
borderRadius: '12',
borderStyle: 'solid', borderStyle: 'solid',
borderColor: 'medGray', borderColor: 'medGray',
borderWidth: '1px', borderWidth: '1px',
bottom: { sm: '56', md: 'unset' }, paddingBottom: '8',
paddingTop: '8',
}), }),
{ {
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',
},
},
}, },
]) ])
export const NavDropdown = style([
baseNavDropdown,
sprinkles({
position: 'absolute',
borderRadius: '12',
}),
{},
])
export const mobileNavDropdown = style([
baseNavDropdown,
sprinkles({
position: 'fixed',
borderTopRightRadius: '12',
borderTopLeftRadius: '12',
top: 'unset',
bottom: '56',
left: '0',
right: '0',
}),
])

@ -1,45 +1,12 @@
import { Box } from 'nft/components/Box' import { Box, BoxProps } from 'nft/components/Box'
import { useIsMobile } from 'nft/hooks' import { useIsMobile } from 'nft/hooks'
import { ReactNode } from 'react' import { ForwardedRef, forwardRef } from 'react'
import * as styles from './NavDropdown.css' import * as styles from './NavDropdown.css'
interface NavDropdownProps { export const NavDropdown = forwardRef((props: BoxProps, ref: ForwardedRef<HTMLElement>) => {
top: number
right?: number
leftAligned?: boolean
horizontalPadding?: boolean
centerHorizontally?: boolean
paddingBottom?: number
paddingTop?: number
children: ReactNode
}
export const NavDropdown = ({
top,
centerHorizontally,
leftAligned,
horizontalPadding,
paddingBottom,
paddingTop,
children,
}: NavDropdownProps) => {
const isMobile = useIsMobile() const isMobile = useIsMobile()
return ( return <Box ref={ref} className={isMobile ? styles.mobileNavDropdown : styles.NavDropdown} {...props} />
<Box })
paddingX={horizontalPadding ? '16' : undefined}
style={{ NavDropdown.displayName = 'NavDropdown'
top: isMobile ? 'unset' : `${top}px`,
left: isMobile ? 0 : centerHorizontally ? '50%' : leftAligned ? '0px' : 'auto',
right: isMobile ? 0 : centerHorizontally || leftAligned ? 'auto' : '0px',
transform: centerHorizontally ? 'translateX(-50%)' : 'unset',
paddingBottom: paddingBottom ?? '24px',
paddingTop: paddingTop ?? '24px',
zIndex: 3,
}}
className={styles.NavDropdown}
>
{children}
</Box>
)
}

@ -7,7 +7,6 @@ export const navIcon = style([
position: 'relative', position: 'relative',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
color: 'blackBlue',
border: 'none', border: 'none',
justifyContent: 'center', justifyContent: 'center',
textAlign: 'center', textAlign: 'center',

@ -11,7 +11,13 @@ interface NavIconProps {
export const NavIcon = ({ children, isActive, onClick }: NavIconProps) => { export const NavIcon = ({ children, isActive, onClick }: NavIconProps) => {
return ( return (
<Box as="button" className={styles.navIcon} background={isActive ? 'accentActiveSoft' : 'none'} onClick={onClick}> <Box
as="button"
className={styles.navIcon}
background={isActive ? 'accentActiveSoft' : 'none'}
color={isActive ? 'blackBlue' : 'darkGray'}
onClick={onClick}
>
{children} {children}
</Box> </Box>
) )

@ -38,15 +38,6 @@ export const baseContainer = style([
}), }),
]) ])
export const baseMobileContainer = style([
sprinkles({
display: 'flex',
width: 'full',
alignItems: 'center',
marginY: '2',
}),
])
export const baseSideContainer = style([ export const baseSideContainer = style([
baseContainer, baseContainer,
sprinkles({ sprinkles({
@ -64,19 +55,13 @@ export const leftSideContainer = style([
}), }),
]) ])
export const leftSideMobileContainer = style([
baseMobileContainer,
sprinkles({
justifyContent: 'flex-start',
}),
])
export const middleContainer = style([ export const middleContainer = style([
baseContainer, baseContainer,
sprinkles({ sprinkles({
flex: '1', flex: '1',
flexShrink: '1', flexShrink: '1',
justifyContent: 'center', justifyContent: 'center',
display: { sm: 'none', lg: 'flex' },
}), }),
]) ])
@ -95,6 +80,7 @@ const baseMenuItem = style([
marginY: '4', marginY: '4',
borderRadius: '12', borderRadius: '12',
transition: '250', transition: '250',
height: 'min',
}), }),
{ {
lineHeight: '24px', lineHeight: '24px',
@ -112,13 +98,6 @@ export const menuItem = style([
}), }),
]) ])
export const rightSideMobileContainer = style([
baseMobileContainer,
sprinkles({
justifyContent: 'flex-end',
}),
])
export const activeMenuItem = style([ export const activeMenuItem = style([
baseMenuItem, baseMenuItem,
sprinkles({ sprinkles({
@ -127,16 +106,17 @@ export const activeMenuItem = style([
}), }),
]) ])
export const mobileWalletContainer = style([ export const mobileBottomBar = style([
sprinkles({ sprinkles({
position: 'fixed', position: 'fixed',
display: 'flex', display: { sm: 'flex', xxl: 'none' },
bottom: '0', bottom: '0',
right: '1/2', right: '0',
marginY: '0', left: '0',
marginX: 'auto', justifyContent: 'space-between',
paddingY: '4',
paddingX: '8',
height: '56',
background: 'lightGray',
}), }),
{
transform: 'translate(50%,-50%)',
},
]) ])

@ -1,16 +1,13 @@
import Web3Status from 'components/Web3Status' import Web3Status from 'components/Web3Status'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft' import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { useWindowSize } from 'hooks/useWindowSize'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { NavLink, NavLinkProps, useLocation } from 'react-router-dom' import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'
import { Box } from '../../nft/components/Box' import { Box } from '../../nft/components/Box'
import { Row } from '../../nft/components/Flex' import { Row } from '../../nft/components/Flex'
import { UniIcon, UniIconMobile } from '../../nft/components/icons' import { UniIcon } from '../../nft/components/icons'
import { breakpoints } from '../../nft/css/sprinkles.css'
import { ChainSwitcher } from './ChainSwitcher' import { ChainSwitcher } from './ChainSwitcher'
import { MenuDropdown } from './MenuDropdown' import { MenuDropdown } from './MenuDropdown'
import { MobileSideBar } from './MobileSidebar'
import * as styles from './Navbar.css' import * as styles from './Navbar.css'
import { SearchBar } from './SearchBar' import { SearchBar } from './SearchBar'
@ -34,46 +31,10 @@ const MenuItem = ({ href, id, isActive, children }: MenuItemProps) => {
) )
} }
const MobileNavbar = () => { const PageTabs = () => {
return (
<>
<nav className={styles.nav}>
<Box display="flex" height="full" flexWrap="nowrap" alignItems="stretch">
<Box className={styles.leftSideMobileContainer}>
<Box as="a" href="#/swap" className={styles.logoContainer}>
<UniIconMobile width="44" height="44" className={styles.logo} />
</Box>
<ChainSwitcher leftAlign={true} />
</Box>
<Box className={styles.middleContainer} display={{ sm: 'none', md: 'flex' }}>
<SearchBar />
</Box>
<Box className={styles.rightSideMobileContainer}>
<Row gap="16">
<Box display={{ sm: 'flex', md: 'none' }}>
<SearchBar />
</Box>
<MobileSideBar />
</Row>
</Box>
</Box>
</nav>
<Box className={styles.mobileWalletContainer}>
<Web3Status />
</Box>
</>
)
}
const Navbar = () => {
const { width: windowWidth } = useWindowSize()
const { pathname } = useLocation() const { pathname } = useLocation()
const nftFlag = useNftFlag() const nftFlag = useNftFlag()
if (windowWidth && windowWidth <= breakpoints.xl) {
return <MobileNavbar />
}
const isPoolActive = const isPoolActive =
pathname.startsWith('/pool') || pathname.startsWith('/pool') ||
pathname.startsWith('/add') || pathname.startsWith('/add') ||
@ -82,13 +43,7 @@ const Navbar = () => {
pathname.startsWith('/find') pathname.startsWith('/find')
return ( return (
<nav className={styles.nav}> <>
<Box display="flex" height="full" flexWrap="nowrap" alignItems="stretch">
<Box className={styles.leftSideContainer}>
<Box as="a" href="#/swap" className={styles.logoContainer}>
<UniIcon width="48" height="48" className={styles.logo} />
</Box>
<Row gap="8">
<MenuItem href="/swap" isActive={pathname.startsWith('/swap')}> <MenuItem href="/swap" isActive={pathname.startsWith('/swap')}>
Swap Swap
</MenuItem> </MenuItem>
@ -103,20 +58,51 @@ const Navbar = () => {
<MenuItem href="/pool" id={'pool-nav-link'} isActive={isPoolActive}> <MenuItem href="/pool" id={'pool-nav-link'} isActive={isPoolActive}>
Pool Pool
</MenuItem> </MenuItem>
</>
)
}
const Navbar = () => {
return (
<>
<nav className={styles.nav}>
<Box display="flex" height="full" flexWrap="nowrap" alignItems="stretch">
<Box className={styles.leftSideContainer}>
<Box as="a" href="#/swap" className={styles.logoContainer}>
<UniIcon width="48" height="48" className={styles.logo} />
</Box>
<Box display={{ sm: 'flex', xxl: 'none' }}>
<ChainSwitcher leftAlign={true} />
</Box>
<Row gap="8" display={{ sm: 'none', xxl: 'flex' }}>
<PageTabs />
</Row> </Row>
</Box> </Box>
<Box className={styles.middleContainer} display="flex"> <Box className={styles.middleContainer}>
<SearchBar /> <SearchBar />
</Box> </Box>
<Box className={styles.rightSideContainer}> <Box className={styles.rightSideContainer}>
<Row gap="12"> <Row gap="12">
<Box display={{ sm: 'flex', lg: 'none' }}>
<SearchBar />
</Box>
<Box display={{ sm: 'none', xxl: 'flex' }}>
<MenuDropdown /> <MenuDropdown />
</Box>
<Box display={{ sm: 'none', xxl: 'flex' }}>
<ChainSwitcher /> <ChainSwitcher />
</Box>
<Web3Status /> <Web3Status />
</Row> </Row>
</Box> </Box>
</Box> </Box>
</nav> </nav>
<Box className={styles.mobileBottomBar}>
<PageTabs />
<MenuDropdown />
</Box>
</>
) )
} }

@ -15,7 +15,7 @@ const baseSearchStyle = style([
}), }),
{ {
'@media': { '@media': {
[`screen and (min-width: ${breakpoints.sm}px)`]: { [`screen and (min-width: ${breakpoints.md}px)`]: {
width: DESKTOP_NAVBAR_WIDTH, width: DESKTOP_NAVBAR_WIDTH,
}, },
}, },

@ -2,14 +2,12 @@ import clsx from 'clsx'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft' import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import useDebounce from 'hooks/useDebounce' import useDebounce from 'hooks/useDebounce'
import { useOnClickOutside } from 'hooks/useOnClickOutside' import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useWindowSize } from 'hooks/useWindowSize'
import { organizeSearchResults } from 'lib/utils/searchBar' import { organizeSearchResults } from 'lib/utils/searchBar'
import { Box } from 'nft/components/Box' import { Box } from 'nft/components/Box'
import { Column, Row } from 'nft/components/Flex' import { Column, Row } from 'nft/components/Flex'
import { Overlay } from 'nft/components/modals/Overlay' import { Overlay } from 'nft/components/modals/Overlay'
import { magicalGradientOnHover, subheadSmall } from 'nft/css/common.css' import { magicalGradientOnHover, subheadSmall } from 'nft/css/common.css'
import { breakpoints } from 'nft/css/sprinkles.css' import { useIsMobile, useSearchHistory } from 'nft/hooks'
import { useSearchHistory } from 'nft/hooks'
import { fetchSearchCollections, fetchTrendingCollections } from 'nft/queries' import { fetchSearchCollections, fetchTrendingCollections } from 'nft/queries'
import { fetchSearchTokens } from 'nft/queries/genie/SearchTokensFetcher' import { fetchSearchTokens } from 'nft/queries/genie/SearchTokensFetcher'
import { fetchTrendingTokens } from 'nft/queries/genie/TrendingTokensFetcher' import { fetchTrendingTokens } from 'nft/queries/genie/TrendingTokensFetcher'
@ -267,8 +265,8 @@ export const SearchBar = () => {
const debouncedSearchValue = useDebounce(searchValue, 300) const debouncedSearchValue = useDebounce(searchValue, 300)
const searchRef = useRef<HTMLDivElement>(null) const searchRef = useRef<HTMLDivElement>(null)
const { pathname } = useLocation() const { pathname } = useLocation()
const { width: windowWidth } = useWindowSize()
const phase1Flag = useNftFlag() const phase1Flag = useNftFlag()
const isMobile = useIsMobile()
useOnClickOutside(searchRef, () => { useOnClickOutside(searchRef, () => {
isOpen && toggleOpen() isOpen && toggleOpen()
@ -318,15 +316,13 @@ export const SearchBar = () => {
setSearchValue('') setSearchValue('')
}, [pathname]) }, [pathname])
const isMobile = useMemo(() => windowWidth && windowWidth <= breakpoints.sm, [windowWidth])
return ( return (
<> <>
<Box <Box
position={{ sm: isOpen ? 'absolute' : 'relative', md: 'relative' }} position={{ sm: isOpen ? 'absolute' : 'relative', lg: 'relative' }}
top={{ sm: '0', md: 'unset' }} top={{ sm: '0', lg: 'unset' }}
left={{ sm: '0', md: 'unset' }} left={{ sm: '0', lg: 'unset' }}
width={{ sm: isOpen ? 'viewWidth' : 'auto', md: 'auto' }} width={{ sm: isOpen ? 'viewWidth' : 'auto', lg: 'auto' }}
ref={searchRef} ref={searchRef}
style={{ zIndex: '1000' }} style={{ zIndex: '1000' }}
> >
@ -335,16 +331,16 @@ export const SearchBar = () => {
borderRadius={isOpen ? undefined : '12'} borderRadius={isOpen ? undefined : '12'}
borderTopRightRadius={isOpen && !isMobile ? '12' : undefined} borderTopRightRadius={isOpen && !isMobile ? '12' : undefined}
borderTopLeftRadius={isOpen && !isMobile ? '12' : undefined} borderTopLeftRadius={isOpen && !isMobile ? '12' : undefined}
display={{ sm: isOpen ? 'flex' : 'none', md: 'flex' }} display={{ sm: isOpen ? 'flex' : 'none', lg: 'flex' }}
justifyContent={isOpen || phase1Flag === NftVariant.Enabled ? 'flex-start' : 'center'} justifyContent={isOpen || phase1Flag === NftVariant.Enabled ? 'flex-start' : 'center'}
onFocus={() => !isOpen && toggleOpen()} onFocus={() => !isOpen && toggleOpen()}
onClick={() => !isOpen && toggleOpen()} onClick={() => !isOpen && toggleOpen()}
gap="12" gap="12"
> >
<Box display={{ sm: 'none', md: 'flex' }}> <Box display={{ sm: 'none', lg: 'flex' }}>
<MagnifyingGlassIcon /> <MagnifyingGlassIcon />
</Box> </Box>
<Box display={{ sm: 'flex', md: 'none' }} color="placeholder" onClick={toggleOpen}> <Box display={{ sm: 'flex', lg: 'none' }} color="placeholder" onClick={toggleOpen}>
<ChevronLeftIcon /> <ChevronLeftIcon />
</Box> </Box>
<Box <Box
@ -359,7 +355,7 @@ export const SearchBar = () => {
value={searchValue} value={searchValue}
/> />
</Row> </Row>
<Box display={{ sm: isOpen ? 'none' : 'flex', md: 'none' }}> <Box display={{ sm: isOpen ? 'none' : 'flex', lg: 'none' }}>
<NavIcon onClick={toggleOpen}> <NavIcon onClick={toggleOpen}>
<NavMagnifyingGlassIcon width={28} height={28} /> <NavMagnifyingGlassIcon width={28} height={28} />
</NavIcon> </NavIcon>

@ -20,6 +20,10 @@ const WalletWrapper = styled.div`
border: ${({ theme }) => `1px solid ${theme.backgroundOutline}`}; border: ${({ theme }) => `1px solid ${theme.backgroundOutline}`};
box-shadow: ${({ theme }) => theme.deepShadow}; box-shadow: ${({ theme }) => theme.deepShadow};
padding: 16px 0; padding: 16px 0;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
width: 100%;
}
` `
export enum MenuState { export enum MenuState {
@ -33,11 +37,12 @@ const WalletDropdownWrapper = styled.div`
top: 65px; top: 65px;
right: 20px; right: 20px;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.xl}px`}) { @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
top: unset; top: unset;
right: 50%; left: 0;
bottom: 45px; right: 0;
transform: translateX(50%); bottom: 56px;
z-index: 1;
} }
` `

@ -6,6 +6,8 @@ import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import WalletDropdown from 'components/WalletDropdown' import WalletDropdown from 'components/WalletDropdown'
import { getConnection } from 'connection/utils' import { getConnection } from 'connection/utils'
import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar' import { NavBarVariant, useNavBarFlag } from 'featureFlags/flags/navBar'
import { Portal } from 'nft/components/common/Portal'
import { useIsMobile } from 'nft/hooks'
import { getIsValidSwapQuote } from 'pages/Swap' import { getIsValidSwapQuote } from 'pages/Swap'
import { darken } from 'polished' import { darken } from 'polished'
import { useMemo, useRef } from 'react' import { useMemo, useRef } from 'react'
@ -285,6 +287,7 @@ export default function Web3Status() {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
const closeModal = useCloseModal(ApplicationModal.WALLET_DROPDOWN) const closeModal = useCloseModal(ApplicationModal.WALLET_DROPDOWN)
const isOpen = useIsOpen() const isOpen = useIsOpen()
const isMobile = useIsMobile()
useOnClickOutside(ref, isOpen ? closeModal : undefined) useOnClickOutside(ref, isOpen ? closeModal : undefined)
@ -300,7 +303,13 @@ export default function Web3Status() {
<span ref={ref}> <span ref={ref}>
<Web3StatusInner /> <Web3StatusInner />
<WalletModal ENSName={ENSName ?? undefined} pendingTransactions={pending} confirmedTransactions={confirmed} /> <WalletModal ENSName={ENSName ?? undefined} pendingTransactions={pending} confirmedTransactions={confirmed} />
{isMobile ? (
<Portal>
<WalletDropdown /> <WalletDropdown />
</Portal>
) : (
<WalletDropdown />
)}
</span> </span>
) )
} }