131 lines
4.6 KiB
JavaScript
131 lines
4.6 KiB
JavaScript
/**
|
|
* Portfolio Alexandre — Scripts JS
|
|
* Filtres dynamiques, navigation mobile, lightbox
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
// ─── Navigation mobile ─────────────────────────────────────────────────
|
|
const navToggle = document.getElementById('navToggle');
|
|
const navLinks = document.querySelector('.nav-links');
|
|
|
|
if (navToggle && navLinks) {
|
|
navToggle.addEventListener('click', () => {
|
|
navLinks.classList.toggle('open');
|
|
});
|
|
// Fermer le menu au clic sur un lien
|
|
navLinks.querySelectorAll('.nav-link').forEach(link => {
|
|
link.addEventListener('click', () => navLinks.classList.remove('open'));
|
|
});
|
|
}
|
|
|
|
// ─── Filtres dynamiques (page projets) ────────────────────────────────
|
|
const filterPills = document.querySelectorAll('.filter-pill:not(.pill-more)');
|
|
|
|
filterPills.forEach(pill => {
|
|
pill.addEventListener('click', () => {
|
|
const filterType = pill.dataset.filter; // 'category' ou 'tech'
|
|
const filterValue = pill.dataset.value;
|
|
|
|
// Mettre à jour l'input hidden correspondant
|
|
const inputId = filterType === 'category' ? 'categoryInput' : 'techInput';
|
|
const hiddenInput = document.getElementById(inputId);
|
|
if (hiddenInput) {
|
|
hiddenInput.value = filterValue;
|
|
}
|
|
|
|
// Mettre à jour l'apparence des pills du même groupe
|
|
const group = pill.closest('.filter-pills');
|
|
if (group) {
|
|
group.querySelectorAll('.filter-pill').forEach(p => p.classList.remove('active'));
|
|
pill.classList.add('active');
|
|
}
|
|
|
|
// Soumettre le formulaire automatiquement
|
|
const form = document.getElementById('filtersForm');
|
|
if (form) form.submit();
|
|
});
|
|
});
|
|
|
|
// ─── Smooth scroll pour ancres internes ───────────────────────────────
|
|
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();
|
|
const navHeight = parseInt(
|
|
getComputedStyle(document.documentElement).getPropertyValue('--nav-height')
|
|
) || 68;
|
|
const top = target.getBoundingClientRect().top + window.scrollY - navHeight - 16;
|
|
window.scrollTo({ top, behavior: 'smooth' });
|
|
}
|
|
});
|
|
});
|
|
|
|
// ─── Animation d'apparition des cartes ────────────────────────────────
|
|
const cards = document.querySelectorAll('.project-card');
|
|
|
|
if ('IntersectionObserver' in window) {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry, i) => {
|
|
if (entry.isIntersecting) {
|
|
setTimeout(() => {
|
|
entry.target.style.opacity = '1';
|
|
entry.target.style.transform = 'translateY(0)';
|
|
}, i * 80);
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
cards.forEach(card => {
|
|
card.style.opacity = '0';
|
|
card.style.transform = 'translateY(20px)';
|
|
card.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
|
|
observer.observe(card);
|
|
});
|
|
}
|
|
|
|
// ─── Navbar : réduire au scroll ───────────────────────────────────────
|
|
const navbar = document.querySelector('.navbar');
|
|
let lastScrollY = window.scrollY;
|
|
|
|
window.addEventListener('scroll', () => {
|
|
if (window.scrollY > 80) {
|
|
navbar?.classList.add('scrolled');
|
|
} else {
|
|
navbar?.classList.remove('scrolled');
|
|
}
|
|
lastScrollY = window.scrollY;
|
|
}, { passive: true });
|
|
|
|
});
|
|
|
|
// ─── Lightbox (fonctions globales appelées depuis HTML) ──────────────────
|
|
function openLightbox(src) {
|
|
const lightbox = document.getElementById('lightbox');
|
|
const lightboxImg = document.getElementById('lightboxImg');
|
|
if (lightbox && lightboxImg) {
|
|
lightboxImg.src = src;
|
|
lightbox.classList.add('open');
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
|
|
function closeLightbox() {
|
|
const lightbox = document.getElementById('lightbox');
|
|
if (lightbox) {
|
|
lightbox.classList.remove('open');
|
|
document.body.style.overflow = '';
|
|
}
|
|
}
|
|
|
|
// Fermer la lightbox avec Échap
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') closeLightbox();
|
|
});
|