Files
skycel 9180f116ec ✉️ Feature: Epic 5 - Formulaire de Contact (Stories 5.1-5.7)
- Formulaire HTML5 avec validation (nom, prénom, email, entreprise, catégorie, objet, message)
- Validation JavaScript côté client (FormValidator)
- Persistance localStorage des données (AppState)
- Intégration reCAPTCHA v3 avec dégradation gracieuse
- Traitement PHP sécurisé (CSRF, validation, envoi email)
- Feedback utilisateur AJAX (succès/erreur)
- Liens contact secondaires (LinkedIn, GitHub, Email protégé)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 01:43:13 +01:00

106 lines
2.8 KiB
JavaScript

// assets/js/main.js
// Script principal du portfolio
document.addEventListener('DOMContentLoaded', () => {
initMobileMenu();
initNavbarScroll();
initEmailProtection();
});
/**
* Gestion du menu mobile
*/
function initMobileMenu() {
const toggle = document.getElementById('mobile-menu-toggle');
const menu = document.getElementById('mobile-menu');
if (!toggle || !menu) return;
const hamburgerIcon = toggle.querySelector('.hamburger-icon');
const closeIcon = toggle.querySelector('.close-icon');
function openMenu() {
menu.classList.remove('hidden');
menu.setAttribute('aria-hidden', 'false');
toggle.setAttribute('aria-expanded', 'true');
toggle.setAttribute('aria-label', 'Fermer le menu');
hamburgerIcon?.classList.add('hidden');
closeIcon?.classList.remove('hidden');
}
function closeMenu() {
menu.classList.add('hidden');
menu.setAttribute('aria-hidden', 'true');
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('aria-label', 'Ouvrir le menu');
hamburgerIcon?.classList.remove('hidden');
closeIcon?.classList.add('hidden');
}
function toggleMenu() {
const isOpen = toggle.getAttribute('aria-expanded') === 'true';
if (isOpen) {
closeMenu();
} else {
openMenu();
}
}
// Toggle au clic
toggle.addEventListener('click', toggleMenu);
// Fermer au clic sur un lien
menu.querySelectorAll('a').forEach(link => {
link.addEventListener('click', closeMenu);
});
// Fermer avec Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && toggle.getAttribute('aria-expanded') === 'true') {
closeMenu();
toggle.focus();
}
});
// Fermer si on redimensionne vers desktop
window.addEventListener('resize', () => {
if (window.innerWidth >= 1024) {
closeMenu();
}
});
}
/**
* Effet d'ombre au scroll
*/
function initNavbarScroll() {
const navbar = document.getElementById('navbar');
if (!navbar) return;
window.addEventListener('scroll', () => {
if (window.scrollY > 10) {
navbar.classList.add('shadow-lg');
} else {
navbar.classList.remove('shadow-lg');
}
}, { passive: true });
}
/**
* Protection de l'email contre le scraping
* Reconstruit l'adresse email à partir de data-attributes
*/
function initEmailProtection() {
const emailLink = document.getElementById('email-link');
if (!emailLink) return;
const user = emailLink.dataset.user;
const domain = emailLink.dataset.domain;
if (user && domain) {
const email = `${user}@${domain}`;
emailLink.href = `mailto:${email}`;
emailLink.title = email;
}
}