@@ -17,14 +17,14 @@ import { vscode } from "../../utils/vscode"
1717import CodeAccordian , { removeLeadingNonAlphanumeric } from "../common/CodeAccordian"
1818import CodeBlock , { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
1919import CommandOutputViewer from "../common/CommandOutputViewer"
20- import MarkdownBlock from "../common/MarkdownBlock"
2120import { ReasoningBlock } from "./ReasoningBlock"
2221import Thumbnails from "../common/Thumbnails"
2322import McpResourceRow from "../mcp/McpResourceRow"
2423import McpToolRow from "../mcp/McpToolRow"
2524import { highlightMentions } from "./TaskHeader"
2625import { CheckpointSaved } from "./checkpoints/CheckpointSaved"
2726import FollowUpSuggest from "./FollowUpSuggest"
27+ import { Markdown } from "@/components/ui/markdown/Markdown"
2828
2929interface ChatRowProps {
3030 message : ClineMessage
@@ -74,6 +74,71 @@ const ChatRow = memo(
7474
7575export default ChatRow
7676
77+ // Define the new wrapper component with copy functionality
78+ const MarkdownWithCopy = memo ( ( { content, partial } : { content : string ; partial ?: boolean } ) => {
79+ const [ isHovering , setIsHovering ] = useState ( false )
80+ // Assuming useCopyToClipboard is imported correctly (it is, line 5)
81+ const { copyWithFeedback } = useCopyToClipboard ( 200 ) // Use shorter feedback duration like original
82+
83+ return (
84+ < div
85+ onMouseEnter = { ( ) => setIsHovering ( true ) }
86+ onMouseLeave = { ( ) => setIsHovering ( false ) }
87+ style = { { position : "relative" } } >
88+ { /* Apply negative margins and text wrap styles */ }
89+ < div style = { { wordBreak : "break-word" , overflowWrap : "anywhere" , marginBottom : - 15 , marginTop : - 15 } } >
90+ { /* Use the imported shared Markdown component */ }
91+ < Markdown content = { content } />
92+ </ div >
93+ { /* Conditional Copy Button */ }
94+ { content && ! partial && isHovering && (
95+ < div
96+ style = { {
97+ position : "absolute" ,
98+ bottom : "-4px" ,
99+ right : "8px" ,
100+ opacity : 0 ,
101+ animation : "fadeIn 0.2s ease-in-out forwards" ,
102+ borderRadius : "4px" ,
103+ } } >
104+ < style >
105+ { `
106+ @keyframes fadeIn {
107+ from { opacity: 0; }
108+ to { opacity: 1.0; }
109+ }
110+ ` }
111+ </ style >
112+ < VSCodeButton
113+ className = "copy-button"
114+ appearance = "icon"
115+ style = { {
116+ height : "24px" ,
117+ border : "none" ,
118+ background : "var(--vscode-editor-background)" ,
119+ transition : "background 0.2s ease-in-out" ,
120+ } }
121+ onClick = { async ( ) => {
122+ const success = await copyWithFeedback ( content ) // Use content prop
123+ if ( success ) {
124+ const button = document . activeElement as HTMLElement
125+ if ( button ) {
126+ button . style . background = "var(--vscode-button-background)"
127+ setTimeout ( ( ) => {
128+ button . style . background = ""
129+ } , 200 )
130+ }
131+ }
132+ } }
133+ title = "Copy as markdown" >
134+ < span className = "codicon codicon-copy" > </ span >
135+ </ VSCodeButton >
136+ </ div >
137+ ) }
138+ </ div >
139+ )
140+ } )
141+
77142export const ChatRowContent = ( {
78143 message,
79144 lastModifiedMessage,
@@ -555,7 +620,7 @@ export const ChatRowContent = ({
555620 { t ( "chat:subtasks.newTaskContent" ) }
556621 </ div >
557622 < div style = { { padding : "12px 16px" , backgroundColor : "var(--vscode-editor-background)" } } >
558- < MarkdownBlock markdown = { tool . content } />
623+ < Markdown content = { tool . content || "" } />
559624 </ div >
560625 </ div >
561626 </ >
@@ -592,7 +657,7 @@ export const ChatRowContent = ({
592657 { t ( "chat:subtasks.completionContent" ) }
593658 </ div >
594659 < div style = { { padding : "12px 16px" , backgroundColor : "var(--vscode-editor-background)" } } >
595- < MarkdownBlock markdown = { t ( "chat:subtasks.completionInstructions" ) } />
660+ < Markdown content = { t ( "chat:subtasks.completionInstructions" ) || "" } />
596661 </ div >
597662 </ div >
598663 </ >
@@ -729,7 +794,7 @@ export const ChatRowContent = ({
729794 padding : "12px 16px" ,
730795 backgroundColor : "var(--vscode-editor-background)" ,
731796 } } >
732- < MarkdownBlock markdown = { message . text } />
797+ < Markdown content = { message . text || "" } />
733798 </ div >
734799 </ div >
735800 </ div >
@@ -844,7 +909,7 @@ export const ChatRowContent = ({
844909 case "text" :
845910 return (
846911 < div >
847- < Markdown markdown = { message . text } partial = { message . partial } />
912+ < MarkdownWithCopy content = { message . text || "" } partial = { message . partial } />
848913 </ div >
849914 )
850915 case "user_feedback" :
@@ -932,7 +997,7 @@ export const ChatRowContent = ({
932997 { title }
933998 </ div >
934999 < div style = { { color : "var(--vscode-charts-green)" , paddingTop : 10 } } >
935- < Markdown markdown = { message . text } />
1000+ < MarkdownWithCopy content = { message . text || "" } partial = { message . partial } />
9361001 </ div >
9371002 </ >
9381003 )
@@ -1023,7 +1088,7 @@ export const ChatRowContent = ({
10231088 </ div >
10241089 ) }
10251090 < div style = { { paddingTop : 10 } } >
1026- < Markdown markdown = { message . text } partial = { message . partial } />
1091+ < MarkdownWithCopy content = { message . text || "" } partial = { message . partial } />
10271092 </ div >
10281093 </ >
10291094 )
@@ -1200,7 +1265,7 @@ export const ChatRowContent = ({
12001265 { title }
12011266 </ div >
12021267 < div style = { { color : "var(--vscode-charts-green)" , paddingTop : 10 } } >
1203- < Markdown markdown = { message . text } partial = { message . partial } />
1268+ < Markdown content = { message . text || "" } />
12041269 </ div >
12051270 </ div >
12061271 )
@@ -1218,7 +1283,7 @@ export const ChatRowContent = ({
12181283 ) }
12191284 < div style = { { paddingTop : 10 , paddingBottom : 15 } } >
12201285 < Markdown
1221- markdown = { message . partial === true ? message ?. text : followUpData ?. question }
1286+ content = { ( message . partial === true ? message ?. text : followUpData ?. question ) || "" }
12221287 />
12231288 </ div >
12241289 < FollowUpSuggest
@@ -1248,63 +1313,3 @@ export const ProgressIndicator = () => (
12481313 </ div >
12491314 </ div >
12501315)
1251-
1252- const Markdown = memo ( ( { markdown, partial } : { markdown ?: string ; partial ?: boolean } ) => {
1253- const [ isHovering , setIsHovering ] = useState ( false )
1254- const { copyWithFeedback } = useCopyToClipboard ( 200 ) // shorter feedback duration for copy button flash
1255-
1256- return (
1257- < div
1258- onMouseEnter = { ( ) => setIsHovering ( true ) }
1259- onMouseLeave = { ( ) => setIsHovering ( false ) }
1260- style = { { position : "relative" } } >
1261- < div style = { { wordBreak : "break-word" , overflowWrap : "anywhere" , marginBottom : - 15 , marginTop : - 15 } } >
1262- < MarkdownBlock markdown = { markdown } />
1263- </ div >
1264- { markdown && ! partial && isHovering && (
1265- < div
1266- style = { {
1267- position : "absolute" ,
1268- bottom : "-4px" ,
1269- right : "8px" ,
1270- opacity : 0 ,
1271- animation : "fadeIn 0.2s ease-in-out forwards" ,
1272- borderRadius : "4px" ,
1273- } } >
1274- < style >
1275- { `
1276- @keyframes fadeIn {
1277- from { opacity: 0; }
1278- to { opacity: 1.0; }
1279- }
1280- ` }
1281- </ style >
1282- < VSCodeButton
1283- className = "copy-button"
1284- appearance = "icon"
1285- style = { {
1286- height : "24px" ,
1287- border : "none" ,
1288- background : "var(--vscode-editor-background)" ,
1289- transition : "background 0.2s ease-in-out" ,
1290- } }
1291- onClick = { async ( ) => {
1292- const success = await copyWithFeedback ( markdown )
1293- if ( success ) {
1294- const button = document . activeElement as HTMLElement
1295- if ( button ) {
1296- button . style . background = "var(--vscode-button-background)"
1297- setTimeout ( ( ) => {
1298- button . style . background = ""
1299- } , 200 )
1300- }
1301- }
1302- } }
1303- title = "Copy as markdown" >
1304- < span className = "codicon codicon-copy" > </ span >
1305- </ VSCodeButton >
1306- </ div >
1307- ) }
1308- </ div >
1309- )
1310- } )
0 commit comments