@@ -92,3 +92,73 @@ describe("CodeBlockWithCopy", () => {
9292 } ) ;
9393 } ) ;
9494} ) ;
95+ import React , { useState } from "react" ;
96+
97+ const CodeBlockWithCopy = ( { title, children, className = "" } ) => {
98+ const [ copied , setCopied ] = useState ( false ) ;
99+
100+ const isDiff = className . includes ( "language-diff" ) ;
101+
102+ const getTextToCopy = ( ) => {
103+ if ( ! children ) return "" ;
104+
105+ let rawText = "" ;
106+
107+ if ( typeof children === "string" ) {
108+ rawText = children ;
109+ } else if ( Array . isArray ( children ) ) {
110+ rawText = children . join ( "" ) ;
111+ } else if ( children . props ?. children ) {
112+ rawText = children . props . children ;
113+ }
114+
115+ if ( isDiff ) {
116+ return rawText
117+ . split ( "\n" )
118+ . filter ( ( line ) => ! line . startsWith ( "-" ) ) // remove deleted lines
119+ . map ( ( line ) => line . replace ( / ^ \+ / , "" ) ) // remove "+" prefix
120+ . join ( "\n" ) ;
121+ }
122+
123+ return rawText ;
124+ } ;
125+
126+ const handleCopy = async ( ) => {
127+ const text = getTextToCopy ( ) ;
128+
129+ try {
130+ await navigator . clipboard . writeText ( text ) ;
131+ setCopied ( true ) ;
132+ setTimeout ( ( ) => setCopied ( false ) , 1500 ) ;
133+ } catch ( err ) {
134+ console . error ( "Copy failed" , err ) ;
135+ }
136+ } ;
137+
138+ return (
139+ < >
140+ { /* REQUIRED for Cypress */ }
141+ < div >
142+ < strong > { title } </ strong >
143+ </ div >
144+
145+ { /* MUST be NEXT sibling */ }
146+ < div className = "code-block-wrapper relative group bg-gray-900 rounded-lg overflow-hidden" >
147+ { /* Copy Button */ }
148+ < button
149+ className = "copy-button absolute top-2 right-2 text-xs px-2 py-1 bg-gray-700 text-white rounded opacity-0 group-hover:opacity-100 transition"
150+ onClick = { handleCopy }
151+ >
152+ { copied ? "Copied" : "Copy" }
153+ </ button >
154+
155+ { /* Code Block */ }
156+ < pre className = "p-4 overflow-x-auto text-sm" >
157+ < code className = { className } > { children } </ code >
158+ </ pre >
159+ </ div >
160+ </ >
161+ ) ;
162+ } ;
163+
164+ export default CodeBlockWithCopy ;
0 commit comments