diff options
author | Robby Zambito <contact@robbyzambito.me> | 2025-07-29 19:09:30 -0400 |
---|---|---|
committer | Robby Zambito <contact@robbyzambito.me> | 2025-07-29 19:12:28 -0400 |
commit | 198bef2c4a13c724d74967e263b9ca41a3abfa48 (patch) | |
tree | 4763b6fae29519e54558815f9c3463a2dd1ee10c /static/script.js | |
parent | 72d420e8acc77c8649d36c0ce92ae51749ecd6c5 (diff) |
Initial fancy site
This is generated by Kagi Code.
Prompt used:
Write a really nice, modern looking, static HTML page. It can reference CSS and JS files, so long as you create both of them also, and they can be statically served.
Diffstat (limited to 'static/script.js')
-rw-r--r-- | static/script.js | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/static/script.js b/static/script.js new file mode 100644 index 0000000..e1fd02c --- /dev/null +++ b/static/script.js @@ -0,0 +1,157 @@ +// Smooth scrolling for navigation 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' + }); + } + }); +}); + +// Mobile menu toggle +const hamburger = document.querySelector('.hamburger'); +const navMenu = document.querySelector('.nav-menu'); + +hamburger.addEventListener('click', () => { + hamburger.classList.toggle('active'); + navMenu.classList.toggle('active'); +}); + +// Close mobile menu when clicking on a link +document.querySelectorAll('.nav-link').forEach(n => n.addEventListener('click', () => { + hamburger.classList.remove('active'); + navMenu.classList.remove('active'); +})); + +// Navbar background on scroll +window.addEventListener('scroll', () => { + const navbar = document.querySelector('.navbar'); + if (window.scrollY > 50) { + navbar.style.background = 'rgba(255, 255, 255, 0.98)'; + } else { + navbar.style.background = 'rgba(255, 255, 255, 0.95)'; + } +}); + +// Intersection Observer for animations +const observerOptions = { + threshold: 0.1, + rootMargin: '0px 0px -50px 0px' +}; + +const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.style.opacity = '1'; + entry.target.style.transform = 'translateY(0)'; + } + }); +}, observerOptions); + +// Observe elements for animation +document.querySelectorAll('.project-card, .stat, .about-text').forEach(el => { + el.style.opacity = '0'; + el.style.transform = 'translateY(30px)'; + el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; + observer.observe(el); +}); + +// Form submission +document.querySelector('.contact-form').addEventListener('submit', function(e) { + e.preventDefault(); + + // Get form data + const formData = new FormData(this); + const name = this.querySelector('input[type="text"]').value; + const email = this.querySelector('input[type="email"]').value; + const message = this.querySelector('textarea').value; + + // Simple validation + if (!name || !email || !message) { + alert('Please fill in all fields'); + return; + } + + // Simulate form submission + const submitBtn = this.querySelector('button[type="submit"]'); + const originalText = submitBtn.textContent; + + submitBtn.textContent = 'Sending...'; + submitBtn.disabled = true; + + setTimeout(() => { + alert('Thank you for your message! I\'ll get back to you soon.'); + this.reset(); + submitBtn.textContent = originalText; + submitBtn.disabled = false; + }, 2000); +}); + +// Add typing animation to hero title +const heroTitle = document.querySelector('.hero-title'); +if (heroTitle) { + const text = heroTitle.innerHTML; + heroTitle.innerHTML = ''; + + let i = 0; + const typeWriter = () => { + if (i < text.length) { + heroTitle.innerHTML += text.charAt(i); + i++; + setTimeout(typeWriter, 50); + } + }; + + // Start typing animation after page load + window.addEventListener('load', () => { + setTimeout(typeWriter, 500); + }); +} + +// Parallax effect for floating cards +window.addEventListener('scroll', () => { + const scrolled = window.pageYOffset; + const parallaxElements = document.querySelectorAll('.floating-card'); + + parallaxElements.forEach((element, index) => { + const speed = 0.5 + (index * 0.1); + const yPos = -(scrolled * speed); + element.style.transform = `translateY(${yPos}px)`; + }); +}); + +// Add mobile menu styles dynamically +const style = document.createElement('style'); +style.textContent = ` + @media (max-width: 768px) { + .nav-menu.active { + display: flex; + position: absolute; + top: 100%; + left: 0; + width: 100%; + background: white; + flex-direction: column; + padding: 1rem 2rem; + box-shadow: var(--shadow); + border-top: 1px solid var(--border); + } + + .hamburger.active span:nth-child(1) { + transform: rotate(-45deg) translate(-5px, 6px); + } + + .hamburger.active span:nth-child(2) { + opacity: 0; + } + + .hamburger.active span:nth-child(3) { + transform: rotate(45deg) translate(-5px, -6px); + } + } +`; +document.head.appendChild(style); |