diff options
Diffstat (limited to '_shared/docs.js')
| -rw-r--r-- | _shared/docs.js | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/_shared/docs.js b/_shared/docs.js new file mode 100644 index 0000000..7e07310 --- /dev/null +++ b/_shared/docs.js @@ -0,0 +1,85 @@ +/* panto docs — progressive enhancement only. + The site is fully functional with this file absent or JS disabled: + every nav item is a real link, all content is in the HTML. This adds + the mobile sidebar toggle, code copy buttons, and TOC scroll-spy. */ +(function () { + 'use strict'; + + /* ---- Mobile sidebar toggle ---------------------------------------- */ + var menuBtn = document.querySelector('[data-menu-toggle]'); + var sidebar = document.querySelector('.pd-sidebar'); + var scrim = document.querySelector('.pd-scrim'); + function closeMenu() { + if (sidebar) sidebar.classList.remove('pd-sidebar--open'); + } + if (menuBtn && sidebar) { + menuBtn.addEventListener('click', function () { + sidebar.classList.toggle('pd-sidebar--open'); + }); + } + if (scrim) scrim.addEventListener('click', closeMenu); + if (sidebar) { + sidebar.addEventListener('click', function (e) { + if (e.target.closest('a')) closeMenu(); + }); + } + + /* ---- Code copy buttons -------------------------------------------- */ + document.querySelectorAll('.pg-code__copy').forEach(function (btn) { + btn.addEventListener('click', function () { + var block = btn.closest('.pg-code'); + var pre = block && block.querySelector('pre'); + if (!pre) return; + var text = pre.innerText; + var done = function () { + btn.classList.add('pg-code__copy--done'); + var label = btn.querySelector('.pg-code__label'); + if (label) label.textContent = 'Copied'; + setTimeout(function () { + btn.classList.remove('pg-code__copy--done'); + if (label) label.textContent = 'Copy'; + }, 1400); + }; + if (navigator.clipboard) navigator.clipboard.writeText(text).then(done, done); + else done(); + }); + }); + + /* ---- Scroll-spy: highlight the active section in TOC + sidebar ---- */ + var tocLinks = Array.prototype.slice.call(document.querySelectorAll('.pd-toc__link')); + var sideLinks = Array.prototype.slice.call( + document.querySelectorAll('.pd-navsec--current .pd-navsec__link') + ); + if (!tocLinks.length || !('IntersectionObserver' in window)) return; + + var ids = tocLinks.map(function (a) { + var href = a.getAttribute('href') || ''; + return href.charAt(0) === '#' ? href.slice(1) : href.split('#')[1]; + }).filter(Boolean); + + function setActive(id) { + tocLinks.forEach(function (a) { + var h = a.getAttribute('href') || ''; + a.classList.toggle('pd-toc__link--active', h === '#' + id); + }); + sideLinks.forEach(function (a) { + var h = a.getAttribute('href') || ''; + a.classList.toggle('pd-navsec__link--active', h.split('#')[1] === id); + }); + } + + var visible = new Set(); + var obs = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (e.isIntersecting) visible.add(e.target.id); + else visible.delete(e.target.id); + }); + var first = ids.find(function (id) { return visible.has(id); }); + if (first) setActive(first); + }, { rootMargin: '-72px 0px -68% 0px', threshold: 0 }); + + ids.forEach(function (id) { + var el = document.getElementById(id); + if (el) obs.observe(el); + }); +})(); |
