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:
@@ -41,7 +41,7 @@ import {
|
||||
} from './pathUtils';
|
||||
import { ClientBindAtoms, ClientLayout, ClientRoot } from './client';
|
||||
import { Home, HomeRouteRoomProvider, HomeSearch } from './client/home';
|
||||
import { Direct, DirectCreate, DirectRouteRoomProvider } from './client/direct';
|
||||
import { Direct, DirectCreate, DirectRouteRoomProvider, DirectSearch } from './client/direct';
|
||||
import { RouteSpaceProvider, SpaceRouteRoomProvider, SpaceSearch, SpaceIndexRedirect } from './client/space';
|
||||
import { ForumAwareSpaceLayout } from '../features/forum/ForumAwareSpaceLayout';
|
||||
import { ForumFeedPage } from '../features/forum/ForumFeedPage';
|
||||
@@ -223,6 +223,7 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize)
|
||||
>
|
||||
{mobile ? null : <Route index element={<WelcomePage />} />}
|
||||
<Route path={_CREATE_PATH} element={<DirectCreate />} />
|
||||
<Route path={_SEARCH_PATH} element={<DirectSearch />} />
|
||||
<Route path={_NOTIFICATIONS_PATH} element={<Notifications />} />
|
||||
<Route path={_INVITES_PATH} element={<Invites />} />
|
||||
<Route
|
||||
|
||||
@@ -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 />
|
||||
|
||||
55
src/app/pages/client/direct/Search.tsx
Normal file
55
src/app/pages/client/direct/Search.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './Direct';
|
||||
export * from './RoomProvider';
|
||||
export * from './DirectCreate';
|
||||
export * from './Search';
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
DIRECT_CREATE_PATH,
|
||||
DIRECT_PATH,
|
||||
DIRECT_ROOM_PATH,
|
||||
DIRECT_SEARCH_PATH,
|
||||
DIRECT_NOTIFICATIONS_PATH,
|
||||
DIRECT_INVITES_PATH,
|
||||
EXPLORE_FEATURED_PATH,
|
||||
@@ -121,6 +122,7 @@ export const getHomeRoomPath = (roomIdOrAlias: string, eventId?: string): string
|
||||
|
||||
export const getDirectPath = (): string => DIRECT_PATH;
|
||||
export const getDirectCreatePath = (): string => DIRECT_CREATE_PATH;
|
||||
export const getDirectSearchPath = (): string => DIRECT_SEARCH_PATH;
|
||||
export const getDirectRoomPath = (roomIdOrAlias: string, eventId?: string): string => {
|
||||
const params = {
|
||||
roomIdOrAlias,
|
||||
@@ -180,6 +182,28 @@ export const getSpaceRoomPath = (
|
||||
return generatePath(SPACE_ROOM_PATH, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep the current room URL (home / direct / space) and only add, replace, or clear
|
||||
* the optional `$eventId` segment. Used so same-room jumps (media, permalinks) don't
|
||||
* re-home the room into a different sidebar section.
|
||||
*/
|
||||
export const withRoomEventId = (pathname: string, eventId?: string): string => {
|
||||
const parts = pathname.split('/').filter(Boolean);
|
||||
|
||||
if (parts.length > 0) {
|
||||
const lastDecoded = decodeRouteParam(parts[parts.length - 1]);
|
||||
if (lastDecoded?.startsWith('$')) {
|
||||
parts.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (eventId) {
|
||||
parts.push(encodeURIComponent(eventId));
|
||||
}
|
||||
|
||||
return `/${parts.join('/')}/`;
|
||||
};
|
||||
|
||||
export const getExplorePath = (): string => EXPLORE_PATH;
|
||||
export const getExploreFeaturedPath = (): string => EXPLORE_FEATURED_PATH;
|
||||
export const getExploreServerPath = (server: string): string => {
|
||||
|
||||
@@ -54,6 +54,7 @@ export type DirectCreateSearchParams = {
|
||||
userId?: string;
|
||||
};
|
||||
export const DIRECT_CREATE_PATH = `/direct/${_CREATE_PATH}`;
|
||||
export const DIRECT_SEARCH_PATH = `/direct/${_SEARCH_PATH}`;
|
||||
export const DIRECT_ROOM_PATH = `/direct/${_ROOM_PATH}`;
|
||||
|
||||
export const SPACE_PATH = '/:spaceIdOrAlias/';
|
||||
|
||||
Reference in New Issue
Block a user