Feat: Decks page.

This commit is contained in:
2026-02-16 19:30:31 +00:00
parent 1cd9b7c976
commit 5661632540
75 changed files with 11850 additions and 536 deletions

View File

@@ -0,0 +1,5 @@
{% set value_previous = '0' if is_blank_row else commander_bracket_preview.commander_bracket_id %}
{% set text_previous = '' if is_blank_row else commander_bracket_preview.name %}
<div class="{{ model.ATTR_COMMANDER_BRACKET_ID }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ value_previous }}" {{ model.ATTR_VALUE_CURRENT }}="{{ value_previous }}">{{ text_previous }}</div>

View File

@@ -0,0 +1,44 @@
{% if is_blank_row %}
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_DECK }}" {{ model.ATTR_DECK_ID }}>
<td class="{{ model.FLAG_NAME }}">
<input type="text"
class="{{ model.FLAG_NAME }}"
{{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }} />
</td>
<td class="{{ model.FLAG_IS_COMMANDER }}">
<input type="checkbox"
class="{{ model.FLAG_IS_COMMANDER }}"
{{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }} />
</td>
<td class="{{ model.ATTR_COMMANDER_BRACKET_ID }} {{ model.FLAG_DDL_PREVIEW }}">
{% include 'components/tcg/_preview_ddl_commander_bracket.html' %}
</td>
{% set active = True %}
{% include 'components/common/inputs/_td_active.html' %}
</tr>
{% else %}
<tr class="{{ model.FLAG_DECK }}" {{ model.ATTR_DECK_ID }}="{{ deck.deck_id }}">
<td class="{{ model.FLAG_NAME }}">
<input type="text"
class="{{ model.FLAG_NAME }}"
{{ model.ATTR_VALUE_CURRENT }}="{{ deck.name }}"
{{ model.ATTR_VALUE_PREVIOUS }}="{{ deck.name }}"
value="{{ deck.name }}" />
</td>
<td class="{{ model.FLAG_IS_COMMANDER }}">
<input type="checkbox"
class="{{ model.FLAG_IS_COMMANDER }}"
{{ model.ATTR_VALUE_CURRENT }}="{{ deck.is_commander | lower }}"
{{ model.ATTR_VALUE_PREVIOUS }}="{{ deck.is_commander | lower }}"
{% if deck.is_commander %}checked{% endif %}
value="{{ deck.is_commander | lower }}" />
</td>
{% set commander_bracket_preview = deck.commander_bracket %}
<td class="{{ model.ATTR_COMMANDER_BRACKET_ID }} {{ model.FLAG_DDL_PREVIEW }}">
{% include 'components/tcg/_preview_ddl_commander_bracket.html' %}
</td>
{% set active = deck.active %}
{% include 'components/common/inputs/_td_active.html' %}
</tr>
{% endif %}

View File

@@ -1,23 +1,36 @@
<script>
var attrCommanderBracketId = "{{ model.ATTR_COMMANDER_BRACKET_ID }}";
var attrDamageId = "{{ model.ATTR_DAMAGE_ID }}";
var attrDeckId = "{{ model.ATTR_DECK_ID }}";
var attrGameId = "{{ model.ATTR_GAME_ID }}";
var attrPlayerId = "{{ model.ATTR_PLAYER_ID }}";
var attrRoundId = "{{ model.ATTR_ROUND_ID }}";
var attrDamageId = "{{ model.ATTR_DAMAGE_ID }}";
var attrDeckId = "{{ model.ATTR_DECK_ID }}";
var attrUserId = "{{ model.ATTR_USER_ID }}";
var attrUserAuth0Id = "{{ model.ATTR_USER_AUTH0_ID }}";
var flagGame = "{{ model.FLAG_GAME }}";
var flagPlayer = "{{ model.FLAG_PLAYER }}";
var flagRound = "{{ model.FLAG_ROUND }}";
var flagCommanderDeaths = "{{ model.FLAG_COMMANDER_DEATHS }}";
var flagDamage = "{{ model.FLAG_DAMAGE }}";
var flagDeck = "{{ model.FLAG_DECK }}";
var flagGame = "{{ model.FLAG_GAME }}";
var flagIsBool = "{{ model.FLAG_IS_BOOL }}";
var flagIsCommander = "{{ model.FLAG_IS_COMMANDER }}";
var flagIsDraft = "{{ model.FLAG_IS_DRAFT }}";
var flagIsEliminated = "{{ model.FLAG_IS_ELIMINATED }}";
var flagIsFloat = "{{ model.FLAG_IS_FLOAT }}";
var flagIsInterval = "{{ model.FLAG_IS_INTERVAL }}";
var flagIsSealed = "{{ model.FLAG_IS_SEALED }}";
var flagHealthChange = "{{ model.FLAG_HEALTH_CHANGE }}";
var flagCommanderDeaths = "{{ model.FLAG_COMMANDER_DEATHS }}";
var flagIsText = "{{ model.FLAG_IS_TEXT }}";
var flagIsTimestamp = "{{ model.FLAG_IS_TIMESTAMP }}";
var flagLifeGain = "{{ model.FLAG_LIFE_GAIN }}";
var flagLifeLoss = "{{ model.FLAG_LIFE_LOSS }}";
var flagPlayer = "{{ model.FLAG_PLAYER }}";
var flagRound = "{{ model.FLAG_ROUND }}";
var flagUser = "{{ model.FLAG_USER }}";
var flagValueBool = "{{ model.FLAG_VALUE_BOOL }}";
var flagValueFloat = "{{ model.FLAG_VALUE_FLOAT }}";
var flagValueInterval = "{{ model.FLAG_VALUE_INTERVAL }}";
var flagValueText = "{{ model.FLAG_VALUE_TEXT }}";
var flagValueTimestamp = "{{ model.FLAG_VALUE_TIMESTAMP }}";
var hashSaveMtgGame = "{{ model.HASH_SAVE_MTG_GAME }}";
var hashSaveMtgGamePlayer = "{{ model.HASH_SAVE_MTG_GAME_PLAYER }}";
var hashSaveMtgGameRound = "{{ model.HASH_SAVE_MTG_GAME_ROUND }}";

