SherlockRamos's picture
Redesign
d4e5829 verified
// Initialize animations and interactions
document.addEventListener('DOMContentLoaded', function() {
// Reveal animations on scroll
const reveals = document.querySelectorAll('.reveal');
function checkReveal() {
reveals.forEach(element => {
const windowHeight = window.innerHeight;
const elementTop = element.getBoundingClientRect().top;
const elementVisible = 150;
if (elementTop < windowHeight - elementVisible) {
element.classList.add('active');
}
});
}
window.addEventListener('scroll', checkReveal);
checkReveal();
// 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'
});
}
});
});
// Parallax effect
const parallaxElements = document.querySelectorAll('.parallax');
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
parallaxElements.forEach(element => {
const speed = element.dataset.speed || 0.5;
element.style.transform = `translateY(${scrolled * speed}px)`;
});
});
// Counter animation
const counters = document.querySelectorAll('[data-counter]');
const speed = 200;
const countUp = () => {
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-counter');
const count = +counter.innerText;
const inc = target / speed;
if (count < target) {
counter.innerText = Math.ceil(count + inc);
setTimeout(updateCount, 1);
} else {
counter.innerText = target;
}
};
updateCount();
});
};
// Trigger counter animation when in view
const observerOptions = {
threshold: 0.5
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
countUp();
observer.unobserve(entry.target);
}
});
}, observerOptions);
counters.forEach(counter => {
observer.observe(counter);
});
// Interactive hover effects
const cards = document.querySelectorAll('.card-hover');
cards.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) / 10;
const rotateY = (centerX - x) / 10;
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.05, 1.05, 1.05)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)';
});
});
// Form validation
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(form);
const data = Object.fromEntries(formData);
// Basic validation
let isValid = true;
const requiredFields = form.querySelectorAll('[required]');
requiredFields.forEach(field => {
if (!field.value.trim()) {
field.classList.add('border-red-500');
isValid = false;
} else {
field.classList.remove('border-red-500');
}
});
if (isValid) {
// Show success message
const successMessage = document.createElement('div');
successMessage.className = 'fixed top-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
successMessage.textContent = 'Form submitted successfully!';
document.body.appendChild(successMessage);
setTimeout(() => {
successMessage.remove();
}, 3000);
form.reset();
}
});
});
// Dynamic year in footer
const yearElements = document.querySelectorAll('[data-year]');
const currentYear = new Date().getFullYear();
yearElements.forEach(element => {
element.textContent = currentYear;
});
// Theme switcher
const themeToggle = document.querySelector('[data-theme-toggle]');
if (themeToggle) {
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark');
const isDark = document.body.classList.contains('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
// Load saved theme
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark');
}
}
});
// Utility functions
const utils = {
debounce: (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
throttle: (func, limit) => {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
},
animateValue: (element, start, end, duration) => {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
element.textContent = Math.floor(progress * (end - start) + start);
if (progress < 1) {
window.requestAnimationFrame(step);
}
};
window.requestAnimationFrame(step);
}
};
// Export utilities for use in components
window.utils = utils;