Add Shared Media drawer and harden same-room navigation.

Widen the media panel, support skinny full-page mode, keep jump-to-latest and return-to-previous reliable, and stop same-room event jumps from remounting the outlet or yanking the sidebar.
This commit is contained in:
2026-07-23 14:52:01 +10:00
parent 61d41900cc
commit 9509a9705e
30 changed files with 1749 additions and 168 deletions

View File

@@ -17,7 +17,7 @@ import {
NavItemContent,
NavLink,
} from '../../../components/nav';
import { getDirectCreatePath, getDirectRoomPath, getDirectNotificationsPath, getDirectInvitesPath } from '../../pathUtils';
import { getDirectCreatePath, getDirectRoomPath, getDirectNotificationsPath, getDirectInvitesPath, getDirectSearchPath } from '../../pathUtils';
import { getCanonicalAliasOrRoomId } from '../../../utils/matrix';
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
import { VirtualTile } from '../../../components/virtualizer';
@@ -41,10 +41,9 @@ import {
getRoomNotificationMode,
useRoomsNotificationPreferencesContext,
} from '../../../hooks/useRoomsNotificationPreferences';
import { useDirectCreateSelected } from '../../../hooks/router/useDirectSelected';
import { useDirectCreateSelected, useDirectSearchSelected } from '../../../hooks/router/useDirectSelected';
import { allInvitesAtom } from '../../../state/room-list/inviteList';
import { UnreadBadge } from '../../../components/unread-badge';
import { UnreadBadge } from '../../../components/unread-badge';
type DirectMenuProps = {
requestClose: () => void;
};
@@ -228,6 +227,7 @@ export function Direct() {
const navigate = useNavigate();
const createDirectSelected = useDirectCreateSelected();
const searchSelected = useDirectSearchSelected();
const selectedRoomId = useSelectedRoom();
const noRoomToDisplay = directs.length === 0;
@@ -283,6 +283,22 @@ export function Direct() {
</NavButton>
</NavItem>
<PluginNavSlot location="direct-messages" />
<NavItem variant="Background" radii="400" aria-selected={searchSelected}>
<NavLink to={getDirectSearchPath()}>
<NavItemContent>
<Box as="span" grow="Yes" alignItems="Center" gap="200">
<Avatar size="200" radii="400">
<Icon src={Icons.Search} size="100" filled={searchSelected} />
</Avatar>
<Box as="span" grow="Yes">
<Text as="span" size="Inherit" truncate>
Message Search
</Text>
</Box>
</Box>
</NavItemContent>
</NavLink>
</NavItem>
</NavCategory>
<NavCategory>
<NotificationsNavItem />

View File

@@ -0,0 +1,55 @@
import React, { useRef } from 'react';
import { Box, Text, Scroll, IconButton } from 'folds';
import { Icon, Icons } from '../../../components/icons';
import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
import { MessageSearch } from '../../../features/message-search';
import { useDirectRooms } from './useDirectRooms';
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
import { BackRouteHandler } from '../../../components/BackRouteHandler';
export function DirectSearch() {
const scrollRef = useRef<HTMLDivElement>(null);
const rooms = useDirectRooms();
const screenSize = useScreenSizeContext();
return (
<Page>
<PageHeader balance>
<Box grow="Yes" alignItems="Center" gap="200">
<Box grow="Yes" basis="No">
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack}>
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
</BackRouteHandler>
)}
</Box>
<Box justifyContent="Center" alignItems="Center" gap="200">
{screenSize !== ScreenSize.Mobile && <Icon size="400" src={Icons.Search} />}
<Text size="H3" truncate>
Message Search
</Text>
</Box>
<Box grow="Yes" basis="No" />
</Box>
</PageHeader>
<Box style={{ position: 'relative' }} grow="Yes">
<Scroll ref={scrollRef} hideTrack visibility="Hover">
<PageContent>
<PageContentCenter>
<MessageSearch
defaultRoomsFilterName="Direct Messages"
allowGlobal
rooms={rooms}
scrollRef={scrollRef}
/>
</PageContentCenter>
</PageContent>
</Scroll>
</Box>
</Page>
);
}

View File

@@ -1,3 +1,4 @@
export * from './Direct';
export * from './RoomProvider';
export * from './DirectCreate';
export * from './Search';