refactor: cleaned up and optimized JS
This commit is contained in:
		
							parent
							
								
									d549590c1f
								
							
						
					
					
						commit
						69ff668926
					
				
					 1 changed files with 159 additions and 150 deletions
				
			
		|  | @ -1,166 +1,175 @@ | |||
| // Email subscription functionality
 | ||||
| document.getElementById("notify-button").addEventListener("click", async () => { | ||||
|     const emailInput = document.getElementById("email-input"); | ||||
|     const email = emailInput.value.trim(); | ||||
| (() => { | ||||
|   'use strict'; | ||||
| 
 | ||||
|     if (email && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { | ||||
|         try { | ||||
|             // Simulate API call - replace with your actual endpoint
 | ||||
|             const response = await fetch("/subscribe", { | ||||
|                 method: "POST", | ||||
|                 headers: { "Content-Type": "application/json" }, | ||||
|                 body: JSON.stringify({ email }), | ||||
|             }); | ||||
|              | ||||
|             const result = await response.json(); | ||||
|             alert(result.message || "Thank you for subscribing!"); | ||||
|             emailInput.value = ""; | ||||
|         } catch (error) { | ||||
|             console.error("Error during subscribe fetch:", error); | ||||
|             alert("Thank you! We'll notify you when we launch."); | ||||
|             emailInput.value = ""; | ||||
|         } | ||||
|     } else { | ||||
|         alert("Please enter a valid email address."); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| // Smooth navbar background on scroll
 | ||||
| window.addEventListener('scroll', function() { | ||||
|   const navbar = document.querySelector('.navbar'); | ||||
|     if (window.scrollY > 100) { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; | ||||
|         navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)'; | ||||
|     } else { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.95)'; | ||||
|         navbar.style.boxShadow = 'none'; | ||||
|     } | ||||
| }); | ||||
|   const featureCards = document.querySelectorAll('.feature-card'); | ||||
|   const newsletterCards = document.querySelectorAll('.newsletter-card'); | ||||
|   const progressBar = document.querySelector('.reading-progress'); | ||||
|   const emailInput = document.getElementById('email-input'); | ||||
|   const notifyBtn = document.getElementById('notify-button'); | ||||
|   const emailRE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||||
| 
 | ||||
| // Add animation on scroll for feature cards
 | ||||
| const observerOptions = { | ||||
|     threshold: 0.1, | ||||
|     rootMargin: '0px 0px -50px 0px' | ||||
| }; | ||||
|   document.addEventListener( | ||||
|     'click', | ||||
|     (e) => { | ||||
|       const a = e.target.closest('a[href^="#"]'); | ||||
|       if (!a) return; | ||||
| 
 | ||||
| const observer = new IntersectionObserver(function(entries) { | ||||
|     entries.forEach(entry => { | ||||
|         if (entry.isIntersecting) { | ||||
|             entry.target.style.opacity = '1'; | ||||
|             entry.target.style.transform = 'translateY(0)'; | ||||
|         } | ||||
|     }); | ||||
| }, observerOptions); | ||||
|       const href = a.getAttribute('href'); | ||||
|       if (!href || href === '#') return; | ||||
| 
 | ||||
| // Initially hide feature cards for animation
 | ||||
| document.querySelectorAll('.feature-card').forEach(card => { | ||||
|     card.style.opacity = '0'; | ||||
|     card.style.transform = 'translateY(30px)'; | ||||
|     card.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; | ||||
|     observer.observe(card); | ||||
| }); | ||||
|       const target = document.querySelector(href); | ||||
|       if (!target) return; | ||||
| 
 | ||||
| // Add smooth scroll behavior for navigation
 | ||||
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { | ||||
|     anchor.addEventListener('click', function (e) { | ||||
|       e.preventDefault(); | ||||
|         document.querySelector(this.getAttribute('href')).scrollIntoView({ | ||||
|             behavior: 'smooth' | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|       target.scrollIntoView({ behavior: 'smooth', block: 'start' }); | ||||
|     }, | ||||
|     { passive: false } | ||||
|   ); | ||||
| 
 | ||||
| // Add loading states for newsletter cards
 | ||||
| window.addEventListener('load', function() { | ||||
|     const cards = document.querySelectorAll('.newsletter-card'); | ||||
|     cards.forEach((card, index) => { | ||||
|         setTimeout(() => { | ||||
|             card.style.opacity = '1'; | ||||
|             card.style.transform = 'translateY(0)'; | ||||
|         }, index * 100); | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| // Enhanced navbar scroll effect
 | ||||
| window.addEventListener('scroll', function() { | ||||
|     const navbar = document.querySelector('.navbar'); | ||||
|     if (window.scrollY > 50) { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; | ||||
|         navbar.style.boxShadow = '0 5px 20px rgba(0, 0, 0, 0.1)'; | ||||
|     } else { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; | ||||
|         navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.05)'; | ||||
|   if ('IntersectionObserver' in window) { | ||||
|     const observer = new IntersectionObserver( | ||||
|       (entries, obs) => { | ||||
|         for (const entry of entries) { | ||||
|           if (entry.isIntersecting) { | ||||
|             entry.target.classList.add('is-visible'); | ||||
|             obs.unobserve(entry.target); | ||||
|           } | ||||
| }); | ||||
|         } | ||||
|       }, | ||||
|       { threshold: 0.1, rootMargin: '0px 0px -50px 0px' } | ||||
|     ); | ||||
| 
 | ||||
| // Share functionality
 | ||||
| function shareNewsletter() { | ||||
|     featureCards.forEach((card) => { | ||||
|       card.classList.add('will-animate'); | ||||
|       observer.observe(card); | ||||
|     }); | ||||
|   } else { | ||||
|     featureCards.forEach((card) => card.classList.add('is-visible')); | ||||
|   } | ||||
| 
 | ||||
|   window.addEventListener('load', () => { | ||||
|     document | ||||
|       .querySelectorAll('.newsletter-header, .newsletter-content') | ||||
|       .forEach((el, i) => { | ||||
|         el.style.transitionDelay = `${i * 0.2}s`; | ||||
|         el.classList.add('is-visible'); | ||||
|       }); | ||||
| 
 | ||||
|     newsletterCards.forEach((card, i) => { | ||||
|       card.style.transitionDelay = `${i * 0.1}s`; | ||||
|       card.classList.add('is-visible'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   let lastY = 0; | ||||
|   let ticking = false; | ||||
| 
 | ||||
|   function onScroll() { | ||||
|     lastY = window.scrollY || window.pageYOffset; | ||||
|     if (!ticking) { | ||||
|       requestAnimationFrame(updateOnScroll); | ||||
|       ticking = true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function updateOnScroll() { | ||||
|     if (navbar) { | ||||
|       navbar.classList.toggle('navbar--scrolled', lastY > 50); | ||||
|       navbar.classList.toggle('navbar--deeper', lastY > 100); | ||||
|     } | ||||
| 
 | ||||
|     if (progressBar) { | ||||
|       const max = document.body.scrollHeight - window.innerHeight; | ||||
|       const progress = max > 0 ? Math.min(Math.max(lastY / max, 0), 1) : 0; | ||||
|       progressBar.style.width = `${progress * 100}%`; | ||||
|     } | ||||
| 
 | ||||
|     ticking = false; | ||||
|   } | ||||
| 
 | ||||
|   window.addEventListener('scroll', onScroll, { passive: true }); | ||||
|   updateOnScroll(); // initial state
 | ||||
| 
 | ||||
|   if (notifyBtn && emailInput) { | ||||
|     let inFlight = false; | ||||
|     const controller = new AbortController(); | ||||
| 
 | ||||
|     notifyBtn.addEventListener('click', async () => { | ||||
|       const email = emailInput.value.trim(); | ||||
|       if (!emailRE.test(email)) { | ||||
|         alert('Please enter a valid email address.'); | ||||
|         emailInput.focus(); | ||||
|         return; | ||||
|       } | ||||
|       if (inFlight) return; | ||||
| 
 | ||||
|       inFlight = true; | ||||
|       notifyBtn.disabled = true; | ||||
| 
 | ||||
|       try { | ||||
|         const res = await fetch('/subscribe', { | ||||
|           method: 'POST', | ||||
|           headers: { 'Content-Type': 'application/json' }, | ||||
|           body: JSON.stringify({ email }), | ||||
|           signal: controller.signal, | ||||
|         }); | ||||
| 
 | ||||
|         let message = 'Thank you for subscribing!'; | ||||
|         if (res.ok) { | ||||
|           const data = await res.json().catch(() => ({})); | ||||
|           message = data.message || message; | ||||
|         } else { | ||||
|           message = "Thanks! We'll notify you when we launch."; | ||||
|         } | ||||
| 
 | ||||
|         alert(message); | ||||
|         emailInput.value = ''; | ||||
|       } catch (err) { | ||||
|         console.error('Subscribe error:', err); | ||||
|         alert("Thanks! We'll notify you when we launch."); | ||||
|         emailInput.value = ''; | ||||
|       } finally { | ||||
|         notifyBtn.disabled = false; | ||||
|         inFlight = false; | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     window.addEventListener('beforeunload', () => controller.abort(), { | ||||
|       passive: true, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   window.shareNewsletter = async function shareNewsletter() { | ||||
|     try { | ||||
|       if (navigator.share) { | ||||
|         navigator.share({ | ||||
|         await navigator.share({ | ||||
|           title: document.title, | ||||
|           text: 'Check out this newsletter from RideAware', | ||||
|             url: window.location.href | ||||
|         }).catch(console.error); | ||||
|     } else { | ||||
|         // Fallback to copying URL to clipboard
 | ||||
|         navigator.clipboard.writeText(window.location.href).then(() => { | ||||
|           url: location.href, | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|     } catch (err) { | ||||
|       console.warn('navigator.share error/cancel:', err); | ||||
|     } | ||||
| 
 | ||||
|     if (navigator.clipboard && window.isSecureContext) { | ||||
|       try { | ||||
|         await navigator.clipboard.writeText(location.href); | ||||
|         alert('Newsletter URL copied to clipboard!'); | ||||
|         }).catch(() => { | ||||
|             alert('Unable to share. Please copy the URL manually.'); | ||||
|         }); | ||||
|         return; | ||||
|       } catch { | ||||
|         /* fall through */ | ||||
|       } | ||||
| } | ||||
| 
 | ||||
| // Enhanced navbar scroll effect
 | ||||
| window.addEventListener('scroll', function() { | ||||
|     const navbar = document.querySelector('.navbar'); | ||||
|     if (window.scrollY > 50) { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; | ||||
|         navbar.style.boxShadow = '0 5px 20px rgba(0, 0, 0, 0.1)'; | ||||
|     } else { | ||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; | ||||
|         navbar.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.05)'; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| // Smooth scroll for anchor links within newsletter content
 | ||||
| document.addEventListener('DOMContentLoaded', function() { | ||||
|     const anchors = document.querySelectorAll('.newsletter-content a[href^="#"]'); | ||||
|     anchors.forEach(anchor => { | ||||
|         anchor.addEventListener('click', function(e) { | ||||
|             e.preventDefault(); | ||||
|             const target = document.querySelector(this.getAttribute('href')); | ||||
|             if (target) { | ||||
|                 target.scrollIntoView({ | ||||
|                     behavior: 'smooth', | ||||
|                     block: 'start' | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| // Add reading progress indicator
 | ||||
| window.addEventListener('scroll', function() { | ||||
|     const article = document.querySelector('.newsletter-content'); | ||||
|     const scrolled = window.scrollY; | ||||
|     const rate = scrolled / (document.body.scrollHeight - window.innerHeight); | ||||
|     const progress = Math.min(Math.max(rate, 0), 1); | ||||
|      | ||||
|     // Update progress bar if exists
 | ||||
|     const progressBar = document.querySelector('.reading-progress'); | ||||
|     if (progressBar) { | ||||
|         progressBar.style.width = (progress * 100) + '%'; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| // Add animation delay for content loading
 | ||||
| window.addEventListener('load', function() { | ||||
|     const elements = document.querySelectorAll('.newsletter-header, .newsletter-content'); | ||||
|     elements.forEach((element, index) => { | ||||
|         setTimeout(() => { | ||||
|             element.style.opacity = '1'; | ||||
|             element.style.transform = 'translateY(0)'; | ||||
|         }, index * 200); | ||||
|     }); | ||||
| }); | ||||
|     const tmp = document.createElement('input'); | ||||
|     tmp.value = location.href; | ||||
|     document.body.appendChild(tmp); | ||||
|     tmp.select(); | ||||
|     document.execCommand('copy'); | ||||
|     document.body.removeChild(tmp); | ||||
|     alert('Newsletter URL copied to clipboard!'); | ||||
|   }; | ||||
| })(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Cipher Vance
						Cipher Vance