Skip to content
theblackmad edited this page Aug 11, 2025 · 1 revision

// Navigation mobile document.addEventListener('DOMContentLoaded', function() { const navToggle = document.querySelector('.nav-toggle'); const navMenu = document.querySelector('.nav-menu'); const navLinks = document.querySelectorAll('.nav-link');

// Toggle menu mobile
navToggle.addEventListener('click', function() {
    navMenu.classList.toggle('active');
    navToggle.classList.toggle('active');
});

// Fermer le menu mobile quand on clique sur un lien
navLinks.forEach(link => {
    link.addEventListener('click', function() {
        navMenu.classList.remove('active');
        navToggle.classList.remove('active');
    });
});

// Fermer le menu mobile quand on clique en dehors
document.addEventListener('click', function(e) {
    if (!navToggle.contains(e.target) && !navMenu.contains(e.target)) {
        navMenu.classList.remove('active');
        navToggle.classList.remove('active');
    }
});

});

// Smooth scrolling pour les liens d'ancrage document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { const headerHeight = document.querySelector('.header').offsetHeight; const targetPosition = target.offsetTop - headerHeight - 20;

        window.scrollTo({
            top: targetPosition,
            behavior: 'smooth'
        });
    }
});

});

// Animation au scroll const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' };

const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions);

// Observer les éléments à animer document.querySelectorAll('.program-card, .stat-card, .step, .contact-item').forEach(el => { el.style.opacity = '0'; el.style.transform = 'translateY(30px)'; el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; observer.observe(el); });

// Header scroll effect window.addEventListener('scroll', function() { const header = document.querySelector('.header'); if (window.scrollY > 100) { header.style.background = 'rgba(255, 255, 255, 0.95)'; header.style.backdropFilter = 'blur(10px)'; } else { header.style.background = '#FFFFFF'; header.style.backdropFilter = 'none'; } });

// Formulaire de contact document.querySelector('.contact-form').addEventListener('submit', function(e) { e.preventDefault();

// Récupérer les données du formulaire
const formData = new FormData(this);
const data = Object.fromEntries(formData);

// Simulation d'envoi (remplacer par vraie logique d'envoi)
showNotification('Votre demande a été envoyée avec succès ! Nous vous contacterons bientôt.', 'success');

// Reset du formulaire
this.reset();

});

// Fonction pour afficher les notifications function showNotification(message, type = 'info') { // Créer l'élément notification const notification = document.createElement('div'); notification.className = notification notification-${type}; notification.innerHTML = <div class="notification-content"> <span class="notification-message">${message}</span> <button class="notification-close">&times;</button> </div>;

// Ajouter les styles
notification.style.cssText = `
    position: fixed;
    top: 100px;
    right: 20px;
    background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#007bff'};
    color: white;
    padding: 15px 20px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 10000;
    transform: translateX(100%);
    transition: transform 0.3s ease;
    max-width: 400px;
`;

// Ajouter au DOM
document.body.appendChild(notification);

// Animer l'entrée
setTimeout(() => {
    notification.style.transform = 'translateX(0)';
}, 100);

// Gérer la fermeture
const closeBtn = notification.querySelector('.notification-close');
closeBtn.addEventListener('click', () => {
    notification.style.transform = 'translateX(100%)';
    setTimeout(() => {
        document.body.removeChild(notification);
    }, 300);
});

// Auto-fermeture après 5 secondes
setTimeout(() => {
    if (document.body.contains(notification)) {
        notification.style.transform = 'translateX(100%)';
        setTimeout(() => {
            if (document.body.contains(notification)) {
                document.body.removeChild(notification);
            }
        }, 300);
    }
}, 5000);

}

// Animation des compteurs dans les stats function animateCounters() { const counters = document.querySelectorAll('.stat-number');

