|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
feather.replace(); |
|
|
|
|
|
|
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => { |
|
|
anchor.addEventListener('click', function (e) { |
|
|
e.preventDefault(); |
|
|
const targetId = this.getAttribute('href'); |
|
|
if (targetId === '#') return; |
|
|
|
|
|
const targetElement = document.querySelector(targetId); |
|
|
if (targetElement) { |
|
|
window.scrollTo({ |
|
|
top: targetElement.offsetTop - 100, |
|
|
behavior: 'smooth' |
|
|
}); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const serviceCards = document.querySelectorAll('service-card'); |
|
|
serviceCards.forEach(card => { |
|
|
card.addEventListener('mouseenter', function() { |
|
|
this.style.transform = 'translateY(-8px)'; |
|
|
this.style.transition = 'transform 0.3s ease'; |
|
|
}); |
|
|
|
|
|
card.addEventListener('mouseleave', function() { |
|
|
this.style.transform = 'translateY(0)'; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const contactForm = document.querySelector('contact-form'); |
|
|
if (contactForm) { |
|
|
contactForm.addEventListener('submit', function(e) { |
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
|
const formData = new FormData(e.target); |
|
|
const data = Object.fromEntries(formData); |
|
|
|
|
|
|
|
|
const submitBtn = e.target.querySelector('button[type="submit"]'); |
|
|
const originalText = submitBtn.innerHTML; |
|
|
submitBtn.innerHTML = '<span class="loading-dots"><span></span><span></span><span></span></span>'; |
|
|
submitBtn.disabled = true; |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
e.target.reset(); |
|
|
|
|
|
|
|
|
showNotification('Message sent successfully! We\'ll get back to you soon.', 'success'); |
|
|
|
|
|
|
|
|
submitBtn.innerHTML = originalText; |
|
|
submitBtn.disabled = false; |
|
|
}, 2000); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const observerOptions = { |
|
|
threshold: 0.1, |
|
|
rootMargin: '0px 0px -50px 0px' |
|
|
}; |
|
|
|
|
|
const observer = new IntersectionObserver((entries) => { |
|
|
entries.forEach(entry => { |
|
|
if (entry.isIntersecting) { |
|
|
entry.target.classList.add('animate-float'); |
|
|
} |
|
|
}); |
|
|
}, observerOptions); |
|
|
|
|
|
|
|
|
const animatedElements = document.querySelectorAll('.service-card, .portfolio-card, .testimonial-card'); |
|
|
animatedElements.forEach(el => { |
|
|
observer.observe(el); |
|
|
}); |
|
|
|
|
|
|
|
|
const statsCounters = document.querySelectorAll('stats-counter'); |
|
|
statsCounters.forEach(counter => { |
|
|
observer.observe(counter); |
|
|
}); |
|
|
|
|
|
|
|
|
window.showNotification = function(message, type = 'success') { |
|
|
const notification = document.createElement('div'); |
|
|
notification.className = `fixed top-4 right-4 z-50 px-6 py-4 rounded-lg shadow-lg transform transition-all duration-300 translate-x-full ${type === 'success' ? 'bg-green-500' : 'bg-red-500'} text-white`; |
|
|
notification.textContent = message; |
|
|
document.body.appendChild(notification); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
notification.classList.remove('translate-x-full'); |
|
|
}, 10); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
notification.classList.add('translate-x-full'); |
|
|
setTimeout(() => { |
|
|
notification.remove(); |
|
|
}, 300); |
|
|
}, 5000); |
|
|
}; |
|
|
|
|
|
|
|
|
const mobileMenuBtn = document.querySelector('[data-mobile-menu-toggle]'); |
|
|
const mobileMenu = document.querySelector('[data-mobile-menu]'); |
|
|
|
|
|
if (mobileMenuBtn && mobileMenu) { |
|
|
mobileMenuBtn.addEventListener('click', () => { |
|
|
mobileMenu.classList.toggle('hidden'); |
|
|
mobileMenu.classList.toggle('flex'); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const darkModeToggle = document.querySelector('[data-dark-mode-toggle]'); |
|
|
if (darkModeToggle) { |
|
|
darkModeToggle.addEventListener('click', () => { |
|
|
document.documentElement.classList.toggle('dark'); |
|
|
localStorage.setItem('darkMode', document.documentElement.classList.contains('dark')); |
|
|
}); |
|
|
|
|
|
|
|
|
if (localStorage.getItem('darkMode') === 'true') { |
|
|
document.documentElement.classList.add('dark'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const lazyImages = document.querySelectorAll('img[data-src]'); |
|
|
const imageObserver = new IntersectionObserver((entries) => { |
|
|
entries.forEach(entry => { |
|
|
if (entry.isIntersecting) { |
|
|
const img = entry.target; |
|
|
img.src = img.dataset.src; |
|
|
img.classList.remove('opacity-0'); |
|
|
imageObserver.unobserve(img); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
lazyImages.forEach(img => { |
|
|
imageObserver.observe(img); |
|
|
img.classList.add('opacity-0', 'transition-opacity', 'duration-500'); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
function debounce(func, wait) { |
|
|
let timeout; |
|
|
return function executedFunction(...args) { |
|
|
const later = () => { |
|
|
clearTimeout(timeout); |
|
|
func(...args); |
|
|
}; |
|
|
clearTimeout(timeout); |
|
|
timeout = setTimeout(later, wait); |
|
|
}; |
|
|
} |
|
|
|
|
|
function throttle(func, limit) { |
|
|
let inThrottle; |
|
|
return function() { |
|
|
const args = arguments; |
|
|
const context = this; |
|
|
if (!inThrottle) { |
|
|
func.apply(context, args); |
|
|
inThrottle = true; |
|
|
setTimeout(() => inThrottle = false, limit); |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
async function fetchDesignInspiration() { |
|
|
try { |
|
|
const response = await fetch('https://api.unsplash.com/photos/random?query=web-design&count=3', { |
|
|
headers: { |
|
|
'Authorization': 'Client-ID YOUR_UNSPLASH_ACCESS_KEY' |
|
|
} |
|
|
}); |
|
|
const data = await response.json(); |
|
|
return data; |
|
|
} catch (error) { |
|
|
console.error('Error fetching design inspiration:', error); |
|
|
return []; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
window.PixelCraftUtils = { |
|
|
debounce, |
|
|
throttle, |
|
|
showNotification: window.showNotification |
|
|
}; |