update: make some improvements to the vote-btn, remove wrapper card for post-details page on mobile

This commit is contained in:
MTG2000
2022-07-21 17:29:06 +03:00
parent ed874f1db3
commit 054853a42d
4 changed files with 58 additions and 39 deletions

View File

@@ -1,7 +1,7 @@
import { MdLocalFireDepartment } from 'react-icons/md'
import Button from 'src/Components/Button/Button'
import { useAppSelector, usePressHolder, useResizeListener } from 'src/utils/hooks'
import { ComponentProps, useRef, useState } from 'react'
import { ComponentProps, SyntheticEvent, useRef, useState } from 'react'
import styles from './styles.module.scss'
import { random, randomItem, numberFormatter } from 'src/utils/helperFunctions'
import { useDebouncedCallback, useMountEffect, useThrottledCallback } from '@react-hookz/web'
@@ -58,9 +58,9 @@ export default function VoteButton({
fillType = 'leftRight',
direction = 'horizontal',
disableCounter = false,
disableShake = false,
disableShake = true,
dense = false,
resetCounterOnRelease: resetCounterOnReleaseProp = false,
resetCounterOnRelease = true,
...props }: Props) {
const [voteCnt, setVoteCnt] = useState(0)
const voteCntRef = useRef(0);
@@ -76,22 +76,52 @@ export default function VoteButton({
const [btnState, setBtnState] = useState<BtnState>('ready');
const isMobileScreen = useAppSelector(s => s.ui.isMobileScreen);
const resetCounterOnRelease = resetCounterOnReleaseProp;
const doVote = useDebouncedCallback(() => {
setBtnState('loading');
const amount = voteCntRef.current;
onVote(amount, {
onSuccess: () => setBtnState("success"),
onSuccess: () => {
setBtnState("success");
spawnSparks(10);
},
onError: () => setBtnState('fail'),
onSetteled: () => {
setVoteCnt(v => v - amount);
setTimeout(() => setBtnState("ready"), 2000);
setTimeout(() => {
setBtnState("ready")
if (resetCounterOnRelease) {
setIncrementsCount(0);
totalIncrementsCountRef.current = 0;
currentIncrementsCountRef.current = 0;
}
voteCntRef.current = 0;
}, 2000);
}
});
voteCntRef.current = 0;
}, [], 1500)
}, [], 1500);
const spawnSparks = (cnt = 5) => {
const newSparks = Array(cnt).fill(0).map((_, idx) => ({
id: (Math.random() + 1).toString(),
offsetX: random(-10, 99),
offsetY: random(10, 90),
animation: randomItem(styles.fly_spark_1, styles.fly_spark_1),
animationSpeed: randomItem(1, 1.5, 2),
color: `hsl(0deg 86% ${random(50, 63)}%)`,
scale: random(1, 1.5)
}))
// if on mobile screen, reduce number of sparks particles to 60%
setSparks(oldSparks => [...oldSparks, ...newSparks])
setTimeout(() => {
setSparks(s => {
return s.filter(spark => !newSparks.some(newSpark => newSpark.id === spark.id))
})
}, 2 * 1000)
}
const clickIncrement = () => {
if (!disableShake)
@@ -120,33 +150,17 @@ export default function VoteButton({
return newValue;
})
if (totalIncrementsCountRef.current && totalIncrementsCountRef.current % 5 === 0) {
const newSparks = Array(5).fill(0).map((_, idx) => ({
id: (Math.random() + 1).toString(),
offsetX: random(-10, 99),
offsetY: random(40, 90),
animation: randomItem(styles.fly_spark_1, styles.fly_spark_1),
animationSpeed: randomItem(1, 1.5, 2),
color: `hsl(0deg 86% ${random(50, 63)}%)`,
scale: random(1, 1.5)
}))
// Each time the button make 5 increments, spawn some flames
if (totalIncrementsCountRef.current && totalIncrementsCountRef.current % 5 === 0)
spawnSparks(5);
// if on mobile screen, reduce number of sparks particles to 60%
setSparks(oldSparks => [...oldSparks, ...newSparks])
setTimeout(() => {
setSparks(s => {
return s.filter(spark => !newSparks.some(newSpark => newSpark.id === spark.id))
})
}, 2 * 1000)
}
doVote();
}
const onHold = useThrottledCallback(clickIncrement, [], 150)
const { onPressDown, onPressUp, isHolding } = usePressHolder(onHold, 100);
const { onPressDown, onPressUp } = usePressHolder(onHold, 200);
const handlePressDown = () => {
if (btnState !== 'ready' && btnState !== 'voting') return;
@@ -155,19 +169,13 @@ export default function VoteButton({
onPressDown();
}
const handlePressUp = (event?: any) => {
const handlePressUp = (event?: SyntheticEvent) => {
if (btnState !== 'voting') return;
if (event?.preventDefault) event.preventDefault();
onPressUp();
onHold();
if (resetCounterOnRelease)
if (!isHolding) {
currentIncrementsCountRef.current = 0;
} else
setTimeout(() =>
currentIncrementsCountRef.current = 0, 150)
}
useMountEffect(() => {
@@ -197,7 +205,7 @@ export default function VoteButton({
<button
onMouseDown={handlePressDown}
onMouseUp={handlePressUp}
onMouseLeave={handlePressUp}
onMouseLeave={() => onPressUp()}
onTouchStart={handlePressDown}
onTouchEnd={handlePressUp}
@@ -264,7 +272,7 @@ export default function VoteButton({
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className={styles.success}>
Thanks!!
+{numberFormatter(voteCntRef.current)}
</motion.div>
}
</AnimatePresence>

View File

@@ -5,6 +5,11 @@
--bg-color: hsl(0deg 86% max(calc((93 - var(--increments) / 3) * 1%), 68%));
/* transition: background-color 1s; */
/* background-color: hsl(25, 100%, max(calc((95 - var(--scale) / 4) * 1%), 63%)); */
transition: transform 0.1s ease-out;
&:active {
transform: scale(0.9);
}
}
.btn_content.clicked_1 {

View File

@@ -25,7 +25,7 @@ export default function StoryPageContent({ story }: Props) {
return (
<>
<div id="content" className="bg-white p-32 border-2 border-gray-200 rounded-16 relative">
<div id="content" className="bg-white md:p-32 md:border-2 border-gray-200 rounded-16 relative">
{story.cover_image &&

View File

@@ -3,6 +3,7 @@
$screen-xs-min: 320px;
@import "./tw.scss", "./shared.scss", "./vendors.scss", "./scrollbar.scss";
@import "/src/styles/mixins/index.scss";
html {
scrollbar-gutter: stable;
@@ -14,7 +15,12 @@ body {
}
.page-container {
width: calc(min(100% - 32px, 1440px));
--padding: 16px;
@include gt-sm {
--padding: 24px;
}
width: calc(min(100%, 1440px) - 2 * var(--padding));
margin: 0 auto;
padding: 32px 0;
}