fix(mobile): full-screen media viewers + touch-pan for zoomed images (M3)
Mobile-audit batch 3. All changes mobile-gated (@media <=750px) so desktop is unchanged. - ModalWide: fill the phone screen (100vw/100vh, no radius) at <=750px instead of floating as an 85vw card. This also full-screens the file/PDF viewer and the avatar-crop editor on mobile (they share ModalWide) — intended. - UserHero avatar viewer: new mobile-only ModalMobileFull class (no desktop effect) so it goes edge-to-edge on phones like the timeline lightbox. - usePan: add touch support (single-finger drag, cleaned up on touchend/cancel/unmount) alongside the unchanged mouse path, so a zoomed image can be panned on a phone. Wired into ImageViewer and the MediaGallery lightbox. Two review passes: mouse path byte-for-byte unchanged; desktop provably unaffected; touch is gated to zoom!=1 so a non-zoomed image never hijacks swipe/scroll. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ export const ImageViewer = as<'div', ImageViewerProps>(
|
||||
const { t } = useTranslation();
|
||||
const saveFile = useSaveFile();
|
||||
const { zoom, zoomIn, zoomOut, setZoom } = useZoom(0.2);
|
||||
const { pan, cursor, onMouseDown } = usePan(zoom !== 1);
|
||||
const { pan, cursor, onMouseDown, onTouchStart } = usePan(zoom !== 1);
|
||||
|
||||
const handleDownload = async () => {
|
||||
const fileContent = await downloadMedia(src);
|
||||
@@ -100,6 +100,7 @@ export const ImageViewer = as<'div', ImageViewerProps>(
|
||||
src={src}
|
||||
alt={alt}
|
||||
onMouseDown={onMouseDown}
|
||||
onTouchStart={onTouchStart}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { UserAvatar } from '../user-avatar';
|
||||
import colorMXID from '../../../util/colorMXID';
|
||||
import { getMxIdLocalPart } from '../../utils/matrix';
|
||||
import { BreakWord, LineClamp2, LineClamp3 } from '../../styles/Text.css';
|
||||
import { ModalMobileFull } from '../../styles/Modal.css';
|
||||
import { UserPresence } from '../../hooks/useUserPresence';
|
||||
import { AvatarPresence, PresenceBadge } from '../presence';
|
||||
import { AvatarDecoration } from '../avatar-decoration/AvatarDecoration';
|
||||
@@ -83,7 +84,11 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
||||
escapeDeactivates: stopPropagation,
|
||||
}}
|
||||
>
|
||||
<Modal size="500" onContextMenu={(evt: any) => evt.stopPropagation()}>
|
||||
<Modal
|
||||
size="500"
|
||||
className={ModalMobileFull}
|
||||
onContextMenu={(evt: any) => evt.stopPropagation()}
|
||||
>
|
||||
<ImageViewer
|
||||
src={viewAvatar}
|
||||
alt={userId}
|
||||
|
||||
Reference in New Issue
Block a user