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;
padding: 0;
@ -12,7 +15,12 @@
--text-light: #6b7280;
--bg-light: #f8fafc;
--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-hover: 0 20px 40px rgba(30, 78, 156, 0.15);
}
@ -26,9 +34,12 @@ body {
line-height: 1.7;
color: var(--text-dark);
overflow-x: hidden;
background: #fff;
}
/* Navigation */
/* =======================
Navigation
======================= */
.navbar {
position: fixed;
top: 0;
@ -39,6 +50,12 @@ body {
z-index: 1000;
padding: 1rem 0;
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 {
@ -51,11 +68,13 @@ body {
}
.logo {
font-size: 1.5rem;
font-size: 1.5rem; /* consistent logo size */
font-weight: 700;
color: var(--text-dark);
text-decoration: none;
transition: transform 0.3s ease;
letter-spacing: 0.2px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
.logo:hover {
@ -63,7 +82,7 @@ body {
}
.logo-accent {
color: var(--primary);
color: var(--accent);
}
.nav-links {
@ -91,11 +110,14 @@ body {
transition: width 0.3s ease;
}
.nav-links a:hover::after {
.nav-links a:hover::after,
.nav-links a.active::after {
width: 100%;
}
/* Hero Section */
/* =======================
Hero Section (Landing)
======================= */
.hero {
min-height: 100vh;
background: var(--gradient);
@ -108,10 +130,7 @@ body {
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
inset: 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;
}
@ -131,7 +150,7 @@ body {
.hero-content h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 800;
color: white;
color: #fff;
margin-bottom: 1.5rem;
line-height: 1.2;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
@ -153,7 +172,7 @@ body {
}
.cta-section h3 {
color: white;
color: #fff;
font-size: 1.5rem;
margin-bottom: 0.5rem;
font-weight: 600;
@ -183,7 +202,7 @@ body {
}
.email-input:focus {
background: white;
background: #fff;
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
}
@ -204,7 +223,7 @@ body {
box-shadow: var(--shadow-hover);
}
/* Countdown Timer */
/* Countdown (if used) */
.countdown {
display: grid;
grid-template-columns: repeat(4, 1fr);
@ -214,7 +233,7 @@ body {
.countdown-item {
text-align: center;
color: white;
color: #fff;
}
.countdown-number {
@ -230,6 +249,7 @@ body {
letter-spacing: 1px;
}
/* Phone mockup */
.hero-visual {
position: relative;
height: 500px;
@ -251,8 +271,13 @@ body {
}
@keyframes float {
0%, 100% { transform: rotate(-5deg) translateY(0px); }
50% { transform: rotate(-5deg) translateY(-20px); }
0%,
100% {
transform: rotate(-5deg) translateY(0);
}
50% {
transform: rotate(-5deg) translateY(-20px);
}
}
.screen {
@ -268,7 +293,7 @@ body {
}
.app-interface {
color: white;
color: #fff;
text-align: center;
}
@ -302,7 +327,9 @@ body {
opacity: 0.8;
}
/* Features Section */
/* =======================
Features Section
======================= */
.features {
padding: 6rem 0;
background: var(--bg-light);
@ -323,6 +350,8 @@ body {
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
color: transparent;
}
.section-header p {
@ -343,7 +372,7 @@ body {
}
.feature-card {
background: white;
background: #fff;
padding: 2.5rem;
border-radius: 20px;
box-shadow: var(--shadow);
@ -377,7 +406,7 @@ body {
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
color: white;
color: #fff;
font-size: 1.5rem;
}
@ -411,15 +440,274 @@ body {
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 {
background: var(--text-dark);
color: white;
color: #fff;
text-align: center;
padding: 2rem 0;
}
/* Mobile Styles */
/* =======================
Responsive
======================= */
@media (max-width: 768px) {
.nav-container {
padding: 0 1rem;
@ -462,6 +750,15 @@ body {
.feature-card {
padding: 2rem;
}
/* Newsletter pages */
.page-header {
padding: 7rem 0 2rem;
}
.main-content {
padding: 1.25rem 1rem 3rem;
}
}
@media (max-width: 480px) {
@ -474,3 +771,132 @@ body {
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>
<html lang="en">
<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') }}">
<!-- templates/index.html -->
{% extends "base.html" %}
</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="#features">Features</a></li>
<li><a href="/newsletters">Newsletters</a></li>
</ul>
</div>
</nav>
{% block title %}RideAware - Smart Cycling Training Platform{% endblock %}
{% block content %}
<!-- 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>
<p class="subtitle">
The ultimate smart training platform for cyclists who demand excellence
in every ride.
</p>
<div class="cta-section">
<h3>Coming soon!</h3>
<p>Join us while waiting for launch</p>
<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>
</div>
</div>
@ -73,7 +65,10 @@
<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>
<p>
From beginners to professionals, RideAware provides comprehensive tools
to optimize your training and performance.
</p>
</div>
<div class="features-container">
@ -84,9 +79,18 @@
</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>
<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>
@ -96,9 +100,18 @@
</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>
<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>
@ -108,9 +121,18 @@
</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>
<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>
@ -120,9 +142,18 @@
</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>
<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>
@ -132,9 +163,18 @@
</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>
<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>
@ -144,21 +184,21 @@
</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>
<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>
</div>
</section>
<!-- 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>
{% endblock %}

View file

@ -1,108 +1,66 @@
<!DOCTYPE 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>
{% extends "base.html" %}
<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">Newsletters</a></li>
</ul>
</div>
</nav>
{% block title %}
RideAware - {{ newsletter.subject if newsletter else 'Newsletter Detail' }}
{% endblock %}
<!-- Back Navigation -->
<div class="back-navigation">
{% block content %}
<div class="article-wrap">
<aside class="article-aside">
<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">
<div class="article-meta">
<h2 class="article-title">{{ newsletter.subject if newsletter else 'Newsletter Title' }}</h2>
<div class="meta-row">
<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">
<div class="meta-row">
<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">
<div class="meta-row">
<i class="fas fa-user"></i>
<span>{{ newsletter.author }}</span>
</div>
{% endif %}
</div>
{% if newsletter and newsletter.get('tags') %}
<div class="newsletter-tags">
<div class="article-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">
<nav class="toc">
<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 %}
{{ 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>
<p>Sample content…</p>
{% endif %}
</article>
<!-- Action Buttons -->
<div class="newsletter-actions">
<a href="/newsletters" class="action-btn primary">
<i class="fas fa-list"></i>
@ -110,7 +68,7 @@
</a>
<button onclick="window.print()" class="action-btn secondary">
<i class="fas fa-print"></i>
Print Newsletter
Print
</button>
<button onclick="shareNewsletter()" class="action-btn secondary">
<i class="fas fa-share-alt"></i>
@ -118,13 +76,39 @@
</button>
</div>
</main>
</div>
{% 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>
{% block extra_scripts %}
<script>
function shareNewsletter() {
if (navigator.share) {
navigator.share({ title: document.title, url: location.href }).catch(() => {});
} else {
navigator.clipboard.writeText(location.href);
alert('Link copied to clipboard!');
}
}
// 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>
<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>
{% extends "base.html" %}
{% block title %}RideAware - Newsletters{% endblock %}
{% block content %}
<!-- Page Header -->
<section class="page-header">
<div class="page-header-content">
@ -32,7 +10,10 @@
<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>
<p>
Stay updated with the latest cycling tips, training insights, and
product updates from our team.
</p>
</div>
</section>
@ -62,7 +43,8 @@
{% if nl.get('preview') %}
{{ nl['preview'][:150] }}...
{% 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 %}
</div>
@ -79,7 +61,10 @@
<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>
<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
@ -87,13 +72,4 @@
</div>
{% endif %}
</main>
<!-- 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>
{% endblock %}