Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< section >
< h3 > Step 5: Build< / h3 >
< div class = "two-col two-col-left-rail" >
< aside class = "card-preview" >
< a href = "https://scryfall.com/search?q={{ commander|urlencode }}" target = "_blank" rel = "noopener" >
< img src = "https://api.scryfall.com/cards/named?fuzzy={{ commander|urlencode }}&format=image&version=normal" alt = "{{ commander }} card image" / >
< / a >
{% if status and status.startswith('Build complete') %}
< div style = "margin-top:.75rem; display:flex; gap:.35rem; flex-wrap:wrap;" >
{% if csv_path %}
< form action = "/files" method = "get" target = "_blank" style = "display:inline; margin:0;" >
< input type = "hidden" name = "path" value = "{{ csv_path }}" / >
< 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 %}
< / div >
{% endif %}
< / aside >
< div class = "grow" >
< div hx-get = "/build/banner?step=Build&i=5&n=5" hx-trigger = "load" > < / div >
< p > Commander: < strong > {{ commander }}< / strong > < / p >
< p > Tags: {{ tags|default([])|join(', ') }}< / p >
2025-08-26 16:25:34 -07:00
< div style = "margin:.35rem 0; color: var(--muted); display:flex; gap:.5rem; align-items:center; flex-wrap:wrap;" >
< span > Owned-only: < strong > {{ 'On' if owned_only else 'Off' }}< / strong > < / span >
< div style = "display:flex;align-items:center;gap:1rem;" >
< button type = "button" hx-get = "/build/step4" hx-target = "#wizard" hx-swap = "innerHTML" style = "background:#374151; color:#e5e7eb; border:none; border-radius:6px; padding:.25rem .5rem; cursor:pointer; font-size:12px;" title = "Change owned settings in Review" > Edit in Review< / button >
< div > Prefer-owned: < strong > {{ 'On' if prefer_owned else 'Off' }}< / strong > < / div >
< / div >
< span style = "margin-left:auto;" > < a href = "/owned" target = "_blank" rel = "noopener" class = "muted" > Manage Owned Library< / a > < / span >
< / div >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< p > Bracket: {{ bracket }}< / p >
{% if i and n %}
< div class = "muted" style = "margin:.25rem 0 .5rem 0;" > Stage {{ i }}/{{ n }}< / div >
{% endif %}
{% if status %}
< div style = "margin-top:1rem;" >
< strong > Status:< / strong > {{ status }}{% if stage_label %} — < em > {{ stage_label }}< / em > {% endif %}
< / div >
{% endif %}
<!-- Controls moved back above the cards as requested -->
< div style = "margin-top:1rem; display:flex; gap:.5rem; flex-wrap:wrap; align-items:center;" >
2025-08-26 16:25:34 -07:00
< form hx-post = "/build/step5/start" hx-target = "#wizard" hx-swap = "innerHTML" style = "display:inline; margin-right:.5rem; display:flex; align-items:center; gap:.5rem;" >
< input type = "hidden" name = "show_skipped" value = "{{ '1' if show_skipped else '0' }}" / >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< button type = "submit" > Start Build< / button >
< / form >
2025-08-26 16:25:34 -07:00
< form hx-post = "/build/step5/continue" hx-target = "#wizard" hx-swap = "innerHTML" style = "display:inline; display:flex; align-items:center; gap:.5rem;" >
< input type = "hidden" name = "show_skipped" value = "{{ '1' if show_skipped else '0' }}" / >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< button type = "submit" { % if status and status . startswith ( ' Build complete ' ) % } disabled { % endif % } > Continue< / button >
< / form >
2025-08-26 16:25:34 -07:00
< form hx-post = "/build/step5/rerun" hx-target = "#wizard" hx-swap = "innerHTML" style = "display:inline; display:flex; align-items:center; gap:.5rem;" >
< input type = "hidden" name = "show_skipped" value = "{{ '1' if show_skipped else '0' }}" / >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< button type = "submit" { % if status and status . startswith ( ' Build complete ' ) % } disabled { % endif % } > Rerun Stage< / button >
< / form >
2025-08-26 16:25:34 -07:00
< label class = "muted" style = "display:flex; align-items:center; gap:.35rem; margin-left: .5rem;" >
< input type = "checkbox" name = "__toggle_show_skipped" { % if show_skipped % } checked { % endif % }
onchange="const val=this.checked?'1':'0'; for(const f of this.closest('section').querySelectorAll('form')){ const h=f.querySelector('input[name=show_skipped]'); if(h) h.value=val; }" />
Show skipped stages
< / label >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< button type = "button" hx-get = "/build/step4" hx-target = "#wizard" hx-swap = "innerHTML" > Back< / button >
< / div >
2025-08-26 16:25:34 -07:00
{% if added_cards is not none %}
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< h4 style = "margin-top:1rem;" > Cards added this stage< / h4 >
2025-08-26 16:25:34 -07:00
{% if skipped and (not added_cards or added_cards|length == 0) %}
< div class = "muted" style = "margin:.25rem 0 .5rem 0;" > No cards added in this stage.< / div >
{% endif %}
< div class = "muted" style = "font-size:12px; margin:.15rem 0 .4rem 0; display:flex; gap:.75rem; align-items:center; flex-wrap:wrap;" >
< span > < span style = "display:inline-block; border:1px solid var(--border); background:rgba(17,24,39,.9); color:#e5e7eb; border-radius:12px; font-size:12px; line-height:18px; height:18px; min-width:18px; padding:0 6px; text-align:center;" > ✔< / span > Owned< / span >
< span > < span style = "display:inline-block; border:1px solid var(--border); background:rgba(17,24,39,.9); color:#e5e7eb; border-radius:12px; font-size:12px; line-height:18px; height:18px; min-width:18px; padding:0 6px; text-align:center;" > ✖< / span > Not owned< / span >
< / div >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
{% if stage_label and stage_label.startswith('Creatures') %}
{% set groups = added_cards|groupby('sub_role') %}
{% for g in groups %}
{% set role = g.grouper %}
{% if role %}
{% set heading = 'Theme: ' + role.title() %}
{% else %}
{% set heading = 'Additional Picks' %}
{% endif %}
< h5 style = "margin:.5rem 0 .25rem 0;" > {{ heading }}< / h5 >
< div class = "card-grid" >
{% for c in g.list %}
2025-08-26 16:25:34 -07:00
{% set owned = (owned_set is defined and c.name and (c.name|lower in owned_set)) %}
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< div class = "card-tile{% if game_changers and (c.name in game_changers) %} game-changer{% endif %}" data-card-name = "{{ c.name }}" data-role = "{{ c.role or c.sub_role or '' }}" data-tags = "{{ (c.tags|join(', ')) if c.tags else '' }}" >
< a href = "https://scryfall.com/search?q={{ c.name|urlencode }}" target = "_blank" rel = "noopener" >
< img src = "https://api.scryfall.com/cards/named?fuzzy={{ c.name|urlencode }}&format=image&version=normal" alt = "{{ c.name }} image" width = "160" / >
< / a >
2025-08-26 16:25:34 -07:00
< div class = "owned-badge" title = "{{ 'Owned' if owned else 'Not owned' }}" aria-label = "{{ 'Owned' if owned else 'Not owned' }}" > {% if owned %}✔{% else %}✖{% endif %}< / div >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< div class = "name" > {{ c.name }}{% if c.count and c.count > 1 %} × {{ c.count }}{% endif %}< / div >
{% if c.reason %}< div class = "reason" > {{ c.reason }}< / div > {% endif %}
< / div >
{% endfor %}
< / div >
{% endfor %}
{% else %}
< div class = "card-grid" >
{% for c in added_cards %}
2025-08-26 16:25:34 -07:00
{% set owned = (owned_set is defined and c.name and (c.name|lower in owned_set)) %}
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< div class = "card-tile{% if game_changers and (c.name in game_changers) %} game-changer{% endif %}" data-card-name = "{{ c.name }}" data-role = "{{ c.role or c.sub_role or '' }}" data-tags = "{{ (c.tags|join(', ')) if c.tags else '' }}" >
< a href = "https://scryfall.com/search?q={{ c.name|urlencode }}" target = "_blank" rel = "noopener" >
< img src = "https://api.scryfall.com/cards/named?fuzzy={{ c.name|urlencode }}&format=image&version=normal" alt = "{{ c.name }} image" width = "160" / >
< / a >
2025-08-26 16:25:34 -07:00
< div class = "owned-badge" title = "{{ 'Owned' if owned else 'Not owned' }}" aria-label = "{{ 'Owned' if owned else 'Not owned' }}" > {% if owned %}✔{% else %}✖{% endif %}< / div >
Web UI: setup progress + logs folding, Finished Decks library, commander search UX (debounce, keyboard, highlights, color chips), ranking fixes (first-word priority, substring include), optional auto-select; setup start reliability (POST+GET), force runs, status with percent/ETA/timestamps; stepwise builder with added stage reporting and sidecar summaries; keyboard grid wrap-around; restrict commander search to eligible rows
2025-08-26 09:48:25 -07:00
< div class = "name" > {{ c.name }}{% if c.count and c.count > 1 %} × {{ c.count }}{% endif %}< / div >
{% if c.reason %}< div class = "reason" > {{ c.reason }}< / div > {% endif %}
< / div >
{% endfor %}
< / div >
{% endif %}
{% endif %}
{% if show_logs and log %}
< details style = "margin-top:1rem;" >
< summary > Show logs< / summary >
< pre style = "margin-top:.5rem; white-space:pre-wrap; background:#0f1115; border:1px solid var(--border); padding:1rem; border-radius:8px; max-height:40vh; overflow:auto;" > {{ log }}< / pre >
< / details >
{% endif %}
<!-- controls now above -->
{% if status and status.startswith('Build complete') %}
{% if summary %}
{% include "partials/deck_summary.html" %}
{% endif %}
{% endif %}
< / div >
< / div >
< / section >