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 () => { |   'use strict'; | ||||||
|     const emailInput = document.getElementById("email-input"); | 
 | ||||||
|     const email = emailInput.value.trim(); |   const navbar = document.querySelector('.navbar'); | ||||||
|      |   const featureCards = document.querySelectorAll('.feature-card'); | ||||||
|     if (email && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { |   const newsletterCards = document.querySelectorAll('.newsletter-card'); | ||||||
|         try { |   const progressBar = document.querySelector('.reading-progress'); | ||||||
|             // Simulate API call - replace with your actual endpoint
 |   const emailInput = document.getElementById('email-input'); | ||||||
|             const response = await fetch("/subscribe", { |   const notifyBtn = document.getElementById('notify-button'); | ||||||
|                 method: "POST", |   const emailRE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||||||
|                 headers: { "Content-Type": "application/json" }, | 
 | ||||||
|                 body: JSON.stringify({ email }), |   document.addEventListener( | ||||||
|             }); |     'click', | ||||||
|              |     (e) => { | ||||||
|             const result = await response.json(); |       const a = e.target.closest('a[href^="#"]'); | ||||||
|             alert(result.message || "Thank you for subscribing!"); |       if (!a) return; | ||||||
|             emailInput.value = ""; | 
 | ||||||
|         } catch (error) { |       const href = a.getAttribute('href'); | ||||||
|             console.error("Error during subscribe fetch:", error); |       if (!href || href === '#') return; | ||||||
|             alert("Thank you! We'll notify you when we launch."); | 
 | ||||||
|             emailInput.value = ""; |       const target = document.querySelector(href); | ||||||
|  |       if (!target) return; | ||||||
|  | 
 | ||||||
|  |       e.preventDefault(); | ||||||
|  |       target.scrollIntoView({ behavior: 'smooth', block: 'start' }); | ||||||
|  |     }, | ||||||
|  |     { passive: false } | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   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); | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|     } else { |       }, | ||||||
|         alert("Please enter a valid email address."); |       { threshold: 0.1, rootMargin: '0px 0px -50px 0px' } | ||||||
|     } |     ); | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| // Smooth navbar background on scroll
 |     featureCards.forEach((card) => { | ||||||
| window.addEventListener('scroll', function() { |       card.classList.add('will-animate'); | ||||||
|     const navbar = document.querySelector('.navbar'); |       observer.observe(card); | ||||||
|     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'; |  | ||||||
|     } |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| // Add animation on scroll for feature cards
 |  | ||||||
| const observerOptions = { |  | ||||||
|     threshold: 0.1, |  | ||||||
|     rootMargin: '0px 0px -50px 0px' |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| const observer = new IntersectionObserver(function(entries) { |  | ||||||
|     entries.forEach(entry => { |  | ||||||
|         if (entry.isIntersecting) { |  | ||||||
|             entry.target.style.opacity = '1'; |  | ||||||
|             entry.target.style.transform = 'translateY(0)'; |  | ||||||
|         } |  | ||||||
|     }); |     }); | ||||||
| }, observerOptions); |   } else { | ||||||
|  |     featureCards.forEach((card) => card.classList.add('is-visible')); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
| // Initially hide feature cards for animation
 |   window.addEventListener('load', () => { | ||||||
| document.querySelectorAll('.feature-card').forEach(card => { |     document | ||||||
|     card.style.opacity = '0'; |       .querySelectorAll('.newsletter-header, .newsletter-content') | ||||||
|     card.style.transform = 'translateY(30px)'; |       .forEach((el, i) => { | ||||||
|     card.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; |         el.style.transitionDelay = `${i * 0.2}s`; | ||||||
|     observer.observe(card); |         el.classList.add('is-visible'); | ||||||
| }); |       }); | ||||||
| 
 | 
 | ||||||
| // Add smooth scroll behavior for navigation
 |     newsletterCards.forEach((card, i) => { | ||||||
| document.querySelectorAll('a[href^="#"]').forEach(anchor => { |       card.style.transitionDelay = `${i * 0.1}s`; | ||||||
|     anchor.addEventListener('click', function (e) { |       card.classList.add('is-visible'); | ||||||
|         e.preventDefault(); |  | ||||||
|         document.querySelector(this.getAttribute('href')).scrollIntoView({ |  | ||||||
|             behavior: 'smooth' |  | ||||||
|         }); |  | ||||||
|     }); |     }); | ||||||
| }); |   }); | ||||||
| 
 | 
 | ||||||
| // Add loading states for newsletter cards
 |   let lastY = 0; | ||||||
| window.addEventListener('load', function() { |   let ticking = false; | ||||||
|     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
 |   function onScroll() { | ||||||
| window.addEventListener('scroll', function() { |     lastY = window.scrollY || window.pageYOffset; | ||||||
|     const navbar = document.querySelector('.navbar'); |     if (!ticking) { | ||||||
|     if (window.scrollY > 50) { |       requestAnimationFrame(updateOnScroll); | ||||||
|         navbar.style.background = 'rgba(255, 255, 255, 0.98)'; |       ticking = true; | ||||||
|         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)'; |  | ||||||
|     } |     } | ||||||
| }); |   } | ||||||
| 
 | 
 | ||||||
| // Share functionality
 |   function updateOnScroll() { | ||||||
| function shareNewsletter() { |     if (navbar) { | ||||||
|     if (navigator.share) { |       navbar.classList.toggle('navbar--scrolled', lastY > 50); | ||||||
|         navigator.share({ |       navbar.classList.toggle('navbar--deeper', lastY > 100); | ||||||
|             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(() => { |  | ||||||
|             alert('Newsletter URL copied to clipboard!'); |  | ||||||
|         }).catch(() => { |  | ||||||
|             alert('Unable to share. Please copy the URL manually.'); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // 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) { |     if (progressBar) { | ||||||
|         progressBar.style.width = (progress * 100) + '%'; |       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}%`; | ||||||
|     } |     } | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| // Add animation delay for content loading
 |     ticking = false; | ||||||
| window.addEventListener('load', function() { |   } | ||||||
|     const elements = document.querySelectorAll('.newsletter-header, .newsletter-content'); | 
 | ||||||
|     elements.forEach((element, index) => { |   window.addEventListener('scroll', onScroll, { passive: true }); | ||||||
|         setTimeout(() => { |   updateOnScroll(); // initial state
 | ||||||
|             element.style.opacity = '1'; | 
 | ||||||
|             element.style.transform = 'translateY(0)'; |   if (notifyBtn && emailInput) { | ||||||
|         }, index * 200); |     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) { | ||||||
|  |         await navigator.share({ | ||||||
|  |           title: document.title, | ||||||
|  |           text: 'Check out this newsletter from RideAware', | ||||||
|  |           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!'); | ||||||
|  |         return; | ||||||
|  |       } catch { | ||||||
|  |         /* fall through */ | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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