@@ -4,7 +4,7 @@ import React, { ReactNode, useEffect, useMemo, useState } from 'react';
44import dayjs from 'dayjs' ;
55import timezone from 'dayjs/plugin/timezone' ;
66import utc from 'dayjs/plugin/utc' ;
7- import { Ban as Error , CircleCheck , TriangleAlert , ChevronRight } from 'lucide-react' ;
7+ import { Ban as Error , CircleCheck , TriangleAlert , ChevronRight , Copy , Check } from 'lucide-react' ;
88import { LuRefreshCw as AutorenewOutlined , LuInfo as Info , LuPencil as Pencil } from 'react-icons/lu' ;
99import { FaRunning } from 'react-icons/fa' ;
1010import { TfiThought } from 'react-icons/tfi' ;
@@ -45,6 +45,26 @@ function ModernSubactivity({
4545 completedSubactivities : number ;
4646} ) {
4747 const [ isExpanded , setIsExpanded ] = useState ( false ) ;
48+ const [ copiedIndex , setCopiedIndex ] = useState < number | null > ( null ) ;
49+
50+ // Function to copy text to clipboard
51+ const copyToClipboard = async ( text : string , index : number ) => {
52+ try {
53+ await navigator . clipboard . writeText ( text ) ;
54+ setCopiedIndex ( index ) ;
55+ setTimeout ( ( ) => setCopiedIndex ( null ) , 2000 ) ; // Reset after 2 seconds
56+ } catch ( err ) {
57+ console . error ( 'Failed to copy text: ' , err ) ;
58+ }
59+ } ;
60+
61+ // Function to clean the message content
62+ const getCleanContent = ( message : string ) : string => {
63+ // Remove the [SUBACTIVITY] prefix and any bracketed metadata
64+ const messageBody = message . substring ( message . indexOf ( ' ' ) ) ;
65+ // Remove any remaining [TYPE] brackets at the start
66+ return messageBody . replace ( / ^ \[ [ ^ \] ] + ] \s * / , '' ) . trim ( ) ;
67+ } ;
4868
4969 return (
5070 < div className = 'w-full bg-gradient-to-br from-background/60 to-muted/30 border border-border/30 rounded-2xl p-4 backdrop-blur-md shadow-sm my-2' >
@@ -93,7 +113,7 @@ function ModernSubactivity({
93113 < div
94114 key = { `${ child . timestamp } -${ child . message . slice ( 0 , 20 ) } ` }
95115 className = { cn (
96- 'flex items-start gap-3 opacity-0 animate-slide-in-from-left rounded-xl p-3 transition-all duration-200' ,
116+ 'group flex items-start gap-3 opacity-0 animate-slide-in-from-left rounded-xl p-3 transition-all duration-200 hover:bg-gradient-to-r hover:from-muted/10 hover:to-muted/5 ' ,
97117 getAnimationDelay ( index ) ,
98118 isCurrentlyRunning
99119 ? 'bg-gradient-to-r from-primary/5 to-primary/10 border-l-2 border-primary/30'
@@ -121,6 +141,25 @@ function ModernSubactivity({
121141 < div className = 'text-xs leading-relaxed text-foreground/85 flex-1' >
122142 < MarkdownBlock content = { messageBody . trim ( ) } />
123143 </ div >
144+ < Tooltip >
145+ < TooltipTrigger asChild >
146+ < Button
147+ variant = 'ghost'
148+ size = 'sm'
149+ onClick = { ( ) => copyToClipboard ( getCleanContent ( child . message ) , index ) }
150+ className = 'opacity-0 group-hover:opacity-100 transition-opacity duration-200 h-6 w-6 p-0 hover:bg-muted/50 rounded-md'
151+ >
152+ { copiedIndex === index ? (
153+ < Check className = 'w-3 h-3 text-green-600' />
154+ ) : (
155+ < Copy className = 'w-3 h-3 text-muted-foreground' />
156+ ) }
157+ </ Button >
158+ </ TooltipTrigger >
159+ < TooltipContent side = 'top' className = 'text-xs' >
160+ { copiedIndex === index ? 'Copied!' : 'Copy content' }
161+ </ TooltipContent >
162+ </ Tooltip >
124163 </ div >
125164 ) ;
126165 } ) }
0 commit comments