View File

@@ -102,6 +102,7 @@
var flagTableMain = "{{ model.FLAG_TABLE_MAIN }}";
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
var flagUser = "{{ model.FLAG_USER }}";
var flagValue = "{{ model.FLAG_VALUE }}";
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
var hashGetALTCHAChallenge = "{{ model.HASH_GET_ALTCHA_CHALLENGE }}";
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";

View File

@@ -43,24 +43,20 @@
<div class="footer-content">
<div class="footer-section">
<h3>{{ model.NAME_COMPANY }}</h3>
<p>Company Number: {{ model.COMPANY_NUMBER }}</p>
<p>Registered in England and Wales</p>
<p>Registered Office: {{ model.COMPANY_ADDRESS_SHORT }}</p>
<p>Email: {{ model.get_mail_contact_public() }}</p>
</div>
<div class="footer-section">
<h3>Legal</h3>
<ul>
<li><a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a></li>
<li><a href="{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}">Accessibility Statement</a></li>
</ul>
<a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a>
<a href="{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}">Accessibility Statement</a>
</div>
<div class="footer-section">
<p>&copy; {{ current_year }} {{ model.NAME_COMPANY }}. <a href="{{ model.HASH_PAGE_LICENSE }}" alt="License" aria-label="License">All rights reserved.</a></p>
</div>
</div>
</div>
<div class="footer-bottom">
<p>&copy; {{ current_year }} {{ model.NAME_COMPANY }}. <a href="{{ model.HASH_PAGE_LICENSE }}" alt="License" aria-label="License">All rights reserved.</a></p>
</div>
</footer>
{% include 'layouts/_shared_scripts.html' %}

View File

