feat: add detail view functionality for documents and FAQs with localization support

This commit is contained in:
mlogclub
2026-06-02 19:55:26 +08:00
parent 9c7bf29b41
commit ffd2227e5e
6 changed files with 299 additions and 2 deletions
+10 -2
View File
@@ -26,17 +26,24 @@ const allowedTags = new Set([
"h6",
"hr",
"i",
"img",
"li",
"ol",
"p",
"pre",
"span",
"strong",
"table",
"tbody",
"td",
"th",
"thead",
"tr",
"u",
"ul",
])
const allowedAttrs = new Set(["class", "href", "rel", "target", "title"])
const allowedAttrs = new Set(["alt", "class", "height", "href", "rel", "src", "target", "title", "width"])
function escapeHTML(value: string) {
return value
@@ -101,7 +108,7 @@ function sanitizeRichHTML(value: string) {
element.removeAttribute(attr.name)
continue
}
if (name === "href" && !isSafeURL(attrValue)) {
if ((name === "href" || name === "src") && !isSafeURL(attrValue)) {
element.removeAttribute(attr.name)
}
}
@@ -140,6 +147,7 @@ export function SafeRichHTML({ html, fallback = "-", className }: SafeRichHTMLPr
<div
className={cn(
"break-words text-sm leading-6 [&_a]:text-primary [&_a]:underline [&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-muted-foreground/40 [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_h1]:mb-2 [&_h1]:text-lg [&_h1]:font-semibold [&_h2]:mb-2 [&_h2]:text-base [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:font-semibold [&_li]:my-1 [&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_p]:m-0 [&_p+*]:mt-2 [&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_strong]:font-semibold [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5",
"break-words text-sm leading-6 [&_a]:text-primary [&_a]:underline [&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:border-muted-foreground/40 [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_h1]:mb-2 [&_h1]:text-lg [&_h1]:font-semibold [&_h2]:mb-2 [&_h2]:text-base [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:font-semibold [&_img]:my-3 [&_img]:max-w-full [&_img]:rounded-md [&_li]:my-1 [&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_p]:m-0 [&_p+*]:mt-2 [&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_strong]:font-semibold [&_table]:my-3 [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:px-2 [&_td]:py-1 [&_th]:border [&_th]:bg-muted [&_th]:px-2 [&_th]:py-1 [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5",
className,
)}
dangerouslySetInnerHTML={{ __html: safeHTML }}