Skip to content

Commit 702816f

Browse files
committed
fix: include manual post-number quotes in reply backlinks
Backlink map generation now merges protocol-level quotedCids with parsed >>number references from reply content. Manual quotes are resolved through numberToCid from usePostNumberStore and deduplicated using Set. Centralized QUOTE_NUMBER_REGEX in url-utils to keep markdown conversion and backlink detection aligned.
1 parent 35783ff commit 702816f

File tree

3 files changed

+51
-17
lines changed

3 files changed

+51
-17
lines changed

src/components/post-desktop/post-desktop.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import styles from '../../views/post/post.module.css';
88
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
99
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
1010
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
11-
import { isValidURL } from '../../lib/utils/url-utils';
11+
import { isValidURL, QUOTE_NUMBER_REGEX } from '../../lib/utils/url-utils';
1212
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
1313
import { formatUserIDForDisplay } from '../../lib/utils/string-utils';
1414
import useModQueueStore from '../../stores/use-mod-queue-store';
@@ -620,6 +620,7 @@ const PostDesktop = ({
620620

621621
const { replies, hasMore, loadMore } = useReplies({ comment: post, flat: true, accountComments: { newerThan: Infinity } });
622622
const registerComments = usePostNumberStore((s) => s.registerComments);
623+
const numberToCid = usePostNumberStore((s) => s.numberToCid);
623624
const prevCidsRef = useRef<string>('');
624625
useEffect(() => {
625626
const all = post ? [post, ...(replies || [])] : replies || [];
@@ -653,17 +654,32 @@ const PostDesktop = ({
653654
const quotedByMap = useMemo(() => {
654655
const map = new Map<string, Comment[]>();
655656
for (const reply of filteredReplies) {
656-
const quotedCids = reply.quotedCids;
657-
if (quotedCids?.length) {
658-
for (const quotedCid of quotedCids) {
659-
const arr = map.get(quotedCid);
660-
if (arr) arr.push(reply);
661-
else map.set(quotedCid, [reply]);
657+
const cidSet = new Set<string>();
658+
659+
if (reply.quotedCids?.length) {
660+
for (const quotedCid of reply.quotedCids) {
661+
cidSet.add(quotedCid);
662+
}
663+
}
664+
665+
if (reply.content) {
666+
for (const match of reply.content.matchAll(QUOTE_NUMBER_REGEX)) {
667+
const postNumber = parseInt(match[1], 10);
668+
const quotedCid = numberToCid[postNumber];
669+
if (quotedCid) {
670+
cidSet.add(quotedCid);
671+
}
662672
}
663673
}
674+
675+
for (const quotedCid of cidSet) {
676+
const arr = map.get(quotedCid);
677+
if (arr) arr.push(reply);
678+
else map.set(quotedCid, [reply]);
679+
}
664680
}
665681
return map;
666-
}, [filteredReplies]);
682+
}, [filteredReplies, numberToCid]);
667683

668684
// Virtuoso scroll position management for infinite replies
669685
const virtuosoRef = useRef<VirtuosoHandle | null>(null);

src/components/post-mobile/post-mobile.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { shouldShowSnow } from '../../lib/snow';
99
import { getHasThumbnail } from '../../lib/utils/media-utils';
1010
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
1111
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
12+
import { QUOTE_NUMBER_REGEX } from '../../lib/utils/url-utils';
1213
import { isAllView, isModQueueView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
1314
import { formatUserIDForDisplay } from '../../lib/utils/string-utils';
1415
import useModQueueStore from '../../stores/use-mod-queue-store';
@@ -465,6 +466,7 @@ const PostMobile = ({
465466
const linksCount = useCountLinksInReplies(post);
466467
const { replies, hasMore, loadMore } = useReplies({ comment: post, accountComments: { newerThan: Infinity } });
467468
const registerComments = usePostNumberStore((s) => s.registerComments);
469+
const numberToCid = usePostNumberStore((s) => s.numberToCid);
468470
const prevCidsRef = useRef<string>('');
469471
useEffect(() => {
470472
const all = post ? [post, ...(replies || [])] : replies || [];
@@ -491,17 +493,32 @@ const PostMobile = ({
491493
const quotedByMap = useMemo(() => {
492494
const map = new Map<string, Comment[]>();
493495
for (const reply of filteredReplies) {
494-
const quotedCids = reply.quotedCids;
495-
if (quotedCids?.length) {
496-
for (const quotedCid of quotedCids) {
497-
const arr = map.get(quotedCid);
498-
if (arr) arr.push(reply);
499-
else map.set(quotedCid, [reply]);
496+
const cidSet = new Set<string>();
497+
498+
if (reply.quotedCids?.length) {
499+
for (const quotedCid of reply.quotedCids) {
500+
cidSet.add(quotedCid);
501+
}
502+
}
503+
504+
if (reply.content) {
505+
for (const match of reply.content.matchAll(QUOTE_NUMBER_REGEX)) {
506+
const postNumber = parseInt(match[1], 10);
507+
const quotedCid = numberToCid[postNumber];
508+
if (quotedCid) {
509+
cidSet.add(quotedCid);
510+
}
500511
}
501512
}
513+
514+
for (const quotedCid of cidSet) {
515+
const arr = map.get(quotedCid);
516+
if (arr) arr.push(reply);
517+
else map.set(quotedCid, [reply]);
518+
}
502519
}
503520
return map;
504-
}, [filteredReplies]);
521+
}, [filteredReplies, numberToCid]);
505522

506523
// Virtuoso scroll position management for infinite replies
507524
const virtuosoRef = useRef<VirtuosoHandle | null>(null);

src/lib/utils/url-utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { copyToClipboard } from './clipboard-utils';
22

3+
export const QUOTE_NUMBER_REGEX = /(?<![>/\w])>>(\d+)/g;
4+
35
export const getHostname = (url: string) => {
46
try {
57
return new URL(url).hostname.replace(/^www\./, '');
@@ -183,8 +185,7 @@ export const isValidCrossboardPattern = (pattern: string): boolean => {
183185
// Transform >>{number} post number patterns to markdown links with special anchor
184186
const preprocessPostNumberPatterns = (content: string): string => {
185187
// Match >> followed by digits, avoid overlap with greentext (>>>), cross-board (>>>/), URLs, CID-like patterns
186-
const pattern = /(?<![>/\w])>>(\d+)(?![\d/])/g;
187-
return content.replace(pattern, (_, num) => `[>>${num}](#q-${num})`);
188+
return content.replace(QUOTE_NUMBER_REGEX, (_, num) => `[>>${num}](#q-${num})`);
188189
};
189190

190191
// Preprocess content to convert plain text 5chan cross-board patterns to markdown links

0 commit comments

Comments
 (0)