style: updating collection page for mobile (#5078)

* style: updating collection page for mobile

* addressing comments

* responding to comments
This commit is contained in:
Jack Short 2022-11-04 16:13:17 -04:00 committed by GitHub
parent b1dc415fb5
commit c233ba1175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 84 additions and 109 deletions

@ -131,7 +131,7 @@ export const Activity = ({ contractAddress, rarityVerified, collectionName, chai
return (
<Box>
<Row gap="8" paddingTop="16">
<Row gap="8" paddingTop={{ sm: '0', md: '16' }}>
<Filter eventType={ActivityEventType.Listing} />
<Filter eventType={ActivityEventType.Sale} />
<Filter eventType={ActivityEventType.Transfer} />

@ -18,7 +18,7 @@ export const ActivitySwitcher = ({
const isLoading = useIsCollectionLoading((state) => state.isCollectionStatsLoading)
return (
<Row gap="24" marginBottom="28">
<Row gap="24" marginBottom={{ sm: '16', md: '28' }}>
{isLoading ? (
ActivitySwitcherLoading
) : (

@ -1,6 +1,6 @@
import { style } from '@vanilla-extract/css'
import { calc } from '@vanilla-extract/css-utils'
import { breakpoints, sprinkles, themeVars, vars } from 'nft/css/sprinkles.css'
import { sprinkles, themeVars } from 'nft/css/sprinkles.css'
export const card = style([
sprinkles({
@ -13,15 +13,6 @@ export const card = style([
{
boxSizing: 'border-box',
WebkitBoxSizing: 'border-box',
'@media': {
[`(max-width: ${breakpoints.sm - 1}px)`]: {
':hover': {
borderColor: themeVars.colors.backgroundOutline,
cursor: 'pointer',
background: vars.color.lightGrayOverlay,
},
},
},
},
])

@ -3,7 +3,6 @@ import { MouseoverTooltip } from 'components/Tooltip'
import { Box } from 'nft/components/Box'
import { Row } from 'nft/components/Flex'
import {
ChevronRightIcon,
MinusIconLarge,
PauseButtonIcon,
PlayButtonIcon,
@ -162,6 +161,8 @@ const Container = ({ asset, selected, addAssetToBag, removeAssetFromBag, childre
position={'relative'}
ref={assetRef}
borderRadius={'20'}
borderBottomLeftRadius={'12'}
borderBottomRightRadius={'12'}
className={selected ? styles.selectedCard : styles.notSelectedCard}
draggable={false}
onMouseEnter={() => toggleHovered()}
@ -195,6 +196,7 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
const [loaded, setLoaded] = useState(false)
const isMobile = useIsMobile()
if (noContent) {
return <NoContentContainer uniformHeight={uniformHeight} />
@ -221,7 +223,7 @@ const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
}
setLoaded(true)
}}
className={clsx(hovered && styles.cardImageHover, !loaded && styles.loadingBackground)}
className={clsx(hovered && !isMobile && styles.cardImageHover, !loaded && styles.loadingBackground)}
/>
</Box>
)
@ -275,7 +277,7 @@ const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
setImageLoaded(true)
}}
visibility={shouldPlay ? 'hidden' : 'visible'}
className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
className={clsx(hovered && !isMobile && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/>
</Box>
{shouldPlay ? (
@ -371,7 +373,7 @@ const Audio = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPla
}
setImageLoaded(true)
}}
className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
className={clsx(hovered && !isMobile && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/>
</Box>
{shouldPlay ? (
@ -569,7 +571,6 @@ const DetailsLink = () => {
}}
>
Details
<ChevronRightIcon width="20px" height="20px" />
</DetailsLinkContainer>
)
}

@ -41,6 +41,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'
import { useInfiniteQuery } from 'react-query'
import { useLocation } from 'react-router-dom'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import { CollectionAssetLoading } from './CollectionAssetLoading'
import { MARKETPLACE_ITEMS } from './MarketplaceSelect'
@ -59,9 +60,31 @@ const rarityIcon = <RarityIcon width="20" height="20" viewBox="2 2 24 24" color=
const ActionsContainer = styled.div`
display: flex;
gap: 10px;
width: 100%;
justify-content: space-between;
`
const ActionsSubContainer = styled.div`
display: flex;
gap: 12px;
flex: 1;
min-width: 0px;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
gap: 10px;
}
`
export const SortDropdownContainer = styled.div<{ isFiltersExpanded: boolean }>`
width: max-content;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.lg}px`}) {
${({ isFiltersExpanded }) => isFiltersExpanded && `display: none;`}
}
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
display: none;
}
`
const EmptyCollectionWrapper = styled.div`
display: block;
textalign: center;
@ -83,9 +106,9 @@ const SweepButton = styled.div<{ toggled: boolean; disabled?: boolean }>`
gap: 8px;
border: none;
border-radius: 12px;
padding: 10px 18px 10px 12px;
padding: 12px 18px 12px 12px;
cursor: ${({ disabled }) => (disabled ? 'auto' : 'pointer')};
color: ${({ toggled, disabled, theme }) => (toggled && !disabled ? theme.white : theme.textPrimary)};
color: ${({ toggled, disabled, theme }) => (toggled && !disabled ? theme.accentTextLightPrimary : theme.textPrimary)};
background: ${({ theme, toggled, disabled }) =>
!disabled && toggled
? 'radial-gradient(101.8% 4091.31% at 0% 0%, #4673FA 0%, #9646FA 100%)'
@ -99,6 +122,16 @@ const SweepButton = styled.div<{ toggled: boolean; disabled?: boolean }>`
},
}) => `${duration.fast} background-color ${timing.in}`};
}
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
padding: 12px 12px 12px 12px;
}
`
const SweepText = styled(ThemedText.BodyPrimary)`
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
display: none;
}
`
export const LoadingButton = styled.div`
@ -424,10 +457,15 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
return (
<>
<AnimatedBox position="sticky" top="72" width="full" zIndex="3" marginBottom="20">
<Box backgroundColor="backgroundBackdrop" width="full" padding="16">
<AnimatedBox position="sticky" top="72" width="full" zIndex="3" marginBottom={{ sm: '8', md: '20' }}>
<Box
backgroundColor="backgroundBackdrop"
width="full"
paddingTop={{ sm: '12', md: '16' }}
paddingBottom={{ sm: '12', md: '16' }}
>
<ActionsContainer>
<Row gap="12">
<ActionsSubContainer>
<TraceEvent
events={[Event.onClick]}
element={ElementName.NFT_FILTER_BUTTON}
@ -439,12 +477,13 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
isMobile={isMobile}
isFiltersExpanded={isFiltersExpanded}
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
collectionCount={collectionNfts?.[0]?.totalCount ?? 0}
/>
</TraceEvent>
<SortDropdown dropDownOptions={sortDropDownOptions} />
<SortDropdownContainer isFiltersExpanded={isFiltersExpanded}>
<SortDropdown dropDownOptions={sortDropDownOptions} />
</SortDropdownContainer>
<CollectionSearch />
</Row>
</ActionsSubContainer>
{!hasErc1155s ? (
isLoading ? (
<LoadingButton />
@ -463,7 +502,9 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
}}
>
<SweepIcon viewBox="0 0 24 24" width="20px" height="20px" />
Sweep
<SweepText fontWeight={600} color="currentColor" lineHeight="20px">
Sweep
</SweepText>
</SweepButton>
)
) : null}

@ -13,13 +13,15 @@ export const CollectionSearch = () => {
return (
<Box
as="input"
flex="1"
borderColor={{ default: 'backgroundOutline', focus: 'genieBlue' }}
borderWidth="1.5px"
borderStyle="solid"
borderRadius="12"
padding="12"
backgroundColor="backgroundSurface"
width="332"
maxWidth="332"
minWidth="0"
fontSize="16"
height="44"
color={{ placeholder: 'textTertiary', default: 'textPrimary' }}

@ -131,6 +131,7 @@ export const statsValue = style([
}),
{
lineHeight: '24px',
whiteSpace: 'nowrap',
},
])

@ -243,9 +243,9 @@ const CollectionDescription = ({ description }: { description: string }) => {
)
}
const StatsItem = ({ children, label, isMobile }: { children: ReactNode; label: string; isMobile: boolean }) => {
const StatsItem = ({ children, label, shouldHide }: { children: ReactNode; label: string; shouldHide: boolean }) => {
return (
<Box display="flex" flexDirection={'column'} alignItems="baseline" gap="2" height="min">
<Box display={shouldHide ? 'none' : 'flex'} flexDirection={'column'} alignItems="baseline" gap="2" height="min">
<span className={styles.statsValue}>{children}</span>
<Box as="span" className={styles.statsLabel}>
{label}
@ -295,34 +295,34 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
) : (
<>
{stats.stats?.floor_price ? (
<StatsItem label="Global floor" isMobile={isMobile ?? false}>
<StatsItem label="Global floor" shouldHide={false}>
{floorPriceStr} ETH
</StatsItem>
) : null}
{stats.stats?.one_day_floor_change ? (
<StatsItem label="24-Hour Floor" isMobile={isMobile ?? false}>
<StatsItem label="24-Hour Floor" shouldHide={false}>
<PercentChange>
{floorChangeStr}% {arrow}
</PercentChange>
</StatsItem>
) : null}
{totalSupplyStr ? (
<StatsItem label="Items" isMobile={isMobile ?? false}>
<StatsItem label="Items" shouldHide={isMobile ?? false}>
{totalSupplyStr}
</StatsItem>
) : null}
{uniqueOwnersPercentage ? (
<StatsItem label="Unique owners" isMobile={isMobile ?? false}>
<StatsItem label="Unique owners" shouldHide={isMobile ?? false}>
{uniqueOwnersPercentage}%
</StatsItem>
) : null}
{stats.stats?.total_volume ? (
<StatsItem label="Total Volume" isMobile={isMobile ?? false}>
<StatsItem label="Total Volume" shouldHide={false}>
{totalVolumeStr} ETH
</StatsItem>
) : null}
{stats.stats?.total_listings && listedPercentageStr > 0 ? (
<StatsItem label="Listed" isMobile={isMobile ?? false}>
<StatsItem label="Listed" shouldHide={isMobile ?? false}>
{listedPercentageStr}%
</StatsItem>
) : null}
@ -394,23 +394,15 @@ export const CollectionStats = ({ stats, isMobile }: { stats: GenieCollection; i
collectionSocialsIsOpen={collectionSocialsIsOpen}
toggleCollectionSocials={toggleCollectionSocials}
/>
{!isMobile && (
<>
{(stats.description || isCollectionStatsLoading) && (
<CollectionDescription description={stats.description ?? ''} />
)}
<StatsRow stats={stats} marginTop="20" />
</>
{(stats.description || isCollectionStatsLoading) && !isMobile && (
<CollectionDescription description={stats.description ?? ''} />
)}
<StatsRow display={{ sm: 'none', md: 'flex' }} stats={stats} marginTop="20" />
</Box>
{isMobile && (
<>
<Box marginBottom="12">{stats.description && <CollectionDescription description={stats.description} />}</Box>
<Marquee>
<StatsRow stats={stats} marginLeft="6" marginRight="6" marginBottom="28" isMobile />
</Marquee>
</>
{(stats.description || isCollectionStatsLoading) && isMobile && (
<CollectionDescription description={stats.description ?? ''} />
)}
<StatsRow isMobile display={{ sm: 'flex', md: 'none' }} stats={stats} marginTop="20" marginBottom="12" />
</Box>
)
}

@ -1,43 +1,21 @@
import clsx from 'clsx'
import { Box } from 'nft/components/Box'
import * as styles from 'nft/components/collection/FilterButton.css'
import { Row } from 'nft/components/Flex'
import { FilterIcon } from 'nft/components/icons'
import { buttonTextMedium } from 'nft/css/common.css'
import { useCollectionFilters, useIsCollectionLoading, useWalletCollections } from 'nft/hooks'
import { putCommas } from 'nft/utils/putCommas'
import { useLocation } from 'react-router-dom'
import { useIsCollectionLoading } from 'nft/hooks'
export const FilterButton = ({
onClick,
isMobile,
isFiltersExpanded,
results,
collectionCount = 0,
}: {
isMobile: boolean
isFiltersExpanded: boolean
results?: number
onClick: () => void
collectionCount?: number
}) => {
const { minPrice, maxPrice, minRarity, maxRarity, traits, markets, buyNow } = useCollectionFilters((state) => ({
minPrice: state.minPrice,
maxPrice: state.maxPrice,
minRarity: state.minRarity,
maxRarity: state.maxRarity,
traits: state.traits,
markets: state.markets,
buyNow: state.buyNow,
}))
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
const { pathname } = useLocation()
const isProfilePage = pathname.startsWith('/profile')
const isCollectionNftsLoading = useIsCollectionLoading((state) => state.isCollectionNftsLoading)
const showFilterBadge = isProfilePage
? collectionFilters.length > 0
: minPrice || maxPrice || minRarity || maxRarity || traits.length || markets.length || buyNow
return (
<Box
className={
@ -45,51 +23,21 @@ export const FilterButton = ({
? styles.filterButtonLoading
: clsx(styles.filterButton, !isFiltersExpanded && styles.filterButtonExpanded)
}
display="flex"
gap="8"
borderRadius="12"
fontSize="16"
cursor="pointer"
position="relative"
onClick={onClick}
paddingTop="12"
paddingLeft="12"
paddingBottom="12"
paddingRight={isMobile ? '8' : '12'}
padding="12"
width={isMobile ? '44' : 'auto'}
height="44"
whiteSpace="nowrap"
color="textPrimary"
>
{!isCollectionNftsLoading && (
<>
{showFilterBadge && (
<Row className={styles.filterBadge} color={isFiltersExpanded ? 'grey700' : 'blue400'}>
</Row>
)}
<FilterIcon
style={{
marginBottom: '-4px',
color: 'textPrimary',
paddingRight: `${!isFiltersExpanded || showFilterBadge ? '6px' : '0px'}`,
}}
/>
</>
)}
<span className={buttonTextMedium}> {!isMobile && !isFiltersExpanded && 'Filter'}</span>
{showFilterBadge && !isMobile ? (
<Box display="inline-block" position="relative">
{!isFiltersExpanded && (
<Box as="span" position="absolute" left="4" style={{ top: '5px', fontSize: '8px' }}>
</Box>
)}
<Box className={buttonTextMedium} paddingLeft={!isFiltersExpanded ? '12' : '2'}>
{collectionCount > 0 ? putCommas(collectionCount) : 0} results
</Box>
</Box>
) : null}
<FilterIcon />
{!isMobile && !isFiltersExpanded && <Box className={buttonTextMedium}> Filter</Box>}
</Box>
)
}

@ -193,7 +193,6 @@ export const ProfilePage = () => {
<FilterButton
isMobile={isMobile}
isFiltersExpanded={isFiltersExpanded}
results={displayAssets.length}
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
/>
<Row gap="8" flexWrap="nowrap">