Skip to content

Commit

Permalink
feat: 🎸 Add Industry Comparison Section (#427)
Browse files Browse the repository at this point in the history
* Open branch

* feat: 🎸 Add Industry Comparison Section

* fix: πŸ› address PR comments

* refactor: πŸ’‘ address PR comments

* docs: ✏️ add descripition for useMousePosition hook

* refactor: πŸ’‘ remove container ref from useMousePosition

* refactor: πŸ’‘ add  SlidingPanel component and update Cryptopunks

* refactor: πŸ’‘ dynamic import for framer motion

* refactor: πŸ’‘ address PR comments

* refactor: πŸ’‘ conditionally call drawDots to improve performance

* style: πŸ’„ remove unused title style

* refactor: πŸ’‘ remove unused prop dimensions from drawDots

* perf: ⚑️ remove mouse hover effect from dot grid animation

---------

Co-authored-by: iamacook <[email protected]>
Co-authored-by: Diogo Soares <[email protected]>
  • Loading branch information
3 people authored Aug 20, 2024
1 parent 0d455d3 commit ca43bb3
Show file tree
Hide file tree
Showing 15 changed files with 442 additions and 158 deletions.
58 changes: 58 additions & 0 deletions src/components/DataRoom/CryptoPunks/Content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Typography } from '@mui/material'
import type { BaseBlock } from '@/components/Home/types'
import type { MotionValue } from 'framer-motion'
import { motion, useTransform } from 'framer-motion'
import dynamic from 'next/dynamic'
import LinksWrapper from '../LinksWrapper'
import css from './styles.module.css'
import { useSafeDataRoomStats } from '@/hooks/useSafeDataRoomStats'
import { useIsMediumScreen } from '@/hooks/useMaxWidth'

const PunksGrid = dynamic(() => import('./PunksGrid'))
const SlidingPanel = dynamic(() => import('@/components/common/SlidingPanel'))

const CRYPTOPUNKS_TOTAL = 10000
const CRYPTOPUNKS_PERCENTAGE_STORED_FALLBACK = 0.092

const Content = ({ scrollYProgress, title, text, link }: BaseBlock & { scrollYProgress: MotionValue<number> }) => {
const { cryptoPunksStoredPercentage } = useSafeDataRoomStats()
const isMobile = useIsMediumScreen()

const opacityParams = isMobile ? [0.4, 0.45, 0.65, 0.66] : [0.25, 0.35, 0.65, 0.7]
const opacity = useTransform(scrollYProgress, opacityParams, [0, 1, 1, 0])

const percentageValue = cryptoPunksStoredPercentage || CRYPTOPUNKS_PERCENTAGE_STORED_FALLBACK
// Converts to percentage with 1 decimal place
const percentageToDisplay = (percentageValue * 100).toFixed(1) + '%'

const cryptoPunksStored = (percentageValue * CRYPTOPUNKS_TOTAL).toFixed(0)
const fractionToDisplay = `${cryptoPunksStored}/${CRYPTOPUNKS_TOTAL}`

return (
<motion.div
className={css.slidingPanelContent}
style={{
opacity,
}}
>
<Typography variant="h2" className={css.text}>
{text}
</Typography>

<Typography variant="h2">{title}</Typography>

<div className={css.statsContainer}>
<Typography variant="h1" className={css.percentage}>
{percentageToDisplay}
</Typography>
<Typography variant="h2" className={css.fraction}>
{fractionToDisplay}
</Typography>
</div>

{link && <LinksWrapper link={link} variant="dark" />}
</motion.div>
)
}

export default Content
53 changes: 53 additions & 0 deletions src/components/DataRoom/CryptoPunks/PunksGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { getRandomColor } from '@/components/DataRoom/CryptoPunks/utils/getRandomColor'
import CryptoPunk from '@/public/images/DataRoom/cryptopunk-silhouette.svg'
import type { MotionValue } from 'framer-motion'
import { motion, useTransform } from 'framer-motion'
import css from './styles.module.css'

const CRYPTOPUNK_ROWS_NR = 8
const CRYPTOPUNK_COLUMNS_NR = 24

