mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor(routing): migrate to directory-based board routing
This commit is contained in:
@@ -4,6 +4,9 @@ import { useAccountComment, useSubscribe } from '@plebbit/plebbit-react-hooks';
|
||||
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
|
||||
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
||||
import { isAllView, isCatalogView, isDescriptionView, isModView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
|
||||
import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
@@ -29,19 +32,21 @@ interface BoardButtonsProps {
|
||||
const CatalogButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const createCatalogLink = () => {
|
||||
if (isInAllView) {
|
||||
if (params?.timeFilterName) return `/p/all/catalog/${params.timeFilterName}`;
|
||||
return `/p/all/catalog`;
|
||||
if (params?.timeFilterName) return `/all/catalog/${params.timeFilterName}`;
|
||||
return `/all/catalog`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
if (params?.timeFilterName) return `/p/subscriptions/catalog/${params.timeFilterName}`;
|
||||
return `/p/subscriptions/catalog`;
|
||||
if (params?.timeFilterName) return `/subscriptions/catalog/${params.timeFilterName}`;
|
||||
return `/subscriptions/catalog`;
|
||||
} else if (isInModView) {
|
||||
if (params?.timeFilterName) return `/p/mod/catalog/${params.timeFilterName}`;
|
||||
return `/p/mod/catalog`;
|
||||
if (params?.timeFilterName) return `/mod/catalog/${params.timeFilterName}`;
|
||||
return `/mod/catalog`;
|
||||
}
|
||||
return `/p/${address}/catalog`;
|
||||
const boardPath = address ? getBoardPath(address, defaultSubplebbits) : address;
|
||||
return `/${boardPath}/catalog`;
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -65,19 +70,21 @@ const SubscribeButton = ({ address }: BoardButtonsProps) => {
|
||||
const ReturnButton = ({ address, isInAllView, isInSubscriptionsView, isInModView }: BoardButtonsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const params = useParams();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const createReturnLink = () => {
|
||||
if (isInAllView) {
|
||||
if (params?.timeFilterName) return `/p/all/${params.timeFilterName}`;
|
||||
return `/p/all`;
|
||||
if (params?.timeFilterName) return `/all/${params.timeFilterName}`;
|
||||
return `/all`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
if (params?.timeFilterName) return `/p/subscriptions/${params.timeFilterName}`;
|
||||
return `/p/subscriptions`;
|
||||
if (params?.timeFilterName) return `/subscriptions/${params.timeFilterName}`;
|
||||
return `/subscriptions`;
|
||||
} else if (isInModView) {
|
||||
if (params?.timeFilterName) return `/p/mod/${params.timeFilterName}`;
|
||||
return `/p/mod`;
|
||||
if (params?.timeFilterName) return `/mod/${params.timeFilterName}`;
|
||||
return `/mod`;
|
||||
}
|
||||
return `/p/${address}`;
|
||||
const boardPath = address ? getBoardPath(address, defaultSubplebbits) : address;
|
||||
return `/${boardPath}`;
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -206,16 +213,16 @@ export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView
|
||||
const timeFilterName = event.target.value;
|
||||
const link = isInAllView
|
||||
? isInCatalogView
|
||||
? `/p/all/catalog/${timeFilterName}`
|
||||
: `/p/all/${timeFilterName}`
|
||||
? `/all/catalog/${timeFilterName}`
|
||||
: `/all/${timeFilterName}`
|
||||
: isInSubscriptionsView
|
||||
? isInCatalogView
|
||||
? `/p/subscriptions/catalog/${timeFilterName}`
|
||||
: `/p/subscriptions/${timeFilterName}`
|
||||
? `/subscriptions/catalog/${timeFilterName}`
|
||||
: `/subscriptions/${timeFilterName}`
|
||||
: isInModView
|
||||
? isInCatalogView
|
||||
? `/p/mod/catalog/${timeFilterName}`
|
||||
: `/p/mod/${timeFilterName}`
|
||||
? `/mod/catalog/${timeFilterName}`
|
||||
: `/mod/${timeFilterName}`
|
||||
: null;
|
||||
link && navigate(link);
|
||||
};
|
||||
@@ -256,7 +263,8 @@ export const MobileBoardButtons = () => {
|
||||
const isInModView = isModView(location.pathname);
|
||||
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const { filteredCount, searchText } = useCatalogFiltersStore();
|
||||
|
||||
@@ -319,11 +327,12 @@ const PostPageStats = () => {
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const isInDescriptionView = isDescriptionView(location.pathname, params);
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
|
||||
const comment = useSubplebbitsPagesStore((state) => state.comments[params?.commentCid as string]);
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[params?.subplebbitAddress as string]);
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[resolvedAddress as string]);
|
||||
|
||||
const descriptionReplyCount = location?.pathname.startsWith('/p/all/') ? 0 : subplebbit?.rules?.length > 0 ? 1 : 0;
|
||||
const descriptionReplyCount = location?.pathname.startsWith('/all/') ? 0 : subplebbit?.rules?.length > 0 ? 1 : 0;
|
||||
const { closed, pinned, replyCount } = comment || {};
|
||||
const linkCount = useCountLinksInReplies(comment);
|
||||
|
||||
@@ -344,7 +353,8 @@ export const DesktopBoardButtons = () => {
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInPendingPostPage = isPendingPostView(location.pathname, params);
|
||||
@@ -438,6 +448,9 @@ const SearchOPsBar = () => {
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
const isInModView = isModView(location.pathname);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const boardPath = resolvedAddress ? getBoardPath(resolvedAddress, defaultSubplebbits) : params?.boardIdentifier || params?.subplebbitAddress;
|
||||
|
||||
const handleSearch = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
@@ -447,18 +460,18 @@ const SearchOPsBar = () => {
|
||||
|
||||
if (isInAllView) {
|
||||
catalogUrl = params?.timeFilterName
|
||||
? `/p/all/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/p/all/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
? `/all/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/all/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
} else if (isInSubscriptionsView) {
|
||||
catalogUrl = params?.timeFilterName
|
||||
? `/p/subscriptions/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/p/subscriptions/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
? `/subscriptions/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/subscriptions/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
} else if (isInModView) {
|
||||
catalogUrl = params?.timeFilterName
|
||||
? `/p/mod/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/p/mod/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
? `/mod/catalog/${params.timeFilterName}?q=${encodeURIComponent(searchQuery)}`
|
||||
: `/mod/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
} else {
|
||||
catalogUrl = `/p/${params?.subplebbitAddress}/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
catalogUrl = `/${boardPath}/catalog?q=${encodeURIComponent(searchQuery)}`;
|
||||
}
|
||||
|
||||
navigate(catalogUrl);
|
||||
|
||||
@@ -7,6 +7,7 @@ import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subple
|
||||
import { isAllView, isSubscriptionsView, isModView } from '../../lib/utils/view-utils';
|
||||
import styles from './board-header.module.css';
|
||||
import { useMultisubMetadata, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import { shouldShowSnow } from '../../lib/snow';
|
||||
@@ -28,7 +29,8 @@ const BoardHeader = () => {
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
const isInModView = isModView(location.pathname);
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
|
||||
|
||||
@@ -47,7 +49,7 @@ const BoardHeader = () => {
|
||||
: isInModView
|
||||
? _.startCase(t('boards_you_moderate'))
|
||||
: defaultSubplebbit?.title || subplebbit?.title;
|
||||
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : isInModView ? 'p/mod' : `p/${address}`;
|
||||
const subtitle = isInAllView ? 'p/all' : isInSubscriptionsView ? 'p/subscriptions' : isInModView ? 'p/mod' : `p/${address || subplebbitAddress || ''}`;
|
||||
|
||||
const { isOffline, isOnlineStatusLoading, offlineIconClass, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import { shouldShowSnow } from '../../lib/snow';
|
||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
|
||||
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
|
||||
import useEditCommentPrivileges from '../../hooks/use-author-privileges';
|
||||
@@ -138,8 +140,10 @@ const CatalogPost = ({ post }: { post: Comment }) => {
|
||||
const params = useParams();
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
|
||||
const postLink = isInAllView && isDescription ? `/p/all/description` : `/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${cid}`}`;
|
||||
const postLink = isInAllView && isDescription ? '/all/description' : `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${cid}`}`;
|
||||
|
||||
const threadIcons = (
|
||||
<div className={styles.threadIcons}>
|
||||
|
||||
@@ -172,9 +172,9 @@ const renderAnchorLink = (children: React.ReactNode, href: string) => {
|
||||
shouldReplaceText = children[0] === href || children[0].trim() === href.trim();
|
||||
}
|
||||
|
||||
// For display purposes, remove leading slash from paths like "/p/something"
|
||||
// For display purposes, remove leading slash from paths like "/biz" or board identifiers
|
||||
let displayText: React.ReactNode = children;
|
||||
if (shouldReplaceText && internalPath.startsWith('/p/')) {
|
||||
if (shouldReplaceText && internalPath.match(/^\/[^/]+$/)) {
|
||||
displayText = internalPath.substring(1); // Remove leading slash
|
||||
} else if (shouldReplaceText) {
|
||||
displayText = internalPath;
|
||||
@@ -188,7 +188,15 @@ const renderAnchorLink = (children: React.ReactNode, href: string) => {
|
||||
}
|
||||
|
||||
// Handle hash routes and internal patterns (including routes that start with /#/)
|
||||
if (href.startsWith('#/') || href.startsWith('/#/') || href.startsWith('/p/') || href.match(/^\/p\/[^/]+(\/c\/[^/]+)?$/)) {
|
||||
// Support both old format (/p/...) for backward compatibility and new format (/{boardIdentifier}/...)
|
||||
if (
|
||||
href.startsWith('#/') ||
|
||||
href.startsWith('/#/') ||
|
||||
href.startsWith('/p/') ||
|
||||
href.match(/^\/p\/[^/]+(\/c\/[^/]+)?$/) ||
|
||||
href.match(/^\/[^/]+(\/thread\/[^/]+)?$/) ||
|
||||
href.match(/^\/[^/]+\/(catalog|description|rules)(\/settings)?$/)
|
||||
) {
|
||||
return <Link to={href}>{children}</Link>;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/po
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||
import { useCommentMediaInfo } from '../../hooks/use-comment-media-info';
|
||||
@@ -62,6 +64,8 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
const { showOmittedReplies } = useShowOmittedReplies();
|
||||
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
|
||||
const { hideAvatars } = useAvatarVisibilityStore();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
|
||||
const params = useParams();
|
||||
const location = useLocation();
|
||||
@@ -165,13 +169,13 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && !isReply && (
|
||||
<span className={styles.postNumLink}>
|
||||
{' '}
|
||||
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>{' '}
|
||||
<Link to={`/${boardPath}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>{' '}
|
||||
</span>
|
||||
)}
|
||||
{!(isDescription || isRules) &&
|
||||
(cid ? (
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
<Link to={`/${boardPath}/thread/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
|
||||
@@ -200,7 +204,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
|
||||
<span className={styles.replyButton}>
|
||||
[
|
||||
<Link
|
||||
to={isInAllView && isDescription ? '/p/all/description' : `/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${postCid}`}`}
|
||||
to={isInAllView && isDescription ? '/all/description' : `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${postCid}`}`}
|
||||
onClick={(e) => !cid && !isDescription && !isRules && e.preventDefault()}
|
||||
>
|
||||
{_.capitalize(t('reply'))}
|
||||
@@ -314,8 +318,10 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
|
||||
|
||||
const { author, cid, deleted, link, linkHeight, linkWidth, postCid, reason, removed, spoiler, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
|
||||
const isRouteLinkToReply = useLocation().pathname.startsWith(`/p/${subplebbitAddress}/c/${cid}`);
|
||||
const isRouteLinkToReply = useLocation().pathname.startsWith(`/${boardPath}/thread/${cid}`);
|
||||
const { hidden } = useHide({ cid });
|
||||
|
||||
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
|
||||
@@ -354,6 +360,8 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
|
||||
const location = useLocation();
|
||||
const isInPendingPostView = isPendingPostView(location.pathname, params);
|
||||
const isInPostPageView = isPostPageView(location.pathname, params);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
|
||||
const { hidden, unhide, hide } = useHide({ cid });
|
||||
const isHidden = hidden && !isInPostPageView;
|
||||
@@ -430,14 +438,14 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
|
||||
<Trans
|
||||
i18nKey={'replies_and_links_omitted'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <Link key={cid} to={`/p/${subplebbitAddress}/c/${cid}`} /> }}
|
||||
components={{ 1: <Link key={cid} to={`/${boardPath}/thread/${cid}`} /> }}
|
||||
values={{ repliesCount, linksCount }}
|
||||
/>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey={'replies_omitted'}
|
||||
shouldUnescape={true}
|
||||
components={{ 1: <Link key={cid} to={`/p/${subplebbitAddress}/c/${cid}`} /> }}
|
||||
components={{ 1: <Link key={cid} to={`/${boardPath}/thread/${cid}`} /> }}
|
||||
values={{ repliesCount }}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isDescriptionView, isModView, isPostPageView, isRulesView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useAnonMode from '../../hooks/use-anon-mode';
|
||||
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import usePublishPost from '../../hooks/use-publish-post';
|
||||
@@ -45,7 +46,8 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
const author = account?.author || {};
|
||||
const { displayName } = author || {};
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
const { setPublishPostOptions, postIndex, publishPost, publishPostOptions, resetPublishPostOptions } = usePublishPost({ subplebbitAddress });
|
||||
|
||||
const textRef = useRef<HTMLTextAreaElement>(null);
|
||||
@@ -160,7 +162,7 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
||||
if (typeof postIndex === 'number') {
|
||||
resetPublishPostOptions();
|
||||
resetFields();
|
||||
navigate(`/profile/${postIndex}`);
|
||||
navigate(`/pending/${postIndex}`);
|
||||
}
|
||||
}, [postIndex, resetPublishPostOptions, navigate]);
|
||||
|
||||
@@ -458,7 +460,8 @@ const PostForm = () => {
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
|
||||
const { isOffline, isOnlineStatusLoading, offlineTitle } = useIsSubplebbitOffline(subplebbit);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store';
|
||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||
import { useCommentMediaInfo } from '../../hooks/use-comment-media-info';
|
||||
@@ -29,6 +31,7 @@ import useReplyModalStore from '../../stores/use-reply-modal-store';
|
||||
|
||||
const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const {
|
||||
author,
|
||||
cid,
|
||||
@@ -48,6 +51,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
timestamp,
|
||||
thumbnailUrl,
|
||||
} = post || {};
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
const isReply = parentCid;
|
||||
const title = post?.title?.trim();
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
@@ -174,14 +178,14 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && !isReply && (
|
||||
<div className={styles.postNumLink}>
|
||||
{' '}
|
||||
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
||||
<Link to={`/${boardPath}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
||||
</div>
|
||||
)}
|
||||
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />{' '}
|
||||
{!(isDescription || isRules) &&
|
||||
(cid ? (
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
<Link to={`/${boardPath}/thread/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
c/
|
||||
</Link>
|
||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
|
||||
@@ -259,7 +263,9 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
|
||||
post = editedComment;
|
||||
}
|
||||
const { author, cid, deleted, postCid, reason, removed, subplebbitAddress } = post || {};
|
||||
const isRouteLinkToReply = useLocation().pathname.startsWith(`/p/${subplebbitAddress}/c/${cid}`);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
const isRouteLinkToReply = useLocation().pathname.startsWith(`/${boardPath}/thread/${cid}`);
|
||||
const { hidden } = useHide({ cid });
|
||||
|
||||
return (
|
||||
@@ -289,6 +295,8 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInPendingPostView = isPendingPostView(location.pathname, params);
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
|
||||
const linksCount = useCountLinksInReplies(post);
|
||||
const replies = useReplies(post);
|
||||
|
||||
@@ -345,7 +353,7 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
|
||||
{linksCount > 0 && ` / ${linksCount} Links`}
|
||||
</span>
|
||||
<Link
|
||||
to={isInAllView && isDescription ? '/p/all/description' : `/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${cid}`}`}
|
||||
to={isInAllView && isDescription ? '/all/description' : `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${cid}`}`}
|
||||
className='button'
|
||||
>
|
||||
{t('view_thread')}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { createPortal } from 'react-dom';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import useAnonModeStore from '../../stores/use-anon-mode-store';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
@@ -58,6 +60,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
const placementRef = useRef<Placement>('right');
|
||||
const availableWidthRef = useRef<number>(0);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: placementRef.current,
|
||||
@@ -100,7 +103,8 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
||||
e.preventDefault();
|
||||
if (cid && subplebbitAddress) {
|
||||
navigate(`/p/${subplebbitAddress}/c/${cid}`);
|
||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
||||
navigate(`/${boardPath}/thread/${cid}`);
|
||||
setTimeout(() => {
|
||||
const element = document.querySelector(`[data-cid="${cid}"]`);
|
||||
element?.scrollIntoView();
|
||||
@@ -131,7 +135,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
<>
|
||||
<Link
|
||||
className={styles.backlink}
|
||||
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
|
||||
to={`/${getBoardPath(backlinkReply?.subplebbitAddress || '', defaultSubplebbits)}/thread/${backlinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
@@ -158,7 +162,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
const replyQuotelink = (
|
||||
<>
|
||||
<Link
|
||||
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
|
||||
to={`/${getBoardPath(quotelinkReply?.subplebbitAddress || '', defaultSubplebbits)}/thread/${quotelinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
className={styles.quoteLink}
|
||||
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
|
||||
@@ -186,6 +190,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: 'bottom',
|
||||
@@ -207,7 +212,8 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
const handleClick = (e: React.MouseEvent, cid: string | undefined, subplebbitAddress: string | undefined) => {
|
||||
e.preventDefault();
|
||||
if (cid && subplebbitAddress) {
|
||||
navigate(`/p/${subplebbitAddress}/c/${cid}`);
|
||||
const boardPath = getBoardPath(subplebbitAddress, defaultSubplebbits);
|
||||
navigate(`/${boardPath}/thread/${cid}`);
|
||||
setTimeout(() => {
|
||||
const element = document.querySelector(`[data-cid="${cid}"]`);
|
||||
element?.scrollIntoView();
|
||||
@@ -246,7 +252,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
</span>
|
||||
{backlinkReply?.shortCid && (
|
||||
<Link
|
||||
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
|
||||
to={`/${getBoardPath(backlinkReply?.subplebbitAddress || '', defaultSubplebbits)}/thread/${backlinkReply?.cid}`}
|
||||
className={styles.backlinkHash}
|
||||
onClick={(e) => handleClick(e, backlinkReply?.cid, backlinkReply?.subplebbitAddress)}
|
||||
>
|
||||
@@ -283,7 +289,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
{quotelinkReply?.shortCid && (
|
||||
<Link
|
||||
className={styles.quoteLink}
|
||||
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
|
||||
to={`/${getBoardPath(quotelinkReply?.subplebbitAddress || '', defaultSubplebbits)}/thread/${quotelinkReply?.cid}`}
|
||||
onClick={(e) => handleClick(e, quotelinkReply?.cid, quotelinkReply?.subplebbitAddress)}
|
||||
>
|
||||
{' '}
|
||||
|
||||
@@ -5,6 +5,7 @@ import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subple
|
||||
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
|
||||
import useSubplebbitStatsVisibilityStore from '../../stores/use-subplebbit-stats-visibility-store';
|
||||
import { isDescriptionView, isRulesView } from '../../lib/utils/view-utils';
|
||||
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import styles from './subplebbit-stats.module.css';
|
||||
|
||||
const SubplebbitStats = () => {
|
||||
@@ -12,7 +13,8 @@ const SubplebbitStats = () => {
|
||||
const params = useParams();
|
||||
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
|
||||
const { address, createdAt } = subplebbit || {};
|
||||
|
||||
@@ -4,7 +4,9 @@ import { useTranslation } from 'react-i18next';
|
||||
import Plebbit from '@plebbit/plebbit-js';
|
||||
import { useAccount, useAccountComment, useAccountSubplebbits } from '@plebbit/plebbit-react-hooks';
|
||||
import { isAllView, isCatalogView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits';
|
||||
import { useDefaultSubplebbitAddresses, useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import { useBoardPath, useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
|
||||
import { getBoardPath } from '../../lib/utils/route-utils';
|
||||
import { TimeFilter } from '../board-buttons';
|
||||
import useCreateBoardModalStore from '../../stores/use-create-board-modal-store';
|
||||
import styles from './topbar.module.css';
|
||||
@@ -55,7 +57,7 @@ const SearchBar = ({ setShowSearchBar }: { setShowSearchBar: (show: boolean) =>
|
||||
const searchInput = searchInputRef.current?.value;
|
||||
if (searchInput) {
|
||||
searchInputRef.current.value = '';
|
||||
navigate(`/p/${searchInput}`);
|
||||
navigate(`/${searchInput}`);
|
||||
setShowSearchBar(false);
|
||||
}
|
||||
};
|
||||
@@ -77,6 +79,7 @@ const TopBarDesktop = () => {
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const [showSearchBar, setShowSearchBar] = useState(false);
|
||||
const { openCreateBoardModal } = useCreateBoardModalStore();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
|
||||
const subscriptions = account?.subscriptions;
|
||||
|
||||
@@ -86,26 +89,28 @@ const TopBarDesktop = () => {
|
||||
return (
|
||||
<div className={styles.boardNavDesktop}>
|
||||
<span className={styles.boardList}>
|
||||
[<Link to='/p/all'>all</Link> / <Link to='/p/subscriptions'>subscriptions</Link>
|
||||
[<Link to='/all'>all</Link> / <Link to='/subscriptions'>subscriptions</Link>
|
||||
{accountSubplebbitAddresses.length > 0 && (
|
||||
<>
|
||||
{' '}
|
||||
/ <Link to='/p/mod'>mod</Link>
|
||||
/ <Link to='/mod'>mod</Link>
|
||||
</>
|
||||
)}
|
||||
]{' '}
|
||||
{subscriptions?.length > 0 && (
|
||||
<>
|
||||
[
|
||||
{subscriptions.map((address: any, index: any) => (
|
||||
<span key={index}>
|
||||
{index === 0 ? null : ' '}
|
||||
<Link to={`/p/${address}${isInCatalogView ? '/catalog' : ''}`}>
|
||||
{address.endsWith('.eth') || address.endsWith('.sol') ? address : address.slice(0, 10).concat('...')}
|
||||
</Link>
|
||||
{index !== subscriptions?.length - 1 ? ' /' : null}
|
||||
</span>
|
||||
))}
|
||||
{subscriptions.map((address: any, index: any) => {
|
||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
||||
const displayText = address.endsWith('.eth') || address.endsWith('.sol') ? address : address.slice(0, 10).concat('...');
|
||||
return (
|
||||
<span key={index}>
|
||||
{index === 0 ? null : ' '}
|
||||
{boardPath && boardPath.trim() ? <Link to={`/${boardPath}${isInCatalogView ? '/catalog' : ''}`}>{displayText}</Link> : <span>{displayText}</span>}
|
||||
{index !== subscriptions?.length - 1 ? ' /' : null}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
]{' '}
|
||||
</>
|
||||
)}
|
||||
@@ -128,6 +133,7 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const subplebbitAddresses = useDefaultSubplebbitAddresses();
|
||||
const defaultSubplebbits = useDefaultSubplebbits();
|
||||
const displaySubplebbitAddress = subplebbitAddress && subplebbitAddress.length > 30 ? subplebbitAddress.slice(0, 30).concat('...') : subplebbitAddress;
|
||||
const [showSearchBar, setShowSearchBar] = useState(false);
|
||||
|
||||
@@ -138,21 +144,36 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||
const isInAllView = isAllView(location.pathname);
|
||||
const isInCatalogView = isCatalogView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : subplebbitAddress;
|
||||
const boardPath = useBoardPath(subplebbitAddress);
|
||||
const selectValue = isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : boardPath || subplebbitAddress;
|
||||
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
||||
|
||||
const boardSelect = (
|
||||
<select value={selectValue} onChange={(e) => navigate(`/p/${e.target.value}${isInCatalogView ? '/catalog' : ''}`)}>
|
||||
<select
|
||||
value={selectValue}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
// If it's a directory code or special route, use it directly
|
||||
if (value === 'all' || value === 'subscriptions' || value === 'mod') {
|
||||
navigate(`/${value}${isInCatalogView ? '/catalog' : ''}`);
|
||||
} else {
|
||||
// Otherwise, resolve to board path
|
||||
const path = getBoardPath(value, defaultSubplebbits);
|
||||
navigate(`/${path}${isInCatalogView ? '/catalog' : ''}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!currentSubplebbitIsInList && subplebbitAddress && <option value={subplebbitAddress}>{displaySubplebbitAddress}</option>}
|
||||
<option value='all'>all</option>
|
||||
<option value='subscriptions'>subscriptions</option>
|
||||
{accountSubplebbitAddresses.length > 0 && <option value='mod'>mod</option>}
|
||||
{subplebbitAddresses.map((address: any, index: number) => {
|
||||
const subplebbitAddress = address?.includes('.') ? address : Plebbit.getShortAddress(address);
|
||||
const boardPath = getBoardPath(address, defaultSubplebbits);
|
||||
return (
|
||||
<option key={index} value={address}>
|
||||
<option key={index} value={boardPath}>
|
||||
{Plebbit.getShortAddress(subplebbitAddress)}
|
||||
</option>
|
||||
);
|
||||
@@ -200,7 +221,8 @@ const TopBarMobile = ({ subplebbitAddress }: { subplebbitAddress: string }) => {
|
||||
const TopBar = () => {
|
||||
const params = useParams();
|
||||
const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any });
|
||||
const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress;
|
||||
const resolvedSubplebbitAddress = useResolvedSubplebbitAddress();
|
||||
const subplebbitAddress = resolvedSubplebbitAddress || accountComment?.subplebbitAddress;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user