Reduce size of card badges, and change trade offers to show all cards by default, but in minimized mode. expand button now toggles between minimized mode and expanded mode for all cards on the trade offer

This commit is contained in:
badblocks 2025-04-03 20:54:09 -07:00
parent 01becbee48
commit fa4f38301b
16 changed files with 117 additions and 236 deletions

View file

@ -5,17 +5,18 @@ from django.utils.safestring import mark_safe
register = template.Library()
@register.inclusion_tag("templatetags/card_badge.html")
def card_badge(card, quantity=1):
def card_badge(card, quantity=None, static=False):
return {
'quantity': quantity,
'style': card.style,
'name': card.name,
'rarity': card.rarity_icon,
'cardset': card.cardset,
'static': static,
}
@register.filter
def card_badge_inline(card, quantity=1):
def card_badge_inline(card, quantity=None):
"""
Renders an inline card badge.
"""
@ -25,5 +26,6 @@ def card_badge_inline(card, quantity=1):
'name': card.name,
'rarity': card.rarity_icon,
'cardset': card.cardset,
'static': True,
})
return mark_safe(html)

View file

@ -3,19 +3,19 @@
{% if group_by and groups %}
{% for group in groups %}
<div class="divider">{{ group.group }}</div>
<div class="flex justify-center flex-wrap gap-4">
<div class="flex justify-center flex-wrap">
{% for card in group.cards %}
<a href="{% url 'cards:card_detail' card.pk %}">
{% card_badge card "" %}
{% card_badge card static=True %}
</a>
{% endfor %}
</div>
{% endfor %}
{% else %}
<div class="flex justify-center flex-wrap gap-4">
<div class="flex justify-center flex-wrap">
{% for card in cards %}
<a href="{% url 'cards:card_detail' card.pk %}">
{% card_badge card "" %}
{% card_badge card static=True %}
</a>
{% endfor %}
</div>

View file

