agahi
Version:
Client-side engine that renders Markdown files as a docs site in the browser—no build step.
103 lines (81 loc) • 3.66 kB
JavaScript
(function () {
'use strict';
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = ".copy-code {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--text-color);\n background-color: var(--background-hover);\n border: 1px solid var(--border-color);\n border-radius: 0.25rem;\n cursor: pointer;\n opacity: 0;\n transition: all 0.2s ease;\n z-index: 1;\n}\n\n/* Show on hover (desktop) */\n\n@media (hover: hover) {\n pre:hover .copy-code {\n opacity: 1;\n }\n}\n\n/* Always show on mobile */\n\n@media (hover: none) and (pointer: coarse) {\n .copy-code {\n opacity: 1;\n }\n}\n\n.copy-code:active,\n.copy-code:focus {\n outline: none;\n color: #fff;\n}\n\n.copy-code:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n";
styleInject(css_248z);
/**
* copy-code Plugin
* This plugin adds a "Copy Code" button to code blocks in the article.
* When clicked, it copies the code to the clipboard and shows a confirmation message.
* It uses MutationObserver to detect dynamically added code blocks.
*/
document.addEventListener('agahi:ready', () => {
const article = document.getElementById('md');
if (!article) {
throw new Error(
'Article element with id="md" not found. Copy code plugin cannot initialize.',
);
}
/**
* Adds a "Copy" button to a given code block and attaches the copy logic.
* @param {HTMLElement} codeBlock - The <code> element to which the button should be added.
*/
const addCopyButton = (codeBlock) => {
const pre = codeBlock.parentElement;
// Ensure the parent is a <pre> tag and that a copy button doesn't already exist.
if (!pre || pre.tagName !== 'PRE' || pre.querySelector('.copy-code')) {
return;
}
const copyButton = document.createElement('button');
copyButton.className = 'copy-code';
copyButton.textContent = 'Copy';
copyButton.onclick = () => {
navigator.clipboard
.writeText(codeBlock.textContent)
.then(() => {
copyButton.textContent = 'Copied!';
setTimeout(() => (copyButton.textContent = 'Copy'), 1500);
})
.catch((err) => {
console.error('Failed to copy using navigator.clipboard:', err);
});
};
pre.appendChild(copyButton);
};
article.querySelectorAll('pre > code').forEach(addCopyButton);
const observer = new MutationObserver((mutations) => {
for (const { addedNodes } of mutations) {
for (const node of addedNodes) {
if (node.nodeType !== 1) continue;
const codes =
node.tagName === 'CODE' && node.parentElement?.tagName === 'PRE'
? [node]
: node.querySelectorAll?.('pre > code') || [];
codes.forEach(addCopyButton);
}
}
});
observer.observe(article, { childList: true, subtree: true });
});
})();