41 lines
1.4 KiB
JavaScript
41 lines
1.4 KiB
JavaScript
/* ───────── js/common.js ───────── */
|
|
(() => {
|
|
function injectFragment(id, url) {
|
|
const el = document.getElementById(id);
|
|
if (!el) return;
|
|
fetch(url)
|
|
.then(r => r.text())
|
|
.then(html => { el.outerHTML = html; })
|
|
.catch(console.error);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Inject shared fragments if placeholders present
|
|
injectFragment('nav-placeholder', 'fragments/nav.html');
|
|
injectFragment('socials-placeholder', 'fragments/socials.html');
|
|
|
|
// Smooth scroll for same-page anchors
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', e => {
|
|
const targetId = anchor.getAttribute('href').slice(1);
|
|
const target = document.getElementById(targetId);
|
|
if (target) {
|
|
e.preventDefault();
|
|
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
});
|
|
});
|
|
|
|
// Lazy-load images & iframes
|
|
document.querySelectorAll('img, iframe').forEach(el => {
|
|
if (!el.hasAttribute('loading')) el.setAttribute('loading', 'lazy');
|
|
});
|
|
|
|
// Ensure nav links have aria-labels
|
|
document.querySelectorAll('header.nav nav a').forEach(link => {
|
|
if (!link.hasAttribute('aria-label')) {
|
|
link.setAttribute('aria-label', link.textContent.trim());
|
|
}
|
|
});
|
|
});
|
|
})();
|