feat: add copy code button functionality to code blocks in show page
This commit is contained in:
@@ -1,7 +1,137 @@
|
||||
<div class="mx-auto container pt-12 sm:pt-16 lg:pt-20 px-6 sm:px-8 lg:px-12">
|
||||
<div class="bg-background-secondary hover:bg-background-secondary/80 border border-neutral p-8 rounded-lg">
|
||||
<article class="prose dark:prose-invert mb-2 max-w-full">
|
||||
<article class="prose dark:prose-invert mb-2 max-w-full" id="page-content">
|
||||
{!! \Illuminate\Support\Str::markdown($page->content) !!}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.code-block-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-code-button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
padding: 6px 12px;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.copy-code-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.copy-code-button.copied {
|
||||
background-color: rgba(34, 197, 94, 0.8);
|
||||
border-color: rgba(34, 197, 94, 1);
|
||||
}
|
||||
|
||||
.dark .copy-code-button {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dark .copy-code-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.dark .copy-code-button.copied {
|
||||
background-color: rgba(34, 197, 94, 0.3);
|
||||
border-color: rgba(34, 197, 94, 0.6);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Find all code blocks within pre tags
|
||||
const codeBlocks = document.querySelectorAll('#page-content pre');
|
||||
|
||||
codeBlocks.forEach((preBlock) => {
|
||||
// Create wrapper if not already wrapped
|
||||
if (!preBlock.parentElement.classList.contains('code-block-wrapper')) {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'code-block-wrapper';
|
||||
preBlock.parentNode.insertBefore(wrapper, preBlock);
|
||||
wrapper.appendChild(preBlock);
|
||||
}
|
||||
|
||||
const wrapper = preBlock.parentElement;
|
||||
|
||||
// Create copy button
|
||||
const copyButton = document.createElement('button');
|
||||
copyButton.className = 'copy-code-button';
|
||||
copyButton.innerHTML = `
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
</svg>
|
||||
<span class="button-text">Copy</span>
|
||||
`;
|
||||
|
||||
copyButton.addEventListener('click', async function() {
|
||||
// Get the code content
|
||||
const codeElement = preBlock.querySelector('code') || preBlock;
|
||||
const code = codeElement.textContent;
|
||||
|
||||
try {
|
||||
// Copy to clipboard
|
||||
await navigator.clipboard.writeText(code);
|
||||
|
||||
// Update button to show success
|
||||
copyButton.classList.add('copied');
|
||||
copyButton.innerHTML = `
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="20 6 9 17 4 12"></polyline>
|
||||
</svg>
|
||||
<span class="button-text">Copied!</span>
|
||||
`;
|
||||
|
||||
// Reset button after 2 seconds
|
||||
setTimeout(() => {
|
||||
copyButton.classList.remove('copied');
|
||||
copyButton.innerHTML = `
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
</svg>
|
||||
<span class="button-text">Copy</span>
|
||||
`;
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy code:', err);
|
||||
const buttonText = copyButton.querySelector('.button-text');
|
||||
buttonText.textContent = 'Failed';
|
||||
|
||||
setTimeout(() => {
|
||||
copyButton.innerHTML = `
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
</svg>
|
||||
<span class="button-text">Copy</span>
|
||||
`;
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
// Add button to wrapper
|
||||
wrapper.appendChild(copyButton);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user