- 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);
|
|
});
|
|
}); |