diff --git a/src/components/chat/MessageItem.tsx b/src/components/chat/MessageItem.tsx index 6ffee0a..ebdb9c7 100644 --- a/src/components/chat/MessageItem.tsx +++ b/src/components/chat/MessageItem.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useState, useCallback } from 'react'; import type { Message, TokenUsage } from '@/types'; import { Message as AIMessage, @@ -13,6 +14,7 @@ import { ToolInput, ToolOutput, } from '@/components/ai-elements/tool'; +import { CopyIcon, CheckIcon } from 'lucide-react'; import type { ToolUIPart } from 'ai'; interface MessageItemProps { @@ -110,6 +112,35 @@ function getToolState(result?: string, isError?: boolean): ToolUIPart['state'] { return 'output-available'; } +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback(async () => { + try { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + // fallback + } + }, [text]); + + return ( + + ); +} + function TokenUsageDisplay({ usage }: { usage: TokenUsage }) { const totalTokens = usage.input_tokens + usage.output_tokens; const costStr = usage.cost_usd !== undefined && usage.cost_usd !== null @@ -182,13 +213,12 @@ export function MessageItem({ message }: MessageItemProps) { )} - {/* Footer with timestamp and token usage - outside MessageContent to avoid overflow-hidden clipping */} - {!isUser && ( -