const PunksGrid = ({ scrollYProgress, isMobile }: { scrollYProgress: MotionValue<number>; isMobile: boolean }) => {
const translateParams = isMobile ? [0, 1] : [0.25, 0.75]
const opacity = useTransform(scrollYProgress, [0, 0.25, 0.7, 0.75], [0, 1, 1, 0])
const translateLTR = useTransform(scrollYProgress, translateParams, ['-50%', '0%'])
const translateRTL = useTransform(scrollYProgress, translateParams, ['0%', '-50%'])

const translateDirection = (index: number) => (index % 2 === 1 ? translateLTR : translateRTL)

return (
<motion.div
style={{
opacity,
}}
className={css.punksGrid}
>
{Array.from({ length: CRYPTOPUNK_ROWS_NR }).map((_, outerIndex) => (
<motion.div
style={{ translateX: translateDirection(outerIndex) }}
className={css.cryptoPunkColumns}
key={outerIndex}
>
{Array.from({ length: CRYPTOPUNK_COLUMNS_NR }).map((_, innerIndex) => (
<motion.div
key={innerIndex}
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.3,
}}
style={{
transformOrigin: 'center',
color: getRandomColor(),
}}
>
<CryptoPunk className={css.cryptopunk} />
</motion.div>
))}
</motion.div>
))}
</motion.div>
)
}

export default PunksGrid
134 changes: 15 additions & 119 deletions src/components/DataRoom/CryptoPunks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import { Typography } from '@mui/material'
import type { BaseBlock } from '@/components/Home/types'
import { useIsMediumScreen } from '@/hooks/useMaxWidth'
import { useScroll } from 'framer-motion'
import dynamic from 'next/dynamic'
import { useRef } from 'react'
import { useScroll, motion, useTransform } from 'framer-motion'
import type { ReactNode } from 'react'
import type { MotionValue } from 'framer-motion'
import css from './styles.module.css'
import LinksWrapper from '../LinksWrapper'
import { getRandomColor } from '@/components/DataRoom/CryptoPunks/utils/getRandomColor'
import CryptoPunk from '@/public/images/DataRoom/cryptopunk-silhouette.svg'
import { useIsMediumScreen } from '@/hooks/useMaxWidth'
import { useSafeDataRoomStats } from '@/hooks/useSafeDataRoomStats'

const CRYPTOPUNKS_TOTAL = 10000
const CRYPTOPUNKS_PERCENTAGE_STORED_FALLBACK = 0.092

const CRYPTOPUNK_ROWS_NR = 8
const CRYPTOPUNK_COLUMNS_NR = 24
const PunksGrid = dynamic(() => import('./PunksGrid'))
const Content = dynamic(() => import('./Content'))
const SlidingPanel = dynamic(() => import('@/components/common/SlidingPanel'))

const CryptoPunks = ({ title, text, link }: BaseBlock) => {
const { cryptoPunksStoredPercentage } = useSafeDataRoomStats()

const backgroundRef = useRef<HTMLDivElement>(null)
const isMobile = useIsMediumScreen()

Expand All @@ -28,113 +18,19 @@ const CryptoPunks = ({ title, text, link }: BaseBlock) => {
offset: ['start end', 'end start'],
})

const percentageValue = cryptoPunksStoredPercentage || CRYPTOPUNKS_PERCENTAGE_STORED_FALLBACK
// Converts to percentage with 1 decimal place
const percentageToDisplay = (percentageValue * 100).toFixed(1) + '%'

const cryptoPunksStored = (percentageValue * CRYPTOPUNKS_TOTAL).toFixed(0)
const fractionToDisplay = `${cryptoPunksStored}/${CRYPTOPUNKS_TOTAL}`

return (
<div ref={backgroundRef} className={css.sectionContainer}>
<div className={css.stickyContainer}>
<LeftPanel scrollYProgress={scrollYProgress} isMobile={isMobile} />
<RightPanel scrollYProgress={scrollYProgress} isMobile={isMobile}>
<Typography variant="h2" className={css.text}>
{text}
</Typography>

<Typography variant="h2">{title}</Typography>

<div className={css.statsContainer}>
<Typography variant="h1" className={css.percentage}>
{percentageToDisplay}
</Typography>
<Typography variant="h2" className={css.fraction}>
{fractionToDisplay}
</Typography>
</div>

{link && <LinksWrapper link={link} variant="dark" />}
</RightPanel>
</div>
</div>
)
}

const LeftPanel = ({ scrollYProgress, isMobile }: { scrollYProgress: MotionValue<number>; isMobile: boolean }) => {
const translateParams = isMobile ? [0, 1] : [0.25, 0.75]
const opacity = useTransform(scrollYProgress, [0, 0.25, 0.7, 0.75], [0, 1, 1, 0])
const translateLTR = useTransform(scrollYProgress, translateParams, ['-50%', '0%'])
const translateRTL = useTransform(scrollYProgress, translateParams, ['0%', '-50%'])

const translateDirection = (index: number) => (index % 2 === 1 ? translateLTR : translateRTL)

return (
<motion.div
style={{
opacity,
}}
className={css.leftPanelContainer}
>
{Array.from({ length: CRYPTOPUNK_ROWS_NR }).map((_, outerIndex) => (
<motion.div
style={{ translateX: translateDirection(outerIndex) }}
className={css.cryptoPunkColumns}
key={outerIndex}
<PunksGrid scrollYProgress={scrollYProgress} isMobile={isMobile} />
<SlidingPanel
panelWidth={isMobile ? '100%' : '50%'}
scrollParams={isMobile ? [0.4, 0.45, 0.65, 0.7] : [0.25, 0.35, 0.65, 0.75]}
translateParams={['100%', '0%', '0%', '100%']}
scrollYProgress={scrollYProgress}
>
{Array.from({ length: CRYPTOPUNK_COLUMNS_NR }).map((_, innerIndex) => (
<motion.div
key={innerIndex}
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.3,
}}
style={{
transformOrigin: 'center',
color: getRandomColor(),
}}
>
<CryptoPunk className={css.cryptopunk} />
</motion.div>
))}
</motion.div>
))}
</motion.div>
)
}

