Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 71 additions & 40 deletions ui/desktop/src/components/MarkdownContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, memo, useMemo } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import remarkBreaks from 'remark-breaks';
Expand All @@ -16,7 +16,14 @@ interface MarkdownContentProps {
className?: string;
}

const CodeBlock = ({ language, children }: { language: string; children: string }) => {
// Memoized CodeBlock component to prevent re-rendering when props haven't changed
const CodeBlock = memo(function CodeBlock({
language,
children,
}: {
language: string;
children: string;
}) {
const [copied, setCopied] = useState(false);
const timeoutRef = useRef<number | null>(null);

Expand All @@ -43,6 +50,44 @@ const CodeBlock = ({ language, children }: { language: string; children: string
};
}, []);

// Memoize the SyntaxHighlighter component to prevent re-rendering
// Only re-render if language or children change
const memoizedSyntaxHighlighter = useMemo(() => {
// For very large code blocks, consider truncating or lazy loading
const isLargeCodeBlock = children.length > 10000; // 10KB threshold

if (isLargeCodeBlock) {
console.log(`Large code block detected (${children.length} chars), consider optimization`);
}

return (
<SyntaxHighlighter
style={oneDark}
language={language}
PreTag="div"
customStyle={{
margin: 0,
width: '100%',
maxWidth: '100%',
}}
codeTagProps={{
style: {
whiteSpace: 'pre-wrap',
wordBreak: 'break-all',
overflowWrap: 'break-word',
fontFamily: 'var(--font-sans)',
},
}}
// Performance optimizations for SyntaxHighlighter
showLineNumbers={false} // Disable line numbers for better performance
wrapLines={false} // Disable line wrapping for better performance
lineProps={undefined} // Don't add extra props to each line
>
{children}
</SyntaxHighlighter>
);
}, [language, children]);

return (
<div className="relative group w-full">
<button
Expand All @@ -54,47 +99,31 @@ const CodeBlock = ({ language, children }: { language: string; children: string
>
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
</button>
<div className="w-full overflow-x-auto">
<SyntaxHighlighter
style={oneDark}
language={language}
PreTag="div"
customStyle={{
margin: 0,
width: '100%',
maxWidth: '100%',
}}
codeTagProps={{
style: {
whiteSpace: 'pre-wrap',
wordBreak: 'break-all',
overflowWrap: 'break-word',
fontFamily: 'var(--font-sans)',
},
}}
>
{children}
</SyntaxHighlighter>
</div>
<div className="w-full overflow-x-auto">{memoizedSyntaxHighlighter}</div>
</div>
);
};

const MarkdownCode = React.forwardRef(function MarkdownCode(
{ inline, className, children, ...props }: CodeProps,
ref: React.Ref<HTMLElement>
) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<CodeBlock language={match[1]}>{String(children).replace(/\n$/, '')}</CodeBlock>
) : (
<code ref={ref} {...props} className="break-all bg-inline-code whitespace-pre-wrap font-sans">
{children}
</code>
);
});

export default function MarkdownContent({ content, className = '' }: MarkdownContentProps) {
const MarkdownCode = memo(
React.forwardRef(function MarkdownCode(
{ inline, className, children, ...props }: CodeProps,
ref: React.Ref<HTMLElement>
) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<CodeBlock language={match[1]}>{String(children).replace(/\n$/, '')}</CodeBlock>
) : (
<code ref={ref} {...props} className="break-all bg-inline-code whitespace-pre-wrap font-sans">
{children}
</code>
);
})
);

const MarkdownContent = memo(function MarkdownContent({
content,
className = '',
}: MarkdownContentProps) {
const [processedContent, setProcessedContent] = useState(content);

useEffect(() => {
Expand Down Expand Up @@ -137,4 +166,6 @@ export default function MarkdownContent({ content, className = '' }: MarkdownCon
</ReactMarkdown>
</div>
);
}
});

export default MarkdownContent;
Loading