11/**
2- * Copy code functionality for code blocks
3- * Simplified and optimized version
2+ * Copy code functionality for code blocks with user-friendly feedback
43 */
54
65/**
76 * Handle click on copy button with unified clipboard handling
7+ * @param event - The click event from the copy button
88 */
99function handleCopyClick ( event : Event ) : void {
1010 event . preventDefault ( ) ;
@@ -13,55 +13,76 @@ function handleCopyClick(event: Event): void {
1313 const button = event . currentTarget as HTMLElement ;
1414 const codeContent = button . getAttribute ( 'data-code' ) ;
1515
16- if ( ! codeContent ) {
17- console . error ( 'No code content found to copy' ) ;
16+ if ( ! codeContent || codeContent . trim ( ) === '' ) {
17+ showErrorMessage ( button ) ;
1818 return ;
1919 }
2020
2121 copyToClipboard ( codeContent , button ) ;
2222}
2323
24- /**
25- * Unified clipboard copy with fallback
26- */
27- async function copyToClipboard (
28- text : string ,
29- button : HTMLElement ,
30- ) : Promise < void > {
24+ async function copyToClipboard ( text : string , button : HTMLElement ) : Promise < void > {
3125 try {
3226 await navigator . clipboard . writeText ( text ) ;
3327 showSuccessMessage ( button ) ;
3428 } catch {
3529 // Fallback for older browsers
3630 const textarea = document . createElement ( 'textarea' ) ;
3731 textarea . value = text ;
38- textarea . style . cssText =
39- 'position:fixed;left:-999999px;top:-999999px;opacity:0;' ;
40-
32+ textarea . style . cssText = 'position:fixed;left:-999999px;top:-999999px;opacity:0;' ;
4133 document . body . appendChild ( textarea ) ;
4234 textarea . select ( ) ;
43-
4435 const success = document . execCommand ( 'copy' ) ;
4536 document . body . removeChild ( textarea ) ;
46-
47- if ( success ) showSuccessMessage ( button ) ;
37+
38+ if ( success ) {
39+ showSuccessMessage ( button ) ;
40+ } else {
41+ showErrorMessage ( button ) ;
42+ }
4843 }
4944}
5045
51- /**
52- * Show success message
53- */
5446function showSuccessMessage ( button : HTMLElement ) : void {
55- const successMessage = button . nextElementSibling as HTMLElement ;
56- if ( successMessage ?. classList . contains ( 'copy-success-message' ) ) {
57- successMessage . classList . remove ( 'hidden' ) ;
58- setTimeout ( ( ) => successMessage . classList . add ( 'hidden' ) , 2000 ) ;
59- }
47+ const originalContent = button . innerHTML ;
48+ const originalClasses = button . className ;
49+
50+ button . className = 'copy-code-btn bg-green-100 text-green-800 text-xs px-4 py-2 rounded-lg transition-all duration-200 flex items-center space-x-2 shadow-sm border border-green-200' ;
51+ button . innerHTML = `
52+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
53+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
54+ </svg>
55+ <span class="font-medium">Copied!</span>
56+ ` ;
57+ button . setAttribute ( 'disabled' , 'true' ) ;
58+
59+ setTimeout ( ( ) => {
60+ button . className = originalClasses ;
61+ button . innerHTML = originalContent ;
62+ button . removeAttribute ( 'disabled' ) ;
63+ } , 2000 ) ;
64+ }
65+
66+ function showErrorMessage ( button : HTMLElement ) : void {
67+ const originalContent = button . innerHTML ;
68+ const originalClasses = button . className ;
69+
70+ button . className = 'copy-code-btn bg-red-100 text-red-800 text-xs px-4 py-2 rounded-lg transition-all duration-200 flex items-center space-x-2 shadow-sm border border-red-200' ;
71+ button . innerHTML = `
72+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
73+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
74+ </svg>
75+ <span class="font-medium">Failed!</span>
76+ ` ;
77+ button . setAttribute ( 'disabled' , 'true' ) ;
78+
79+ setTimeout ( ( ) => {
80+ button . className = originalClasses ;
81+ button . innerHTML = originalContent ;
82+ button . removeAttribute ( 'disabled' ) ;
83+ } , 2500 ) ;
6084}
6185
62- /**
63- * Initialize copy code functionality
64- */
6586export function initCodeCopy ( ) : void {
6687 document . querySelectorAll ( '.copy-code-btn' ) . forEach ( ( button ) => {
6788 if ( button instanceof HTMLElement ) {
@@ -71,18 +92,11 @@ export function initCodeCopy(): void {
7192 } ) ;
7293}
7394
74- // Auto-initialize when available
95+ // Auto-initialize
7596if ( typeof window !== 'undefined' ) {
7697 if ( document . readyState === 'loading' ) {
7798 document . addEventListener ( 'DOMContentLoaded' , initCodeCopy ) ;
7899 } else {
79100 initCodeCopy ( ) ;
80101 }
81-
82- // Re-initialize for dynamic content
83- let timeoutId : number ;
84- document . addEventListener ( 'click' , ( ) => {
85- clearTimeout ( timeoutId ) ;
86- timeoutId = window . setTimeout ( initCodeCopy , 100 ) ;
87- } ) ;
88102}
0 commit comments