This commit is contained in:
parent
0f855d19e1
commit
fe7c107c0e
1 changed files with 94 additions and 99 deletions
|
|
@ -7,115 +7,110 @@ import "katex/dist/katex.min.css"
|
|||
import BodyLink from "./BodyLink"
|
||||
import EntryLoadingSkeleton from "./EntryLoadingSkeleton"
|
||||
import { useSearchParams } from "react-router"
|
||||
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table"
|
||||
const ImagePreprocessor = (src) => {
|
||||
const filename = src.src.split("/").pop()
|
||||
const s3RootUrl = "https://eolas.s3.systemsobscure.net/"
|
||||
return <img src={s3RootUrl + filename} />
|
||||
const filename = src.src.split("/").pop()
|
||||
const s3RootUrl = "https://eolas.s3.systemsobscure.net/"
|
||||
return <img src={s3RootUrl + filename} />
|
||||
}
|
||||
|
||||
const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
||||
|
||||
const highlighter = (children, highlight) => {
|
||||
if (!highlight || typeof children !== "string") return children
|
||||
const words = highlight.trim().split(/\s+/)
|
||||
const pattern = words.length > 1 ? escapeRegex(highlight) : escapeRegex(words[0])
|
||||
const regex = new RegExp(`\\b(${pattern})\\b`, "gi")
|
||||
const parts = children.split(regex)
|
||||
if (!highlight || typeof children !== "string") return children
|
||||
const words = highlight.trim().split(/\s+/)
|
||||
const pattern = words.length > 1 ? escapeRegex(highlight) : escapeRegex(words[0])
|
||||
const regex = new RegExp(`\\b(${pattern})\\b`, "gi")
|
||||
const parts = children.split(regex)
|
||||
|
||||
return parts.map((part, i) =>
|
||||
regex.test(part) ? (
|
||||
<mark key={i} className="dark:bg-[#4c1d95] dark:text-white bg-[#ddd6fe]">
|
||||
{part}
|
||||
</mark>
|
||||
) : (
|
||||
part
|
||||
),
|
||||
)
|
||||
return parts.map((part, i) =>
|
||||
regex.test(part) ? (
|
||||
<mark key={i} className="dark:bg-[#4c1d95] dark:text-white bg-[#ddd6fe]">
|
||||
{part}
|
||||
</mark>
|
||||
) : (
|
||||
part
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export default function EntryBody({ body, isLoading }) {
|
||||
const [searchParams] = useSearchParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
const highlight = searchParams.get("highlight")
|
||||
const highlight = searchParams.get("highlight")
|
||||
|
||||
if (isLoading) {
|
||||
return <EntryLoadingSkeleton />
|
||||
}
|
||||
return (
|
||||
<div className="max-w-2xl p-4 lg:p-6">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
components={{
|
||||
h1: () => null,
|
||||
h2: ({ children }) => (
|
||||
<h2 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<h3 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ children }) => (
|
||||
<h4 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h4>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<p className="leading-[1.5] mb-4 not-first:mt-4">
|
||||
{highlighter(children, highlight)}
|
||||
</p>
|
||||
),
|
||||
ul: ({ children }) => <ul className="list-disc ml-10 mb-4 space-y-1">{children}</ul>,
|
||||
ol: ({ children }) => (
|
||||
<ol className="list-decimal ml-10 mb-4 space-y-1">{children}</ol>
|
||||
),
|
||||
li: ({ children }) => (
|
||||
<li className="list-disc ml-10 mb-4 space-y-1">
|
||||
{highlighter(children, highlight)}
|
||||
</li>
|
||||
),
|
||||
table: ({ children }) => <table className="w-full mb-4 text-sm">{children}</table>,
|
||||
tr: ({ children }) => (
|
||||
<tr className="even:bg-muted m-0 border-t p-0">
|
||||
{highlighter(children, highlight)}
|
||||
</tr>
|
||||
),
|
||||
th: ({ children }) => (
|
||||
<th className="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
|
||||
{highlighter(children, highlight)}
|
||||
</th>
|
||||
),
|
||||
td: ({ children }) => (
|
||||
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
|
||||
{highlighter(children, highlight)}
|
||||
</td>
|
||||
),
|
||||
blockquote: ({ children }) => (
|
||||
<blockquote className="mt-4 border-l-2 pl-6 text-muted-foreground">
|
||||
{highlighter(children, highlight)}
|
||||
</blockquote>
|
||||
),
|
||||
pre: ({ children }) => {
|
||||
const child = children.props
|
||||
return <CodeBlock className={child.className}>{child.children}</CodeBlock>
|
||||
},
|
||||
code: ({ children }) => (
|
||||
<code className="rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
img: ({ src }) => <ImagePreprocessor src={src} />,
|
||||
a: ({ href, children }) => {
|
||||
return <BodyLink link={href} children={children} />
|
||||
},
|
||||
}}
|
||||
>
|
||||
{body}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)
|
||||
if (isLoading) {
|
||||
return <EntryLoadingSkeleton />
|
||||
}
|
||||
return (
|
||||
<div className="max-w-2xl p-4 lg:p-6">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
components={{
|
||||
h1: () => null,
|
||||
h2: ({ children }) => (
|
||||
<h2 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<h3 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ children }) => (
|
||||
<h4 className="scroll-m-20 font-semibold mt-8 mb-4 first:mt-0">
|
||||
{highlighter(children, highlight)}
|
||||
</h4>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<p className="leading-[1.5] mb-4 not-first:mt-4">
|
||||
{highlighter(children, highlight)}
|
||||
</p>
|
||||
),
|
||||
ul: ({ children }) => <ul className="list-disc ml-10 mb-4 space-y-1">{children}</ul>,
|
||||
ol: ({ children }) => (
|
||||
<ol className="list-decimal ml-10 mb-4 space-y-1">{children}</ol>
|
||||
),
|
||||
li: ({ children }) => (
|
||||
<li className="list-disc ml-10 mb-4 space-y-1">
|
||||
{highlighter(children, highlight)}
|
||||
</li>
|
||||
),
|
||||
table: ({ children }) => (
|
||||
<Table className="w-full mb-4 text-sm overflow-x-auto">{children}</Table>
|
||||
),
|
||||
thead: ({ children }) => <TableHeader>{children}</TableHeader>,
|
||||
|
||||
tr: ({ children }) => <TableRow>{highlighter(children, highlight)}</TableRow>,
|
||||
|
||||
th: ({ children }) => <TableHead>{highlighter(children, highlight)}</TableHead>,
|
||||
td: ({ children }) => <TableCell>{highlighter(children, highlight)}</TableCell>,
|
||||
tbody: ({ children }) => <TableBody>{children}</TableBody>,
|
||||
|
||||
blockquote: ({ children }) => (
|
||||
<blockquote className="mt-4 border-l-2 pl-6 text-muted-foreground">
|
||||
{highlighter(children, highlight)}
|
||||
</blockquote>
|
||||
),
|
||||
pre: ({ children }) => {
|
||||
const child = children.props
|
||||
return <CodeBlock className={child.className}>{child.children}</CodeBlock>
|
||||
},
|
||||
code: ({ children }) => (
|
||||
<code className="rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
img: ({ src }) => <ImagePreprocessor src={src} />,
|
||||
a: ({ href, children }) => {
|
||||
return <BodyLink link={href} children={children} />
|
||||
},
|
||||
}}
|
||||
>
|
||||
{body}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue