mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(markdown): add spoiler text
This commit is contained in:
@@ -125,31 +125,84 @@ const blockquoteToGreentext = () => (tree: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const spoilerToDiv = () => (tree: any) => {
|
||||||
|
tree.children.forEach((node: any) => {
|
||||||
|
if (node.type === 'paragraph') {
|
||||||
|
const text = node.children.map((child: any) => child.value).join('');
|
||||||
|
if (text.includes('§§SPOILER_START§§')) {
|
||||||
|
node.type = 'span';
|
||||||
|
node.data = {
|
||||||
|
hName: 'span',
|
||||||
|
};
|
||||||
|
node.children.forEach((child: any) => {
|
||||||
|
if (child.type === 'text') {
|
||||||
|
const parts = child.value.split(/(§§SPOILER_START§§.*?§§SPOILER_END§§)/);
|
||||||
|
if (parts.length > 1) {
|
||||||
|
const newChildren = parts.map((part: string) => {
|
||||||
|
const spoilerMatch = part.match(/§§SPOILER_START§§(.*?)§§SPOILER_END§§/);
|
||||||
|
if (spoilerMatch) {
|
||||||
|
return {
|
||||||
|
type: 'span',
|
||||||
|
data: {
|
||||||
|
hName: 'span',
|
||||||
|
hProperties: {
|
||||||
|
className: 'spoilertext',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
value: spoilerMatch[1],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'text',
|
||||||
|
value: part,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
node.children = newChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
interface MarkdownProps {
|
interface MarkdownProps {
|
||||||
content: string;
|
content: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Markdown = ({ content, title }: MarkdownProps) => {
|
const Markdown = ({ content, title }: MarkdownProps) => {
|
||||||
|
const preprocessedContent = useMemo(() => {
|
||||||
|
if (!content) return '';
|
||||||
|
return content.replace(/<spoiler>([^<]*)<\/spoiler>/g, '§§SPOILER_START§§$1§§SPOILER_END§§').replace(/<img[^>]*src=['"]([^'"]+)['"][^>]*>/gi, '$1');
|
||||||
|
}, [content]);
|
||||||
|
|
||||||
const remarkPlugins: any[] = [[supersub]];
|
const remarkPlugins: any[] = [[supersub]];
|
||||||
|
|
||||||
if (content && content.length <= MAX_LENGTH_FOR_GFM) {
|
if (preprocessedContent && preprocessedContent.length <= MAX_LENGTH_FOR_GFM) {
|
||||||
remarkPlugins.push([remarkGfm, { singleTilde: false }]);
|
remarkPlugins.push([remarkGfm, { singleTilde: false }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const customSchema = useMemo(
|
const customSchema = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
...defaultSchema,
|
...defaultSchema,
|
||||||
tagNames: [...(defaultSchema.tagNames || []), 'div'],
|
tagNames: [...(defaultSchema.tagNames || []), 'div', 'span'],
|
||||||
attributes: {
|
attributes: {
|
||||||
...defaultSchema.attributes,
|
...defaultSchema.attributes,
|
||||||
div: ['className'],
|
div: ['className'],
|
||||||
|
span: ['className'],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
remarkPlugins.push([blockquoteToGreentext]);
|
remarkPlugins.push([blockquoteToGreentext]);
|
||||||
|
remarkPlugins.push([spoilerToDiv]);
|
||||||
|
|
||||||
const isInCatalogView = isCatalogView(useLocation().pathname, useParams());
|
const isInCatalogView = isCatalogView(useLocation().pathname, useParams());
|
||||||
|
|
||||||
@@ -162,7 +215,7 @@ const Markdown = ({ content, title }: MarkdownProps) => {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
children={content}
|
children={preprocessedContent}
|
||||||
remarkPlugins={remarkPlugins}
|
remarkPlugins={remarkPlugins}
|
||||||
rehypePlugins={[[rehypeSanitize, customSchema]]}
|
rehypePlugins={[[rehypeSanitize, customSchema]]}
|
||||||
components={{
|
components={{
|
||||||
@@ -173,7 +226,10 @@ const Markdown = ({ content, title }: MarkdownProps) => {
|
|||||||
h4: ({ children }) => <p className={styles.header}>{children}</p>,
|
h4: ({ children }) => <p className={styles.header}>{children}</p>,
|
||||||
h5: ({ children }) => <p className={styles.header}>{children}</p>,
|
h5: ({ children }) => <p className={styles.header}>{children}</p>,
|
||||||
h6: ({ children }) => <p className={styles.header}>{children}</p>,
|
h6: ({ children }) => <p className={styles.header}>{children}</p>,
|
||||||
img: ({ src }) => <span>{src}</span>,
|
img: ({ src, alt }) => {
|
||||||
|
const displayText = src || alt || 'image';
|
||||||
|
return <span>{displayText}</span>;
|
||||||
|
},
|
||||||
video: ({ src }) => <span>{src}</span>,
|
video: ({ src }) => <span>{src}</span>,
|
||||||
iframe: ({ src }) => <span>{src}</span>,
|
iframe: ({ src }) => <span>{src}</span>,
|
||||||
source: ({ src }) => <span>{src}</span>,
|
source: ({ src }) => <span>{src}</span>,
|
||||||
|
|||||||
@@ -26,6 +26,16 @@ hr {
|
|||||||
color: var(--post-greentext-color);
|
color: var(--post-greentext-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spoilertext {
|
||||||
|
color: #000 !important;
|
||||||
|
background: #000 !important;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spoilertext:hover {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
.capitalize {
|
.capitalize {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14584,7 +14584,7 @@ react-scripts@5.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "^2.3.2"
|
fsevents "^2.3.2"
|
||||||
|
|
||||||
react-virtuoso@^4.12.3:
|
react-virtuoso@4.12.3:
|
||||||
version "4.12.3"
|
version "4.12.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.12.3.tgz#beecf0582b31058c5a6ed3ec58fc43fd780e5844"
|
resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.12.3.tgz#beecf0582b31058c5a6ed3ec58fc43fd780e5844"
|
||||||
integrity sha512-6X1p/sU7hecmjDZMAwN+r3go9EVjofKhwkUbVlL8lXhBZecPv9XVCkZ/kBPYOr0Mv0Vl5+Ziwgexg9Kh7+NNXQ==
|
integrity sha512-6X1p/sU7hecmjDZMAwN+r3go9EVjofKhwkUbVlL8lXhBZecPv9XVCkZ/kBPYOr0Mv0Vl5+Ziwgexg9Kh7+NNXQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user