diff --git a/api/src/games/ws-handler.ts b/api/src/games/ws-handler.ts
index 57ea12a..b34d065 100644
--- a/api/src/games/ws-handler.ts
+++ b/api/src/games/ws-handler.ts
@@ -77,15 +77,19 @@ export function handleGameMessage(msg: GameWsClientMessage, ctx: WsContext): voi
}
const spectatorView = roomManager.getSpectatorView(msg.roomId);
- ctx.publish(`room:${msg.roomId}`, JSON.stringify({ type: "GAME_UPDATE", roomId: msg.roomId, state: spectatorView }));
+ const updateMsg = JSON.stringify({ type: "GAME_UPDATE", roomId: msg.roomId, state: spectatorView });
+ ctx.publish(`room:${msg.roomId}`, updateMsg);
+ ctx.send(updateMsg);
if (result.gameOver) {
- ctx.publish(`room:${msg.roomId}`, JSON.stringify({
+ const endedMsg = JSON.stringify({
type: "GAME_ENDED",
roomId: msg.roomId,
winner: result.gameOver.winner,
reason: result.gameOver.reason,
- }));
+ });
+ ctx.publish(`room:${msg.roomId}`, endedMsg);
+ ctx.send(endedMsg);
ctx.publish("lobby", JSON.stringify({ type: "ROOM_LIST_UPDATE", rooms: roomManager.listRooms() }));
}
break;
diff --git a/panel/src/components/Layout.tsx b/panel/src/components/Layout.tsx
index f4231d2..a161919 100644
--- a/panel/src/components/Layout.tsx
+++ b/panel/src/components/Layout.tsx
@@ -13,8 +13,10 @@ import {
ChevronRight,
Gamepad2,
Trophy,
+ Menu,
+ X,
} from "lucide-react";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { cn } from "../lib/utils";
import type { AuthUser } from "../lib/useAuth";
@@ -54,6 +56,7 @@ export default function Layout({
children: React.ReactNode;
}) {
const [collapsed, setCollapsed] = useState(false);
+ const [mobileOpen, setMobileOpen] = useState(false);
const location = useLocation();
const navigate = useNavigate();
@@ -63,6 +66,11 @@ export default function Layout({
? `https://cdn.discordapp.com/avatars/${user.discordId}/${user.avatar}.png?size=64`
: null;
+ // Close mobile drawer on route change
+ useEffect(() => {
+ setMobileOpen(false);
+ }, [location.pathname]);
+
function isActive(path: string): boolean {
if (path === "/admin" && location.pathname === "/admin") return true;
if (path === "/dashboard" && location.pathname === "/dashboard") return true;
@@ -70,75 +78,123 @@ export default function Layout({
return false;
}
+ function handleNav(path: string) {
+ navigate(path);
+ setMobileOpen(false);
+ }
+
+ const sidebarContent = (
+ <>
+
+
+
+ {(!collapsed || mobileOpen) && (
+
+ {avatarUrl ? (
+

+ ) : (
+
+ {user.username[0]?.toUpperCase()}
+
+ )}
+
+
+ )}
+
+
+ {/* Collapse toggle only on desktop */}
+
+
+
+ >
+ );
+
return (
+ {/* Mobile header bar */}
+
+
+
Aurora
+
+
+ {/* Mobile overlay */}
+ {mobileOpen && (
+
setMobileOpen(false)}
+ />
+ )}
+
+ {/* Sidebar - mobile drawer + desktop fixed */}