mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(catalog): preserve literal preview markers
This commit is contained in:
@@ -480,6 +480,22 @@ describe('CatalogRow', () => {
|
|||||||
expect(container.textContent).toContain('Text title: Plain thread body');
|
expect(container.textContent).toContain('Text title: Plain thread body');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('preserves literal catalog teaser markers without applying body markdown styles', async () => {
|
||||||
|
const post: TestComment = {
|
||||||
|
cid: 'literal-markers',
|
||||||
|
content: '>we got 5chan before Half Life 3\n*poisons u*',
|
||||||
|
replyCount: 2,
|
||||||
|
communityAddress: 'music-posting.eth',
|
||||||
|
};
|
||||||
|
|
||||||
|
await renderWithRouter(createElement(CatalogRow, { row: [post] }), '/mu/catalog');
|
||||||
|
|
||||||
|
expect(container.textContent).toContain('>we got 5chan before Half Life 3');
|
||||||
|
expect(container.textContent).toContain('*poisons u*');
|
||||||
|
expect(container.querySelector('.greentext')).toBeNull();
|
||||||
|
expect(container.querySelector('.spoilertext')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('applies the estimated row height to the virtualization wrapper', async () => {
|
it('applies the estimated row height to the virtualization wrapper', async () => {
|
||||||
const post: TestComment = {
|
const post: TestComment = {
|
||||||
cid: 'estimated-post',
|
cid: 'estimated-post',
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
|||||||
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
|
||||||
import useHide from '../../hooks/use-hide';
|
import useHide from '../../hooks/use-hide';
|
||||||
import { isCommentArchived } from '../../lib/utils/comment-moderation-utils';
|
import { isCommentArchived } from '../../lib/utils/comment-moderation-utils';
|
||||||
import { removeMarkdown } from '../../lib/utils/post-utils';
|
import { CATALOG_PREVIEW_MARKDOWN_OPTIONS, removeMarkdown } from '../../lib/utils/post-utils';
|
||||||
import PostMenuDesktop from '../post-desktop/post-menu-desktop';
|
import PostMenuDesktop from '../post-desktop/post-menu-desktop';
|
||||||
import styles from './catalog-row.module.css';
|
import styles from './catalog-row.module.css';
|
||||||
import capitalize from 'lodash/capitalize';
|
import capitalize from 'lodash/capitalize';
|
||||||
@@ -215,7 +215,7 @@ const CatalogPost = memo(
|
|||||||
{content ? ': ' : ''}
|
{content ? ': ' : ''}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{content && removeMarkdown(content)}
|
{content && removeMarkdown(content, CATALOG_PREVIEW_MARKDOWN_OPTIONS)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ describe('misc utils', () => {
|
|||||||
expect(removeMarkdown('[spoiler]secret[/spoiler]\n>greentext\n**bold** [label](https://example.com) `code` ```block``` ')).toBe(
|
expect(removeMarkdown('[spoiler]secret[/spoiler]\n>greentext\n**bold** [label](https://example.com) `code` ```block``` ')).toBe(
|
||||||
'secret\ngreentext\nbold label code block',
|
'secret\ngreentext\nbold label code block',
|
||||||
);
|
);
|
||||||
|
expect(removeMarkdown('>greentext\n*poisons u* _and underlines_', { preserveEmphasisMarkers: true, preserveGreentextMarkers: true })).toBe(
|
||||||
|
'>greentext\n*poisons u* _and underlines_',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preloads theme asset URLs through Image instances', () => {
|
it('preloads theme asset URLs through Image instances', () => {
|
||||||
|
|||||||
@@ -21,13 +21,31 @@ export function getTextColorForBackground(rgb: string): string {
|
|||||||
return brightness > 125 ? 'black' : 'white';
|
return brightness > 125 ? 'black' : 'white';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeMarkdown(md: string): string {
|
export interface RemoveMarkdownOptions {
|
||||||
return md
|
preserveEmphasisMarkers?: boolean;
|
||||||
|
preserveGreentextMarkers?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CATALOG_PREVIEW_MARKDOWN_OPTIONS: RemoveMarkdownOptions = {
|
||||||
|
preserveEmphasisMarkers: true,
|
||||||
|
preserveGreentextMarkers: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function removeMarkdown(md: string, options: RemoveMarkdownOptions = {}): string {
|
||||||
|
let withoutMarkdown = md
|
||||||
.replace(/\[spoiler\](.*?)\[\/spoiler\]/gis, '$1') // spoiler tags - keep inner text
|
.replace(/\[spoiler\](.*?)\[\/spoiler\]/gis, '$1') // spoiler tags - keep inner text
|
||||||
.replace(/\[([^\]]*?)\]\([^)]*\)/g, '$1') // [text](url) -> text
|
.replace(/\[([^\]]*?)\]\([^)]*\)/g, '$1') // [text](url) -> text
|
||||||
.replace(/ /g, ' ') // -> space
|
.replace(/ /g, ' '); // -> space
|
||||||
.replace(/^>\s*/gm, '') // greentext at line start
|
|
||||||
.replace(/[*_]/g, '') // bold/italic markers
|
if (!options.preserveGreentextMarkers) {
|
||||||
|
withoutMarkdown = withoutMarkdown.replace(/^>\s*/gm, ''); // greentext at line start
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.preserveEmphasisMarkers) {
|
||||||
|
withoutMarkdown = withoutMarkdown.replace(/[*_]/g, ''); // bold/italic markers
|
||||||
|
}
|
||||||
|
|
||||||
|
return withoutMarkdown
|
||||||
.replace(/```[\s\S]*?```/g, (m) => m.slice(3, -3)) // code blocks - keep content
|
.replace(/```[\s\S]*?```/g, (m) => m.slice(3, -3)) // code blocks - keep content
|
||||||
.replace(/`([^`]*)`/g, '$1') // inline code - keep content
|
.replace(/`([^`]*)`/g, '$1') // inline code - keep content
|
||||||
.trim();
|
.trim();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Comment } from '@bitsocial/bitsocial-react-hooks';
|
|||||||
import { layout, layoutNextLine, prepare, prepareWithSegments } from '@chenglou/pretext';
|
import { layout, layoutNextLine, prepare, prepareWithSegments } from '@chenglou/pretext';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from './media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from './media-utils';
|
||||||
import { EXPANDED_MEDIA_DATA_ATTRIBUTE } from './measurement-attributes';
|
import { EXPANDED_MEDIA_DATA_ATTRIBUTE } from './measurement-attributes';
|
||||||
import { removeMarkdown } from './post-utils';
|
import { CATALOG_PREVIEW_MARKDOWN_OPTIONS, removeMarkdown, type RemoveMarkdownOptions } from './post-utils';
|
||||||
import { getRenderableMobileBacklinks } from './reply-backlink-utils';
|
import { getRenderableMobileBacklinks } from './reply-backlink-utils';
|
||||||
|
|
||||||
export type ReplyVirtualizationMode = 'off' | 'estimates' | 'item-size';
|
export type ReplyVirtualizationMode = 'off' | 'estimates' | 'item-size';
|
||||||
@@ -393,8 +393,8 @@ const getCatalogPostMediaHeight = (post: Comment | undefined, imageSize: Catalog
|
|||||||
return mediaBox ? mediaBox.height + CATALOG_CARD_MEDIA_GAP_HEIGHT : 0;
|
return mediaBox ? mediaBox.height + CATALOG_CARD_MEDIA_GAP_HEIGHT : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeRenderedCommentText = (rawContent: string): string =>
|
const normalizeRenderedCommentText = (rawContent: string, markdownOptions?: RemoveMarkdownOptions): string =>
|
||||||
removeMarkdown(rawContent)
|
removeMarkdown(rawContent, markdownOptions)
|
||||||
.replace(/\n \n/g, '\n\n')
|
.replace(/\n \n/g, '\n\n')
|
||||||
.replace(/\n{3,}/g, '\n\n')
|
.replace(/\n{3,}/g, '\n\n')
|
||||||
.split('\n')
|
.split('\n')
|
||||||
@@ -402,7 +402,7 @@ const normalizeRenderedCommentText = (rawContent: string): string =>
|
|||||||
.join('\n')
|
.join('\n')
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
const getVisibleCommentBodyText = (comment: Comment | undefined, maxContentChars: number): string => {
|
const getVisibleCommentBodyText = (comment: Comment | undefined, maxContentChars: number, markdownOptions?: RemoveMarkdownOptions): string => {
|
||||||
if (!comment) {
|
if (!comment) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -412,7 +412,7 @@ const getVisibleCommentBodyText = (comment: Comment | undefined, maxContentChars
|
|||||||
const removed = comment.removed;
|
const removed = comment.removed;
|
||||||
const reason = comment.reason?.trim();
|
const reason = comment.reason?.trim();
|
||||||
const rawContent = comment.content || '';
|
const rawContent = comment.content || '';
|
||||||
const content = normalizeRenderedCommentText(rawContent.slice(0, maxContentChars));
|
const content = normalizeRenderedCommentText(rawContent.slice(0, maxContentChars), markdownOptions);
|
||||||
|
|
||||||
if (purged) {
|
if (purged) {
|
||||||
return 'This post was purged';
|
return 'This post was purged';
|
||||||
@@ -433,13 +433,13 @@ const getVisibleCommentBodyText = (comment: Comment | undefined, maxContentChars
|
|||||||
return content;
|
return content;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVisibleCommentText = (comment: Comment | undefined, maxContentChars: number): string => {
|
const getVisibleCommentText = (comment: Comment | undefined, maxContentChars: number, markdownOptions?: RemoveMarkdownOptions): string => {
|
||||||
if (!comment) {
|
if (!comment) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = comment.title?.trim();
|
const title = comment.title?.trim();
|
||||||
const content = getVisibleCommentBodyText(comment, maxContentChars);
|
const content = getVisibleCommentBodyText(comment, maxContentChars, markdownOptions);
|
||||||
|
|
||||||
if (title && content) {
|
if (title && content) {
|
||||||
return `${title}: ${content}`;
|
return `${title}: ${content}`;
|
||||||
@@ -455,7 +455,7 @@ const getVisibleCatalogText = (post: Comment | undefined, showOPComment: boolean
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return getVisibleCommentText(post, 1600);
|
return getVisibleCommentText(post, 1600, CATALOG_PREVIEW_MARKDOWN_OPTIONS);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMobileBacklinkCount = (reply: Comment, backlinkMaps: ReplyBacklinkMaps): number => {
|
const getMobileBacklinkCount = (reply: Comment, backlinkMaps: ReplyBacklinkMaps): number => {
|
||||||
|
|||||||
Reference in New Issue
Block a user