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.
 
 
 
 
spa_instat_tv/src/features/StreamPlayer/components/LikeButton/index.tsx

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)