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

@ -0,0 +1,825 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #1e4e9c;
--secondary: #337cf2;
--accent: #00d4ff;
--text-dark: #1a1a1a;
--text-light: #6b7280;
--bg-light: #f8fafc;
--white: #ffffff;
--gradient: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 50%, var(--accent) 100%);
--shadow: 0 10px 30px rgba(30, 78, 156, 0.1);
--shadow-hover: 0 20px 40px rgba(30, 78, 156, 0.15);
--border-radius: 20px;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
line-height: 1.7;
color: var(--text-dark);
background: var(--bg-light);
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Navigation */
.navbar {
position: sticky;
top: 0;
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(20px);
z-index: 1000;
padding: 1rem 0;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.05);
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--text-dark);
text-decoration: none;
transition: transform 0.3s ease;
}
.logo:hover {
transform: scale(1.05);
}
.logo-accent {
color: var(--primary);
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
align-items: center;
}
.nav-links a {
text-decoration: none;
color: var(--text-dark);
font-weight: 500;
transition: all 0.3s ease;
position: relative;
padding: 0.5rem 1rem;
border-radius: 25px;
}
.nav-links a.active {
background: var(--gradient);
color: white;
transform: translateY(-2px);
}
.nav-links a:not(.active)::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 2px;
background: var(--gradient);
transition: width 0.3s ease;
}
.nav-links a:not(.active):hover::after {
width: 80%;
}
/* Header Section */
.page-header {
background: var(--gradient);
padding: 4rem 0 2rem;
text-align: center;
position: relative;
overflow: hidden;
}
.page-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="1" fill="rgba(255,255,255,0.1)"/></pattern></defs><rect width="100%" height="100%" fill="url(%23dots)"/></svg>');
opacity: 0.3;
}
.page-header-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
position: relative;
z-index: 1;
}
.page-header h1 {
font-size: clamp(2.5rem, 5vw, 3.5rem);
font-weight: 800;
color: white;
margin-bottom: 1rem;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
}
.page-header p {
font-size: 1.25rem;
color: rgba(255, 255, 255, 0.9);
max-width: 600px;
margin: 0 auto;
font-weight: 300;
}
.header-icon {
display: inline-block;
font-size: 3rem;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
/* Main Content (List page) */
.main-content {
flex: 1;
max-width: 1200px;
margin: 0 auto;
padding: 3rem 2rem;
width: 100%;
}
/* Newsletter Grid */
.newsletters-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 2rem;
margin-top: 2rem;
}
.newsletter-card {
background: white;
border-radius: var(--border-radius);
padding: 2rem;
box-shadow: var(--shadow);
border: 1px solid rgba(30, 78, 156, 0.05);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.newsletter-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--gradient);
}
.newsletter-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-hover);
}
.newsletter-header {
display: flex;
align-items: flex-start;
gap: 1rem;
margin-bottom: 1rem;
}
.newsletter-icon {
width: 50px;
height: 50px;
background: var(--gradient);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 1.25rem;
flex-shrink: 0;
}
.newsletter-info h2 {
font-size: 1.375rem;
font-weight: 600;
color: var(--text-dark);
margin-bottom: 0.5rem;
line-height: 1.4;
}
.newsletter-info h2 a {
color: inherit;
text-decoration: none;
transition: color 0.3s ease;
}
.newsletter-info h2 a:hover {
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.newsletter-date {
color: var(--text-light);
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.newsletter-excerpt {
color: var(--text-light);
margin-bottom: 1.5rem;
font-size: 0.95rem;
line-height: 1.6;
}
.read-more-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: var(--gradient);
color: white;
text-decoration: none;
padding: 0.75rem 1.5rem;
border-radius: 25px;
font-weight: 500;
transition: all 0.3s ease;
font-size: 0.875rem;
}
.read-more-btn:hover {
transform: translateX(5px);
box-shadow: 0 5px 15px rgba(30, 78, 156, 0.3);
}
/* Empty State */
.empty-state {
text-align: center;
padding: 4rem 2rem;
background: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
border: 1px solid rgba(30, 78, 156, 0.05);
}
.empty-icon {
font-size: 4rem;
color: var(--text-light);
margin-bottom: 1.5rem;
opacity: 0.5;
}
.empty-state h3 {
font-size: 1.5rem;
color: var(--text-dark);
margin-bottom: 1rem;
}
.empty-state p {
color: var(--text-light);
font-size: 1.125rem;
max-width: 400px;
margin: 0 auto 2rem;
}
.subscribe-prompt {
background: var(--gradient);
color: white;
text-decoration: none;
padding: 1rem 2rem;
border-radius: 25px;
font-weight: 600;
display: inline-flex;
align-items: center;
gap: 0.75rem;
transition: all 0.3s ease;
}
.subscribe-prompt:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-hover);
}
/* Footer (list page) */
.footer {
background: var(--text-dark);
color: white;
text-align: center;
padding: 2rem 0;
margin-top: auto;
}
.footer p {
opacity: 0.8;
}
/* Mobile Styles (list page) */
@media (max-width: 768px) {
.nav-container {
padding: 0 1rem;
}
.nav-links {
gap: 1rem;
}
.nav-links a {
padding: 0.5rem 0.75rem;
font-size: 0.875rem;
}
.page-header {
padding: 3rem 0 1.5rem;
}
.main-content {
padding: 2rem 1rem;
}
.newsletters-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.newsletter-card {
padding: 1.5rem;
}
.newsletter-header {
flex-direction: column;
align-items: center;
text-align: center;
gap: 1rem;
}
.empty-state {
padding: 3rem 1.5rem;
}
}
/* Loading Animation (list page cards) */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
.newsletter-card {
animation: fadeInUp 0.6s ease forwards;
}
.newsletter-card:nth-child(2) { animation-delay: 0.1s; }
.newsletter-card:nth-child(3) { animation-delay: 0.2s; }
.newsletter-card:nth-child(4) { animation-delay: 0.3s; }
/* ----------------------------- */
/* Detail Page Additions (unique) */
/* ----------------------------- */
/* Back Button */
.back-navigation {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 2rem 0;
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.75rem;
color: var(--text-light);
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
padding: 0.75rem 1rem;
border-radius: 25px;
background: white;
box-shadow: var(--shadow);
border: 1px solid rgba(30, 78, 156, 0.05);
}
.back-link:hover {
color: var(--primary);
transform: translateX(-5px);
box-shadow: var(--shadow-hover);
}
.back-link i {
transition: transform 0.3s ease;
}
.back-link:hover i {
transform: translateX(-3px);
}
/* Main Content (detail page override) */
.main-content {
flex: 1;
max-width: 900px;
margin: 0 auto;
padding: 2rem;
width: 100%;
}
/* Newsletter Header (detail) */
.newsletter-header {
background: white;
padding: 3rem;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
margin-bottom: 2rem;
text-align: center;
position: relative;
overflow: hidden;
border: 1px solid rgba(30, 78, 156, 0.05);
}
.newsletter-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--gradient);
}
.newsletter-icon {
width: 80px;
height: 80px;
background: var(--gradient);
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 2rem;
margin: 0 auto 1.5rem;
box-shadow: 0 10px 20px rgba(30, 78, 156, 0.2);
}
.newsletter-header h1 {
font-size: clamp(1.75rem, 4vw, 2.5rem);
font-weight: 700;
color: var(--text-dark);
margin-bottom: 1rem;
line-height: 1.3;
}
.newsletter-meta {
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
color: var(--text-light);
font-size: 0.95rem;
margin-bottom: 1.5rem;
}
.meta-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.newsletter-tags {
display: flex;
gap: 0.75rem;
justify-content: center;
flex-wrap: wrap;
}
.tag {
background: rgba(30, 78, 156, 0.1);
color: var(--primary);
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.875rem;
font-weight: 500;
}
/* Newsletter Content (detail) */
.newsletter-content {
background: white;
padding: 3rem;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
border: 1px solid rgba(30, 78, 156, 0.05);
position: relative;
}
.newsletter-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--gradient);
}
/* Typography */
.newsletter-content h1,
.newsletter-content h2,
.newsletter-content h3,
.newsletter-content h4,
.newsletter-content h5,
.newsletter-content h6 {
color: var(--text-dark);
font-weight: 600;
margin-top: 2rem;
margin-bottom: 1rem;
line-height: 1.3;
}
.newsletter-content h1 {
font-size: 2.25rem;
font-weight: 700;
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.newsletter-content h2 {
font-size: 1.875rem;
border-bottom: 2px solid rgba(30, 78, 156, 0.1);
padding-bottom: 0.5rem;
}
.newsletter-content h3 {
font-size: 1.5rem;
color: var(--primary);
}
.newsletter-content h4 {
font-size: 1.25rem;
}
.newsletter-content p {
margin-bottom: 1.5rem;
font-size: 1.0625rem;
line-height: 1.8;
color: var(--text-dark);
}
.newsletter-content ul,
.newsletter-content ol {
margin-bottom: 1.5rem;
padding-left: 2rem;
}
.newsletter-content li {
margin-bottom: 0.75rem;
color: var(--text-dark);
line-height: 1.7;
}
.newsletter-content blockquote {
background: rgba(30, 78, 156, 0.05);
border-left: 4px solid var(--primary);
padding: 1.5rem 2rem;
margin: 2rem 0;
border-radius: 0 15px 15px 0;
font-style: italic;
color: var(--text-light);
position: relative;
}
.newsletter-content blockquote::before {
content: '"';
font-size: 3rem;
color: var(--primary);
position: absolute;
top: 0.5rem;
left: 1rem;
opacity: 0.3;
}
.newsletter-content a {
color: var(--primary);
text-decoration: none;
font-weight: 500;
border-bottom: 1px solid transparent;
transition: all 0.3s ease;
}
.newsletter-content a:hover {
border-bottom-color: var(--primary);
color: var(--secondary);
}
.newsletter-content img {
max-width: 100%;
height: auto;
border-radius: 15px;
margin: 2rem 0;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.newsletter-content pre {
background: #f8fafc;
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 1.5rem;
overflow-x: auto;
margin: 2rem 0;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
}
.newsletter-content code {
background: rgba(30, 78, 156, 0.1);
color: var(--primary);
padding: 0.25rem 0.5rem;
border-radius: 5px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9em;
}
.newsletter-content table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.newsletter-content th,
.newsletter-content td {
padding: 1rem 1.5rem;
text-align: left;
border-bottom: 1px solid rgba(30, 78, 156, 0.1);
}
.newsletter-content th {
background: var(--gradient);
color: white;
font-weight: 600;
}
/* Action Buttons */
.newsletter-actions {
display: flex;
gap: 1rem;
justify-content: center;
margin: 3rem 0 2rem;
flex-wrap: wrap;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 2rem;
border: none;
border-radius: 25px;
font-weight: 600;
text-decoration: none;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
}
.action-btn.primary {
background: var(--gradient);
color: white;
}
.action-btn.secondary {
background: white;
color: var(--primary);
border: 2px solid var(--primary);
}
.action-btn:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-hover);
}
/* Footer (detail page override) */
.footer {
background: var(--text-dark);
color: white;
text-align: center;
padding: 2rem 0;
margin-top: 2rem;
}
/* Mobile (detail page) */
@media (max-width: 768px) {
.back-navigation {
padding: 1.5rem 1rem 0;
}
.main-content {
padding: 1rem;
}
.newsletter-header {
padding: 2rem 1.5rem;
}
.newsletter-meta {
flex-direction: column;
gap: 1rem;
}
.newsletter-content {
padding: 2rem 1.5rem;
}
.newsletter-content h1 { font-size: 1.75rem; }
.newsletter-content h2 { font-size: 1.5rem; }
.newsletter-content h3 { font-size: 1.25rem; }
.newsletter-actions {
flex-direction: column;
align-items: center;
}
.action-btn {
width: 100%;
max-width: 300px;
justify-content: center;
}
.newsletter-content pre {
padding: 1rem;
font-size: 0.875rem;
}
.newsletter-content th,
.newsletter-content td {
padding: 0.75rem 1rem;
font-size: 0.875rem;
}
}
@media (max-width: 480px) {
.newsletter-header {
padding: 1.5rem 1rem;
}
.newsletter-content {
padding: 1.5rem 1rem;
}
.newsletter-icon {
width: 60px;
height: 60px;
font-size: 1.5rem;
}
}
/* Print Styles */
@media print {
.navbar,
.back-navigation,
.newsletter-actions,
.footer {
display: none;
}
.newsletter-header,
.newsletter-content {
box-shadow: none;
border: 1px solid #ddd;
}
.newsletter-content {
page-break-inside: avoid;
}
}
/* Animation (detail page elements) */
.newsletter-header,
.newsletter-content {
animation: fadeInUp 0.6s ease forwards;
}
.newsletter-content {
animation-delay: 0.2s;
}

