2025-11-05 17:32:17 +04:00
|
|
|
// Smooth scrolling
|
|
|
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
|
|
|
anchor.addEventListener('click', function (e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
|
|
|
if (target) {
|
|
|
|
|
target.scrollIntoView({
|
|
|
|
|
behavior: 'smooth',
|
|
|
|
|
block: 'start'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Mobile menu toggle
|
|
|
|
|
const menuToggle = document.querySelector('.menu-toggle');
|
|
|
|
|
const navLinks = document.querySelector('.nav-links');
|
|
|
|
|
let menuOpen = false;
|
|
|
|
|
|
|
|
|
|
menuToggle?.addEventListener('click', () => {
|
|
|
|
|
menuOpen = !menuOpen;
|
|
|
|
|
if (menuOpen) {
|
|
|
|
|
navLinks.style.display = 'flex';
|
|
|
|
|
navLinks.style.position = 'absolute';
|
|
|
|
|
navLinks.style.top = '100%';
|
|
|
|
|
navLinks.style.left = '0';
|
|
|
|
|
navLinks.style.right = '0';
|
|
|
|
|
navLinks.style.background = 'rgba(0, 0, 0, 0.98)';
|
|
|
|
|
navLinks.style.flexDirection = 'column';
|
|
|
|
|
navLinks.style.padding = '1rem';
|
|
|
|
|
navLinks.style.borderTop = '2px solid #E8A625';
|
|
|
|
|
|
|
|
|
|
// Animate menu toggle
|
|
|
|
|
menuToggle.children[0].style.transform = 'rotate(45deg) translateY(8px)';
|
|
|
|
|
menuToggle.children[1].style.opacity = '0';
|
|
|
|
|
menuToggle.children[2].style.transform = 'rotate(-45deg) translateY(-8px)';
|
|
|
|
|
} else {
|
|
|
|
|
navLinks.style.display = 'none';
|
|
|
|
|
|
|
|
|
|
// Reset menu toggle
|
|
|
|
|
menuToggle.children[0].style.transform = '';
|
|
|
|
|
menuToggle.children[1].style.opacity = '1';
|
|
|
|
|
menuToggle.children[2].style.transform = '';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Close mobile menu when clicking outside
|
|
|
|
|
document.addEventListener('click', (e) => {
|
|
|
|
|
if (menuOpen && !menuToggle.contains(e.target) && !navLinks.contains(e.target)) {
|
|
|
|
|
menuOpen = false;
|
|
|
|
|
navLinks.style.display = 'none';
|
|
|
|
|
menuToggle.children[0].style.transform = '';
|
|
|
|
|
menuToggle.children[1].style.opacity = '1';
|
|
|
|
|
menuToggle.children[2].style.transform = '';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Scroll animations
|
|
|
|
|
const observerOptions = {
|
2025-11-05 17:56:25 +04:00
|
|
|
threshold: 0.15,
|
|
|
|
|
rootMargin: '0px 0px -50px 0px'
|
2025-11-05 17:32:17 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
|
|
|
entries.forEach(entry => {
|
|
|
|
|
if (entry.isIntersecting) {
|
2025-11-05 17:56:25 +04:00
|
|
|
entry.target.classList.add('animate-in');
|
2025-11-05 17:32:17 +04:00
|
|
|
observer.unobserve(entry.target);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}, observerOptions);
|
|
|
|
|
|
|
|
|
|
// Observe all cards
|
2025-11-05 17:56:25 +04:00
|
|
|
document.querySelectorAll('.service-card, .project-card, .value-card, .partner-card').forEach(el => {
|
|
|
|
|
el.classList.add('fade-in-element');
|
2025-11-05 17:32:17 +04:00
|
|
|
observer.observe(el);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Navbar scroll effect
|
|
|
|
|
let lastScroll = 0;
|
|
|
|
|
const nav = document.querySelector('nav');
|
|
|
|
|
|
|
|
|
|
window.addEventListener('scroll', () => {
|
|
|
|
|
const currentScroll = window.pageYOffset;
|
|
|
|
|
|
|
|
|
|
if (currentScroll > 100) {
|
|
|
|
|
nav.style.background = 'rgba(0, 0, 0, 0.98)';
|
|
|
|
|
nav.style.boxShadow = '0 2px 20px rgba(232, 166, 37, 0.3)';
|
|
|
|
|
} else {
|
|
|
|
|
nav.style.background = 'rgba(0, 0, 0, 0.95)';
|
|
|
|
|
nav.style.boxShadow = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hide/show navbar on scroll
|
|
|
|
|
if (currentScroll > lastScroll && currentScroll > 500) {
|
|
|
|
|
nav.style.transform = 'translateY(-100%)';
|
|
|
|
|
} else {
|
|
|
|
|
nav.style.transform = 'translateY(0)';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastScroll = currentScroll;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Network animation enhancement
|
|
|
|
|
function createNetworkLine() {
|
|
|
|
|
const nodes = document.querySelectorAll('.node');
|
|
|
|
|
const networkBg = document.querySelector('.network-bg');
|
|
|
|
|
|
|
|
|
|
if (nodes.length > 1 && networkBg) {
|
|
|
|
|
for (let i = 0; i < nodes.length - 1; i++) {
|
|
|
|
|
const line = document.createElement('div');
|
|
|
|
|
line.style.position = 'absolute';
|
|
|
|
|
line.style.height = '1px';
|
|
|
|
|
line.style.background = 'linear-gradient(90deg, transparent, #E8A625, transparent)';
|
|
|
|
|
line.style.opacity = '0.2';
|
|
|
|
|
line.style.animation = `pulse 4s infinite ${i * 0.5}s`;
|
|
|
|
|
|
|
|
|
|
const node1 = nodes[i];
|
|
|
|
|
const node2 = nodes[i + 1];
|
|
|
|
|
|
|
|
|
|
// Calculate line position and angle
|
|
|
|
|
const x1 = parseFloat(node1.style.left);
|
|
|
|
|
const y1 = parseFloat(node1.style.top);
|
|
|
|
|
const x2 = parseFloat(node2.style.left);
|
|
|
|
|
const y2 = parseFloat(node2.style.top);
|
|
|
|
|
|
|
|
|
|
const distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
|
|
|
|
const angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
|
|
|
|
|
|
|
|
|
|
line.style.width = distance + '%';
|
|
|
|
|
line.style.left = x1 + '%';
|
|
|
|
|
line.style.top = y1 + '%';
|
|
|
|
|
line.style.transform = `rotate(${angle}deg)`;
|
|
|
|
|
line.style.transformOrigin = '0 0';
|
|
|
|
|
|
|
|
|
|
networkBg.appendChild(line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize network lines
|
|
|
|
|
createNetworkLine();
|
|
|
|
|
|
|
|
|
|
// Dynamic typing effect for hero subtitle
|
|
|
|
|
const subtitle = document.querySelector('.hero-subtitle');
|
|
|
|
|
if (subtitle) {
|
|
|
|
|
const text = subtitle.textContent;
|
|
|
|
|
subtitle.textContent = '';
|
|
|
|
|
let index = 0;
|
|
|
|
|
|
|
|
|
|
function typeWriter() {
|
|
|
|
|
if (index < text.length) {
|
|
|
|
|
subtitle.textContent += text.charAt(index);
|
|
|
|
|
index++;
|
|
|
|
|
setTimeout(typeWriter, 100);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setTimeout(typeWriter, 800);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add hover effect to project cards with tilt
|
|
|
|
|
document.querySelectorAll('.project-card, .service-card').forEach(card => {
|
|
|
|
|
card.addEventListener('mousemove', (e) => {
|
|
|
|
|
const rect = card.getBoundingClientRect();
|
|
|
|
|
const x = e.clientX - rect.left;
|
|
|
|
|
const y = e.clientY - rect.top;
|
|
|
|
|
|
|
|
|
|
const centerX = rect.width / 2;
|
|
|
|
|
const centerY = rect.height / 2;
|
|
|
|
|
|
|
|
|
|
const rotateX = (y - centerY) / 20;
|
|
|
|
|
const rotateY = (centerX - x) / 20;
|
|
|
|
|
|
|
|
|
|
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(-5px)`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
card.addEventListener('mouseleave', () => {
|
|
|
|
|
card.style.transform = '';
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Easter egg: Konami code
|
|
|
|
|
const konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];
|
|
|
|
|
let konamiIndex = 0;
|
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
|
|
|
if (e.key === konamiCode[konamiIndex]) {
|
|
|
|
|
konamiIndex++;
|
|
|
|
|
if (konamiIndex === konamiCode.length) {
|
|
|
|
|
document.body.style.animation = 'pulse 1s';
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
alert('🎮 Félicitations! Vous avez trouvé le code secret! Bienvenue dans la résistance numérique!');
|
|
|
|
|
document.body.style.animation = '';
|
|
|
|
|
}, 1000);
|
|
|
|
|
konamiIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
konamiIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Progressive enhancement: Add loading states
|
|
|
|
|
// Disabled - not needed for external links
|
|
|
|
|
// document.querySelectorAll('.service-link, .project-card').forEach(link => {
|
|
|
|
|
// link.addEventListener('click', function(e) {
|
|
|
|
|
// if (this.href && this.href !== '#') {
|
|
|
|
|
// this.style.opacity = '0.6';
|
|
|
|
|
// this.innerHTML += ' ⌛';
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// Custom donation handler
|
|
|
|
|
function handleCustomDonation(type) {
|
|
|
|
|
const input = document.getElementById(type === 'oneTime' ? 'customAmountOneTime' : 'customAmountMonthly');
|
|
|
|
|
const amount = input.value;
|
|
|
|
|
|
|
|
|
|
if (!amount || amount < 1) {
|
|
|
|
|
alert('Veuillez entrer un montant valide');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Redirect to custom amount Stripe URL
|
|
|
|
|
const stripeUrl = type === 'oneTime'
|
|
|
|
|
? 'https://don.o-k-i.net/b/6oE2aO94P88X9u8eV4' // Custom one-time donation
|
|
|
|
|
: 'https://don.o-k-i.net/b/6oE2aO94P88X9u8eV4'; // Uses same link for custom amounts
|
|
|
|
|
|
|
|
|
|
window.location.href = stripeUrl;
|
|
|
|
|
}
|