feat: Implement forum feed layout and refactor space navigation logic to support new routing structure
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
_FEATURED_PATH,
|
||||
_INVITES_PATH,
|
||||
_JOIN_PATH,
|
||||
_FEED_PATH,
|
||||
_LOBBY_PATH,
|
||||
_NOTIFICATIONS_PATH,
|
||||
_ROOM_PATH,
|
||||
@@ -37,14 +38,13 @@ import {
|
||||
getInboxNotificationsPath,
|
||||
getLoginPath,
|
||||
getOriginBaseUrl,
|
||||
getSpaceLobbyPath,
|
||||
} from './pathUtils';
|
||||
import { ClientBindAtoms, ClientLayout, ClientRoot } from './client';
|
||||
import { Home, HomeRouteRoomProvider, HomeSearch } from './client/home';
|
||||
import { Direct, DirectCreate, DirectRouteRoomProvider } from './client/direct';
|
||||
import { RouteSpaceProvider, Space, SpaceRouteRoomProvider, SpaceSearch } from './client/space';
|
||||
import { RouteSpaceProvider, SpaceRouteRoomProvider, SpaceSearch, SpaceIndexRedirect } from './client/space';
|
||||
import { ForumAwareSpaceLayout } from '../features/forum/ForumAwareSpaceLayout';
|
||||
import { ForumSpaceLayout } from '../features/forum/ForumSpaceLayout';
|
||||
import { ForumFeedPage } from '../features/forum/ForumFeedPage';
|
||||
import { Explore, FeaturedRooms, PublicRooms } from './client/explore';
|
||||
import { Notifications, Inbox, Invites } from './client/inbox';
|
||||
import { setAfterLoginRedirectPath } from './afterLoginRedirectPath';
|
||||
@@ -238,25 +238,12 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize)
|
||||
path={SPACE_PATH}
|
||||
element={
|
||||
<RouteSpaceProvider>
|
||||
<ForumSpaceLayout>
|
||||
<ForumAwareSpaceLayout />
|
||||
</ForumSpaceLayout>
|
||||
<ForumAwareSpaceLayout />
|
||||
</RouteSpaceProvider>
|
||||
}
|
||||
>
|
||||
{mobile ? null : (
|
||||
<Route
|
||||
index
|
||||
loader={({ params }) => {
|
||||
const { spaceIdOrAlias } = params;
|
||||
if (spaceIdOrAlias) {
|
||||
return redirect(getSpaceLobbyPath(spaceIdOrAlias));
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
element={<WelcomePage />}
|
||||
/>
|
||||
)}
|
||||
<Route index element={<SpaceIndexRedirect />} />
|
||||
<Route path={_FEED_PATH} element={<ForumFeedPage />} />
|
||||
<Route path={_LOBBY_PATH} element={<Lobby />} />
|
||||
<Route path={_SEARCH_PATH} element={<SpaceSearch />} />
|
||||
<Route
|
||||
|
||||
@@ -37,7 +37,7 @@ import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { mDirectAtom } from '../../../state/mDirectList';
|
||||
import { roomToParentsAtom } from '../../../state/room/roomToParents';
|
||||
import { allRoomsAtom } from '../../../state/room-list/roomList';
|
||||
import { getHomePath, getSpaceLobbyPath, getSpacePath, joinPathComponent } from '../../pathUtils';
|
||||
import { getHomePath, getSpaceDefaultPath, getSpacePath, joinPathComponent } from '../../pathUtils';
|
||||
import {
|
||||
SidebarAvatar,
|
||||
SidebarItem,
|
||||
@@ -1067,7 +1067,7 @@ export function SpaceTabs({ scrollRef }: SpaceTabsProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigate(getSpaceLobbyPath(getCanonicalAliasOrRoomId(mx, targetSpaceId)));
|
||||
navigate(getSpaceDefaultPath(mx, targetSpaceId));
|
||||
};
|
||||
|
||||
const handleFolderToggle: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||
@@ -1206,7 +1206,7 @@ export function HiddenSpacesTabs() {
|
||||
return;
|
||||
}
|
||||
|
||||
navigate(getSpaceLobbyPath(getCanonicalAliasOrRoomId(mx, targetSpaceId)));
|
||||
navigate(getSpaceDefaultPath(mx, targetSpaceId));
|
||||
};
|
||||
|
||||
const handleHomeClick = () => {
|
||||
|
||||
@@ -335,7 +335,12 @@ export function Space() {
|
||||
const getToLink = (roomId: string) =>
|
||||
getSpaceRoomPath(spaceIdOrAlias, getCanonicalAliasOrRoomId(mx, roomId));
|
||||
|
||||
if (shouldShowForumLobby(space)) {
|
||||
const isForum = shouldShowForumLobby(space);
|
||||
// Forum feed unless user opened manage, search, or a room (not tied to URL alias encoding).
|
||||
const feedActive = isForum && !lobbySelected && !searchSelected && !selectedRoomId;
|
||||
const showForumFeedSidebar = feedActive;
|
||||
|
||||
if (showForumFeedSidebar) {
|
||||
return (
|
||||
<PageNav className={forumBoardCss.ForumPageNav}>
|
||||
<SpaceHeader />
|
||||
@@ -346,6 +351,8 @@ export function Space() {
|
||||
);
|
||||
}
|
||||
|
||||
const spacePath = getCanonicalAliasOrRoomId(mx, space.roomId);
|
||||
|
||||
return (
|
||||
<PageNav>
|
||||
<SpaceHeader />
|
||||
@@ -358,38 +365,42 @@ export function Space() {
|
||||
/>
|
||||
)}
|
||||
<NavCategory>
|
||||
<NavItem variant="Background" radii="400" aria-selected={lobbySelected}>
|
||||
<NavLink to={getSpaceLobbyPath(getCanonicalAliasOrRoomId(mx, space.roomId))}>
|
||||
<NavItemContent>
|
||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||
<Avatar size="200" radii="400">
|
||||
<Icon src={Icons.Flag} size="100" filled={lobbySelected} />
|
||||
</Avatar>
|
||||
<Box as="span" grow="Yes">
|
||||
<Text as="span" size="Inherit" truncate>
|
||||
Lobby
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</NavItemContent>
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
<NavItem variant="Background" radii="400" aria-selected={searchSelected}>
|
||||
<NavLink to={getSpaceSearchPath(getCanonicalAliasOrRoomId(mx, space.roomId))}>
|
||||
<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>
|
||||
{!isForum && (
|
||||
<>
|
||||
<NavItem variant="Background" radii="400" aria-selected={lobbySelected}>
|
||||
<NavLink to={getSpaceLobbyPath(spacePath)}>
|
||||
<NavItemContent>
|
||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||
<Avatar size="200" radii="400">
|
||||
<Icon src={Icons.Flag} size="100" filled={lobbySelected} />
|
||||
</Avatar>
|
||||
<Box as="span" grow="Yes">
|
||||
<Text as="span" size="Inherit" truncate>
|
||||
Lobby
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</NavItemContent>
|
||||
</NavLink>
|
||||
</NavItem>
|
||||
<NavItem variant="Background" radii="400" aria-selected={searchSelected}>
|
||||
<NavLink to={getSpaceSearchPath(spacePath)}>
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
<PluginNavSlot location="channel-list" />
|
||||
</NavCategory>
|
||||
<NavCategory
|
||||
|
||||
26
src/app/pages/client/space/SpaceIndexRedirect.tsx
Normal file
26
src/app/pages/client/space/SpaceIndexRedirect.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { useSpace } from '../../../hooks/useSpace';
|
||||
import { shouldShowForumLobby } from '../../../utils/room';
|
||||
import { getSpaceDefaultPath } from '../../pathUtils';
|
||||
import { ForumFeedPage } from '../../../features/forum/ForumFeedPage';
|
||||
|
||||
/** Sends /:spaceId/ to the forum feed or space lobby. */
|
||||
export function SpaceIndexRedirect() {
|
||||
const mx = useMatrixClient();
|
||||
const space = useSpace();
|
||||
const navigate = useNavigate();
|
||||
const isForum = shouldShowForumLobby(space);
|
||||
|
||||
useEffect(() => {
|
||||
navigate(getSpaceDefaultPath(mx, space.roomId), { replace: true });
|
||||
}, [mx, navigate, space.roomId]);
|
||||
|
||||
// Avoid a blank main pane while redirecting forum spaces to /feed/.
|
||||
if (isForum) {
|
||||
return <ForumFeedPage />;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { useAutoJoinOnSpaceVisit } from '../../../hooks/useAutoJoinSpaceRooms';
|
||||
import { useSpaces } from '../../../state/hooks/roomList';
|
||||
import { allRoomsAtom } from '../../../state/room-list/roomList';
|
||||
import { useSelectedSpace } from '../../../hooks/router/useSelectedSpace';
|
||||
@@ -21,6 +22,8 @@ export function RouteSpaceProvider({ children }: RouteSpaceProviderProps) {
|
||||
const selectedSpaceId = useSelectedSpace();
|
||||
const space = mx.getRoom(selectedSpaceId);
|
||||
|
||||
useAutoJoinOnSpaceVisit(space ?? undefined);
|
||||
|
||||
if (!space || !joinedSpaces.includes(space.roomId)) {
|
||||
return <JoinBeforeNavigate roomIdOrAlias={spaceIdOrAlias ?? ''} viaServers={viaServers} />;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './SpaceIndexRedirect';
|
||||
export * from './SpaceProvider';
|
||||
export * from './Space';
|
||||
export * from './Search';
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
REGISTER_PATH,
|
||||
RESET_PASSWORD_PATH,
|
||||
ROOT_PATH,
|
||||
SPACE_FEED_PATH,
|
||||
SPACE_LOBBY_PATH,
|
||||
SPACE_PATH,
|
||||
SPACE_ROOM_PATH,
|
||||
@@ -28,6 +29,9 @@ import {
|
||||
} from './paths';
|
||||
import { trimLeadingSlash, trimTrailingSlash } from '../utils/common';
|
||||
import { HashRouterConfig } from '../hooks/useClientConfig';
|
||||
import type { MatrixClient } from 'matrix-js-sdk';
|
||||
import { getCanonicalAliasOrRoomId } from '../utils/matrix';
|
||||
import { shouldShowForumLobby } from '../utils/room';
|
||||
|
||||
export const joinPathComponent = (path: Path): string => path.pathname + path.search + path.hash;
|
||||
|
||||
@@ -128,6 +132,21 @@ export const getSpaceLobbyPath = (spaceIdOrAlias: string): string => {
|
||||
};
|
||||
return generatePath(SPACE_LOBBY_PATH, params);
|
||||
};
|
||||
export const getSpaceFeedPath = (spaceIdOrAlias: string): string => {
|
||||
const params = {
|
||||
spaceIdOrAlias: encodeURIComponent(spaceIdOrAlias),
|
||||
};
|
||||
return generatePath(SPACE_FEED_PATH, params);
|
||||
};
|
||||
/** Forum spaces open the post feed; other spaces open the lobby. */
|
||||
export const getSpaceDefaultPath = (mx: MatrixClient, spaceId: string): string => {
|
||||
const spaceIdOrAlias = getCanonicalAliasOrRoomId(mx, spaceId);
|
||||
const space = mx.getRoom(spaceId);
|
||||
if (space && shouldShowForumLobby(space)) {
|
||||
return getSpaceFeedPath(spaceIdOrAlias);
|
||||
}
|
||||
return getSpaceLobbyPath(spaceIdOrAlias);
|
||||
};
|
||||
export const getSpaceSearchPath = (spaceIdOrAlias: string): string => {
|
||||
const params = {
|
||||
spaceIdOrAlias: encodeURIComponent(spaceIdOrAlias),
|
||||
|
||||
@@ -22,6 +22,7 @@ export const RESET_PASSWORD_PATH = '/reset-password/:server?/';
|
||||
export const _CREATE_PATH = 'create/';
|
||||
export const _JOIN_PATH = 'join/';
|
||||
export const _LOBBY_PATH = 'lobby/';
|
||||
export const _FEED_PATH = 'feed/';
|
||||
/**
|
||||
* array of rooms and senders mxId assigned
|
||||
* to search param as string should be "," separated
|
||||
@@ -57,6 +58,7 @@ export const DIRECT_ROOM_PATH = `/direct/${_ROOM_PATH}`;
|
||||
|
||||
export const SPACE_PATH = '/:spaceIdOrAlias/';
|
||||
export const SPACE_LOBBY_PATH = `/:spaceIdOrAlias/${_LOBBY_PATH}`;
|
||||
export const SPACE_FEED_PATH = `/:spaceIdOrAlias/${_FEED_PATH}`;
|
||||
export const SPACE_SEARCH_PATH = `/:spaceIdOrAlias/${_SEARCH_PATH}`;
|
||||
export const SPACE_ROOM_PATH = `/:spaceIdOrAlias/${_ROOM_PATH}`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user