 1a66ebdfc4
			
		
	
	
		1a66ebdfc4
		
	
	
	
	
		
			
			- Redesign landing page with contemporary gradient backgrounds and glassmorphism - Add 3D phone mockup with floating animation and interactive stats display - Implement modern navigation with blur backdrop and smooth scroll effects - Update feature cards with icons, hover animations, and improved typography - Integrate countdown timer into hero CTA section with glassmorphic styling - Add responsive email signup form with enhanced validation - Modernize newsletters listing page with card-based grid layout - Add empty state design with call-to-action for newsletter subscription - Implement smooth loading animations and hover effects for newsletter cards - Update navigation consistency across all pages - Redesign newsletter detail page with professional article layout - Add reading metadata display (date, reading time, author, tags) - Enhance content typography with proper heading hierarchy and styling - Implement share functionality with Web Share API and clipboard fallback - Add print-optimized styles and action buttons - Improve mobile reading experience with responsive design - Establish consistent design system with CSS custom properties - Use CSS Grid and Flexbox for modern, flexible layouts - Add comprehensive mobile responsiveness (320px to desktop) - Implement smooth animations and micro-interactions throughout - Maintain accessibility with semantic HTML and proper contrast ratios - Preserve all existing Flask template functionality and JavaScript features Breaking changes: Complete visual redesign requires updated asset references Performance: Optimized CSS with efficient animations and modern layout techniques
		
			
				
	
	
		
			166 lines
		
	
	
		
			No EOL
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			No EOL
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Email subscription functionality
 | |
| document.getElementById("notify-button").addEventListener("click", async () => {
 | |
|     const emailInput = document.getElementById("email-input");
 | |
|     const email = emailInput.value.trim();
 | |
|     
 | |
|     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';
 | |
|     }
 | |
| });
 | |
| 
 | |
| // 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);
 | |
| 
 | |
| // 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);
 | |
| });
 | |
| 
 | |
| // 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'
 | |
|         });
 | |
|     });
 | |
| });
 | |
| 
 | |
| // 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)';
 | |
|     }
 | |
| });
 | |
| 
 | |
| // Share functionality
 | |
| function shareNewsletter() {
 | |
|     if (navigator.share) {
 | |
|         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(() => {
 | |
|             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) {
 | |
|         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);
 | |
|     });
 | |
| }); |