lottery page
This commit is contained in:
parent
fb6090d9fd
commit
e46670628f
|
|
@ -93,8 +93,7 @@ html {
|
|||
}
|
||||
|
||||
.text-stroke {
|
||||
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white,
|
||||
1px 1px 0 white;
|
||||
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
|
||||
}
|
||||
|
||||
.big-swiper .swiper-pagination-bullet {
|
||||
|
|
@ -122,20 +121,20 @@ html {
|
|||
|
||||
.small-swiper .swiper-button-next:after {
|
||||
color: white;
|
||||
content: url("/arrow-right-small.svg");
|
||||
content: url('/arrow-right-small.svg');
|
||||
}
|
||||
.small-swiper .swiper-button-prev:after {
|
||||
color: white;
|
||||
content: url("/arrow-left-small.svg");
|
||||
content: url('/arrow-left-small.svg');
|
||||
}
|
||||
|
||||
.big-swiper .swiper-button-next:after {
|
||||
color: white;
|
||||
content: url("/arrow-right-big.svg");
|
||||
content: url('/arrow-right-big.svg');
|
||||
}
|
||||
.big-swiper .swiper-button-prev:after {
|
||||
color: white;
|
||||
content: url("/arrow-left-big.svg");
|
||||
content: url('/arrow-left-big.svg');
|
||||
}
|
||||
|
||||
video {
|
||||
|
|
@ -188,15 +187,15 @@ big {
|
|||
@apply bg-[#E6E6FA] rounded-xl py-3 px-4 placeholder:text-[#BCBCD6] outline-none;
|
||||
}
|
||||
|
||||
.calendar [aria-label="Go to next month"] {
|
||||
.calendar [aria-label='Go to next month'] {
|
||||
@apply shadow-sm transition-all;
|
||||
}
|
||||
|
||||
.calendar [aria-label="Go to previous month"] {
|
||||
.calendar [aria-label='Go to previous month'] {
|
||||
@apply shadow-sm transition-all;
|
||||
}
|
||||
|
||||
.day-styles [name="day"] {
|
||||
.day-styles [name='day'] {
|
||||
@apply p-4 text-textDarkt leading-[140%] bg-purple-600 rounded-full;
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +261,7 @@ big {
|
|||
}
|
||||
|
||||
.wheel-circle {
|
||||
background: url("/wheel-circle.svg");
|
||||
background: url('/wheel-circle.svg');
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -296,7 +295,7 @@ big {
|
|||
} */
|
||||
|
||||
.slot-seperator {
|
||||
content: url("/dash.svg");
|
||||
content: url('/dash.svg');
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -315,7 +314,7 @@ big {
|
|||
|
||||
@media (max-width: 1024px) {
|
||||
.slot-seperator {
|
||||
content: url("/dash-md.svg");
|
||||
content: url('/dash-md.svg');
|
||||
@apply mx-2;
|
||||
}
|
||||
}
|
||||
|
|
@ -340,7 +339,7 @@ big {
|
|||
|
||||
@media (max-width: 426px) {
|
||||
.slot-seperator {
|
||||
content: url("/dash-sm.svg");
|
||||
content: url('/dash-sm.svg');
|
||||
@apply mx-2;
|
||||
}
|
||||
}
|
||||
|
|
@ -353,14 +352,27 @@ big {
|
|||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2); /* Add depth */
|
||||
}
|
||||
|
||||
.span.flash {
|
||||
animation: flash 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes dots-flash {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes confetti-move {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateX(0) translateY(0) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(calc(var(--end-x) / 2)) translateY(-30vh)
|
||||
rotate(180deg);
|
||||
transform: translateX(calc(var(--end-x) / 2)) translateY(-30vh) rotate(180deg);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { cn } from '@/lib/utils';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface AnimatedTextProps {
|
||||
|
|
@ -37,7 +38,9 @@ const AnimatedText = ({
|
|||
delay: i * wordDelay,
|
||||
ease: 'easeOut',
|
||||
}}
|
||||
className={`inline-block mx-2 ${wordClassName}`}>
|
||||
className={cn(`inline-block mx-2`, wordClassName, {
|
||||
'animate-dotsFlash': text === '...',
|
||||
})}>
|
||||
{word}
|
||||
</motion.span>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
const { width, height } = useWindowSize();
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
const [isSlotCounterAnimating, setIsSlotCounterAnimating] = useState(false);
|
||||
const [winnerSelectingStatus, setWinnerSelectingStatus] = useState<
|
||||
'not-selected' | 'is-selecting' | 'selected'
|
||||
>('not-selected');
|
||||
const [pendingWinner, setPendingWinner] = useState<LotteryWinnerDataSimplified | null>(null);
|
||||
|
||||
// Refs
|
||||
|
|
@ -34,6 +37,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
|
||||
// Add new state for display text
|
||||
const [displayText, setDisplayText] = useState<string>('...');
|
||||
const [winnerText, setWinnerText] = useState<string>('');
|
||||
|
||||
// Initialize winners from lottery data
|
||||
useEffect(() => {
|
||||
|
|
@ -85,7 +89,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
setDisplayText(`${winnerData.winner_no}-nji ýeňiji saýlanýar`);
|
||||
|
||||
// Start the sequence
|
||||
setIsSlotCounterAnimating(true);
|
||||
setWinnerSelectingStatus('is-selecting');
|
||||
setPendingWinner(winnerData);
|
||||
setCurrentNumber(winnerData.ticket);
|
||||
|
||||
|
|
@ -93,7 +97,9 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
await new Promise((resolve) => setTimeout(resolve, SLOT_COUNTER_DURATION));
|
||||
|
||||
// Update text to show winner's phone
|
||||
setDisplayText(winnerData.client);
|
||||
setDisplayText('The winner is');
|
||||
setWinnerText(winnerData.client);
|
||||
setWinnerSelectingStatus('selected');
|
||||
|
||||
setIsConfettiActive(true);
|
||||
setWinners((prev) => [...prev, winnerData]);
|
||||
|
|
@ -102,9 +108,11 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
setTimeout(() => {
|
||||
if (mountedRef.current) {
|
||||
setIsConfettiActive(false);
|
||||
setIsSlotCounterAnimating(false);
|
||||
// setIsSlotCounterAnimating(false);
|
||||
setWinnerSelectingStatus('not-selected');
|
||||
setPendingWinner(null);
|
||||
setDisplayText('...'); // Reset text
|
||||
setWinnerText('');
|
||||
}
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
|
|
@ -157,7 +165,6 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
Connection error. Please refresh the page.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isConfettiActive && (
|
||||
<div className="fixed top-0 left-0 z-50">
|
||||
<ReactConfetti
|
||||
|
|
@ -181,16 +188,32 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
|||
|
||||
<div className="container">
|
||||
<div
|
||||
className="flex flex-col items-center rounded-[32px] pt-[40px]"
|
||||
className="flex flex-col items-center rounded-[32px] gap-[40px] pt-[40px]"
|
||||
style={{ background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)' }}>
|
||||
<AnimatedText
|
||||
text={displayText}
|
||||
className="text-center text-[100px] leading-[108px] text-[#E65E19]"
|
||||
/>
|
||||
<div className="translate-y-1/2 z-10">
|
||||
{winnerSelectingStatus === 'not-selected' || winnerSelectingStatus === 'is-selecting' ? (
|
||||
<AnimatedText
|
||||
text={displayText}
|
||||
className="text-center flex items-center justify-center text-[100px] leading-[108px] text-[#E65E19]"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedText
|
||||
text={displayText}
|
||||
className="text-center text-[56px] leading-[64px] text-[#E65E19]"
|
||||
/>
|
||||
{winnerText && (
|
||||
<AnimatedText
|
||||
text={winnerText}
|
||||
className="text-center text-[80px] leading-[88px] text-[#E65E19]"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="z-10">
|
||||
<LotterySlotCounter numberString={currentNumber} isAnimating={isSlotCounterAnimating} />
|
||||
</div>
|
||||
<div className="flex gap-6 rounded-[12px] flex-1 w-full items-center justify-center md:pt-[122px] sm:pt-[90px] pt-[40px] sm:pb-[62px] pb-[32px] px-4">
|
||||
<div className="flex gap-6 rounded-[12px] flex-1 w-full items-center justify-center sm:pb-[62px] pb-[32px] px-4">
|
||||
<LotteryWinnersList winners={winners} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -77,13 +77,14 @@ const LotterySlotCounter = ({ numberString, isAnimating }: LotterySlotCounterPro
|
|||
<SlotCounter
|
||||
value={formattedNumber}
|
||||
startValue={formattedNumber}
|
||||
startValueOnce
|
||||
charClassName="rolling-number"
|
||||
separatorClassName="slot-seperator"
|
||||
duration={2}
|
||||
speed={2}
|
||||
startFromLastDigit
|
||||
delay={2}
|
||||
animateUnchanged={false}
|
||||
startFromLastDigit
|
||||
animateOnVisible={false}
|
||||
autoAnimationStart={false}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ export const theme = {
|
|||
|
||||
animation: {
|
||||
buble: 'buble 7s infinite',
|
||||
dotsFlash: 'dotsFlash 1.5s infinite',
|
||||
},
|
||||
|
||||
keyframes: {
|
||||
|
|
@ -221,6 +222,17 @@ export const theme = {
|
|||
transform: 'scale(1) translate(0%, 0%)',
|
||||
},
|
||||
},
|
||||
dotsFlash: {
|
||||
'0%': {
|
||||
opacity: '1',
|
||||
},
|
||||
'50%': {
|
||||
opacity: '0',
|
||||
},
|
||||
'100%': {
|
||||
opacity: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,80 +1,86 @@
|
|||
import type { Config } from "tailwindcss"
|
||||
import type { Config } from 'tailwindcss';
|
||||
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
darkMode: ['class'],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
],
|
||||
prefix: "",
|
||||
],
|
||||
prefix: '',
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
'2xl': '1400px',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
'accordion-down': {
|
||||
from: { height: '0' },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: '0' },
|
||||
},
|
||||
|
||||
'dots-flash': {
|
||||
from: { opacity: '0' },
|
||||
to: { opacity: '1' },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
'dots-flash': 'dots-flash 1s infinite;',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
} satisfies Config
|
||||
plugins: [require('tailwindcss-animate')],
|
||||
} satisfies Config;
|
||||
|
||||
export default config
|
||||
export default config;
|
||||
|
|
|
|||
Loading…
Reference in New Issue