summaryrefslogtreecommitdiffstats
path: root/assets/js/code-copy.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/code-copy.js')
-rw-r--r--assets/js/code-copy.js79
1 files changed, 79 insertions, 0 deletions
diff --git a/assets/js/code-copy.js b/assets/js/code-copy.js
new file mode 100644
index 0000000..8591436
--- /dev/null
+++ b/assets/js/code-copy.js
@@ -0,0 +1,79 @@
+(function () {
+ var LANG_NAMES = {
+ bash: 'Shell', sh: 'Shell', shell: 'Shell', zsh: 'Shell',
+ js: 'JavaScript', javascript: 'JavaScript',
+ ts: 'TypeScript', typescript: 'TypeScript',
+ go: 'Go',
+ py: 'Python', python: 'Python',
+ rs: 'Rust', rust: 'Rust',
+ html: 'HTML',
+ css: 'CSS',
+ toml: 'TOML',
+ yaml: 'YAML', yml: 'YAML',
+ json: 'JSON',
+ sql: 'SQL',
+ md: 'Markdown', markdown: 'Markdown',
+ c: 'C',
+ cpp: 'C++', 'c++': 'C++',
+ java: 'Java',
+ php: 'PHP',
+ ruby: 'Ruby', rb: 'Ruby',
+ swift: 'Swift',
+ kotlin: 'Kotlin', kt: 'Kotlin',
+ dockerfile: 'Dockerfile',
+ makefile: 'Makefile',
+ text: 'Text', txt: 'Text',
+ };
+
+ function prettyName(lang) {
+ if (!lang) return '';
+ var key = lang.toLowerCase();
+ return LANG_NAMES[key] || (lang.charAt(0).toUpperCase() + lang.slice(1));
+ }
+
+ function getCodeText(wrapper) {
+ var el = wrapper.querySelector('.lntd:last-child code')
+ || wrapper.querySelector('.code-body code')
+ || wrapper.querySelector('.code-body pre');
+ return el ? el.innerText : '';
+ }
+
+ function initBlock(wrapper) {
+ var header = wrapper.querySelector('.code-header');
+ if (header) {
+ var label = wrapper.querySelector('.code-lang-label');
+ if (label) label.textContent = prettyName(header.getAttribute('data-lang') || '');
+ }
+
+ var btn = wrapper.querySelector('[data-copy-target]');
+ if (!btn) return;
+
+ btn.addEventListener('click', function () {
+ var text = getCodeText(wrapper);
+ if (!text) return;
+
+ navigator.clipboard.writeText(text).then(function () {
+ var copyIcon = btn.querySelector('.icon-copy');
+ var checkIcon = btn.querySelector('.icon-check');
+ var liveRegion = wrapper.querySelector('.code-copy-status');
+ if (copyIcon) copyIcon.classList.add('hidden');
+ if (checkIcon) checkIcon.classList.remove('hidden');
+ btn.classList.add('is-copied');
+ if (liveRegion) liveRegion.textContent = 'Code copied to clipboard.';
+
+ setTimeout(function () {
+ if (copyIcon) copyIcon.classList.remove('hidden');
+ if (checkIcon) checkIcon.classList.add('hidden');
+ btn.classList.remove('is-copied');
+ if (liveRegion) liveRegion.textContent = '';
+ }, 2000);
+ }).catch(function () {
+ // silent fail for insecure contexts
+ });
+ });
+ }
+
+ document.addEventListener('DOMContentLoaded', function () {
+ document.querySelectorAll('.code-block-wrapper').forEach(initBlock);
+ });
+})();