Skip to content

Commit

Permalink
feat(chat): improve styling of code blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Feb 23, 2025
1 parent c122a9c commit 03a11cb
Show file tree
Hide file tree
Showing 11 changed files with 50 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import clsx from 'clsx';
import { memo, useMemo, useSyncExternalStore } from 'react';
import sanitizeHtml from 'sanitize-html';

import type { SdkMessageWebSearchItemT } from '@llm/sdk';

Expand All @@ -9,7 +8,8 @@ import { createStoreSubscriber, truncateText } from '@llm/commons';
import type { AIStreamContent, AIStreamObservable } from '../../hooks';

import { ChatMessageMarkdown } from './chat-message-markdown';
import { useContentHydration } from './parser';
import { useContentHydration } from './hydrate';
import { sanitizeContentPreservingCodeBlocks } from './sanitize-content-preserving-code-blocks';

type Props = {
content: string | AIStreamObservable;
Expand Down Expand Up @@ -56,14 +56,14 @@ export const ChatMessageContent = memo((

const isStreaming = typeof content !== 'string';
const sanitizedContent = useMemo(() => {
const html = sanitizeHtml(stream.content);
const html = sanitizeContentPreservingCodeBlocks(stream.content);

if (truncate) {
return truncateText(truncate, '...')(html);
}

return html;
}, [stream, truncate]);
}, [stream.content, truncate]);

const hydrationResult = useContentHydration({
disabled,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './chat-message-content';
export * from './parser';
export * from './hydrate';
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import sanitizeHtml from 'sanitize-html';

export function sanitizeContentPreservingCodeBlocks(content: string): string {
const codeBlocks: string[] = [];

// Split content by ``` to handle unclosed blocks
const parts = content.split('```');
let result = parts[0];

// Process alternating text/code blocks
for (let i = 1; i < parts.length; i++) {
if (i % 2 === 1) {
// This is a code block
const placeholder = `__CODE_BLOCK_${Math.floor(i / 2)}__`;
const codeContent = `\`\`\`${parts[i]}${i < parts.length - 1 ? '```' : ''}`;
codeBlocks.push(codeContent);
result += placeholder;
}
else {
// This is regular text
result += parts[i];
}
}

const sanitizedContent = sanitizeHtml(result);

// Restore code blocks
return sanitizedContent.replace(/__CODE_BLOCK_(\d+)__/g, (_, index) =>
codeBlocks[Number.parseInt(index, 10)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function ChatCodeBlock({ language, children }: ChatCodeBlockProps) {
};

return (
<div className="relative bg-[#f7f7f8] border border-gray-200 rounded-md">
<div className="relative bg-[#fafafa] border border-gray-200 rounded-md">
<div className="flex justify-between items-center px-4 pt-2">
<span className="text-gray-600 text-xs">{language || 'plaintext'}</span>
<button
Expand All @@ -35,18 +35,20 @@ export function ChatCodeBlock({ language, children }: ChatCodeBlockProps) {
</button>
</div>

<SyntaxHighlighter
language={language || 'plaintext'}
style={oneLight}
customStyle={{
margin: 0,
padding: '1rem',
background: 'transparent',
}}
PreTag="div"
>
{children}
</SyntaxHighlighter>
<div className="max-h-[500px] overflow-auto">
<SyntaxHighlighter
language={language || 'plaintext'}
style={oneLight}
customStyle={{
margin: 0,
padding: '1rem',
background: 'inherit',
}}
PreTag="div"
>
{children}
</SyntaxHighlighter>
</div>
</div>
);
}

0 comments on commit 03a11cb

Please sign in to comment.