search: slightly better results appearance
This commit is contained in:
37
web/src/components/markdown/markdown-content.tsx
Normal file
37
web/src/components/markdown/markdown-content.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useMemo } from "preact/hooks";
|
||||
import DOMPurify from "dompurify";
|
||||
import { marked } from "marked";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type MarkdownMode = "default" | "citationTokens";
|
||||
|
||||
type Props = {
|
||||
markdown: string;
|
||||
className?: string;
|
||||
mode?: MarkdownMode;
|
||||
resolveCitationIndex?: (href: string) => number | undefined;
|
||||
};
|
||||
|
||||
function replaceMarkdownLinksWithCitationTokens(markdown: string, resolveCitationIndex?: (href: string) => number | undefined) {
|
||||
if (!resolveCitationIndex) return markdown;
|
||||
return markdown.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (_full, _label, href) => {
|
||||
const index = resolveCitationIndex(href);
|
||||
if (!index) return "";
|
||||
return `<span class="md-cite-token">[${index}]</span>`;
|
||||
});
|
||||
}
|
||||
|
||||
function renderMarkdown(markdown: string) {
|
||||
const rawHtml = marked.parse(markdown, { gfm: true, breaks: true }) as string;
|
||||
return DOMPurify.sanitize(rawHtml, { ADD_ATTR: ["class", "target", "rel"] });
|
||||
}
|
||||
|
||||
export function MarkdownContent({ markdown, className, mode = "default", resolveCitationIndex }: Props) {
|
||||
const html = useMemo(() => {
|
||||
const prepared =
|
||||
mode === "citationTokens" ? replaceMarkdownLinksWithCitationTokens(markdown, resolveCitationIndex) : markdown;
|
||||
return renderMarkdown(prepared);
|
||||
}, [markdown, mode, resolveCitationIndex]);
|
||||
|
||||
return <div className={cn("md-content", className)} dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
}
|
||||
Reference in New Issue
Block a user