diff --git a/src/components/ChatMessage.tsx b/src/components/ChatMessage.tsx index 0b1f447..9bdb4b7 100644 --- a/src/components/ChatMessage.tsx +++ b/src/components/ChatMessage.tsx @@ -4,6 +4,7 @@ import remarkGfm from 'remark-gfm'; import rehypeHighlight from 'rehype-highlight'; import type { ChatMessage as ChatMessageType, MessageBlock } from '../types'; import { ThinkingBlock } from './ThinkingBlock'; +import { CodeBlock } from './CodeBlock'; import { ToolCall } from './ToolCall'; import { Bot, User, Wrench } from 'lucide-react'; import { t, locale } from '../lib/i18n'; @@ -127,10 +128,12 @@ function getInternalBlocks(blocks: MessageBlock[]): MessageBlock[] { return blocks.filter(b => b.type === 'thinking' || b.type === 'tool_use' || b.type === 'tool_result'); } +const markdownComponents = { pre: CodeBlock }; + function renderTextBlocks(blocks: MessageBlock[]) { return getTextBlocks(blocks).map((block, i) => (
- + {autoFormatText((block as any).text)}
@@ -220,7 +223,7 @@ export function ChatMessageComponent({ message }: { message: ChatMessageType }) {/* User-visible text */} {message.blocks.length > 0 ? renderTextBlocks(message.blocks) : (
- + {autoFormatText(message.content)}
diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx new file mode 100644 index 0000000..c32ff99 --- /dev/null +++ b/src/components/CodeBlock.tsx @@ -0,0 +1,38 @@ +import { useState, useCallback, type HTMLAttributes } from 'react'; +import { Check, Copy } from 'lucide-react'; + +/** + * Custom
 renderer for ReactMarkdown.
+ * Wraps code blocks with a floating copy button.
+ */
+export function CodeBlock(props: HTMLAttributes) {
+  const [copied, setCopied] = useState(false);
+
+  const handleCopy = useCallback(() => {
+    // Extract text from the nested  element
+    const code = (props.children as any)?.props?.children;
+    if (typeof code === 'string') {
+      navigator.clipboard.writeText(code).then(() => {
+        setCopied(true);
+        setTimeout(() => setCopied(false), 2000);
+      });
+    }
+  }, [props.children]);
+
+  return (
+    
+
+      
+    
+ ); +}