You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.9 KiB
164 lines
4.9 KiB
import {
|
|
forwardRef,
|
|
memo,
|
|
useEffect,
|
|
useRef,
|
|
useState,
|
|
} from 'react'
|
|
|
|
import { isMobileDevice } from 'config'
|
|
|
|
import { defaultTheme } from 'features/Theme/config'
|
|
|
|
import {
|
|
Button,
|
|
Svg,
|
|
Path,
|
|
} from './styled'
|
|
|
|
const COLOR_PAIRS = [
|
|
['#FF0000', '#FFDF00'],
|
|
['#70FF00', '#0001FF'],
|
|
['#CD00FF', defaultTheme.colors.white],
|
|
[defaultTheme.colors.white, defaultTheme.colors.white],
|
|
[defaultTheme.colors.white, defaultTheme.colors.white],
|
|
[defaultTheme.colors.white, defaultTheme.colors.white],
|
|
['#FF0000', '#FFDF00'],
|
|
['#70FF00', '#0001FF'],
|
|
['#CD00FF', defaultTheme.colors.white],
|
|
[],
|
|
]
|
|
|
|
const OFFSET_CHANGE_SPEED = isMobileDevice ? 20 : 5
|
|
|
|
const ANIMATION_INTERVAL = 5000
|
|
|
|
const FREEZE_TIME = 6000
|
|
|
|
const PARTICLES_GENERATION_TIME = 1500
|
|
|
|
type Props = {
|
|
onClick: () => void,
|
|
setGenerateParticles: (state: boolean) => void,
|
|
}
|
|
|
|
const LikeButtonFC = forwardRef<HTMLButtonElement, Props>((
|
|
{
|
|
onClick,
|
|
setGenerateParticles,
|
|
},
|
|
ref,
|
|
) => {
|
|
const stop1Ref = useRef<SVGStopElement>(null)
|
|
const stop2Ref = useRef<SVGStopElement>(null)
|
|
|
|
const [canAnimate, setCanAnimate] = useState(false)
|
|
const [isDisabled, setIsDisabled] = useState(false)
|
|
const freezeTimeoutIdRef = useRef<NodeJS.Timeout | null>(null)
|
|
const generateTimeoutIdRef = useRef<NodeJS.Timeout | null>(null)
|
|
|
|
const startGenerateParticles = () => setGenerateParticles(true)
|
|
|
|
const stopGenerateParticles = () => setGenerateParticles(false)
|
|
|
|
const handleClick = () => {
|
|
onClick()
|
|
setIsDisabled(true)
|
|
startGenerateParticles()
|
|
|
|
freezeTimeoutIdRef.current = setTimeout(() => setIsDisabled(false), FREEZE_TIME)
|
|
generateTimeoutIdRef.current = setTimeout(stopGenerateParticles, PARTICLES_GENERATION_TIME)
|
|
}
|
|
|
|
useEffect(() => {
|
|
let requestAnimationId: number
|
|
let timeoutId: NodeJS.Timeout
|
|
let index = 0
|
|
let offset = 100
|
|
|
|
const animate = () => {
|
|
if (!stop1Ref.current || !stop2Ref.current) return
|
|
|
|
stop1Ref.current.setAttribute('offset', `${offset}%`)
|
|
stop2Ref.current.setAttribute('offset', `${offset}%`)
|
|
stop1Ref.current.setAttribute('stop-color', `${COLOR_PAIRS[index][0]}`)
|
|
stop2Ref.current.setAttribute('stop-color', `${COLOR_PAIRS[index][1]}`)
|
|
|
|
offset = Math.max(offset - OFFSET_CHANGE_SPEED, 0)
|
|
|
|
if (offset === 0) {
|
|
offset = 100
|
|
index = index + 1 <= COLOR_PAIRS.length - 1
|
|
? index + 1
|
|
: 0
|
|
}
|
|
|
|
if (index === COLOR_PAIRS.length - 1 && offset === 100) {
|
|
requestAnimationId && cancelAnimationFrame(requestAnimationId)
|
|
setCanAnimate(false)
|
|
index = 0
|
|
|
|
timeoutId = setTimeout(() => {
|
|
requestAnimationId = requestAnimationFrame(animate)
|
|
}, ANIMATION_INTERVAL)
|
|
} else {
|
|
requestAnimationId = requestAnimationFrame(animate)
|
|
setCanAnimate(true)
|
|
}
|
|
}
|
|
|
|
timeoutId = setTimeout(animate, ANIMATION_INTERVAL)
|
|
|
|
return () => {
|
|
timeoutId && clearTimeout(timeoutId)
|
|
requestAnimationId && cancelAnimationFrame(requestAnimationId)
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => () => {
|
|
freezeTimeoutIdRef.current && clearTimeout(freezeTimeoutIdRef.current)
|
|
generateTimeoutIdRef.current && clearTimeout(generateTimeoutIdRef.current)
|
|
}, [])
|
|
|
|
return (
|
|
<Button
|
|
disabled={isDisabled}
|
|
canAnimate={canAnimate}
|
|
ref={ref}
|
|
aria-label='Like this moment'
|
|
onClick={handleClick}
|
|
>
|
|
<Svg
|
|
width='30'
|
|
height='30'
|
|
viewBox='0 0 30 30'
|
|
fill='none'
|
|
>
|
|
<defs>
|
|
<linearGradient id='gradient'>
|
|
<stop
|
|
ref={stop1Ref}
|
|
offset='50%'
|
|
stopColor={defaultTheme.colors.white}
|
|
/>
|
|
<stop
|
|
ref={stop2Ref}
|
|
offset='50%'
|
|
stopColor={defaultTheme.colors.white}
|
|
/>
|
|
</linearGradient>
|
|
</defs>
|
|
|
|
<g>
|
|
<Path
|
|
fill={canAnimate ? 'url(#gradient)' : defaultTheme.colors.white}
|
|
d='M17.0939 0.686035C15.6852 0.686035 16.1589 3.64594 16.1589 3.64594C16.1589 3.64594 13.1482 11.8087 10.2685 13.9842C9.65136 14.6215 9.26489 15.3262 9.02179 15.9023C8.96569 16.0432 8.91583 16.178 8.87219 16.3006C8.67896 16.6867 8.26757 17.2811 7.38867 17.802L10.2685 30.1135C10.2685 30.1135 14.7252 30.6834 19.1945 30.5915C20.9835 30.7324 22.8784 30.7447 24.3868 30.426C29.5106 29.3536 28.2265 25.8422 28.2265 25.8422C30.9879 23.8015 29.4171 21.2522 29.4171 21.2522C31.873 18.7335 29.4607 16.6193 29.4607 16.6193C29.4607 16.6193 30.7884 14.5847 29.0743 13.0466C26.9363 11.1223 21.1331 12.4031 21.1331 12.4031C20.7279 12.4705 20.2978 12.5563 19.8365 12.6666C19.8365 12.6666 17.8294 13.5858 19.8365 7.59861C21.8499 1.61139 18.5026 0.686035 17.0939 0.686035ZM8.19893 29.2249L6.01728 19.0338C5.89261 18.4516 5.29422 17.9736 4.68959 17.9736H0.525765L0.519531 30.279H7.32003C7.9309 30.2851 8.32359 29.8071 8.19893 29.2249Z'
|
|
/>
|
|
</g>
|
|
</Svg>
|
|
</Button>
|
|
)
|
|
})
|
|
|
|
export const LikeButton = memo(LikeButtonFC)
|
|
|
|
|