From 154e35ef9fd99cfaabed0599ff8ffa6a71bbd7c4 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 18 Jul 2026 23:22:59 -0400 Subject: [PATCH] =?UTF-8?q?fix(mobile):=20deep-audit=20structural=20fixes?= =?UTF-8?q?=20=E2=80=94=20dialogs,=20toasts,=20call=20bar=20(N1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the 6-agent deep per-feature audit. Mobile-gated / consistency fixes; desktop unchanged except two intentional dialog-width normalizations noted below. - In-call control bar: wrap="Wrap" on the SequenceCard so the compact two-group row wraps on the narrowest phones (<=390px) instead of pushing End off-screen (M1 fixed the 500-750px band; this covers narrower). Desktop stays one row. - In-call soundboard popout: clamp maxWidth to the viewport (like M5's screenshare popover) so it can't overflow a narrow phone. - Report-Message dialog + "Seen by" (EventReaders) modals (Message.tsx x2 + RoomViewFollowing): add useModalStyle so they go full-screen on mobile like their sibling report/receipt modals (they floated as fixed cards before). - In-app toast container: full-width toasts inset from both edges on mobile (ScreenSize.Mobile); a fixed 280-340px card previously overflowed a narrow phone. Desktop byte-identical (bottom-right floating card). - Policy-list tabs + audio-controls rows: wrap="Wrap" (inert on desktop). Intentional desktop deltas (normalizing to existing sibling modals, verified by two review passes as consistent, not regressions): Report dialog max-width 380->480px; EventReaders modals 460->360px. Co-Authored-By: Claude Opus 4.8 --- src/app/components/media/MediaControls.tsx | 2 +- src/app/features/call/CallControls.tsx | 1 + src/app/features/call/CallSoundboard.tsx | 7 ++++++- .../features/room-settings/PolicyListViewer.tsx | 2 +- src/app/features/room/RoomViewFollowing.tsx | 4 +++- src/app/features/room/message/Message.tsx | 7 +++++-- src/app/features/toast/LotusToastContainer.tsx | 17 +++++++++++++---- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/app/components/media/MediaControls.tsx b/src/app/components/media/MediaControls.tsx index fb8565d22..e66dfe5db 100644 --- a/src/app/components/media/MediaControls.tsx +++ b/src/app/components/media/MediaControls.tsx @@ -11,7 +11,7 @@ export const MediaControl = as<'div', MediaControlProps>( ({ before, after, leftControl, rightControl, children, ...props }, ref) => ( {before && {before}} - + {leftControl} diff --git a/src/app/features/call/CallControls.tsx b/src/app/features/call/CallControls.tsx index 2de1aa27c..f4ebf661e 100644 --- a/src/app/features/call/CallControls.tsx +++ b/src/app/features/call/CallControls.tsx @@ -387,6 +387,7 @@ export function CallControls({ callEmbed }: CallControlsProps) { radii="500" alignItems="Center" justifyContent="SpaceBetween" + wrap="Wrap" > diff --git a/src/app/features/call/CallSoundboard.tsx b/src/app/features/call/CallSoundboard.tsx index 3216d784c..56afb267f 100644 --- a/src/app/features/call/CallSoundboard.tsx +++ b/src/app/features/call/CallSoundboard.tsx @@ -135,7 +135,12 @@ export function CallSoundboard({ callEmbed }: CallSoundboardProps) { escapeDeactivates: stopPropagation, }} > - + {/* Tabs */} - + ( ({ className, room, ...props }, ref) => { const mx = useMatrixClient(); const [open, setOpen] = useState(false); + const modalStyle = useModalStyle(360); const latestEvent = useRoomLatestRenderedEvent(room); const latestEventReaders = useRoomEventReaders(room, latestEvent?.getId()); const names = latestEventReaders @@ -55,7 +57,7 @@ export const RoomViewFollowing = as<'div', RoomViewFollowingProps>( escapeDeactivates: stopPropagation, }} > - + setOpen(false)} /> diff --git a/src/app/features/room/message/Message.tsx b/src/app/features/room/message/Message.tsx index ac3c6a783..7bfe2d761 100644 --- a/src/app/features/room/message/Message.tsx +++ b/src/app/features/room/message/Message.tsx @@ -65,6 +65,7 @@ import { MessageLayout, MessageSpacing } from '../../../state/settings'; import { msgTranslationActiveAtomFamily } from '../../../state/translation'; import { chromeTranslationEngine } from '../../../utils/translation/chromeEngine'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; +import { useModalStyle } from '../../../hooks/useModalStyle'; import { useRecentEmoji } from '../../../hooks/useRecentEmoji'; import * as css from './styles.css'; import { MsgAppearClass, SendingSpinClass } from '../../../styles/Animations.css'; @@ -260,6 +261,7 @@ export const MessageReadReceiptItem = as< } >(({ room, eventId, onClose, ...props }, ref) => { const [open, setOpen] = useState(false); + const modalStyle = useModalStyle(360); const handleClose = () => { setOpen(false); @@ -278,7 +280,7 @@ export const MessageReadReceiptItem = as< escapeDeactivates: stopPropagation, }} > - + @@ -674,6 +676,7 @@ export const MessageReportItem = as< >(({ room, mEvent, onClose, ...props }, ref) => { const mx = useMatrixClient(); const [open, setOpen] = useState(false); + const modalStyle = useModalStyle(480); const [reportState, reportMessage] = useAsyncCallback( useCallback( (eventId: string, score: number, reason: string) => @@ -715,7 +718,7 @@ export const MessageReportItem = as< escapeDeactivates: stopPropagation, }} > - +
| null>(null); useEffect(() => { @@ -80,8 +82,11 @@ function ToastCard({ toast }: ToastCardProps) { }`, borderRadius: config.radii.R400, padding: `${config.space.S300} ${config.space.S400}`, - minWidth: '280px', - maxWidth: '340px', + // Full-width on phones (the container spans the viewport there); a fixed + // 280-340px card would otherwise overflow a narrow screen. + minWidth: isMobile ? 0 : '280px', + maxWidth: isMobile ? 'none' : '340px', + width: isMobile ? '100%' : undefined, boxShadow: lotusTerminal ? toast.sticky ? 'var(--lt-box-glow-cyan)' @@ -216,13 +221,17 @@ export function LotusToastContainer() { }, []); const toasts = useAtomValue(toastQueueAtom); + const isMobile = useScreenSize() === ScreenSize.Mobile; if (toasts.length === 0) return null; const containerStyle: CSSProperties = { position: 'fixed', - bottom: '1.5rem', - right: '1.5rem', + // Span the width just inside the screen edges on a phone (so full-width + // cards fit); float bottom-right on desktop. + bottom: isMobile ? config.space.S200 : '1.5rem', + right: isMobile ? config.space.S200 : '1.5rem', + left: isMobile ? config.space.S200 : undefined, zIndex: zIndices.toast, display: 'flex', flexDirection: 'column',