Commit 819302b5 authored by Jack Short's avatar Jack Short Committed by GitHub

feat: adding collection stats to collection page (#4391)

* feat: adding collection stats

* removing debounced callback

* addressing comments

* updating marquee and updating isMobile hook

* adding bool to useIsMobile
parent c53d7fcc
import { style } from '@vanilla-extract/css'
import { body, bodySmall } from 'nft/css/common.css'
import { breakpoints, sprinkles } from '../../css/sprinkles.css'
export const statsText = style([
sprinkles({
marginTop: { mobile: '8', tabletSm: '40' },
marginBottom: { mobile: '0', tabletSm: '28' },
}),
{
'@media': {
[`(max-width: ${breakpoints.tabletSm - 1}px)`]: {
marginLeft: '68px',
},
},
},
])
export const smallStatsText = style({
marginLeft: '84px',
})
export const statsRowItem = sprinkles({ paddingRight: '12' })
export const baseCollectionImage = sprinkles({
left: '0',
borderStyle: 'solid',
borderWidth: '4px',
borderColor: 'white',
})
export const collectionImage = style([
baseCollectionImage,
{
width: '143px',
height: '143px',
verticalAlign: 'top',
top: '-118px',
'@media': {
[`(max-width: ${breakpoints.tabletSm - 1}px)`]: {
width: '60px',
height: '60px',
borderWidth: '2px',
top: '-20px',
},
},
},
])
export const nameText = sprinkles({
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
})
export const description = style([
sprinkles({
fontSize: '14',
display: 'inline-block',
}),
{
maxWidth: 'min(calc(100% - 112px), 600px)',
verticalAlign: 'top',
lineHeight: '20px',
},
])
export const descriptionOpen = style([
{
whiteSpace: 'normal',
verticalAlign: 'top',
lineHeight: '20px',
},
sprinkles({
overflow: 'visible',
display: 'inline',
maxWidth: 'full',
}),
])
export const readMore = style([
{
verticalAlign: 'top',
lineHeight: '20px',
},
sprinkles({
color: 'blue400',
cursor: 'pointer',
marginLeft: '4',
fontSize: '14',
}),
])
export const statsLabel = style([
bodySmall,
sprinkles({
fontWeight: 'normal',
color: 'darkGray',
whiteSpace: 'nowrap',
}),
{
lineHeight: '20px',
},
])
export const statsValue = style([
body,
sprinkles({
fontWeight: 'medium',
}),
{
lineHeight: '24px',
},
])
This diff is collapsed.
import { globalKeyframes, style } from '@vanilla-extract/css'
import { sprinkles } from '../../css/sprinkles.css'
globalKeyframes('scroll', {
'0%': {
transform: 'translateX(0%)',
},
'100%': {
transform: 'translateX(-100%)',
},
})
export const marquee = style([
sprinkles({
minWidth: 'full',
zIndex: '1',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
}),
{
flex: '0 0 auto',
animation: 'scroll var(--duration) linear infinite',
},
])
import { Box } from 'nft/components/Box'
import * as styles from 'nft/components/layout/Marquee.css'
import { ReactNode, useEffect, useRef, useState } from 'react'
export const Marquee = ({ children, speed = 20 }: { children: ReactNode; speed?: number }) => {
const [duration, setDuration] = useState(0)
const containerRef = useRef<HTMLDivElement | null>(null)
const marqueeRef = useRef<HTMLDivElement | null>(null)
const updateScrollDuration = () => {
let containerWidth = 0
let marqueeWidth = 0
try {
if (marqueeRef.current && containerRef.current) {
containerWidth = containerRef.current.getBoundingClientRect().width
marqueeWidth = marqueeRef.current.getBoundingClientRect().width
}
} catch (e) {}
if (marqueeWidth < containerWidth) {
setDuration(containerWidth / speed)
} else {
setDuration(marqueeWidth / speed)
}
}
useEffect(() => {
updateScrollDuration()
// Rerender on window resize
window.addEventListener('resize', updateScrollDuration)
return () => {
window.removeEventListener('resize', updateScrollDuration)
}
})
return (
<Box ref={containerRef} overflowX="hidden" display="flex" flexDirection="row" position="relative" width="full">
<div ref={marqueeRef} style={{ ['--duration' as string]: `${duration}s` }} className={styles.marquee}>
{children}
</div>
<div style={{ ['--duration' as string]: `${duration}s` }} className={styles.marquee}>
{children}
</div>
</Box>
)
}
import create from 'zustand' import { breakpoints } from 'nft/css/sprinkles.css'
import { devtools } from 'zustand/middleware' import { useEffect, useState } from 'react'
import { breakpoints } from '../css/sprinkles.css' const isClient = typeof window === 'object'
interface IsMobileState { function getIsMobile() {
isMobile: boolean return isClient ? window.innerWidth < breakpoints.tabletSm : false
width: number
setMobileWidth: (width: number) => void
} }
export const useIsMobile = create<IsMobileState>()( export function useIsMobile(): boolean {
devtools( const [isMobile, setIsMobile] = useState(getIsMobile)
(set) => ({
isMobile: true, useEffect(() => {
width: 800, function handleResize() {
setMobileWidth: (width: number) => setIsMobile(getIsMobile())
set(() => ({ }
width,
isMobile: width < breakpoints.tabletSm, if (isClient) {
})), window.addEventListener('resize', handleResize)
}), return () => {
{ name: 'isMobile' } window.removeEventListener('resize', handleResize)
) }
) }
return undefined
}, [])
return isMobile
}
import { AnimatedBox, Box } from 'nft/components/Box'
import { CollectionStats } from 'nft/components/collection/CollectionStats'
import { Column, Row } from 'nft/components/Flex'
import { CollectionProps } from 'nft/pages/collection/common'
import * as styles from 'nft/pages/collection/common.css'
export const CollectionDesktop = ({ collectionStats }: CollectionProps) => {
return (
<Column width="full">
<Box width="full" height="160">
<Box
as="img"
maxHeight="full"
width="full"
src={collectionStats?.bannerImageUrl}
className={`${styles.bannerImage}`}
/>
</Box>
{collectionStats && (
<Row paddingLeft="32" paddingRight="32">
<CollectionStats stats={collectionStats} isMobile={false} />
</Row>
)}
<Row alignItems="flex-start" position="relative" paddingLeft="32" paddingRight="32">
<AnimatedBox width="full">CollectionNfts</AnimatedBox>
</Row>
</Column>
)
}
import { AnimatedBox, Box } from 'nft/components/Box'
import { CollectionStats } from 'nft/components/collection/CollectionStats'
import { Column, Row } from 'nft/components/Flex'
import { CollectionProps } from 'nft/pages/collection/common'
import * as styles from 'nft/pages/collection/common.css'
export const CollectionMobile = ({ collectionStats }: CollectionProps) => {
return (
<Column width="full">
<Box width="full" height="160">
<Box
as="img"
maxHeight="full"
width="full"
src={collectionStats?.bannerImageUrl}
className={`${styles.bannerImage}`}
/>
</Box>
{collectionStats && (
<Row paddingLeft="32" paddingRight="32">
<CollectionStats stats={collectionStats} isMobile={true} />
</Row>
)}
<Row alignItems="flex-start" position="relative" paddingLeft="32" paddingRight="32">
<AnimatedBox width="full">CollectionNfts</AnimatedBox>
</Row>
</Column>
)
}
import { style } from '@vanilla-extract/css'
import { buttonTextMedium } from 'nft/css/common.css'
import { sprinkles, vars } from '../../css/sprinkles.css'
export const bannerContainerNoBanner = style({ height: '0', marginTop: '0px' })
export const bannerImage = style({ objectFit: 'cover' })
export const baseActivitySwitcherToggle = style([
buttonTextMedium,
sprinkles({
position: 'relative',
background: 'none',
border: 'none',
cursor: 'pointer',
}),
{
lineHeight: '24px',
},
])
export const activitySwitcherToggle = style([
baseActivitySwitcherToggle,
sprinkles({
color: 'darkGray',
}),
])
export const selectedActivitySwitcherToggle = style([
baseActivitySwitcherToggle,
sprinkles({
color: 'blackBlue',
}),
{
':after': {
content: '',
position: 'absolute',
background: vars.color.genieBlue,
width: '100%',
height: '2px',
left: '0px',
right: '0px',
bottom: '-8px',
},
},
])
import { GenieCollection } from 'nft/types'
export interface CollectionProps {
collectionStats: GenieCollection | undefined
}
export const Collection = () => { import { useQuery } from 'react-query'
return <div>Collection Page</div> import { useParams } from 'react-router-dom'
import { useIsMobile } from '../../hooks/useIsMobile'
import { CollectionStatsFetcher } from '../../queries'
import { CollectionDesktop } from './CollectionDesktop'
import { CollectionMobile } from './CollectionMobile'
const Collection = () => {
const { contractAddress } = useParams()
const isMobile = useIsMobile()
const { data: collectionStats } = useQuery(['collectionStats', contractAddress], () =>
CollectionStatsFetcher(contractAddress as string)
)
return isMobile ? (
<CollectionMobile collectionStats={collectionStats} />
) : (
<CollectionDesktop collectionStats={collectionStats} />
)
} }
export default Collection export default Collection
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