refactor(routing): migrate to directory-based board routing

This commit is contained in:
plebeius
2025-11-07 12:50:58 +01:00
parent e7e2a2fda7
commit d78fed1fda
22 changed files with 332 additions and 163 deletions
+5 -3
View File
@@ -8,6 +8,7 @@ import { shouldShowSnow } from '../../lib/snow';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter from '../../hooks/use-time-filter';
import useInterfaceSettingsStore from '../../stores/use-interface-settings-store';
@@ -35,7 +36,8 @@ const createThreadsWithoutImagesFilter = () => ({
const Board = () => {
const { t } = useTranslation();
const location = useLocation();
const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>();
const subplebbitAddress = useResolvedSubplebbitAddress();
const boardPath = useBoardPath(subplebbitAddress);
const { hideThreadsWithoutImages } = useInterfaceSettingsStore();
const isInAllView = isAllView(location.pathname);
@@ -194,7 +196,7 @@ const Board = () => {
i18nKey='more_threads_last_week'
values={{ currentTimeFilterName, count: feed.length }}
components={{
1: <Link to={(isInAllView ? '/p/all' : isInSubscriptionsView ? '/p/subscriptions' : isInModView ? '/p/mod' : `/p/${subplebbitAddress}`) + '/1w'} />,
1: <Link to={(isInAllView ? '/all' : isInSubscriptionsView ? '/subscriptions' : isInModView ? '/mod' : `/${boardPath}`) + '/1w'} />,
}}
/>
</div>
@@ -204,7 +206,7 @@ const Board = () => {
i18nKey='more_threads_last_month'
values={{ currentTimeFilterName, count: feed.length }}
components={{
1: <Link to={(isInAllView ? '/p/all' : isInSubscriptionsView ? '/p/subscriptions' : isInModView ? '/p/mod' : `/p/${subplebbitAddress}`) + '/1m'} />,
1: <Link to={(isInAllView ? '/all' : isInSubscriptionsView ? '/subscriptions' : isInModView ? '/mod' : `/${boardPath}`) + '/1m'} />,
}}
/>
</div>
+5 -3
View File
@@ -7,6 +7,7 @@ import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-util
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
import useCatalogFeedRows from '../../hooks/use-catalog-feed-rows';
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
import { useResolvedSubplebbitAddress, useBoardPath } from '../../hooks/use-resolved-subplebbit-address';
import { useFeedStateString } from '../../hooks/use-state-string';
import useTimeFilter from '../../hooks/use-time-filter';
import useWindowWidth from '../../hooks/use-window-width';
@@ -125,7 +126,8 @@ const createCombinedFilter = (
const Catalog = () => {
const { t } = useTranslation();
const location = useLocation();
const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>();
const subplebbitAddress = useResolvedSubplebbitAddress();
const boardPath = useBoardPath(subplebbitAddress);
const isInAllView = isAllView(location.pathname);
const defaultSubplebbits = useDefaultSubplebbits();
@@ -366,7 +368,7 @@ const Catalog = () => {
i18nKey='more_threads_last_week'
values={{ currentTimeFilterName, count: feed.length }}
components={{
1: <Link to={(isInAllView ? '/p/all/catalog' : isInSubscriptionsView ? '/p/subscriptions/catalog' : `/p/${subplebbitAddress}/catalog`) + '/1w'} />,
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subscriptions/catalog' : `/${boardPath}/catalog`) + '/1w'} />,
}}
/>
</div>
@@ -376,7 +378,7 @@ const Catalog = () => {
i18nKey='more_threads_last_month'
values={{ currentTimeFilterName, count: feed.length }}
components={{
1: <Link to={(isInAllView ? '/p/all/catalog' : isInSubscriptionsView ? '/p/subscriptions/catalog' : `/p/${subplebbitAddress}/catalog`) + '/1m'} />,
1: <Link to={(isInAllView ? '/all/catalog' : isInSubscriptionsView ? '/subscriptions/catalog' : `/${boardPath}/catalog`) + '/1m'} />,
}}
/>
</div>
+7 -3
View File
@@ -1,6 +1,7 @@
import { Link, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useDefaultSubplebbitsState, MultisubSubplebbit } from '../../../hooks/use-default-subplebbits';
import { useDefaultSubplebbitsState, useDefaultSubplebbits, MultisubSubplebbit } from '../../../hooks/use-default-subplebbits';
import { getBoardPath } from '../../../lib/utils/route-utils';
import LoadingEllipsis from '../../../components/loading-ellipsis';
import useDisclaimerModalStore from '../../../stores/use-disclaimer-modal-store';
import useDirectoryModalStore from '../../../stores/use-directory-modal-store';
@@ -34,16 +35,19 @@ const BoardsList = ({ multisub }: { multisub: MultisubSubplebbit[] }) => {
const { showDisclaimerModal } = useDisclaimerModalStore();
const { openDirectoryModal } = useDirectoryModalStore();
const { useCatalogLinks, boardFilter } = useBoardsFilterStore();
const defaultSubplebbits = useDefaultSubplebbits();
const handleLinkClick = (e: React.MouseEvent<HTMLAnchorElement>, address: string) => {
e.preventDefault();
showDisclaimerModal(address, navigate);
const boardPath = getBoardPath(address, defaultSubplebbits);
showDisclaimerModal(address, navigate, boardPath);
};
// Helper to generate link URL with optional catalog suffix
const getBoardLink = (address: string | null): string => {
if (!address) return '#';
return `/p/${address}${useCatalogLinks ? '/catalog' : ''}`;
const boardPath = getBoardPath(address, defaultSubplebbits);
return `/${boardPath}${useCatalogLinks ? '/catalog' : ''}`;
};
// Handler for placeholder board links
@@ -9,7 +9,8 @@ import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
import { CatalogPostMedia } from '../../../components/catalog-row';
import LoadingEllipsis from '../../../components/loading-ellipsis';
import BoxModal from '../box-modal';
import { MultisubSubplebbit } from '../../../hooks/use-default-subplebbits';
import { MultisubSubplebbit, useDefaultSubplebbits } from '../../../hooks/use-default-subplebbits';
import { getBoardPath } from '../../../lib/utils/route-utils';
import { removeMarkdown } from '../../../lib/utils/post-utils';
interface PopularThreadProps {
@@ -27,16 +28,18 @@ export const ContentPreview = ({ content, maxLength = 99 }: { content: string; m
const PopularThreadCard = ({ post, multisub }: PopularThreadProps) => {
const { cid, content, link, linkHeight, linkWidth, subplebbitAddress, thumbnailUrl, title } = post || {};
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
const defaultSubplebbits = useDefaultSubplebbits();
// Find the matching MultisubSubplebbit entry and get its title
const multisubEntry = multisub.find((ms) => ms?.address === subplebbitAddress);
const boardTitle = multisubEntry?.title?.replace(/^\/[^/]+\/\s*-\s*/, '') || '';
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
return (
<div className={styles.popularThread} key={cid}>
<div className={styles.title}>{boardTitle}</div>
<div className={styles.mediaContainer}>
<Link to={`/p/${subplebbitAddress}/c/${cid}`}>
<Link to={`/${boardPath}/thread/${cid}`}>
<CatalogPostMedia commentMediaInfo={commentMediaInfo} isOutOfFeed={true} cid={cid} />
</Link>
</div>
+5 -2
View File
@@ -13,7 +13,10 @@ const NotFoundImage = () => {
const NotFound = () => {
const location = useLocation();
const subplebbitAddress = location.pathname.startsWith('/p/') ? location.pathname.split('/')[2] : '';
// Extract boardIdentifier from pathname (could be directory code or address)
const pathParts = location.pathname.split('/').filter(Boolean);
const boardIdentifier = pathParts[0] && pathParts[0] !== 'not-found' && pathParts[0] !== 'faq' ? pathParts[0] : '';
const subplebbitAddress = boardIdentifier || '';
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
const { address, shortAddress } = subplebbit || {};
@@ -32,7 +35,7 @@ const NotFound = () => {
<>
<br />
<div className={styles.backToBoard}>
[<Link to={`/p/${subplebbitAddress}`}>Back to p/{shortAddress}</Link>]
[<Link to={`/${boardIdentifier || subplebbitAddress}`}>Back to p/{shortAddress}</Link>]
</div>
</>
)}
+6 -2
View File
@@ -1,6 +1,8 @@
import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useAccountComment, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
import { getBoardPath } from '../../lib/utils/route-utils';
import { Post } from '../post';
const PendingPost = () => {
@@ -9,6 +11,7 @@ const PendingPost = () => {
const commentIndex = accountCommentIndex ? parseInt(accountCommentIndex) : undefined;
const post = useAccountComment({ commentIndex });
const navigate = useNavigate();
const defaultSubplebbits = useDefaultSubplebbits();
useEffect(() => window.scrollTo(0, 0), []);
@@ -28,9 +31,10 @@ const PendingPost = () => {
useEffect(() => {
if (post?.cid && post?.subplebbitAddress) {
navigate(`/p/${post?.subplebbitAddress}/c/${post?.cid}`, { replace: true });
const boardPath = getBoardPath(post.subplebbitAddress, defaultSubplebbits);
navigate(`/${boardPath}/thread/${post.cid}`, { replace: true });
}
}, [post, navigate]);
}, [post, navigate, defaultSubplebbits]);
return <Post post={post} />;
};
+4 -2
View File
@@ -4,6 +4,7 @@ import { Comment, Role, useComment, useEditedComment, useSubplebbit } from '@ple
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
import { useLocation, useParams } from 'react-router-dom';
import { isAllView, isDescriptionView, isRulesView } from '../../lib/utils/view-utils';
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import useIsMobile from '../../hooks/use-is-mobile';
import ErrorDisplay from '../../components/error-display/error-display';
import PostDesktop from '../../components/post-desktop';
@@ -53,7 +54,8 @@ const PostPage = () => {
const { t } = useTranslation();
const params = useParams();
const location = useLocation();
const { commentCid, subplebbitAddress } = params;
const { commentCid } = params;
const subplebbitAddress = useResolvedSubplebbitAddress();
const isInAllView = isAllView(location.pathname);
const isInDescriptionView = isDescriptionView(location.pathname, params);
const isInRulesView = isRulesView(location.pathname, params);
@@ -101,7 +103,7 @@ const PostPage = () => {
avatarUrl={suggested?.avatarUrl}
createdAt={createdAt}
description={description}
replyCount={location.pathname.startsWith('/p/all/') ? 0 : rules?.length > 0 ? 1 : 0}
replyCount={location.pathname.startsWith('/all/') ? 0 : rules?.length > 0 ? 1 : 0}
subplebbitAddress={subplebbitAddress}
shortAddress={shortAddress}
title={title}