fix(mobile): make media gallery and members panel accessible on mobile
MediaGallery: fixed panel now goes full-width (100%) on mobile instead of the inaccessible 320px right sidebar. Added 'Media Gallery' MenuItem to RoomMenu (visible only on mobile) so users can open it from the More Options (···) button. MembersDrawer: removed ScreenSize.Desktop gate in Room.tsx so it now renders on mobile too. CSS media query (≤750px) makes it position:fixed inset:0 width:100% on mobile instead of the 266px desktop sidebar. Added 'Members' MenuItem to RoomMenu for mobile access. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import { useMatrixClient } from '../../hooks/useMatrixClient';
|
|||||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||||
import { decryptFile, downloadEncryptedMedia, mxcUrlToHttp } from '../../utils/matrix';
|
import { decryptFile, downloadEncryptedMedia, mxcUrlToHttp } from '../../utils/matrix';
|
||||||
import { ContainerColor } from '../../styles/ContainerColor.css';
|
import { ContainerColor } from '../../styles/ContainerColor.css';
|
||||||
|
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||||
|
|
||||||
type GalleryTab = 'image' | 'video' | 'file';
|
type GalleryTab = 'image' | 'video' | 'file';
|
||||||
|
|
||||||
@@ -531,6 +532,8 @@ type MediaGalleryProps = {
|
|||||||
export function MediaGallery({ room, onClose }: MediaGalleryProps) {
|
export function MediaGallery({ room, onClose }: MediaGalleryProps) {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
|
const screenSize = useScreenSizeContext();
|
||||||
|
const isMobile = screenSize === ScreenSize.Mobile;
|
||||||
|
|
||||||
const [tab, setTab] = useState<GalleryTab>('image');
|
const [tab, setTab] = useState<GalleryTab>('image');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -650,9 +653,9 @@ export function MediaGallery({ room, onClose }: MediaGalleryProps) {
|
|||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
width: '320px',
|
width: isMobile ? '100%' : '320px',
|
||||||
zIndex: 500,
|
zIndex: 500,
|
||||||
borderLeft: `1px solid ${color.Surface.ContainerLine}`,
|
borderLeft: isMobile ? 'none' : `1px solid ${color.Surface.ContainerLine}`,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,6 +3,14 @@ import { config, toRem } from 'folds';
|
|||||||
|
|
||||||
export const MembersDrawer = style({
|
export const MembersDrawer = style({
|
||||||
width: toRem(266),
|
width: toRem(266),
|
||||||
|
'@media': {
|
||||||
|
'(max-width: 750px)': {
|
||||||
|
position: 'fixed',
|
||||||
|
inset: 0,
|
||||||
|
width: '100%',
|
||||||
|
zIndex: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MembersDrawerHeader = style({
|
export const MembersDrawerHeader = style({
|
||||||
|
|||||||
@@ -78,9 +78,11 @@ export function Room() {
|
|||||||
<CallChatView />
|
<CallChatView />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!callView && screenSize === ScreenSize.Desktop && isDrawer && (
|
{!callView && isDrawer && (
|
||||||
<>
|
<>
|
||||||
<Line variant="Background" direction="Vertical" size="300" />
|
{screenSize === ScreenSize.Desktop && (
|
||||||
|
<Line variant="Background" direction="Vertical" size="300" />
|
||||||
|
)}
|
||||||
<MembersDrawer key={room.roomId} room={room} members={members} />
|
<MembersDrawer key={room.roomId} room={room} members={members} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -80,10 +80,14 @@ import { bookmarksPanelAtom } from '../../state/bookmarksPanel';
|
|||||||
type RoomMenuProps = {
|
type RoomMenuProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
|
galleryOpen?: boolean;
|
||||||
|
onToggleGallery?: () => void;
|
||||||
};
|
};
|
||||||
const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose }, ref) => {
|
const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(
|
||||||
|
({ room, requestClose, galleryOpen, onToggleGallery }, ref) => {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
||||||
|
const screenSize = useScreenSizeContext();
|
||||||
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
||||||
const powerLevels = usePowerLevelsContext();
|
const powerLevels = usePowerLevelsContext();
|
||||||
const creators = useRoomCreators(room);
|
const creators = useRoomCreators(room);
|
||||||
@@ -99,6 +103,7 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
|
|||||||
const [invitePrompt, setInvitePrompt] = useState(false);
|
const [invitePrompt, setInvitePrompt] = useState(false);
|
||||||
const [reportRoomOpen, setReportRoomOpen] = useState(false);
|
const [reportRoomOpen, setReportRoomOpen] = useState(false);
|
||||||
const [bookmarksOpen, setBookmarksOpen] = useAtom(bookmarksPanelAtom);
|
const [bookmarksOpen, setBookmarksOpen] = useAtom(bookmarksPanelAtom);
|
||||||
|
const [peopleDrawer, setPeopleDrawer] = useSetting(settingsAtom, 'isPeopleDrawer');
|
||||||
|
|
||||||
const handleMarkAsRead = () => {
|
const handleMarkAsRead = () => {
|
||||||
markAsRead(mx, room.roomId, hideActivity);
|
markAsRead(mx, room.roomId, hideActivity);
|
||||||
@@ -186,6 +191,38 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
|
|||||||
Saved Messages
|
Saved Messages
|
||||||
</Text>
|
</Text>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
{screenSize === ScreenSize.Mobile && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setPeopleDrawer(!peopleDrawer);
|
||||||
|
requestClose();
|
||||||
|
}}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.User} filled={peopleDrawer} />}
|
||||||
|
radii="300"
|
||||||
|
aria-pressed={peopleDrawer}
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Members
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
{screenSize === ScreenSize.Mobile && onToggleGallery && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
onToggleGallery();
|
||||||
|
requestClose();
|
||||||
|
}}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.Photo} filled={galleryOpen} />}
|
||||||
|
radii="300"
|
||||||
|
aria-pressed={galleryOpen}
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Media Gallery
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
{!isServerNotice && (
|
{!isServerNotice && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={handleInvite}
|
onClick={handleInvite}
|
||||||
@@ -288,7 +325,8 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
|
|||||||
</Box>
|
</Box>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
type CallMenuProps = {
|
type CallMenuProps = {
|
||||||
onVoiceCall: () => void;
|
onVoiceCall: () => void;
|
||||||
@@ -783,7 +821,12 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
|||||||
escapeDeactivates: stopPropagation,
|
escapeDeactivates: stopPropagation,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RoomMenu room={room} requestClose={() => setMenuAnchor(undefined)} />
|
<RoomMenu
|
||||||
|
room={room}
|
||||||
|
requestClose={() => setMenuAnchor(undefined)}
|
||||||
|
galleryOpen={galleryOpen}
|
||||||
|
onToggleGallery={() => setGalleryOpen((v) => !v)}
|
||||||
|
/>
|
||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user