style: updating bag (#5539)
* style: updating bag * desktop bag * initial setup * bag animations * mobile stylings * removing vanilla extract components * background position * design comments * screen sizing * closing filters and bag on appropriate screen sizes * move screen size to main hooks * prettier * bag margins * footer outline * correct scrolling indicator width * collection stats truncation * merged with main * collection stats on screen
This commit is contained in:
parent
0622ff30f6
commit
77747f9f6f
@ -3,7 +3,7 @@ import { breakpoints, sprinkles } from 'nft/css/sprinkles.css'
|
||||
|
||||
export const assetsContainer = style([
|
||||
sprinkles({
|
||||
paddingX: '16',
|
||||
paddingX: '20',
|
||||
maxHeight: 'full',
|
||||
overflowY: 'scroll',
|
||||
}),
|
||||
|
@ -30,6 +30,7 @@ import { combineBuyItemsWithTxRoute } from 'nft/utils/txRoute/combineItemsWithTx
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useQuery, useQueryClient } from 'react-query'
|
||||
import styled from 'styled-components/macro'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import * as styles from './Bag.css'
|
||||
@ -38,22 +39,53 @@ import { BagHeader } from './BagHeader'
|
||||
import EmptyState from './EmptyContent'
|
||||
import { ProfileBagContent } from './profile/ProfileBagContent'
|
||||
|
||||
export const BAG_WIDTH = 320
|
||||
export const XXXL_BAG_WIDTH = 360
|
||||
|
||||
interface SeparatorProps {
|
||||
top?: boolean
|
||||
show?: boolean
|
||||
}
|
||||
|
||||
const BagContainer = styled.div<{ raiseZIndex: boolean }>`
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 88px;
|
||||
right: 20px;
|
||||
width: ${BAG_WIDTH}px;
|
||||
height: calc(100vh - 108px);
|
||||
background: ${({ theme }) => theme.backgroundSurface};
|
||||
border: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
border-radius: 16px;
|
||||
box-shadow: ${({ theme }) => theme.shallowShadow};
|
||||
z-index: ${({ raiseZIndex }) => (raiseZIndex ? Z_INDEX.modalOverTooltip : 3)};
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: ${({ theme }) => `${theme.breakpoint.xxxl}px`}) {
|
||||
width: ${XXXL_BAG_WIDTH}px;
|
||||
}
|
||||
`
|
||||
|
||||
const DetailsPageBackground = styled.div`
|
||||
position: fixed;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
top: 72px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`
|
||||
|
||||
const ScrollingIndicator = ({ top, show }: SeparatorProps) => (
|
||||
<Box
|
||||
marginX="16"
|
||||
marginX="24"
|
||||
borderWidth="1px"
|
||||
borderStyle="solid"
|
||||
borderColor="transparent"
|
||||
@ -112,7 +144,7 @@ const Bag = () => {
|
||||
|
||||
const itemsInBag = useMemo(() => recalculateBagUsingPooledAssets(uncheckedItemsInBag), [uncheckedItemsInBag])
|
||||
|
||||
const [isOpen, setModalIsOpen] = useState(false)
|
||||
const [isModalOpen, setModalIsOpen] = useState(false)
|
||||
const [userCanScroll, setUserCanScroll] = useState(false)
|
||||
const [scrollProgress, setScrollProgress] = useState(0)
|
||||
const scrollRef = (node: HTMLDivElement) => {
|
||||
@ -229,8 +261,8 @@ const Bag = () => {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (bagIsLocked && !isOpen) setModalIsOpen(true)
|
||||
}, [bagIsLocked, isOpen])
|
||||
if (bagIsLocked && !isModalOpen) setModalIsOpen(true)
|
||||
}, [bagIsLocked, isModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (transactionStateRef.current === TxStateType.Confirming) setBagStatus(BagStatus.PROCESSING_TRANSACTION)
|
||||
@ -281,60 +313,57 @@ const Bag = () => {
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
{!(isProfilePage && profilePageState === ProfilePageStateType.LISTING) ? (
|
||||
<Column
|
||||
data-testid="nft-bag"
|
||||
zIndex={isMobile || isOpen ? 'modalOverTooltip' : '3'}
|
||||
className={styles.bagContainer}
|
||||
>
|
||||
<BagHeader
|
||||
numberOfAssets={isProfilePage ? sellAssets.length : itemsInBag.length}
|
||||
closeBag={handleCloseBag}
|
||||
resetFlow={isProfilePage ? resetSellAssets : reset}
|
||||
isProfilePage={isProfilePage}
|
||||
/>
|
||||
{shouldRenderEmptyState && <EmptyState />}
|
||||
<ScrollingIndicator top show={userCanScroll && scrollProgress > 0} />
|
||||
<Column ref={scrollRef} className={styles.assetsContainer} onScroll={scrollHandler} gap="12">
|
||||
{isProfilePage ? <ProfileBagContent /> : <BagContent />}
|
||||
</Column>
|
||||
{hasAssetsToShow && !isProfilePage && (
|
||||
<BagFooter
|
||||
totalEthPrice={totalEthPrice}
|
||||
totalUsdPrice={totalUsdPrice}
|
||||
bagStatus={bagStatus}
|
||||
fetchAssets={fetchAssets}
|
||||
eventProperties={eventProperties}
|
||||
<BagContainer data-testid="nft-bag" raiseZIndex={isMobile || isModalOpen}>
|
||||
{!(isProfilePage && profilePageState === ProfilePageStateType.LISTING) ? (
|
||||
<>
|
||||
<BagHeader
|
||||
numberOfAssets={isProfilePage ? sellAssets.length : itemsInBag.length}
|
||||
closeBag={handleCloseBag}
|
||||
resetFlow={isProfilePage ? resetSellAssets : reset}
|
||||
isProfilePage={isProfilePage}
|
||||
/>
|
||||
)}
|
||||
{isSellingAssets && isProfilePage && (
|
||||
<Box
|
||||
marginTop="32"
|
||||
marginX="28"
|
||||
paddingY="10"
|
||||
className={`${buttonTextMedium} ${commonButtonStyles}`}
|
||||
backgroundColor="accentAction"
|
||||
color="white"
|
||||
textAlign="center"
|
||||
onClick={() => {
|
||||
isMobile && toggleBag()
|
||||
setProfilePageState(ProfilePageStateType.LISTING)
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
</Box>
|
||||
)}
|
||||
</Column>
|
||||
) : (
|
||||
<Column zIndex={isMobile || isOpen ? 'modalOverTooltip' : '3'} className={styles.bagContainer}>
|
||||
{shouldRenderEmptyState && <EmptyState />}
|
||||
<ScrollingIndicator top show={userCanScroll && scrollProgress > 0} />
|
||||
<Column ref={scrollRef} className={styles.assetsContainer} onScroll={scrollHandler} gap="12">
|
||||
{isProfilePage ? <ProfileBagContent /> : <BagContent />}
|
||||
</Column>
|
||||
{hasAssetsToShow && !isProfilePage && (
|
||||
<BagFooter
|
||||
totalEthPrice={totalEthPrice}
|
||||
totalUsdPrice={totalUsdPrice}
|
||||
bagStatus={bagStatus}
|
||||
fetchAssets={fetchAssets}
|
||||
eventProperties={eventProperties}
|
||||
/>
|
||||
)}
|
||||
{isSellingAssets && isProfilePage && (
|
||||
<Box
|
||||
marginTop="32"
|
||||
marginX="28"
|
||||
marginBottom="16"
|
||||
paddingY="10"
|
||||
className={`${buttonTextMedium} ${commonButtonStyles}`}
|
||||
backgroundColor="accentAction"
|
||||
color="white"
|
||||
textAlign="center"
|
||||
onClick={() => {
|
||||
isMobile && toggleBag()
|
||||
setProfilePageState(ProfilePageStateType.LISTING)
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<ListingModal />
|
||||
</Column>
|
||||
)}
|
||||
)}
|
||||
</BagContainer>
|
||||
|
||||
{isDetailsPage ? (
|
||||
<DetailsPageBackground onClick={toggleBag} />
|
||||
) : (
|
||||
isOpen && <Overlay onClick={() => (!bagIsLocked ? setModalIsOpen(false) : undefined)} />
|
||||
isModalOpen && <Overlay onClick={() => (!bagIsLocked ? setModalIsOpen(false) : undefined)} />
|
||||
)}
|
||||
</Portal>
|
||||
)
|
||||
|
@ -96,7 +96,7 @@ export const BagContent = () => {
|
||||
/>
|
||||
))}
|
||||
</Column>
|
||||
<Column gap="8">
|
||||
<Column>
|
||||
{unchangedAssets
|
||||
.slice(0)
|
||||
.reverse()
|
||||
|
@ -2,10 +2,6 @@ import { style } from '@vanilla-extract/css'
|
||||
import { body } from 'nft/css/common.css'
|
||||
import { sprinkles } from 'nft/css/sprinkles.css'
|
||||
|
||||
export const footerContainer = sprinkles({
|
||||
paddingX: '16',
|
||||
})
|
||||
|
||||
export const footer = style([
|
||||
sprinkles({
|
||||
background: 'backgroundModule',
|
||||
|
@ -22,13 +22,17 @@ import { switchChain } from 'utils/switchChain'
|
||||
|
||||
import * as styles from './BagFooter.css'
|
||||
|
||||
const FooterContainer = styled.div`
|
||||
padding: 0px 12px;
|
||||
`
|
||||
|
||||
const Footer = styled.div`
|
||||
border-top: 1px solid ${({ theme }) => theme.backgroundOutline};
|
||||
color: ${({ theme }) => theme.textPrimary};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 8px;
|
||||
padding: 12px 16px;
|
||||
margin: 0px 16px 8px;
|
||||
padding: 12px 0px;
|
||||
border-bottom-left-radius: 12px;
|
||||
border-bottom-right-radius: 12px;
|
||||
`
|
||||
@ -149,9 +153,9 @@ export const BagFooter = ({
|
||||
const isPending = PENDING_BAG_STATUSES.includes(bagStatus)
|
||||
|
||||
return (
|
||||
<Column className={styles.footerContainer}>
|
||||
<FooterContainer>
|
||||
<Footer>
|
||||
<Column gap="4" paddingTop="8" paddingBottom="20">
|
||||
<Column gap="4" paddingTop="8" paddingBottom={warningText ? '8' : '20'}>
|
||||
<Row justifyContent="space-between">
|
||||
<Box>
|
||||
<ThemedText.HeadlineSmall>Total</ThemedText.HeadlineSmall>
|
||||
@ -180,6 +184,6 @@ export const BagFooter = ({
|
||||
</ActionButton>
|
||||
</TraceEvent>
|
||||
</Footer>
|
||||
</Column>
|
||||
</FooterContainer>
|
||||
)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ const Wrapper = styled.div`
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
justify-content: flex-start;
|
||||
margin: 16px 20px;
|
||||
margin: 16px 28px;
|
||||
text-align: center;
|
||||
`
|
||||
interface BagHeaderProps {
|
||||
@ -82,7 +82,9 @@ export const BagHeader = ({ numberOfAssets, closeBag, resetFlow, isProfilePage }
|
||||
{numberOfAssets > 0 && (
|
||||
<>
|
||||
<CounterDot sizing={sizing}>{numberOfAssets}</CounterDot>
|
||||
<ClearButton onClick={resetFlow}>Clear all</ClearButton>
|
||||
<ClearButton onClick={resetFlow}>
|
||||
<Trans>Clear all</Trans>
|
||||
</ClearButton>
|
||||
</>
|
||||
)}
|
||||
<IconWrapper onClick={closeBag}>
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
useLoadSweepAssetsQuery,
|
||||
} from 'graphql/data/nft/Asset'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import { useScreenSize } from 'hooks/useScreenSize'
|
||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||
import { CollectionSearch, FilterButton } from 'nft/components/collection'
|
||||
import { CollectionAsset } from 'nft/components/collection/CollectionAsset'
|
||||
@ -378,6 +379,7 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
||||
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
||||
const oldStateRef = useRef<CollectionFilters | null>(null)
|
||||
const isMobile = useIsMobile()
|
||||
const screenSize = useScreenSize()
|
||||
|
||||
useEffect(() => {
|
||||
setIsCollectionNftsLoading(isLoadingNext)
|
||||
@ -514,7 +516,10 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
||||
isMobile={isMobile}
|
||||
isFiltersExpanded={isFiltersExpanded}
|
||||
collectionCount={collectionAssets?.[0]?.totalCount ?? 0}
|
||||
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
|
||||
onClick={() => {
|
||||
if (bagExpanded && !screenSize['xl']) toggleBag()
|
||||
setFiltersExpanded(!isFiltersExpanded)
|
||||
}}
|
||||
/>
|
||||
</TraceEvent>
|
||||
<SortDropdownContainer isFiltersExpanded={isFiltersExpanded}>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Column from 'components/Column'
|
||||
import Row from 'components/Row'
|
||||
import { useIsMobile } from 'nft/hooks'
|
||||
import { BAG_WIDTH, XXXL_BAG_WIDTH } from 'nft/components/bag/Bag'
|
||||
import { useBag, useIsMobile } from 'nft/hooks'
|
||||
import { BannerWrapper, CollectionBannerLoading } from 'nft/pages/collection'
|
||||
import { ScreenBreakpointsPaddings } from 'nft/pages/collection/index.css'
|
||||
import styled from 'styled-components/macro'
|
||||
@ -13,8 +14,13 @@ const CollectionDescriptionSection = styled(Column)`
|
||||
${ScreenBreakpointsPaddings}
|
||||
`
|
||||
|
||||
const StyledColumn = styled(Column)`
|
||||
width: 100%;
|
||||
const StyledColumn = styled(Column)<{ isBagExpanded: boolean }>`
|
||||
width: ${({ isBagExpanded }) => (isBagExpanded ? `calc(100% - ${BAG_WIDTH + 16}px)` : '100%')};
|
||||
align-self: start;
|
||||
|
||||
@media only screen and (min-width: ${({ theme }) => `${theme.breakpoint.xxxl}px`}) {
|
||||
width: ${({ isBagExpanded }) => (isBagExpanded ? `calc(100% - ${XXXL_BAG_WIDTH + 16}px)` : '100%')};
|
||||
}
|
||||
`
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
@ -23,10 +29,12 @@ const StyledRow = styled(Row)`
|
||||
`
|
||||
|
||||
export const CollectionPageSkeleton = () => {
|
||||
const isBagExpanded = useBag((s) => s.bagExpanded)
|
||||
const isMobile = useIsMobile()
|
||||
|
||||
return (
|
||||
<StyledColumn>
|
||||
<BannerWrapper width="full">
|
||||
<StyledColumn isBagExpanded={isBagExpanded}>
|
||||
<BannerWrapper>
|
||||
<CollectionBannerLoading />
|
||||
</BannerWrapper>
|
||||
<CollectionDescriptionSection>
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { getDeltaArrow } from 'components/Tokens/TokenDetails/PriceChart'
|
||||
import { useScreenSize } from 'hooks/useScreenSize'
|
||||
import { Box, BoxProps } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { body, bodySmall, headlineMedium, headlineSmall } from 'nft/css/common.css'
|
||||
import { loadingAsset } from 'nft/css/loading.css'
|
||||
import { themeVars } from 'nft/css/sprinkles.css'
|
||||
import { useIsMobile } from 'nft/hooks'
|
||||
import { useBag, useIsMobile } from 'nft/hooks'
|
||||
import { useIsCollectionLoading } from 'nft/hooks/useIsCollectionLoading'
|
||||
import { GenieCollection, TokenType } from 'nft/types'
|
||||
import { floorFormatter, quantityFormatter, roundWholePercentage, volumeFormatter } from 'nft/utils/numbers'
|
||||
@ -353,6 +354,10 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
|
||||
const floorChangeStr = Math.round(Math.abs(stats?.stats?.one_day_floor_change ?? 0))
|
||||
const arrow = stats?.stats?.one_day_floor_change ? getDeltaArrow(stats.stats.one_day_floor_change) : undefined
|
||||
|
||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||
const isScreenSize = useScreenSize()
|
||||
const isSmallContainer = isMobile || (!isScreenSize['lg'] && isBagExpanded)
|
||||
|
||||
return (
|
||||
<Row gap={{ sm: '24', md: '36', lg: '48', xl: '60' }} {...props}>
|
||||
{isCollectionStatsLoading ? (
|
||||
@ -383,13 +388,13 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
|
||||
</StatsItem>
|
||||
) : null}
|
||||
{Boolean(uniqueOwnersPercentage && stats.standard !== TokenType.ERC1155) ? (
|
||||
<StatsItem label="Unique owners" shouldHide={isMobile ?? false}>
|
||||
<StatsItem label="Unique owners" shouldHide={isSmallContainer ?? false}>
|
||||
{uniqueOwnersPercentage}%
|
||||
</StatsItem>
|
||||
) : null}
|
||||
|
||||
{stats.stats?.total_listings && stats.standard !== TokenType.ERC1155 ? (
|
||||
<StatsItem label="Listed" shouldHide={isMobile ?? false}>
|
||||
<StatsItem label="Listed" shouldHide={isSmallContainer ?? false}>
|
||||
{listedPercentageStr}%
|
||||
</StatsItem>
|
||||
) : null}
|
||||
@ -463,7 +468,7 @@ export const CollectionStats = ({ stats, isMobile }: { stats: GenieCollection; i
|
||||
{(stats.description || isCollectionStatsLoading) && !isMobile && (
|
||||
<CollectionDescription description={stats.description ?? ''} />
|
||||
)}
|
||||
<StatsRow display={{ sm: 'none', md: 'flex' }} stats={stats} marginTop="20" />
|
||||
<StatsRow display={{ sm: 'none', md: 'flex' }} overflow="hidden" stats={stats} marginTop="20" />
|
||||
</Box>
|
||||
{(stats.description || isCollectionStatsLoading) && isMobile && (
|
||||
<CollectionDescription description={stats.description ?? ''} />
|
||||
|
@ -6,8 +6,6 @@ import { css } from 'styled-components/macro'
|
||||
|
||||
import { sprinkles } from '../../css/sprinkles.css'
|
||||
|
||||
export const bannerImage = style({ objectFit: 'cover' })
|
||||
|
||||
export const baseActivitySwitcherToggle = style([
|
||||
buttonTextMedium,
|
||||
sprinkles({
|
||||
|
@ -1,42 +1,99 @@
|
||||
import { Trace } from '@uniswap/analytics'
|
||||
import { PageName } from '@uniswap/analytics-events'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import Column from 'components/Column'
|
||||
import { OpacityHoverState } from 'components/Common'
|
||||
import Row from 'components/Row'
|
||||
import { LoadingBubble } from 'components/Tokens/loading'
|
||||
import { useLoadAssetsQuery } from 'graphql/data/nft/Asset'
|
||||
import { useCollectionQuery, useLoadCollectionQuery } from 'graphql/data/nft/Collection'
|
||||
import { useScreenSize } from 'hooks/useScreenSize'
|
||||
import { BAG_WIDTH, XXXL_BAG_WIDTH } from 'nft/components/bag/Bag'
|
||||
import { MobileHoverBag } from 'nft/components/bag/MobileHoverBag'
|
||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||
import { Activity, ActivitySwitcher, CollectionNfts, CollectionStats, Filters } from 'nft/components/collection'
|
||||
import { CollectionNftsAndMenuLoading } from 'nft/components/collection/CollectionNfts'
|
||||
import { CollectionPageSkeleton } from 'nft/components/collection/CollectionPageSkeleton'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { BagCloseIcon } from 'nft/components/icons'
|
||||
import { useBag, useCollectionFilters, useFiltersExpanded, useIsMobile } from 'nft/hooks'
|
||||
import * as styles from 'nft/pages/collection/index.css'
|
||||
import { GenieCollection } from 'nft/types'
|
||||
import { Suspense, useEffect } from 'react'
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||
import { easings, useSpring } from 'react-spring'
|
||||
import { animated, easings, useSpring } from 'react-spring'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
import { TRANSITION_DURATIONS } from 'theme/styles'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
|
||||
const FILTER_WIDTH = 332
|
||||
const BAG_WIDTH = 324
|
||||
|
||||
export const BannerWrapper = styled(Box)`
|
||||
height: 100px;
|
||||
export const CollectionBannerLoading = styled(LoadingBubble)`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0px;
|
||||
|
||||
@media screen and (min-width: ${({ theme }) => theme.breakpoint.sm}px) {
|
||||
border-radius: 16px;
|
||||
}
|
||||
`
|
||||
|
||||
const CollectionContainer = styled(Column)`
|
||||
width: 100%;
|
||||
align-self: start;
|
||||
will-change: width;
|
||||
`
|
||||
|
||||
const AnimatedCollectionContainer = animated(CollectionContainer)
|
||||
|
||||
const CollectionAssetsContainer = styled.div<{ hideUnderneath: boolean }>`
|
||||
position: ${({ hideUnderneath }) => (hideUnderneath ? 'fixed' : 'static')};
|
||||
`
|
||||
|
||||
const AnimatedCollectionAssetsContainer = animated(CollectionAssetsContainer)
|
||||
|
||||
export const BannerWrapper = styled.div`
|
||||
height: 100px;
|
||||
max-width: 100%;
|
||||
|
||||
@media screen and (min-width: ${({ theme }) => theme.breakpoint.sm}px) {
|
||||
margin-top: 16px;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
height: 288px;
|
||||
}
|
||||
`
|
||||
|
||||
export const CollectionBannerLoading = () => <Box height="full" width="full" className={styles.loadingBanner} />
|
||||
const Banner = styled.div<{ src: string }>`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-image: url(${({ src }) => src});
|
||||
background-position-y: center;
|
||||
background-size: cover;
|
||||
|
||||
@media screen and (min-width: ${({ theme }) => theme.breakpoint.sm}px) {
|
||||
border-radius: 16px;
|
||||
}
|
||||
`
|
||||
|
||||
const CollectionDescriptionSection = styled(Column)`
|
||||
${styles.ScreenBreakpointsPaddings}
|
||||
`
|
||||
|
||||
const FiltersContainer = styled.div<{ isMobile: boolean; isFiltersExpanded: boolean }>`
|
||||
position: ${({ isMobile }) => (isMobile ? 'fixed' : 'sticky')};
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: ${({ isMobile }) => (isMobile ? '100%' : '0px')};
|
||||
height: ${({ isMobile, isFiltersExpanded }) => (isMobile && isFiltersExpanded ? '100%' : undefined)};
|
||||
background: ${({ theme, isMobile }) => (isMobile ? theme.backgroundBackdrop : undefined)};
|
||||
z-index: ${Z_INDEX.modalBackdrop};
|
||||
overflow-y: ${({ isMobile }) => (isMobile ? 'scroll' : undefined)};
|
||||
|
||||
@media screen and (min-width: ${({ theme }) => theme.breakpoint.sm}px) {
|
||||
top: 72px;
|
||||
}
|
||||
`
|
||||
|
||||
const MobileFilterHeader = styled(Row)`
|
||||
padding: 20px 16px;
|
||||
justify-content: space-between;
|
||||
@ -74,19 +131,21 @@ const Collection = () => {
|
||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||
const setBagExpanded = useBag((state) => state.setBagExpanded)
|
||||
const { chainId } = useWeb3React()
|
||||
const screenSize = useScreenSize()
|
||||
|
||||
const collectionStats = useCollectionQuery(contractAddress as string)
|
||||
|
||||
const { gridX, gridWidthOffset } = useSpring({
|
||||
gridX: isFiltersExpanded && !isMobile ? FILTER_WIDTH : 0,
|
||||
gridWidthOffset:
|
||||
isFiltersExpanded && !isMobile
|
||||
? isBagExpanded
|
||||
? BAG_WIDTH + FILTER_WIDTH
|
||||
: FILTER_WIDTH
|
||||
: isBagExpanded && !isMobile
|
||||
? BAG_WIDTH
|
||||
: 0,
|
||||
const { CollectionContainerWidthChange } = useSpring({
|
||||
CollectionContainerWidthChange:
|
||||
isBagExpanded && !isMobile ? (screenSize['xxxl'] ? XXXL_BAG_WIDTH : BAG_WIDTH) + 16 : 0,
|
||||
config: {
|
||||
duration: TRANSITION_DURATIONS.medium,
|
||||
easing: easings.easeOutSine,
|
||||
},
|
||||
})
|
||||
|
||||
const { gridWidthOffset } = useSpring({
|
||||
gridWidthOffset: isFiltersExpanded && !isMobile ? FILTER_WIDTH : 0,
|
||||
config: {
|
||||
duration: TRANSITION_DURATIONS.medium,
|
||||
easing: easings.easeOutSine,
|
||||
@ -101,6 +160,10 @@ const Collection = () => {
|
||||
setMarketCount(marketCount)
|
||||
}, [collectionStats?.marketplaceCount, setMarketCount])
|
||||
|
||||
useEffect(() => {
|
||||
if (isBagExpanded && isFiltersExpanded && !screenSize['xl']) setFiltersExpanded(false)
|
||||
}, [isBagExpanded, isFiltersExpanded, screenSize, setFiltersExpanded])
|
||||
|
||||
useEffect(() => {
|
||||
setBagExpanded({ bagExpanded: false, manualClose: false })
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -119,21 +182,18 @@ const Collection = () => {
|
||||
properties={{ collection_address: contractAddress, chain_id: chainId, is_activity_view: isActivityToggled }}
|
||||
shouldLogImpression
|
||||
>
|
||||
<Column width="full">
|
||||
<AnimatedCollectionContainer
|
||||
style={{
|
||||
width: CollectionContainerWidthChange.to((x) => `calc(100% - ${x as number}px)`),
|
||||
}}
|
||||
>
|
||||
{contractAddress ? (
|
||||
<>
|
||||
<BannerWrapper width="full">
|
||||
<Box
|
||||
as={collectionStats?.bannerImageUrl ? 'img' : 'div'}
|
||||
height="full"
|
||||
width="full"
|
||||
<BannerWrapper>
|
||||
<Banner
|
||||
src={
|
||||
collectionStats?.bannerImageUrl
|
||||
? `${collectionStats.bannerImageUrl}?w=${window.innerWidth}`
|
||||
: undefined
|
||||
collectionStats?.bannerImageUrl ? `${collectionStats.bannerImageUrl}?w=${window.innerWidth}` : ''
|
||||
}
|
||||
className={styles.bannerImage}
|
||||
background="none"
|
||||
/>
|
||||
</BannerWrapper>
|
||||
<CollectionDescriptionSection>
|
||||
@ -150,16 +210,7 @@ const Collection = () => {
|
||||
/>
|
||||
</CollectionDescriptionSection>
|
||||
<CollectionDisplaySection>
|
||||
<Box
|
||||
position={isMobile ? 'fixed' : 'sticky'}
|
||||
top={{ sm: '0', md: '72' }}
|
||||
left="0"
|
||||
width={isMobile ? 'full' : '0'}
|
||||
height={isMobile && isFiltersExpanded ? 'full' : undefined}
|
||||
background={isMobile ? 'backgroundBackdrop' : undefined}
|
||||
zIndex="modalBackdrop"
|
||||
overflowY={isMobile ? 'scroll' : undefined}
|
||||
>
|
||||
<FiltersContainer isMobile={isMobile} isFiltersExpanded={isFiltersExpanded}>
|
||||
{isFiltersExpanded && (
|
||||
<>
|
||||
{isMobile && (
|
||||
@ -173,13 +224,12 @@ const Collection = () => {
|
||||
<Filters traitsByGroup={collectionStats?.traits ?? {}} />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</FiltersContainer>
|
||||
|
||||
{/* @ts-ignore: https://github.com/microsoft/TypeScript/issues/34933 */}
|
||||
<AnimatedBox
|
||||
position={isMobile && (isFiltersExpanded || isBagExpanded) ? 'fixed' : 'static'}
|
||||
<AnimatedCollectionAssetsContainer
|
||||
hideUnderneath={isMobile && (isFiltersExpanded || isBagExpanded)}
|
||||
style={{
|
||||
transform: gridX.to((x) => `translate(${x as number}px)`),
|
||||
transform: gridWidthOffset.to((x) => `translate(${x as number}px)`),
|
||||
width: gridWidthOffset.to((x) => `calc(100% - ${x as number}px)`),
|
||||
}}
|
||||
>
|
||||
@ -202,14 +252,13 @@ const Collection = () => {
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</AnimatedBox>
|
||||
</AnimatedCollectionAssetsContainer>
|
||||
</CollectionDisplaySection>
|
||||
</>
|
||||
) : (
|
||||
// TODO: Put no collection asset page here
|
||||
<div className={styles.noCollectionAssets}>No collection assets exist at this address</div>
|
||||
)}
|
||||
</Column>
|
||||
</AnimatedCollectionContainer>
|
||||
</Trace>
|
||||
<MobileHoverBag />
|
||||
</>
|
||||
|
@ -10,7 +10,6 @@ import { Box } from 'nft/components/Box'
|
||||
import { CollectionPageSkeleton } from 'nft/components/collection/CollectionPageSkeleton'
|
||||
import { AssetDetailsLoading } from 'nft/components/details/AssetDetailsLoading'
|
||||
import { ProfilePageLoadingSkeleton } from 'nft/components/profile/view/ProfilePageLoadingSkeleton'
|
||||
import { useBag } from 'nft/hooks'
|
||||
import { lazy, Suspense, useEffect, useState } from 'react'
|
||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom'
|
||||
import { useIsDarkMode } from 'state/user/hooks'
|
||||
@ -201,9 +200,7 @@ export default function App() {
|
||||
return () => window.removeEventListener('scroll', scrollListener)
|
||||
}, [])
|
||||
|
||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||
|
||||
const isHeaderTransparent = !scrolledState && !isBagExpanded
|
||||
const isHeaderTransparent = !scrolledState
|
||||
|
||||
const landingPageFlag = useLandingPageFlag()
|
||||
|
||||
|
@ -11,4 +11,5 @@ export enum Z_INDEX {
|
||||
modal = 1060,
|
||||
popover = 1070,
|
||||
tooltip = 1080,
|
||||
modalOverTooltip = 1090,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user