- Disabled game mode selector while matchmaking is active.

- Updated match start header in Player to match new UI theme.
- Reworked TicTacToe layout with dark theme, centered layout, and Framer Motion transitions.
- Added animated header bar and unified styling across Player, Board, and main screen.
- Improved opacity/transition behavior for the board based on session state.
- Cleaned up unused code and reorganized match data callback handling.
This commit is contained in:
2025-11-29 03:05:33 +05:30
parent 601048f0e4
commit 0d167b8ccc
2 changed files with 75 additions and 29 deletions

View File

@@ -147,6 +147,7 @@ export default function Player({
<select
value={selectedMode}
disabled={isQueueing}
onChange={(e) => setSelectedMode(e.target.value)}
style={{
padding: "8px",
@@ -269,8 +270,8 @@ export default function Player({
textAlign: "center",
}}
>
<h2 style={{ fontSize: "22px", color: "#f1c40f" }}>
Go {session.username}!
<h2 style={{ marginBottom: "10px" }}>
Go, <span style={{ color: "#2ecc71" }}>{session.username}</span>
</h2>
</motion.div>
)}

View File

@@ -1,9 +1,8 @@
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { useNakama } from "./providers/NakamaProvider";
import Board from "./Board";
import Player from "./Player";
// import { Match } from "@heroiclabs/nakama-js";
// import MatchList from "./MatchList";
export default function TicTacToe() {
const [board, setBoard] = useState<string[][]>([
@@ -13,9 +12,13 @@ export default function TicTacToe() {
]);
const [turn, setTurn] = useState<number>(0);
const [winner, setWinner] = useState<string | null>(null);
// const [openMatches, setOpenMatches] = useState<Match[]>([]);
const [players, setPlayers] = useState<string[]>([]);
const { sendMatchData, onMatchData, matchId, session } = useNakama();
// ------------------------------------------
// MATCH DATA CALLBACK (from Player component)
// ------------------------------------------
function onMatchDataCallback(msg: { opCode: number; data: any }) {
console.log("[Match Data]", msg);
@@ -26,20 +29,10 @@ export default function TicTacToe() {
setBoard(state.board);
setTurn(state.turn);
setWinner(state.winner || null);
// new:
setPlayers(state.players || []);
}
}
const {
onMatchData,
sendMatchData,
// listOpenMatches,
matchId,
session,
} = useNakama();
useEffect(() => {
onMatchData(onMatchDataCallback);
}, [onMatchData]);
@@ -73,13 +66,64 @@ export default function TicTacToe() {
}
return (
<div>
<h1>Tic Tac Toe Multiplayer</h1>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
style={{
minHeight: "100vh",
background: "#060606",
padding: "30px 0",
color: "white",
display: "flex",
flexDirection: "column",
alignItems: "center"
}}
>
{/* Game header bar */}
<motion.h1
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
style={{
marginBottom: "20px",
padding: "10px 20px",
background: "rgba(255,255,255,0.03)",
borderRadius: "16px",
boxShadow: "0 0 20px rgba(255,255,255,0.05)",
backdropFilter: "blur(5px)",
fontSize: "26px",
fontWeight: 700,
letterSpacing: "1px",
}}
>
Tic Tac Toe Multiplayer
</motion.h1>
<Player
onMatchDataCallback={onMatchDataCallback}
/>
{/* Player component panel */}
<div
style={{
marginBottom: "25px",
width: "100%",
display: "flex",
justifyContent: "center"
}}
>
<Player onMatchDataCallback={onMatchDataCallback} />
</div>
{/* Board display container */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: session ? 1 : 0.2, y: session ? 0 : 20 }}
transition={{ duration: 0.4 }}
style={{
padding: "20px",
background: "rgba(255,255,255,0.03)",
borderRadius: "20px",
boxShadow: "0 6px 20px rgba(0,0,0,0.4)",
minWidth: "300px",
}}
>
<Board
board={board}
turn={turn}
@@ -88,6 +132,7 @@ export default function TicTacToe() {
myUserId={session?.user_id ?? null}
onCellClick={handleCellClick}
/>
</div>
</motion.div>
</motion.div>
);
}