EbrahemHesham's picture
https://www.toukoum.fr/
9f0cabe verified
Raw
History Blame Contribute Delete
9.82 kB
// Intersection Observer for scroll animations
document.addEventListener('DOMContentLoaded', function() {
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.classList.add('animate-fade-in');
}
});
}, observerOptions);
// Observe elements that should animate on scroll
const elementsToObserve = document.querySelectorAll('section');
elementsToObserve.forEach(el => {
observer.observe(el);
});
// Stat counter animation
const animateCounters = () => {
const counters = document.querySelectorAll('[data-count]');
counters.forEach(counter => {
const target = parseInt(counter.getAttribute('data-count'));
const duration = 2000;
const step = target / (duration / 16);
let current = 0;
const timer = setInterval(() => {
current += step;
if (current >= target) {
counter.textContent = target;
clearInterval(timer);
} else {
counter.textContent = Math.floor(current);
}
}, 16);
});
};
// Trigger counter animation when stats section is visible
const statsSection = document.querySelector('.grid');
if (statsSection) {
const statsObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
animateCounters();
statsObserver.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
statsObserver.observe(statsSection);
}
});
// Mobile menu toggle
function toggleMobileMenu() {
const mobileMenu = document.querySelector('.mobile-menu');
const overlay = document.querySelector('.overlay');
const hamburger = document.querySelector('.hamburger');
if (mobileMenu && overlay && hamburger) {
mobileMenu.classList.toggle('active');
overlay.classList.toggle('active');
hamburger.classList.toggle('active');
}
}
// Close mobile menu when clicking overlay
function closeMobileMenu() {
const mobileMenu = document.querySelector('.mobile-menu');
const overlay = document.querySelector('.overlay');
const hamburger = document.querySelector('.hamburger');
if (mobileMenu && overlay && hamburger) {
mobileMenu.classList.remove('active');
overlay.classList.remove('active');
hamburger.classList.remove('active');
}
}
// Work filtering functionality (for work page)
let selectedCategory = 'all';
function showCategory(category) {
selectedCategory = category;
// Update tab buttons
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(btn => {
if (btn.getAttribute('onclick').includes(category)) {
btn.classList.add('bg-gray-900', 'text-white');
btn.classList.remove('bg-gray-200', 'text-gray-700');
} else {
btn.classList.add('bg-gray-200', 'text-gray-700');
btn.classList.remove('bg-gray-900', 'text-white');
}
});
// Show/hide projects with animation
const tabContents = document.querySelectorAll('.tab-content');
tabContents.forEach(content => {
content.classList.remove('active');
});
const activeContent = document.querySelector(`.tab-content[data-category="${category}"]`);
if (activeContent) {
setTimeout(() => {
activeContent.classList.add('active');
}, 100);
}
}
// Project modal functionality (for work page)
function openProject(title) {
const modal = document.createElement('div');
modal.className = 'fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop';
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
modal.innerHTML = `
<div class="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto relative transform scale-95 transition-transform duration-300">
<button onclick="closeProject()" class="absolute top-4 right-4 z-10 w-10 h-10 bg-white rounded-full flex items-center justify-center hover:bg-gray-100 transition-colors">
<i data-feather="x" class="w-6 h-6"></i>
</button>
<img src="http://static.photos/640x360/42" alt="${title}" class="w-full h-auto">
<div class="p-8">
<h2 class="text-3xl font-light mb-4">${title}</h2>
<p class="text-gray-600 mb-6">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>
<div class="flex flex-wrap gap-2 mb-6">
<span class="px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm">Web Design</span>
<span class="px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm">Branding</span>
<span class="px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm">UI/UX</span>
</div>
<a href="contact.html" class="inline-flex items-center gap-2 px-6 py-3 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-all">
Start a Similar Project
<i data-feather="arrow-right" class="w-4 h-4"></i>
</a>
</div>
</div>
`;
document.body.appendChild(modal);
document.body.style.overflow = 'hidden';
// Animate in
setTimeout(() => {
modal.firstElementChild.style.transform = 'scale(1)';
}, 10);
// Re-render Feather icons
if (window.feather) {
feather.replace();
}
}
function closeProject() {
const modal = document.querySelector('.modal-backdrop');
if (modal) {
modal.firstElementChild.style.transform = 'scale(0.95)';
setTimeout(() => {
modal.remove();
document.body.style.overflow = '';
}, 300);
}
}
// Close modal when clicking outside
document.addEventListener('click', function(e) {
if (e.target.classList.contains('modal-backdrop')) {
closeProject();
}
});
// Form submission handler (for contact page)
function submitContactForm(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const submitBtn = form.querySelector('button[type="submit"]');
// Show loading state
const originalBtnText = submitBtn.innerHTML;
submitBtn.innerHTML = '<span class="loading-dots">Sending</span>';
submitBtn.disabled = true;
// Simulate form submission
setTimeout(() => {
// Success message
const successMessage = document.createElement('div');
successMessage.className = 'mb-6 p-4 bg-green-100 text-green-700 rounded-lg';
successMessage.innerHTML = `
<div class="flex items-center gap-3">
<i data-feather="check-circle" class="w-6 h-6"></i>
<span>Thank you for your message! We'll get back to you soon.</span>
</div>
`;
form.parentNode.insertBefore(successMessage, form);
form.reset();
// Reset button
submitBtn.innerHTML = originalBtnText;
submitBtn.disabled = false;
// Re-render Feather icons
if (window.feather) {
feather.replace();
}
// Remove success message after 5 seconds
setTimeout(() => {
successMessage.remove();
}, 5000);
}, 2000);
}
// Smooth scroll to top
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
// Parallax effect for hero section
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
const parallax = document.querySelector('.parallax-bg');
if (parallax && window.innerWidth > 768) {
const yPos = -(scrolled * 0.5);
parallax.style.transform = `translateY(${yPos}px)`;
}
});
// Add hover effect to project cards
document.addEventListener('DOMContentLoaded', () => {
const projectCards = document.querySelectorAll('.project-card');
projectCards.forEach(card => {
card.addEventListener('mouseenter', () => {
card.style.transform = 'translateY(-8px)';
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'translateY(0)';
});
});
});
// Lazy loading images
function lazyLoadImages() {
const images = document.querySelectorAll('img[loading="lazy"]');
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.src;
img.classList.remove('opacity-0');
img.classList.add('opacity-100');
observer.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
}
// Initialize lazy loading
lazyLoadImages();
// Keyboard navigation for accessibility
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeProject();
closeMobileMenu();
}
});