feat: Implement forum feed layout and refactor space navigation logic to support new routing structure
This commit is contained in:
@@ -1,15 +1,31 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { PageRoot } from '../../components/page';
|
||||
import { AnimatedOutlet } from '../../components/AnimatedOutlet';
|
||||
import { MobileFriendlyPageNav } from '../../pages/MobileFriendly';
|
||||
import { SPACE_PATH } from '../../pages/paths';
|
||||
import { Space } from '../../pages/client/space/Space';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
|
||||
import { useSpace } from '../../hooks/useSpace';
|
||||
import { isForumContainer, shouldShowForumLobby } from '../../utils/room';
|
||||
import { ForumBoardProvider } from './ForumBoardContext';
|
||||
|
||||
/**
|
||||
* Space sidebar + outlet. Forum spaces render ForumFeedSidebar in Space.tsx.
|
||||
*/
|
||||
export function ForumAwareSpaceLayout() {
|
||||
return (
|
||||
const mx = useMatrixClient();
|
||||
const space = useSpace();
|
||||
const selectedRoomId = useSelectedRoom();
|
||||
|
||||
const scope = useMemo(() => {
|
||||
const room = selectedRoomId ? mx.getRoom(selectedRoomId) : null;
|
||||
const topicRoomId =
|
||||
room && room.roomId !== space.roomId && !isForumContainer(room) ? room.roomId : undefined;
|
||||
return { forumSpaceId: space.roomId, topicRoomId };
|
||||
}, [mx, selectedRoomId, space.roomId]);
|
||||
|
||||
const layout = (
|
||||
<PageRoot
|
||||
nav={
|
||||
<MobileFriendlyPageNav path={SPACE_PATH}>
|
||||
@@ -20,4 +36,14 @@ export function ForumAwareSpaceLayout() {
|
||||
<AnimatedOutlet />
|
||||
</PageRoot>
|
||||
);
|
||||
|
||||
if (!shouldShowForumLobby(space)) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
return (
|
||||
<ForumBoardProvider forumSpace={space} scope={scope}>
|
||||
{layout}
|
||||
</ForumBoardProvider>
|
||||
);
|
||||
}
|
||||
|
||||
6
src/app/features/forum/ForumFeedPage.tsx
Normal file
6
src/app/features/forum/ForumFeedPage.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { ForumBoardDetail } from './ForumBoardDetail';
|
||||
|
||||
/** Forum post feed in the main pane (sidebar holds filters + post list). */
|
||||
export function ForumFeedPage() {
|
||||
return <ForumBoardDetail />;
|
||||
}
|
||||
@@ -1,30 +1,8 @@
|
||||
import React, { ReactNode, useMemo } from 'react';
|
||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||
import { useSelectedRoom } from '../../hooks/router/useSelectedRoom';
|
||||
import { useSpace } from '../../hooks/useSpace';
|
||||
import { isForumContainer, shouldShowForumLobby } from '../../utils/room';
|
||||
import { ForumBoardProvider } from './ForumBoardContext';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
/** Shares forum board state between space sidebar and lobby/room outlet. */
|
||||
/**
|
||||
* @deprecated Forum board context now lives in ForumAwareSpaceLayout.
|
||||
*/
|
||||
export function ForumSpaceLayout({ children }: { children: ReactNode }) {
|
||||
const mx = useMatrixClient();
|
||||
const space = useSpace();
|
||||
const selectedRoomId = useSelectedRoom();
|
||||
|
||||
const scope = useMemo(() => {
|
||||
const room = selectedRoomId ? mx.getRoom(selectedRoomId) : null;
|
||||
const topicRoomId =
|
||||
room && room.roomId !== space.roomId && !isForumContainer(room) ? room.roomId : undefined;
|
||||
return { forumSpaceId: space.roomId, topicRoomId };
|
||||
}, [mx, selectedRoomId, space.roomId]);
|
||||
|
||||
if (!shouldShowForumLobby(space)) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return (
|
||||
<ForumBoardProvider forumSpace={space} scope={scope}>
|
||||
{children}
|
||||
</ForumBoardProvider>
|
||||
);
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ export { ForumBoardDetail } from './ForumBoardDetail';
|
||||
export { ForumSortIcons } from './forumLucideIcons';
|
||||
export { ForumSpaceShell } from './ForumSpaceShell';
|
||||
export { ForumThreadDetail } from './ForumThreadDetail';
|
||||
export { ForumFeedPage } from './ForumFeedPage';
|
||||
export { ForumAwareSpaceLayout } from './ForumAwareSpaceLayout';
|
||||
export { ForumSpaceLayout } from './ForumSpaceLayout';
|
||||
export type { ForumBoardScope } from './useForumBoard';
|
||||
|
||||
@@ -41,8 +41,7 @@ import { getSpaceRoomPath } from '../../pages/pathUtils';
|
||||
import { StateEvent } from '../../../types/matrix/room';
|
||||
import { CanDropCallback, useDnDMonitor } from './DnD';
|
||||
import { ASCIILexicalTable, orderKeys } from '../../utils/ASCIILexicalTable';
|
||||
import { getStateEvent, shouldShowForumLobby } from '../../utils/room';
|
||||
import { ForumBoardDetail } from '../forum/ForumBoardDetail';
|
||||
import { getStateEvent } from '../../utils/room';
|
||||
import { useClosedLobbyCategoriesAtom } from '../../state/hooks/closedLobbyCategories';
|
||||
import {
|
||||
makeCinnySpacesContent,
|
||||
@@ -151,15 +150,7 @@ const useCanDropLobbyItem = (
|
||||
return canDrop;
|
||||
};
|
||||
|
||||
function ForumSpaceLobby() {
|
||||
return <ForumBoardDetail />;
|
||||
}
|
||||
|
||||
export function Lobby() {
|
||||
const space = useSpace();
|
||||
if (shouldShowForumLobby(space)) {
|
||||
return <ForumSpaceLobby />;
|
||||
}
|
||||
return <SpaceCardLobby />;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,12 @@ import { AddExistingModal } from '../add-existing';
|
||||
import { SpeechBubble } from '../../components/speech-bubble/SpeechBubble';
|
||||
import { SpaceOptionsMenu, type OpenAddExistingOptions } from '../space/SpaceOptionsMenu';
|
||||
import type { HierarchyItemSpace } from '../../hooks/useSpaceHierarchy';
|
||||
import { StateEvent } from '../../../types/matrix/room';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { getCanonicalAliasOrRoomId } from '../../utils/matrix';
|
||||
import { getSpaceFeedPath } from '../../pages/pathUtils';
|
||||
import { shouldShowForumLobby } from '../../utils/room';
|
||||
import { useForumBoardContextOptionally } from '../forum/ForumBoardContext';
|
||||
import { StateEvent } from '../../../types/matrix/room';
|
||||
|
||||
type LobbyMenuProps = {
|
||||
powerLevels: IPowerLevels;
|
||||
@@ -37,7 +41,9 @@ type LobbyMenuProps = {
|
||||
const LobbyMenu = forwardRef<HTMLDivElement, LobbyMenuProps>(
|
||||
({ powerLevels, requestClose }, ref) => {
|
||||
const mx = useMatrixClient();
|
||||
const navigate = useNavigate();
|
||||
const space = useSpace();
|
||||
const isForum = shouldShowForumLobby(space);
|
||||
const creators = useRoomCreators(space);
|
||||
|
||||
const permissions = useRoomPermissions(creators, powerLevels);
|
||||
@@ -55,6 +61,11 @@ const LobbyMenu = forwardRef<HTMLDivElement, LobbyMenuProps>(
|
||||
requestClose();
|
||||
};
|
||||
|
||||
const handleOpenFeed = () => {
|
||||
navigate(getSpaceFeedPath(getCanonicalAliasOrRoomId(mx, space.roomId)));
|
||||
requestClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
|
||||
{invitePrompt && (
|
||||
@@ -67,6 +78,18 @@ const LobbyMenu = forwardRef<HTMLDivElement, LobbyMenuProps>(
|
||||
/>
|
||||
)}
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
{isForum && (
|
||||
<MenuItem
|
||||
onClick={handleOpenFeed}
|
||||
size="300"
|
||||
after={<Icon size="100" src={Icons.Thread} />}
|
||||
radii="300"
|
||||
>
|
||||
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||
Feed
|
||||
</Text>
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={handleInvite}
|
||||
variant="Primary"
|
||||
|
||||
@@ -28,6 +28,10 @@ import { copyToClipboard } from '../../utils/dom';
|
||||
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
|
||||
import { getMatrixToRoom } from '../../plugins/matrix-to';
|
||||
import { getViaServers } from '../../plugins/via-servers';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { getSpaceFeedPath, getSpaceLobbyPath } from '../../pages/pathUtils';
|
||||
import { shouldShowForumLobby } from '../../utils/room';
|
||||
import { useSpaceFeedSelected } from '../../hooks/router/useSelectedSpace';
|
||||
|
||||
type ForumAddOptions = {
|
||||
item: HierarchyItem;
|
||||
@@ -50,6 +54,9 @@ type SpaceOptionsMenuProps = {
|
||||
export const SpaceOptionsMenu = forwardRef<HTMLDivElement, SpaceOptionsMenuProps>(
|
||||
({ room, requestClose, forumAdd, onOpenAddExisting }, ref) => {
|
||||
const mx = useMatrixClient();
|
||||
const navigate = useNavigate();
|
||||
const onFeed = useSpaceFeedSelected();
|
||||
const isForum = shouldShowForumLobby(room);
|
||||
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
||||
const [developerTools] = useSetting(settingsAtom, 'developerTools');
|
||||
const roomToParents = useAtomValue(roomToParentsAtom);
|
||||
@@ -101,6 +108,16 @@ export const SpaceOptionsMenu = forwardRef<HTMLDivElement, SpaceOptionsMenuProps
|
||||
requestClose();
|
||||
};
|
||||
|
||||
const handleOpenFeed = () => {
|
||||
navigate(getSpaceFeedPath(getCanonicalAliasOrRoomId(mx, room.roomId)));
|
||||
requestClose();
|
||||
};
|
||||
|
||||
const handleOpenManage = () => {
|
||||
navigate(getSpaceLobbyPath(getCanonicalAliasOrRoomId(mx, room.roomId)));
|
||||
requestClose();
|
||||
};
|
||||
|
||||
const handleAddTopic = () => {
|
||||
if (!forumAdd) return;
|
||||
openCreateRoomModal(forumAdd.item.roomId);
|
||||
@@ -200,6 +217,30 @@ export const SpaceOptionsMenu = forwardRef<HTMLDivElement, SpaceOptionsMenuProps
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isForum && !onFeed && (
|
||||
<MenuItem
|
||||
onClick={handleOpenFeed}
|
||||
size="300"
|
||||
after={<Icon size="100" src={Icons.Thread} />}
|
||||
radii="300"
|
||||
>
|
||||
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||
Feed
|
||||
</Text>
|
||||
</MenuItem>
|
||||
)}
|
||||
{isForum && onFeed && (
|
||||
<MenuItem
|
||||
onClick={handleOpenManage}
|
||||
size="300"
|
||||
after={<Icon size="100" src={Icons.Flag} />}
|
||||
radii="300"
|
||||
>
|
||||
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||
Manage
|
||||
</Text>
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={handleMarkAsRead}
|
||||
size="300"
|
||||
|
||||
Reference in New Issue
Block a user