import { Check, Copy, CornerUpLeft } from "lucide-react" import React, { useState } from "react" import ReactMarkdown from "react-markdown" import remarkGfm from "remark-gfm" import { Button } from "../../ui/button" import ContextTabs from "./ContextTabs" import { copyToClipboard, stringifyContent } from "./lib/chatUtils" import { createMarkdownComponents } from "./lib/markdownComponents" import { MessageProps } from "./types" export default function ChatMessage({ message, setContext, setIsContextExpanded, socket, handleApplyCode, activeFileName, activeFileContent, editorRef, mergeDecorationsCollection, setMergeDecorationsCollection, selectFile, }: MessageProps) { // State for expanded message index const [expandedMessageIndex, setExpandedMessageIndex] = useState< number | null >(null) // State for copied text const [copiedText, setCopiedText] = useState(null) // Render copy button for text content const renderCopyButton = (text: any) => ( ) // Set context for code when asking about code const askAboutCode = (code: any) => { const contextString = stringifyContent(code) const newContext = `Regarding this code:\n${contextString}` // Format timestamp to match chat message format (HH:MM PM) const timestamp = new Date().toLocaleTimeString("en-US", { hour12: true, hour: "2-digit", minute: "2-digit", }) // Instead of replacing context, append to it if (message.role === "assistant") { // For assistant messages, create a new context tab with the response content and timestamp setContext(newContext, `AI Response (${timestamp})`, { start: 1, end: contextString.split("\n").length, }) } else { // For user messages, create a new context tab with the selected content and timestamp setContext(newContext, `User Chat (${timestamp})`, { start: 1, end: contextString.split("\n").length, }) } setIsContextExpanded(false) } // Render markdown elements for code and text const renderMarkdownElement = (props: any) => { const { node, children } = props const content = stringifyContent(children) return (
{renderCopyButton(content)}
{/* Render markdown element */} {React.createElement( node.tagName, { ...props, className: `${ props.className || "" } hover:bg-transparent rounded p-1 transition-colors`, }, children )}
) } // Create markdown components const components = createMarkdownComponents( renderCopyButton, renderMarkdownElement, askAboutCode, activeFileName, activeFileContent, editorRef, handleApplyCode, selectFile, mergeDecorationsCollection, setMergeDecorationsCollection, ) return (
{/* Render context tabs */} {message.role === "user" && message.context && (
{}} contextTabs={parseContextToTabs(message.context)} onRemoveTab={() => {}} isExpanded={expandedMessageIndex === 0} onToggleExpand={() => setExpandedMessageIndex(expandedMessageIndex === 0 ? null : 0) } className="[&_div:first-child>div:first-child>div]:bg-[#0D0D0D] [&_button:first-child]:hidden [&_button:last-child]:hidden" /> {expandedMessageIndex === 0 && (
{renderCopyButton( message.context.replace(/^Regarding this code:\n/, "") )}
{/* Render code textarea */} {(() => { const code = message.context.replace( /^Regarding this code:\n/, "" ) const match = /language-(\w+)/.exec(code) const language = match ? match[1] : "typescript" return (