From 77e408cad86709e75f748818aa3fe2e2bcdc4890 Mon Sep 17 00:00:00 2001 From: Chris Parsons <438676+chrisparsons83@users.noreply.github.com> Date: Sun, 22 Feb 2026 22:36:12 -0800 Subject: [PATCH] Make draft room fully usable on mobile (#30) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add bottom nav bar (Lobby/Board/Roster/Controls) with 56px touch targets - Add mobile card list view in AvailableParticipantsSection with 44px Draft/Queue buttons - Add round labels and sticky header row to DraftGridSection grid - Add mobile Sheet for commissioner actions in DraftGridSection (replaces right-click context menu) - Use useMediaQuery to render a single layout tree, eliminating duplicate component instances (previously both desktop and mobile layouts were always in the DOM) - Add compact header on mobile (text-lg vs text-3xl); hide commissioner buttons and Exit link in header on mobile — surfaced in Controls tab instead - Add "On Clock" bar on mobile showing current team and timer during active draft - Add "your turn" indicator dot on Lobby bottom nav tab - Default mobile tab to "board" for commissioner-only viewers - Fix sticky corner cell z-index in TeamsDraftedGrid (z-10 → z-20) - Fix round column spacer in DraftGridSection header not being sticky-left - Extract shared prop objects to eliminate copy-paste between layouts - Extract getParticipantState() helper to deduplicate participant render logic - Move MobileSheetData type and MOBILE_TABS array to module scope - Remove unnecessary non-null assertions in DraftGridSection Sheet handlers Co-authored-by: Claude Sonnet 4.6 --- .../draft/AvailableParticipantsSection.tsx | 149 +++++- app/components/draft/DraftGridSection.tsx | 129 +++++- app/components/draft/TeamsDraftedGrid.tsx | 4 +- app/hooks/useMediaQuery.ts | 15 + .../leagues/$leagueId.draft.$seasonId.tsx | 427 ++++++++++++------ 5 files changed, 550 insertions(+), 174 deletions(-) create mode 100644 app/hooks/useMediaQuery.ts diff --git a/app/components/draft/AvailableParticipantsSection.tsx b/app/components/draft/AvailableParticipantsSection.tsx index 0f47df9..a3c3ce9 100644 --- a/app/components/draft/AvailableParticipantsSection.tsx +++ b/app/components/draft/AvailableParticipantsSection.tsx @@ -2,6 +2,24 @@ import { Button } from "~/components/ui/button"; import { Badge } from "~/components/ui/badge"; import { ListPlus, ListX } from "lucide-react"; +function getParticipantState( + participant: { id: string; sport: { id: string } }, + draftedParticipantIds: Set, + queue: Array<{ participantId: string }>, + eligibility: { + eligibleSportIds: Set; + ineligibleReasons: Record; + } | null +) { + const isDrafted = draftedParticipantIds.has(participant.id); + const isInQueue = queue.some((item) => item.participantId === participant.id); + const isEligible = eligibility + ? eligibility.eligibleSportIds.has(participant.sport.id) + : true; + const ineligibleReason = eligibility?.ineligibleReasons[participant.sport.id]; + return { isDrafted, isInQueue, isEligible, ineligibleReason }; +} + interface AvailableParticipantsSectionProps { participants: Array<{ id: string; @@ -66,12 +84,12 @@ export function AvailableParticipantsSection({ className="w-full px-3 py-2 border rounded-md text-sm bg-background text-foreground" /> -
+
{/* Sport Filter Dropdown */}