@ -1,10 +1,8 @@
{% load trade_offer_tags %}
{% if trade_offers %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex flex-row flex-wrap gap-1 justify-center items-start">
{% for offer in trade_offers %}
<div class="mb-4">
{% render_trade_offer offer %}
</div>
{% endfor %}
</div>
{% else %}

View file

@ -1,7 +1,6 @@
{% extends "base.html" %}
{% load static card_badge %}
{% block content %}
<div class="container mx-auto p-4">
<!-- Card header with badge and details -->
<div class="flex items-center mb-6">
<div class="ml-4">
@ -95,5 +94,4 @@
</div>
</div>
</div>
{% endblock %}

View file

@ -27,13 +27,13 @@
<!-- Sort Dropdown -->
<div class="dropdown dropdown-end m-1">
<div tabindex="0" class="btn">
Sort by: <span x-text="order === 'absolute' ? 'None' : (order === 'alphabetical' ? 'Alphabetical' : 'Rarity')"></span>
Sort by: <span x-text="order === 'absolute' ? 'Cardset' : (order === 'alphabetical' ? 'Alphabetical' : 'Rarity')"></span>
<svg class="size-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-52">
<li><a href="#" @click.prevent="order = 'absolute'; page = 1; loadCards()">None</a></li>
<li><a href="#" @click.prevent="order = 'absolute'; page = 1; loadCards()">Cardset</a></li>
<li><a href="#" @click.prevent="order = 'alphabetical'; page = 1; loadCards()">Alphabetical</a></li>
<li><a href="#" @click.prevent="order = 'rarity'; page = 1; loadCards()">Rarity</a></li>
</ul>

View file

@ -4,7 +4,7 @@
{% for card in cards %}
<a href="{% url 'cards:card_detail' card.id %}"
class="flex justify-between items-center text-primary no-underline">
{% card_badge card card.offer_count %}
{% card_badge card quantity=card.offer_count static=True %}
</a>
{% endfor %}
</div>

View file

@ -4,7 +4,7 @@
For a TradeOffer, we use {% render_trade_offer %}; for a TradeAcceptance, {% render_trade_acceptance %}.
{% endcomment %}
<div class="flex flex-row gap-4 flex-wrap justify-center items-start">
<div class="flex flex-row gap-2 flex-wrap justify-center items-start">
{% for offer in offers %}
<div class="flex flex-none">
{% if offer.accepted_by %}

View file

@ -8,7 +8,7 @@
<form method="post" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit Acceptance</button>
<button type="submit" class="btn btn-primary">Accept Trade</button>
</form>
{% if form.errors %}
<div class="alert alert-error mt-4">

View file

@ -4,7 +4,7 @@
{% block title %}Trade Offers{% endblock title %}
{% block content %}
<div class="container mx-auto max-w-4xl mt-6" x-data="{
<div x-data="{
// Initialize allExpanded from the URL if present, defaulting to false.
allExpanded: new URLSearchParams(window.location.search).get('expanded') === 'true',
page: {{ page_obj.number|default:1 }},

View file

@ -46,7 +46,7 @@
</div>
{% endif %}
<div class="mt-6 flex justify-between">
<div class="mt-6 flex justify-end">
{% if is_initiator %}
<a href="{{ delete_close_url }}" class="btn btn-danger">Delete/Close Trade Offer</a>
{% elif request.user.is_authenticated %}

View file

@ -1,8 +1,19 @@
<div class="card-badge relative inline-block">
<div class="card-badge-inner freeze-bg-color grid grid-cols-4 grid-rows-2 my-2 px-2 py-2 h-14 w-36 text-white shadow-md shadow-black/50" style="{{ style }}">
<div class="cardname row-span-1 col-span-4 truncate text-ellipsis self-start font-semibold leading-tight text-sm max-w-7/8">{{ name }}</div>
<div class="rarity row-start-2 col-span-2 truncate self-end align-bottom text-xs">{{ rarity }}</div>
<div class="cardset row-start-2 col-start-3 col-span-2 text-right truncate self-end align-bottom font-semibold leading-none text-sm">{{ cardset }}</div>
{% if not static %}
<div class="relative block">
<div :class="badgeExpanded ? 'grid grid-rows-2 grid-cols-4 h-[52px]' : 'flex flex-row items-center h-[32px]'" x-transition.duration.500ms class="p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
<div :class="badgeExpanded ? 'row-start-1 col-start-1 col-span-3' : 'grow'" x-transition.duration.500ms class="truncate text-ellipsis font-semibold leading-tight text-sm">{{ name }}</div>
<div x-show="badgeExpanded" x-transition.duration.500ms x-cloak class="row-start-2 col-start-1 col-span-3 truncate align-bottom text-xs">{{ rarity }}</div>
<div x-show="true" x-transition.duration.500ms x-cloak :class="badgeExpanded ? 'row-start-2 col-start-4 col-span-1 align-bottom' : 'grow-0 shrink-0'" class="text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
{% if quantity != None %}<div x-show="true" x-transition.duration.500ms x-cloak :class="badgeExpanded ? 'row-start-1 col-start-4 justify-self-end -me-0.5' : 'grow-0 shrink-0'" class="relative w-fit ps-1"><div class="card-quantity-badge relative bg-gray-600 text-white text-sm font-semibold rounded-full text-center size-max px-1.5">{{ quantity }}</div></div>{% endif %}
</div>
{% if quantity != "" %}<span class="card-quantity-badge freeze-bg-color absolute top-3.75 right-1.5 bg-gray-600 text-white text-sm font-semibold rounded-full px-1.5">{{ quantity }}</span>{% endif %}
</div>
{% else %}
<div class="relative inline-block m-1">
<div class="grid grid-rows-2 grid-cols-4 h-[52px] p-1.5 w-40 text-white shadow-lg" style="{{ style }}">
<div class="row-start-1 col-start-1 col-span-3 truncate text-ellipsis font-semibold leading-tight text-sm">{{ name }}</div>
<div class="row-start-2 col-start-1 col-span-3 truncate align-bottom text-xs">{{ rarity }}</div>
<div class="row-start-2 col-start-4 col-span-1 align-bottom text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
{% if quantity != None %}<div class="row-start-1 col-start-4 justify-self-end -me-0.5 relative w-fit ps-1"><div class="card-quantity-badge relative bg-gray-600 text-white text-sm font-semibold rounded-full text-center size-max px-1.5">{{ quantity }}</div></div>{% endif %}
</div>
</div>
{% endif %}

View file

@ -1,6 +1,6 @@
{% load gravatar card_badge %}
<div class="card card-border bg-base-100 shadow-lg w-84 mx-auto">
<div class="card card-border bg-base-100 shadow-lg w-90 mx-auto">
<!-- Header -->
<div class="py-4 mx-4">
<div class="flex justify-between items-center">
@ -40,11 +40,11 @@
</a>
<!-- Footer: Only info button with acceptance hash -->
<div class="flex justify-between px-2 pb-2">
<div class="flex justify-between p-2">
<div class="text-gray-500 text-sm">
{{ acceptance.get_state_display }}
</div>
<div class="text-gray-500 text-sm tooltip tooltip-left" data-tip="Trade ID: {{ acceptance.hash }}">
<div class="text-gray-500 text-sm tooltip tooltip-left" data-tip="ID: {{ acceptance.hash }}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round"
d="M11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0zm-9-3.75h.008v.008H12V8.25z" />

View file

@ -2,7 +2,7 @@
{% cache 60 trade_offer offer_pk %}
<div class="trade-offer-card m-2 h-full w-auto flex justify-center">
<div x-data="tradeOfferCard()" x-init="defaultExpanded = {{expanded|lower}}; badgeExpanded = defaultExpanded; acceptanceExpanded = defaultExpanded; flipped = {{flipped|lower}}" class="transition-all duration-500 trade-offer-card my-auto"
<div x-data="tradeOfferCard()" x-init="defaultExpanded = {{expanded|lower}}; badgeExpanded = defaultExpanded; flipped = {{flipped|lower}}" class="trade-offer-card my-auto"
@toggle-all.window="setBadge($event.detail.expanded)">
<!-- Flip container providing perspective -->
@ -11,19 +11,19 @@
The rotating element (.flip-inner) now uses CSS Grid to stack its children in a single cell.
Persistent border, shadow, and rounding are applied here and the card rotates entirely.
-->
<div class="flip-inner freeze-bg-color grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg w-84 transform transition-transform duration-700 ease-in-out"
<div class="flip-inner grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg w-90 transform transition-transform duration-700 ease-in-out"
:class="{'rotate-y-180': flipped}">
<!-- Front Face: Trade Offer -->
<!-- Using grid placement classes (col-start-1 row-start-1) ensures both faces overlap -->
<div class="flip-face front col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between">
<div x-show="!flipped" class="flip-face front col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between">
<!-- Header -->
<div class="flip-face-header self-start">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<!-- Set this container as relative to position the avatar absolutely -->
<div class="relative mt-6 mb-4 mx-2 sm:mx-4">
<!-- Two-column grid for the labels -->
<div class="grid grid-cols-2 items-center">
<div class="grid grid-cols-2">
<span class="text-sm font-semibold text-center">Has</span>
<span class="text-sm font-semibold text-center">Wants</span>
</div>
@ -44,16 +44,16 @@
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<div class="px-2 main-badges pb-0">
<!-- Normal mode: just use an outer grid with 2 columns -->
<div class="flex flex-row gap-2 justify-around">
<div class="flex flex-row justify-around">
<!-- Has Side -->
<div class="flex flex-col gap-2">
{% for card in have_cards_available|slice:"0:1" %}
<div class="flex flex-col gap-y-2">
{% for card in have_cards_available %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
<!-- Wants Side -->
<div class="flex flex-col gap-2">
{% for card in want_cards_available|slice:"0:1" %}
<div class="flex flex-col gap-y-2">
{% for card in want_cards_available %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
@ -67,40 +67,17 @@
</div>
</div>
{% endif %}
<!-- Extra Card Badges (Collapsible) -->
<div x-show="badgeExpanded" x-collapse.duration.500ms x-cloak class="px-2 extra-badges">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<div class="flex flex-row gap-2 justify-around">
<!-- Has Side Extra Badges -->
<div class="flex flex-col gap-2">
{% for card in have_cards_available|slice:"1:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
<!-- Wants Side Extra Badges -->
<div class="flex flex-col gap-2">
{% for card in want_cards_available|slice:"1:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
</div>
</a>
</div>
</div>
{% if have_cards_available|length > 1 or want_cards_available|length > 1 %}
<div @click="badgeExpanded = !badgeExpanded" class="flex justify-center h-5 cursor-pointer">
<div class="flip-face-footer self-end">
<div class="flex justify-between px-2 pb-2">
<div @click="badgeExpanded = !badgeExpanded" class="flex justify-center h-5 cursor-pointer tooltip tooltip-right" data-tip="Expand/Collapse">
<svg x-bind:class="{ 'rotate-180': badgeExpanded }"
class="transition-transform duration-500 h-5 w-5 cursor-pointer"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M19 9l-7 7-7-7" />
</svg>
</div>
{% else %}
<div class="h-5"></div>
{% endif %}
<div class="flip-face-footer self-end">
<div class="flex justify-between px-2 pb-2">
<div class="text-gray-500 text-sm tooltip tooltip-right" data-tip="ID: {{ offer_hash }}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="size-5">
@ -108,8 +85,7 @@
d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
</svg>
</div>
<!-- Front-to-back flip button -->
<div class="cursor-pointer text-gray-500" @click="flipped = true; acceptanceExpanded = defaultExpanded">
<div class="cursor-pointer text-gray-500 tooltip tooltip-left" data-tip="Flip to Accepted Trades" @click="flipped = true; acceptanceExpanded = defaultExpanded">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 8.689c0-.864.933-1.406 1.683-.977l7.108 4.061a1.125 1.125 0 0 1 0 1.954l-7.108 4.061A1.125 1.125 0 0 1 3 16.811V8.69ZM12.75 8.689c0-.864.933-1.406 1.683-.977l7.108 4.061a1.125 1.125 0 0 1 0 1.954l-7.108 4.061a1.125 1.125 0 0 1-1.683-.977V8.69Z" />
</svg>
@ -120,35 +96,30 @@
<!-- Back Face: Acceptances View -->
<!-- Placed in the same grid cell as the front face -->
<div class="flip-face back col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between" style="transform: rotateY(180deg);">
<div x-show="flipped" class="flip-face back col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between" style="transform: rotateY(180deg);">
<div class="self-start">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline">
<div class="py-4 mx-2 sm:mx-4">
<div class="grid grid-cols-3 items-center">
<div class="flex justify-center items-center">
<span class="text-sm font-semibold">Has</span>
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<div class="relative mt-6 mb-4 mx-2 sm:mx-4">
<div class="grid grid-cols-2">
<span class="text-sm font-semibold text-center">Has</span>
<span class="text-sm font-semibold text-center">Wants</span>
</div>
<div class="flex justify-center items-center">
<!-- The avatar is placed absolutely and centered -->
<div class="absolute inset-x-0 top-1/2 transform -translate-y-1/2 flex justify-center">
<div class="avatar">
<div class="w-10 rounded-full">
{{ initiated_by_email|gravatar:40 }}
</div>
</div>
</div>
<div class="flex justify-center items-center">
<span class="text-sm font-semibold">Wants</span>
</div>
</div>
</div>
</a>
</div>
<div class="self-start">
<div class="px-2 pb-0">
<div class="overflow-hidden">
{% if acceptances.0 %}
<div class="space-y-3">
{% with acceptance=acceptances.0 %}
<a href="{% url 'trade_acceptance_update' pk=acceptance.pk %}" class="no-underline"
{% for acceptance in acceptances %}
<a href="{% url 'trade_acceptance_update' pk=acceptance.pk %}" class="no-underline block mb-2"
data-tooltip-html='<div class="flex items-center space-x-2">
<div class="avatar">
<div class="w-10 rounded-full">
@ -161,75 +132,34 @@
<span class="text-sm">Acceptance ID: {{ acceptance.hash }}</span>
</div>
</div>'>
<div class="grid grid-cols-2 gap-4 items-center">
<div>
<div class="grid grid-cols-2 gap-1 justify-items-center">
{% card_badge acceptance.requested_card %}
</div>
<div>
{% card_badge acceptance.offered_card %}
</div>
</div>
</a>
{% endwith %}
</div>
{% endif %}
</div>
<div x-show="acceptanceExpanded" x-collapse.duration.500ms class="space-y-3">
{% for acceptance in acceptances|slice:"1:" %}
<a href="{% url 'trade_acceptance_update' pk=acceptance.pk %}" class="no-underline"
data-tooltip-html='<div class="flex items-center space-x-2">
<div class="avatar">
<div class="w-10 rounded-full">
{{ acceptance.accepted_by.user.email|gravatar:"40" }}
</div>
</div>
<div class="flex flex-col">
<span class="text-sm">Accepted by: {{ acceptance.accepted_by.user.username }}</span>
<span class="text-sm">State: {{ acceptance.state }}</span>
<span class="text-sm">Acceptance ID: {{ acceptance.hash }}</span>
</div>
</div>'>
<div class="grid grid-cols-2 gap-4 items-center">
<div>
{% card_badge acceptance.requested_card %}
</div>
<div>
{% card_badge acceptance.offered_card %}
</div>
</div>
</a>
{% endfor %}
</div>
</div>
<div class="flex justify-center h-5">
{% if acceptances|length > 1 %}
<svg @click="acceptanceExpanded = !acceptanceExpanded"
x-bind:class="{ 'rotate-180': acceptanceExpanded }"
class="transition-transform duration-500 h-5 w-5 cursor-pointer"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7" />
</svg>
{% endif %}
</div>
</div>
<div class="flex justify-between px-2 pb-2 self-end">
<!-- Back-to-front flip button -->
<div class="text-gray-500 cursor-pointer" @click="flipped = false; badgeExpanded = defaultExpanded">
<div class="text-gray-500 cursor-pointer tooltip tooltip-right" data-tip="Flip to Offered Cards" @click="flipped = false; badgeExpanded = defaultExpanded">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 16.811c0 .864-.933 1.406-1.683.977l-7.108-4.061a1.125 1.125 0 0 1 0-1.954l7.108-4.061A1.125 1.125 0 0 1 21 8.689v8.122ZM11.25 16.811c0 .864-.933 1.406-1.683.977l-7.108-4.061a1.125 1.125 0 0 1 0-1.954l7.108-4.061a1.125 1.125 0 0 1 1.683.977v8.122Z" />
</svg>
</div>
<div class="px-1 text-center">
<span class="text-sm font-semibold">
Acceptances ({{ acceptances|length }})
Accepted Trades ({{ acceptances|length }})
</span>
</div>
<div class="text-gray-500 text-sm tooltip tooltip-left" data-tip="ID: {{ offer_hash }}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="size-5">
<path stroke-linecap="round" stroke-linejoin="round"
d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
<div class="flex justify-center h-5 tooltip tooltip-left" data-tip="Expand/Collapse">
<svg @click="badgeExpanded = !badgeExpanded"
x-bind:class="{ 'rotate-180': badgeExpanded }"
class="transition-transform duration-500 h-5 w-5 cursor-pointer"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>

View file

@ -13,26 +13,17 @@
<!-- Flip container providing perspective -->
<div class="flip-container">
<!--
The rotating element (.flip-inner) now uses CSS Grid to stack its children in a single cell.
Persistent border, shadow, and rounding are applied here and the card rotates entirely.
-->
<div class="flip-inner freeze-bg-color grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg {% if num_cards_available >= 4 %}w-160{% else %}w-96 md:w-80 lg:w-96{% endif %} transform transition-transform duration-700 ease-in-out">
<div class="flip-inner grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg {% if num_cards_available >= 4 %}w-192{% else %}w-96{% endif %} transform transition-transform duration-700 ease-in-out">
<!-- Front Face: Trade Offer -->
<!-- Using grid placement classes (col-start-1 row-start-1) ensures both faces overlap -->
<div class="flip-face front mb-2 col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between">
<!-- Header -->
<div class="flip-face-header self-start">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<!-- Set this container as relative to position the avatar absolutely -->
<div class="relative mt-6 mb-4 mx-2 sm:mx-4">
<div class="mt-6 mb-4 mx-2 sm:mx-4">
<!-- Two-column grid for the labels -->
<div class="grid grid-cols-2 items-center">
<span class="text-sm font-semibold text-center">Has</span>
<span class="text-sm font-semibold text-center">Wants</span>
</div>
<!-- The avatar is placed absolutely and centered -->
<div class="flex flex-row justify-around w-full relative">
<div class="text-sm font-semibold text-center ms-3">Has</div>
<div class="absolute inset-x-0 top-1/2 transform -translate-y-1/2 flex justify-center">
<div class="avatar">
<div class="w-10 rounded-full">
@ -40,20 +31,21 @@
</div>
</div>
</div>
<div class="text-sm font-semibold text-center {% if expanded %}ms-8{% else %}me-2{% endif %}">Wants</div>
</div>
</div>
</a>
</div>
<!-- Main Trade Offer Row -->
<div class="flip-face-body self-start">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<div class="px-2 main-badges pb-0">
{% if num_cards_available >= 4 %}
<!-- When screenshot_mode is true, use an outer grid with 3 columns: Has side, a vertical divider, and Wants side -->
<div class="px-4 main-badges pb-0">
{% if expanded %}
<div class="flex flex-row gap-2 justify-around">
<!-- Has Side (inner grid of 2 columns) -->
<div class="flex flex-row gap-2">
{% for card in have_cards_available|slice:"0:2" %}
{% card_badge card.card card.quantity %}
<div class="grid grid-cols-2 gap-2">
{% for card in have_cards_available %}
{% card_badge card.card card.quantity static=True %}
{% endfor %}
</div>
<!-- Vertical Divider -->
@ -61,9 +53,9 @@
<div class="w-px bg-gray-300 h-full"></div>
</div>
<!-- Wants Side (inner grid of 2 columns) -->
<div class="flex flex-row gap-2">
{% for card in want_cards_available|slice:"0:2" %}
{% card_badge card.card card.quantity %}
<div class="grid grid-cols-2 gap-2">
{% for card in want_cards_available %}
{% card_badge card.card card.quantity static=True %}
{% endfor %}
</div>
</div>
@ -72,64 +64,20 @@
<div class="flex flex-row gap-2 justify-around">
<!-- Has Side -->
<div class="flex flex-col gap-2">
{% for card in have_cards_available|slice:"0:1" %}
{% card_badge card.card card.quantity %}
{% for card in have_cards_available %}
{% card_badge card.card card.quantity static=True %}
{% endfor %}
</div>
<!-- Wants Side -->
<div class="flex flex-col gap-2">
{% for card in want_cards_available|slice:"0:1" %}
{% card_badge card.card card.quantity %}
{% for card in want_cards_available %}
{% card_badge card.card card.quantity static=True %}
{% endfor %}
</div>
</div>
{% endif %}
</div>
</a>
<!-- Extra Card Badges (Collapsible) -->
{% if num_cards_available >= 4 %}
<div class="px-2 extra-badges">
<!-- In screenshot mode, add a vertical divider between the Has and Wants sides -->
<div class="flex flex-row gap-2 justify-around">
<!-- Has Side Extra Badges -->
<div class="grid grid-cols-2 gap-2 {% if num_cards_available >= 4 %}w-[296px]{% endif %}">
{% for card in have_cards_available|slice:"2:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
<!-- Vertical Divider -->
<div class="flex justify-center">
<div class="w-px bg-gray-300 h-full"></div>
</div>
<!-- Wants Side Extra Badges -->
<div class="grid grid-cols-2 gap-2 {% if num_cards_available >= 4 %}w-[296px]{% endif %}">
{% for card in want_cards_available|slice:"2:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
</div>
</div>
{% else %}
<div class="px-2 extra-badges">
<a href="{% url 'trade_offer_detail' pk=offer_pk %}" class="no-underline block">
<div class="flex flex-row gap-2 justify-around">
<!-- Has Side Extra Badges -->
<div class="flex flex-col gap-2">
{% for card in have_cards_available|slice:"1:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
<!-- Wants Side Extra Badges -->
<div class="flex flex-col gap-2">
{% for card in want_cards_available|slice:"1:" %}
{% card_badge card.card card.quantity %}
{% endfor %}
</div>
</div>
</a>
</div>
{% endif %}
</div>
<div class="flip-face-footer self-end">

View file

@ -97,19 +97,12 @@ def render_trade_offer_png(context, offer, show_friend_code=False):
]
num_cards = max(len(have_cards_available), len(want_cards_available))
aspect_ratio = 1.91
base_height = (round(num_cards / 2) * 56) + 138
image_height = (num_cards * 52) + ((num_cards - 1) * 8) + 106
# cards | padding between cards | header/footer
if (len(have_cards_available) + len(want_cards_available)) >= 4:
base_width = (4 * 144) + 96
image_width = (4 * 160) + 160
else:
base_width = (2 * 144) + 128
if base_height > base_width:
image_height = base_height
image_width = int(round(image_height * aspect_ratio)) + 1
else:
image_width = base_width
image_height = int(round(image_width / aspect_ratio))
image_width = (2 * 160) + 92
request = context.get("request")
if request.get_host().startswith("localhost"):
@ -129,6 +122,7 @@ def render_trade_offer_png(context, offer, show_friend_code=False):
'friend_code': offer.initiated_by.friend_code,
'show_friend_code': show_friend_code,
'num_cards_available': len(have_cards_available) + len(want_cards_available),
'expanded': (len(have_cards_available) + len(want_cards_available)) >= 4,
'image_width': image_width,
'image_height': image_height,
'base_url': base_url,

View file

@ -11,7 +11,7 @@ from meta.views import Meta
from .models import TradeOffer, TradeAcceptance
from .forms import (TradeAcceptanceCreateForm, TradeOfferCreateForm, TradeAcceptanceTransitionForm)
from django.template.loader import render_to_string
from trades.templatetags.trade_offer_tags import render_trade_offer
from trades.templatetags.trade_offer_tags import render_trade_offer_png
from playwright.sync_api import sync_playwright
from django.conf import settings
from .mixins import FriendCodeRequiredMixin
@ -514,7 +514,7 @@ class TradeOfferPNGView(View):
trade_offer.image.open()
return HttpResponse(trade_offer.image.read(), content_type="image/png")
tag_context = trade_offer_tags.render_trade_offer_png(
tag_context = render_trade_offer_png(
{'request': request}, trade_offer, show_friend_code=True
)
image_width = tag_context.get('image_width')