MAALOUFimad02/Machine_Learning_Training
0
1/* ═══════════════════════════════════════════════════════════════════════════2 ML ACADEMY — SHARED JAVASCRIPT3 Animations et interactions communes à toutes les pages4 ═══════════════════════════════════════════════════════════════════════════ */5 6// ═══════════════════════════════════════════════════════════════════════════7// NAVIGATION ACTIVE STATE8// ═══════════════════════════════════════════════════════════════════════════9document.addEventListener('DOMContentLoaded', () => {10 // Mark active nav link based on current page11 const currentPage = window.location.pathname.split('/').pop() || 'index.html';12 13 document.querySelectorAll('.nav-link').forEach(link => {14 const href = link.getAttribute('href');15 if (href === currentPage || (currentPage === '' && href === 'index.html')) {16 link.classList.add('active');17 } else {18 link.classList.remove('active');19 }20 });21});22 23// ═══════════════════════════════════════════════════════════════════════════24// SMOOTH SCROLL FOR ANCHOR LINKS25// ═══════════════════════════════════════════════════════════════════════════26document.querySelectorAll('a[href^="#"]').forEach(anchor => {27 anchor.addEventListener('click', function(e) {28 e.preventDefault();29 const target = document.querySelector(this.getAttribute('href'));30 if (target) {31 const offsetTop = target.offsetTop - 100; // Account for fixed navbar32 window.scrollTo({33 top: offsetTop,34 behavior: 'smooth'35 });36 }37 });38});39 40// ═══════════════════════════════════════════════════════════════════════════41// SCROLL ANIMATIONS OBSERVER42// ═══════════════════════════════════════════════════════════════════════════43const scrollObserverOptions = {44 root: null,45 rootMargin: '0px 0px -100px 0px',46 threshold: 0.147};48 49const scrollObserver = new IntersectionObserver((entries) => {50 entries.forEach(entry => {51 if (entry.isIntersecting) {52 entry.target.classList.add('visible');53 54 // Add stagger delay for child elements if needed55 const staggerChildren = entry.target.querySelectorAll('.stagger-child');56 staggerChildren.forEach((child, index) => {57 child.style.animationDelay = `${index * 0.1}s`;58 child.classList.add('animate-in');59 });60 }61 });62}, scrollObserverOptions);63 64// Observe all elements with scroll-animate class65document.querySelectorAll('.scroll-animate').forEach(el => {66 scrollObserver.observe(el);67});68 69// ═══════════════════════════════════════════════════════════════════════════70// NAVBAR SCROLL EFFECT71// ═══════════════════════════════════════════════════════════════════════════72let lastScrollY = window.scrollY;73let ticking = false;74 75function updateNavbar() {76 const navbar = document.querySelector('.navbar');77 78 if (window.scrollY > 50) {79 navbar.style.background = 'rgba(15, 15, 26, 0.95)';80 navbar.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';81 } else {82 navbar.style.background = 'rgba(15, 15, 26, 0.85)';83 navbar.style.boxShadow = 'none';84 }85 86 ticking = false;87}88 89window.addEventListener('scroll', () => {90 lastScrollY = window.scrollY;91 92 if (!ticking) {93 window.requestAnimationFrame(updateNavbar);94 ticking = true;95 }96});97 98// ═══════════════════════════════════════════════════════════════════════════99// PARALLAX EFFECT FOR HERO BACKGROUND100// ═══════════════════════════════════════════════════════════════════════════101const heroBg = document.querySelector('.hero-bg');102if (heroBg) {103 window.addEventListener('scroll', () => {104 const scrolled = window.scrollY;105 heroBg.style.transform = `translateY(${scrolled * 0.3}px)`;106 });107}108 109// ═══════════════════════════════════════════════════════════════════════════110// TYPING EFFECT FOR HERO TEXT (optional)111// ═══════════════════════════════════════════════════════════════════════════112function typeWriter(element, text, speed = 50) {113 let i = 0;114 element.textContent = '';115 116 function type() {117 if (i < text.length) {118 element.textContent += text.charAt(i);119 i++;120 setTimeout(type, speed);121 }122 }123 124 type();125}126 127// ═══════════════════════════════════════════════════════════════════════════128// COUNTER ANIMATION FOR STATS129// ═══════════════════════════════════════════════════════════════════════════130function animateCounter(element, target, duration = 2000) {131 let start = 0;132 const increment = target / (duration / 16);133 134 function updateCounter() {135 start += increment;136 if (start < target) {137 element.textContent = Math.floor(start);138 requestAnimationFrame(updateCounter);139 } else {140 element.textContent = target;141 }142 }143 144 updateCounter();145}146 147// Observe stat elements and animate when visible148const statObserver = new IntersectionObserver((entries) => {149 entries.forEach(entry => {150 if (entry.isIntersecting && !entry.target.classList.contains('counted')) {151 entry.target.classList.add('counted');152 const target = parseInt(entry.target.dataset.target);153 if (!isNaN(target)) {154 animateCounter(entry.target, target);155 }156 }157 });158}, { threshold: 0.5 });159 160document.querySelectorAll('[data-target]').forEach(el => {161 statObserver.observe(el);162});163 164// ═══════════════════════════════════════════════════════════════════════════165// MAGNETIC BUTTON EFFECT166// ═══════════════════════════════════════════════════════════════════════════167document.querySelectorAll('.btn').forEach(button => {168 button.addEventListener('mousemove', (e) => {169 const rect = button.getBoundingClientRect();170 const x = e.clientX - rect.left - rect.width / 2;171 const y = e.clientY - rect.top - rect.height / 2;172 173 button.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px)`;174 });175 176 button.addEventListener('mouseleave', () => {177 button.style.transform = '';178 });179});180 181// ═══════════════════════════════════════════════════════════════════════════182// CARD HOVER 3D EFFECT183// ═══════════════════════════════════════════════════════════════════════════184document.querySelectorAll('.card, .feature-card, .module-card').forEach(card => {185 card.addEventListener('mousemove', (e) => {186 const rect = card.getBoundingClientRect();187 const x = e.clientX - rect.left;188 const y = e.clientY - rect.top;189 190 const centerX = rect.width / 2;191 const centerY = rect.height / 2;192 193 const rotateX = (y - centerY) / 20;194 const rotateY = (centerX - x) / 20;195 196 card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateZ(10px)`;197 });198 199 card.addEventListener('mouseleave', () => {200 card.style.transform = '';201 });202});203 204// ═══════════════════════════════════════════════════════════════════════════205// GLITCH EFFECT FOR TEXT (optional)206// ═══════════════════════════════════════════════════════════════════════════207function glitchText(element, originalText) {208 const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';209 let iterations = 0;210 211 const interval = setInterval(() => {212 element.textContent = originalText213 .split('')214 .map((char, index) => {215 if (index < iterations) {216 return originalText[index];217 }218 return chars[Math.floor(Math.random() * chars.length)];219 })220 .join('');221 222 if (iterations >= originalText.length) {223 clearInterval(interval);224 }225 226 iterations += 1 / 3;227 }, 30);228}229 230// ═══════════════════════════════════════════════════════════════════════════231// PARTICLE MOUSE INTERACTION232// ═══════════════════════════════════════════════════════════════════════════233const particlesContainer = document.querySelector('.particles-container');234if (particlesContainer) {235 document.addEventListener('mousemove', (e) => {236 const particles = particlesContainer.querySelectorAll('.particle');237 const mouseX = e.clientX / window.innerWidth;238 const mouseY = e.clientY / window.innerHeight;239 240 particles.forEach((particle, index) => {241 const speed = (index + 1) * 0.5;242 const x = (mouseX - 0.5) * speed * 20;243 const y = (mouseY - 0.5) * speed * 20;244 245 particle.style.transform = `translate(${x}px, ${y}px)`;246 });247 });248}249 250// ═══════════════════════════════════════════════════════════════════════════251// LOADING ANIMATION252// ═══════════════════════════════════════════════════════════════════════════253window.addEventListener('load', () => {254 document.body.classList.add('loaded');255 256 // Animate elements with delay257 document.querySelectorAll('[data-delay]').forEach(el => {258 const delay = parseInt(el.dataset.delay);259 setTimeout(() => {260 el.classList.add('animate-in');261 }, delay);262 });263});264 265// ═══════════════════════════════════════════════════════════════════════════266// FORM VALIDATION HELPERS267// ═══════════════════════════════════════════════════════════════════════════268function validateEmail(email) {269 const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;270 return re.test(email);271}272 273function validateRequired(value) {274 return value.trim().length > 0;275}276 277// ═══════════════════════════════════════════════════════════════════════════278// TOOLTIP SYSTEM279// ═══════════════════════════════════════════════════════════════════════════280function createTooltip(element, text) {281 const tooltip = document.createElement('div');282 tooltip.className = 'tooltip';283 tooltip.textContent = text;284 tooltip.style.cssText = `285 position: absolute;286 background: var(--bg-tertiary);287 color: var(--text-primary);288 padding: 8px 12px;289 border-radius: 6px;290 font-size: 0.8rem;291 white-space: nowrap;292 z-index: 1000;293 opacity: 0;294 transition: opacity 0.3s ease;295 pointer-events: none;296 `;297 298 document.body.appendChild(tooltip);299 300 element.addEventListener('mouseenter', () => {301 const rect = element.getBoundingClientRect();302 tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`;303 tooltip.style.top = `${rect.top - tooltip.offsetHeight - 8}px`;304 tooltip.style.opacity = '1';305 });306 307 element.addEventListener('mouseleave', () => {308 tooltip.style.opacity = '0';309 });310}311 312// ═══════════════════════════════════════════════════════════════════════════313// COPY TO CLIPBOARD314// ═══════════════════════════════════════════════════════════════════════════315async function copyToClipboard(text) {316 try {317 await navigator.clipboard.writeText(text);318 showNotification('Copié dans le presse-papier !', 'success');319 } catch (err) {320 showNotification('Erreur lors de la copie', 'error');321 }322}323 324// ═══════════════════════════════════════════════════════════════════════════325// NOTIFICATION SYSTEM326// ═══════════════════════════════════════════════════════════════════════════327function showNotification(message, type = 'info') {328 const notification = document.createElement('div');329 notification.className = `notification notification-${type}`;330 notification.textContent = message;331 notification.style.cssText = `332 position: fixed;333 top: 80px;334 right: 20px;335 padding: 12px 24px;336 background: var(--bg-card);337 border: 1px solid var(--border-color);338 border-radius: 8px;339 font-size: 0.9rem;340 z-index: 10000;341 animation: slideInRight 0.3s ease;342 `;343 344 if (type === 'success') {345 notification.style.borderColor = 'var(--success)';346 notification.style.color = 'var(--success)';347 } else if (type === 'error') {348 notification.style.borderColor = 'var(--danger)';349 notification.style.color = 'var(--danger)';350 }351 352 document.body.appendChild(notification);353 354 setTimeout(() => {355 notification.style.animation = 'slideOutRight 0.3s ease';356 setTimeout(() => notification.remove(), 300);357 }, 3000);358}359 360// ═══════════════════════════════════════════════════════════════════════════361// KEYBOARD SHORTCUTS362// ═══════════════════════════════════════════════════════════════════════════363document.addEventListener('keydown', (e) => {364 // Ctrl/Cmd + K for search (if implemented)365 if ((e.ctrlKey || e.metaKey) && e.key === 'k') {366 e.preventDefault();367 // Open search modal368 }369 370 // Escape to close modals371 if (e.key === 'Escape') {372 document.querySelectorAll('.modal.open').forEach(modal => {373 modal.classList.remove('open');374 });375 }376});377 378// ═══════════════════════════════════════════════════════════════════════════379// PREFERS REDUCED MOTION380// ═══════════════════════════════════════════════════════════════════════════381const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');382 383if (prefersReducedMotion.matches) {384 document.documentElement.style.setProperty('--transition-fast', '0s');385 document.documentElement.style.setProperty('--transition-base', '0s');386 document.documentElement.style.setProperty('--transition-slow', '0s');387}388 389// ═══════════════════════════════════════════════════════════════════════════390// CONSOLE EASTER EGG391// ═══════════════════════════════════════════════════════════════════════════392console.log('%c🧠 ML Academy', 'font-size: 24px; font-weight: bold; color: #6366f1;');393console.log('%cFormation Machine Learning — GE-MCI 4A', 'font-size: 14px; color: #94a3b8;');394console.log('%cBienvenue dans la console ! Curieux de voir comment ça marche ?', 'font-size: 12px; color: #64748b;');395 