fix: table overflow
All checks were successful
Deploy eolas-app / deploy (push) Successful in 1m5s

This commit is contained in:
Thomas Bishop 2025-12-17 19:05:22 +00:00
parent 0f855d19e1
commit fe7c107c0e

View file

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