ramonzaca's picture
Create a landing page for a Data & AI consulting firm called Deployr.
42c9fe2 verified
// Main JavaScript for Deployr Landing Page
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
initializeAnimations();
initializeScrollEffects();
initializeParallax();
initializeParticles();
initializeTypingEffect();
initializeCountUp();
initializeModalHandlers();
});
// Initialize animations
function initializeAnimations() {
// Intersection Observer for fade-in animations
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-fade-in-up');
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all service cards and sections
document.querySelectorAll('.service-card, section > div').forEach(el => {
observer.observe(el);
});
}
// Scroll effects
function initializeScrollEffects() {
let lastScrollY = window.scrollY;
let ticking = false;
function updateScrollEffects() {
const scrollY = window.scrollY;
const navbar = document.querySelector('nav');
// Navbar background on scroll
if (scrollY > 50) {
navbar.classList.add('bg-dark/95', 'backdrop-blur-lg', 'shadow-lg');
} else {
navbar.classList.remove('bg-dark/95', 'backdrop-blur-lg', 'shadow-lg');
}
lastScrollY = scrollY;
ticking = false;
}
function requestTick() {
if (!ticking) {
window.requestAnimationFrame(updateScrollEffects);
ticking = true;
}
}
window.addEventListener('scroll', requestTick);
}
// Parallax effect
function initializeParallax() {
const parallaxElements = document.querySelectorAll('[data-parallax]');
function updateParallax() {
const scrolled = window.pageYOffset;
parallaxElements.forEach(element => {
const speed = element.dataset.speed || 0.5;
const yPos = -(scrolled * speed);
element.style.transform = `translateY(${yPos}px)`;
});
}
window.addEventListener('scroll', updateParallax);
}
// Particle effects
function initializeParticles() {
const particleContainer = document.createElement('div');
particleContainer.className = 'fixed inset-0 pointer-events-none z-0';
document.body.appendChild(particleContainer);
for (let i = 0; i < 20; i++) {
setTimeout(() => {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 10 + 's';
particle.style.animationDuration = (10 + Math.random() * 10) + 's';
particleContainer.appendChild(particle);
}, i * 200);
}
}
// Typing effect
function initializeTypingEffect() {
const typingElement = document.querySelector('[data-typing]');
if (!typingElement) return;
const text = typingElement.getAttribute('data-typing');
let index = 0;
function type() {
if (index < text.length) {
typingElement.textContent += text.charAt(index);
index++;
setTimeout(type, 100);
}
}
type();
}
// Count up animation
function initializeCountUp() {
const countElements = document.querySelectorAll('[data-count]');
const countObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const target = parseInt(entry.target.getAttribute('data-count'));
const duration = 2000;
const increment = target / (duration / 16);
let current = 0;
const updateCount = () => {
if (current < target) {
current += increment;
entry.target.textContent = Math.floor(current);
requestAnimationFrame(updateCount);
} else {
entry.target.textContent = target;
}
};
updateCount();
countObserver.unobserve(entry.target);
}
});
});
countElements.forEach(el => countObserver.observe(el));
}
// Modal handlers
function initializeModalHandlers() {
// Open modal buttons
document.querySelectorAll('[data-modal]').forEach(button => {
button.addEventListener('click', () => {
const modalId = button.getAttribute('data-modal');
const modal = document.getElementById(modalId);
if (modal) {
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
});
});
// Close modal buttons
document.querySelectorAll('[data-close-modal]').forEach(button => {
button.addEventListener('click', () => {
const modal = button.closest('.modal');
if (modal) {
modal.classList.add('hidden');
document.body.style.overflow = 'auto';
}
});
});
// Close modal on backdrop click
document.querySelectorAll('.modal').forEach(modal => {
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.add('hidden');
document.body.style.overflow = 'auto';
}
});
});
}
// Smooth scroll for anchor links
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'
});
}
});
});
// Form validation
function validateForm(formId) {
const form = document.getElementById(formId);
if (!form) return false;
const inputs = form.querySelectorAll('input[required], textarea[required]');
let isValid = true;
inputs.forEach(input => {
if (!input.value.trim()) {
input.classList.add('border-red-500');
isValid = false;
} else {
input.classList.remove('border-red-500');
}
});
return isValid;
}
// Loading state for buttons
function setLoading(buttonId, loading = true) {
const button = document.getElementById(buttonId);
if (!button) return;
if (loading) {
button.disabled = true;
button.classList.add('opacity-50', 'cursor-not-allowed');
button.innerHTML = '<span class="loading-spinner inline-block mr-2"></span>Loading...';
} else {
button.disabled = false;
button.classList.remove('opacity-50', 'cursor-not-allowed');
button.innerHTML = button.getAttribute('data-original-text') || 'Submit';
}
}
// Toast notification
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg transform transition-all duration-300 z-50 ${
type === 'success' ? 'bg-green-500' : 'bg-red-500'
} text-white`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('translate-y-0', 'opacity-100');
}, 100);
setTimeout(() => {
toast.classList.add('translate-y-full', 'opacity-0');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// API call helper
async function apiCall(url, options = {}) {
try {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API call failed:', error);
showToast('An error occurred. Please try again.', 'error');
throw error;
}
}
// Initialize GSAP animations if available
if (typeof gsap !== 'undefined') {
gsap.registerPlugin(ScrollTrigger);
// Hero section animation
gsap.timeline()
.from('.hero h1', { y: 50, opacity: 0, duration: 1 })
.from('.hero p', { y: 30, opacity: 0, duration: 0.8 }, '-=0.5')
.from('.hero .cta', { y: 20, opacity: 0, duration: 0.6 }, '-=0.3');
}
// Theme toggle (if implemented)
function toggleTheme() {
document.body.classList.toggle('light-theme');
const isLight = document.body.classList.contains('light-theme');
localStorage.setItem('theme', isLight ? 'light' : 'dark');
}
// Load saved theme
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'light') {
document.body.classList.add('light-theme');
}
// Analytics tracking
function trackEvent(eventName, properties = {}) {
if (typeof gtag !== 'undefined') {
gtag('event', eventName, properties);
}
}
// Utility debouncing function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Optimized resize handler
const optimizedResize = debounce(() => {
// Handle resize events
}, 100);
window.addEventListener('resize', optimizedResize);
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const openModal = document.querySelector('.modal:not(.hidden)');
if (openModal) {
openModal.classList.add('hidden');
document.body.style.overflow = 'auto';
}
}
});
// Initialize tooltips
function initializeTooltips() {
document.querySelectorAll('[data-tooltip]').forEach(element => {
element.addEventListener('mouseenter', (e) => {
const tooltip = document.createElement('div');
tooltip.className = 'absolute z-50 px-2 py-1 text-xs bg-gray-800 text-white rounded';
tooltip.textContent = e.target.getAttribute('data-tooltip');
tooltip.style.bottom = '100%';
tooltip.style.left = '50%';
tooltip.style.transform = 'translateX(-50%)';
e.target.style.position = 'relative';
e.target.appendChild(tooltip);
});
element.addEventListener('mouseleave', (e) => {
const tooltip = e.target.querySelector('.absolute');
if (tooltip) tooltip.remove();
});
});
}
// Initialize everything
initializeTooltips();