portfolio / script.js
Redhanuman's picture
make an portfolio
7469cbf verified
// Mobile menu functionality
document.addEventListener('DOMContentLoaded', function() {
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
const mobileMenu = document.getElementById('mobile-menu');
if (mobileMenuBtn && mobileMenu) {
mobileMenuBtn.addEventListener('click', function() {
mobileMenu.classList.toggle('hidden');
// Change menu icon
const icon = mobileMenuBtn.querySelector('[data-feather]');
if (mobileMenu.classList.contains('hidden')) {
icon.setAttribute('data-feather', 'menu');
} else {
icon.setAttribute('data-feather', 'x');
}
feather.replace();
});
}
// Smooth scrolling for navigation links
const navLinks = document.querySelectorAll('a[href^="#"]');
navLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
const offsetTop = targetElement.offsetTop - 80; // Account for fixed navbar
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
// Close mobile menu if open
if (mobileMenu && !mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.add('hidden');
const icon = mobileMenuBtn.querySelector('[data-feather]');
icon.setAttribute('data-feather', 'menu');
feather.replace();
}
}
});
});
// Navbar background on scroll
const navbar = document.querySelector('nav');
window.addEventListener('scroll', function() {
if (window.scrollY > 50) {
navbar.classList.add('shadow-lg');
} else {
navbar.classList.remove('shadow-lg');
}
});
// Intersection Observer for fade-in animations
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');
}
});
}, observerOptions);
// Observe sections for animations
const sections = document.querySelectorAll('section');
sections.forEach(section => {
observer.observe(section);
});
// Add loading animation to images
const images = document.querySelectorAll('img');
images.forEach(img => {
img.addEventListener('load', function() {
this.style.opacity = '1';
});
});
// Typing effect for hero text (optional enhancement)
function typeWriter(element, text, speed = 100) {
let i = 0;
element.innerHTML = '';
function type() {
if (i < text.length) {
text.charAt(i element.innerHTML +=);
i++;
setTimeout(type, speed);
}
}
type();
}
// Contact form handling (if you add a form)
const contactForm = document.getElementById('contact-form');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this);
const data = Object.fromEntries(formData);
// Simulate form submission
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
submitBtn.textContent = 'Sending...';
submitBtn.disabled = true;
setTimeout(() => {
submitBtn.textContent = 'Message Sent!';
setTimeout(() => {
submitBtn.textContent = originalText;
submitBtn.disabled = false;
this.reset();
}, 2000);
}, 1000);
});
}
// Theme toggle functionality (if you want to add dark mode later)
function toggleTheme() {
document.body.classList.toggle('dark');
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light');
}
// Load saved theme
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark');
}
// Add keyboard navigation
document.addEventListener('keydown', function(e) {
// ESC key closes mobile menu
if (e.key === 'Escape' && mobileMenu && !mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.add('hidden');
const icon = mobileMenuBtn.querySelector('[data-feather]');
icon.setAttribute('data-feather', 'menu');
feather.replace();
}
});
// Add performance optimizations
// Lazy load images
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) = entry.target;
{
const img img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
const lazyImages = document.querySelectorAll('img[data-src]');
lazyImages.forEach(img => imageObserver.observe(img));
}
// Add error handling for images
images.forEach(img => {
img.addEventListener('error', function() {
this.style.display = 'none';
});
});
// Console message for developers
console.log('%c👋 Hi there! Thanks for checking out my portfolio.', 'color: #6366f1; font-size: 16px; font-weight: bold;');
console.log('%cIf you\'re interested in the code, feel free to reach out!', 'color: #4f46e5; font-size: 14px;');
});