diff --git a/src/components/markdown/markdown.tsx b/src/components/markdown/markdown.tsx index bb79e537..9c1fd36e 100644 --- a/src/components/markdown/markdown.tsx +++ b/src/components/markdown/markdown.tsx @@ -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 { content: string; title?: string; } const Markdown = ({ content, title }: MarkdownProps) => { + const preprocessedContent = useMemo(() => { + if (!content) return ''; + return content.replace(/([^<]*)<\/spoiler>/g, '§§SPOILER_START§§$1§§SPOILER_END§§').replace(/]*src=['"]([^'"]+)['"][^>]*>/gi, '$1'); + }, [content]); + 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 }]); } const customSchema = useMemo( () => ({ ...defaultSchema, - tagNames: [...(defaultSchema.tagNames || []), 'div'], + tagNames: [...(defaultSchema.tagNames || []), 'div', 'span'], attributes: { ...defaultSchema.attributes, div: ['className'], + span: ['className'], }, }), [], ); remarkPlugins.push([blockquoteToGreentext]); + remarkPlugins.push([spoilerToDiv]); const isInCatalogView = isCatalogView(useLocation().pathname, useParams()); @@ -162,7 +215,7 @@ const Markdown = ({ content, title }: MarkdownProps) => { )} { h4: ({ children }) =>

{children}

, h5: ({ children }) =>

{children}

, h6: ({ children }) =>

{children}

, - img: ({ src }) => {src}, + img: ({ src, alt }) => { + const displayText = src || alt || 'image'; + return {displayText}; + }, video: ({ src }) => {src}, iframe: ({ src }) => {src}, source: ({ src }) => {src}, diff --git a/src/index.css b/src/index.css index b0591088..67d57662 100644 --- a/src/index.css +++ b/src/index.css @@ -26,6 +26,16 @@ hr { color: var(--post-greentext-color); } +.spoilertext { + color: #000 !important; + background: #000 !important; + text-decoration: none; +} + +.spoilertext:hover { + color: #fff !important; +} + .capitalize { text-transform: capitalize; } diff --git a/yarn.lock b/yarn.lock index ad2cf2c9..e111e0bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14584,7 +14584,7 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" -react-virtuoso@^4.12.3: +react-virtuoso@4.12.3: version "4.12.3" resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-4.12.3.tgz#beecf0582b31058c5a6ed3ec58fc43fd780e5844" integrity sha512-6X1p/sU7hecmjDZMAwN+r3go9EVjofKhwkUbVlL8lXhBZecPv9XVCkZ/kBPYOr0Mv0Vl5+Ziwgexg9Kh7+NNXQ==