counters.forEach(counter => {
    const target = parseInt(counter.textContent.replace(/\D/g, ''));
    const suffix = counter.textContent.replace(/\d/g, '');
    let current = 0;
    const increment = target / 50;
    
    const updateCounter = () => {
        if (current < target) {
            current += increment;
            counter.textContent = Math.ceil(current) + suffix;
            requestAnimationFrame(updateCounter);
        } else {
            counter.textContent = target + suffix;
        }
    };
    
    // Observer pour déclencher l'animation quand visible
    const counterObserver = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                updateCounter();
                counterObserver.unobserve(entry.target);
            }
        });
    }, { threshold: 0.5 });
    
    counterObserver.observe(counter);
});

}

// Initialiser les animations des compteurs animateCounters();

// Parallax effect pour le hero window.addEventListener('scroll', function() { const scrolled = window.pageYOffset; const hero = document.querySelector('.hero'); const heroContent = document.querySelector('.hero-content');

if (hero && scrolled < hero.offsetHeight) {
    heroContent.style.transform = `translateY(${scrolled * 0.5}px)`;
}

});

// Lazy loading pour les images if ('IntersectionObserver' in window) { const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); });

document.querySelectorAll('img[data-src]').forEach(img => {
    imageObserver.observe(img);
});

}

// Gestion du focus pour l'accessibilité document.addEventListener('keydown', function(e) { if (e.key === 'Tab') { document.body.classList.add('keyboard-navigation'); } });

document.addEventListener('mousedown', function() { document.body.classList.remove('keyboard-navigation'); });

// Validation du formulaire en temps réel const formInputs = document.querySelectorAll('.contact-form input, .contact-form select, .contact-form textarea');

formInputs.forEach(input => { input.addEventListener('blur', function() { validateField(this); });

input.addEventListener('input', function() {
    if (this.classList.contains('error')) {
        validateField(this);
    }
});

});

function validateField(field) { const value = field.value.trim(); let isValid = true; let errorMessage = '';

// Validation selon le type de champ
switch (field.type) {
    case 'email':
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (value && !emailRegex.test(value)) {
            isValid = false;
            errorMessage = 'Veuillez entrer une adresse email valide';
        }
        break;
    case 'tel':
        const phoneRegex = /^[\d\s\-\+\(\)]+$/;
        if (value && !phoneRegex.test(value)) {
            isValid = false;
            errorMessage = 'Veuillez entrer un numéro de téléphone valide';
        }
        break;
    default:
        if (field.hasAttribute('required') && !value) {
            isValid = false;
            errorMessage = 'Ce champ est requis';
        }
}

// Appliquer les styles de validation
if (isValid) {
    field.classList.remove('error');
    field.classList.add('valid');
    removeErrorMessage(field);
} else {
    field.classList.remove('valid');
    field.classList.add('error');
    showErrorMessage(field, errorMessage);
}

return isValid;

}

function showErrorMessage(field, message) { removeErrorMessage(field);

const errorDiv = document.createElement('div');
errorDiv.className = 'field-error';
errorDiv.textContent = message;
errorDiv.style.cssText = `
    color: #dc3545;
    font-size: 0.875rem;
    margin-top: 5px;
    display: block;
`;

field.parentNode.appendChild(errorDiv);

}

function removeErrorMessage(field) { const existingError = field.parentNode.querySelector('.field-error'); if (existingError) { existingError.remove(); } }

// Ajouter les styles CSS pour la validation const validationStyles = document.createElement('style'); validationStyles.textContent = ` .form-group input.error, .form-group select.error, .form-group textarea.error { border-color: #dc3545; box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1); }

.form-group input.valid,
.form-group select.valid,
.form-group textarea.valid {
    border-color: #28a745;
    box-shadow: 0 0 0 3px rgba(40, 167, 69, 0.1);
}

.keyboard-navigation *:focus {
    outline: 2px solid #F4A261;
    outline-offset: 2px;
}

.notification-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.notification-close {
    background: none;
    border: none;
    color: white;
    font-size: 1.5rem;
    cursor: pointer;
    padding: 0;
    line-height: 1;
}

.notification-close:hover {
    opacity: 0.8;
}

`;

document.head.appendChild(validationStyles);

console.log('Site web CPPJP initialisé avec succès!');

Clone this wiki locally