shoelace/docs/assets/scripts/docs.js

246 wiersze
6.6 KiB
JavaScript
Czysty Zwykły widok Historia

2023-06-06 12:22:18 +00:00
//
// Sidebar
//
// When the sidebar is hidden, we apply the inert attribute to prevent focus from reaching it. Due to the many states
// the sidebar can have (e.g. static, hidden, expanded), we test for visibility by checking to see if it's placed
// offscreen or not. Then, on resize/transition we make sure to update the attribute accordingly.
//
(() => {
2023-06-08 16:02:24 +00:00
function getSidebar() {
return document.getElementById('sidebar');
}
2023-06-06 12:22:18 +00:00
function isSidebarOpen() {
return document.documentElement.classList.contains('sidebar-open');
}
function isSidebarVisible() {
2023-06-08 16:02:24 +00:00
return getSidebar().getBoundingClientRect().x >= 0;
2023-06-06 12:22:18 +00:00
}
function toggleSidebar(force) {
const isOpen = typeof force === 'boolean' ? force : !isSidebarOpen();
return document.documentElement.classList.toggle('sidebar-open', isOpen);
}
function updateInert() {
2023-06-08 16:02:24 +00:00
getSidebar().inert = !isSidebarVisible();
2023-06-06 12:22:18 +00:00
}
// Toggle the menu
2023-06-08 16:02:24 +00:00
document.addEventListener('click', event => {
const menuToggle = event.target.closest('#menu-toggle');
console.log(event.target, menuToggle);
if (!menuToggle) return;
toggleSidebar();
});
2023-06-06 12:22:18 +00:00
// Update the sidebar's inert state when the window resizes and when the sidebar transitions
window.addEventListener('resize', () => toggleSidebar(false));
2023-06-08 16:02:24 +00:00
document.addEventListener('transitionend', event => {
const sidebar = event.target.closest('#sidebar');
if (!sidebar) return;
updateInert();
});
// Close when a menu item is selected on mobile
document.addEventListener('click', event => {
const sidebar = event.target.closest('#sidebar');
const link = event.target.closest('a');
if (!sidebar || !link) return;
if (isSidebarOpen()) {
toggleSidebar();
}
});
2023-06-06 12:22:18 +00:00
// Close when open and escape is pressed
document.addEventListener('keydown', event => {
if (event.key === 'Escape' && isSidebarOpen()) {
event.stopImmediatePropagation();
toggleSidebar();
}
});
// Close when clicking outside of the sidebar
document.addEventListener('mousedown', event => {
2023-06-07 21:23:57 +00:00
if (isSidebarOpen() & !event.target?.closest('#sidebar, #menu-toggle')) {
2023-06-06 12:22:18 +00:00
event.stopImmediatePropagation();
toggleSidebar();
}
});
updateInert();
})();
//
// Theme switcher
//
(() => {
function toggleTheme() {
const isDark = !document.documentElement.classList.contains('sl-theme-dark');
document.documentElement.classList.toggle('sl-theme-dark', isDark);
localStorage.setItem('theme', isDark ? 'dark' : 'light');
}
// Toggle the theme
2023-06-08 16:02:24 +00:00
document.addEventListener('click', event => {
const themeToggle = event.target.closest('#theme-toggle');
if (!themeToggle) return;
toggleTheme();
});
2023-06-06 12:22:18 +00:00
// Toggle with backslash
document.addEventListener('keydown', event => {
if (
event.key === '\\' &&
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
) {
event.preventDefault();
toggleTheme();
}
});
})();
//
// Open details when printing
//
(() => {
const detailsOpenOnPrint = new Set();
window.addEventListener('beforeprint', () => {
detailsOpenOnPrint.clear();
document.querySelectorAll('details').forEach(details => {
if (details.open) {
detailsOpenOnPrint.add(details);
}
details.open = true;
});
});
window.addEventListener('afterprint', () => {
document.querySelectorAll('details').forEach(details => {
details.open = detailsOpenOnPrint.has(details);
});
detailsOpenOnPrint.clear();
});
})();
//
// Copy code buttons
//
(() => {
document.addEventListener('click', event => {
const button = event.target.closest('.copy-code-button');
const pre = button?.closest('pre');
const code = pre?.querySelector('code');
const copyIcon = button?.querySelector('.copy-code-button__copy-icon');
const copiedIcon = button?.querySelector('.copy-code-button__copied-icon');
if (button && code) {
navigator.clipboard.writeText(code.innerText);
copyIcon.style.display = 'none';
copiedIcon.style.display = 'inline';
button.classList.add('copy-code-button--copied');
setTimeout(() => {
copyIcon.style.display = 'inline';
copiedIcon.style.display = 'none';
button.classList.remove('copy-code-button--copied');
}, 1000);
}
});
})();
//
// Smooth links
//
(() => {
document.addEventListener('click', event => {
const link = event.target.closest('a');
const id = (link?.hash ?? '').substr(1);
const isFragment = link?.hasAttribute('href') && link?.getAttribute('href').startsWith('#');
if (!link || !isFragment || link.getAttribute('data-smooth-link') === 'false') {
return;
}
// Scroll to the top
if (link.hash === '') {
event.preventDefault();
window.scroll({ top: 0, behavior: 'smooth' });
history.pushState(undefined, undefined, location.pathname);
}
// Scroll to an id
if (id) {
const target = document.getElementById(id);
if (target) {
event.preventDefault();
window.scroll({ top: target.offsetTop, behavior: 'smooth' });
history.pushState(undefined, undefined, `#${id}`);
}
}
});
})();
//
// Table of Contents scrollspy
//
(() => {
2023-06-08 16:15:02 +00:00
// This will be stale if its not a function.
const getLinks = () => [...document.querySelectorAll('.content__toc a')];
2023-06-06 12:22:18 +00:00
const linkTargets = new WeakMap();
const visibleTargets = new WeakSet();
const observer = new IntersectionObserver(handleIntersect, { rootMargin: '0px 0px' });
let debounce;
function handleIntersect(entries) {
entries.forEach(entry => {
// Remember which targets are visible
if (entry.isIntersecting) {
visibleTargets.add(entry.target);
} else {
visibleTargets.delete(entry.target);
}
});
updateActiveLinks();
}
function updateActiveLinks() {
2023-06-08 19:24:56 +00:00
const links = getLinks();
2023-06-06 12:22:18 +00:00
// Find the first visible target and activate the respective link
links.find(link => {
const target = linkTargets.get(link);
if (target && visibleTargets.has(target)) {
links.forEach(el => el.classList.toggle('active', el === link));
return true;
}
return false;
});
}
// Observe link targets
2023-06-08 19:24:56 +00:00
function observeLinks() {
2023-06-08 16:15:02 +00:00
getLinks().forEach(link => {
const hash = link.hash.slice(1);
const target = hash ? document.querySelector(`.content__body #${hash}`) : null;
2023-06-06 12:22:18 +00:00
2023-06-08 16:15:02 +00:00
if (target) {
linkTargets.set(link, target);
observer.observe(target);
}
});
}
2023-06-08 19:24:56 +00:00
observeLinks();
2023-06-08 16:15:02 +00:00
2023-06-08 19:24:56 +00:00
document.addEventListener('turbo:load', updateActiveLinks);
document.addEventListener('turbo:load', observeLinks);
2023-06-06 12:22:18 +00:00
})();