refactored frontent to separate files

This commit is contained in:
2026-02-24 12:56:54 -07:00
parent 9dc6e9749c
commit 8bb086eac9
13 changed files with 369 additions and 309 deletions

View File

@@ -0,0 +1,89 @@
import { useEffect, useState } from "react";
import { useGameChannelContext } from "../contexts/useGameChannelContext";
interface Player {
x: number;
y: number;
}
interface GameState {
[playerId: string]: Player;
}
export const BoardDisplay = () => {
const { channel, isJoined } = useGameChannelContext();
const [players, setPlayers] = useState<GameState>({});
const [myPlayerId, setMyPlayerId] = useState<string | null>(null);
useEffect(() => {
if (!channel || !isJoined) return;
// Listen for game state updates
const ref = channel.on("game_state", (payload: { players: GameState }) => {
setPlayers(payload.players);
if (!myPlayerId && Object.keys(payload.players).length > 0) {
const playerIds = Object.keys(payload.players);
if (playerIds.length > 0) {
setMyPlayerId(playerIds[playerIds.length - 1]);
}
}
});
// Cleanup listener on unmount
return () => {
channel.off("game_state", ref);
};
}, [channel, isJoined, myPlayerId]);
return (
<div
style={{
position: "relative",
width: "800px",
height: "600px",
background: "#16213e",
margin: "50px auto",
border: "2px solid #0f3460",
overflow: "hidden",
}}
>
{Object.entries(players).map(([id, player]) => (
<div
key={id}
style={{
position: "absolute",
left: player.x,
top: player.y,
width: "20px",
height: "20px",
borderRadius: "50%",
background: id === myPlayerId ? "#e94560" : "#53a8b6",
border:
id === myPlayerId ? "3px solid #ff6b6b" : "2px solid #48d6e0",
transition: "all 0.1s linear",
transform: "translate(-50%, -50%)",
boxShadow:
id === myPlayerId ? "0 0 10px #e94560" : "0 0 5px #53a8b6",
}}
>
{id === myPlayerId && (
<div
style={{
position: "absolute",
top: "-25px",
left: "50%",
transform: "translateX(-50%)",
color: "#fff",
fontSize: "10px",
whiteSpace: "nowrap",
}}
>
You
</div>
)}
</div>
))}
</div>
);
};

View File

@@ -0,0 +1,26 @@
import { useWebSocketContext } from "../contexts/useWebSocketContext";
import { useGameChannelContext } from "../contexts/useGameChannelContext";
export const ConnectionStatus = () => {
const { connectionStatus } = useWebSocketContext();
const { channelStatus } = useGameChannelContext();
return (
<div
style={{
position: "absolute",
top: 10,
right: 10,
color: "white",
fontFamily: "monospace",
background: "rgba(0,0,0,0.5)",
padding: "10px",
borderRadius: "5px",
fontSize: "12px",
}}
>
<div>WebSocket: {connectionStatus}</div>
<div>Channel: {channelStatus}</div>
</div>
);
};

View File

@@ -0,0 +1,45 @@
import { useEffect, useRef } from "react";
import { useGameChannelContext } from "../contexts/useGameChannelContext";
export const UserInput = () => {
const { channel } = useGameChannelContext();
const keysPressed = useRef<Set<string>>(new Set());
useEffect(() => {
if (!channel) return;
const handleKeyDown = (e: KeyboardEvent) => {
const key = e.key.toLowerCase();
if (["w", "a", "s", "d"].includes(key)) {
e.preventDefault();
// Only send if not already pressed (prevent repeat)
if (!keysPressed.current.has(key)) {
keysPressed.current.add(key);
// Send to active channel
if (channel.state === "joined") {
channel.push("move", { direction: key });
}
}
}
};
const handleKeyUp = (e: KeyboardEvent) => {
const key = e.key.toLowerCase();
if (["w", "a", "s", "d"].includes(key)) {
keysPressed.current.delete(key);
}
};
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
return () => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("keyup", handleKeyUp);
};
}, [channel]);
return null;
};