chore(ui): Formatted and cleaned up the code

This commit is contained in:
Cipher Vance 2025-08-31 13:25:12 -05:00
parent ffdc4cde38
commit 46093d2b56
5 changed files with 638 additions and 611 deletions

View file

@ -1,4 +1,3 @@
{% set is_home = is_home | default(false) %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -9,17 +8,30 @@
/> />
<title>{% block title %}RideAware{% endblock %}</title> <title>{% block title %}RideAware{% endblock %}</title>
<!-- Icons/Fonts -->
<link <link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
rel="stylesheet" rel="stylesheet"
/> />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
rel="stylesheet"
/>
<!-- Core CSS -->
<link <link
rel="stylesheet" rel="stylesheet"
href="{{ url_for('static', filename='css/styles.css') }}" href="{{ url_for('static', filename='css/styles.css') }}"
/> />
<!-- Favicons -->
<link
rel="icon"
type="image/png"
sizes="32x32"
href="{{ url_for('static', filename='assets/32x32.png') }}"
/>
<link <link
rel="alternate icon" rel="alternate icon"
type="image/png" type="image/png"
@ -35,22 +47,31 @@
rel="manifest" rel="manifest"
href="{{ url_for('static', filename='assets/site.webmanifest') }}" href="{{ url_for('static', filename='assets/site.webmanifest') }}"
/> />
<meta <meta name="theme-color" content="#0f172a" />
name="theme-color"
content="#0f172a"
/>
{% block extra_head %}{% endblock %} {% block extra_head %}{% endblock %}
</head> </head>
<body> <body>
{% set is_home = is_home | default(false) %}
<nav class="navbar"> <nav class="navbar">
<div class="nav-container"> <div class="nav-container">
<a href="/" class="logo">Ride<span class="logo-accent">Aware</span></a> <a href="{{ url_for('index') }}" class="logo" aria-label="RideAware home">
<img
src="{{ url_for('static', filename='assets/logo.png') }}"
alt="RideAware"
class="logo-img"
width="140"
height="28"
decoding="async"
fetchpriority="high"
/>
</a>
<ul class="nav-links"> <ul class="nav-links">
{% if is_home %} {% if is_home %}
<li><a href="#features">Features</a></li> <li><a href="#features">Features</a></li>
{% endif %} {% endif %}
<li><a href="/newsletters">Newsletters</a></li> <li><a href="{{ url_for('newsletters') }}">Newsletters</a></li>
</ul> </ul>
</div> </div>
</nav> </nav>
@ -61,6 +82,7 @@
<p>&copy; 2025 RideAware. All rights reserved.</p> <p>&copy; 2025 RideAware. All rights reserved.</p>
</footer> </footer>
<!-- Core JS -->
<script <script
defer defer
src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js" src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js"

View file

@ -1,392 +1,367 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Welcome to RideAware!</title> <meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<!--[if mso]> <!--[if mso]>
<noscript> <noscript>
<xml> <xml>
<o:OfficeDocumentSettings> <o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch> <o:PixelsPerInch>96</o:PixelsPerInch>
<o:AllowPNG/>
</o:OfficeDocumentSettings> </o:OfficeDocumentSettings>
</xml> </xml>
</noscript> </noscript>
<![endif]--> <![endif]-->
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Welcome to RideAware!</title>
<style> <style>
/* Reset and base styles */ /* Basic resets (email-safe) */
* { html,
margin: 0;
padding: 0;
box-sizing: border-box;
}
body { body {
margin: 0; margin: 0 !important;
padding: 0; padding: 0 !important;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; height: 100% !important;
line-height: 1.6; width: 100% !important;
color: #1a1a1a; }
background-color: #f8fafc; * {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%; -ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
} }
table,
table { td {
border-collapse: collapse; mso-table-lspace: 0pt !important;
mso-table-lspace: 0pt; mso-table-rspace: 0pt !important;
mso-table-rspace: 0pt;
} }
img { img {
-ms-interpolation-mode: bicubic;
border: 0; border: 0;
max-width: 100%;
height: auto;
line-height: 100%;
outline: none; outline: none;
text-decoration: none; text-decoration: none;
display: block;
height: auto;
max-width: 100%;
} }
/* Wrapper/background */
/* Email container */ .bg {
.email-wrapper { background-color: #f8fafc;
}
/* Container */
.container {
width: 100%;
max-width: 600px; max-width: 600px;
margin: 0 auto; margin: 0 auto;
background-color: #ffffff; background-color: #ffffff;
} }
/* Header */
/* Header styles */
.header { .header {
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%); background: #1e4e9c;
background-color: #1e4e9c; /* Fallback */ background-image: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
padding: 50px 30px; padding: 40px 24px;
text-align: center; text-align: center;
color: white; color: #ffffff;
} }
.logo-text {
.welcome-icon { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
font-size: 3rem; Helvetica, Arial, sans-serif;
margin-bottom: 20px; font-weight: 800;
display: block;
}
.logo {
font-size: 24px; font-size: 24px;
font-weight: 700; line-height: 1.2;
color: white; color: #ffffff;
margin-bottom: 15px; margin: 0 0 8px 0;
display: block;
} }
.logo-accent { .logo-accent {
color: #00d4ff; color: #00d4ff;
} }
.header-title {
.header h1 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
color: white; Helvetica, Arial, sans-serif;
font-size: 28px; font-size: 26px;
font-weight: 800; font-weight: 800;
margin: 0 0 10px; margin: 6px 0 6px 0;
color: #ffffff;
} }
.subtitle { .subtitle {
color: rgba(255, 255, 255, 0.9); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
font-size: 16px; Helvetica, Arial, sans-serif;
font-weight: 300; font-size: 15px;
color: rgba(255, 255, 255, 0.92);
margin: 0; margin: 0;
} }
/* Content */
/* Content styles */
.content { .content {
padding: 40px 30px; padding: 32px 24px;
text-align: center; text-align: center;
} }
.main-message { .main-message {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 18px; font-size: 18px;
color: #1a1a1a; color: #1a1a1a;
margin-bottom: 25px; font-weight: 600;
font-weight: 500; margin: 0 0 16px 0;
} }
.description { .description {
font-size: 16px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 15px;
color: #6b7280; color: #6b7280;
margin-bottom: 35px; line-height: 1.6;
line-height: 1.7; margin: 0 0 24px 0;
}
/* Feature block */
.features-wrap {
padding: 0 24px 24px 24px;
} }
/* Feature highlights */
.features { .features {
background: linear-gradient(135deg, rgba(30, 78, 156, 0.05) 0%, rgba(0, 212, 255, 0.05) 100%); border: 1px solid rgba(30, 78, 156, 0.12);
background-color: #f8fafc; /* Fallback */
border-radius: 12px; border-radius: 12px;
padding: 30px 25px; background-color: #ffffff;
margin: 30px 0; padding: 20px;
border: 1px solid rgba(30, 78, 156, 0.1);
} }
.features-title {
.features h3 { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
color: #1e4e9c; color: #1e4e9c;
font-size: 20px; font-size: 18px;
font-weight: 700; font-weight: 700;
margin-bottom: 20px; margin: 0 0 12px 0;
}
.feature-grid {
width: 100%;
}
.feature-item {
text-align: center; text-align: center;
padding: 15px; }
background: white; .feature-item {
width: 100%;
text-align: left;
padding: 10px 12px;
border-radius: 10px; border-radius: 10px;
margin-bottom: 15px; background: #ffffff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); border: 1px solid rgba(2, 6, 23, 0.05);
margin-bottom: 10px;
} }
.feature-icon {
font-size: 2rem;
margin-bottom: 8px;
display: block;
}
.feature-title { .feature-title {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: #1a1a1a; color: #1a1a1a;
margin-bottom: 5px; margin: 0 0 4px 0;
} }
.feature-desc { .feature-desc {
font-size: 12px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 13px;
color: #6b7280; color: #6b7280;
line-height: 1.4; margin: 0;
} }
/* CTA */
/* CTA styles */ .cta {
.cta-section { padding: 8px 24px 32px 24px;
margin: 35px 0;
padding: 25px;
}
.cta-button {
display: inline-block;
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
background-color: #1e4e9c; /* Fallback */
color: white !important;
text-decoration: none;
padding: 15px 35px;
border-radius: 25px;
font-weight: 600;
font-size: 16px;
box-shadow: 0 5px 15px rgba(30, 78, 156, 0.3);
}
.cta-button:hover {
background-color: #337cf2;
text-decoration: none;
}
/* Social section */
.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 {
text-align: center; text-align: center;
} }
.cta-btn {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
display: inline-block;
background: #1e4e9c;
background-image: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
color: #ffffff !important;
text-decoration: none;
padding: 14px 28px;
border-radius: 999px;
font-weight: 700;
font-size: 16px;
}
/* Social */
.social {
background-color: #f8fafc;
padding: 20px 24px;
text-align: center;
border-radius: 12px;
margin: 0 24px 24px 24px;
}
.social-title {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 15px;
font-weight: 700;
margin: 0 0 10px 0;
color: #1a1a1a;
}
.social-link { .social-link {
display: inline-block; display: inline-block;
width: 40px; width: 40px;
height: 40px; height: 40px;
background: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
background-color: #1e4e9c; /* Fallback */
color: white;
text-decoration: none; text-decoration: none;
color: #ffffff !important;
border-radius: 50%; border-radius: 50%;
line-height: 40px; line-height: 40px;
font-size: 16px;
margin: 0 7px;
text-align: center; text-align: center;
margin: 0 6px;
background-image: linear-gradient(135deg, #1e4e9c 0%, #337cf2 100%);
} }
/* Footer */
.social-link:hover {
background-color: #337cf2;
}
/* Footer styles */
.footer { .footer {
background: #1a1a1a; background: #1a1a1a;
color: white; color: #ffffff;
padding: 30px;
text-align: center; text-align: center;
padding: 24px;
} }
.footer p {
.footer-content { margin: 6px 0;
margin-bottom: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
font-size: 13px;
} }
.footer-content p {
margin: 5px 0;
font-size: 14px;
}
.unsubscribe { .unsubscribe {
margin-top: 20px; border-top: 1px solid rgba(255, 255, 255, 0.12);
padding-top: 20px; margin-top: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.1); padding-top: 14px;
} }
.unsubscribe a { .unsubscribe a {
color: #9ca3af; color: #9ca3af !important;
text-decoration: none; text-decoration: none;
font-size: 13px; font-size: 13px;
} }
.unsubscribe a:hover { .unsubscribe a:hover {
color: #00d4ff; color: #00d4ff !important;
text-decoration: underline; text-decoration: underline;
} }
/* Mobile */
/* Mobile responsive */
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
.email-wrapper {
width: 100% !important;
}
.header { .header {
padding: 40px 20px !important; padding: 32px 18px !important;
} }
.header h1 {
font-size: 24px !important;
}
.content { .content {
padding: 30px 20px !important; padding: 24px 18px !important;
} }
.features { .features {
padding: 25px 20px !important; padding: 16px !important;
}
.feature-item {
margin-bottom: 10px !important;
}
.social-link {
margin: 0 5px !important;
} }
} }
</style> </style>
</head> </head>
<body> <body class="bg">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #f8fafc;"> <center role="article" aria-roledescription="email">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr> <tr>
<td align="center"> <td align="center">
<div class="email-wrapper"> <table role="presentation" class="container" width="600" cellspacing="0" cellpadding="0" border="0">
<!-- Header --> <!-- Header -->
<div class="header"> <tr>
<div class="welcome-icon">🎉</div> <td class="header">
<div class="logo">Ride<span class="logo-accent">Aware</span></div> <!-- Optional image logo: replace src if you prefer image instead of text -->
<h1>Welcome Aboard!</h1> <!--
<p class="subtitle">You're now part of the RideAware community</p> <img src="https://your-cdn/rideaware-logo.png" alt="RideAware" width="140" height="28" />
</div> -->
<div class="logo-text">Ride<span class="logo-accent">Aware</span></div>
<!-- Content --> <div style="font-size: 36px; line-height: 1; margin-bottom: 10px;" aria-hidden="true">🎉</div>
<div class="content"> <div class="header-title">Welcome Aboard!</div>
<p class="main-message">Thanks for subscribing to RideAware newsletter!</p> <div class="subtitle">You're now part of the RideAware community</div>
</td>
</tr>
<!-- Body -->
<tr>
<td class="content">
<p class="main-message">Thanks for subscribing to the RideAware newsletter!</p>
<p class="description"> <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. Were thrilled to have you with us. Expect training tips, performance insights,
product news, and community highlights—delivered straight to your inbox.
</p> </p>
</td>
</tr>
<!-- Features --> <!-- Features -->
<div class="features"> <tr>
<h3>What to expect from us:</h3> <td class="features-wrap">
<div class="feature-grid"> <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" class="features">
<div class="feature-item"> <tr>
<span class="feature-icon">🚴‍♂️</span> <td align="center" style="padding-bottom: 10px;">
<div class="features-title">What to expect from us</div>
</td>
</tr>
<tr>
<td>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td class="feature-item">
<div class="feature-title">Training Tips</div> <div class="feature-title">Training Tips</div>
<div class="feature-desc">Expert advice to improve your performance</div> <div class="feature-desc">Actionable advice to improve your performance.</div>
</div> </td>
<div class="feature-item"> </tr>
<span class="feature-icon">📊</span> <tr>
<td class="feature-item">
<div class="feature-title">Performance Insights</div> <div class="feature-title">Performance Insights</div>
<div class="feature-desc">Data-driven analysis for better rides</div> <div class="feature-desc">Data-driven analysis for smarter rides.</div>
</div> </td>
<div class="feature-item"> </tr>
<span class="feature-icon">🆕</span> <tr>
<td class="feature-item">
<div class="feature-title">Feature Updates</div> <div class="feature-title">Feature Updates</div>
<div class="feature-desc">Be first to know about new releases</div> <div class="feature-desc">Be first to know about new releases.</div>
</div> </td>
<div class="feature-item"> </tr>
<span class="feature-icon">👥</span> <tr>
<td class="feature-item" style="margin-bottom: 0;">
<div class="feature-title">Community Stories</div> <div class="feature-title">Community Stories</div>
<div class="feature-desc">Inspiring journeys from fellow cyclists</div> <div class="feature-desc">Inspiring journeys from fellow cyclists.</div>
</div> </td>
</div> </tr>
</div> </table>
</td>
</tr>
</table>
</td>
</tr>
<!-- CTA --> <!-- CTA -->
<div class="cta-section"> <tr>
<p style="margin-bottom: 20px;">Ready to start your journey with RideAware?</p> <td class="cta" align="center">
<a href="https://rideaware.com" target="_blank" class="cta-button"> <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; color:#1a1a1a; font-size:15px; margin: 0 0 12px 0;">
Explore RideAware → Ready to start your journey with 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> </p>
<a href="https://rideaware.org" target="_blank" class="cta-btn">Explore RideAware →</a>
</td>
</tr>
<!-- Social -->
<tr>
<td>
<div class="social">
<div class="social-title">Stay Connected</div>
<a href="https://twitter.com" class="social-link" title="Twitter" aria-label="Twitter">T</a>
<a href="https://facebook.com" class="social-link" title="Facebook" aria-label="Facebook">f</a>
<a href="https://instagram.com" class="social-link" title="Instagram" aria-label="Instagram">IG</a>
</div> </div>
</td>
</tr>
<!-- Footer --> <!-- Footer -->
<div class="footer"> <tr>
<div class="footer-content"> <td class="footer">
<p><strong>RideAware Team</strong></p> <p><strong>RideAware Team</strong></p>
<p>Empowering cyclists, one ride at a time</p> <p>Empowering cyclists, one ride at a time</p>
</div>
<div class="unsubscribe"> <div class="unsubscribe">
<p> <p style="margin: 0;">
<a href="{{ unsubscribe_link }}">Unsubscribe</a> | <a href="{{ unsubscribe_link }}">Unsubscribe</a>
&nbsp;|&nbsp;
<a href="mailto:support@rideaware.com">Contact Support</a> <a href="mailto:support@rideaware.com">Contact Support</a>
</p> </p>
<p style="font-size: 12px; color: #6b7280; margin-top: 10px;"> <p style="font-size: 12px; color: #9ca3af;">
© 2025 RideAware. All rights reserved. © 2025 RideAware. All rights reserved.
</p> </p>
<p style="font-size: 11px; color: #9ca3af; margin-top: 8px;"> <p style="font-size: 11px; color: #9ca3af;">
This email was sent to you because you subscribed to RideAware updates. You received this email because you subscribed to RideAware updates.
</p> </p>
</div> </div>
</div>
</div>
</td> </td>
</tr> </tr>
</table> </table>
</td>
</tr>
</table>
</center>
</body> </body>
</html> </html>

