Commit 7ecbc552 authored by Jack Short's avatar Jack Short Committed by GitHub

feat: cards resize to uniform height (#4639)

* feat: cards resize to uniform height if differenting heights in collection

* setting uniform height if card is video
parent dadc9973
...@@ -23,6 +23,10 @@ export const card = style([ ...@@ -23,6 +23,10 @@ export const card = style([
}, },
]) ])
export const loadingBackground = style({
background: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
})
export const notSelectedCard = style([ export const notSelectedCard = style([
card, card,
sprinkles({ sprinkles({
......
...@@ -7,7 +7,7 @@ import { MinusIconLarge, PauseButtonIcon, PlayButtonIcon, PlusIconLarge } from ' ...@@ -7,7 +7,7 @@ import { MinusIconLarge, PauseButtonIcon, PlayButtonIcon, PlusIconLarge } from '
import { body, subheadSmall } from 'nft/css/common.css' import { body, subheadSmall } 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 { useIsMobile } from 'nft/hooks'
import { GenieAsset } from 'nft/types' import { GenieAsset, UniformHeight, UniformHeights } from 'nft/types'
import { import {
createContext, createContext,
MouseEvent, MouseEvent,
...@@ -88,13 +88,18 @@ const Container = ({ asset, children }: CardProps) => { ...@@ -88,13 +88,18 @@ const Container = ({ asset, children }: CardProps) => {
} }
/* -------- CARD IMAGE -------- */ /* -------- CARD IMAGE -------- */
const Image = () => { interface ImageProps {
uniformHeight: UniformHeight
setUniformHeight: (height: UniformHeight) => void
}
const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
const { hovered, asset } = useCardContext() const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl) const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
const [loaded, setLoaded] = useState(false) const [loaded, setLoaded] = useState(false)
if (noContent) { if (noContent) {
return <NoContentContainer /> return <NoContentContainer uniformHeight={uniformHeight} />
} }
return ( return (
...@@ -104,31 +109,35 @@ const Image = () => { ...@@ -104,31 +109,35 @@ const Image = () => {
alt={asset.name || asset.tokenId} alt={asset.name || asset.tokenId}
width="full" width="full"
style={{ style={{
aspectRatio: 'auto', aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto',
transition: 'transform 0.4s ease 0s', transition: 'transform 0.4s ease 0s',
background: loaded
? 'none'
: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
}} }}
src={asset.imageUrl || asset.smallImageUrl} src={asset.imageUrl || asset.smallImageUrl}
objectFit={'contain'} objectFit={'contain'}
draggable={false} draggable={false}
onError={() => setNoContent(true)} onError={() => setNoContent(true)}
onLoad={() => { onLoad={(e) => {
if (uniformHeight === UniformHeights.unset) {
setUniformHeight(e.currentTarget.clientHeight)
} else if (uniformHeight !== UniformHeights.notUniform && e.currentTarget.clientHeight !== uniformHeight) {
setUniformHeight(UniformHeights.notUniform)
}
setLoaded(true) setLoaded(true)
}} }}
className={clsx(hovered && styles.cardImageHover)} className={clsx(hovered && styles.cardImageHover, !loaded && styles.loadingBackground)}
/> />
</Box> </Box>
) )
} }
interface MediaProps { interface MediaProps {
uniformHeight: UniformHeight
setUniformHeight: (u: UniformHeight) => void
shouldPlay: boolean shouldPlay: boolean
setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void
} }
const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
const vidRef = useRef<HTMLVideoElement>(null) const vidRef = useRef<HTMLVideoElement>(null)
const { hovered, asset } = useCardContext() const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl) const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
...@@ -142,7 +151,7 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { ...@@ -142,7 +151,7 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
} }
if (noContent) { if (noContent) {
return <NoContentContainer /> return <NoContentContainer uniformHeight={UniformHeights.notUniform} />
} }
return ( return (
...@@ -156,19 +165,20 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { ...@@ -156,19 +165,20 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
aspectRatio: '1', aspectRatio: '1',
transition: 'transform 0.4s ease 0s', transition: 'transform 0.4s ease 0s',
willChange: 'transform', willChange: 'transform',
background: imageLoaded
? 'none'
: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
}} }}
src={asset.imageUrl || asset.smallImageUrl} src={asset.imageUrl || asset.smallImageUrl}
objectFit={'contain'} objectFit={'contain'}
draggable={false} draggable={false}
onError={() => setNoContent(true)} onError={() => setNoContent(true)}
onLoad={() => { onLoad={() => {
if (uniformHeight !== UniformHeights.notUniform) {
setUniformHeight(UniformHeights.notUniform)
}
setImageLoaded(true) setImageLoaded(true)
}} }}
visibility={shouldPlay ? 'hidden' : 'visible'} visibility={shouldPlay ? 'hidden' : 'visible'}
className={clsx(hovered && styles.cardImageHover)} className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/> />
</Box> </Box>
{shouldPlay ? ( {shouldPlay ? (
...@@ -224,7 +234,7 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { ...@@ -224,7 +234,7 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
) )
} }
const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { const Audio = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
const audRef = useRef<HTMLAudioElement>(null) const audRef = useRef<HTMLAudioElement>(null)
const { hovered, asset } = useCardContext() const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl) const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
...@@ -238,7 +248,7 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { ...@@ -238,7 +248,7 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
} }
if (noContent) { if (noContent) {
return <NoContentContainer /> return <NoContentContainer uniformHeight={uniformHeight} />
} }
return ( return (
...@@ -249,20 +259,22 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => { ...@@ -249,20 +259,22 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
alt={asset.name || asset.tokenId} alt={asset.name || asset.tokenId}
width="full" width="full"
style={{ style={{
aspectRatio: 'auto', aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto',
transition: 'transform 0.4s ease 0s', transition: 'transform 0.4s ease 0s',
background: imageLoaded
? 'none'
: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
}} }}
src={asset.imageUrl || asset.smallImageUrl} src={asset.imageUrl || asset.smallImageUrl}
objectFit={'contain'} objectFit={'contain'}
draggable={false} draggable={false}
onError={() => setNoContent(true)} onError={() => setNoContent(true)}
onLoad={() => { onLoad={(e) => {
if (uniformHeight === UniformHeights.unset) {
setUniformHeight(e.currentTarget.clientHeight)
} else if (uniformHeight !== UniformHeights.notUniform && e.currentTarget.clientHeight !== uniformHeight) {
setUniformHeight(UniformHeights.notUniform)
}
setImageLoaded(true) setImageLoaded(true)
}} }}
className={clsx(hovered && styles.cardImageHover)} className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/> />
</Box> </Box>
{shouldPlay ? ( {shouldPlay ? (
...@@ -503,7 +515,32 @@ const MarketplaceIcon = ({ marketplace }: { marketplace: string }) => { ...@@ -503,7 +515,32 @@ const MarketplaceIcon = ({ marketplace }: { marketplace: string }) => {
) )
} }
const NoContentContainer = () => ( interface NoContentContainerProps {
uniformHeight: UniformHeight
}
const NoContentContainer = ({ uniformHeight }: NoContentContainerProps) => (
<>
{uniformHeight !== UniformHeights.unset && uniformHeight !== UniformHeights.notUniform ? (
<Box
display="flex"
width="full"
style={{
height: `${uniformHeight as number}px`,
background: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
}}
fontWeight="normal"
color="grey500"
className={body}
justifyContent="center"
alignItems="center"
textAlign="center"
>
Content not
<br />
available yet
</Box>
) : (
<Box <Box
position="relative" position="relative"
width="full" width="full"
...@@ -527,6 +564,8 @@ const NoContentContainer = () => ( ...@@ -527,6 +564,8 @@ const NoContentContainer = () => (
available yet available yet
</Box> </Box>
</Box> </Box>
)}
</>
) )
export { export {
......
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import * as Card from 'nft/components/collection/Card' import * as Card from 'nft/components/collection/Card'
import { GenieAsset } from 'nft/types' import { GenieAsset, UniformHeight } from 'nft/types'
import { formatWeiToDecimal } from 'nft/utils/currency' import { formatWeiToDecimal } from 'nft/utils/currency'
import { isAudio } from 'nft/utils/isAudio' import { isAudio } from 'nft/utils/isAudio'
import { isVideo } from 'nft/utils/isVideo' import { isVideo } from 'nft/utils/isVideo'
...@@ -14,11 +14,19 @@ enum AssetMediaType { ...@@ -14,11 +14,19 @@ enum AssetMediaType {
interface CollectionAssetProps { interface CollectionAssetProps {
asset: GenieAsset asset: GenieAsset
uniformHeight: UniformHeight
setUniformHeight: (u: UniformHeight) => void
mediaShouldBePlaying: boolean mediaShouldBePlaying: boolean
setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void
} }
export const CollectionAsset = ({ asset, mediaShouldBePlaying, setCurrentTokenPlayingMedia }: CollectionAssetProps) => { export const CollectionAsset = ({
asset,
uniformHeight,
setUniformHeight,
mediaShouldBePlaying,
setCurrentTokenPlayingMedia,
}: CollectionAssetProps) => {
const { notForSale, assetMediaType } = useMemo(() => { const { notForSale, assetMediaType } = useMemo(() => {
let notForSale = true let notForSale = true
let assetMediaType = AssetMediaType.Image let assetMediaType = AssetMediaType.Image
...@@ -39,11 +47,21 @@ export const CollectionAsset = ({ asset, mediaShouldBePlaying, setCurrentTokenPl ...@@ -39,11 +47,21 @@ export const CollectionAsset = ({ asset, mediaShouldBePlaying, setCurrentTokenPl
return ( return (
<Card.Container asset={asset}> <Card.Container asset={asset}>
{assetMediaType === AssetMediaType.Image ? ( {assetMediaType === AssetMediaType.Image ? (
<Card.Image /> <Card.Image uniformHeight={uniformHeight} setUniformHeight={setUniformHeight} />
) : assetMediaType === AssetMediaType.Video ? ( ) : assetMediaType === AssetMediaType.Video ? (
<Card.Video shouldPlay={mediaShouldBePlaying} setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia} /> <Card.Video
uniformHeight={uniformHeight}
setUniformHeight={setUniformHeight}
shouldPlay={mediaShouldBePlaying}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
/>
) : ( ) : (
<Card.Audio shouldPlay={mediaShouldBePlaying} setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia} /> <Card.Audio
uniformHeight={uniformHeight}
setUniformHeight={setUniformHeight}
shouldPlay={mediaShouldBePlaying}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
/>
)} )}
<Card.DetailsContainer> <Card.DetailsContainer>
<Card.InfoContainer> <Card.InfoContainer>
......
...@@ -6,7 +6,8 @@ import { Center } from 'nft/components/Flex' ...@@ -6,7 +6,8 @@ import { Center } from 'nft/components/Flex'
import { bodySmall, buttonTextMedium, header2 } from 'nft/css/common.css' import { bodySmall, buttonTextMedium, header2 } from 'nft/css/common.css'
import { useCollectionFilters } from 'nft/hooks' import { useCollectionFilters } from 'nft/hooks'
import { AssetsFetcher } from 'nft/queries' import { AssetsFetcher } from 'nft/queries'
import { useMemo, useState } from 'react' import { UniformHeight, UniformHeights } from 'nft/types'
import { useEffect, useMemo, useState } from 'react'
import InfiniteScroll from 'react-infinite-scroll-component' import InfiniteScroll from 'react-infinite-scroll-component'
import { useInfiniteQuery } from 'react-query' import { useInfiniteQuery } from 'react-query'
...@@ -16,7 +17,6 @@ interface CollectionNftsProps { ...@@ -16,7 +17,6 @@ interface CollectionNftsProps {
export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
const buyNow = useCollectionFilters((state) => state.buyNow) const buyNow = useCollectionFilters((state) => state.buyNow)
const { const {
data: collectionAssets, data: collectionAssets,
isSuccess: AssetsFetchSuccess, isSuccess: AssetsFetchSuccess,
...@@ -48,6 +48,7 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { ...@@ -48,6 +48,7 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
} }
) )
const [uniformHeight, setUniformHeight] = useState<UniformHeight>(UniformHeights.unset)
const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState<string | undefined>() const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState<string | undefined>()
const collectionNfts = useMemo(() => { const collectionNfts = useMemo(() => {
...@@ -56,6 +57,10 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { ...@@ -56,6 +57,10 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
return collectionAssets.pages.flat() return collectionAssets.pages.flat()
}, [collectionAssets, AssetsFetchSuccess]) }, [collectionAssets, AssetsFetchSuccess])
useEffect(() => {
setUniformHeight(UniformHeights.unset)
}, [contractAddress])
if (!collectionNfts) { if (!collectionNfts) {
// TODO: collection unavailable page // TODO: collection unavailable page
return <div>No CollectionAssets</div> return <div>No CollectionAssets</div>
...@@ -76,6 +81,8 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => { ...@@ -76,6 +81,8 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
<CollectionAsset <CollectionAsset
key={asset.address + asset.tokenId} key={asset.address + asset.tokenId}
asset={asset} asset={asset}
uniformHeight={uniformHeight}
setUniformHeight={setUniformHeight}
mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia} mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia} setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
/> />
......
...@@ -20,7 +20,6 @@ const Collection = () => { ...@@ -20,7 +20,6 @@ const Collection = () => {
CollectionStatsFetcher(contractAddress as string) CollectionStatsFetcher(contractAddress as string)
) )
/// @reviewer these look the same now but will be diff later
const { gridX, gridWidthOffset } = useSpring({ const { gridX, gridWidthOffset } = useSpring({
gridX: isFiltersExpanded ? FILTER_WIDTH : 0, gridX: isFiltersExpanded ? FILTER_WIDTH : 0,
gridWidthOffset: isFiltersExpanded ? FILTER_WIDTH : 0, gridWidthOffset: isFiltersExpanded ? FILTER_WIDTH : 0,
......
...@@ -34,11 +34,13 @@ export type CollectionSort = Record< ...@@ -34,11 +34,13 @@ export type CollectionSort = Record<
'asc' | 'desc' | 1 | -1 | { $gte?: string | number; $lte?: string | number } | string | number 'asc' | 'desc' | 1 | -1 | { $gte?: string | number; $lte?: string | number } | string | number
> >
export enum UniformHeight { export enum UniformHeights {
unset, unset,
notUniform, notUniform,
} }
export type UniformHeight = UniformHeights | number
export enum ActivityEventType { export enum ActivityEventType {
Listing = 'LISTING', Listing = 'LISTING',
Sale = 'SALE', Sale = 'SALE',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment