import { rem, typo, color as colorMixin } from '@/styles/mixins'
import { css } from '@emotion/react'
import Slot from './Slot'
const wrapperStyle = css([
typo.HS28,
{
height: '1em',
lineHeight: 1,
fontVariantNumeric: 'tabular-nums',
fontSize: `var(--font-size)`,
color: `var(--color)`,
overflow: 'hidden',
},
])
type Props = {
className?: string
num?: number
fontSize?: number
color?: string
}
const SlotMachine = ({ className, num, fontSize = 28, color = colorMixin.DB1000 }: Props) => {
return (
<div
className={className}
aria-label={`${num}`}
css={wrapperStyle}
style={{ ['--font-size' as any]: rem(fontSize), ['--color' as any]: color }}
>
{num
? num
.toLocaleString()
.split('')
.map((digitStr, index) => {
if (digitStr === ',') {
return digitStr
}
const digit = Number(digitStr)
return <Slot key={index} digit={digit} index={index} />
})
: null}
명
</div>
)
}
export default SlotMachine
import { keyframes } from '@emotion/react'
import { Fragment } from 'react'
type Props = {
digit: number
index: number
}
const transformNone = keyframes`
to {
transform: none
}
`
const easeOutQuart = 'cubic-bezier(0.25, 1, 0.5, 1)'
const easeInOutQuint = 'cubic-bezier(0.83, 0, 0.17, 1)'
const easeInOutExpo = 'cubic-bezier(0.87, 0, 0.13, 1)'
const Slot = ({ digit, index }: Props) => {
return (
<span
css={{
position: 'relative',
top: `var(--top, 0)`,
display: 'inline-flex',
flexDirection: 'column',
transform: `var(--transform)`,
animation: `${transformNone} 6s ${easeInOutQuint} forwards`,
}}
style={{
['--top' as any]: -1 * digit + -10 * index + 'em',
['--transform' as any]: `translateY(calc((100% - ${10 - digit}em)))`,
}}
>
{[...Array(index + 1)].map((_, i) => (
<Fragment key={i}>
<span>0</span>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
</Fragment>
))}
</span>
)
}
export default Slot