From b451504d07743892256400f4133ac3d67990d19f Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Sun, 16 Aug 2026 09:35:19 -0600 Subject: [PATCH] Fix mobile display: RoomInfoPanel inaccessible, emoji picker overflow RoomInfoPanel was hard-gated behind !isMobile in ChatShellPage.tsx, but its trigger button ("Room details" in ChatPane.tsx) still rendered and toggled state unconditionally -- tapping it on mobile did nothing visible, with no way to reach room info/members/settings at all. Fixed by removing the gate and making the panel itself responsive: it renders as a full-screen fixed overlay below the mobile breakpoint instead of the desktop resizable aside (which stays exactly as before -- verified in-browser at both viewport sizes). Also found and fixed a second real bug during the mobile audit: the emoji picker's fixed 320px width overflows a 375px-wide viewport by 5px depending on trigger position (e.g. the composer's emoji button, near the left edge). Shrunk it to 280px with a proportionally reduced column count below 480px, rather than attempting dynamic position-aware sizing for a 5px overflow. Co-Authored-By: Claude Sonnet 5 --- frontend/src/components/EmojiPicker.css | 17 +++++++++++++++++ frontend/src/components/RoomInfoPanel.css | 17 +++++++++++++++++ frontend/src/components/RoomInfoPanel.tsx | 7 +++++-- frontend/src/pages/ChatShellPage.tsx | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/EmojiPicker.css b/frontend/src/components/EmojiPicker.css index c0f57d7..f60f9fe 100644 --- a/frontend/src/components/EmojiPicker.css +++ b/frontend/src/components/EmojiPicker.css @@ -88,3 +88,20 @@ .emoji-picker-item:hover { background: var(--ds-surface-2); } + +/* The picker is positioned absolutely relative to its trigger button, which + can sit close enough to a narrow viewport's edge that the full 320px + width runs off-screen (e.g. the composer's emoji trigger, near the left + edge, overflows the right edge on a 375px-wide phone). Shrinking the + fixed width -- rather than trying to dynamically reposition based on the + trigger's actual offset -- is enough margin for every real trigger + position in this app. */ +@media (max-width: 480px) { + .emoji-picker { + width: min(280px, calc(100vw - 32px)); + } + + .emoji-picker-grid { + grid-template-columns: repeat(7, 1fr); + } +} diff --git a/frontend/src/components/RoomInfoPanel.css b/frontend/src/components/RoomInfoPanel.css index e211f47..66d3854 100644 --- a/frontend/src/components/RoomInfoPanel.css +++ b/frontend/src/components/RoomInfoPanel.css @@ -28,6 +28,23 @@ background: color-mix(in srgb, var(--ds-accent) 40%, transparent); } +/* Below MOBILE_BREAKPOINT (frontend/src/hooks/useWindowWidth.ts), the + resizable-aside layout doesn't fit -- shown as a full-viewport overlay + instead. RoomInfoPanel.tsx skips its inline `style={{ width }}` on + mobile so this width rule isn't fighting an inline style, which would + otherwise win regardless of this media query's specificity. */ +@media (max-width: 859px) { + .room-info-panel { + position: fixed; + inset: 0; + z-index: 50; + width: 100%; + min-width: 0; + max-width: none; + border-left: none; + } +} + .room-info-header { display: flex; justify-content: space-between; diff --git a/frontend/src/components/RoomInfoPanel.tsx b/frontend/src/components/RoomInfoPanel.tsx index 0bb7b81..3ab423b 100644 --- a/frontend/src/components/RoomInfoPanel.tsx +++ b/frontend/src/components/RoomInfoPanel.tsx @@ -20,6 +20,7 @@ import { } from '../api/webhooks' import { useAuth } from '../context/AuthContext' import { useResizableWidth } from '../hooks/useResizableWidth' +import { MOBILE_BREAKPOINT, useWindowWidth } from '../hooks/useWindowWidth' import type { EventSubscription, EventType, @@ -57,6 +58,8 @@ export function RoomInfoPanel({ }: RoomInfoPanelProps) { const { user } = useAuth() const myRole = room.role + const windowWidth = useWindowWidth() + const isMobile = windowWidth < MOBILE_BREAKPOINT const { width, startResize } = useResizableWidth({ storageKey: 'room-info-panel-width', defaultWidth: 260, @@ -231,8 +234,8 @@ export function RoomInfoPanel({ } return ( -