diff --git a/web/src/components/common/DocumentRenderer/index.jsx b/web/src/components/common/DocumentRenderer/index.jsx
index 68e868c5..8c15c073 100644
--- a/web/src/components/common/DocumentRenderer/index.jsx
+++ b/web/src/components/common/DocumentRenderer/index.jsx
@@ -17,7 +17,7 @@ along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useMemo, useState } from 'react';
import { API, showError } from '../../../helpers';
import { Empty, Card, Spin, Typography } from '@douyinfe/semi-ui';
const { Title } = Typography;
@@ -28,7 +28,7 @@ import {
import { useTranslation } from 'react-i18next';
import MarkdownRenderer from '../markdown/MarkdownRenderer';
-// 检查是否为 URL
+// Check whether content is a URL.
const isUrl = (content) => {
try {
new URL(content.trim());
@@ -38,27 +38,23 @@ const isUrl = (content) => {
}
};
-// 检查是否为 HTML 内容
+// Check whether content contains HTML.
const isHtmlContent = (content) => {
if (!content || typeof content !== 'string') return false;
- // 检查是否包含HTML标签
const htmlTagRegex = /<\/?[a-z][\s\S]*>/i;
return htmlTagRegex.test(content);
};
-// 安全地渲染HTML内容
+// Parse HTML content and extract inline styles.
const sanitizeHtml = (html) => {
- // 创建一个临时元素来解析HTML
const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
- // 提取样式
const styles = Array.from(tempDiv.querySelectorAll('style'))
.map((style) => style.innerHTML)
.join('\n');
- // 提取body内容,如果没有body标签则使用全部内容
const bodyContent = tempDiv.querySelector('body');
const content = bodyContent ? bodyContent.innerHTML : html;
@@ -76,15 +72,11 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
const { t } = useTranslation();
const [content, setContent] = useState('');
const [loading, setLoading] = useState(true);
- const [htmlStyles, setHtmlStyles] = useState('');
- const [processedHtmlContent, setProcessedHtmlContent] = useState('');
const loadContent = async () => {
- // 先从缓存中获取
const cachedContent = localStorage.getItem(cacheKey) || '';
if (cachedContent) {
setContent(cachedContent);
- processContent(cachedContent);
setLoading(false);
}
@@ -93,7 +85,6 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
const { success, message, data } = res.data;
if (success && data) {
setContent(data);
- processContent(data);
localStorage.setItem(cacheKey, data);
} else {
if (!cachedContent) {
@@ -111,16 +102,12 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
}
};
- const processContent = (rawContent) => {
- if (isHtmlContent(rawContent)) {
- const { content: htmlContent, styles } = sanitizeHtml(rawContent);
- setProcessedHtmlContent(htmlContent);
- setHtmlStyles(styles);
- } else {
- setProcessedHtmlContent('');
- setHtmlStyles('');
+ const htmlPayload = useMemo(() => {
+ if (!isHtmlContent(content)) {
+ return { content: '', styles: '' };
}
- };
+ return sanitizeHtml(content);
+ }, [content]);
useEffect(() => {
loadContent();
@@ -129,8 +116,9 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
// 处理HTML样式注入
useEffect(() => {
const styleId = `document-renderer-styles-${cacheKey}`;
+ const { styles } = htmlPayload;
- if (htmlStyles) {
+ if (styles) {
let styleEl = document.getElementById(styleId);
if (!styleEl) {
styleEl = document.createElement('style');
@@ -138,7 +126,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
styleEl.type = 'text/css';
document.head.appendChild(styleEl);
}
- styleEl.innerHTML = htmlStyles;
+ styleEl.innerHTML = styles;
} else {
const el = document.getElementById(styleId);
if (el) el.remove();
@@ -148,7 +136,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
const el = document.getElementById(styleId);
if (el) el.remove();
};
- }, [htmlStyles, cacheKey]);
+ }, [cacheKey, htmlPayload]);
// 显示加载状态
if (loading) {
@@ -207,15 +195,6 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
// 如果是 HTML 内容,直接渲染
if (isHtmlContent(content)) {
- const { content: htmlContent, styles } = sanitizeHtml(content);
-
- // 设置样式(如果有的话)
- useEffect(() => {
- if (styles && styles !== htmlStyles) {
- setHtmlStyles(styles);
- }
- }, [content, styles, htmlStyles]);
-
return (
@@ -225,7 +204,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => {
diff --git a/web/src/components/layout/headerbar/ThemeToggle.jsx b/web/src/components/layout/headerbar/ThemeToggle.jsx
index 45e7918d..95cf8db5 100644
--- a/web/src/components/layout/headerbar/ThemeToggle.jsx
+++ b/web/src/components/layout/headerbar/ThemeToggle.jsx
@@ -95,13 +95,15 @@ const ThemeToggle = ({ theme, onThemeToggle, t }) => {
}
>
-
+
+
+
);
};