Files
Stride/app/templates/stats.html
T

38 lines
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends 'base.html' %}
{% block title %}Stats studio · Stride{% endblock %}
{% block head %}<link rel="stylesheet" href="{{ url_for('static', filename='stats.css') }}">{% endblock %}
{% block content %}
<div id="stats-studio" data-owner="{{ current_user.id }}" data-query="{{ query_text }}">
<div class="page-heading"><div><span class="eyebrow">YOUR RUNNING / STATS STUDIO</span><h1>Ask more of your runs.</h1><p>Build a question. Find the pattern. Explore the runs behind it.</p></div><button type="button" class="button secondary" id="save-view">☆ Save view</button></div>
<div id="saved-views" class="studio-presets" aria-label="Saved views"></div>
<form method="get" id="explorer-form" class="panel question-panel">
<div class="studio-row"><span class="eyebrow">YOUR QUESTION</span><button type="button" class="text-button" id="query-toggle" aria-expanded="{{ 'true' if error else 'false' }}" aria-controls="query-editor">〈/〉 {{ 'Hide' if error else 'Show' }} query</button></div>
<div class="studio-sentence">Show <label class="sr-only" for="metric">Primary metric</label><select id="metric" name="metric">{% for key, info in metrics.items() %}<option value="{{ key }}" {{ 'selected' if query.metric == key }}>{{ info[0]|lower }}</option>{% endfor %}</select> and <label class="sr-only" for="secondary">Second metric</label><select id="secondary" name="secondary"><option value="none" {{ 'selected' if query.secondary == 'none' }}>no second metric</option>{% for key, info in metrics.items() %}<option value="{{ key }}" {{ 'selected' if query.secondary == key }}>{{ info[0]|lower }}</option>{% endfor %}</select><br>
from runs during the last <label class="sr-only" for="weeks">Number of weeks</label><input id="weeks" name="weeks" type="number" min="1" max="104" value="{{ query.weeks }}" required> weeks, grouped by <label class="sr-only" for="group">Grouping</label><select id="group" name="group"><option value="week" {{ 'selected' if query.group == 'week' }}>week</option><option value="month" {{ 'selected' if query.group == 'month' }}>month</option></select>.</div>
<div class="studio-filters">
<label>Distance at least · km<input name="minimum" type="number" min="0" max="1000" step="any" value="{{ query.minimum }}"></label>
<label>Distance at most · km<input name="maximum" type="number" min="0" max="1000" step="any" value="{{ query.maximum if query.maximum is not none else '' }}" placeholder="Any"></label>
<label>Heart rate at least · bpm<input name="hr_min" type="number" min="0" max="1000" step="any" value="{{ query.hr_min if query.hr_min is not none else '' }}" placeholder="Any"></label>
<label>Heart rate at most · bpm<input name="hr_max" type="number" min="0" max="1000" step="any" value="{{ query.hr_max if query.hr_max is not none else '' }}" placeholder="Any"></label>
<label>Ending on<input name="end" type="date" value="{{ query.end or '' }}" aria-describedby="end-help"><span id="end-help">Blank = today</span></label>
<label>Compare with<select name="compare"><option value="yes" {{ 'selected' if query.compare }}>Previous period</option><option value="no" {{ 'selected' if not query.compare }}>No comparison</option></select></label>
</div>
<div id="query-editor" {% if not error %}hidden{% endif %}><label for="query-input">Edit query</label><textarea id="query-input" spellcheck="false" rows="8">{{ submitted_query if error and submitted_query else query_text }}</textarea><p class="field-help">Supported clauses: runs, during last N weeks, ending YYYY-MM-DD, distance and heart_rate filters, summarize, by week/month, compare previous period/none. Filters use km and bpm.</p></div>
{% if error %}<p class="studio-error" role="alert">{{ error }}</p>{% endif %}
<div class="studio-row studio-bottom"><span class="field-help">Whole runs · Recorded timer time · {{ current_user.timezone }}</span><button class="button primary" type="submit">Explore {{ icon('arrow') }}</button></div>
</form>
<div class="studio-presets" aria-label="Starting questions"><span class="subtle-label">START WITH</span><a href="{{ url_for('web.stats',metric='distance',secondary='duration') }}">Weekly volume</a><a href="{{ url_for('web.stats',metric='pace',secondary='heart_rate',minimum=10) }}">Long-run progression</a><a href="{{ url_for('web.stats',metric='pace',secondary='heart_rate',hr_min=140,hr_max=150) }}">Pace at similar heart rate</a><a href="{{ url_for('web.stats',metric='cadence',secondary='ground_contact') }}">Running form</a></div>
{% if results %}
<div class="studio-row result-heading"><div><h2>{{ results.count }} matching {{ 'run' if results.count == 1 else 'runs' }}</h2><p>{{ results.start }} – {{ results.end }} · {{ '%.1f'|format(results.distance) }} km{% if query.compare %}<br>Compared with {{ results.previous_start }} – {{ results.previous_end }} · {{ results.prior_count }} runs{% endif %}</p></div></div>
{% if not results.count %}<div class="panel studio-empty"><h2>No runs match this question.</h2><p>Try a longer period or widen the distance and heart rate filters.</p></div>{% else %}
<div class="studio-metrics">{% for card in results.cards %}<article class="stat-card"><span class="eyebrow">{{ card.label }}</span><div class="stat-value">{{ card.value }}<small>{{ card.unit }}</small></div>{% if query.compare %}<p>Previous: {{ card.previous }} {{ card.unit }}{% if card.delta %} · {{ card.delta }} {{ 'sec/km' if card.key == 'pace' else card.unit }}{% endif %}</p>{% endif %}<p>{{ card.coverage }} of {{ results.count }} runs with usable data</p><details><summary>How this is calculated</summary><p>{{ card.definition }}{% if card.key in ('cadence','power','ground_contact','stride_length') %} Coverage counts runs, not sensor recording time.{% endif %}</p></details></article>{% endfor %}</div>
<section class="panel"><div class="section-head"><div><span class="eyebrow">TRENDS / {{ query.group|upper }}</span><h2>Your question over time</h2></div><span class="subtle-label">Solid: current · Dashed: previous</span></div><div class="studio-charts">{% for card in results.cards %}<div class="studio-chart"><h3>{{ card.label }} <small>{{ card.unit }}</small></h3><div><canvas id="stats-chart-{{ loop.index0 }}" role="img" aria-label="{{ card.label }} grouped by {{ query.group }}"></canvas></div></div>{% endfor %}</div><p class="studio-chart-help">Select a current-period point to see its contributing runs below. Missing data leaves a gap; comparison runs are aligned by elapsed days.</p></section>
{% endif %}
<section class="panel studio-evidence"><div class="section-head"><div><span class="eyebrow">BEHIND THE NUMBERS</span><h2 id="evidence-heading">Contributing runs</h2></div><div class="studio-row"><label class="studio-period" for="evidence-period">Period <select id="evidence-period"><option value="">All results</option>{% for label in results.chart.labels %}<option>{{ label }}</option>{% endfor %}</select></label><button type="button" class="text-button" id="clear-selection" hidden>Show all results</button></div></div><div class="activity-table-wrap"><table class="activity-table"><thead><tr><th>RUN / LOCAL DATE</th><th>DISTANCE</th>{% for card in results.cards %}<th>{{ card.label|upper }} · {{ card.unit }}</th>{% endfor %}</tr></thead><tbody id="evidence-body">{% for row in results.rows %}<tr><td><a href="{{ url_for('web.activity',activity_id=row.id) }}"><strong>{{ row.title }}</strong><br><small>{{ row.date }}</small></a></td><td>{{ row.distance }} km</td>{% for value in row['values'] %}<td>{{ value }}</td>{% endfor %}</tr>{% else %}<tr><td colspan="4">No matching runs.</td></tr>{% endfor %}</tbody></table></div><div class="studio-pagination"><span>Page {{ results.page }} of {{ results.pages }} · up to 25 runs per page</span>{% if results.page > 1 %}<a class="button secondary" href="{{ url_for('web.stats',query=query_text,page=results.page-1) }}">Previous</a>{% endif %}{% if results.page < results.pages %}<a class="button secondary" href="{{ url_for('web.stats',query=query_text,page=results.page+1) }}">Next</a>{% endif %}</div></section>
<script id="stats-data" type="application/json">{{ results.chart|tojson }}</script>
{% endif %}
<div id="studio-status" role="status" class="field-help"></div>
</div>
{% endblock %}
{% block scripts %}<script src="{{ url_for('static',filename='vendor/chart.umd.js') }}"></script><script src="{{ url_for('static',filename='stats.js') }}"></script>{% endblock %}