diff --git a/src/components/BilingualMarkdownRenderer.tsx b/src/components/BilingualMarkdownRenderer.tsx index e66caff2..80bdc2b3 100644 --- a/src/components/BilingualMarkdownRenderer.tsx +++ b/src/components/BilingualMarkdownRenderer.tsx @@ -234,7 +234,8 @@ const BilingualMarkdownRenderer = forwardRef([\s\S]*?)<\/code>/g; + // 修改正则以支持带属性的 code 标签(如 ) + const codeRegex = /]*)?>([\s\S]*?)<\/code>/g; let lastIndex = 0; let match: RegExpExecArray | null; while ((match = codeRegex.exec(translatedTexts[i])) !== null) { diff --git a/src/components/MarkdownRenderer.tsx b/src/components/MarkdownRenderer.tsx index 5ec1e271..0e1f61f4 100644 --- a/src/components/MarkdownRenderer.tsx +++ b/src/components/MarkdownRenderer.tsx @@ -860,7 +860,9 @@ const MarkdownRenderer: React.FC = memo(({ {children} ), code: ({ className, children, ...props }) => { - const isInline = !className; + // 检查 props 中是否有 'data-code-block' 标记(由 pre 组件添加) + const isCodeBlock = 'data-code-block' in props || !!className; + const isInline = !isCodeBlock; const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; @@ -874,7 +876,14 @@ const MarkdownRenderer: React.FC = memo(({ ); }, - pre: ({ children }) => <>{children}, + pre: ({ children }) => { + // 给 code 子元素添加标记,表明它是代码块而不是行内代码 + if (React.isValidElement(children) && children.type === 'code') { + return <>{React.cloneElement(children as React.ReactElement>, { 'data-code-block': true })}; + } + // 对于非 code 子元素(如 ASCII 字符画),保留 pre 标签 + return
{children}
; + }, blockquote: ({ children }) => (
{children} diff --git a/src/index.css b/src/index.css index 72f785bf..1697c92e 100644 --- a/src/index.css +++ b/src/index.css @@ -191,6 +191,13 @@ /* ========== Markdown Prose Component Styles ========== */ @layer components { + .prose pre { + overflow-x: auto; + white-space: pre; + overflow-wrap: normal; + word-break: normal; + } + .prose pre code { display: block; padding: 1rem; @@ -199,6 +206,27 @@ line-height: 1.5rem; tab-size: 2; -moz-tab-size: 2; + white-space: pre; + overflow-wrap: normal; + word-break: normal; + overflow-x: auto; + } + + /* 纯 pre 标签样式(如字符画、ASCII art),不包含 code 子元素 */ + .prose pre:not(:has(code)) { + padding: 1rem; + background-color: #f8fafc; + border-radius: 0.5rem; + font-size: 0.875rem; + line-height: 1.5rem; + font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace; + border: 1px solid rgba(0, 0, 0, 0.06); + } + + .dark .prose pre:not(:has(code)) { + background-color: #1e293b; + border-color: rgba(255, 255, 255, 0.04); + color: #e6edf3; } .prose :not(pre) > code {