From 06d19988c7df53636277f945f9ed853bda76471b Mon Sep 17 00:00:00 2001 From: Cipher Date: Mon, 25 Aug 2025 08:20:32 -0500 Subject: [PATCH] feat: added main.min.js --- static/js/main.min.js | 175 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 static/js/main.min.js diff --git a/static/js/main.min.js b/static/js/main.min.js new file mode 100644 index 0000000..d271f62 --- /dev/null +++ b/static/js/main.min.js @@ -0,0 +1,175 @@ +(() => { + 'use strict'; + + const navbar = document.querySelector('.navbar'); + 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@]+$/; + + document.addEventListener( + 'click', + (e) => { + const a = e.target.closest('a[href^="#"]'); + if (!a) return; + + const href = a.getAttribute('href'); + if (!href || href === '#') return; + + 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); + } + } + }, + { threshold: 0.1, rootMargin: '0px 0px -50px 0px' } + ); + + 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) { + 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!'); + }; + })(); \ No newline at end of file