const RightPanel = ({
scrollYProgress,
children,
isMobile,
}: {
scrollYProgress: MotionValue<number>
children: ReactNode
isMobile: boolean
}) => {
const opacityParams = isMobile ? [0.4, 0.45, 0.65, 0.66] : [0.25, 0.35, 0.65, 0.7]
const translateParams = isMobile ? [0.4, 0.45, 0.65, 0.7] : [0.25, 0.35, 0.65, 0.75]
const opacity = useTransform(scrollYProgress, opacityParams, [0, 1, 1, 0])
const bgTranslate = useTransform(scrollYProgress, translateParams, ['100%', '0%', '0%', '100%'])

return (
<div className={css.rightPanelContainer}>
<motion.div
className={css.rightPanelContent}
style={{
opacity,
}}
>
{children}
</motion.div>
<motion.div
className={css.rightPanelBG}
style={{
translateX: bgTranslate,
}}
></motion.div>
<Content title={title} text={text} link={link} scrollYProgress={scrollYProgress} />
</SlidingPanel>
</div>
</div>
)
}
Expand Down
44 changes: 5 additions & 39 deletions src/components/DataRoom/CryptoPunks/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,7 @@
display: flex;
}

.rightPanelContainer {
width: 50%;
height: 100%;
position: absolute;
right: 0;
color: var(--mui-palette-text-dark);
overflow-x: hidden;
display: flex;
align-items: flex-end;
padding-top: 64px;
}

.rightPanelContent {
.slidingPanelContent {
z-index: 20;
display: flex;
flex-direction: column;
Expand All @@ -33,14 +21,6 @@
gap: 30px;
}

.rightPanelBG {
position: absolute;
inset: 0;
background-color: var(--mui-palette-primary-main);
z-index: 10;
margin-top: 72px;
}

.percentage {
font-size: 120px;
line-height: 120px;
Expand All @@ -65,7 +45,7 @@
align-items: baseline;
}

.leftPanelContainer {
.punksGrid {
width: 100%;
height: 100%;
overflow: hidden;
Expand Down Expand Up @@ -94,39 +74,25 @@
flex-direction: column-reverse;
}

.leftPanelContainer {
.punksGrid {
padding-top: 72px;
width: 100%;
height: 100%;
overflow: hidden;
}

.rightPanelContainer {
width: 100%;
height: 100%;
position: absolute;
bottom: 0;
}

.rightPanelContent {
.slidingPanelContent {
justify-content: end;
padding: 30px;
gap: 30px;
}

.rightPanelBG {
margin-top: 64px;
}

.statsContainer {
display: flex;
flex-direction: column;
gap: 30px;
}

.leftPanelContainer {
overflow: hidden;
}

.cryptopunk {
width: 60px;
}
Expand Down
38 changes: 38 additions & 0 deletions src/components/DataRoom/IndustryComparison/Content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { BaseBlock } from '@/components/Home/types'
import { Typography } from '@mui/material'
import type { MotionValue } from 'framer-motion'
import { motion, useTransform } from 'framer-motion'
import DotGrid from './DotGrid'
import css from './styles.module.css'
import { useIsMediumScreen } from '@/hooks/useMaxWidth'
import type { RefObject } from 'react'

const Content = ({
scrollYProgress,
title,
containerRef,
}: {
title: BaseBlock['title']
scrollYProgress: MotionValue<number>
containerRef: RefObject<HTMLDivElement>
}) => {
const isMobile = useIsMediumScreen()

const scrollParams = [0.25, 0.35, 0.65, 0.75]
const opacityParams = [0, 1, 1, 0]
const opacity = useTransform(scrollYProgress, scrollParams, opacityParams)

return (
<motion.div
className={css.slidingPanelContent}
style={{
opacity: isMobile ? 1 : opacity,
}}
>
<Typography variant="h1">{title}</Typography>
<DotGrid containerRef={containerRef} />
</motion.div>
)
}

export default Content
Loading

0 comments on commit ca43bb3

Please sign in to comment.