75 lines
2 KiB
JavaScript
75 lines
2 KiB
JavaScript
// Theme toggle with localStorage
|
|
const themeToggle = document.getElementById('theme-toggle');
|
|
const html = document.documentElement;
|
|
const savedTheme = localStorage.getItem('theme');
|
|
|
|
function applyTheme(theme) {
|
|
if (theme === 'light') {
|
|
html.setAttribute('data-theme', 'light');
|
|
themeToggle.textContent = '☀';
|
|
themeToggle.setAttribute('aria-label', 'Switch to dark mode');
|
|
} else {
|
|
html.removeAttribute('data-theme');
|
|
themeToggle.textContent = '☾';
|
|
themeToggle.setAttribute('aria-label', 'Switch to light mode');
|
|
}
|
|
}
|
|
|
|
if (savedTheme) {
|
|
applyTheme(savedTheme);
|
|
}
|
|
|
|
themeToggle.addEventListener('click', () => {
|
|
const current = html.getAttribute('data-theme');
|
|
const next = current === 'light' ? 'dark' : 'light';
|
|
applyTheme(next);
|
|
localStorage.setItem('theme', next);
|
|
});
|
|
|
|
// Dynamic current year in footer
|
|
const yearSpan = document.getElementById('current-year');
|
|
if (yearSpan) {
|
|
yearSpan.textContent = new Date().getFullYear();
|
|
}
|
|
|
|
// Scroll reveal animation
|
|
const revealElements = document.querySelectorAll('section');
|
|
|
|
const revealObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry, index) => {
|
|
if (entry.isIntersecting) {
|
|
setTimeout(() => {
|
|
entry.target.classList.add('visible');
|
|
}, index * 80);
|
|
revealObserver.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, {
|
|
threshold: 0.15,
|
|
rootMargin: '0px 0px -40px 0px'
|
|
});
|
|
|
|
revealElements.forEach((el) => {
|
|
el.classList.add('reveal');
|
|
revealObserver.observe(el);
|
|
});
|
|
|
|
// Stagger cards inside directory preview
|
|
const cards = document.querySelectorAll('.card');
|
|
const cardObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry, index) => {
|
|
if (entry.isIntersecting) {
|
|
setTimeout(() => {
|
|
entry.target.classList.add('visible');
|
|
}, index * 120);
|
|
cardObserver.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, {
|
|
threshold: 0.2
|
|
});
|
|
|
|
cards.forEach((card) => {
|
|
card.classList.add('reveal');
|
|
cardObserver.observe(card);
|
|
});
|