52 lines
1.9 KiB
JavaScript
52 lines
1.9 KiB
JavaScript
// ─── Scroll reveal ─────────────────────────────────────────
|
|
const reveals = document.querySelectorAll('.reveal');
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(e => {
|
|
if (e.isIntersecting) {
|
|
e.target.classList.add('visible');
|
|
observer.unobserve(e.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
|
|
reveals.forEach(el => observer.observe(el));
|
|
|
|
// ─── Active nav link on scroll ──────────────────────────────
|
|
const sections = document.querySelectorAll('section[id]');
|
|
const navLinks = document.querySelectorAll('.nav-links a');
|
|
window.addEventListener('scroll', () => {
|
|
let current = '';
|
|
sections.forEach(s => {
|
|
if (window.scrollY >= s.offsetTop - 120) current = s.id;
|
|
});
|
|
navLinks.forEach(a => {
|
|
a.style.color = a.getAttribute('href') === `#${current}` ? 'var(--mauve)' : '';
|
|
});
|
|
});
|
|
|
|
// ─── Project filters ──────────────────────────────────────────────
|
|
const filterChips = document.querySelectorAll('.filter-chip');
|
|
const projectCards = document.querySelectorAll('#project-grid .project-card');
|
|
|
|
if (filterChips.length > 0 && projectCards.length > 0) {
|
|
const applyFilter = (filter) => {
|
|
projectCards.forEach(card => {
|
|
const tech = (card.dataset.tech || '').split(/\s+/).filter(Boolean);
|
|
const shouldShow = filter === 'all' || tech.includes(filter);
|
|
card.classList.toggle('is-hidden', !shouldShow);
|
|
});
|
|
};
|
|
|
|
filterChips.forEach(chip => {
|
|
chip.addEventListener('click', () => {
|
|
const selected = chip.dataset.filter || 'all';
|
|
|
|
filterChips.forEach(other => {
|
|
other.classList.toggle('active', other === chip);
|
|
});
|
|
|
|
applyFilter(selected);
|
|
});
|
|
});
|
|
}
|
|
|