mirror of
https://github.com/aljazceru/landscape-template.git
synced 2025-12-27 19:24:18 +01:00
158 lines
5.2 KiB
TypeScript
158 lines
5.2 KiB
TypeScript
import { MdLocalFireDepartment } from 'react-icons/md'
|
|
import Button from 'src/Components/Button/Button'
|
|
import { useAppSelector, usePressHolder } from 'src/utils/hooks'
|
|
import _throttle from 'lodash.throttle'
|
|
import { ComponentProps, useRef, useState } from 'react'
|
|
import styles from './vote-button-style.module.css'
|
|
import { random, randomItem } from 'src/utils/helperFunctions'
|
|
|
|
|
|
interface Particle {
|
|
id: string,
|
|
offsetX: number,
|
|
color: '#ff6a00' | '#ff7717' | '#ff6217' | '#ff8217' | '#ff5717'
|
|
animation: 'fly-spark-1' | 'fly-spark-2',
|
|
animationSpeed: 1 | 2 | 3,
|
|
scale: number
|
|
}
|
|
|
|
type Props = {
|
|
onVote: (Vote: number) => void
|
|
} & Omit<ComponentProps<typeof Button>, 'children'>
|
|
|
|
export default function VoteButton({ onVote = () => { }, ...props }: Props) {
|
|
const [voteCnt, setVoteCnt] = useState(0)
|
|
const voteCntRef = useRef(0);
|
|
const [sparks, setSparks] = useState<Particle[]>([]);
|
|
const [wasActive, setWasActive] = useState(false);
|
|
|
|
const isMobileScreen = useAppSelector(s => s.ui.isMobileScreen)
|
|
|
|
|
|
const { onPressDown, onPressUp } = usePressHolder(_throttle(() => {
|
|
const _incStep = (Math.ceil((voteCnt + 1) / 10) + 1) ** 2 * 10;
|
|
setVoteCnt(s => {
|
|
const newValue = s + _incStep;
|
|
voteCntRef.current = newValue;
|
|
return newValue;
|
|
})
|
|
|
|
const newSpark = {
|
|
id: Math.random().toString(),
|
|
offsetX: random(1, 99),
|
|
animation: randomItem(styles.fly_spark_1, styles.fly_spark_1),
|
|
animationSpeed: randomItem(1, 1.5, 2),
|
|
color: randomItem('#ff6a00', '#ff7717', '#ff6217', '#ff8217', '#ff5717'),
|
|
scale: random(1.2, 2.2)
|
|
};
|
|
|
|
// if on mobile screen, reduce number of sparks particles to 60%
|
|
if (!isMobileScreen || Math.random() > .4) {
|
|
setSparks(oldSparks => [...oldSparks, newSpark])
|
|
setTimeout(() => {
|
|
setSparks(s => {
|
|
return s.filter(spark => spark.id !== newSpark.id)
|
|
})
|
|
|
|
}, newSpark.animationSpeed * 1000)
|
|
}
|
|
|
|
}, 100), 100);
|
|
|
|
const handlePressDown = () => {
|
|
setWasActive(true);
|
|
onPressDown();
|
|
}
|
|
|
|
const handlePressUp = (event?: any) => {
|
|
if (!wasActive) return;
|
|
|
|
setWasActive(false);
|
|
if (event?.preventDefault) event.preventDefault();
|
|
onPressUp();
|
|
if (voteCnt === 0)
|
|
onVote(10);
|
|
else
|
|
setTimeout(() => {
|
|
setSparks([]);
|
|
onVote(voteCntRef.current);
|
|
setVoteCnt(0);
|
|
voteCntRef.current = 0;
|
|
}, 500)
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
onMouseDown={handlePressDown}
|
|
onMouseUp={handlePressUp}
|
|
onMouseLeave={handlePressUp}
|
|
|
|
onTouchStart={handlePressDown}
|
|
onTouchEnd={handlePressUp}
|
|
size='md'
|
|
color='none'
|
|
className={`${styles.vote_button} border relative 100 my-16 noselect`}
|
|
style={{
|
|
"--scale": voteCnt,
|
|
} as any}
|
|
{...props}
|
|
>
|
|
Hold To Vote !!! <MdLocalFireDepartment className='text-fire' />
|
|
|
|
<span
|
|
className={styles.vote_counter}
|
|
>{voteCnt}</span>
|
|
|
|
<div
|
|
className={styles.spark}
|
|
style={{
|
|
"--offsetX": 23,
|
|
"--animationSpeed": 3,
|
|
"--scale": 1,
|
|
"animationIterationCount": 'infinite',
|
|
"animationName": styles.fly_spark_1,
|
|
"animationDelay": '1.1s',
|
|
color: '#ff6a00'
|
|
} as any}
|
|
><MdLocalFireDepartment className='' /></div>
|
|
<div
|
|
className={styles.spark}
|
|
style={{
|
|
"--offsetX": 50,
|
|
"--animationSpeed": 2.2,
|
|
"--scale": 1,
|
|
"animationIterationCount": 'infinite',
|
|
"animationName": styles.fly_spark_2,
|
|
"animationDelay": '0.4s',
|
|
color: '#ff6a00'
|
|
} as any}
|
|
><MdLocalFireDepartment className='' /></div>
|
|
<div
|
|
className={styles.spark}
|
|
style={{
|
|
"--offsetX": 70,
|
|
"--animationSpeed": 2.5,
|
|
"--scale": 1,
|
|
"animationIterationCount": 'infinite',
|
|
"animationName": styles.fly_spark_1,
|
|
color: '#ff6a00'
|
|
} as any}
|
|
><MdLocalFireDepartment className='' /></div>
|
|
{sparks.map(spark =>
|
|
<div
|
|
key={spark.id}
|
|
className={styles.spark}
|
|
style={{
|
|
"--offsetX": spark.offsetX,
|
|
"--animationSpeed": spark.animationSpeed,
|
|
"--scale": spark.scale,
|
|
"animationName": spark.animation,
|
|
"color": spark.color
|
|
} as any}
|
|
><MdLocalFireDepartment className='' /></div>)
|
|
}
|
|
</Button>
|
|
|
|
)
|
|
}
|