[custom_chat_bubble]
<?php
/**
* Enhance Gutenberg Code blocks:
* - Copy icon with checkmark feedback
* - Line numbers
* - Mobile-friendly horizontal scroll
* - Improved accessibility and selection
*/
function ewdt_enhance_code_blocks_with_copy() {
if ( is_admin() ) {
return;
}
// CSS
$css = "
/* General code block improvements */
pre.wp-block-code {
overflow-x: auto;
white-space: pre;
-webkit-overflow-scrolling: touch;
position: relative;
padding-right: 3em; /* room for copy icon */
}
pre.wp-block-code code {
user-select: text;
word-break: normal;
white-space: pre;
display: block;
}
/* Line number support */
.wp-block-code.has-line-numbers {
counter-reset: line;
padding-left: 3em;
}
.wp-block-code.has-line-numbers code span {
display: block;
padding-left: 0.5em;
position: relative;
}
.wp-block-code.has-line-numbers code span::before {
counter-increment: line;
content: counter(line);
position: absolute;
left: -2.5em;
color: #999;
font-size: 0.85em;
text-align: right;
width: 2em;
}
/* Copy button styles */
.code-copy-btn {
position: absolute;
top: 8px;
right: 8px;
background: transparent;
border: none;
cursor: pointer;
padding: 4px;
opacity: 0.6;
transition: opacity 0.3s ease;
z-index: 20;
display: flex;
align-items: center;
justify-content: center;
}
.code-copy-btn:hover {
opacity: 1;
}
.code-copy-btn svg {
width: 18px;
height: 18px;
fill: #0073aa;
transition: fill 0.3s ease;
}
.code-copy-tooltip {
position: absolute;
top: -28px;
right: 0;
background: #0073aa;
color: #fff;
padding: 4px 8px;
border-radius: 3px;
font-size: 11px;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
white-space: nowrap;
}
.code-copy-tooltip.show {
opacity: 1;
pointer-events: auto;
}
";
// JavaScript
$js = <<<JS
document.addEventListener('DOMContentLoaded', function () {
const clipboardSVG = `
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
</svg>`;
const checkmarkSVG = `
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<path d="M9 16.2l-3.5-3.5-1.4 1.4L9 19 20.5 7.5l-1.4-1.4z"/>
</svg>`;
const codeBlocks = document.querySelectorAll('pre.wp-block-code code');
codeBlocks.forEach(code => {
const pre = code.closest('pre.wp-block-code');
// Line numbering
const lines = code.textContent.split('\\n');
const newHTML = lines.map(line => {
const span = document.createElement('span');
span.textContent = line || '\\u00A0'; // visible empty lines
return span.outerHTML;
}).join('');
pre.classList.add('has-line-numbers');
code.innerHTML = newHTML;
// Copy button and tooltip
const button = document.createElement('button');
button.className = 'code-copy-btn';
button.type = 'button';
button.setAttribute('aria-label', 'Copy code to clipboard');
button.innerHTML = clipboardSVG;
const tooltip = document.createElement('span');
tooltip.className = 'code-copy-tooltip';
tooltip.innerText = 'Copied!';
pre.appendChild(button);
pre.appendChild(tooltip);
button.addEventListener('click', function () {
const rawText = Array.from(code.querySelectorAll('span')).map(span => span.textContent).join('\\n');
navigator.clipboard.writeText(rawText).then(function () {
button.innerHTML = checkmarkSVG;
tooltip.classList.add('show');
setTimeout(() => {
button.innerHTML = clipboardSVG;
tooltip.classList.remove('show');
}, 2000);
}).catch(function (err) {
console.error('Copy failed: ', err);
});
});
});
});
JS;
wp_add_inline_style( 'wp-block-library', $css );
wp_add_inline_script( 'jquery-core', $js );
}
add_action( 'wp_enqueue_scripts', 'ewdt_enhance_code_blocks_with_copy' );
some text
Regular paragraph.