@@ -416,4 +416,69 @@ if (isDetailPage) {
416416 if ( evt . key === "Escape" ) closeCodePanel ( ) ;
417417 } ) ;
418418
419+ // ----------------------------------------------------------
420+ // Copy Code button
421+ // ----------------------------------------------------------
422+ var btnCopyCode = document . getElementById ( "btn-copy-code" ) ;
423+ var copyToast = document . getElementById ( "copy-toast" ) ;
424+ var toastTimeout = null ;
425+
426+ function showCopySuccess ( ) {
427+ if ( ! btnCopyCode ) return ;
428+
429+ // Swap icons on the button
430+ var copyIcon = btnCopyCode . querySelector ( ".copy-icon" ) ;
431+ var checkIcon = btnCopyCode . querySelector ( ".check-icon" ) ;
432+ var btnLabel = btnCopyCode . querySelector ( ".copy-btn-label" ) ;
433+
434+ if ( copyIcon ) copyIcon . style . display = "none" ;
435+ if ( checkIcon ) checkIcon . style . display = "inline" ;
436+ if ( btnLabel ) btnLabel . textContent = "Copied!" ;
437+ btnCopyCode . classList . add ( "copied" ) ;
438+ btnCopyCode . disabled = true ;
439+
440+ // Show toast
441+ if ( copyToast ) {
442+ copyToast . classList . add ( "show" ) ;
443+ }
444+
445+ // Auto-reset after 2.5 s
446+ clearTimeout ( toastTimeout ) ;
447+ toastTimeout = setTimeout ( function ( ) {
448+ if ( copyIcon ) copyIcon . style . display = "inline" ;
449+ if ( checkIcon ) checkIcon . style . display = "none" ;
450+ if ( btnLabel ) btnLabel . textContent = "Copy Code" ;
451+ btnCopyCode . classList . remove ( "copied" ) ;
452+ btnCopyCode . disabled = false ;
453+ if ( copyToast ) copyToast . classList . remove ( "show" ) ;
454+ } , 2500 ) ;
455+ }
456+
457+ if ( btnCopyCode ) {
458+ btnCopyCode . addEventListener ( "click" , function ( ) {
459+ var code = codeContentEl ? codeContentEl . textContent : "" ;
460+ if ( ! code || code === "Loading..." || code === "Loading starter code..." ) return ;
461+
462+ // Use Clipboard API with textarea fallback
463+ if ( navigator . clipboard && navigator . clipboard . writeText ) {
464+ navigator . clipboard . writeText ( code ) . then ( showCopySuccess ) . catch ( function ( ) {
465+ fallbackCopy ( code ) ;
466+ } ) ;
467+ } else {
468+ fallbackCopy ( code ) ;
469+ }
470+ } ) ;
471+ }
472+
473+ function fallbackCopy ( text ) {
474+ var ta = document . createElement ( "textarea" ) ;
475+ ta . value = text ;
476+ ta . style . cssText = "position:fixed;top:-9999px;left:-9999px;opacity:0" ;
477+ document . body . appendChild ( ta ) ;
478+ ta . focus ( ) ;
479+ ta . select ( ) ;
480+ try { document . execCommand ( "copy" ) ; showCopySuccess ( ) ; } catch ( e ) { /* silent fail */ }
481+ document . body . removeChild ( ta ) ;
482+ }
483+
419484} // end isDetailPage
0 commit comments