View file

@ -1,358 +1,476 @@
/* Reset and General Styles */
html {
box-sizing: border-box;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
:root {
--primary: #1e4e9c;
--secondary: #337cf2;
--accent: #00d4ff;
--text-dark: #1a1a1a;
--text-light: #6b7280;
--bg-light: #f8fafc;
--white: #ffffff;
--gradient: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 50%, var(--accent) 100%);
--shadow: 0 10px 30px rgba(30, 78, 156, 0.1);
--shadow-hover: 0 20px 40px rgba(30, 78, 156, 0.15);
}
html {
scroll-behavior: smooth;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
line-height: 1.7;
color: var(--text-dark);
overflow-x: hidden;
}
img {
max-width: 100%;
height: auto;
/* Navigation */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
z-index: 1000;
padding: 1rem 0;
transition: all 0.3s ease;
}
/* Header and Nav */
header {
background-color: #fff;
padding: 10px 20px;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin: 5px auto;
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
header nav {
display: flex;
justify-content: flex-start; /* Align items to the start */
align-items: center;
.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--text-dark);
text-decoration: none;
transition: transform 0.3s ease;
}
header nav a {
text-decoration: none;
color: #000;
margin-left: 20px;
font-size: 22px;
.logo:hover {
transform: scale(1.05);
}
/* Hero Section Styles */
.hero-section-1 {
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
.logo-accent {
color: var(--primary);
}
.hero-content,
.hero-text {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}
.hero-text img {
width: 70%;
display: block;
margin: 0 auto;
.nav-links a {
text-decoration: none;
color: var(--text-dark);
font-weight: 500;
transition: color 0.3s ease;
position: relative;
}
.hero-text h1 {
font-size: 48px;
font-weight: bold;
color: #000;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
.nav-links a::after {
content: '';
position: absolute;
bottom: -5px;
left: 0;
width: 0;
height: 2px;
background: var(--gradient);
transition: width 0.3s ease;
}
.hero-text p {
font-size: 18px;
color: #000;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
.nav-links a:hover::after {
width: 100%;
}
.hero-section-2 {
background-color: #337cf2;
padding: 100px 0;
text-align: center;
width: 100%;
margin: 0;
/* Hero Section */
.hero {
min-height: 100vh;
background: var(--gradient);
display: flex;
align-items: center;
position: relative;
overflow: hidden;
}
.hero-section-2 .inner-container {
padding: 0 20px;
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grain" width="100" height="100" patternUnits="userSpaceOnUse"><circle cx="20" cy="20" r="1" fill="rgba(255,255,255,0.1)"/><circle cx="80" cy="40" r="1" fill="rgba(255,255,255,0.05)"/><circle cx="40" cy="80" r="1" fill="rgba(255,255,255,0.1)"/></pattern></defs><rect width="100%" height="100%" fill="url(%23grain)"/></svg>');
opacity: 0.3;
}
.hero-sec2-header {
padding-top: 2.5%;
font-size: 40px;
.hero-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: center;
position: relative;
z-index: 1;
}
.hero-section-2 form {
padding: 10px;
font-size: 1rem;
width: calc(100% - 50px);
max-width: 600px;
margin: 0 auto;
.hero-content h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 800;
color: white;
margin-bottom: 1.5rem;
line-height: 1.2;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
}
.hero-section-2 input {
padding: 10px;
width: 15%;
border: 1px solid #ccc;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
.hero-content .subtitle {
font-size: 1.25rem;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 2rem;
font-weight: 300;
}
.hero-section-2 button {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
.cta-section {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
padding: 2rem;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Feature Cards */
.hero-section-3 {
width: 100%;
.cta-section h3 {
color: white;
font-size: 1.5rem;
margin-bottom: 0.5rem;
font-weight: 600;
}
.hero-section-3 h2 {
margin-top: 0;
text-align: center;
.cta-section p {
color: rgba(255, 255, 255, 0.8);
margin-bottom: 1.5rem;
}
.feature-cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
.email-form {
display: flex;
gap: 1rem;
margin-bottom: 1.5rem;
}
.email-input {
flex: 1;
padding: 1rem 1.5rem;
border: none;
border-radius: 50px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
font-size: 1rem;
outline: none;
transition: all 0.3s ease;
}
.email-input:focus {
background: white;
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
}
.notify-btn {
padding: 1rem 2rem;
background: var(--white);
color: var(--primary);
border: none;
border-radius: 50px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
white-space: nowrap;
}
.notify-btn:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-hover);
}
/* Countdown Timer */
.countdown {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-top: 1rem;
}
.countdown-item {
text-align: center;
color: white;
}
.countdown-number {
font-size: 2rem;
font-weight: 700;
display: block;
}
.countdown-label {
font-size: 0.875rem;
opacity: 0.8;
text-transform: uppercase;
letter-spacing: 1px;
}
.hero-visual {
position: relative;
height: 500px;
display: flex;
align-items: center;
justify-content: center;
}
.phone-mockup {
width: 300px;
height: 600px;
background: linear-gradient(145deg, #2a2a2a, #1a1a1a);
border-radius: 40px;
padding: 20px;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3);
position: relative;
transform: rotate(-5deg);
animation: float 6s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: rotate(-5deg) translateY(0px); }
50% { transform: rotate(-5deg) translateY(-20px); }
}
.screen {
width: 100%;
height: 100%;
background: var(--gradient);
border-radius: 25px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
}
.app-interface {
color: white;
text-align: center;
}
.app-logo {
font-size: 2rem;
font-weight: 700;
margin-bottom: 1rem;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 2rem;
}
.stat-card {
background: rgba(255, 255, 255, 0.1);
padding: 1rem;
border-radius: 15px;
text-align: center;
}
.stat-number {
font-size: 1.5rem;
font-weight: 700;
}
.stat-label {
font-size: 0.75rem;
opacity: 0.8;
}
/* Features Section */
.features {
padding: 6rem 0;
background: var(--bg-light);
position: relative;
}
.section-header {
text-align: center;
max-width: 800px;
margin: 0 auto 4rem;
padding: 0 2rem;
}
.section-header h2 {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 700;
margin-bottom: 1rem;
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.section-header p {
font-size: 1.125rem;
color: var(--text-light);
}
.features-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
}
.feature-card {
background-color: #fff;
padding: 20px;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
margin: 20px;
width: 30%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
word-wrap: break-word;
overflow-wrap: break-word;
background: white;
padding: 2.5rem;
border-radius: 20px;
box-shadow: var(--shadow);
transition: all 0.3s ease;
border: 1px solid rgba(30, 78, 156, 0.05);
position: relative;
overflow: hidden;
}
.feature-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--gradient);
}
.feature-card:hover {
transform: translateY(-10px);
box-shadow: var(--shadow-hover);
}
.feature-icon {
width: 60px;
height: 60px;
background: var(--gradient);
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
color: white;
font-size: 1.5rem;
}
.feature-card h3 {
margin-top: 0;
text-align: center;
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--text-dark);
}
.feature-card ul {
list-style: none;
padding: 0;
margin: 0;
text-align: center;
.feature-list {
list-style: none;
}
.feature-card li {
margin-bottom: 10px;
font-size: 16px;
color: #666;
.feature-list li {
margin-bottom: 0.75rem;
position: relative;
padding-left: 1.5rem;
color: var(--text-light);
}
.feature-card li::before {
content: "\2022";
font-size: 16px;
color: #337cf2;
margin-right: 10px;
.feature-list li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--secondary);
font-weight: bold;
}
/* Main Content */
main {
width: 100%;
margin: 0;
padding: 0;
display: block;
}
main .inner-container {
padding: 10px 20px;
}
main h1 {
text-align: center;
margin-bottom: 20px;
color: #007bff;
.feature-list li strong {
color: var(--text-dark);
}
/* Footer */
.normal-footer {
background-color: #337cf2;
color: #fff;
padding: 10px;
text-align: center;
clear: both;
margin-top: auto;
.footer {
background: var(--text-dark);
color: white;
text-align: center;
padding: 2rem 0;
}
.fixed-footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #337cf2;
color: #fff;
padding: 10px;
text-align: center;
z-index: 1000;
}
/* Newsletter Styles */
.newsletter {
margin-bottom: 40px;
border-bottom: 1px solid #ddd;
padding-bottom: 20px;
}
.newsletter h2 {
color: #007bff;
}
.newsletter-time {
color: #666;
font-size: 0.9em;
}
.newsletter-detail {
max-width: 800px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.newsletter-detail h1 {
color: #007bff;
}
.back-link {
margin-top: 20px;
display: inline-block;
color: #007bff;
text-decoration: none;
}
.back-link:hover {
text-decoration: underline;
}
.cards-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.newsletter-content {
width: 100%; /* Fixed to 100% */
}
.newsletter-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
width: 300px;
display: flex;
flex-direction: column;
padding: 20px;
transition: transform 0.15s ease-in-out;
}
.newsletter-card:hover {
transform: translateY(-5px);
}
.newsletter-card h2 {
font-size: 1.5em;
color: #007bff;
margin-bottom: 10px;
}
.newsletter-card p.newsletter-time {
font-size: 0.8em;
}
.newsletter-main {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* Media Queries */
/* Mobile Styles */
@media (max-width: 768px) {
.hero-content {
flex-direction: column;
padding: 0;
}
.nav-container {
padding: 0 1rem;
}
.hero-text {
width: 100%;
padding: 10px;
}
.nav-links {
display: none;
}
.hero-section-2 input {
width: 80%;
}
.hero-container {
grid-template-columns: 1fr;
gap: 2rem;
text-align: center;
}
.feature-card {
width: 90%;
}
.hero-visual {
order: -1;
height: 300px;
}
.hero-text h1 {
font-size: 2.5em;
}
.phone-mockup {
width: 200px;
height: 400px;
}
.hero-section-2 {
padding: 50px 0;
}
.email-form {
flex-direction: column;
}
.hero-sec2-header {
font-size: 32px;
}
.countdown {
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.hero-section-2 form {
width: calc(100% - 40px);
padding: 10px;
}
.features-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.feature-card {
padding: 2rem;
}
}
@media (max-width: 480px) {
.hero-text h1 {
font-size: 2em;
}
.hero-section-2 input {
width: 90%;
}
.feature-card {
width: 100%;
margin: 10px 0;
}
.hero-section-1 {
padding: 50px 0;
}
}
.cta-section {
padding: 1.5rem;
margin: 0 1rem;
}
.features-container {
padding: 0 1rem;
}
}

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

View file

@ -3,33 +3,442 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Thanks for Subscribing!</title>
<title>Welcome to RideAware!</title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<style>
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
color: #1a1a1a;
background-color: #f8fafc;
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
table {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
a {
color: #007bff;
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
a:hover {
/* Container */
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(30, 78, 156, 0.1);
overflow: hidden;
}
.email-wrapper {
background-color: #f8fafc;
padding: 20px;
}
/* Header */
.header {
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 50%, #00d4ff 100%);
padding: 50px 30px;
text-align: center;
position: relative;
}
.header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="celebration" width="50" height="50" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="2" fill="rgba(255,255,255,0.1)"/><circle cx="40" cy="25" r="1.5" fill="rgba(0,212,255,0.2)"/><circle cx="25" cy="40" r="1" fill="rgba(255,255,255,0.15)"/></pattern></defs><rect width="100%" height="100%" fill="url(%23celebration)"/></svg>');
opacity: 0.4;
}
.welcome-icon {
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 20px;
font-size: 2.5rem;
position: relative;
z-index: 1;
}
.logo {
font-size: 24px;
font-weight: 700;
color: white;
text-decoration: none;
position: relative;
z-index: 1;
margin-bottom: 15px;
display: inline-block;
}
.logo-accent {
color: #00d4ff;
}
.header h1 {
color: white;
font-size: 28px;
font-weight: 800;
margin: 0 0 10px;
position: relative;
z-index: 1;
}
.header .subtitle {
color: rgba(255, 255, 255, 0.9);
font-size: 16px;
font-weight: 300;
position: relative;
z-index: 1;
}
/* Content */
.content {
padding: 40px 30px;
text-align: center;
}
.main-message {
font-size: 18px;
color: #1a1a1a;
margin-bottom: 25px;
font-weight: 500;
}
.description {
font-size: 16px;
color: #6b7280;
margin-bottom: 35px;
line-height: 1.7;
}
/* Feature highlights */
.features {
background: linear-gradient(135deg, rgba(30, 78, 156, 0.05) 0%, rgba(0, 212, 255, 0.05) 100%);
border-radius: 12px;
padding: 30px 25px;
margin: 30px 0;
border: 1px solid rgba(30, 78, 156, 0.1);
}
.features h3 {
color: #1e4e9c;
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 20px;
margin-top: 20px;
}
.feature-item {
text-align: center;
padding: 15px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.feature-icon {
font-size: 2rem;
margin-bottom: 8px;
display: block;
}
.feature-title {
font-size: 14px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 5px;
}
.feature-desc {
font-size: 12px;
color: #6b7280;
line-height: 1.4;
}
/* CTA Button */
.cta-section {
margin: 35px 0;
padding: 25px;
}
.cta-button {
display: inline-block;
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
color: white;
text-decoration: none;
padding: 15px 35px;
border-radius: 25px;
font-weight: 600;
font-size: 16px;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(30, 78, 156, 0.3);
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(30, 78, 156, 0.4);
text-decoration: none;
color: white;
}
/* Social links */
.social-section {
margin: 30px 0;
padding: 25px;
background: #f8fafc;
border-radius: 12px;
}
.social-section h4 {
color: #1a1a1a;
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
}
.social-links {
display: flex;
justify-content: center;
gap: 15px;
}
.social-link {
display: inline-block;
width: 40px;
height: 40px;
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
color: white;
text-decoration: none;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
transition: all 0.3s ease;
}
.social-link:hover {
transform: translateY(-2px) scale(1.05);
box-shadow: 0 5px 15px rgba(30, 78, 156, 0.3);
}
/* Footer */
.footer {
background: #1a1a1a;
color: white;
padding: 30px;
text-align: center;
}
.footer-content {
margin-bottom: 20px;
}
.footer p {
margin: 5px 0;
opacity: 0.8;
font-size: 14px;
}
.unsubscribe {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.unsubscribe a {
color: #9ca3af;
text-decoration: none;
font-size: 13px;
}
.unsubscribe a:hover {
color: #00d4ff;
text-decoration: underline;
}
/* Links */
a {
color: #337cf2;
text-decoration: none;
font-weight: 500;
}
a:hover {
color: #1e4e9c;
text-decoration: underline;
}
/* Mobile responsive */
@media only screen and (max-width: 600px) {
.email-wrapper {
padding: 10px;
}
.header {
padding: 40px 20px;
}
.header h1 {
font-size: 24px;
}
.content {
padding: 30px 20px;
}
.features {
padding: 25px 20px;
}
.feature-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.social-links {
gap: 10px;
}
.footer {
padding: 25px 20px;
}
}
</style>
</head>
<body>
<div class="container">
<h2>Thanks for subscribing to RideAware newsletter!</h2>
<p>We're excited to share our journey with you.</p>
<p>If you ever wish to unsubscribe, please click <a href="{{ unsubscribe_link }}">here</a>.</p>
<div class="email-wrapper">
<div class="email-container">
<!-- Header -->
<div class="header">
<div class="welcome-icon">🎉</div>
<div class="logo">Ride<span class="logo-accent">Aware</span></div>
<h1>Welcome Aboard!</h1>
<p class="subtitle">You're now part of the RideAware community</p>
</div>
<!-- Content -->
<div class="content">
<p class="main-message">Thanks for subscribing to RideAware newsletter!</p>
<p class="description">
We're absolutely thrilled to have you join our community of passionate cyclists. Get ready for exclusive insights, training tips, feature updates, and much more delivered straight to your inbox.
</p>
<!-- What to expect -->
<div class="features">
<h3>What to expect from us:</h3>
<div class="feature-grid">
<div class="feature-item">
<span class="feature-icon">🚴‍♂️</span>
<div class="feature-title">Training Tips</div>
<div class="feature-desc">Expert advice to improve your performance</div>
</div>
<div class="feature-item">
<span class="feature-icon">📊</span>
<div class="feature-title">Performance Insights</div>
<div class="feature-desc">Data-driven analysis for better rides</div>
</div>
<div class="feature-item">
<span class="feature-icon">🆕</span>
<div class="feature-title">Feature Updates</div>
<div class="feature-desc">Be first to know about new releases</div>
</div>
<div class="feature-item">
<span class="feature-icon">👥</span>
<div class="feature-title">Community Stories</div>
<div class="feature-desc">Inspiring journeys from fellow cyclists</div>
</div>
</div>
</div>
<!-- CTA -->
<div class="cta-section">
<p style="margin-bottom: 20px;">Ready to start your journey with RideAware?</p>
<a href="https://rideaware.com" target="_blank" class="cta-button">
Explore RideAware →
</a>
</div>
<!-- Social section -->
<div class="social-section">
<h4>Stay Connected</h4>
<div class="social-links">
<a href="#" class="social-link" title="Follow us on Twitter">🐦</a>
<a href="#" class="social-link" title="Like us on Facebook">📘</a>
<a href="#" class="social-link" title="Follow us on Instagram">📷</a>
</div>
</div>
<p style="color: #6b7280; font-size: 14px; margin-top: 30px;">
We're excited to share our journey with you and help you achieve your cycling goals. Welcome to the RideAware family! 🚴‍♀️
</p>
</div>
<!-- Footer -->
<div class="footer">
<div class="footer-content">
<p><strong>RideAware Team</strong></p>
<p>Empowering cyclists, one ride at a time</p>
</div>
<div class="unsubscribe">
<p>
<a href="{{ unsubscribe_link }}">Unsubscribe</a> |
<a href="mailto:support@rideaware.com">Contact Support</a> |
</p>
<p style="font-size: 12px; color: #6b7280; margin-top: 10px;">
© 2025 RideAware. All rights reserved.
</p>
<p style="font-size: 11px; color: #9ca3af; margin-top: 8px;">
This email was sent to you because you subscribed to RideAware updates.
</p>
</div>
</div>
</div>
</div>
</body>
</html>
</html>

View file

@ -2,94 +2,179 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RideAware</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RideAware - Smart Cycling Training Platform</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
<header>
<nav>
<a href="/">
<span>Ride</span><span style="color: #1e4e9c;">Aware</span>
</a>
<a href="/newsletters">Newsletters</a>
</nav>
</header>
<main>
<section class="hero-section-1">
<div class="hero-content">
<div class="hero-text">
<img src="{{ url_for('static', filename='assets/RideAwareLogo.svg') }}" alt="RideAware Logo">
</div>
</section>
<section class="hero-section-2">
<h2>Get notified when were launching</h2>
<p>Sign up to receive updates and special offers as we prepare to launch.</p>
<!-- Navigation -->
<nav class="navbar">
<div class="nav-container">
<a href="#" class="logo">Ride<span class="logo-accent">Aware</span></a>
<ul class="nav-links">
<li><a href="#features">Features</a></li>
<li><a href="/newsletters">Newsletters</a></li>
</ul>
</div>
</nav>
<div class="subscription">
<input id="email-input" type="email" placeholder="Enter your email" required />
<button id="notify-button">Notify Me</button>
<!-- Hero Section -->
<section class="hero">
<div class="hero-container">
<div class="hero-content">
<h1>Elevate Your Cycling Journey</h1>
<p class="subtitle">The ultimate smart training platform for cyclists who demand excellence in every ride.</p>
<div class="cta-section">
<h3>Get Early Access</h3>
<p>Join thousands of cyclists waiting for launch</p>
<div class="email-form">
<input type="email" class="email-input" id="email-input" placeholder="Enter your email address" required>
<button class="notify-btn" id="notify-button">Notify Me</button>
</div>
<div class="countdown" id="countdown">
<div class="countdown-item">
<span class="countdown-number" id="days">00</span>
<span class="countdown-label">Days</span>
</div>
<div class="countdown-item">
<span class="countdown-number" id="hours">00</span>
<span class="countdown-label">Hours</span>
</div>
<div class="countdown-item">
<span class="countdown-number" id="minutes">00</span>
<span class="countdown-label">Minutes</span>
</div>
<div class="countdown-item">
<span class="countdown-number" id="seconds">00</span>
<span class="countdown-label">Seconds</span>
</div>
</div>
</div>
</div>
<div class="hero-visual">
<div class="phone-mockup">
<div class="screen">
<div class="app-interface">
<div class="app-logo">RideAware</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number">24.5</div>
<div class="stat-label">KM/H AVG</div>
</div>
<div class="stat-card">
<div class="stat-number">45</div>
<div class="stat-label">MINUTES</div>
</div>
<div class="stat-card">
<div class="stat-number">285</div>
<div class="stat-label">CALORIES</div>
</div>
<div class="stat-card">
<div class="stat-number">18.2</div>
<div class="stat-label">DISTANCE</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</section>
<section class="hero-section-3">
<h2 class="hero-sec2-header">Features</h2>
<div class="feature-cards">
<!-- Features Section -->
<section class="features" id="features">
<div class="section-header">
<h2>Powerful Features for Every Cyclist</h2>
<p>From beginners to professionals, RideAware provides comprehensive tools to optimize your training and performance.</p>
</div>
<div class="features-container">
<div class="features-grid">
<div class="feature-card">
<h3>Workout Planning</h3>
<ul>
<li><b>Customizable Training Plans:</b> Allow users to create customized training plans based on their goals and fitness level.</li>
<li><b>Workout Scheduling:</b> Provide a feature to schedule workouts and set reminders.</li>
<li><b>Goal Setting:</b> Allow users to set and track their fitness goals.</li>
<div class="feature-icon">
<i class="fas fa-calendar-alt"></i>
</div>
<h3>Smart Training Plans</h3>
<ul class="feature-list">
<li><strong>AI-Powered Planning:</strong> Customized training plans based on your goals and fitness level</li>
<li><strong>Adaptive Scheduling:</strong> Smart workout scheduling with automated reminders</li>
<li><strong>Goal Tracking:</strong> Set and monitor your cycling objectives in real-time</li>
</ul>
</div>
<div class="feature-card">
<h3>Workout Tracking</h3>
<ul>
<li><b>Workout Logging:</b> Allow users to log their workouts, including exercises, sets, reps, and weight.</li>
<li><b>Data Analysis:</b> Provide tools to analyze user data, including charts, graphs, and statistics.</li>
<li><b>Progress Tracking:</b> Allow users to track their progress over time.</li>
<div class="feature-icon">
<i class="fas fa-chart-line"></i>
</div>
<h3>Advanced Analytics</h3>
<ul class="feature-list">
<li><strong>Detailed Logging:</strong> Track exercises, sets, reps, and performance metrics</li>
<li><strong>Data Visualization:</strong> Interactive charts, graphs, and progress statistics</li>
<li><strong>Progress Insights:</strong> Monitor your improvement over time with AI analysis</li>
</ul>
</div>
<div class="feature-card">
<h3>Training and Coaching</h3>
<ul>
<li><b>Coaching and Guidance:</b> Provide coaching and guidance to help users achieve their fitness goals.</li>
<li><b>Virtual Training Rides:</b> Offer immersive virtual training rides to boost users' cycling performance.</li>
<li><b>Structured Workouts:</b> Offer structured workouts to help users improve their fitness and performance.</li>
<div class="feature-icon">
<i class="fas fa-bicycle"></i>
</div>
<h3>Virtual Training</h3>
<ul class="feature-list">
<li><strong>Expert Coaching:</strong> Professional guidance to achieve your cycling goals</li>
<li><strong>Immersive Rides:</strong> Virtual training experiences to boost performance</li>
<li><strong>Structured Workouts:</strong> Designed programs for fitness and performance gains</li>
</ul>
</div>
<div class="feature-card">
<h3>Nutrition and Recovery</h3>
<ul>
<li><b>Nutrition Planning:</b> Provide tools to help users plan and track their nutrition.</li>
<li><b>Recovery Planning:</b> Offer resources and tools to help users plan and track their recovery.</li>
<li><b>Injury Prevention and Management:</b> Provide resources and tools to help users prevent and manage injuries.</li>
<div class="feature-icon">
<i class="fas fa-heart"></i>
</div>
<h3>Health & Recovery</h3>
<ul class="feature-list">
<li><strong>Nutrition Tracking:</strong> Plan and monitor your dietary intake for optimal performance</li>
<li><strong>Recovery Optimization:</strong> Tools and resources for effective rest and recovery</li>
<li><strong>Injury Prevention:</strong> Proactive measures to prevent and manage injuries</li>
</ul>
</div>
<div class="feature-card">
<h3>Social and Community</h3>
<ul>
<li><b>Social Sharing:</b> Allow users to share their workouts and progress on social media.</li>
<li><b>Community Forum:</b> Create a community forum where users can connect with each other and share their experiences.</li>
<li><b>Leaderboards:</b> Provide leaderboards to encourage competition and motivation.</li>
<div class="feature-icon">
<i class="fas fa-users"></i>
</div>
<h3>Community & Social</h3>
<ul class="feature-list">
<li><strong>Social Sharing:</strong> Share achievements and progress on social platforms</li>
<li><strong>Active Community:</strong> Connect with fellow cyclists and share experiences</li>
<li><strong>Competitive Leaderboards:</strong> Challenge yourself against the community</li>
</ul>
</div>
<div class="feature-card">
<h3>Integration and Data</h3>
<ul>
<li><b>Integration with Wearable Devices:</b> Integrate with wearable devices to track user activity and health metrics.</li>
<li><b>Integration with Music Services:</b> Integrate with music services to provide a more engaging workout experience.</li>
<li><b>Data Import/Export:</b> Allow users to import and export their data to other platforms.</li>
<div class="feature-icon">
<i class="fas fa-sync-alt"></i>
</div>
<h3>Smart Integration</h3>
<ul class="feature-list">
<li><strong>Wearable Sync:</strong> Connect with fitness trackers and smart devices</li>
<li><strong>Music Integration:</strong> Seamlessly sync with your favorite music services</li>
<li><strong>Data Portability:</strong> Easy import/export to other cycling platforms</li>
</ul>
</div>
</div>
</section>
</main>
<footer class="normal-footer">
Copyright &copy; 2025 RideAware. All rights reserved.
</div>
</section>
<!-- Footer -->
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<script src="{{ url_for('static', filename='js/countdown.js') }}"></script>
</body>
</html>
</html>

View file

@ -1,32 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RideAware - Newsletter Detail</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RideAware - {{ newsletter.subject if newsletter else 'Newsletter Detail' }}</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/newsletter_styles.css') }}">
</head>
<body>
<header>
<nav>
<a href="/">
<span>Ride</span><span style="color: #1e4e9c;">Aware</span>
</a>
<a href="/newsletters">Newsletters</a>
<!-- Navigation -->
<nav class="navbar">
<div class="nav-container">
<a href="/" class="logo">Ride<span class="logo-accent">Aware</span></a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/newsletters">Newsletters</a></li>
</ul>
</div>
</nav>
</header>
<main>
<a href="/newsletters" class="back-link">← Back to Newsletters</a>
<h1>{{ newsletter.subject }}</h1>
<div class="newsletter-content">
{{ newsletter.body | safe }}
</div>
</main>
<footer class="normal-footer">
<p>© 2025 RideAware. All rights reserved.</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<!-- Back Navigation -->
<div class="back-navigation">
<a href="/newsletters" class="back-link">
<i class="fas fa-arrow-left"></i>
Back to Newsletters
</a>
</div>
<!-- Main Content -->
<main class="main-content">
<!-- Newsletter Header -->
<div class="newsletter-header">
<div class="newsletter-icon">
<i class="fas fa-envelope-open-text"></i>
</div>
<h1>{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h1>
<div class="newsletter-meta">
<div class="meta-item">
<i class="fas fa-calendar-alt"></i>
<span>{{ newsletter.sent_at if newsletter else 'Published Date' }}</span>
</div>
{% if newsletter and newsletter.get('reading_time') %}
<div class="meta-item">
<i class="fas fa-clock"></i>
<span>{{ newsletter.reading_time }} min read</span>
</div>
{% endif %}
{% if newsletter and newsletter.get('author') %}
<div class="meta-item">
<i class="fas fa-user"></i>
<span>{{ newsletter.author }}</span>
</div>
{% endif %}
</div>
{% if newsletter and newsletter.get('tags') %}
<div class="newsletter-tags">
{% for tag in newsletter.tags %}
<span class="tag">{{ tag }}</span>
{% endfor %}
</div>
{% else %}
<div class="newsletter-tags">
<span class="tag">Cycling Tips</span>
<span class="tag">Training</span>
<span class="tag">Performance</span>
</div>
{% endif %}
</div>
<!-- Newsletter Content -->
<article class="newsletter-content">
{% if newsletter %}
{{ newsletter.body | safe }}
{% else %}
<h2>Welcome to RideAware Newsletter</h2>
<p>This is a sample newsletter content that demonstrates the modern, clean design of our newsletter system. The content would typically include cycling tips, training advice, and product updates.</p>
<h3>This Week's Highlights</h3>
<ul>
<li>New training features released</li>
<li>Community spotlight on top performers</li>
<li>Upcoming events and challenges</li>
<li>Expert tips from professional cyclists</li>
</ul>
<blockquote>
"The bicycle is a curious vehicle. Its passenger is its engine." - John Howard
</blockquote>
<p>Stay tuned for more exciting content and updates from the RideAware team. We're committed to helping you achieve your cycling goals with the best tools and community support.</p>
{% endif %}
</article>
<!-- Action Buttons -->
<div class="newsletter-actions">
<a href="/newsletters" class="action-btn primary">
<i class="fas fa-list"></i>
View All Newsletters
</a>
<button onclick="window.print()" class="action-btn secondary">
<i class="fas fa-print"></i>
Print Newsletter
</button>
<button onclick="shareNewsletter()" class="action-btn secondary">
<i class="fas fa-share-alt"></i>
Share
</button>
</div>
</main>
<!-- Footer -->
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>
</html>

View file

@ -1,40 +1,91 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RideAware - Newsletters</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RideAware - Newsletters</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/newsletter_styles.css') }}">
</head>
<body>
<header>
<nav>
<a href="/">
<span>Ride</span><span style="color: #1e4e9c;">Aware</span>
</a>
<a href="/newsletters" class="active">Newsletters</a>
</nav>
</header>
<main class="newsletter-main">
<h1>RideAware Newsletters</h1>
{% if newsletters %}
{% for nl in newsletters %}
<div class="newsletter">
<h2>
<a href="/newsletter/{{ nl['id'] }}">{{ nl['subject'] }}</a>
</h2>
<p class="newsletter-time">Sent on: {{ nl['sent_at'] }}</p>
<a href="/newsletter/{{ nl['id'] }}" class="read-more">Read More</a>
<!-- Navigation -->
<nav class="navbar">
<div class="nav-container">
<a href="/" class="logo">Ride<span class="logo-accent">Aware</span></a>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/newsletters" class="active">Newsletters</a></li>
</ul>
</div>
{% endfor %}
{% else %}
<p>No newsletters to display yet.</p>
{% endif %}
</main>
<footer class="fixed-footer">
<p>© 2025 RideAware. All rights reserved.</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</nav>
<!-- Page Header -->
<section class="page-header">
<div class="page-header-content">
<div class="header-icon">
<i class="fas fa-newspaper"></i>
</div>
<h1>RideAware Newsletters</h1>
<p>Stay updated with the latest cycling tips, training insights, and product updates from our team.</p>
</div>
</section>
<!-- Main Content -->
<main class="main-content">
{% if newsletters %}
<div class="newsletters-grid">
{% for nl in newsletters %}
<article class="newsletter-card">
<div class="newsletter-header">
<div class="newsletter-icon">
<i class="fas fa-envelope-open-text"></i>
</div>
<div class="newsletter-info">
<h2>
<a href="/newsletter/{{ nl['id'] }}">{{ nl['subject'] }}</a>
</h2>
</div>
</div>
<div class="newsletter-date">
<i class="fas fa-calendar-alt"></i>
<span>Sent on: {{ nl['sent_at'] }}</span>
</div>
<div class="newsletter-excerpt">
{% if nl.get('preview') %}
{{ nl['preview'][:150] }}...
{% else %}
Get the latest updates on cycling training, performance tips, and RideAware features in this newsletter edition.
{% endif %}
</div>
<a href="/newsletter/{{ nl['id'] }}" class="read-more-btn">
Read Full Newsletter
<i class="fas fa-arrow-right"></i>
</a>
</article>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<div class="empty-icon">
<i class="fas fa-inbox"></i>
</div>
<h3>No Newsletters Yet</h3>
<p>We're working on some amazing content for you. Subscribe to be the first to know when we publish our newsletters!</p>
<a href="/" class="subscribe-prompt">
<i class="fas fa-bell"></i>
Subscribe for Updates
</a>
</div>
{% endif %}
</main>
<!-- Footer -->
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>
</html>

View file

@ -1,98 +1,455 @@
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0;
padding: 0;
}
.container {
max-width: 750px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h1, h2 {
color: #007bff;
}
h1 {
text-align: center;
}
ul {
padding-left: 20px;
}
.footer {
text-align: center;
margin-top: 20px;
font-size: 0.9em;
color: #666;
}
a {
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🚀 RideAware Development Update</title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<style>
/* Reset and base styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #1a1a1a;
background-color: #f8fafc;
margin: 0;
padding: 0;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
/* Container */
.email-container {
max-width: 650px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(30, 78, 156, 0.1);
overflow: hidden;
}
.email-wrapper {
background-color: #f8fafc;
padding: 20px;
}
/* Header */
.header {
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 50%, #00d4ff 100%);
padding: 40px 30px;
text-align: center;
position: relative;
}
.header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="1" fill="rgba(255,255,255,0.1)"/></pattern></defs><rect width="100%" height="100%" fill="url(%23dots)"/></svg>');
opacity: 0.3;
}
.logo {
font-size: 28px;
font-weight: 700;
color: white;
text-decoration: none;
position: relative;
z-index: 1;
}
.logo-accent {
color: #00d4ff;
}
.header h1 {
color: white;
font-size: 32px;
font-weight: 800;
margin: 20px 0 10px;
position: relative;
z-index: 1;
}
.header .subtitle {
color: rgba(255, 255, 255, 0.9);
font-size: 16px;
font-weight: 300;
position: relative;
z-index: 1;
}
/* Content */
.content {
padding: 40px 30px;
}
.greeting {
font-size: 18px;
color: #1a1a1a;
margin-bottom: 20px;
font-weight: 500;
}
.intro {
font-size: 16px;
color: #374151;
margin-bottom: 30px;
line-height: 1.7;
}
/* Section styling */
.section {
margin-bottom: 35px;
background: #f8fafc;
border-radius: 12px;
padding: 25px;
border-left: 4px solid #337cf2;
}
.section h2 {
color: #1e4e9c;
font-size: 22px;
font-weight: 700;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.section-icon {
font-size: 20px;
}
.feature-list {
list-style: none;
padding: 0;
margin: 0;
}
.feature-list li {
margin-bottom: 15px;
padding-left: 20px;
position: relative;
font-size: 15px;
line-height: 1.6;
color: #374151;
}
.feature-list li::before {
content: '✓';
position: absolute;
left: 0;
top: 0;
color: #10b981;
font-weight: bold;
font-size: 16px;
}
.feature-list li strong {
color: #1a1a1a;
font-weight: 600;
}
.feature-list li code {
background: rgba(30, 78, 156, 0.1);
color: #1e4e9c;
padding: 2px 6px;
border-radius: 4px;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 13px;
}
/* Next steps */
.next-steps {
background: linear-gradient(135deg, rgba(30, 78, 156, 0.05) 0%, rgba(0, 212, 255, 0.05) 100%);
border-radius: 12px;
padding: 25px;
margin: 30px 0;
border: 1px solid rgba(30, 78, 156, 0.1);
}
.next-steps h2 {
color: #1e4e9c;
font-size: 20px;
margin-bottom: 15px;
}
.next-steps ul {
list-style: none;
padding: 0;
margin: 0;
}
.next-steps li {
margin-bottom: 10px;
padding-left: 25px;
position: relative;
color: #374151;
}
.next-steps li::before {
content: '→';
position: absolute;
left: 0;
color: #337cf2;
font-weight: bold;
}
/* CTA Button */
.cta-section {
text-align: center;
margin: 35px 0;
padding: 30px;
background: white;
border-radius: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.cta-button {
display: inline-block;
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
color: white;
text-decoration: none;
padding: 15px 30px;
border-radius: 25px;
font-weight: 600;
font-size: 16px;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(30, 78, 156, 0.3);
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(30, 78, 156, 0.4);
text-decoration: none;
color: white;
}
/* Footer */
.footer {
background: #1a1a1a;
color: white;
padding: 30px;
text-align: center;
}
.footer p {
margin: 5px 0;
opacity: 0.8;
}
.team-signature {
font-weight: 600;
color: #00d4ff;
margin-top: 15px;
}
.unsubscribe {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.unsubscribe a {
color: #9ca3af;
text-decoration: none;
font-size: 14px;
}
.unsubscribe a:hover {
color: #00d4ff;
text-decoration: underline;
}
/* Links */
a {
color: #337cf2;
text-decoration: none;
font-weight: 500;
}
a:hover {
color: #1e4e9c;
text-decoration: underline;
}
/* Mobile responsive */
@media only screen and (max-width: 600px) {
.email-wrapper {
padding: 10px;
}
.header {
padding: 30px 20px;
}
.header h1 {
font-size: 24px;
}
.content {
padding: 30px 20px;
}
.section {
padding: 20px 15px;
}
.section h2 {
font-size: 18px;
}
.cta-section {
padding: 20px;
}
.footer {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 RideAware Development Update</h1>
<p>Dear RideAware Community,</p>
<p>Were excited to share the latest updates on the development of the RideAware platform! Over the past few weeks, weve been hard at work implementing new features, improving the backend infrastructure, and enhancing the user experience. Heres a summary of what weve accomplished:</p>
<div class="email-wrapper">
<div class="email-container">
<!-- Header -->
<div class="header">
<div class="logo">Ride<span class="logo-accent">Aware</span></div>
<h1>🚀 Development Update</h1>
<p class="subtitle">Latest progress on your favorite cycling platform</p>
</div>
<h2>🔒 User Authentication and Security</h2>
<ul>
<li><strong>Signup and Login System:</strong> Weve implemented a robust user authentication system that allows users to securely sign up and log in to the platform. Passwords are hashed using industry-standard algorithms (<code>pbkdf2:sha256</code>) to ensure user data is stored securely.</li>
<li><strong>Error Handling and Validation:</strong> Input validation has been added to ensure usernames and passwords meet security and usability standards. Users are notified of errors such as invalid credentials or duplicate accounts with clear and helpful messages.</li>
<li><strong>Logout Functionality:</strong> A logout feature has been added, allowing users to securely end their sessions.</li>
</ul>
<!-- Content -->
<div class="content">
<p class="greeting">Dear RideAware Community,</p>
<p class="intro">
We're excited to share the latest updates on the development of the RideAware platform! Over the past few weeks, we've been hard at work implementing new features, improving the backend infrastructure, and enhancing the user experience. Here's a summary of what we've accomplished:
</p>
<h2>👤 User Profiles</h2>
<ul>
<li><strong>User Profile Creation:</strong> A new <code>UserProfile</code> system has been introduced, allowing users to store additional information such as their first name, last name, bio, and profile picture.</li>
<li><strong>Automatic Profile Creation:</strong> User profiles are now automatically created when a new user account is registered, ensuring a seamless onboarding experience.</li>
<li><strong>One-to-One Relationship:</strong> The backend now supports a one-to-one relationship between users and their profiles, making it easy to manage and query user data.</li>
</ul>
<!-- User Authentication Section -->
<div class="section">
<h2><span class="section-icon">🔒</span> User Authentication and Security</h2>
<ul class="feature-list">
<li><strong>Signup and Login System:</strong> We've implemented a robust user authentication system that allows users to securely sign up and log in to the platform. Passwords are hashed using industry-standard algorithms (<code>pbkdf2:sha256</code>) to ensure user data is stored securely.</li>
<li><strong>Error Handling and Validation:</strong> Input validation has been added to ensure usernames and passwords meet security and usability standards. Users are notified of errors such as invalid credentials or duplicate accounts with clear and helpful messages.</li>
<li><strong>Logout Functionality:</strong> A logout feature has been added, allowing users to securely end their sessions.</li>
</ul>
</div>
<h2>🛠 Backend Improvements</h2>
<ul>
<li><strong>PostgreSQL Integration:</strong> Weve migrated from a local SQLite database to a robust PostgreSQL database hosted on a separate server. This change improves scalability, performance, and environment separation.</li>
<li><strong>SQLAlchemy ORM:</strong> The backend now uses SQLAlchemy for database interactions, simplifying the codebase and improving maintainability.</li>
<li><strong>Error Logging and Debugging:</strong> Enhanced logging has been added to track issues during signup, login, and database operations. This ensures that any problems can be quickly identified and resolved.</li>
</ul>
<!-- User Profiles Section -->
<div class="section">
<h2><span class="section-icon">👤</span> User Profiles</h2>
<ul class="feature-list">
<li><strong>User Profile Creation:</strong> A new <code>UserProfile</code> system has been introduced, allowing users to store additional information such as their first name, last name, bio, and profile picture.</li>
<li><strong>Automatic Profile Creation:</strong> User profiles are now automatically created when a new user account is registered, ensuring a seamless onboarding experience.</li>
<li><strong>One-to-One Relationship:</strong> The backend now supports a one-to-one relationship between users and their profiles, making it easy to manage and query user data.</li>
</ul>
</div>
<h2>🌐 Frontend Enhancements</h2>
<ul>
<li><strong>Vue.js Login Component:</strong> A new login component has been developed using Vue.js, providing a clean and user-friendly interface for authentication.</li>
<li><strong>Error Feedback:</strong> The frontend now displays clear error messages for invalid login attempts or missing input fields, improving the user experience.</li>
<li><strong>Environment-Specific API Configuration:</strong> The frontend now dynamically uses environment variables to configure the API base URL, making it easier to switch between development and production environments.</li>
</ul>
<!-- Backend Improvements Section -->
<div class="section">
<h2><span class="section-icon">🛠</span> Backend Improvements</h2>
<ul class="feature-list">
<li><strong>PostgreSQL Integration:</strong> We've migrated from a local SQLite database to a robust PostgreSQL database hosted on a separate server. This change improves scalability, performance, and environment separation.</li>
<li><strong>SQLAlchemy ORM:</strong> The backend now uses SQLAlchemy for database interactions, simplifying the codebase and improving maintainability.</li>
<li><strong>Error Logging and Debugging:</strong> Enhanced logging has been added to track issues during signup, login, and database operations. This ensures that any problems can be quickly identified and resolved.</li>
</ul>
</div>
<h2>📧 Newsletter System</h2>
<ul>
<li><strong>User Notifications:</strong> A foundation has been laid for a newsletter system, allowing users to stay updated on the latest developments and announcements.</li>
<li><strong>Unsubscribe Links:</strong> Unsubscribe links are now included in all emails, ensuring compliance with best practices and user preferences.</li>
</ul>
<!-- Frontend Enhancements Section -->
<div class="section">
<h2><span class="section-icon">🌐</span> Frontend Enhancements</h2>
<ul class="feature-list">
<li><strong>Vue.js Login Component:</strong> A new login component has been developed using Vue.js, providing a clean and user-friendly interface for authentication.</li>
<li><strong>Error Feedback:</strong> The frontend now displays clear error messages for invalid login attempts or missing input fields, improving the user experience.</li>
<li><strong>Environment-Specific API Configuration:</strong> The frontend now dynamically uses environment variables to configure the API base URL, making it easier to switch between development and production environments.</li>
</ul>
</div>
<h2>🎯 Whats Next?</h2>
<p>Looking ahead, were planning to:</p>
<ul>
<li>Implement a password reset feature for users who forget their credentials.</li>
<li>Add two-factor authentication (2FA) for enhanced account security.</li>
<li>Build a dashboard for users to manage their profiles and preferences.</li>
<li>Continue refining the frontend design for a more polished user experience.</li>
</ul>
<!-- Newsletter System Section -->
<div class="section">
<h2><span class="section-icon">📧</span> Newsletter System</h2>
<ul class="feature-list">
<li><strong>User Notifications:</strong> A foundation has been laid for a newsletter system, allowing users to stay updated on the latest developments and announcements.</li>
<li><strong>Unsubscribe Links:</strong> Unsubscribe links are now included in all emails, ensuring compliance with best practices and user preferences.</li>
</ul>
</div>
<h2>💡 Get Involved</h2>
<p>Were proud to share that the RideAware platform is open source! If youre a developer or enthusiast, you can view the codebase, contribute to the project, or provide feedback. Check out the repository here: <a href="https://github.com/rideaware" target="_blank">RideAware GitHub</a>.</p>
<!-- What's Next Section -->
<div class="next-steps">
<h2>🎯 What's Next?</h2>
<p>Looking ahead, we're planning to:</p>
<ul>
<li>Implement a password reset feature for users who forget their credentials.</li>
<li>Add two-factor authentication (2FA) for enhanced account security.</li>
<li>Build a dashboard for users to manage their profiles and preferences.</li>
<li>Continue refining the frontend design for a more polished user experience.</li>
</ul>
</div>
<p>Thank you for your continued support as we build RideAware into a platform that empowers cyclists and fosters a connected community. Stay tuned for more updates!</p>
<!-- CTA Section -->
<div class="cta-section">
<h2>💡 Get Involved</h2>
<p style="margin-bottom: 20px;">We're proud to share that the RideAware platform is open source! If you're a developer or enthusiast, you can view the codebase, contribute to the project, or provide feedback.</p>
<a href="https://github.com/rideaware" target="_blank" class="cta-button">
Visit GitHub Repository →
</a>
</div>
<p>Best regards,</p>
<p><strong>The RideAware Development Team 🚴‍♂️</strong></p>
</div>
<p>Thank you for your continued support as we build RideAware into a platform that empowers cyclists and fosters a connected community. Stay tuned for more updates!</p>
</div>
<!-- Footer -->
<div class="footer">
<p>Best regards,</p>
<p class="team-signature">The RideAware Development Team 🚴‍♂️</p>
<div class="unsubscribe">
<p>
<a href="{{ unsubscribe_link }}">Unsubscribe</a> |
<a href="mailto:support@rideaware.com">Contact Support</a>
</p>
<p style="font-size: 12px; color: #9ca3af; margin-top: 10px;">
© 2025 RideAware. All rights reserved.
</p>
</div>
</div>
</div>
</div>
</body>
</html>