refactor(markdown): replace react-markdown with custom imageboard-style text parser

This commit is contained in:
plebeius
2026-03-04 15:20:06 +08:00
parent 1aabe7a6b2
commit e6afb041ae
8 changed files with 191 additions and 1039 deletions
-51
View File
@@ -181,54 +181,3 @@ export const isValidCrossboardPattern = (pattern: string): boolean => {
// Check if it's just a full address pattern: >>>/board.eth
return isValidDomain(pathPart) || isValidIPNSKey(pathPart);
};
// Transform >>{number} post number patterns to markdown links with special anchor
const preprocessPostNumberPatterns = (content: string): string => {
// Match >> followed by digits, avoid overlap with greentext (>>>), cross-board (>>>/), URLs, CID-like patterns
return content.replace(QUOTE_NUMBER_REGEX, (_, num) => `[>>${num}](#q-${num})`);
};
// Preprocess content to convert plain text 5chan cross-board patterns to markdown links
export const preprocess5chanPatterns = (content: string): string => {
const withPostNumbers = preprocessPostNumberPatterns(content);
// Pattern to match ">>>/something" or ">>>/something/cid"
// Negative lookbehind prevents matching patterns that are already part of URLs
// Matches: >>>/directory/, >>>/directory/cid (46 chars), >>>/address, >>>/address/cid (46 chars)
const pattern = /(?<!https?:\/\/[^\s]*)>>>\/([a-zA-Z0-9]{1,10}\/(?:[a-zA-Z0-9]{46})?|[a-zA-Z0-9\-.]+(?:\/[a-zA-Z0-9]{46})?)[.,:;!?]*/g;
return withPostNumbers.replace(pattern, (match, capturedPath) => {
// Remove any trailing punctuation from the captured path
const cleanPath = capturedPath.replace(/[.,:;!?]+$/, '');
const fullPattern = `>>>/${cleanPath}`;
if (isValidCrossboardPattern(fullPattern)) {
// Generate internal route based on pattern type
let internalRoute: string;
// Directory with trailing slash: >>>/biz/ → /biz
if (/^[a-zA-Z0-9]{1,10}\/$/.test(cleanPath)) {
internalRoute = `/${cleanPath.slice(0, -1)}`;
}
// Directory + CID: >>>/biz/cid → /biz/thread/cid (CID is 46 chars)
else if (/^[a-zA-Z0-9]{1,10}\/[a-zA-Z0-9]{46}$/.test(cleanPath)) {
const [code, cid] = cleanPath.split('/');
internalRoute = `/${code}/thread/${cid}`;
}
// Full address + CID: >>>/board.eth/cid → /board.eth/thread/cid (CID is 46 chars)
else if (/^[^/]+\/[a-zA-Z0-9]{46}$/.test(cleanPath)) {
const [address, cid] = cleanPath.split('/');
internalRoute = `/${address}/thread/${cid}`;
}
// Just a full address: >>>/board.eth → /board.eth
else {
internalRoute = `/${cleanPath}`;
}
// Preserve trailing punctuation outside the link
const trailingPunctuation = match.slice(fullPattern.length);
return `[${fullPattern}](${internalRoute})${trailingPunctuation}`;
}
return match;
});
};