diff --git a/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx b/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx index 62822de13a..68d75da9fd 100644 --- a/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx +++ b/src/renderer/src/components/CodeBlockView/HtmlArtifactsCard.tsx @@ -250,7 +250,7 @@ const Container = styled.div<{ $isStreaming: boolean }>` border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; - margin: 16px 0; + margin: 10px 0; ` const GeneratingContainer = styled.div` diff --git a/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx b/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx index be3e0b7e08..e636b57e76 100644 --- a/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx +++ b/src/renderer/src/components/CodeBlockView/MermaidPreview.tsx @@ -142,7 +142,7 @@ const MermaidPreview: React.FC = ({ children, setTools }) => }> {(mermaidError || error) && {mermaidError || error}} - + ) diff --git a/src/renderer/src/components/CodeBlockView/view.tsx b/src/renderer/src/components/CodeBlockView/view.tsx index 1ab685e8ba..95fb6ddf30 100644 --- a/src/renderer/src/components/CodeBlockView/view.tsx +++ b/src/renderer/src/components/CodeBlockView/view.tsx @@ -4,7 +4,7 @@ import { CodeTool, CodeToolbar, TOOL_SPECS, useCodeTool } from '@renderer/compon import { useSettings } from '@renderer/hooks/useSettings' import { pyodideService } from '@renderer/services/PyodideService' import { extractTitle } from '@renderer/utils/formats' -import { getExtensionByLanguage, isValidPlantUML } from '@renderer/utils/markdown' +import { getExtensionByLanguage, isHtmlCode, isValidPlantUML } from '@renderer/utils/markdown' import dayjs from 'dayjs' import { CirclePlay, CodeXml, Copy, Download, Eye, Square, SquarePen, SquareSplitHorizontal } from 'lucide-react' import React, { memo, useCallback, useEffect, useMemo, useState } from 'react' @@ -229,7 +229,7 @@ export const CodeBlockView: React.FC = memo(({ children, language, onSave }, [specialView, sourceView, viewMode]) // HTML 代码块特殊处理 - 在所有 hooks 调用之后 - if (language === 'html') { + if (language === 'html' && isHtmlCode(children)) { return } diff --git a/src/renderer/src/pages/home/Messages/Message.tsx b/src/renderer/src/pages/home/Messages/Message.tsx index 2579477942..14052ad7c3 100644 --- a/src/renderer/src/pages/home/Messages/Message.tsx +++ b/src/renderer/src/pages/home/Messages/Message.tsx @@ -95,7 +95,7 @@ const MessageItem: FC = ({ stopEditing() }, [stopEditing]) - const isLastMessage = index === 0 + const isLastMessage = index === 0 || !!isGrouped const isAssistantMessage = message.role === 'assistant' const showMenubar = !hideMenuBar && !isStreaming && !message.status.includes('ing') && !isEditing @@ -190,6 +190,7 @@ const MessageContainer = styled.div` transform: translateZ(0); will-change: transform; padding: 10px; + padding-bottom: 0; border-radius: 10px; &.message-highlight { background-color: var(--color-primary-mute); diff --git a/src/renderer/src/pages/home/Messages/MessageContent.tsx b/src/renderer/src/pages/home/Messages/MessageContent.tsx index f301831a4e..61b113a011 100644 --- a/src/renderer/src/pages/home/Messages/MessageContent.tsx +++ b/src/renderer/src/pages/home/Messages/MessageContent.tsx @@ -14,7 +14,7 @@ const MessageContent: React.FC = ({ message }) => { return ( <> {!isEmpty(message.mentions) && ( - + {message.mentions?.map((model) => {'@' + model.name})} )} diff --git a/src/renderer/src/utils/__tests__/markdown.test.ts b/src/renderer/src/utils/__tests__/markdown.test.ts index a078f2c418..ee00924d71 100644 --- a/src/renderer/src/utils/__tests__/markdown.test.ts +++ b/src/renderer/src/utils/__tests__/markdown.test.ts @@ -8,6 +8,7 @@ import { findCitationInChildren, getCodeBlockId, getExtensionByLanguage, + isHtmlCode, markdownToPlainText, processLatexBrackets, removeTrailingDoubleSpaces, @@ -698,4 +699,31 @@ $$ }) }) }) + + describe('isHtmlCode', () => { + it('should detect HTML with DOCTYPE', () => { + expect(isHtmlCode('')).toBe(true) + expect(isHtmlCode('')).toBe(true) + }) + + it('should detect HTML with html/head/body tags', () => { + expect(isHtmlCode('')).toBe(true) + expect(isHtmlCode('')).toBe(true) + expect(isHtmlCode('')).toBe(true) + expect(isHtmlCode('')).toBe(true) + }) + + it('should detect complete HTML structure', () => { + const html = 'TestHello' + expect(isHtmlCode(html)).toBe(true) + }) + + it('should return false for non-HTML content', () => { + expect(isHtmlCode(null)).toBe(false) + expect(isHtmlCode('')).toBe(false) + expect(isHtmlCode('Hello world')).toBe(false) + expect(isHtmlCode('a < b')).toBe(false) + expect(isHtmlCode('
')).toBe(false) + }) + }) }) diff --git a/src/renderer/src/utils/markdown.ts b/src/renderer/src/utils/markdown.ts index 8505ed36c7..99e2591194 100644 --- a/src/renderer/src/utils/markdown.ts +++ b/src/renderer/src/utils/markdown.ts @@ -267,6 +267,47 @@ export function isValidPlantUML(code: string | null): boolean { return diagramType !== undefined && code.search(`@end${diagramType}`) !== -1 } +/** + * 检查代码是否具有HTML特征 + * @param code 输入的代码字符串 + * @returns 是HTML代码 true,否则 false + */ +export function isHtmlCode(code: string | null): boolean { + if (!code || !code.trim()) { + return false + } + + const trimmedCode = code.trim() + + // 检查是否包含HTML文档类型声明 + if (trimmedCode.includes('') || trimmedCode.includes('')) { + return true + } + + // 检查是否包含html标签 + if (trimmedCode.includes('')) { + return true + } + + // 检查是否包含head标签 + if (trimmedCode.includes('') || trimmedCode.includes('')) { + return true + } + + // 检查是否包含body标签 + if (trimmedCode.includes('')) { + return true + } + + // 检查是否以HTML标签开头和结尾的完整HTML结构 + const htmlTagPattern = /^\s*]*>[\s\S]*<\/html>\s*$/i + if (htmlTagPattern.test(trimmedCode)) { + return true + } + + return false +} + /** * 将 Markdown 字符串转换为纯文本。 * @param markdown Markdown 字符串。