mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 08:30:58 -05:00
fix: limit maximum quote depth to 3
This commit is contained in:
parent
34bb2bbc13
commit
4a85dd69cf
3 changed files with 34 additions and 9 deletions
|
@ -3,11 +3,13 @@ import { Suspense, lazy } from "preact/compat";
|
||||||
const Renderer = lazy(() => import("./RemarkRenderer"));
|
const Renderer = lazy(() => import("./RemarkRenderer"));
|
||||||
|
|
||||||
export interface MarkdownProps {
|
export interface MarkdownProps {
|
||||||
content?: string | null;
|
content: string;
|
||||||
disallowBigEmoji?: boolean;
|
disallowBigEmoji?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Markdown(props: MarkdownProps) {
|
export default function Markdown(props: MarkdownProps) {
|
||||||
|
if (!props.content) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// @ts-expect-error Typings mis-match.
|
// @ts-expect-error Typings mis-match.
|
||||||
<Suspense fallback={props.content}>
|
<Suspense fallback={props.content}>
|
||||||
|
|
|
@ -15,14 +15,14 @@ import { memo } from "preact/compat";
|
||||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||||
|
|
||||||
import { MarkdownProps } from "./Markdown";
|
import { MarkdownProps } from "./Markdown";
|
||||||
|
import { handlers } from "./hast";
|
||||||
import { RenderCodeblock } from "./plugins/Codeblock";
|
import { RenderCodeblock } from "./plugins/Codeblock";
|
||||||
import { RenderAnchor } from "./plugins/anchors";
|
import { RenderAnchor } from "./plugins/anchors";
|
||||||
import { remarkChannels, RenderChannel } from "./plugins/channels";
|
import { remarkChannels, RenderChannel } from "./plugins/channels";
|
||||||
import { isOnlyEmoji, remarkEmoji, RenderEmoji } from "./plugins/emoji";
|
import { isOnlyEmoji, remarkEmoji, RenderEmoji } from "./plugins/emoji";
|
||||||
import { remarkMention, RenderMention } from "./plugins/mentions";
|
import { remarkMention, RenderMention } from "./plugins/mentions";
|
||||||
import { passThroughComponents } from "./plugins/remarkRegexComponent";
|
|
||||||
import { remarkSpoiler, RenderSpoiler } from "./plugins/spoiler";
|
import { remarkSpoiler, RenderSpoiler } from "./plugins/spoiler";
|
||||||
import { remarkTimestamps, timestampHandler } from "./plugins/timestamps";
|
import { remarkTimestamps } from "./plugins/timestamps";
|
||||||
import "./prism";
|
import "./prism";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,10 +139,7 @@ const render = unified()
|
||||||
.use(remarkEmoji)
|
.use(remarkEmoji)
|
||||||
.use(remarkMention)
|
.use(remarkMention)
|
||||||
.use(remarkRehype, {
|
.use(remarkRehype, {
|
||||||
handlers: {
|
handlers,
|
||||||
...passThroughComponents("emoji", "spoiler", "mention", "channel"),
|
|
||||||
timestamp: timestampHandler,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.use(rehypeKatex, {
|
.use(rehypeKatex, {
|
||||||
maxSize: 10,
|
maxSize: 10,
|
||||||
|
@ -173,15 +170,34 @@ const Container = styled.div<{ largeEmoji: boolean }>`
|
||||||
--emoji-size: ${(props) => (props.largeEmoji ? "3em" : "1.25em")};
|
--emoji-size: ${(props) => (props.largeEmoji ? "3em" : "1.25em")};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex for matching execessive blockquotes
|
||||||
|
*/
|
||||||
|
const RE_QUOTE = /(^[>\s][>\s])[>\s]+([^]+)$/gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitise Markdown input before rendering
|
||||||
|
* @param content Input string
|
||||||
|
* @returns Sanitised string
|
||||||
|
*/
|
||||||
|
function sanitise(content: string) {
|
||||||
|
// Strip excessive blockquote indentation
|
||||||
|
return content.replace(RE_QUOTE, (_, m0, m1) => m0 + m1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remark renderer component
|
* Remark renderer component
|
||||||
*/
|
*/
|
||||||
export default memo(({ content, disallowBigEmoji }: MarkdownProps) => {
|
export default memo(({ content, disallowBigEmoji }: MarkdownProps) => {
|
||||||
|
const sanitisedContent = useMemo(() => sanitise(content), [content]);
|
||||||
|
|
||||||
const [Content, setContent] = useState<React.ReactElement>(null!);
|
const [Content, setContent] = useState<React.ReactElement>(null!);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
render.process(content!).then((file) => setContent(file.result));
|
render
|
||||||
}, [content]);
|
.process(sanitisedContent)
|
||||||
|
.then((file) => setContent(file.result));
|
||||||
|
}, [sanitisedContent]);
|
||||||
|
|
||||||
const largeEmoji = useMemo(
|
const largeEmoji = useMemo(
|
||||||
() => !disallowBigEmoji && isOnlyEmoji(content!),
|
() => !disallowBigEmoji && isOnlyEmoji(content!),
|
||||||
|
|
7
src/components/markdown/hast.ts
Normal file
7
src/components/markdown/hast.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { passThroughComponents } from "./plugins/remarkRegexComponent";
|
||||||
|
import { timestampHandler } from "./plugins/timestamps";
|
||||||
|
|
||||||
|
export const handlers = {
|
||||||
|
...passThroughComponents("emoji", "spoiler", "mention", "channel"),
|
||||||
|
timestamp: timestampHandler,
|
||||||
|
};
|
Loading…
Reference in a new issue