Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/web/templates/_summary_cards.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<section class="{{ summary_class | default('summary') }}" aria-label="{{ summary_label | default('Summary statistics') }}">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{# Shared team/season/window controls. Both metric pages post to their own path
via form_action, so one selector serves both without a second selection
system. The route validates the team-season pair on every request. #}
{# Team-only GET controls for team_id, season, and window. Each Team metric
supplies form_action; the Team-season catalog supports season-selector.js.
Routes validate the Team-season pair even without JavaScript. #}
<script type="application/json" id="team-seasons-data">{{ team_seasons_catalog | tojson }}</script>

<form class="controls card" method="get" action="{{ form_action }}">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/baserunners.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -72,15 +72,7 @@ <h2>{{ analysis.team_name }} — Baserunners per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
14 changes: 4 additions & 10 deletions app/web/templates/comparison.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -65,15 +65,9 @@ <h2>{{ analysis.team_name }} — Hits vs Batting Strikeouts</h2>
</div>
</section>

<section class="summary summary--comparison" aria-label="Comparison summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% with summary_class="summary summary--comparison", summary_label="Comparison summary statistics" %}
{% include "_summary_cards.html" %}
{% endwith %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/hits_allowed.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -72,15 +72,7 @@ <h2>{{ analysis.team_name }} &mdash; Hits Allowed per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand All @@ -51,15 +51,7 @@ <h2>{{ analysis.team_name }} — Hits per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/pitching.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -71,15 +71,7 @@ <h2>{{ analysis.team_name }} &mdash; Pitches per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/run_differential.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -73,15 +73,7 @@ <h2>{{ analysis.team_name }} — Run Differential per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/runs.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand All @@ -51,15 +51,7 @@ <h2>{{ analysis.team_name }} — Runs Scored per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
12 changes: 2 additions & 10 deletions app/web/templates/strikeouts.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h2>No team data has been imported yet</h2>
<pre class="command"><code>{{ import_command }}</code></pre>
</section>
{% else %}
{% include "_selector_form.html" %}
{% include "_team_selector_form.html" %}

{% if state == "not_found" %}
<section class="card notice">
Expand Down Expand Up @@ -70,15 +70,7 @@ <h2>{{ analysis.team_name }} — Batting Strikeouts per Game</h2>
<div class="chart-card__figure">{{ chart_html | safe }}</div>
</section>

<section class="summary" aria-label="Summary statistics">
{% for card in summary_cards %}
<article class="card summary-card">
<p class="summary-card__label">{{ card.label }}</p>
<p class="summary-card__value">{{ card.value }}</p>
<p class="summary-card__caption">{{ card.caption }}</p>
</article>
{% endfor %}
</section>
{% include "_summary_cards.html" %}

<section class="about">
<span class="about__icon" aria-hidden="true">
Expand Down
4 changes: 2 additions & 2 deletions docs/team-strikeouts-visualization.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ and their labels must stay distinct. A `GenericMetricEngine` would have to
encode all of that as configuration.

What *is* shared is genuinely shared infrastructure that already existed: the
team-season selector (`app/web/selection.py`), the selector form partial
(`_selector_form.html`), figure rendering, and date/matchup formatting.
team-season selector (`app/web/selection.py`), the Team selector form partial
(`_team_selector_form.html`), figure rendering, and date/matchup formatting.

## 10. Legacy null-data behavior

Expand Down
6 changes: 6 additions & 0 deletions docs/ui-information-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ navigation through `_team_navigation.html`. Individual metric templates retain
selectors, charts, interpretation, and recovery states. A future Player UI can
extend the same shell without copying Team assumptions.

Team metric pages include `_team_selector_form.html` for their Team, season, and
rolling-window GET controls. It relies on the Team-season catalog and stays
outside the entity-neutral shell; future Player selection should follow its own
requirements. The small `_summary_cards.html` partial renders route-provided
cards and preserves Comparison's distinct section class and accessible label.

The brand links to bare `/`. On Team pages, Teams links to the selection-aware
Hits URL. Metric links preserve `team_id`, `season`, and `window`, including the
existing requested-versus-resolved distinction in terminal states. Generic
Expand Down
2 changes: 2 additions & 0 deletions tests/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ def test_page_contains_the_summary_cards(client: TestClient, seed: SeedFn) -> No
"""Milestone 5 replaced the prior-window card with the MLB comparison."""
seed(hits=[6, 8, 10, 12] * 10)
body = client.get("/").text
assert '<section class="summary" aria-label="Summary statistics">' in body
assert body.count('class="card summary-card"') == 4
assert "Recent 15-Game Avg" in body
assert "Season Avg" in body
assert "vs MLB" in body
Expand Down
4 changes: 4 additions & 0 deletions tests/test_web_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ def test_complete_coverage_renders_exact_rolling_indexes_and_four_summary_cards(
assert traces[2]["y"] == pytest.approx([100.0, 100.0])

cards = summary_card_values(body)
assert (
'<section class="summary summary--comparison" '
'aria-label="Comparison summary statistics">'
) in body
assert set(cards) == {
"Recent Hits Index",
"Recent K Index",
Expand Down
10 changes: 10 additions & 0 deletions tests/test_web_page_scaffolding.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ def test_empty_database_renders_the_empty_state_with_requested_values(
assert "--team-id 136 --season 2025" in body
# No stored team means no selector form to fill in.
assert '<select id="team_id"' not in body
assert 'id="team-seasons-data"' not in body
assert "/static/js/season-selector.js" not in body
assert_navigation(body, current=page, query="window=15")

requested = client.get(f"{path}?team_id=147&season=2023&window=5")
Expand Down Expand Up @@ -414,6 +416,14 @@ def test_explicit_selection_is_reflected_in_the_form_and_navigation(
assert response.status_code == 200
body = response.text
assert f'<form class="controls card" method="get" action="{path}">' in body
for field in ("team_id", "season", "window"):
assert f'<label for="{field}">' in body
assert f'<select id="{field}" name="{field}">' in body
assert '<img class="control__logo js-logo"' in body
assert 'alt=""' in body
assert 'id="team-seasons-data"' in body
assert "/static/js/season-selector.js" in body
assert '<button type="submit">Update chart</button>' in body
assert f'<option value="{MARINERS_ID}" selected>{MARINERS_NAME}</option>' in body
assert '<option value="2024" selected>2024</option>' in body
assert '<option value="5" selected>5 Games</option>' in body
Expand Down
Loading