feat: Add Select Page Modal (#4643)
* add select nfts shopping bag modal * Add shopping bag to top lovel modal wrapper * addressing comments * rename to listingTag Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
This commit is contained in:
parent
49c5cbbf3b
commit
8c947a0e0d
@ -2,9 +2,12 @@ import { useWeb3React } from '@web3-react/core'
|
|||||||
import AddressClaimModal from 'components/claim/AddressClaimModal'
|
import AddressClaimModal from 'components/claim/AddressClaimModal'
|
||||||
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
|
||||||
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
|
||||||
|
import { lazy } from 'react'
|
||||||
import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
|
import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
|
||||||
import { ApplicationModal } from 'state/application/reducer'
|
import { ApplicationModal } from 'state/application/reducer'
|
||||||
|
|
||||||
|
const Cart = lazy(() => import('nft/components/sell/modal/ListingTag'))
|
||||||
|
|
||||||
export default function TopLevelModals() {
|
export default function TopLevelModals() {
|
||||||
const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM)
|
const addressClaimOpen = useModalIsOpen(ApplicationModal.ADDRESS_CLAIM)
|
||||||
const addressClaimToggle = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
|
const addressClaimToggle = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
|
||||||
@ -18,6 +21,7 @@ export default function TopLevelModals() {
|
|||||||
<>
|
<>
|
||||||
<AddressClaimModal isOpen={addressClaimOpen} onDismiss={addressClaimToggle} />
|
<AddressClaimModal isOpen={addressClaimOpen} onDismiss={addressClaimToggle} />
|
||||||
<ConnectedAccountBlocked account={account} isOpen={open} />
|
<ConnectedAccountBlocked account={account} isOpen={open} />
|
||||||
|
<Cart />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
52
src/nft/components/sell/modal/ListingTag.css.ts
Normal file
52
src/nft/components/sell/modal/ListingTag.css.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { style } from '@vanilla-extract/css'
|
||||||
|
import { breakpoints, sprinkles } from 'nft/css/sprinkles.css'
|
||||||
|
|
||||||
|
export const tagContainer = style([
|
||||||
|
sprinkles({
|
||||||
|
borderRadius: '20',
|
||||||
|
borderWidth: '1px',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderColor: 'medGray',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'@media': {
|
||||||
|
[`screen and (max-width: ${breakpoints.md}px)`]: {
|
||||||
|
borderRadius: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const tagAssets = style([
|
||||||
|
sprinkles({
|
||||||
|
maxHeight: 'inherit',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'@media': {
|
||||||
|
[`screen and (min-width: ${breakpoints.md}px)`]: {
|
||||||
|
maxHeight: '55vh',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'::-webkit-scrollbar': { display: 'none' },
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const closeIcon = style({
|
||||||
|
transform: 'rotate(90deg)',
|
||||||
|
float: 'right',
|
||||||
|
paddingTop: '1px',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const orderButton = style([
|
||||||
|
sprinkles({
|
||||||
|
width: 'full',
|
||||||
|
paddingY: '12',
|
||||||
|
paddingX: '0',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
':hover': {
|
||||||
|
boxShadow: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
120
src/nft/components/sell/modal/ListingTag.tsx
Normal file
120
src/nft/components/sell/modal/ListingTag.tsx
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import Loader from 'components/Loader'
|
||||||
|
import { Box } from 'nft/components/Box'
|
||||||
|
import { Column } from 'nft/components/Flex'
|
||||||
|
import { CloseDropDownIcon } from 'nft/components/icons'
|
||||||
|
import { bodySmall, buttonMedium, headlineSmall } from 'nft/css/common.css'
|
||||||
|
import { useBag, useIsMobile, useSellAsset, useSellPageState } from 'nft/hooks'
|
||||||
|
import { SellPageStateType } from 'nft/types'
|
||||||
|
import { lazy, Suspense } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
|
import * as styles from './ListingTag.css'
|
||||||
|
|
||||||
|
const CartSellAssetRow = lazy(() => import('./TagAssetRow'))
|
||||||
|
|
||||||
|
const Cart = () => {
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const isNFTSellPage = pathname.startsWith('/nfts/sell')
|
||||||
|
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||||
|
const setSellPageState = useSellPageState((state) => state.setSellPageState)
|
||||||
|
const sellPageState = useSellPageState((state) => state.state)
|
||||||
|
const toggleCart = useBag((state) => state.toggleBag)
|
||||||
|
const isMobile = useIsMobile()
|
||||||
|
const bagExpanded = useBag((s) => s.bagExpanded)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
zIndex={{ sm: '3', md: '2' }}
|
||||||
|
width={{ sm: 'full', md: 'auto' }}
|
||||||
|
height={{ sm: 'full', md: 'auto' }}
|
||||||
|
position="fixed"
|
||||||
|
left={{ sm: '0', md: 'unset' }}
|
||||||
|
right={{ sm: 'unset', md: '0' }}
|
||||||
|
top={{ sm: '0', md: 'unset' }}
|
||||||
|
display={bagExpanded && isNFTSellPage ? 'flex' : 'none'}
|
||||||
|
>
|
||||||
|
<Suspense fallback={<Loader />}>
|
||||||
|
<Column
|
||||||
|
marginTop={{ sm: '0', md: '4' }}
|
||||||
|
marginRight={{ sm: '0', md: '20' }}
|
||||||
|
className={styles.tagContainer}
|
||||||
|
width={{ sm: 'full', md: '288' }}
|
||||||
|
height={{ sm: 'full', md: 'auto' }}
|
||||||
|
backgroundColor="white"
|
||||||
|
marginLeft="0"
|
||||||
|
justifyContent="flex-start"
|
||||||
|
>
|
||||||
|
{sellPageState === SellPageStateType.LISTING ? null : (
|
||||||
|
<>
|
||||||
|
<BagHeader bagQuantity={sellAssets.length} />
|
||||||
|
<Column
|
||||||
|
overflowX="hidden"
|
||||||
|
overflowY="auto"
|
||||||
|
position="relative"
|
||||||
|
paddingTop="6"
|
||||||
|
paddingBottom="6"
|
||||||
|
height="full"
|
||||||
|
className={styles.tagAssets}
|
||||||
|
>
|
||||||
|
{sellAssets.length
|
||||||
|
? sellAssets.map((asset, index) => <CartSellAssetRow asset={asset} key={index} />)
|
||||||
|
: null}
|
||||||
|
</Column>
|
||||||
|
<Box padding="12">
|
||||||
|
<Box
|
||||||
|
as="button"
|
||||||
|
className={`${buttonMedium} ${styles.orderButton}`}
|
||||||
|
disabled={sellAssets.length === 0}
|
||||||
|
onClick={() => {
|
||||||
|
isMobile && toggleCart()
|
||||||
|
setSellPageState(SellPageStateType.LISTING)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Column>
|
||||||
|
</Suspense>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const BagHeader = ({ bagQuantity }: { bagQuantity: number }) => {
|
||||||
|
const toggleCart = useBag((state) => state.toggleBag)
|
||||||
|
const resetSellAssets = useSellAsset((state) => state.reset)
|
||||||
|
const isMobile = useIsMobile()
|
||||||
|
return (
|
||||||
|
<Box position="relative" zIndex="2" paddingTop="20" paddingLeft="12" paddingRight="12">
|
||||||
|
{isMobile ? (
|
||||||
|
<Box
|
||||||
|
as="button"
|
||||||
|
border="none"
|
||||||
|
color="darkGray"
|
||||||
|
background="black"
|
||||||
|
className={styles.closeIcon}
|
||||||
|
onClick={toggleCart}
|
||||||
|
>
|
||||||
|
<CloseDropDownIcon />
|
||||||
|
</Box>
|
||||||
|
) : null}
|
||||||
|
<Box className={headlineSmall} paddingTop="0" paddingBottom="8" paddingX="0" margin="0">
|
||||||
|
{'Selected items'}
|
||||||
|
</Box>
|
||||||
|
{bagQuantity > 0 ? (
|
||||||
|
<Box className={bodySmall} paddingTop="0" paddingBottom="8" paddingX="0" marginY="0" marginX="auto">
|
||||||
|
{bagQuantity} {bagQuantity === 1 ? 'NFT' : 'NFTs'}
|
||||||
|
<Box as="span" position="relative" paddingRight="2" paddingLeft="4" style={{ fontSize: '8px', top: '-2px' }}>
|
||||||
|
•
|
||||||
|
</Box>
|
||||||
|
<Box as="span" color="blue400" onClick={resetSellAssets} cursor="pointer" paddingLeft="2">
|
||||||
|
Remove all
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cart
|
82
src/nft/components/sell/modal/TagAssetRow.css.ts
Normal file
82
src/nft/components/sell/modal/TagAssetRow.css.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { style } from '@vanilla-extract/css'
|
||||||
|
import { sprinkles } from 'nft/css/sprinkles.css'
|
||||||
|
|
||||||
|
export const tagAssetImage = style([
|
||||||
|
sprinkles({
|
||||||
|
borderRadius: '8',
|
||||||
|
height: '52',
|
||||||
|
width: '52',
|
||||||
|
marginRight: '12',
|
||||||
|
marginLeft: '8',
|
||||||
|
cursor: 'pointer',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const tagAssetName = style([
|
||||||
|
sprinkles({
|
||||||
|
fontWeight: 'medium',
|
||||||
|
overflow: 'hidden',
|
||||||
|
marginRight: 'auto',
|
||||||
|
marginTop: '4',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
export const tagAssetCollectionName = style([
|
||||||
|
sprinkles({
|
||||||
|
fontWeight: 'normal',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
maxWidth: '65%',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const tagAssetRowBottom = style([
|
||||||
|
sprinkles({
|
||||||
|
width: 'full',
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
marginRight: '4',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
marginTop: '-10px',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const removeAsset = style([
|
||||||
|
sprinkles({
|
||||||
|
position: 'absolute',
|
||||||
|
cursor: 'pointer',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
bottom: '-12px',
|
||||||
|
left: '22px',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export const removeIcon = style([
|
||||||
|
sprinkles({
|
||||||
|
width: '32',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
export const tagAssetInfo = style([
|
||||||
|
sprinkles({
|
||||||
|
fontSize: '14',
|
||||||
|
color: 'blackBlue',
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
width: 'full',
|
||||||
|
overflowX: 'hidden',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
lineHeight: '17px',
|
||||||
|
},
|
||||||
|
])
|
43
src/nft/components/sell/modal/TagAssetRow.tsx
Normal file
43
src/nft/components/sell/modal/TagAssetRow.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { Box } from 'nft/components/Box'
|
||||||
|
import { bodySmall, subheadSmall } from 'nft/css/common.css'
|
||||||
|
import { useSellAsset } from 'nft/hooks'
|
||||||
|
import { WalletAsset } from 'nft/types'
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
import * as styles from './TagAssetRow.css'
|
||||||
|
|
||||||
|
const CartSellAssetRow = ({ asset }: { asset: WalletAsset }) => {
|
||||||
|
const removeAsset = useSellAsset((state) => state.removeSellAsset)
|
||||||
|
const [hovered, setHovered] = useState(false)
|
||||||
|
const handleHover = () => setHovered(!hovered)
|
||||||
|
const assetRowRef = useRef<HTMLDivElement>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hovered && assetRowRef.current && assetRowRef.current.matches(':hover') === false) setHovered(false)
|
||||||
|
}, [hovered])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box display="flex" padding="4" marginBottom="4" borderRadius="8" position="relative">
|
||||||
|
<Box
|
||||||
|
onMouseEnter={handleHover}
|
||||||
|
onMouseLeave={handleHover}
|
||||||
|
onClick={() => {
|
||||||
|
removeAsset(asset)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box visibility={hovered ? 'visible' : 'hidden'} className={styles.removeAsset}>
|
||||||
|
<img className={styles.removeIcon} src={'/nft/svgs/minusCircle.svg'} alt="Remove item" />
|
||||||
|
</Box>
|
||||||
|
<img className={styles.tagAssetImage} src={asset.image_url} alt={asset.name} />
|
||||||
|
</Box>
|
||||||
|
<Box className={styles.tagAssetInfo}>
|
||||||
|
<Box className={`${subheadSmall} ${styles.tagAssetName}`}>{asset.name || `#${asset.tokenId}`}</Box>
|
||||||
|
<Box className={styles.tagAssetRowBottom}>
|
||||||
|
<Box className={`${bodySmall} ${styles.tagAssetCollectionName}`}>{asset.collection?.name}</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CartSellAssetRow
|
Loading…
Reference in New Issue
Block a user