Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dataroom): Counter animation responsiveness #454

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 17 additions & 35 deletions src/components/DataRoom/TransactionsOnChain/Counter.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,29 @@
import { motion, type MotionValue, useSpring, useTransform } from 'framer-motion'
import { useEffect } from 'react'
import { calculateYPosition } from '@/components/DataRoom/TransactionsOnChain/utils/calculateYPosition'
import { useIsMediumScreen } from '@/hooks/useMaxWidth'
import css from './styles.module.css'
import { calculateYPosition } from './utils/calculateYPosition'

type CounterProps = {
value: number
}

type DigitProps = {
place: number
value: number
}

type NumberProps = {
mv: MotionValue<number>
number: number
}

const DIGIT_HEIGHT_SM = 120
const DIGIT_HEIGHT_MD = 215

const Counter = ({ value }: CounterProps) => {
const integerPart = Math.floor(value)
const decimalPart = value % 1

const Counter = ({ value }: { value: number }) => {
return (
<div className={css.counter}>
<Digit place={1} value={integerPart} />
<span className={css.counterSpan}>.</span>
<Digit place={0.1} value={decimalPart} />
<Digit place={0.01} value={decimalPart} />
<span className={css.counterSpan}>%</span>
<Digit place={1} value={value} />
<div className={css.dot}>
<div className={css.number}>.</div>
</div>
<Digit place={0.1} value={value} />
<Digit place={0.01} value={value} />
<div className={css.percentage}>
<div className={css.number}>%</div>
</div>
</div>
)
}

const Digit = ({ place, value }: DigitProps) => {
const Digit = ({ place, value }: { place: number; value: number }) => {
const valueRoundedToPlace = Math.floor(value / place) % 10
const animatedValue = useSpring(valueRoundedToPlace, {
damping: 5,
stiffness: 15,
stiffness: 50,
damping: 15,
})

useEffect(() => {
Expand All @@ -56,12 +39,11 @@ const Digit = ({ place, value }: DigitProps) => {
)
}

const Number = ({ mv, number }: NumberProps) => {
const height = useIsMediumScreen() ? DIGIT_HEIGHT_SM : DIGIT_HEIGHT_MD
const yPosition = useTransform(mv, (latest: number) => calculateYPosition(latest, number, height))
const Number = ({ mv, number }: { mv: MotionValue<number>; number: number }) => {
const y = useTransform(mv, (latest) => calculateYPosition(latest, number))

return (
<motion.span style={{ y: yPosition }} className={css.number}>
<motion.span style={{ y }} className={css.number}>
{number}
</motion.span>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ const CounterContainer = ({ percentage }: { percentage: number }) => {
className={css.counterContainer}
ref={targetScrollRef}
>
<div className={css.box1}>
<div className={css.counterPartial}>
<Counter value={value} />
</div>

<div className={css.box2}>
<div className={css.counterPartial}>
<Counter value={value} />
</div>

<div>
<div className={css.counterFull}>
<Counter value={value} />
</div>
</motion.div>
Expand Down
11 changes: 6 additions & 5 deletions src/components/DataRoom/TransactionsOnChain/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ const TransactionsOnChain = ({ text, link }: BaseBlock) => {
return (
<div className={css.sectionContainer}>
<div className={css.stickyContainer}>
<CounterContainer percentage={percentageValue} />

<div className={css.content}>
<Typography variant="h1">{text}</Typography>

<div className={css.linkContainer}>{link && <LinksWrapper link={link} />}</div>
<CounterContainer percentage={percentageValue} />
<Typography className={css.text} variant="h1">
{text}
</Typography>
</div>

<div className={css.linkContainer}>{link && <LinksWrapper link={link} />}</div>
</div>
</div>
)
Expand Down
129 changes: 70 additions & 59 deletions src/components/DataRoom/TransactionsOnChain/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,126 +5,137 @@
.stickyContainer {
height: 100vh;
display: flex;
justify-content: center;
flex-direction: column;
justify-content: space-around;
align-items: flex-start;
padding-left: 30px;
position: sticky;
padding-left: 15px;
padding-right: 15px;
width: 100%;
gap: 60px;
top: 0;
}

.content {
display: flex;
flex-direction: column;
width: 100%;
align-items: flex-start;
gap: 30px;
flex-direction: row;
justify-content: center;
gap: 20px;
}

.linkContainer {
align-self: auto;
margin-top: 0;
margin-right: 0;
align-self: flex-end;
padding-left: 0px;
}

.counterContainer {
color: var(--mui-palette-primary-main);
font-size: 30px;
font-weight: 400;
display: flex;
overflow: visible;
flex-direction: column;
justify-content: flex-start;
gap: 30px;
margin-top: 72px;
width: 50%;
padding-top: 16px;
}

.box1 {
height: 50px;
.counter {
display: flex;
overflow: hidden;
line-height: 1;
justify-content: center;
}

.box2 {
height: 70px;
overflow: hidden;
.text {
width: 50%;
font-size: 80px;
padding-left: 0px;
}

.digit {
position: relative;
width: 1ch;
font-variant-numeric: tabular-nums;
height: 1.25ch;
}

.dot {
position: relative;
width: 0.2ch;
font-variant-numeric: tabular-nums;
height: 1.25ch;
}

.percentage {
position: relative;
width: 0.8ch;
height: 120px;
width: 1.25ch;
font-variant-numeric: tabular-nums;
height: 1.25ch;
}

.number {
width: fit-content;
position: absolute;
inset: 0px;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}

.counter {
display: flex;
overflow: hidden;
font-size: 120px;
.counterPartial,
.counterFull {
width: 100%;
font-size: 150px;
}

.counterSpan {
margin-top: 44px;
.counterPartial {
height: 0.7ch;
overflow: hidden;
}

@media (min-width: 900px) {
.sectionContainer {
height: 150vh;
}

@media (max-width: 900px) {
.content {
margin-top: 80px;
margin-right: 80px;
}

.digit {
width: 1ch;
flex-direction: column;
align-items: flex-start;
gap: 60px;
}

.linkContainer {
align-self: flex-end;
margin-top: 80px;
/* margin-right: 80px; */
align-self: auto;
margin-top: 0;
margin-right: 0;
padding-left: 15px;
}

.counterContainer {
gap: 0;
}

.box1 {
height: 100px;
}

.box2 {
height: 150px;
width: 100%;
}

.stickyContainer {
flex-direction: row;
justify-content: space-around;
align-items: center;
gap: 120px;
.counter {
justify-content: flex-start;
}

.counterContainer {
translate: 50px 0;
.text {
width: 100%;
font-size: 50px;
padding-left: 15px;
}

.digit {
height: 215px;
.counterPartial,
.counterFull {
font-size: 120px;
}
}

.counter {
@media (min-width: 1150px) {
.counterPartial,
.counterFull {
font-size: 200px;
}

.counterSpan {
margin-top: 96px;
.text {
font-size: 90px;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
/**
* Calculates the Y position for individual digits in the counter animation
* to create a smooth rolling effect from 0 to the targetNumber.
* Calculates the vertical position for a number in a rolling counter animation.
*
* @returns {number} The calculated Y position.
* @param {number} latest - The current value of the counter.
* @param {number} number - The number for which to calculate the position.
* @returns {string} The calculated vertical position as a CSS em value.
*
* This function determines the offset between the current counter value and the
* given number, then calculates an appropriate vertical position. The result
* is used to create a rolling number effect in the counter animation.
*/
export function calculateYPosition(latest: number, targetNumber: number, digitHeight: number): number {
const currentDigit = latest % 10
const digitDifference = (10 + targetNumber - currentDigit) % 10
export function calculateYPosition(latest: number, number: number): string {
let placeValue = latest % 10
let offset = (10 + number - placeValue) % 10
Comment on lines +13 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you change these variables to let ?


let yOffset = digitDifference * digitHeight
let memo = offset * 1.5

// Adjust for shortest path (up or down)
if (digitDifference > 5) {
yOffset -= 10 * digitHeight
if (offset > 5) {
memo -= 10 * 1.5
}

return yOffset
return `${memo}em`
}
Loading