@@ -0,0 +1,111 @@
{% extends 'layouts/layout_tcg.html' %}
{% block page_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/tcg_decks.bundle.css') }}">
{% endblock %}
{% block page_body %}
{#
<div class="section-header">
<h2 class="tcg-section-title">Decks</h2>
</div>
#}
<!-- Filters Form -->
<form id="{{ model.ID_FORM_FILTERS }}" class="tcg-card {{ model.FLAG_FILTER }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
{{ model.form_filters.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_COLUMN }} {{ model.FLAG_FILTER }} {{ model.FLAG_SEARCH }}"
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.form_filters.search.data }}">
{{ model.form_filters.search.label(class="tcg-label") }}
{{ model.form_filters.search(class="tcg-input", placeholder="Search decks...") }}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_COLUMN }} {{ model.FLAG_FILTER }} {{ model.FLAG_ACTIVE }}"
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.form_filters.active_only.data }}">
{{ model.form_filters.active_only() }}
{{ model.form_filters.active_only.label(class="tcg-label") }}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_COLUMN }} {{ model.FLAG_FILTER }} {{ model.FLAG_IS_COMMANDER }}"
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.form_filters.is_commander.data }}">
{{ model.form_filters.is_commander() }}
{{ model.form_filters.is_commander.label(class="tcg-label") }}
</div>
</div>
{% set block_id = 'buttons_table_default' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</form>
{#
{% set block_id = 'container_buttons_save_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</form>
#}
<div class="decks-section tcg-card">
<!-- Decks Table -->
<table class="decks-table {{ model.FLAG_TABLE_MAIN }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }} {{ model.FLAG_DECK }}" id="{{ model.ID_TABLE_MAIN }}">
<thead>
<tr>
<th class="{{ model.FLAG_NAME }}">Name</th>
<th class="{{ model.FLAG_IS_COMMANDER }}">Is Commander</th>
<th class="{{ model.ATTR_COMMANDER_BRACKET_ID }}">Commander Bracket</th>
<th class="{{ model.FLAG_ACTIVE }}">
{% set class_name = model.FLAG_ACTIVE %}
{% set attribute_text = '' %}
{% include 'components/common/buttons/_icon_add.html' %}
</th>
</tr>
</thead>
<tbody>
{% set is_blank_row = False %}
{% for deck in model.decks %}
{% include 'components/tcg/_row_deck.html' %}
{% endfor %}
</tbody>
</table>
<!-- Statistics -->
<div class="section-header">
<h2 class="tcg-section-title">Statistics</h2>
</div>
<table class="{{ model.FLAG_STATISTICS }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }} {{ model.FLAG_DECK }}">
<thead>
<tr>
<th class="{{ model.FLAG_DECK }}">Deck</th>
<th class="{{ model.FLAG_NAME }}">Name</th>
<th class="{{ model.FLAG_VALUE }}">Value</th>
</tr>
</thead>
<tbody>
{% for statistic in model.statistics %}
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_STATISTIC }}" {{ model.ATTR_STATISTIC_ID }}>
<td class="{{ model.ATTR_DECK_ID }} {{ model.ATTR_ENTITY_RECORD_ID }}">{{ statistic.entity_record_name }}</td>
<td class="{{ model.FLAG_NAME }}">{{ statistic.name }}</td>
<td class="{{ model.FLAG_VALUE }}">{{ statistic.get_formatted_value() }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<div id="{{ model.ID_CONTAINER_TEMPLATE_ELEMENTS }}">
<!-- Active column -->
<!-- Delete -->
{% set class_name = '' %}
{% include 'components/common/buttons/_icon_trash.html' %}
<!-- Undelete -->
{% set class_name = model.FLAG_ACTIVE %}
{% set attribute_text = '' %}
{% include 'components/common/buttons/_icon_add.html' %}
</div>
<script>
var attrCommanderBracketId = "{{ model.ATTR_COMMANDER_BRACKET_ID }}";
var commanderBrackets = {{ model.convert_list_objects_to_json(model.commander_brackets) | tojson | safe }};
var decks = {{ model.convert_list_objects_to_json(model.decks) | tojson | safe }};
var flagStatistics = "{{ model.FLAG_STATISTICS }}";
var flagIsCommander = "{{ model.FLAG_IS_COMMANDER }}";
</script>
{% endblock %}

View File

@@ -135,7 +135,8 @@
<th class="{{ model.ATTR_ROUND_ID }}">Round</th>
<th class="{{ model.ATTR_PLAYER_ID }}">Player</th>
<th class="{{ model.ATTR_RECEIVED_FROM_COMMANDER_PLAYER_ID }}">Received From Commander</th>
<th class="{{ model.FLAG_HEALTH_CHANGE }}">Health Change</th>
<th class="{{ model.FLAG_LIFE_GAIN }}">Life Gain</th>
<th class="{{ model.FLAG_LIFE_LOSS }}">Life Loss</th>
<th class="{{ model.FLAG_COMMANDER_DEATHS }}">Commander Deaths</th>
<th class="{{ model.FLAG_IS_ELIMINATED }}">Is Eliminated</th>
</tr>
@@ -181,9 +182,6 @@
var damageRecords = {{ model.convert_list_objects_to_json(model.damage_records) | tojson | safe }};
var decks = {{ model.convert_list_objects_to_json(model.decks) | tojson | safe }};
var flagDamageLog = "{{ model.FLAG_DAMAGE_LOG }}";
var flagDisplayOrder = "{{ model.FLAG_DISPLAY_ORDER }}";
var flagHealthChange = "{{ model.FLAG_HEALTH_CHANGE }}";
var flagIsEliminated = "{{ model.FLAG_IS_ELIMINATED }}";
var flagRoundDisplayOrderButton = "{{ model.FLAG_ROUND_DISPLAY_ORDER_BUTTON }}";
var flagRoundDisplayOrderMinus = "{{ model.FLAG_ROUND_DISPLAY_ORDER_MINUS }}";
var flagRoundDisplayOrderPlus = "{{ model.FLAG_ROUND_DISPLAY_ORDER_PLUS }}";

View File

@@ -40,67 +40,65 @@
</form>
<!-- Games Table -->
<div class="games-table-container">
<table class="games-table" id="gamesTable">
<thead>
<tr>
<th>Game ID</th>
<th>Type</th>
<th>Location</th>
<th>Started</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% if model.games and model.games|length > 0 %}
{% for game in model.games %}
<tr class="game-row {% if not game.active %}inactive{% endif %}" data-game-id="{{ game.game_id }}">
<td class="game-id">#{{ game.game_id }}</td>
<td class="game-type">
{% if game.is_commander %}
<span class="badge badge-commander">Commander</span>
{% elif game.is_draft %}
<span class="badge badge-draft">Draft</span>
{% elif game.is_sealed %}
<span class="badge badge-sealed">Sealed</span>
{% else %}
<span class="badge badge-standard">Standard</span>
{% endif %}
</td>
<td class="game-location">{{ game.location_name or 'Unknown' }}</td>
<td class="game-date">{{ model.format_datetime_text(game.start_on) if game.start_on else 'Not started' }}</td>
<td class="game-status">
{% if game.end_on %}
<span class="status status-ended">Ended</span>
{% elif game.active %}
<span class="status status-active">Active</span>
{% else %}
<span class="status status-inactive">Inactive</span>
{% endif %}
</td>
<td class="game-actions">
<a href="{{ model.HASH_PAGE_MTG_GAME }}/{{ game.game_id }}" class="btn-tcg btn-join">Join Game</a>
</td>
</tr>
{% endfor %}
{% else %}
<tr class="no-games-row">
<td colspan="6" class="no-games">
<div class="no-games-message">
<span class="no-games-icon">&#x2694;</span>
<p>No games found. Start a new battle!</p>
</div>
<table class="games-table {{ model.FLAG_TABLE_MAIN }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }} {{ model.FLAG_DECK }}" id="{{ model.ID_TABLE_MAIN }}">
<thead>
<tr>
<th class="{{ model.ATTR_GAME_ID }}">Game ID</th>
<th class="{{ model.FLAG_IS_COMMANDER }}">Type</th>
<th class="{{ model.FLAG_LOCATION_NAME }}">Location</th>
<th class="{{ model.FLAG_START_ON }}">Started</th>
<th class="{{ model.FLAG_ACTIVE }}">Status</th>
<th class="{{ model.FLAG_NAV_MTG_GAME }}">Actions</th>
</tr>
</thead>
<tbody>
{% if model.games and model.games|length > 0 %}
{% for game in model.games %}
<tr class="game-row {% if not game.active %}inactive{% endif %}" data-game-id="{{ game.game_id }}">
<td class="{{ model.ATTR_GAME_ID }}">#{{ game.game_id }}</td>
<td class="{{ model.FLAG_IS_COMMANDER }}">
{% if game.is_commander %}
<span class="badge badge-commander">Commander</span>
{% elif game.is_draft %}
<span class="badge badge-draft">Draft</span>
{% elif game.is_sealed %}
<span class="badge badge-sealed">Sealed</span>
{% else %}
<span class="badge badge-standard">Standard</span>
{% endif %}
</td>
<td class="{{ model.FLAG_LOCATION_NAME }}">{{ game.location_name or 'Unknown' }}</td>
<td class="{{ model.FLAG_START_ON }}">{{ model.format_datetime_text(game.start_on) if game.start_on else 'Not started' }}</td>
<td class="{{ model.FLAG_ACTIVE }}">
{% if game.end_on %}
<span class="status status-ended">Ended</span>
{% elif game.active %}
<span class="status status-active">Active</span>
{% else %}
<span class="status status-inactive">Inactive</span>
{% endif %}
</td>
<td class="{{ model.FLAG_NAV_MTG_GAME }}">
<a href="{{ model.HASH_PAGE_MTG_GAME }}/{{ game.game_id }}" class="btn-tcg btn-join">Join Game</a>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% endfor %}
{% else %}
<tr class="no-games-row">
<td colspan="6" class="no-games">
<div class="no-games-message">
<span class="no-games-icon">&#x2694;</span>
<p>No games found. Start a new battle!</p>
</div>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
<!-- New Game Modal -->
<div id="newGameModal" class="modal-overlay hidden">
<div id="newGameModal" class="modal-overlay {{ model.FLAG_IS_COLLAPSED }}">
<div class="modal-content tcg-card">
<div class="modal-header">
<h2 class="tcg-section-title">Create New Game</h2>
@@ -158,5 +156,4 @@
var flagStartOn = "{{ model.FLAG_START_ON }}";
var flagStartingLife = "{{ model.FLAG_STARTING_LIFE }}";
</script>
{# <script src="{{ url_for('static', filename='js/pages/tcg/mtg_games.js') }}"></script> #}
{% endblock %}