dodey917's picture
I want you to help to build the website
9f30756 verified
// Main JavaScript file for portfolio website
document.addEventListener('DOMContentLoaded', function() {
// Initialize all functionality
initMobileMenu();
initSmoothScrolling();
initScrollAnimations();
initFormHandling();
initScrollToTop();
initTypingEffect();
});
// Mobile menu functionality
function initMobileMenu() {
const mobileMenuButton = document.getElementById('mobile-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
if (mobileMenuButton && mobileMenu) {
mobileMenuButton.addEventListener('click', function() {
mobileMenu.classList.toggle('hidden');
// Toggle menu icon
const icon = mobileMenuButton.querySelector('i');
if (mobileMenu.classList.contains('hidden')) {
icon.setAttribute('data-feather', 'menu');
} else {
icon.setAttribute('data-feather', 'x');
}
feather.replace();
});
// Close mobile menu when clicking on a link
const mobileLinks = mobileMenu.querySelectorAll('a');
mobileLinks.forEach(link => {
link.addEventListener('click', function() {
mobileMenu.classList.add('hidden');
const icon = mobileMenuButton.querySelector('i');
icon.setAttribute('data-feather', 'menu');
feather.replace();
});
});
}
}
// Smooth scrolling for navigation links
function initSmoothScrolling() {
const navLinks = document.querySelectorAll('a[href^="#"]');
navLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
const navHeight = document.querySelector('nav').offsetHeight;
const targetPosition = targetSection.offsetTop - navHeight;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
}
// Scroll-triggered animations
function initScrollAnimations() {
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-fade-in-up');
entry.target.style.opacity = '1';
}
});
}, observerOptions);
// Observe elements for animation
const animateElements = document.querySelectorAll('.card-hover, .bg-white, section > div');
animateElements.forEach(el => {
el.style.opacity = '0';
observer.observe(el);
});
// Scroll-based navigation highlight
window.addEventListener('scroll', highlightActiveNav);
}
function highlightActiveNav() {
const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('nav a[href^="#"]');
const navHeight = document.querySelector('nav').offsetHeight;
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop - navHeight - 100;
const sectionHeight = section.offsetHeight;
if (window.pageYOffset >= sectionTop && window.pageYOffset < sectionTop + sectionHeight) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('text-primary-600', 'font-semibold');
link.classList.add('text-secondary-600');
if (link.getAttribute('href') === '#' + current) {
link.classList.remove('text-secondary-600');
link.classList.add('text-primary-600', 'font-semibold');
}
});
}
// Form handling
function initFormHandling() {
const contactForm = document.querySelector('form');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this);
const formObject = {};
formData.forEach((value, key) => {
formObject[key] = value;
});
// Show loading state
const submitButton = this.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
submitButton.textContent = 'Sending...';
submitButton.disabled = true;
// Simulate form submission (replace with actual API call)
setTimeout(() => {
// Show success message
showNotification('Message sent successfully!', 'success');
// Reset form
this.reset();
// Reset button
submitButton.textContent = originalText;
submitButton.disabled = false;
}, 2000);
});
}
}
// Notification system
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed top-20 right-4 z-50 px-6 py-3 rounded-lg shadow-lg transform translate-x-full transition-transform duration-300 ${
type === 'success' ? 'bg-green-500 text-white' :
type === 'error' ? 'bg-red-500 text-white' :
'bg-blue-500 text-white'
}`;
notification.textContent = message;
document.body.appendChild(notification);
// Slide in
setTimeout(() => {
notification.classList.remove('translate-x-full');
}, 100);
// Slide out and remove
setTimeout(() => {
notification.classList.add('translate-x-full');
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 4000);
}
// Scroll to top button
function initScrollToTop() {
// Create scroll to top button
const scrollButton = document.createElement('button');
scrollButton.innerHTML = '<i data-feather="arrow-up"></i>';
scrollButton.className = 'fixed bottom-6 right-6 w-12 h-12 bg-primary-600 text-white rounded-full shadow-lg hover:bg-primary-700 transition-colors duration-300 opacity-0 transform translate-y-full z-50';
scrollButton.style.display = 'none';
document.body.appendChild(scrollButton);
feather.replace();
// Show/hide based on scroll position
window.addEventListener('scroll', function() {
if (window.pageYOffset > 300) {
scrollButton.style.display = 'block';
setTimeout(() => {
scrollButton.classList.remove('opacity-0', 'translate-y-full');
}, 10);
} else {
scrollButton.classList.add('opacity-0', 'translate-y-full');
setTimeout(() => {
scrollButton.style.display = 'none';
}, 300);
}
});
// Scroll to top functionality
scrollButton.addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
}
// Typing effect for hero section
function initTypingEffect() {
const heroTitle = document.querySelector('#home h1');
if (heroTitle) {
const text = heroTitle.textContent;
heroTitle.textContent = '';
heroTitle.style.borderRight = '2px solid white';
let i = 0;
const typeWriter = () => {
if (i < text.length) {
heroTitle.textContent += text.charAt(i);
i++;
setTimeout(typeWriter, 100);
} else {
// Remove cursor after typing is complete
setTimeout(() => {
heroTitle.style.borderRight = 'none';
}, 1000);
}
};
// Start typing effect after a short delay
setTimeout(typeWriter, 1000);
}
}
// Parallax effect for hero section
window.addEventListener('scroll', function() {
const scrolled = window.pageYOffset;
const heroSection = document.querySelector('#home');
if (heroSection) {
const rate = scrolled * -0.5;
heroSection.style.transform = `translateY(${rate}px)`;
}
});
// Counter animation
function animateCounters() {
const counters = document.querySelectorAll('[data-count]');
counters.forEach(counter => {
const target = parseInt(counter.getAttribute('data-count'));
const increment = target / 100;
let current = 0;
const timer = setInterval(() => {
current += increment;
counter.textContent = Math.floor(current);
if (current >= target) {
counter.textContent = target;
clearInterval(timer);
}
}, 20);
});
}
// Initialize counter animation when about section is visible
const aboutSection = document.querySelector('#about');
if (aboutSection) {
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
animateCounters();
observer.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
observer.observe(aboutSection);
}
// Portfolio filter functionality (if needed)
function initPortfolioFilter() {
const filterButtons = document.querySelectorAll('[data-filter]');
const portfolioItems = document.querySelectorAll('[data-category]');
filterButtons.forEach(button => {
button.addEventListener('click', function() {
const filter = this.getAttribute('data-filter');
// Update active button
filterButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
// Filter portfolio items
portfolioItems.forEach(item => {
if (filter === 'all' || item.getAttribute('data-category') === filter) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
});
}
// Theme switcher (for future dark mode implementation)
function initThemeSwitcher() {
const themeToggle = document.getElementById('theme-toggle');
if (themeToggle) {
themeToggle.addEventListener('click', function() {
document.body.classList.toggle('dark-theme');
// Save theme preference
const isDark = document.body.classList.contains('dark-theme');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
// Update toggle icon
const icon = this.querySelector('i');
if (isDark) {
icon.setAttribute('data-feather', 'sun');
} else {
icon.setAttribute('data-feather', 'moon');
}
feather.replace();
});
// Load saved theme preference
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark-theme');
}
}
}
// Performance optimization
function optimizePerformance() {
// Lazy load images
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
// Debounce scroll events
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Apply debouncing to scroll events
const debouncedScroll = debounce(() => {
// Scroll-dependent operations
}, 10);
window.addEventListener('scroll', debouncedScroll);
}
// Initialize performance optimizations
optimizePerformance();