secutorpro's picture
🐳 19/06 - 15:34 - uneliore et acyive en reel
de09ad3 verified
Raw
History Blame Contribute Delete
5.56 kB
// Intersection Observer for fade-in animations
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('opacity-100', 'translate-y-0');
entry.target.classList.remove('opacity-0', 'translate-y-10');
}
});
}, observerOptions);
// Observe all cards and sections
document.addEventListener('DOMContentLoaded', () => {
const elements = document.querySelectorAll('section > div, .group');
elements.forEach((el, index) => {
el.classList.add('transition-all', 'duration-700', 'opacity-0', 'translate-y-10');
el.style.transitionDelay = `${index * 50}ms`;
observer.observe(el);
});
// Form handling with real-time validation
const form = document.querySelector('form');
if (form) {
// Real-time input validation styling
const inputs = form.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
input.addEventListener('focus', () => {
input.parentElement.classList.add('focused');
});
input.addEventListener('blur', () => {
input.parentElement.classList.remove('focused');
if (input.value.trim()) {
input.classList.add('field-valid');
input.classList.remove('field-invalid');
} else if (input.hasAttribute('required')) {
input.classList.add('field-invalid');
input.classList.remove('field-valid');
}
});
// Live character feedback
input.addEventListener('input', () => {
if (input.tagName === 'TEXTAREA') {
const remaining = 500 - input.value.length;
let counter = input.parentElement.querySelector('.char-counter');
if (!counter) {
counter = document.createElement('div');
counter.className = 'char-counter text-xs font-mono text-slate-500 text-right mt-1';
input.parentElement.appendChild(counter);
}
counter.textContent = `${remaining} caractères restants`;
counter.style.color = remaining < 50 ? '#f59e0b' : remaining < 0 ? '#ef4444' : '#64748b';
}
});
});
form.addEventListener('submit', (e) => {
e.preventDefault();
const btn = form.querySelector('button[type="submit"]');
const originalText = btn.innerText;
const originalClasses = btn.className;
btn.innerHTML = '<span class="inline-flex items-center gap-2"><svg class="animate-spin h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg> ENVOI EN COURS...</span>';
btn.disabled = true;
btn.style.opacity = '0.8';
setTimeout(() => {
btn.innerHTML = '✓ DEMANDE ENVOYÉE';
btn.className = btn.className.replace('from-primary', 'from-green-500').replace('to-cyan-600', 'to-green-600');
btn.style.opacity = '1';
// Success feedback on form
form.style.transition = 'all 0.3s ease';
form.style.boxShadow = '0 0 30px rgba(34, 197, 94, 0.2)';
setTimeout(() => { form.style.boxShadow = ''; }, 2000);
setTimeout(() => {
form.reset();
inputs.forEach(input => {
input.classList.remove('field-valid', 'field-invalid');
});
// Remove char counters
form.querySelectorAll('.char-counter').forEach(c => c.remove());
btn.textContent = originalText;
btn.disabled = false;
btn.className = originalClasses;
}, 3000);
}, 1500);
});
}
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const target = document.querySelector(targetId);
if (target) {
const navHeight = 80;
const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - navHeight;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
// Parallax effect on hero section
const heroSection = document.querySelector('section');
if (heroSection) {
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
const bgElements = heroSection.querySelectorAll('.absolute');
bgElements.forEach((el, i) => {
const speed = 0.1 + (i * 0.05);
el.style.transform = `translateY(${scrolled * speed}px)`;
});
}, { passive: true });
}
});