feat: Complete UI/UX redesign with modern responsive design

- 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
This commit is contained in:
Cipher Vance 2025-08-24 12:47:15 -05:00
parent 778533b655
commit 1a66ebdfc4
9 changed files with 2612 additions and 546 deletions

View file

@ -1,20 +1,20 @@
// Countdown timer
const targetDate = new Date("2025-01-31T00:00:00Z"); // Set your launch date
const targetDate = new Date("2025-12-31T00:00:00Z");
function updateCountdown() {
const now = new Date();
const difference = targetDate - now;
if (difference < 0) {
document.getElementById("countdown").innerHTML = "<p>We're Live!</p>";
document.getElementById("countdown").innerHTML = "<p style='color: white; font-size: 1.5rem;'>We're Live!</p>";
return;
}
const days = Math.floor(difference / (1000 * 60 * 60 * 24));
const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((difference / (1000 * 60)) % 60);
const seconds = Math.floor((difference / 1000) % 60);
document.getElementById("days").textContent = days.toString().padStart(2, "0");
document.getElementById("hours").textContent = hours.toString().padStart(2, "0");
document.getElementById("minutes").textContent = minutes.toString().padStart(2, "0");
@ -22,3 +22,4 @@ function updateCountdown() {
}
setInterval(updateCountdown, 1000);
updateCountdown(); // Run immediately

View file

@ -1,34 +1,166 @@
// Email subscription functionality
document.getElementById("notify-button").addEventListener("click", async () => {
const emailInput = document.getElementById("email-input");
const email = emailInput.value.trim();
if (email) {
try {
const response = await fetch("/subscribe", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
// Check if response is OK, then parse JSON
const result = await response.json();
console.log("Server response:", result);
alert(result.message || result.error);
} catch (error) {
console.error("Error during subscribe fetch:", error);
alert("There was an error during subscription. Please try again later.");
}
emailInput.value = ""; // Clear input field
} else {
alert("Please enter a valid email.");
}
});
window.addEventListener('scroll', function() {
var footerHeight = document.querySelector('footer').offsetHeight;
if (window.scrollY + window.innerHeight >= document.body.offsetHeight - footerHeight) {
document.querySelector('footer').style.display = 'block';
} else {
document.querySelector('footer').style.display = 'none';
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);
});
});