Deploy from Lumerel

This commit is contained in:
Lumerel Deploy
2026-02-17 03:21:33 +00:00
commit b04a0a515b
5 changed files with 1551 additions and 0 deletions

231
script.js Normal file
View File

@@ -0,0 +1,231 @@
// Mobile Menu Toggle
const mobileToggle = document.getElementById('mobileToggle');
const navMenu = document.getElementById('navMenu');
mobileToggle.addEventListener('click', () => {
navMenu.classList.toggle('active');
// Animate hamburger to X
const spans = mobileToggle.querySelectorAll('span');
if (navMenu.classList.contains('active')) {
spans[0].style.transform = 'rotate(45deg) translate(5px, 5px)';
spans[1].style.opacity = '0';
spans[2].style.transform = 'rotate(-45deg) translate(7px, -6px)';
} else {
spans[0].style.transform = 'none';
spans[1].style.opacity = '1';
spans[2].style.transform = 'none';
}
});
// Close mobile menu when clicking on a link
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('click', () => {
navMenu.classList.remove('active');
const spans = mobileToggle.querySelectorAll('span');
spans[0].style.transform = 'none';
spans[1].style.opacity = '1';
spans[2].style.transform = 'none';
});
});
// Navbar scroll effect
const nav = document.getElementById('nav');
let lastScroll = 0;
window.addEventListener('scroll', () => {
const currentScroll = window.pageYOffset;
if (currentScroll > 50) {
nav.classList.add('scrolled');
} else {
nav.classList.remove('scrolled');
}
lastScroll = currentScroll;
});
// 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) {
const offsetTop = target.offsetTop - 80;
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}
});
});
// Animate on Scroll (AOS) implementation
function initAOS() {
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('aos-animate');
}
});
}, observerOptions);
// Observe all elements with data-aos attribute
document.querySelectorAll('[data-aos]').forEach(element => {
observer.observe(element);
});
}
// Initialize AOS when DOM is loaded
document.addEventListener('DOMContentLoaded', initAOS);
// Animate skill bars when they come into view
const skillObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const progressBars = entry.target.querySelectorAll('.skill-progress');
progressBars.forEach(bar => {
const width = bar.style.width;
bar.style.width = '0';
setTimeout(() => {
bar.style.width = width;
}, 100);
});
skillObserver.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
const skillsSection = document.querySelector('.skills');
if (skillsSection) {
skillObserver.observe(skillsSection);
}
// Contact Form Handling
const contactForm = document.getElementById('contactForm');
contactForm.addEventListener('submit', (e) => {
e.preventDefault();
// Get form data
const formData = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
subject: document.getElementById('subject').value,
message: document.getElementById('message').value
};
// In a real application, you would send this data to a server
console.log('Form submitted:', formData);
// Show success message
showNotification('Thank you for your message! I\'ll get back to you soon.', 'success');
// Reset form
contactForm.reset();
});
// Notification function
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 100px;
right: 20px;
background: ${type === 'success' ? '#10b981' : '#3b82f6'};
color: white;
padding: 1rem 1.5rem;
border-radius: 8px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
z-index: 10000;
animation: slideIn 0.3s ease;
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = 'slideOut 0.3s ease';
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
// Add animation keyframes
const style = document.createElement('style');
style.textContent = `
@keyframes slideIn {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(400px);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Parallax effect for hero section
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
const hero = document.querySelector('.hero');
if (hero && scrolled < window.innerHeight) {
const parallaxElements = hero.querySelectorAll('.floating-card');
parallaxElements.forEach((element, index) => {
const speed = 0.5 + (index * 0.1);
element.style.transform = `translateY(${scrolled * speed}px)`;
});
}
});
// Add active state to navigation based on scroll position
window.addEventListener('scroll', () => {
const sections = document.querySelectorAll('section[id]');
const scrollY = window.pageYOffset;
sections.forEach(section => {
const sectionHeight = section.offsetHeight;
const sectionTop = section.offsetTop - 100;
const sectionId = section.getAttribute('id');
const navLink = document.querySelector(`.nav-link[href="#${sectionId}"]`);
if (navLink && scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) {
document.querySelectorAll('.nav-link').forEach(link => {
link.style.color = '';
});
navLink.style.color = 'var(--primary-color)';
}
});
});
// Preload animation for page load
window.addEventListener('load', () => {
document.body.style.opacity = '0';
setTimeout(() => {
document.body.style.transition = 'opacity 0.5s ease';
document.body.style.opacity = '1';
}, 100);
});