feat: add favicon, one stylesheet, base.html

This commit is contained in:
Cipher Vance 2025-08-31 13:05:16 -05:00
parent 2e9bda85c7
commit 7a31bb7e3a
7 changed files with 1166 additions and 671 deletions

BIN
static/assets/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,3 +1,6 @@
/* =======================
Global Reset & Variables
======================= */
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -12,7 +15,12 @@
--text-light: #6b7280; --text-light: #6b7280;
--bg-light: #f8fafc; --bg-light: #f8fafc;
--white: #ffffff; --white: #ffffff;
--gradient: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 50%, var(--accent) 100%); --gradient: linear-gradient(
135deg,
var(--primary) 0%,
var(--secondary) 50%,
var(--accent) 100%
);
--shadow: 0 10px 30px rgba(30, 78, 156, 0.1); --shadow: 0 10px 30px rgba(30, 78, 156, 0.1);
--shadow-hover: 0 20px 40px rgba(30, 78, 156, 0.15); --shadow-hover: 0 20px 40px rgba(30, 78, 156, 0.15);
} }
@ -26,9 +34,12 @@ body {
line-height: 1.7; line-height: 1.7;
color: var(--text-dark); color: var(--text-dark);
overflow-x: hidden; overflow-x: hidden;
background: #fff;
} }
/* Navigation */ /* =======================
Navigation
======================= */
.navbar { .navbar {
position: fixed; position: fixed;
top: 0; top: 0;
@ -39,6 +50,12 @@ body {
z-index: 1000; z-index: 1000;
padding: 1rem 0; padding: 1rem 0;
transition: all 0.3s ease; transition: all 0.3s ease;
border-bottom: 1px solid rgba(2, 6, 23, 0.04);
/* Lock navbar typography (prevents subtle shifts) */
font-size: 1rem; /* 16px baseline */
line-height: 1.2;
letter-spacing: 0;
} }
.nav-container { .nav-container {
@ -51,11 +68,13 @@ body {
} }
.logo { .logo {
font-size: 1.5rem; font-size: 1.5rem; /* consistent logo size */
font-weight: 700; font-weight: 700;
color: var(--text-dark); color: var(--text-dark);
text-decoration: none; text-decoration: none;
transition: transform 0.3s ease; transition: transform 0.3s ease;
letter-spacing: 0.2px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
} }
.logo:hover { .logo:hover {
@ -63,7 +82,7 @@ body {
} }
.logo-accent { .logo-accent {
color: var(--primary); color: var(--accent);
} }
.nav-links { .nav-links {
@ -91,11 +110,14 @@ body {
transition: width 0.3s ease; transition: width 0.3s ease;
} }
.nav-links a:hover::after { .nav-links a:hover::after,
.nav-links a.active::after {
width: 100%; width: 100%;
} }
/* Hero Section */ /* =======================
Hero Section (Landing)
======================= */
.hero { .hero {
min-height: 100vh; min-height: 100vh;
background: var(--gradient); background: var(--gradient);
@ -108,10 +130,7 @@ body {
.hero::before { .hero::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; inset: 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>'); 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; opacity: 0.3;
} }
@ -131,7 +150,7 @@ body {
.hero-content h1 { .hero-content h1 {
font-size: clamp(2.5rem, 5vw, 4rem); font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 800; font-weight: 800;
color: white; color: #fff;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
line-height: 1.2; line-height: 1.2;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.1); text-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
@ -153,7 +172,7 @@ body {
} }
.cta-section h3 { .cta-section h3 {
color: white; color: #fff;
font-size: 1.5rem; font-size: 1.5rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
font-weight: 600; font-weight: 600;
@ -183,7 +202,7 @@ body {
} }
.email-input:focus { .email-input:focus {
background: white; background: #fff;
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3); box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
} }
@ -204,7 +223,7 @@ body {
box-shadow: var(--shadow-hover); box-shadow: var(--shadow-hover);
} }
/* Countdown Timer */ /* Countdown (if used) */
.countdown { .countdown {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
@ -214,7 +233,7 @@ body {
.countdown-item { .countdown-item {
text-align: center; text-align: center;
color: white; color: #fff;
} }
.countdown-number { .countdown-number {
@ -230,6 +249,7 @@ body {
letter-spacing: 1px; letter-spacing: 1px;
} }
/* Phone mockup */
.hero-visual { .hero-visual {
position: relative; position: relative;
height: 500px; height: 500px;
@ -251,8 +271,13 @@ body {
} }
@keyframes float { @keyframes float {
0%, 100% { transform: rotate(-5deg) translateY(0px); } 0%,
50% { transform: rotate(-5deg) translateY(-20px); } 100% {
transform: rotate(-5deg) translateY(0);
}
50% {
transform: rotate(-5deg) translateY(-20px);
}
} }
.screen { .screen {
@ -268,7 +293,7 @@ body {
} }
.app-interface { .app-interface {
color: white; color: #fff;
text-align: center; text-align: center;
} }
@ -302,7 +327,9 @@ body {
opacity: 0.8; opacity: 0.8;
} }
/* Features Section */ /* =======================
Features Section
======================= */
.features { .features {
padding: 6rem 0; padding: 6rem 0;
background: var(--bg-light); background: var(--bg-light);
@ -323,6 +350,8 @@ body {
background: var(--gradient); background: var(--gradient);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
background-clip: text;
color: transparent;
} }
.section-header p { .section-header p {
@ -343,7 +372,7 @@ body {
} }
.feature-card { .feature-card {
background: white; background: #fff;
padding: 2.5rem; padding: 2.5rem;
border-radius: 20px; border-radius: 20px;
box-shadow: var(--shadow); box-shadow: var(--shadow);
@ -377,7 +406,7 @@ body {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
color: white; color: #fff;
font-size: 1.5rem; font-size: 1.5rem;
} }
@ -411,15 +440,274 @@ body {
color: var(--text-dark); color: var(--text-dark);
} }
/* Footer */ /* =======================
Newsletter Pages (List & Detail)
======================= */
/* Page header banner */
.page-header {
background: linear-gradient(
180deg,
rgba(30, 78, 156, 0.06),
rgba(0, 212, 255, 0.06)
);
padding: 8rem 0 3rem; /* account for fixed navbar */
border-bottom: 1px solid rgba(30, 78, 156, 0.08);
}
.page-header-content {
max-width: 1000px;
margin: 0 auto;
padding: 0 2rem;
text-align: center;
}
.page-header .header-icon {
width: 64px;
height: 64px;
margin: 0 auto 1rem;
border-radius: 16px;
background: var(--gradient);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--shadow);
font-size: 1.5rem;
}
.page-header h1 {
font-size: clamp(2rem, 4vw, 2.5rem);
font-weight: 700;
color: var(--text-dark);
margin-bottom: 0.5rem;
}
.page-header p {
color: var(--text-light);
font-size: 1.05rem;
}
/* Main content container */
.main-content {
max-width: 1100px;
margin: 0 auto;
padding: 2rem 2rem 4rem;
}
/* Grid of newsletter cards */
.newsletters-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1.5rem;
}
/* Individual card */
.newsletter-card {
background: #fff;
border: 1px solid rgba(30, 78, 156, 0.08);
border-radius: 16px;
padding: 1.25rem 1.25rem 1rem;
box-shadow: var(--shadow);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.newsletter-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-hover);
}
.newsletter-header {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.newsletter-icon {
width: 44px;
height: 44px;
border-radius: 12px;
background: var(--gradient);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 44px;
}
.newsletter-info h2 {
font-size: 1.1rem;
margin: 0;
}
.newsletter-info a {
color: var(--text-dark);
text-decoration: none;
}
.newsletter-info a:hover {
color: var(--secondary);
}
/* Meta/date and excerpt */
.newsletter-date {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--text-light);
font-size: 0.9rem;
margin-bottom: 0.5rem;
}
.newsletter-excerpt {
color: var(--text-dark);
opacity: 0.9;
margin-bottom: 0.75rem;
}
/* Read more button */
.read-more-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: #fff;
background: var(--gradient);
padding: 0.55rem 0.9rem;
border-radius: 999px;
text-decoration: none;
font-weight: 600;
}
/* Detail page nav back link */
.back-navigation {
max-width: 1100px;
margin: 6rem auto 0; /* space for fixed navbar */
padding: 0 2rem;
}
.back-link {
color: var(--secondary);
text-decoration: none;
font-weight: 600;
}
.back-link:hover {
text-decoration: underline;
}
/* Detail header, meta, tags */
.newsletter-header h1 {
margin-top: 0.5rem;
}
.newsletter-meta {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 1.25rem;
margin-top: 0.5rem;
color: var(--text-light);
}
.newsletter-meta .meta-item {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.newsletter-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.75rem;
}
.newsletter-tags .tag {
font-size: 0.85rem;
padding: 0.3rem 0.6rem;
background: rgba(51, 124, 242, 0.1);
color: var(--secondary);
border: 1px solid rgba(51, 124, 242, 0.2);
border-radius: 999px;
}
/* Detail content */
.newsletter-content {
margin-top: 1.25rem;
background: #fff;
border: 1px solid rgba(30, 78, 156, 0.08);
border-radius: 16px;
padding: 1.5rem;
box-shadow: var(--shadow);
}
.newsletter-content h2,
.newsletter-content h3 {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.newsletter-content p,
.newsletter-content li {
color: var(--text-dark);
}
.newsletter-content ul {
padding-left: 1.25rem;
}
.newsletter-content blockquote {
margin: 1rem 0;
padding: 1rem 1.25rem;
background: rgba(0, 212, 255, 0.08);
border-left: 4px solid var(--accent);
border-radius: 8px;
color: var(--text-dark);
}
/* Actions */
.newsletter-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-top: 1rem;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
border-radius: 10px;
padding: 0.6rem 1rem;
cursor: pointer;
border: none;
text-decoration: none;
font-weight: 600;
}
.action-btn.primary {
background: var(--gradient);
color: #fff;
}
.action-btn.secondary {
background: #f1f5f9;
color: var(--text-dark);
}
/* =======================
Footer
======================= */
.footer { .footer {
background: var(--text-dark); background: var(--text-dark);
color: white; color: #fff;
text-align: center; text-align: center;
padding: 2rem 0; padding: 2rem 0;
} }
/* Mobile Styles */ /* =======================
Responsive
======================= */
@media (max-width: 768px) { @media (max-width: 768px) {
.nav-container { .nav-container {
padding: 0 1rem; padding: 0 1rem;
@ -462,6 +750,15 @@ body {
.feature-card { .feature-card {
padding: 2rem; padding: 2rem;
} }
/* Newsletter pages */
.page-header {
padding: 7rem 0 2rem;
}
.main-content {
padding: 1.25rem 1rem 3rem;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
@ -474,3 +771,132 @@ body {
padding: 0 1rem; padding: 0 1rem;
} }
} }
/* =======================
Hard Guards for Navbar
======================= */
/* Ensure navbar logo colors are always visible on white background */
.navbar .logo {
color: var(--text-dark) !important;
}
.navbar .logo .logo-accent {
color: var(--accent) !important;
}
/* Prevent content typography from leaking into the navbar */
.navbar,
.navbar * {
text-transform: none;
letter-spacing: normal;
line-height: normal;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
}
/* Article layout for newsletter detail */
.article-wrap {
max-width: 1200px;
margin: 6rem auto 3rem;
padding: 0 2rem;
display: grid;
grid-template-columns: 280px 1fr;
gap: 2rem;
}
.article-aside {
position: sticky;
top: 84px; /* below fixed navbar */
align-self: start;
}
.article-meta {
background: #fff;
border: 1px solid rgba(30, 78, 156, 0.08);
border-radius: 16px;
padding: 1rem;
box-shadow: var(--shadow);
margin-top: 0.75rem;
}
.article-title {
font-size: 1.1rem;
margin: 0 0 0.5rem 0;
}
.meta-row {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--text-light);
font-size: 0.95rem;
margin: 0.25rem 0;
}
.article-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: 0.5rem;
}
.article-tags .tag {
font-size: 0.8rem;
padding: 0.25rem 0.5rem;
background: rgba(51, 124, 242, 0.08);
color: var(--secondary);
border: 1px solid rgba(51, 124, 242, 0.2);
border-radius: 999px;
}
.toc {
margin-top: 1rem;
background: #fff;
border: 1px solid rgba(30, 78, 156, 0.08);
border-radius: 16px;
padding: 0.75rem 0.75rem 0.75rem 1rem;
box-shadow: var(--shadow);
}
.toc-title {
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--text-dark);
}
#toc-list {
list-style: none;
padding-left: 0;
}
#toc-list li {
margin: 0.25rem 0;
}
#toc-list a {
text-decoration: none;
color: var(--text-dark);
font-size: 0.95rem;
}
#toc-list a:hover { color: var(--secondary); }
.toc-h3 { margin-left: 0.75rem; opacity: 0.9; }
.article-main .article-hero {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.article-hero .newsletter-icon {
width: 44px;
height: 44px;
border-radius: 12px;
background: var(--gradient);
color: #fff;
display: inline-flex;
align-items: center;
justify-content: center;
}
@media (max-width: 992px) {
.article-wrap {
grid-template-columns: 1fr;
}
.article-aside {
position: static;
}
}

69
templates/base.html Normal file
View file

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
<title>{% block title %}RideAware{% endblock %}</title>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
rel="stylesheet"
/>
<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
rel="stylesheet"
href="{{ url_for('static', filename='css/styles.css') }}"
/>
<link
rel="alternate icon"
type="image/png"
sizes="32x32"
href="{{ url_for('static', filename='assets/32x32.png') }}"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="{{ url_for('static', filename='assets/apple-touch-icon.png') }}"
/>
<link
rel="manifest"
href="{{ url_for('static', filename='assets/site.webmanifest') }}"
/>
<meta
name="theme-color"
content="#0f172a"
/>
{% block extra_head %}{% endblock %}
</head>
<body>
<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>
{% block content %}{% endblock %}
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script
defer
src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js"
crossorigin="anonymous"
></script>
{% block extra_scripts %}{% endblock %}
</body>
</html>

View file

@ -1,39 +1,31 @@
<!DOCTYPE html> <!-- templates/index.html -->
<html lang="en"> {% extends "base.html" %}
<head>
<meta charset="UTF-8">
<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="preconnect" href="https://cdn.statically.io" crossorigin>
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head> {% block title %}RideAware - Smart Cycling Training Platform{% endblock %}
<body>
<!-- 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>
{% block content %}
<!-- Hero Section --> <!-- Hero Section -->
<section class="hero"> <section class="hero">
<div class="hero-container"> <div class="hero-container">
<div class="hero-content"> <div class="hero-content">
<h1>Elevate Your Cycling Journey</h1> <h1>Elevate Your Cycling Journey</h1>
<p class="subtitle">The ultimate smart training platform for cyclists who demand excellence in every ride.</p> <p class="subtitle">
The ultimate smart training platform for cyclists who demand excellence
in every ride.
</p>
<div class="cta-section"> <div class="cta-section">
<h3>Coming soon!</h3> <h3>Coming soon!</h3>
<p>Join us while waiting for launch</p> <p>Join us while waiting for launch</p>
<div class="email-form"> <div class="email-form">
<input type="email" class="email-input" id="email-input" placeholder="Enter your email address" required> <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> <button class="notify-btn" id="notify-button">Notify Me</button>
</div> </div>
</div> </div>
@ -73,7 +65,10 @@
<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>From beginners to professionals, RideAware provides comprehensive tools to optimize your training and performance.</p> <p>
From beginners to professionals, RideAware provides comprehensive tools
to optimize your training and performance.
</p>
</div> </div>
<div class="features-container"> <div class="features-container">
@ -84,9 +79,18 @@
</div> </div>
<h3>Smart Training Plans</h3> <h3>Smart Training Plans</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>AI-Powered Planning:</strong> Customized training plans based on your goals and fitness level</li> <li>
<li><strong>Adaptive Scheduling:</strong> Smart workout scheduling with automated reminders</li> <strong>AI-Powered Planning:</strong> Customized training plans
<li><strong>Goal Tracking:</strong> Set and monitor your cycling objectives in real-time</li> 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> </ul>
</div> </div>
@ -96,9 +100,18 @@
</div> </div>
<h3>Advanced Analytics</h3> <h3>Advanced Analytics</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>Detailed Logging:</strong> Track exercises, sets, reps, and performance metrics</li> <li>
<li><strong>Data Visualization:</strong> Interactive charts, graphs, and progress statistics</li> <strong>Detailed Logging:</strong> Track exercises, sets, reps,
<li><strong>Progress Insights:</strong> Monitor your improvement over time with AI analysis</li> 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> </ul>
</div> </div>
@ -108,9 +121,18 @@
</div> </div>
<h3>Virtual Training</h3> <h3>Virtual Training</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>Expert Coaching:</strong> Professional guidance to achieve your cycling goals</li> <li>
<li><strong>Immersive Rides:</strong> Virtual training experiences to boost performance</li> <strong>Expert Coaching:</strong> Professional guidance to achieve
<li><strong>Structured Workouts:</strong> Designed programs for fitness and performance gains</li> 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> </ul>
</div> </div>
@ -120,9 +142,18 @@
</div> </div>
<h3>Health & Recovery</h3> <h3>Health & Recovery</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>Nutrition Tracking:</strong> Plan and monitor your dietary intake for optimal performance</li> <li>
<li><strong>Recovery Optimization:</strong> Tools and resources for effective rest and recovery</li> <strong>Nutrition Tracking:</strong> Plan and monitor your dietary
<li><strong>Injury Prevention:</strong> Proactive measures to prevent and manage injuries</li> 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> </ul>
</div> </div>
@ -132,9 +163,18 @@
</div> </div>
<h3>Community & Social</h3> <h3>Community & Social</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>Social Sharing:</strong> Share achievements and progress on social platforms</li> <li>
<li><strong>Active Community:</strong> Connect with fellow cyclists and share experiences</li> <strong>Social Sharing:</strong> Share achievements and progress
<li><strong>Competitive Leaderboards:</strong> Challenge yourself against the community</li> 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> </ul>
</div> </div>
@ -144,21 +184,21 @@
</div> </div>
<h3>Smart Integration</h3> <h3>Smart Integration</h3>
<ul class="feature-list"> <ul class="feature-list">
<li><strong>Wearable Sync:</strong> Connect with fitness trackers and smart devices</li> <li>
<li><strong>Music Integration:</strong> Seamlessly sync with your favorite music services</li> <strong>Wearable Sync:</strong> Connect with fitness trackers and
<li><strong>Data Portability:</strong> Easy import/export to other cycling platforms</li> 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> </ul>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
{% endblock %}
<!-- Footer -->
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script defer
src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js"
crossorigin="anonymous"></script>
</body>
</html>

View file

@ -1,108 +1,66 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="en">
<head>
<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="preconnect" href="https://cdn.statically.io" crossorigin>
<link rel="preload" as="style" {% block title %}
href="https://cdn.statically.io/gl/rideaware/landing/main/static/css/newsletter_styles.min.css" RideAware - {{ newsletter.subject if newsletter else 'Newsletter Detail' }}
onload="this.onload=null;this.rel='stylesheet'"> {% endblock %}
<noscript>
<link rel="stylesheet"
href="https://cdn.statically.io/gl/rideaware/landing/main/static/css/newsletter_styles.min.css">
</noscript>
</head>
<body>
<!-- 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>
<!-- Back Navigation --> {% block content %}
<div class="back-navigation"> <div class="article-wrap">
<aside class="article-aside">
<a href="/newsletters" class="back-link"> <a href="/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>
<!-- Main Content --> <div class="article-meta">
<main class="main-content"> <h2 class="article-title">{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h2>
<!-- Newsletter Header --> <div class="meta-row">
<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> <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-item"> <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-item"> <div class="meta-row">
<i class="fas fa-user"></i> <i class="fas fa-user"></i>
<span>{{ newsletter.author }}</span> <span>{{ newsletter.author }}</span>
</div> </div>
{% endif %} {% endif %}
</div>
{% if newsletter and newsletter.get('tags') %} {% if newsletter and newsletter.get('tags') %}
<div class="newsletter-tags"> <div class="article-tags">
{% for tag in newsletter.tags %} {% for tag in newsletter.tags %}
<span class="tag">{{ tag }}</span> <span class="tag">{{ tag }}</span>
{% endfor %} {% endfor %}
</div> </div>
{% else %}
<div class="newsletter-tags">
<span class="tag">Cycling Tips</span>
<span class="tag">Training</span>
<span class="tag">Performance</span>
</div>
{% endif %} {% endif %}
</div> </div>
<!-- Newsletter Content --> <nav class="toc">
<article class="newsletter-content"> <div class="toc-title">On this page</div>
<ol id="toc-list"></ol>
</nav>
</aside>
<main class="article-main">
<header class="article-hero">
<div class="newsletter-icon"><i class="fas fa-envelope-open-text"></i></div>
<h1>{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h1>
</header>
<article class="newsletter-content" id="article">
{% if newsletter %} {% if newsletter %}
{{ newsletter.body | safe }} {{ newsletter.body | safe }}
{% else %} {% else %}
<h2>Welcome to RideAware Newsletter</h2> <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> <p>Sample content…</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 %} {% endif %}
</article> </article>
<!-- Action Buttons -->
<div class="newsletter-actions"> <div class="newsletter-actions">
<a href="/newsletters" class="action-btn primary"> <a href="/newsletters" class="action-btn primary">
<i class="fas fa-list"></i> <i class="fas fa-list"></i>
@ -110,7 +68,7 @@
</a> </a>
<button onclick="window.print()" class="action-btn secondary"> <button onclick="window.print()" class="action-btn secondary">
<i class="fas fa-print"></i> <i class="fas fa-print"></i>
Print Newsletter Print
</button> </button>
<button onclick="shareNewsletter()" class="action-btn secondary"> <button onclick="shareNewsletter()" class="action-btn secondary">
<i class="fas fa-share-alt"></i> <i class="fas fa-share-alt"></i>
@ -118,13 +76,39 @@
</button> </button>
</div> </div>
</main> </main>
</div>
{% endblock %}
<!-- Footer --> {% block extra_scripts %}
<footer class="footer"> <script>
<p>&copy; 2025 RideAware. All rights reserved.</p> function shareNewsletter() {
</footer> if (navigator.share) {
<script defer navigator.share({ title: document.title, url: location.href }).catch(() => {});
src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js" } else {
crossorigin="anonymous"></script> navigator.clipboard.writeText(location.href);
</body> alert('Link copied to clipboard!');
</html> }
}
// Build TOC from h2/h3 inside the article
(function buildTOC() {
const article = document.getElementById('article');
if (!article) return;
const headings = article.querySelectorAll('h2, h3');
const list = document.getElementById('toc-list');
if (!headings.length || !list) return;
headings.forEach((h, idx) => {
const id = h.id || `h-${idx}`;
h.id = id;
const li = document.createElement('li');
li.className = h.tagName === 'H2' ? 'toc-h2' : 'toc-h3';
const a = document.createElement('a');
a.href = `#${id}`;
a.textContent = h.textContent;
li.appendChild(a);
list.appendChild(li);
});
})();
</script>
{% endblock %}

View file

@ -1,30 +1,8 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="en">
<head>
<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="preload" as="style"
href="https://cdn.statically.io/gl/rideaware/landing/main/static/css/newsletter_styles.min.css"
onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet"
href="https://cdn.statically.io/gl/rideaware/landing/main/static/css/newsletter_styles.min.css">
</noscript>
`</head>
<body>
<!-- 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>
</nav>
{% block title %}RideAware - Newsletters{% endblock %}
{% block content %}
<!-- Page Header --> <!-- Page Header -->
<section class="page-header"> <section class="page-header">
<div class="page-header-content"> <div class="page-header-content">
@ -32,7 +10,10 @@
<i class="fas fa-newspaper"></i> <i class="fas fa-newspaper"></i>
</div> </div>
<h1>RideAware Newsletters</h1> <h1>RideAware Newsletters</h1>
<p>Stay updated with the latest cycling tips, training insights, and product updates from our team.</p> <p>
Stay updated with the latest cycling tips, training insights, and
product updates from our team.
</p>
</div> </div>
</section> </section>
@ -62,7 +43,8 @@
{% 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 RideAware features in this newsletter edition. Get the latest updates on cycling training, performance tips, and
RideAware features in this newsletter edition.
{% endif %} {% endif %}
</div> </div>
@ -79,7 +61,10 @@
<i class="fas fa-inbox"></i> <i class="fas fa-inbox"></i>
</div> </div>
<h3>No Newsletters Yet</h3> <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> <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"> <a href="/" class="subscribe-prompt">
<i class="fas fa-bell"></i> <i class="fas fa-bell"></i>
Subscribe for Updates Subscribe for Updates
@ -87,13 +72,4 @@
</div> </div>
{% endif %} {% endif %}
</main> </main>
{% endblock %}
<!-- Footer -->
<footer class="footer">
<p>&copy; 2025 RideAware. All rights reserved.</p>
</footer>
<script defer
src="https://cdn.statically.io/gl/rideaware/landing/06d19988c7df53636277f945f9ed853bda76471b/static/js/main.min.js"
crossorigin="anonymous"></script>
</body>
</html>