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([
},
])
export const loadingBackground = style({
background: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
})
export const notSelectedCard = style([
card,
sprinkles({
......
......@@ -7,7 +7,7 @@ import { MinusIconLarge, PauseButtonIcon, PlayButtonIcon, PlusIconLarge } from '
import { body, subheadSmall } from 'nft/css/common.css'
import { themeVars, vars } from 'nft/css/sprinkles.css'
import { useIsMobile } from 'nft/hooks'
import { GenieAsset } from 'nft/types'
import { GenieAsset, UniformHeight, UniformHeights } from 'nft/types'
import {
createContext,
MouseEvent,
......@@ -88,13 +88,18 @@ const Container = ({ asset, children }: CardProps) => {
}
/* -------- CARD IMAGE -------- */
const Image = () => {
interface ImageProps {
uniformHeight: UniformHeight
setUniformHeight: (height: UniformHeight) => void
}
const Image = ({ uniformHeight, setUniformHeight }: ImageProps) => {
const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
const [loaded, setLoaded] = useState(false)
if (noContent) {
return <NoContentContainer />
return <NoContentContainer uniformHeight={uniformHeight} />
}
return (
......@@ -104,31 +109,35 @@ const Image = () => {
alt={asset.name || asset.tokenId}
width="full"
style={{
aspectRatio: 'auto',
aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto',
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}
objectFit={'contain'}
draggable={false}
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)
}}
className={clsx(hovered && styles.cardImageHover)}
className={clsx(hovered && styles.cardImageHover, !loaded && styles.loadingBackground)}
/>
</Box>
)
}
interface MediaProps {
uniformHeight: UniformHeight
setUniformHeight: (u: UniformHeight) => void
shouldPlay: boolean
setCurrentTokenPlayingMedia: (tokenId: string | undefined) => void
}
const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
const Video = ({ uniformHeight, setUniformHeight, shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
const vidRef = useRef<HTMLVideoElement>(null)
const { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
......@@ -142,7 +151,7 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
}
if (noContent) {
return <NoContentContainer />
return <NoContentContainer uniformHeight={UniformHeights.notUniform} />
}
return (
......@@ -156,19 +165,20 @@ const Video = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
aspectRatio: '1',
transition: 'transform 0.4s ease 0s',
willChange: 'transform',
background: imageLoaded
? 'none'
: `linear-gradient(270deg, ${themeVars.colors.medGray} 0%, ${themeVars.colors.lightGray} 100%)`,
}}
src={asset.imageUrl || asset.smallImageUrl}
objectFit={'contain'}
draggable={false}
onError={() => setNoContent(true)}
onLoad={() => {
if (uniformHeight !== UniformHeights.notUniform) {
setUniformHeight(UniformHeights.notUniform)
}
setImageLoaded(true)
}}
visibility={shouldPlay ? 'hidden' : 'visible'}
className={clsx(hovered && styles.cardImageHover)}
className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/>
</Box>
{shouldPlay ? (
......@@ -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 { hovered, asset } = useCardContext()
const [noContent, setNoContent] = useState(!asset.smallImageUrl && !asset.imageUrl)
......@@ -238,7 +248,7 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
}
if (noContent) {
return <NoContentContainer />
return <NoContentContainer uniformHeight={uniformHeight} />
}
return (
......@@ -249,20 +259,22 @@ const Audio = ({ shouldPlay, setCurrentTokenPlayingMedia }: MediaProps) => {
alt={asset.name || asset.tokenId}
width="full"
style={{
aspectRatio: 'auto',
aspectRatio: uniformHeight === UniformHeights.notUniform ? '1' : 'auto',
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}
objectFit={'contain'}
draggable={false}
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)
}}
className={clsx(hovered && styles.cardImageHover)}
className={clsx(hovered && styles.cardImageHover, !imageLoaded && styles.loadingBackground)}
/>
</Box>
{shouldPlay ? (
......@@ -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
position="relative"
width="full"
......@@ -527,6 +564,8 @@ const NoContentContainer = () => (
available yet
</Box>
</Box>
)}
</>
)
export {
......
import { BigNumber } from '@ethersproject/bignumber'
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 { isAudio } from 'nft/utils/isAudio'
import { isVideo } from 'nft/utils/isVideo'
......@@ -14,11 +14,19 @@ enum AssetMediaType {
interface CollectionAssetProps {
asset: GenieAsset
uniformHeight: UniformHeight
setUniformHeight: (u: UniformHeight) => void
mediaShouldBePlaying: boolean
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(() => {
let notForSale = true
let assetMediaType = AssetMediaType.Image
......@@ -39,11 +47,21 @@ export const CollectionAsset = ({ asset, mediaShouldBePlaying, setCurrentTokenPl
return (
<Card.Container asset={asset}>
{assetMediaType === AssetMediaType.Image ? (
<Card.Image />
<Card.Image uniformHeight={uniformHeight} setUniformHeight={setUniformHeight} />
) : 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.InfoContainer>
......
......@@ -6,7 +6,8 @@ import { Center } from 'nft/components/Flex'
import { bodySmall, buttonTextMedium, header2 } from 'nft/css/common.css'
import { useCollectionFilters } from 'nft/hooks'
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 { useInfiniteQuery } from 'react-query'
......@@ -16,7 +17,6 @@ interface CollectionNftsProps {
export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
const buyNow = useCollectionFilters((state) => state.buyNow)
const {
data: collectionAssets,
isSuccess: AssetsFetchSuccess,
......@@ -48,6 +48,7 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
}
)
const [uniformHeight, setUniformHeight] = useState<UniformHeight>(UniformHeights.unset)
const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState<string | undefined>()
const collectionNfts = useMemo(() => {
......@@ -56,6 +57,10 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
return collectionAssets.pages.flat()
}, [collectionAssets, AssetsFetchSuccess])
useEffect(() => {
setUniformHeight(UniformHeights.unset)
}, [contractAddress])
if (!collectionNfts) {
// TODO: collection unavailable page
return <div>No CollectionAssets</div>
......@@ -76,6 +81,8 @@ export const CollectionNfts = ({ contractAddress }: CollectionNftsProps) => {
<CollectionAsset
key={asset.address + asset.tokenId}
asset={asset}
uniformHeight={uniformHeight}
setUniformHeight={setUniformHeight}
mediaShouldBePlaying={asset.tokenId === currentTokenPlayingMedia}
setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia}
/>
......
......@@ -20,7 +20,6 @@ const Collection = () => {
CollectionStatsFetcher(contractAddress as string)
)
/// @reviewer these look the same now but will be diff later
const { gridX, gridWidthOffset } = useSpring({
gridX: isFiltersExpanded ? FILTER_WIDTH : 0,
gridWidthOffset: isFiltersExpanded ? FILTER_WIDTH : 0,
......
......@@ -34,11 +34,13 @@ export type CollectionSort = Record<
'asc' | 'desc' | 1 | -1 | { $gte?: string | number; $lte?: string | number } | string | number
>
export enum UniformHeight {
export enum UniformHeights {
unset,
notUniform,
}
export type UniformHeight = UniformHeights | number
export enum ActivityEventType {
Listing = 'LISTING',
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