diff --git a/src/components/comment-content/comment-content.tsx b/src/components/comment-content/comment-content.tsx index 7b6a99dd..dacedfd5 100644 --- a/src/components/comment-content/comment-content.tsx +++ b/src/components/comment-content/comment-content.tsx @@ -1,8 +1,9 @@ -import { Fragment, useState } from 'react'; +import { Fragment, useMemo, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { Trans, useTranslation } from 'react-i18next'; import { Comment, useComment } from '@plebbit/plebbit-react-hooks'; import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages'; +import usePostNumberStore from '../../stores/use-post-number-store'; import Plebbit from '@plebbit/plebbit-js'; import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isPostPageView } from '../../lib/utils/view-utils'; @@ -52,6 +53,23 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => { const isReply = !!parentCid; const isReplyingToReply = isReply && parentCid !== postCid; + const contentNumbers = useMemo(() => { + if (!content) return new Set(); + const matches = content.matchAll(/(?/\w])>>(\d+)(?![\d/])/g); + return new Set([...matches].map((m) => parseInt(m[1], 10))); + }, [content]); + + const cidToNumber = usePostNumberStore((state) => state.cidToNumber); + const filteredQuotedCids = useMemo(() => { + if (!quotedCids?.length) return []; + return quotedCids.filter((cid: string) => { + const num = cidToNumber[cid]; + return num === undefined || !contentNumbers.has(num); + }); + }, [quotedCids, cidToNumber, contentNumbers]); + + const shouldShowReplyingToReply = isReplyingToReply && (parentCid ? !contentNumbers.has(cidToNumber[parentCid] ?? -1) : true); + const stateString = useStateString(post); const loadingString =
{stateString !== 'Failed' ? : stateString}
; @@ -61,9 +79,9 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => { {isReply && state !== 'failed' && !(deleted || removed) && - (quotedCids?.length > 0 - ? quotedCids.map((cid: string) => ) - : isReplyingToReply && )} + (filteredQuotedCids.length > 0 + ? filteredQuotedCids.map((cid: string) => ) + : shouldShowReplyingToReply && )} {removed ? ( reason ? ( <> @@ -86,7 +104,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => { ) ) : ( <> - {!showOriginal && } + {!showOriginal && } {pendingApproval && ( <>
@@ -102,7 +120,7 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => { )} {edit && original?.content !== content && ( - {showOriginal && } + {showOriginal && }

(tree: any) => { interface MarkdownProps { content: string; title?: string; + postCid?: string; } -const renderAnchorLink = (children: React.ReactNode, href: string) => { +const NUMBER_QUOTE_HREF_REGEX = /^#q-(\d+)$/; + +const NumberQuoteLink = ({ number, threadPostCid }: { number: number; threadPostCid?: string }) => { + const cid = usePostNumberStore((state) => state.numberToCid[number]); + const commentFromStore = useSubplebbitsPagesStore((state) => (cid ? state.comments[cid] : undefined)); + const commentFromHook = useComment({ commentCid: cid, onlyIfCached: true }); + const comment = commentFromHook?.number !== undefined ? commentFromHook : commentFromStore; + const isOP = Boolean(threadPostCid && cid === threadPostCid); + + if (!comment) { + return {`>>${number}`}; + } + + return ; +}; + +const renderAnchorLink = (children: React.ReactNode, href: string, threadPostCid?: string) => { if (!href) { return {children}; } + const numberQuoteMatch = href.match(NUMBER_QUOTE_HREF_REGEX); + if (numberQuoteMatch) { + const number = parseInt(numberQuoteMatch[1], 10); + return ; + } + // Check if this is a valid 5chan link that should be handled internally if (is5chanLink(href)) { const internalPath = transform5chanLinkToInternal(href); @@ -215,7 +242,7 @@ const renderAnchorLink = (children: React.ReactNode, href: string) => { ); }; -const Markdown = ({ content, title }: MarkdownProps) => { +const Markdown = ({ content, title, postCid }: MarkdownProps) => { const remarkPlugins: any[] = [[supersub]]; if (content && content.length <= MAX_LENGTH_FOR_GFM) { @@ -285,10 +312,10 @@ const Markdown = ({ content, title }: MarkdownProps) => { console.debug('Invalid URL:', href); } - return renderAnchorLink(children, href); + return renderAnchorLink(children, href, postCid); } - return renderAnchorLink(children, href || ''); + return renderAnchorLink(children, href || '', postCid); }, } as ExtendedComponents }