View file

@ -1,4 +1,3 @@
<!-- templates/index.html -->
{% extends "base.html" %} {% extends "base.html" %}
{% block title %}RideAware - Smart Cycling Training Platform{% endblock %} {% block title %}RideAware - Smart Cycling Training Platform{% endblock %}
@ -10,8 +9,8 @@
<div class="hero-content"> <div class="hero-content">
<h1>Elevate Your Cycling Journey</h1> <h1>Elevate Your Cycling Journey</h1>
<p class="subtitle"> <p class="subtitle">
The ultimate smart training platform for cyclists who demand excellence The ultimate smart training platform for cyclists who demand
in every ride. excellence in every ride.
</p> </p>
<div class="cta-section"> <div class="cta-section">
@ -35,7 +34,18 @@
<div class="phone-mockup"> <div class="phone-mockup">
<div class="screen"> <div class="screen">
<div class="app-interface"> <div class="app-interface">
<div class="app-brand">
<img
src="{{ url_for('static', filename='assets/32x32.png') }}"
alt="RideAware icon"
class="app-brand-icon"
width="32"
height="32"
decoding="async"
/>
<div class="app-logo">RideAware</div> <div class="app-logo">RideAware</div>
</div>
<div class="stats-grid"> <div class="stats-grid">
<div class="stat-card"> <div class="stat-card">
<div class="stat-number">24.5</div> <div class="stat-number">24.5</div>
@ -62,12 +72,13 @@
</section> </section>
<!-- Features Section --> <!-- Features Section -->
{% if is_home %}
<section class="features" id="features"> <section class="features" id="features">
<div class="section-header"> <div class="section-header">
<h2>Powerful Features for Every Cyclist</h2> <h2>Powerful Features for Every Cyclist</h2>
<p> <p>
From beginners to professionals, RideAware provides comprehensive tools From beginners to professionals, RideAware provides comprehensive
to optimize your training and performance. tools to optimize your training and performance.
</p> </p>
</div> </div>
@ -109,8 +120,8 @@
and progress statistics and progress statistics
</li> </li>
<li> <li>
<strong>Progress Insights:</strong> Monitor your improvement over <strong>Progress Insights:</strong> Monitor your improvement
time with AI analysis over time with AI analysis
</li> </li>
</ul> </ul>
</div> </div>
@ -122,12 +133,12 @@
<h3>Virtual Training</h3> <h3>Virtual Training</h3>
<ul class="feature-list"> <ul class="feature-list">
<li> <li>
<strong>Expert Coaching:</strong> Professional guidance to achieve <strong>Expert Coaching:</strong> Professional guidance to
your cycling goals achieve your cycling goals
</li> </li>
<li> <li>
<strong>Immersive Rides:</strong> Virtual training experiences to <strong>Immersive Rides:</strong> Virtual training experiences
boost performance to boost performance
</li> </li>
<li> <li>
<strong>Structured Workouts:</strong> Designed programs for <strong>Structured Workouts:</strong> Designed programs for
@ -143,16 +154,16 @@
<h3>Health & Recovery</h3> <h3>Health & Recovery</h3>
<ul class="feature-list"> <ul class="feature-list">
<li> <li>
<strong>Nutrition Tracking:</strong> Plan and monitor your dietary <strong>Nutrition Tracking:</strong> Plan and monitor your
intake for optimal performance dietary intake for optimal performance
</li> </li>
<li> <li>
<strong>Recovery Optimization:</strong> Tools and resources for <strong>Recovery Optimization:</strong> Tools and resources for
effective rest and recovery effective rest and recovery
</li> </li>
<li> <li>
<strong>Injury Prevention:</strong> Proactive measures to prevent <strong>Injury Prevention:</strong> Proactive measures to
and manage injuries prevent and manage injuries
</li> </li>
</ul> </ul>
</div> </div>
@ -185,8 +196,8 @@
<h3>Smart Integration</h3> <h3>Smart Integration</h3>
<ul class="feature-list"> <ul class="feature-list">
<li> <li>
<strong>Wearable Sync:</strong> Connect with fitness trackers and <strong>Wearable Sync:</strong> Connect with fitness trackers
smart devices and smart devices
</li> </li>
<li> <li>
<strong>Music Integration:</strong> Seamlessly sync with your <strong>Music Integration:</strong> Seamlessly sync with your
@ -201,4 +212,5 @@
</div> </div>
</div> </div>
</section> </section>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -7,23 +7,28 @@
{% block content %} {% block content %}
<div class="article-wrap"> <div class="article-wrap">
<aside class="article-aside"> <aside class="article-aside">
<a href="/newsletters" class="back-link"> <a href="{{ url_for('newsletters') }}" class="back-link">
<i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-left"></i>
Back to Newsletters Back to Newsletters
</a> </a>
<div class="article-meta"> <div class="article-meta">
<h2 class="article-title">{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h2> <h2 class="article-title">
{{ newsletter.subject if newsletter else 'Newsletter Title' }}
</h2>
<div class="meta-row"> <div class="meta-row">
<i class="fas fa-calendar-alt"></i> <i class="fas fa-calendar-alt"></i>
<span>{{ newsletter.sent_at if newsletter else 'Published Date' }}</span> <span>{{ newsletter.sent_at if newsletter else 'Published Date' }}</span>
</div> </div>
{% if newsletter and newsletter.get('reading_time') %} {% if newsletter and newsletter.get('reading_time') %}
<div class="meta-row"> <div class="meta-row">
<i class="fas fa-clock"></i> <i class="fas fa-clock"></i>
<span>{{ newsletter.reading_time }} min read</span> <span>{{ newsletter.reading_time }} min read</span>
</div> </div>
{% endif %} {% endif %}
{% if newsletter and newsletter.get('author') %} {% if newsletter and newsletter.get('author') %}
<div class="meta-row"> <div class="meta-row">
<i class="fas fa-user"></i> <i class="fas fa-user"></i>
@ -48,7 +53,9 @@
<main class="article-main"> <main class="article-main">
<header class="article-hero"> <header class="article-hero">
<div class="newsletter-icon"><i class="fas fa-envelope-open-text"></i></div> <div class="newsletter-icon">
<i class="fas fa-envelope-open-text"></i>
</div>
<h1>{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h1> <h1>{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h1>
</header> </header>
@ -62,7 +69,7 @@
</article> </article>
<div class="newsletter-actions"> <div class="newsletter-actions">
<a href="/newsletters" class="action-btn primary"> <a href="{{ url_for('newsletters') }}" class="action-btn primary">
<i class="fas fa-list"></i> <i class="fas fa-list"></i>
View All Newsletters View All Newsletters
</a> </a>
@ -83,7 +90,9 @@
<script> <script>
function shareNewsletter() { function shareNewsletter() {
if (navigator.share) { if (navigator.share) {
navigator.share({ title: document.title, url: location.href }).catch(() => {}); navigator
.share({ title: document.title, url: location.href })
.catch(() => {});
} else { } else {
navigator.clipboard.writeText(location.href); navigator.clipboard.writeText(location.href);
alert('Link copied to clipboard!'); alert('Link copied to clipboard!');
@ -94,6 +103,7 @@
(function buildTOC() { (function buildTOC() {
const article = document.getElementById('article'); const article = document.getElementById('article');
if (!article) return; if (!article) return;
const headings = article.querySelectorAll('h2, h3'); const headings = article.querySelectorAll('h2, h3');
const list = document.getElementById('toc-list'); const list = document.getElementById('toc-list');
if (!headings.length || !list) return; if (!headings.length || !list) return;
@ -101,11 +111,14 @@
headings.forEach((h, idx) => { headings.forEach((h, idx) => {
const id = h.id || `h-${idx}`; const id = h.id || `h-${idx}`;
h.id = id; h.id = id;
const li = document.createElement('li'); const li = document.createElement('li');
li.className = h.tagName === 'H2' ? 'toc-h2' : 'toc-h3'; li.className = h.tagName === 'H2' ? 'toc-h2' : 'toc-h3';
const a = document.createElement('a'); const a = document.createElement('a');
a.href = `#${id}`; a.href = `#${id}`;
a.textContent = h.textContent; a.textContent = h.textContent;
li.appendChild(a); li.appendChild(a);
list.appendChild(li); list.appendChild(li);
}); });

View file

@ -29,7 +29,9 @@
</div> </div>
<div class="newsletter-info"> <div class="newsletter-info">
<h2> <h2>
<a href="/newsletter/{{ nl['id'] }}">{{ nl['subject'] }}</a> <a href="{{ url_for('newsletter_detail', newsletter_id=nl['id']) }}">
{{ nl['subject'] }}
</a>
</h2> </h2>
</div> </div>
</div> </div>
@ -43,12 +45,15 @@
{% if nl.get('preview') %} {% if nl.get('preview') %}
{{ nl['preview'][:150] }}... {{ nl['preview'][:150] }}...
{% else %} {% else %}
Get the latest updates on cycling training, performance tips, and Get the latest updates on cycling training, performance tips,
RideAware features in this newsletter edition. and RideAware features in this newsletter edition.
{% endif %} {% endif %}
</div> </div>
<a href="/newsletter/{{ nl['id'] }}" class="read-more-btn"> <a
href="{{ url_for('newsletter_detail', newsletter_id=nl['id']) }}"
class="read-more-btn"
>
Read Full Newsletter Read Full Newsletter
<i class="fas fa-arrow-right"></i> <i class="fas fa-arrow-right"></i>
</a> </a>
@ -65,7 +70,7 @@
We're working on some amazing content for you. Subscribe to be the We're working on some amazing content for you. Subscribe to be the
first to know when we publish our newsletters! first to know when we publish our newsletters!
</p> </p>
<a href="/" class="subscribe-prompt"> <a href="{{ url_for('index') }}" class="subscribe-prompt">
<i class="fas fa-bell"></i> <i class="fas fa-bell"></i>
Subscribe for Updates Subscribe for Updates
</a> </a>