feat(ui): implement timed haiku rotation with staggered line reveal and group fade-out
- Added haiku display block under board with Framer Motion animations - Implement sequential line-by-line fade-in (staggered 2.4s per line) - Implement full-haiku fade-out using AnimatePresence keyed by haikuIndex - Added timed rotation logic using total animation duration (~14.4s) - Integrated getHaiku() random selector for new haiku each cycle - Ensured smooth transitions by updating haikuIndex on cycle end - Added no-winner condition wrapper to show haikus during gameplay
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useNakama } from "./providers/NakamaProvider";
|
||||
import getHaiku from "./utils/haikus";
|
||||
|
||||
interface BoardProps {
|
||||
board: string[][];
|
||||
@@ -47,6 +48,21 @@ export default function Board({
|
||||
status = isMyTurn ? "Your turn" : "Opponent's turn";
|
||||
}
|
||||
|
||||
const [haiku, setHaiku] = useState(getHaiku());
|
||||
const [haikuIndex, setHaikuIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const totalTime = 3 * 2400 + 6000 + 2400;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
const next = getHaiku();
|
||||
setHaiku(next);
|
||||
setHaikuIndex((i) => i + 1);
|
||||
}, totalTime);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [haikuIndex]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{matchId && (
|
||||
@@ -154,6 +170,58 @@ export default function Board({
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
{!winner && (
|
||||
<div
|
||||
style={{
|
||||
minHeight: "90px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginTop: "14px",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={haikuIndex}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: 2.4,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
lineHeight: "1.35",
|
||||
}}
|
||||
>
|
||||
{haiku.map((line, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
delay: i * 2.4, // line-by-line stagger timing
|
||||
duration: 10.0,
|
||||
ease: "easeOut",
|
||||
}}
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
color: "#f1c40f",
|
||||
fontWeight: 700,
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{line}
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Winner pulse animation */}
|
||||
{winner && (
|
||||
<motion.div
|
||||
|
||||
Reference in New Issue
Block a user