mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2026-03-24 14:06:31 +01:00
195 lines
10 KiB
HTML
195 lines
10 KiB
HTML
{% extends "base.html" %}
|
||
{% block banner_subtitle %}Finished Decks{% endblock %}
|
||
{% block content %}
|
||
<h2>Finished Deck</h2>
|
||
{% if display_name %}
|
||
<div><strong>{{ display_name }}</strong></div>
|
||
{% endif %}
|
||
{% set hover_tags_source = deck_theme_tags if deck_theme_tags else (tags if tags else commander_combined_tags) %}
|
||
{% set hover_tags_joined = hover_tags_source|join(', ') %}
|
||
<div class="muted">Commander:
|
||
<strong class="commander-hover"
|
||
data-card-name="{{ commander }}"
|
||
data-original-name="{{ commander }}"
|
||
data-role="{{ commander_role_label }}"
|
||
{% if hover_tags_joined %}data-tags="{{ hover_tags_joined }}"{% endif %}
|
||
{% if commander_tag_slugs %}data-tags-slug="{{ commander_tag_slugs|join(' ') }}"{% endif %}
|
||
{% if commander_overlap_tags %}data-overlaps="{{ commander_overlap_tags|join(', ') }}"{% endif %}
|
||
{% if commander_reason_text %}data-reasons="{{ commander_reason_text|e }}"{% endif %}>{{ commander }}</strong>
|
||
{% if tags and tags|length %} • Themes: {{ tags|join(', ') }}{% endif %}
|
||
</div>
|
||
<div class="muted">This view mirrors the end-of-build summary. Use the buttons to download the CSV/TXT exports.</div>
|
||
|
||
<div class="two-col two-col-left-rail" style="margin-top:.75rem;">
|
||
<aside class="card-preview">
|
||
{% if commander %}
|
||
{# Strip synergy annotation for Scryfall search and image fuzzy param #}
|
||
{% set commander_base = (commander.split(' - Synergy (')[0] if ' - Synergy (' in commander else commander) %}
|
||
<div class="commander-card"
|
||
tabindex="0"
|
||
style="display:inline-block; cursor:pointer;"
|
||
data-card-name="{{ commander_base }}"
|
||
data-original-name="{{ commander }}"
|
||
data-role="{{ commander_role_label }}"
|
||
{% if hover_tags_joined %}data-tags="{{ hover_tags_joined }}"{% endif %}
|
||
{% if commander_tag_slugs %}data-tags-slug="{{ commander_tag_slugs|join(' ') }}"{% endif %}
|
||
{% if commander_overlap_tags %}data-overlaps="{{ commander_overlap_tags|join(', ') }}"{% endif %}
|
||
{% if commander_reason_text %}data-reasons="{{ commander_reason_text|e }}"{% endif %}>
|
||
<img src="{{ commander_base|card_image('normal') }}"
|
||
alt="{{ commander }} card image"
|
||
data-card-name="{{ commander_base }}"
|
||
data-original-name="{{ commander }}"
|
||
data-role="{{ commander_role_label }}"
|
||
{% if hover_tags_joined %}data-tags="{{ hover_tags_joined }}"{% endif %}
|
||
{% if commander_tag_slugs %}data-tags-slug="{{ commander_tag_slugs|join(' ') }}"{% endif %}
|
||
{% if commander_overlap_tags %}data-overlaps="{{ commander_overlap_tags|join(', ') }}"{% endif %}
|
||
{% if commander_reason_text %}data-reasons="{{ commander_reason_text|e }}"{% endif %}
|
||
width="320" />
|
||
</div>
|
||
<div class="muted" style="margin-top:.25rem;">Commander: <span data-card-name="{{ commander }}"
|
||
data-original-name="{{ commander }}"
|
||
data-role="{{ commander_role_label }}"
|
||
{% if hover_tags_joined %}data-tags="{{ hover_tags_joined }}"{% endif %}
|
||
{% if commander_tag_slugs %}data-tags-slug="{{ commander_tag_slugs|join(' ') }}"{% endif %}
|
||
{% if commander_overlap_tags %}data-overlaps="{{ commander_overlap_tags|join(', ') }}"{% endif %}
|
||
{% if commander_reason_text %}data-reasons="{{ commander_reason_text|e }}"{% endif %}>{{ commander }}</span></div>
|
||
{% endif %}
|
||
<div style="margin-top:.75rem; display:flex; gap:.35rem; flex-wrap:wrap;">
|
||
{% if csv_path %}
|
||
<form action="/decks/download-csv" method="get" target="_blank" style="display:inline; margin:0;">
|
||
<input type="hidden" name="name" value="{{ name }}" />
|
||
<button type="submit">Download CSV</button>
|
||
</form>
|
||
{% endif %}
|
||
{% if txt_path %}
|
||
<form action="/files" method="get" target="_blank" style="display:inline; margin:0;">
|
||
<input type="hidden" name="path" value="{{ txt_path }}" />
|
||
<button type="submit">Download TXT</button>
|
||
</form>
|
||
{% endif %}
|
||
<a href="/decks/compare?A={{ name|urlencode }}" class="btn" role="button" title="Compare this deck with another">Compare…</a>
|
||
{% if budget_report %}
|
||
<a href="/decks/pickups?name={{ name|urlencode }}" class="btn" role="button" title="View cards to acquire for this budget build">Pickups List</a>
|
||
{% endif %}
|
||
<form method="get" action="/decks" style="display:inline; margin:0;">
|
||
<button type="submit">Back to Finished Decks</button>
|
||
</form>
|
||
</div>
|
||
{% if budget_report %}
|
||
{% set bstatus = budget_report.budget_status %}
|
||
<div class="budget-badge budget-badge--{{ bstatus }}" style="margin-top:.6rem;">
|
||
{% if bstatus == 'under' %}
|
||
Under Budget: ${{ "%.2f"|format(budget_report.total_price) }} / ${{ "%.2f"|format(budget_config.total) }}
|
||
{% elif bstatus == 'soft_exceeded' %}
|
||
Over Budget (soft): ${{ "%.2f"|format(budget_report.total_price) }} / ${{ "%.2f"|format(budget_config.total) }}
|
||
(+${{ "%.2f"|format(budget_report.overage) }})
|
||
{% else %}
|
||
Hard Cap Exceeded: ${{ "%.2f"|format(budget_report.total_price) }} / ${{ "%.2f"|format(budget_config.total) }}
|
||
(+${{ "%.2f"|format(budget_report.overage) }})
|
||
{% endif %}
|
||
</div>
|
||
{% if budget_report.over_budget_cards %}
|
||
<div class="panel panel-info-warning" style="margin-top:.5rem;">
|
||
<strong>Cards over budget:</strong>
|
||
<ul class="muted" style="margin:.25rem 0 0 1rem; padding:0; font-size:.85em;">
|
||
{% for c in budget_report.over_budget_cards %}
|
||
<li>{{ c.card }} — ${{ "%.2f"|format(c.price) }}{% if c.ceiling_exceeded %} (above ${{ "%.2f"|format(budget_config.card_ceiling) }} ceiling){% endif %}</li>
|
||
{% endfor %}
|
||
</ul>
|
||
</div>
|
||
{% endif %}
|
||
{% endif %}
|
||
</aside>
|
||
<div class="grow">
|
||
{% if summary %}
|
||
{% if owned_set %}
|
||
{% set ns = namespace(owned=0, total=0) %}
|
||
{% set tb = summary.type_breakdown %}
|
||
{% if tb and tb.cards %}
|
||
{% for t, clist in tb.cards.items() %}
|
||
{% for c in clist %}
|
||
{% set cnt = c.count if c.count else 1 %}
|
||
{% set ns.total = ns.total + cnt %}
|
||
{% if c.name and (c.name|lower in owned_set) %}
|
||
{% set ns.owned = ns.owned + cnt %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{% endfor %}
|
||
{% endif %}
|
||
{% set not_owned = (ns.total - ns.owned) %}
|
||
{% set pct = ( (ns.owned * 100.0 / (ns.total or 1)) | round(1) ) %}
|
||
<div class="panel" style="margin-bottom:.75rem;">
|
||
<div style="display:flex; gap:1rem; align-items:center; flex-wrap:wrap;">
|
||
<div><strong>Ownership</strong></div>
|
||
<div class="muted">Owned: {{ ns.owned }} • Not owned: {{ not_owned }} • Total: {{ ns.total }} ({{ pct }}%)</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{{ render_cached('partials/deck_summary.html', name, request=request, summary=summary, game_changers=game_changers, owned_set=owned_set, combos=combos, synergies=synergies, versions=versions) | safe }}
|
||
{# M8: Price charts accordion — placed in main area, only available on the saved deck view #}
|
||
{% if (price_category_chart and price_category_chart.total > 0) or price_histogram_chart %}
|
||
<section class="summary-section-lg">
|
||
<details class="analytics-accordion" id="price-charts-accordion">
|
||
<summary class="combo-summary">
|
||
<span>Price Breakdown</span>
|
||
<span class="muted text-xs font-normal ml-2">spend by category & distribution</span>
|
||
</summary>
|
||
<div class="analytics-content mt-3">
|
||
{% if price_category_chart and price_category_chart.total > 0 %}
|
||
<div class="price-cat-section">
|
||
<div class="price-cat-heading">Spend by Category — ${{ '%.2f'|format(price_category_chart.total) }} total</div>
|
||
<div class="price-cat-bar" title="Total: ${{ '%.2f'|format(price_category_chart.total) }}">
|
||
{% for cat in price_category_chart.order %}
|
||
{% set cat_total = price_category_chart.totals.get(cat, 0) %}
|
||
{% if cat_total > 0 %}
|
||
{% set pct = (cat_total * 100 / price_category_chart.total) | round(1) %}
|
||
<div class="price-cat-seg"
|
||
style="width:{{ pct }}%; background:{{ price_category_chart.colors.get(cat, '#f59e0b') }};"
|
||
title="{{ cat }}: ${{ '%.2f'|format(cat_total) }} ({{ pct }}%)"></div>
|
||
{% endif %}
|
||
{% endfor %}
|
||
</div>
|
||
<div class="price-cat-legend">
|
||
{% for cat in price_category_chart.order %}
|
||
{% set cat_total = price_category_chart.totals.get(cat, 0) %}
|
||
{% if cat_total > 0 %}
|
||
<span class="price-cat-legend-item">
|
||
<span class="price-cat-swatch" style="background:{{ price_category_chart.colors.get(cat, '#f59e0b') }};"></span>
|
||
{{ cat }} ${{ '%.2f'|format(cat_total) }}
|
||
</span>
|
||
{% endif %}
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{% if price_histogram_chart %}
|
||
<div class="price-hist-section">
|
||
<div class="price-hist-heading">Price Distribution</div>
|
||
<div class="price-hist-bars">
|
||
{% for bin in price_histogram_chart %}
|
||
<div class="price-hist-column"
|
||
data-type="hist"
|
||
data-range="${{ '%.2f'|format(bin.range_min) }}–${{ '%.2f'|format(bin.range_max) }}"
|
||
data-val="{{ bin.count }}"
|
||
data-cards="{% for c in bin.cards %}{{ c.name }}|{{ '%.2f'|format(c.price) }}{% if not loop.last %} • {% endif %}{% endfor %}">
|
||
<div class="price-hist-bar" style="height:{{ bin.pct | default(0) }}%; background:{{ bin.color }};"></div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
<div class="price-hist-xlabels">
|
||
{% for bin in price_histogram_chart %}
|
||
<div class="price-hist-xlabel">{{ bin.x_label }}</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</details>
|
||
</section>
|
||
{% endif %}
|
||
{% else %}
|
||
<div class="muted">No summary available.</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|