From a7c0900c3bcc7cc768baf862f5f2863264319a2f Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Fri, 12 Jun 2026 01:12:26 +0330 Subject: [PATCH] ui: unified rounded navbar everywhere, vertical home actions, no bot disconnect spam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - NavRail: one rounded "pill" tab bar on every screen (matches home). ScreenShell lays out as a portrait column and floats the nav with margins + safe-area; dropped the landscape side-rail variant. - Home: the three mode cards now stack vertically as full-width rows (portrait friendly) instead of a 3-up landscape row. - Disconnect: removed the simulated random opponent "disconnect" in local games (DISCONNECT_CHANCE) and the in-game DisconnectBanner — bots/filled seats just auto-play their turn; no message, no pause. (Live reconnect grace still tracked internally but no longer shows a banner.) Co-Authored-By: Claude Opus 4.8 --- src/components/GameTable.tsx | 30 +------------------------- src/components/HomeScreen.tsx | 26 +++++++++++----------- src/components/online/NavRail.tsx | 25 +++++++-------------- src/components/online/ScreenHeader.tsx | 15 +++++++++---- src/lib/game-store.ts | 29 +++++-------------------- 5 files changed, 39 insertions(+), 86 deletions(-) diff --git a/src/components/GameTable.tsx b/src/components/GameTable.tsx index e405e36..12e8c4f 100644 --- a/src/components/GameTable.tsx +++ b/src/components/GameTable.tsx @@ -1,7 +1,7 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { Crown, Flag, LogOut, SmilePlus, Volume2, VolumeX, WifiOff, Zap } from "lucide-react"; +import { Crown, Flag, LogOut, SmilePlus, Volume2, VolumeX, Zap } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { useGameStore } from "@/lib/game-store"; import { useSoundStore } from "@/lib/sound-store"; @@ -210,7 +210,6 @@ export function GameTable({ - @@ -734,33 +733,6 @@ function TurnTimer() { ); } -function DisconnectBanner() { - const seat = useGameStore((s) => s.disconnectedSeat); - const deadline = useGameStore((s) => s.reconnectDeadline); - const name = useGameStore((s) => (seat != null ? s.seatPlayers[seat]?.name : null)); - const secs = useCountdown(deadline); - const { t } = useI18n(); - return ( - - {seat != null && ( - -
- - - {t("dc.waiting", { name: name ?? "", s: secs ?? 0 })} - -
-
- )} -
- ); -} - /* ----------------------------- Reactions ------------------------------ */ const REACTION_POS: Record = { diff --git a/src/components/HomeScreen.tsx b/src/components/HomeScreen.tsx index 95a8a3c..42a3c68 100644 --- a/src/components/HomeScreen.tsx +++ b/src/components/HomeScreen.tsx @@ -104,11 +104,11 @@ export function HomeScreen() { {t("app.subtitle")} - {/* mode cards */} + {/* mode cards — stacked vertically for portrait */} - {badge && ( - - {badge} - - )} {icon} - {name} - - {desc} + + {name} + + {desc} + + {badge && ( + + {badge} + + )} ); } diff --git a/src/components/online/NavRail.tsx b/src/components/online/NavRail.tsx index f0c2d11..f7fbc78 100644 --- a/src/components/online/NavRail.tsx +++ b/src/components/online/NavRail.tsx @@ -11,9 +11,9 @@ import { cn } from "@/lib/cn"; type Item = { key: Screen; icon: typeof Home; label: string; authed?: boolean; badge?: number }; /** - * UNO-style primary navigation. A vertical rail pinned to the side in landscape - * (the app's main orientation) and a bottom tab bar in portrait. Active section - * is highlighted gold and pulled forward. + * UNO-style primary navigation: a single rounded "pill" tab bar floating at the + * bottom on every screen (portrait-first). Active section is highlighted gold. + * `bottom` only drops the redundant "home" item when used on the home screen. */ export function NavRail({ bottom = false }: { bottom?: boolean }) { const screen = useUIStore((s) => s.screen); @@ -48,16 +48,8 @@ export function NavRail({ bottom = false }: { bottom?: boolean }) { return (