checkpoint 1

This commit is contained in:
2025-08-24 18:16:04 -07:00
parent c550f7d0df
commit 91493446b7
20 changed files with 4439 additions and 758 deletions

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GarminSync - {{block "title" .}}{{end}}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<style>
:root {
--primary: #1c6bff;
--primary-hover: #0a5af7;
}
.activity-card {
transition: transform 0.2s;
cursor: pointer;
}
.activity-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
</style>
</head>
<body>
<nav class="container-fluid">
<ul>
<li><strong>GarminSync</strong></li>
</ul>
<ul>
<li><a href="/">Dashboard</a></li>
<li><a href="/activities">Activities</a></li>
<li><a href="/settings">Settings</a></li>
</ul>
</nav>
<main class="container">
{{block "content" .}}{{end}}
</main>
<footer class="container-fluid">
<p>GarminSync v1.0 · Last sync: {{.LastSync}}</p>
</footer>
</body>
</html>

View File

@@ -0,0 +1,70 @@
{{define "title"}}{{.ActivityName}}{{end}}
{{define "content"}}
<article>
<header>
<hgroup>
<h1>{{.ActivityName}}</h1>
<h2>{{.ActivityType}} • {{.StartTime.Format "Jan 2, 2006"}}</h2>
</hgroup>
</header>
<div class="grid">
<div>
<h3>Metrics</h3>
<ul>
<li><strong>Distance:</strong> {{printf "%.2f km" (div .Distance 1000)}}</li>
<li><strong>Duration:</strong> {{.Duration | formatDuration}}</li>
<li><strong>Avg HR:</strong> {{.AvgHeartRate}} bpm</li>
<li><strong>Avg Power:</strong> {{.AvgPower}}W</li>
<li><strong>Calories:</strong> {{.Calories}}</li>
<li><strong>Steps:</strong> {{.Steps}}</li>
<li><strong>Elevation Gain:</strong> {{.ElevationGain | formatMeters}}m</li>
</ul>
</div>
<div>
<h3>Location</h3>
{{if and (ne .StartLatitude 0) (ne .StartLongitude 0)}}
<div id="map" style="height: 300px; background: #f0f0f0; border-radius: 4px;">
<!-- Map will be rendered here -->
</div>
<script>
// Simple static map for now - will be enhanced later
const mapEl = document.getElementById('map');
const lat = {{.StartLatitude}};
const lng = {{.StartLongitude}};
mapEl.innerHTML = `
<iframe
width="100%"
height="300"
frameborder="0"
style="border:0"
src="https://www.openstreetmap.org/export/embed.html?bbox=${lng-0.01},${lat-0.01},${lng+0.01},${lat+0.01}&layer=mapnik&marker=${lat},${lng}">
</iframe>
`;
</script>
{{else}}
<p>No location data available</p>
{{end}}
</div>
</div>
<div>
<a href="{{.Filename}}" download role="button">Download FIT File</a>
</div>
</article>
{{end}}
{{define "scripts"}}
<script>
// Custom formatting function for duration
function formatDuration(seconds) {
const hrs = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
return `${hrs}h ${mins}m`;
}
// Register as helper function
window.formatDuration = formatDuration;
</script>
{{end}}

View File

@@ -0,0 +1,27 @@
{{define "title"}}Activities{{end}}
{{define "content"}}
<article>
<header>
<h1>Activity List</h1>
<div class="grid">
<form method="get">
<input type="search" name="q" placeholder="Search activities..."
hx-get="/activities" hx-trigger="keyup changed delay:500ms"
hx-target="#activity-list" hx-include="this">
</form>
<select name="type" hx-get="/activities" hx-trigger="change"
hx-target="#activity-list" hx-include="previous input">
<option value="">All Types</option>
<option value="running">Running</option>
<option value="cycling">Cycling</option>
<option value="swimming">Swimming</option>
</select>
</div>
</header>
<div id="activity-list" hx-get="/partials/activities" hx-trigger="load">
Loading activities...
</div>
</article>
{{end}}

View File

@@ -0,0 +1,35 @@
{{define "title"}}Dashboard{{end}}
{{define "content"}}
<article>
<h1>Activity Dashboard</h1>
<div class="stats-grid">
<div class="card">
<header>Total Activities</header>
<h2>{{.Total}}</h2>
</div>
<div class="card">
<header>Downloaded</header>
<h2>{{.Downloaded}}</h2>
</div>
<div class="card">
<header>Missing</header>
<h2>{{.Missing}}</h2>
</div>
</div>
<div class="grid">
<a href="/sync" role="button" class="secondary">Sync Now</a>
<a href="/activities" role="button">View Activities</a>
</div>
</article>
<article>
<h2>Recent Activities</h2>
{{/* Will be replaced by HTMX */}}
<div id="recent-activities" hx-get="/partials/recent_activities" hx-trigger="load">
Loading...
</div>
</article>
{{end}}