fix(media-gallery): dock as a flex sibling like MembersDrawer (was floating)
The real reason the gallery didn't look or function like the Members drawer
or Saved Messages: it was a position:fixed overlay floating over the timeline,
mounted from RoomViewHeader. Now it docks into the room layout row exactly like
MembersDrawer.
- new mediaGalleryAtom (mirrors bookmarksPanelAtom) holds the open state
- RoomViewHeader toggles the atom instead of local useState and no longer
renders the panel
- Room.tsx renders <MediaGallery> as a flex sibling of the timeline with a
vertical Line separator on desktop and key={room.roomId} to reset per room
- MediaGallery.css: static width on desktop, position:fixed inset:0 full-screen
only on mobile (identical strategy to MembersDrawer.css); root Box shrink="No"
The panel now shares the row with the timeline instead of overlapping it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,24 +1,20 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { color, config, toRem } from 'folds';
|
||||
|
||||
// Right-side drawer that floats over the room view. 320px is wider than the
|
||||
// 266px member/bookmark drawers because it hosts a media grid; on narrow
|
||||
// viewports it expands to fill the screen, matching the app's other drawers.
|
||||
// Right-side drawer DOCKED into the room layout row (a flex sibling of the
|
||||
// timeline), exactly like MembersDrawer — not a floating overlay. 320px is a
|
||||
// little wider than the 266px member/bookmark drawers because it hosts a media
|
||||
// grid. On narrow viewports it becomes a full-screen fixed panel, matching the
|
||||
// app's other drawers.
|
||||
export const MediaGalleryDrawer = style({
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: toRem(320),
|
||||
zIndex: 500,
|
||||
overflow: 'hidden',
|
||||
borderLeftWidth: config.borderWidth.B300,
|
||||
borderLeftStyle: 'solid',
|
||||
borderLeftColor: color.Background.ContainerLine,
|
||||
'@media': {
|
||||
'(max-width: 750px)': {
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
width: '100%',
|
||||
borderLeftWidth: 0,
|
||||
zIndex: 500,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -625,6 +625,7 @@ export function MediaGallery({ room, onClose }: MediaGalleryProps) {
|
||||
<>
|
||||
<Box
|
||||
className={classNames(css.MediaGalleryDrawer, ContainerColor({ variant: 'Background' }))}
|
||||
shrink="No"
|
||||
direction="Column"
|
||||
>
|
||||
{/* Header */}
|
||||
|
||||
@@ -2,9 +2,11 @@ import React, { useCallback } from 'react';
|
||||
import { Box, Line } from 'folds';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { isKeyHotkey } from 'is-hotkey';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { RoomView } from './RoomView';
|
||||
import { MembersDrawer } from './MembersDrawer';
|
||||
import { MediaGallery } from './MediaGallery';
|
||||
import { mediaGalleryAtom } from '../../state/mediaGallery';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
import { useSetting } from '../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
@@ -31,6 +33,8 @@ export function Room() {
|
||||
const callEmbed = useCallEmbed();
|
||||
|
||||
const [isDrawer] = useSetting(settingsAtom, 'isPeopleDrawer');
|
||||
const galleryOpen = useAtomValue(mediaGalleryAtom);
|
||||
const setGalleryOpen = useSetAtom(mediaGalleryAtom);
|
||||
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
||||
const screenSize = useScreenSizeContext();
|
||||
const powerLevels = usePowerLevels(room);
|
||||
@@ -78,6 +82,14 @@ export function Room() {
|
||||
<CallChatView />
|
||||
</>
|
||||
)}
|
||||
{!callView && galleryOpen && (
|
||||
<>
|
||||
{screenSize === ScreenSize.Desktop && (
|
||||
<Line variant="Background" direction="Vertical" size="300" />
|
||||
)}
|
||||
<MediaGallery key={room.roomId} room={room} onClose={() => setGalleryOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
{!callView && isDrawer && (
|
||||
<>
|
||||
{screenSize === ScreenSize.Desktop && (
|
||||
|
||||
@@ -73,7 +73,7 @@ import { RoomSettingsPage } from '../../state/roomSettings';
|
||||
import { useCallEmbed, useCallStart } from '../../hooks/useCallEmbed';
|
||||
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
|
||||
import { webRTCSupported } from '../../utils/rtc';
|
||||
import { MediaGallery } from './MediaGallery';
|
||||
import { mediaGalleryAtom } from '../../state/mediaGallery';
|
||||
import { usePendingKnocks } from '../../hooks/usePendingKnocks';
|
||||
import { bookmarksPanelAtom } from '../../state/bookmarksPanel';
|
||||
|
||||
@@ -488,7 +488,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
||||
: undefined;
|
||||
|
||||
const [peopleDrawer, setPeopleDrawer] = useSetting(settingsAtom, 'isPeopleDrawer');
|
||||
const [galleryOpen, setGalleryOpen] = useState(false);
|
||||
const [galleryOpen, setGalleryOpen] = useAtom(mediaGalleryAtom);
|
||||
const pendingKnocks = usePendingKnocks(room);
|
||||
|
||||
const handleSearchClick = () => {
|
||||
@@ -820,7 +820,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
||||
room={room}
|
||||
requestClose={() => setMenuAnchor(undefined)}
|
||||
galleryOpen={galleryOpen}
|
||||
onToggleGallery={() => setGalleryOpen((v) => !v)}
|
||||
onToggleGallery={() => setGalleryOpen((v: boolean) => !v)}
|
||||
/>
|
||||
</FocusTrap>
|
||||
}
|
||||
@@ -828,7 +828,6 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
|
||||
</Box>
|
||||
</Box>
|
||||
</PageHeader>
|
||||
{galleryOpen && <MediaGallery room={room} onClose={() => setGalleryOpen(false)} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { atom } from 'jotai';
|
||||
|
||||
export const mediaGalleryAtom = atom<boolean>(false);
|
||||
Reference in New Issue
Block a user