diff --git a/frontend/components/Markdown.tsx b/frontend/components/Markdown.tsx index 9ee8e3d2..46f02ee1 100644 --- a/frontend/components/Markdown.tsx +++ b/frontend/components/Markdown.tsx @@ -6,7 +6,16 @@ import rehypeHighlight from 'rehype-highlight'; import rehypeKatex from 'rehype-katex'; import 'katex/dist/katex.min.css'; import { useTheme } from '../contexts/ThemeContext'; -import { ClipboardCheck, Clipboard, ChevronDown, ChevronUp, WrapText, Brain } from 'lucide-react'; +import { + ClipboardCheck, + Clipboard, + ChevronDown, + ChevronUp, + WrapText, + Brain, + Eye, +} from 'lucide-react'; +import { Modal } from './ui/Modal'; interface MarkdownProps { text: string; @@ -327,6 +336,19 @@ const MarkdownComponents: any = { const [copied, setCopied] = React.useState(false); const [isCollapsed, setIsCollapsed] = React.useState(false); const [isWrapped, setIsWrapped] = React.useState(false); + const [showHtmlPreview, setShowHtmlPreview] = React.useState(false); + + // Helper function to check if code is a full HTML page + const isFullHtmlPage = (code: string): boolean => { + if (!code) return false; + const trimmed = code.trim().toLowerCase(); + // Check for DOCTYPE, html tag, or both head and body tags + return ( + trimmed.includes('') || + (trimmed.includes('')) || + (trimmed.includes('
{ try { @@ -362,6 +384,10 @@ const MarkdownComponents: any = { const codeClassName = childEl?.props?.className || ''; const languageMatch = codeClassName.match(/language-(\w+)/); const language = languageMatch ? languageMatch[1] : null; + + // Get code content for HTML detection + const codeContent = typeof childEl?.props?.children === 'string' ? childEl.props.children : ''; + const isHtml = language === 'html' && isFullHtmlPage(codeContent); const wrappedChild = React.isValidElement(childEl) ? React.cloneElement(childEl as React.ReactElement
- {/* Header with language and copy button */}
-
- {language && {language}}
-
-
-
-
- {/* padded, scrollable code area */}
-
- {wrappedChild}
-
-
+ {/* padded, scrollable code area */}
+
+ {wrappedChild}
+
+
+
+ {/* HTML Preview Modal */}
+ {isHtml && (
+ setShowHtmlPreview(false)}
+ title="HTML Preview"
+ maxWidthClassName="max-w-6xl"
+ >
+
+
+ )}
+ >
);
},
code: function CodeRenderer({