refactor: remove description and rules mock posts

Removed all fake posts for subplebbit description and rules, including dedicated routes, components, and all related logic across the codebase. Board admins can now pin regular posts if they want to provide a description.
This commit is contained in:
plebeius
2025-12-23 19:14:25 +01:00
parent 13b0f10a23
commit 5e79ce91b6
24 changed files with 142 additions and 490 deletions
-5
View File
@@ -164,13 +164,8 @@ const App = () => (
<Route path='/:boardIdentifier/catalog' element={null} />
<Route path='/:boardIdentifier/catalog/settings' element={null} />
<Route path='/all/description' element={<Post />} />
<Route path='/:boardIdentifier/thread/:commentCid' element={<Post />} />
<Route path='/:boardIdentifier/thread/:commentCid/settings' element={<Post />} />
<Route path='/:boardIdentifier/description' element={<Post />} />
<Route path='/:boardIdentifier/description/settings' element={<Post />} />
<Route path='/:boardIdentifier/rules' element={<Post />} />
<Route path='/:boardIdentifier/rules/settings' element={<Post />} />
<Route path='/pending/:accountCommentIndex' element={<PendingPost />} />
<Route path='/pending/:accountCommentIndex/settings' element={<PendingPost />} />
@@ -3,7 +3,7 @@ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
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 { isAllView, isCatalogView, isModView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
import { getBoardPath, isDirectoryBoard } from '../../lib/utils/route-utils';
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
@@ -365,23 +365,21 @@ const PostPageStats = () => {
const { t } = useTranslation();
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[resolvedAddress as string]);
const descriptionReplyCount = location?.pathname.startsWith('/all/') ? 0 : subplebbit?.rules?.length > 0 ? 1 : 0;
const { closed, pinned, replyCount } = comment || {};
const linkCount = useCountLinksInReplies(comment);
const displayReplyCount = replyCount !== undefined ? replyCount.toString() : isInDescriptionView ? descriptionReplyCount : '?';
const replyCountTooltip = replyCount !== undefined || isInDescriptionView ? _.capitalize(t('replies')) : t('loading');
const displayReplyCount = replyCount !== undefined ? replyCount.toString() : '?';
const replyCountTooltip = replyCount !== undefined ? _.capitalize(t('replies')) : t('loading');
return (
<span>
{(pinned || isInDescriptionView) && `${_.capitalize(t('sticky'))} / `}
{(closed || isInDescriptionView) && `${_.capitalize(t('closed'))} / `}
{pinned && `${_.capitalize(t('sticky'))} / `}
{closed && `${_.capitalize(t('closed'))} / `}
<Tooltip children={displayReplyCount} content={replyCountTooltip} /> / <Tooltip children={linkCount?.toString()} content={_.capitalize(t('links'))} />
</span>
);
+9 -32
View File
@@ -34,7 +34,7 @@ interface CatalogPostMediaProps {
linkHeight?: number;
}
export const CatalogPostMedia = ({ cid, commentMediaInfo, isOutOfFeed, linkWidth, linkHeight }: CatalogPostMediaProps) => {
export const CatalogPostMedia = ({ cid, commentMediaInfo, linkWidth, linkHeight }: CatalogPostMediaProps) => {
const { patternThumbnailUrl, thumbnail, type, url } = commentMediaInfo || {};
const iframeThumbnail = patternThumbnailUrl || thumbnail;
const gifFrameUrl = useFetchGifFirstFrame(type === 'gif' ? url : undefined);
@@ -58,7 +58,7 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, isOutOfFeed, linkWidth
displayHeight = `${maxThumbnailSize}px`;
}
if (type === 'audio' || isOutOfFeed) {
if (type === 'audio') {
displayWidth = 'unset';
displayHeight = 'unset';
}
@@ -112,24 +112,7 @@ export const CatalogPostMedia = ({ cid, commentMediaInfo, isOutOfFeed, linkWidth
const CatalogPost = ({ post }: { post: Comment }) => {
const { t } = useTranslation();
const {
author,
cid,
content,
isDescription,
isRules,
link,
linkHeight,
linkWidth,
locked,
pinned,
replyCount,
spoiler,
subplebbitAddress,
timestamp,
title,
thumbnailUrl,
} = post || {};
const { author, cid, content, link, linkHeight, linkWidth, locked, pinned, replyCount, spoiler, subplebbitAddress, timestamp, title, thumbnailUrl } = post || {};
const linkCount = useCountLinksInReplies(post);
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
@@ -145,7 +128,7 @@ const CatalogPost = ({ post }: { post: Comment }) => {
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : '';
const postMenuProps = useMemo(() => selectPostMenuProps(post), [post]);
const postLink = isInAllView && isDescription ? '/all/description' : `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${cid}`}`;
const postLink = boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`;
const threadIcons = (
<div className={styles.threadIcons}>
@@ -236,12 +219,12 @@ const CatalogPost = ({ post }: { post: Comment }) => {
'--maxHeight': maxHeight,
} as React.CSSProperties;
const isTextOnlyThread = !hasThumbnail || isRules;
const isTextOnlyThread = !hasThumbnail;
return (
<>
<div className={`${styles.post} ${imageSize === 'Large' ? styles.large : ''}`} style={CSSProperties}>
<div onMouseOver={() => setHoveredCid(isDescription ? 'd' : isRules ? 'r' : cid)} onMouseLeave={() => setHoveredCid(null)}>
<div onMouseOver={() => setHoveredCid(cid)} onMouseLeave={() => setHoveredCid(null)}>
{hidden ? (
<Link to={postLink}>
<span className={styles.hiddenThumbnail} />
@@ -266,13 +249,7 @@ const CatalogPost = ({ post }: { post: Comment }) => {
{spoiler ? (
<img src='assets/spoiler.png' alt='' />
) : (
<CatalogPostMedia
cid={cid}
commentMediaInfo={commentMediaInfo}
isOutOfFeed={isDescription || isRules}
linkWidth={linkWidth}
linkHeight={linkHeight}
/>
<CatalogPostMedia cid={cid} commentMediaInfo={commentMediaInfo} linkWidth={linkWidth} linkHeight={linkHeight} />
)}
</div>
</Link>
@@ -295,7 +272,7 @@ const CatalogPost = ({ post }: { post: Comment }) => {
<div className={styles.postContent}>{(showOPComment || isTextOnlyThread) && (hasThumbnail ? postContent : <Link to={postLink}>{postContent}</Link>)}</div>
</div>
</div>
{(hoveredCid === cid || isDescription) &&
{hoveredCid === cid &&
showPortal &&
createPortal(
<div className={styles.postPreview} ref={refs.setFloating} style={floatingStyles}>
@@ -307,7 +284,7 @@ const CatalogPost = ({ post }: { post: Comment }) => {
) : (
t('posted_by')
)}{' '}
<span className={`${styles.postAuthor} ${(isCatalogPostAuthorMod || isRules || isDescription) && styles.capcode}`}>
<span className={`${styles.postAuthor} ${isCatalogPostAuthorMod && styles.capcode}`}>
{author?.displayName || _.capitalize(t('anonymous'))}
{isCatalogPostAuthorMod && <span className='capitalize'>{` ## Board ${catalogPostAuthorRole}`}</span>}
</span>
@@ -23,7 +23,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
const isMobile = useIsMobile();
// TODO: commentAuthor is not yet available outside of editedComment, wait for API to be updated
const { cid, content, deleted, edit, isRules, original, parentCid, postCid, reason, removed, state } = post || {};
const { cid, content, deleted, edit, original, parentCid, postCid, reason, removed, state } = post || {};
// const banned = !!post?.commentAuthor?.banExpiresAt;
const [showFullComment, setShowFullComment] = useState(false);
@@ -45,7 +45,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
const loadingString = <div className={styles.stateString}>{stateString !== 'Failed' ? <LoadingEllipsis string={stateString || t('loading')} /> : stateString}</div>;
return (
<blockquote className={`${styles.postMessage} ${!isReply && isMobile && styles.clampLines} ${isRules && styles.rulesMessage}`}>
<blockquote className={`${styles.postMessage} ${!isReply && isMobile && styles.clampLines}`}>
{isReply && state !== 'failed' && isReplyingToReply && !(deleted || removed) && <ReplyQuotePreview isQuotelinkReply={true} quotelinkReply={quotelinkReply} />}
{removed ? (
reason ? (
@@ -13,8 +13,6 @@ interface MediaProps {
deleted?: boolean;
displayHeight?: string;
displayWidth?: string;
isDescription?: boolean;
isRules?: boolean;
isFloatingEmbed?: boolean;
isOutOfFeed?: boolean;
isReply?: boolean;
@@ -204,9 +202,7 @@ const Image = ({ commentMediaInfo, displayHeight, displayWidth, isOutOfFeed, par
const CommentMedia = ({
commentMediaInfo,
deleted,
isDescription,
isFloatingEmbed,
isRules,
linkHeight,
linkWidth,
parentCid,
@@ -251,7 +247,7 @@ const CommentMedia = ({
displayWidth = '100%';
displayHeight = '100%';
}
const isOutOfFeed = isDescription || isRules || isFloatingEmbed || spoiler || false; // virtuoso wrapper unneeded
const isOutOfFeed = isFloatingEmbed || spoiler || false; // virtuoso wrapper unneeded
return (
<span className={styles.content}>
+2 -2
View File
@@ -32,7 +32,7 @@ const timestampToDays = (timestamp: number) => {
const EditMenu = ({ post }: { post: Comment }) => {
const { t } = useTranslation();
const isMobile = useIsMobile();
const { author, cid, content, deleted, isRules, locked, parentCid, pinned, postCid, reason, removed, spoiler, subplebbitAddress } = post || {};
const { author, cid, content, deleted, locked, parentCid, pinned, postCid, reason, removed, spoiler, subplebbitAddress } = post || {};
const [isEditMenuOpen, setIsEditMenuOpen] = useState(false);
const [isContentEditorOpen, setIsContentEditorOpen] = useState(false);
@@ -216,7 +216,7 @@ const EditMenu = ({ post }: { post: Comment }) => {
setIsEditMenuOpen(!isEditMenuOpen);
} else {
setIsEditMenuOpen(false);
alert(parentCid || isRules ? t('cannot_edit_reply') : t('cannot_edit_thread'));
alert(parentCid ? t('cannot_edit_reply') : t('cannot_edit_thread'));
}
}}
checked={isEditMenuOpen}
+52 -104
View File
@@ -58,8 +58,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
const replies = useReplies(post);
const { address, shortAddress } = author || {};
const displayName = author?.displayName?.trim();
const { isDescription, isRules } = post || {}; // custom properties, not from api
const authorRole = roles?.[address]?.role.replace('moderator', 'mod') || (isDescription || isRules ? 'mod' : undefined);
const authorRole = roles?.[address]?.role.replace('moderator', 'mod');
const stateString = useStateString(post);
const isReply = parentCid;
const { showOmittedReplies } = useShowOmittedReplies();
@@ -139,66 +138,60 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
</span>
)}{' '}
</span>
{!(isDescription || isRules) && (
<>
{author?.avatar && !(deleted || removed) && !hideAvatars && avatarImageUrl ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
{author?.avatar && !(deleted || removed) && !hideAvatars && avatarImageUrl ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
</span>
) : null}
(ID:{' '}
{deleted ? (
t('deleted')
) : removed ? (
t('removed')
) : (
<Tooltip
children={
<span
title={t('highlight_posts')}
className={styles.userAddress}
onClick={() => handleUserAddressClick(userID, postCid)}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{userID}
</span>
) : null}
(ID:{' '}
{deleted ? (
t('deleted')
) : removed ? (
t('removed')
) : (
<Tooltip
children={
<span
title={t('highlight_posts')}
className={styles.userAddress}
onClick={() => handleUserAddressClick(userID, postCid)}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{userID}
</span>
}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || showOmittedReplies[postCid] || (postReplyCount < 6 && !pinned)}
/>
)}
){' '}
</>
}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || showOmittedReplies[postCid] || (postReplyCount < 6 && !pinned)}
/>
)}
){' '}
</span>
<span className={styles.dateTime}>
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />
{isDescription || isRules ? '' : ' '}
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />{' '}
</span>
<span className={styles.postNum}>
{!(isDescription || isRules) &&
(cid ? (
<span className={styles.postNumLink}>
<Link
to={boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`}
className={styles.linkToPost}
title={t('link_to_post')}
onClick={(e) => !cid && e.preventDefault()}
>
CID:
</Link>
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
{shortCid}
</span>
{cid ? (
<span className={styles.postNumLink}>
<Link
to={boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`}
className={styles.linkToPost}
title={t('link_to_post')}
onClick={(e) => !cid && e.preventDefault()}
>
CID:
</Link>
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
{shortCid}
</span>
) : (
<>
<span>CID:</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
))}
</span>
) : (
<>
<span>CID:</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
)}
{pinned && (
<span className={`${styles.stickyIconWrapper} ${!locked && styles.addPaddingBeforeReply}`}>
<img src='assets/icons/sticky.gif' alt='' className={styles.stickyIcon} title={t('sticky')} />
@@ -212,16 +205,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
{!isInPostPageView && !isReply && !isHidden && (
<span className={styles.replyButton}>
[
<Link
to={
isInAllView && isDescription
? '/all/description'
: boardPath
? `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${postCid}`}`
: `/${isDescription ? 'description' : isRules ? 'rules' : `thread/${postCid}`}`
}
onClick={(e) => !cid && !isDescription && !isRules && e.preventDefault()}
>
<Link to={boardPath ? `/${boardPath}/thread/${postCid}` : `/thread/${postCid}`} onClick={(e) => !cid && e.preventDefault()}>
{_.capitalize(t('reply'))}
</Link>
]
@@ -246,8 +230,6 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden }: PostProps) => {
interface PostMediaProps {
commentMediaInfo: CommentMediaInfo | undefined;
hasThumbnail: boolean;
isDescription: boolean;
isRules: boolean;
spoiler: boolean;
deleted: boolean;
removed: boolean;
@@ -262,8 +244,6 @@ interface PostMediaProps {
const PostMedia = ({
commentMediaInfo,
hasThumbnail,
isDescription,
isRules,
spoiler,
deleted,
removed,
@@ -330,14 +310,11 @@ const PostMedia = ({
<CommentMedia
commentMediaInfo={commentMediaInfo}
deleted={deleted}
isDescription={isDescription}
isRules={isRules}
removed={removed}
linkHeight={linkHeight}
linkWidth={linkWidth}
showThumbnail={showThumbnail}
setShowThumbnail={setShowThumbnail}
isOutOfFeed={isDescription || isRules}
parentCid={parentCid}
spoiler={spoiler}
/>
@@ -356,7 +333,6 @@ 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) : undefined;
@@ -381,8 +357,6 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
<PostMedia
commentMediaInfo={commentMediaInfo}
hasThumbnail={hasThumbnail}
isDescription={isDescription}
isRules={isRules}
spoiler={spoiler}
deleted={deleted}
removed={removed}
@@ -403,7 +377,6 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostProps) => {
const { t } = useTranslation();
const { author, cid, content, deleted, link, linkHeight, linkWidth, pinned, postCid, removed, spoiler, state, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
const { isDescription, isRules } = post || {}; // custom properties, not from api
const params = useParams();
const location = useLocation();
const isInPendingPostView = isPendingPostView(location.pathname, params);
@@ -427,17 +400,6 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
const stateString = useStateString(post) || t('downloading_board');
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
const subplebbitRulesReply = {
isRules: true,
subplebbitAddress,
timestamp: subplebbit?.createdAt,
author: { displayName: _.capitalize(t('anonymous')) },
content: `${subplebbit?.rules?.map((rule: string, index: number) => `${index + 1}. ${rule}`).join('\n')}`,
replyCount: 0,
};
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
@@ -451,7 +413,7 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
<div className={styles.replyQuotePreviewSpacer} />
)}
<div className={isHidden ? styles.postDesktopHidden : ''}>
{!isInPostPageView && !isDescription && !isRules && showReplies && (
{!isInPostPageView && showReplies && (
<span className={`${styles.hideButtonWrapper} ${!hasThumbnail ? styles.hideButtonWrapperNoImage : ''}`}>
<span className={`${styles.hideButton} ${hidden ? styles.unhideThread : styles.hideThread}`} onClick={hidden ? unhide : hide} />
</span>
@@ -462,8 +424,6 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
<PostMedia
commentMediaInfo={commentMediaInfo}
hasThumbnail={hasThumbnail}
isDescription={isDescription}
isRules={isRules}
spoiler={spoiler}
deleted={deleted}
removed={removed}
@@ -479,7 +439,7 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
{!isHidden && !content && !(deleted || removed) && <div className={styles.spacer} />}
{!isHidden && <CommentContent comment={post} />}
</div>
{!isHidden && !isDescription && !isRules && !isInPendingPostView && (replyCount > 5 || (pinned && repliesCount > 0)) && !isInPostPageView && (
{!isHidden && !isInPendingPostView && (replyCount > 5 || (pinned && repliesCount > 0)) && !isInPostPageView && (
<span className={styles.summary}>
<span
className={`${showOmittedReplies[cid] ? styles.hideOmittedReplies : styles.showOmittedReplies} ${styles.omittedRepliesButtonWrapper}`}
@@ -517,20 +477,8 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
<Reply reply={reply} roles={roles} postReplyCount={replyCount} />
</div>
))}
{isDescription && subplebbit?.rules && subplebbit?.rules.length > 0 && (
<div className={styles.replyContainer}>
<Reply reply={subplebbitRulesReply} />
</div>
)}
</div>
{!isInPendingPostView &&
(!isDescription || (isDescription && !subplebbit?.updatedAt)) &&
!isRules &&
stateString &&
stateString !== 'Failed' &&
state !== 'succeeded' &&
isInPostPageView &&
!(!showReplies && !showAllReplies) ? (
{!isInPendingPostView && stateString && stateString !== 'Failed' && state !== 'succeeded' && isInPostPageView && !(!showReplies && !showAllReplies) ? (
<div className={styles.stateString}>
<br />
<LoadingEllipsis string={stateString} />
@@ -124,7 +124,7 @@ type PostMenuDesktopProps = {
const PostMenuDesktop = ({ postMenu }: PostMenuDesktopProps) => {
const { t } = useTranslation();
const { authorAddress, cid, isDescription, isRules, link, thumbnailUrl, linkWidth, linkHeight, postCid, subplebbitAddress } = postMenu || {};
const { authorAddress, cid, link, thumbnailUrl, linkWidth, linkHeight, postCid, subplebbitAddress } = postMenu || {};
const commentMediaInfo = getCommentMediaInfo(link || '', thumbnailUrl || '', linkWidth ?? 0, linkHeight ?? 0);
const { thumbnail, type, url } = commentMediaInfo || {};
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
@@ -152,7 +152,7 @@ const PostMenuDesktop = ({ postMenu }: PostMenuDesktopProps) => {
const headingId = useId();
const handleMenuClick = () => {
if (cid || isDescription || isRules) {
if (cid) {
setMenuBtnRotated((prev) => !prev);
}
};
@@ -166,21 +166,19 @@ const PostMenuDesktop = ({ postMenu }: PostMenuDesktopProps) => {
className={isInCatalogView ? styles.postMenuBtnCatalog : styles.postMenuBtn}
title='Post menu'
onClick={handleMenuClick}
style={{ transform: menuBtnRotated && (cid || isDescription || isRules) ? 'rotate(90deg)' : 'rotate(0deg)' }}
style={{ transform: menuBtnRotated && cid ? 'rotate(90deg)' : 'rotate(0deg)' }}
>
</span>
</span>
{menuBtnRotated &&
(cid || isDescription || isRules) &&
cid &&
createPortal(
<FloatingFocusManager context={context} modal={false}>
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
{cid && subplebbitAddress && <CopyLinkButton cid={cid} subplebbitAddress={subplebbitAddress} linkType='thread' onClose={handleClose} />}
{cid && <CopyContentIdButton cid={cid} onClose={handleClose} />}
{!cid && isDescription && subplebbitAddress && <CopyLinkButton subplebbitAddress={subplebbitAddress} linkType='description' onClose={handleClose} />}
{!cid && isRules && subplebbitAddress && <CopyLinkButton subplebbitAddress={subplebbitAddress} linkType='rules' onClose={handleClose} />}
{!(isInPostPageView && postCid === cid) && !isDescription && !isRules && (
{!(isInPostPageView && postCid === cid) && (
<div
className={styles.postMenuItem}
onClick={() => {
@@ -192,8 +190,8 @@ const PostMenuDesktop = ({ postMenu }: PostMenuDesktopProps) => {
</div>
)}
{link && isValidURL(link) && (type === 'image' || type === 'gif' || thumbnail) && url && <ImageSearchButton url={url} onClose={handleClose} />}
{!isDescription && !isRules && authorAddress && <BlockUserButton address={authorAddress} />}
{!isDescription && !isRules && (isInAllView || isInSubscriptionsView) && subplebbitAddress && <BlockBoardButton address={subplebbitAddress} />}
{authorAddress && <BlockUserButton address={authorAddress} />}
{(isInAllView || isInSubscriptionsView) && subplebbitAddress && <BlockBoardButton address={subplebbitAddress} />}
</div>
</FloatingFocusManager>,
document.body,
+2 -4
View File
@@ -8,7 +8,7 @@ import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/s
import { getHasThumbnail, getLinkMediaInfo } from '../../lib/utils/media-utils';
import { formatMarkdown } from '../../lib/utils/post-utils';
import { isValidURL } from '../../lib/utils/url-utils';
import { isAllView, isDescriptionView, isModView, isPostPageView, isRulesView, isSubscriptionsView } from '../../lib/utils/view-utils';
import { isAllView, isModView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
import { useResolvedSubplebbitAddress } from '../../hooks/use-resolved-subplebbit-address';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
@@ -357,9 +357,7 @@ const PostForm = () => {
const { t } = useTranslation();
const location = useLocation();
const params = useParams();
const isInDescriptionView = isDescriptionView(location.pathname, params);
const isInPostView = isPostPageView(location.pathname, params);
const isInRulesView = isRulesView(location.pathname, params);
const isInAllView = isAllView(location.pathname);
const isInModView = isModView(location.pathname);
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
@@ -374,7 +372,7 @@ const PostForm = () => {
}
const { deleted, locked, removed, postCid } = comment || {};
const isThreadClosed = deleted || locked || removed || isInDescriptionView || isInRulesView;
const isThreadClosed = deleted || locked || removed;
const [showForm, setShowForm] = useState(false);
@@ -135,8 +135,7 @@ type PostMenuMobileProps = {
};
const PostMenuMobile = ({ postMenu, editMenuPost }: PostMenuMobileProps) => {
const { authorAddress, cid, deleted, isDescription, isRules, link, linkHeight, linkWidth, parentCid, postCid, removed, subplebbitAddress, thumbnailUrl } =
postMenu || {};
const { authorAddress, cid, deleted, link, linkHeight, linkWidth, parentCid, postCid, removed, subplebbitAddress, thumbnailUrl } = postMenu || {};
const { isAccountMod, isAccountCommentAuthor } = useEditCommentPrivileges({ commentAuthorAddress: authorAddress, subplebbitAddress });
const commentMediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
const { thumbnail, type, url } = commentMediaInfo || {};
@@ -155,7 +154,7 @@ const PostMenuMobile = ({ postMenu, editMenuPost }: PostMenuMobileProps) => {
const headingId = useId();
const handleMenuClick = () => {
if (cid || isDescription || isRules) {
if (cid) {
setIsMenuOpen((prev) => !prev);
}
};
@@ -172,17 +171,15 @@ const PostMenuMobile = ({ postMenu, editMenuPost }: PostMenuMobileProps) => {
...
</span>
{isMenuOpen &&
(cid || isDescription || isRules) &&
cid &&
createPortal(
<FloatingFocusManager context={context} modal={false}>
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
{cid && subplebbitAddress && <CopyLinkButton cid={cid} subplebbitAddress={subplebbitAddress} linkType='thread' onClose={handleClose} />}
{cid && <CopyContentIdButton cid={cid} onClose={handleClose} />}
{!cid && isDescription && subplebbitAddress && <CopyLinkButton subplebbitAddress={subplebbitAddress} linkType='description' onClose={handleClose} />}
{!cid && isRules && subplebbitAddress && <CopyLinkButton subplebbitAddress={subplebbitAddress} linkType='rules' onClose={handleClose} />}
{cid && subplebbitAddress && <HidePostButton cid={cid} isReply={!!parentCid} postCid={postCid} onClose={handleClose} />}
{cid && subplebbitAddress && !isDescription && !isRules && authorAddress && <BlockUserButton address={authorAddress} />}
{cid && subplebbitAddress && !isInBoardView && !isDescription && !isRules && <BlockBoardButton address={subplebbitAddress} />}
{cid && subplebbitAddress && authorAddress && <BlockUserButton address={authorAddress} />}
{cid && subplebbitAddress && !isInBoardView && <BlockBoardButton address={subplebbitAddress} />}
{link && isValidURL(link) && (type === 'image' || type === 'gif' || thumbnail) && url && <ImageSearchButtons url={url} onClose={handleClose} />}
</div>
</FloatingFocusManager>,
+49 -92
View File
@@ -55,10 +55,9 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
const boardPath = subplebbitAddress ? getBoardPath(subplebbitAddress, defaultSubplebbits) : undefined;
const isReply = parentCid;
const title = post?.title?.trim();
const { isDescription, isRules } = post || {}; // custom properties, not from api
const { address, shortAddress } = author || {};
const displayName = author?.displayName?.trim();
const authorRole = roles?.[address]?.role.replace('moderator', 'mod') || (isDescription || isRules ? 'mod' : undefined);
const authorRole = roles?.[address]?.role.replace('moderator', 'mod');
const { imageUrl: avatarImageUrl } = useAuthorAvatar({ author });
const { hideAvatars } = useAvatarVisibilityStore();
@@ -134,37 +133,33 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
</span>
)}
</span>
{!(isDescription || isRules) && (
<>
{author?.avatar && !(deleted || removed) && !hideAvatars && avatarImageUrl ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
{author?.avatar && !(deleted || removed) && !hideAvatars && avatarImageUrl ? (
<span className={styles.authorAvatar}>
<img src={avatarImageUrl} alt='' />
</span>
) : null}
(ID: {''}
{removed ? (
_.lowerCase(t('removed'))
) : deleted ? (
_.lowerCase(t('deleted'))
) : (
<Tooltip
children={
<span
title={t('highlight_posts')}
className={styles.userAddress}
onClick={() => handleUserAddressClick(userID, postCid)}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{userID}
</span>
) : null}
(ID: {''}
{removed ? (
_.lowerCase(t('removed'))
) : deleted ? (
_.lowerCase(t('deleted'))
) : (
<Tooltip
children={
<span
title={t('highlight_posts')}
className={styles.userAddress}
onClick={() => handleUserAddressClick(userID, postCid)}
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{userID}
</span>
}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || postReplyCount < 6}
/>
)}
){' '}
</>
}
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || postReplyCount < 6}
/>
)}
){' '}
{pinned && (
<span className={styles.stickyIconWrapper}>
<img src='assets/icons/sticky.gif' alt='' className={styles.stickyIcon} title={t('sticky')} />
@@ -196,29 +191,28 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
</div>
)}
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />{' '}
{!(isDescription || isRules) &&
(cid ? (
<span className={styles.postNumLink}>
<Link
to={boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`}
className={styles.linkToPost}
title={t('link_to_post')}
onClick={(e) => !cid && e.preventDefault()}
>
CID:
</Link>
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
{shortCid.slice(0, -4)}
</span>
{cid ? (
<span className={styles.postNumLink}>
<Link
to={boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`}
className={styles.linkToPost}
title={t('link_to_post')}
onClick={(e) => !cid && e.preventDefault()}
>
CID:
</Link>
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={onReplyModalClick}>
{shortCid.slice(0, -4)}
</span>
) : (
<>
<span>CID:</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
))}
</span>
) : (
<>
<span>CID:</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
</>
)}
</span>
</span>
</div>
@@ -229,7 +223,6 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles }: PostProps) => {
const PostMediaContent = ({ post, link }: { post: any; link: string }) => {
const [showThumbnail, setShowThumbnail] = useState(true);
const { isDescription, isRules } = post || {}; // custom properties, not from api
const { thumbnailUrl, linkWidth, linkHeight, spoiler, deleted, removed, parentCid } = post || {};
const commentMediaInfo = useCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
@@ -239,14 +232,11 @@ const PostMediaContent = ({ post, link }: { post: any; link: string }) => {
<CommentMedia
commentMediaInfo={commentMediaInfo}
deleted={deleted}
isDescription={isDescription}
isRules={isRules}
removed={removed}
linkHeight={linkHeight}
linkWidth={linkWidth}
showThumbnail={showThumbnail}
setShowThumbnail={setShowThumbnail}
isOutOfFeed={isDescription || isRules}
parentCid={parentCid}
spoiler={spoiler}
/>
@@ -310,7 +300,6 @@ const Reply = ({ postReplyCount, reply, roles }: PostProps) => {
const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostProps) => {
const { t } = useTranslation();
const { author, cid, pinned, postCid, replyCount, state, subplebbitAddress } = post || {};
const { isDescription, isRules } = post || {}; // custom properties, not from api
const params = useParams();
const location = useLocation();
const isInAllView = isAllView(location.pathname);
@@ -326,17 +315,6 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
const stateString = useStateString(post) || t('loading_post');
const subplebbit = useSubplebbitsStore((state) => state.subplebbits[subplebbitAddress]);
const showRules = isDescription && subplebbit?.rules && subplebbit?.rules.length > 0;
const subplebbitRulesReply = {
isRules: true,
subplebbitAddress,
timestamp: subplebbit?.createdAt,
author: { displayName: _.capitalize(t('anonymous')) },
content: `${subplebbit?.rules?.map((rule: string, index: number) => `${index + 1}. ${rule}`).join('\n')}`,
replyCount: 0,
};
return (
<>
{hidden && !isInPostPageView ? (
@@ -373,16 +351,7 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
{replyCount > 0 && `${replyCount} Replies`}
{linksCount > 0 && ` / ${linksCount} Links`}
</span>
<Link
to={
isInAllView && isDescription
? '/all/description'
: boardPath
? `/${boardPath}/${isDescription ? 'description' : isRules ? 'rules' : `thread/${cid}`}`
: `/${isDescription ? 'description' : isRules ? 'rules' : `thread/${cid}`}`
}
className='button'
>
<Link to={boardPath ? `/${boardPath}/thread/${cid}` : `/thread/${cid}`} className='button'>
{t('view_thread')}
</Link>
</div>
@@ -400,20 +369,8 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
<Reply postReplyCount={replyCount} reply={reply} roles={roles} />
</div>
))}
{showRules && (
<div className={styles.replyContainer}>
<Reply reply={subplebbitRulesReply} />
</div>
)}
</div>
{!isInPendingPostView &&
(!isDescription || (isDescription && !subplebbit?.updatedAt)) &&
!isRules &&
stateString &&
stateString !== 'Failed' &&
state !== 'succeeded' &&
isInPostPageView &&
!(!showReplies && !showAllReplies) ? (
{!isInPendingPostView && stateString && stateString !== 'Failed' && state !== 'succeeded' && isInPostPageView && !(!showReplies && !showAllReplies) ? (
<div className={styles.stateString}>
<LoadingEllipsis string={stateString} />
</div>
@@ -1 +0,0 @@
export { default } from './subplebbit-description';
@@ -1,44 +0,0 @@
import { Post } from '../../views/post';
import { useTranslation } from 'react-i18next';
import { isAllView } from '../../lib/utils/view-utils';
import { useMultisubMetadata } from '../../hooks/use-default-subplebbits';
import { useLocation } from 'react-router-dom';
import _ from 'lodash';
interface DescriptionPostProps {
avatarUrl?: string;
createdAt: number;
description: string;
replyCount: number;
shortAddress: string;
subplebbitAddress: string | undefined;
title: string;
}
const SubplebbitDescription = ({ avatarUrl, createdAt, description, replyCount, shortAddress, subplebbitAddress, title }: DescriptionPostProps) => {
const { t } = useTranslation();
const location = useLocation();
const isInAllView = isAllView(location.pathname);
const multisubMetadata = useMultisubMetadata();
const descriptionSubplebbitAddress = isInAllView ? 'all' : subplebbitAddress;
const post = {
isDescription: true,
subplebbitAddress: descriptionSubplebbitAddress,
timestamp: isInAllView ? multisubMetadata?.createdAt : createdAt,
author: { displayName: _.capitalize(t('anonymous')) },
content: isInAllView ? multisubMetadata?.description : description,
link: avatarUrl,
replyCount,
title: t('welcome_to_board', {
board: isInAllView ? multisubMetadata?.title : title || `p/${shortAddress}`,
interpolation: { escapeValue: false },
}),
pinned: true,
locked: true,
};
return <Post post={post} />;
};
export default SubplebbitDescription;
-1
View File
@@ -1 +0,0 @@
export { default } from './subplebbit-rules';
@@ -1,29 +0,0 @@
import { Post } from '../../views/post';
import { useTranslation } from 'react-i18next';
import _ from 'lodash';
interface RulesPostProps {
subplebbitAddress: string | undefined;
createdAt: number;
rules: string[];
}
const SubplebbitRules = ({ subplebbitAddress, createdAt, rules }: RulesPostProps) => {
const { t } = useTranslation();
const content = rules?.map((rule, index) => `${index + 1}. ${rule}`).join('\n');
const post = {
isRules: true,
subplebbitAddress,
timestamp: createdAt,
author: { displayName: _.capitalize(t('anonymous')) },
content,
replyCount: 0,
title: _.capitalize(t('rules')),
pinned: true,
locked: true,
};
return <Post post={post} />;
};
export default SubplebbitRules;
@@ -4,7 +4,6 @@ import { useAccountComment, useSubplebbitStats } from '@plebbit/plebbit-react-ho
import useSubplebbitsStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits';
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';
@@ -24,12 +23,10 @@ const SubplebbitStats = () => {
const isHidden = hiddenStats[address];
const location = useLocation();
const isInDescriptionView = isDescriptionView(location.pathname, params);
const isInRulesView = isRulesView(location.pathname, params);
const comment = useSubplebbitsPagesStore((state) => state.comments[params?.commentCid as string]);
const { deleted, locked, removed } = comment || {};
const hideStats = deleted || locked || removed || isInDescriptionView || isInRulesView;
const hideStats = deleted || locked || removed;
const unixToMMDDYYYY = (timestamp: number) => {
const date = new Date(timestamp * 1000);
+2 -64
View File
@@ -1,36 +1,19 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { useAccountComments, Subplebbit } from '@plebbit/plebbit-react-hooks';
import useInterfaceSettingsStore from '../stores/use-interface-settings-store';
import { getCommentMediaInfo, getHasThumbnail } from '../lib/utils/media-utils';
import { isAllView } from '../lib/utils/view-utils';
import { useMultisubMetadata } from './use-default-subplebbits';
import _ from 'lodash';
import useCatalogFiltersStore from '../stores/use-catalog-filters-store';
const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolean, subplebbit: Subplebbit) => {
const { t } = useTranslation();
const { address, createdAt, description, rules, shortAddress, suggested, title } = subplebbit || {};
const { avatarUrl } = suggested || {};
const { address } = subplebbit || {};
const { hideThreadsWithoutImages } = useInterfaceSettingsStore();
const location = useLocation();
const isInAllView = isAllView(location.pathname);
const multisub = useMultisubMetadata();
const { accountComments } = useAccountComments();
const { searchText } = useCatalogFiltersStore();
const feedWithFakePostsOnTop = useMemo(() => {
if (!isFeedLoaded) {
return []; // prevent rules and description from appearing while feed is loading
}
if (!description && !rules && !isInAllView) {
return feed;
}
const _feed = [...feed];
// show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update
@@ -65,53 +48,8 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
);
}
// add subplebbit description and rules as fake posts at the top of the feed
if (description && description.length > 0 && !searchText) {
_feed.unshift({
isDescription: true,
subplebbitAddress: address,
timestamp: createdAt,
author: { displayName: `## ${t('board_mods')}` },
content: isInAllView ? multisub?.description : description,
link: avatarUrl,
title: t('welcome_to_board', { board: isInAllView ? multisub?.title : title || `p/${shortAddress}`, interpolation: { escapeValue: false } }),
pinned: true,
locked: true,
});
}
// rules are shown in description thread if both are set
if (rules && rules.length > 0 && !description && !searchText) {
_feed.unshift({
isRules: true,
subplebbitAddress: address,
timestamp: createdAt,
author: { displayName: `## ${t('board_mods')}` },
content: rules.map((rule: string, index: number) => `${index + 1}. ${rule}`).join('\n'),
title: _.capitalize(t('rules')),
pinned: true,
locked: true,
});
}
return _feed;
}, [
accountComments,
feed,
description,
rules,
address,
isFeedLoaded,
createdAt,
title,
shortAddress,
avatarUrl,
t,
isInAllView,
multisub,
hideThreadsWithoutImages,
searchText,
]);
}, [accountComments, feed, address, isFeedLoaded, hideThreadsWithoutImages]);
const rows = useMemo(() => {
const rows = [];
-5
View File
@@ -53,11 +53,6 @@ const useReplies = (comment: Comment) => {
});
}, [flattenedReplies, accountRepliesNotYetPublished]);
// if the comment is a fake comment for description or rules, return an empty array
if (comment?.isDescription || comment?.isRules) {
return [];
}
return repliesAndNotYetPublishedReplies;
};
-4
View File
@@ -5,8 +5,6 @@ export type PostMenuProps = {
postCid?: string;
parentCid?: string;
subplebbitAddress?: string;
isDescription?: boolean;
isRules?: boolean;
authorAddress?: string;
link?: string;
linkWidth?: number;
@@ -21,8 +19,6 @@ export const selectPostMenuProps = (post?: Comment): PostMenuProps => ({
postCid: post?.postCid,
parentCid: post?.parentCid,
subplebbitAddress: post?.subplebbitAddress,
isDescription: post?.isDescription,
isRules: post?.isRules,
authorAddress: post?.author?.address,
link: post?.link,
linkWidth: post?.linkWidth,
-8
View File
@@ -105,8 +105,6 @@ export const isFeedRoute = (pathname: string): boolean => {
const normalizedPath = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
if (normalizedPath.includes('/thread/')) return false;
if (normalizedPath.endsWith('/description')) return false;
if (normalizedPath.endsWith('/rules')) return false;
if (normalizedPath.startsWith('/pending/')) return false;
const pathWithoutSettings = normalizedPath.replace(/\/settings$/, '');
@@ -130,8 +128,6 @@ export const isPostRoute = (pathname: string): boolean => {
const normalizedPath = pathname.replace(/\/settings$/, '');
if (normalizedPath.includes('/thread/')) return true;
if (normalizedPath.endsWith('/description')) return true;
if (normalizedPath.endsWith('/rules')) return true;
return false;
};
@@ -150,10 +146,6 @@ export const getFeedCacheKey = (pathname: string): string | null => {
return parts[0] || null;
}
if (normalizedPath.endsWith('/description') || normalizedPath.endsWith('/rules')) {
return normalizedPath.replace(/\/(description|rules)$/, '');
}
if (normalizedPath.startsWith('/pending/')) {
return null;
}
+2 -5
View File
@@ -17,11 +17,10 @@ export const isValidURL = (url: string) => {
}
};
export type ShareLinkType = 'thread' | 'description' | 'rules';
export type ShareLinkType = 'thread';
// Copies a share link to clipboard for a board, thread, description, or rules page
export function copyShareLinkToClipboard(boardIdentifier: string, linkType: 'thread', cid: string): Promise<void>;
export function copyShareLinkToClipboard(boardIdentifier: string, linkType: Exclude<ShareLinkType, 'thread'>, cid?: undefined): Promise<void>;
export async function copyShareLinkToClipboard(boardIdentifier: string, linkType: ShareLinkType, cid?: string): Promise<void> {
if (linkType === 'thread') {
if (!cid) {
@@ -71,12 +70,10 @@ export const is5chanLink = (url: string): boolean => {
// - /{boardIdentifier} (directory code or address)
// - /{boardIdentifier}/thread/{commentCid}
// - /{boardIdentifier}/catalog
// - /{boardIdentifier}/description
// - /{boardIdentifier}/rules
// - /all, /subs, /mod, /pending/{index}
return (
/^\/p\/[^/]+(\/c\/[^/]+)?$/.test(routePath) ||
/^\/[^/]+(\/thread\/[^/]+|\/catalog|\/description|\/rules)?$/.test(routePath) ||
/^\/[^/]+(\/thread\/[^/]+|\/catalog)?$/.test(routePath) ||
/^\/(all|subscriptions|mod)(\/catalog|\/thread\/[^/]+)?(\/[^/]+)?$/.test(routePath) ||
/^\/pending\/[^/]+$/.test(routePath)
);
+1 -21
View File
@@ -51,12 +51,6 @@ export const isCatalogView = (pathname: string, params: ParamsType): boolean =>
);
};
export const isDescriptionView = (pathname: string, params: ParamsType): boolean => {
const decodedPathname = decodeURIComponent(pathname);
const identifier = params.boardIdentifier || params.subplebbitAddress;
return pathname === '/all/description' ? true : identifier ? decodedPathname.startsWith(`/${identifier}/description`) : false;
};
export const isHomeView = (pathname: string): boolean => {
return pathname === '/';
};
@@ -70,29 +64,17 @@ export const isPendingPostView = (pathname: string, params: ParamsType): boolean
};
export const isPostPageView = (pathname: string, params: ParamsType): boolean => {
if (isDescriptionView(pathname, params) || isRulesView(pathname, params)) {
return true;
}
const decodedPathname = decodeURIComponent(pathname);
const identifier = params.boardIdentifier || params.subplebbitAddress;
return identifier && params.commentCid ? decodedPathname.startsWith(`/${identifier}/thread/${params.commentCid}`) : false;
};
export const isRulesView = (pathname: string, params: ParamsType): boolean => {
const decodedPathname = decodeURIComponent(pathname);
const identifier = params.boardIdentifier || params.subplebbitAddress;
return identifier ? decodedPathname.startsWith(`/${identifier}/rules`) : false;
};
export const isSettingsView = (pathname: string, params: ParamsType): boolean => {
const { accountCommentIndex, boardIdentifier, commentCid, subplebbitAddress } = params;
const identifier = boardIdentifier || subplebbitAddress;
const decodedPathname = decodeURIComponent(pathname);
return (
(identifier && commentCid && decodedPathname === `/${identifier}/thread/${commentCid}/settings`) ||
(identifier && decodedPathname === `/${identifier}/description/settings`) ||
(identifier && decodedPathname === `/${identifier}/rules/settings`) ||
decodedPathname === `/pending/${accountCommentIndex}/settings`
(identifier && commentCid && decodedPathname === `/${identifier}/thread/${commentCid}/settings`) || decodedPathname === `/pending/${accountCommentIndex}/settings`
);
};
@@ -115,11 +97,9 @@ export const isNotFoundView = (pathname: string, params: ParamsType): boolean =>
!isAllView(pathname) &&
!isBoardView(pathname, params) &&
!isCatalogView(pathname, params) &&
!isDescriptionView(pathname, params) &&
!isHomeView(pathname) &&
!isPendingPostView(pathname, params) &&
!isPostPageView(pathname, params) &&
!isRulesView(pathname, params) &&
!isSettingsView(pathname, params) &&
!isSubscriptionsView(pathname, params)
);
-14
View File
@@ -16,8 +16,6 @@ import useSortingStore from '../../stores/use-sorting-store';
import { getSubplebbitAddress } from '../../lib/utils/route-utils';
import ErrorDisplay from '../../components/error-display/error-display';
import LoadingEllipsis from '../../components/loading-ellipsis';
import SubplebbitDescription from '../../components/subplebbit-description';
import SubplebbitRules from '../../components/subplebbit-rules';
import { Post } from '../post';
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
@@ -336,23 +334,11 @@ const Board = ({ feedCacheKey, viewType, boardIdentifier: boardIdentifierProp, t
<>
{shouldShowSnow() && <hr />}
<div className={`${styles.content} ${shouldShowSnow() ? styles.garland : ''}`}>
{((description && description.length > 0) || isInAllView) && (
<SubplebbitDescription
avatarUrl={suggested?.avatarUrl}
subplebbitAddress={subplebbitAddress}
createdAt={createdAt}
description={description}
replyCount={isInAllView ? 0 : rules?.length > 0 ? 1 : 0}
shortAddress={shortAddress}
title={title}
/>
)}
{shouldShowErrorToUser && (
<div className={styles.error}>
<ErrorDisplay error={error} />
</div>
)}
{rules && !description && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
<Virtuoso
increaseViewportBy={{ bottom: 1200, top: 1200 }}
totalCount={combinedFeed.length}
+2 -20
View File
@@ -3,14 +3,12 @@ import { useTranslation } from 'react-i18next';
import { Comment, Role, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
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 { isAllView } 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';
import PostMobile from '../../components/post-mobile';
import SubplebbitDescription from '../../components/subplebbit-description';
import SubplebbitRules from '../../components/subplebbit-rules';
import styles from './post.module.css';
export interface PostProps {
@@ -57,8 +55,6 @@ const PostPage = () => {
const { commentCid } = params;
const subplebbitAddress = useResolvedSubplebbitAddress();
const isInAllView = isAllView(location.pathname);
const isInDescriptionView = isDescriptionView(location.pathname, params);
const isInRulesView = isRulesView(location.pathname, params);
const comment = useComment({ commentCid });
const subplebbit = useSubplebbit({ subplebbitAddress });
@@ -98,21 +94,7 @@ const PostPage = () => {
<ErrorDisplay error={error} />
</div>
)}
{isInDescriptionView ? (
<SubplebbitDescription
avatarUrl={suggested?.avatarUrl}
createdAt={createdAt}
description={description}
replyCount={location.pathname.startsWith('/all/') ? 0 : rules?.length > 0 ? 1 : 0}
subplebbitAddress={subplebbitAddress}
shortAddress={shortAddress}
title={title}
/>
) : isInRulesView ? (
<SubplebbitRules createdAt={createdAt} rules={rules} subplebbitAddress={subplebbitAddress} />
) : (
<Post post={post} showAllReplies={true} />
)}
<Post post={post} showAllReplies={true} />
</div>
);
};