finished conversion to tailwind
This commit is contained in:
parent
6e2843c60e
commit
d62956d465
50 changed files with 2490 additions and 1273 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags i18n widget_tweaks %}
|
||||
{% load crispy_forms_tags i18n %}
|
||||
|
||||
{% block head_title %}{% trans "Log In" %}{% endblock %}
|
||||
|
||||
|
|
@ -11,12 +11,12 @@
|
|||
{{ form.non_field_errors }}
|
||||
<div>
|
||||
<label for="{{ form.login.id_for_label }}" class="block font-medium text-gray-700">{{ form.login.label }}</label>
|
||||
{{ form.login|add_class:"input input-bordered w-full" }}
|
||||
{{ form.login }}
|
||||
{{ form.login.errors }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ form.password.id_for_label }}" class="block font-medium text-gray-700">{{ form.password.label }}</label>
|
||||
{{ form.password|add_class:"input input-bordered w-full" }}
|
||||
{{ form.password }}
|
||||
{{ form.password.errors }}
|
||||
</div>
|
||||
{% if form.remember %}
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<button type="submit" class="btn btn-primary w-full">{% trans "Log In" %}</button>
|
||||
</form>
|
||||
<div class="mt-4 text-center">
|
||||
<a href="{% url 'account_reset_password' %}" class="text-primary underline">{% trans "Forgot Password?" %}</a>
|
||||
<a href="{% url 'account_request_login_code' %}" class="text-primary underline">{% trans "Login by Code" %}</a> | <a href="{% url 'account_reset_password' %}" class="text-primary underline">{% trans "Forgot Password?" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
23
theme/templates/account/settings.html
Normal file
23
theme/templates/account/settings.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}{% trans "Settings" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto flex items-center justify-center min-h-screen">
|
||||
<div class="w-full max-w-sm p-6 bg-base-100 shadow rounded-box">
|
||||
<h1 class="text-3xl font-bold text-center mb-6">{% trans "Settings" %}</h1>
|
||||
<div class="flex flex-col gap-4">
|
||||
<a href="{% url 'list_friend_codes' %}" class="btn btn-primary w-full">
|
||||
{% trans "Friend Codes" %}
|
||||
</a>
|
||||
<a href="{% url 'account_logout' %}" class="btn btn-warning w-full">
|
||||
{% trans "Logout" %}
|
||||
</a>
|
||||
<a href="https://www.gravatar.com/profile/" target="_blank" rel="noopener noreferrer" class="btn btn-secondary w-full">
|
||||
{% trans "Profile" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n widget_tweaks %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}{% trans "Sign Up" %}{% endblock %}
|
||||
|
||||
|
|
@ -11,27 +11,27 @@
|
|||
{{ form.non_field_errors }}
|
||||
<div>
|
||||
<label for="{{ form.username.id_for_label }}" class="block font-medium text-gray-700">{{ form.username.label }}</label>
|
||||
{{ form.username|add_class:"input input-bordered w-full" }}
|
||||
{{ form.username }}
|
||||
{{ form.username.errors }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ form.email.id_for_label }}" class="block font-medium text-gray-700">{{ form.email.label }}</label>
|
||||
{{ form.email|add_class:"input input-bordered w-full" }}
|
||||
{{ form.email }}
|
||||
{{ form.email.errors }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ form.password1.id_for_label }}" class="block font-medium text-gray-700">{{ form.password1.label }}</label>
|
||||
{{ form.password1|add_class:"input input-bordered w-full" }}
|
||||
{{ form.password1 }}
|
||||
{{ form.password1.errors }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ form.password2.id_for_label }}" class="block font-medium text-gray-700">{{ form.password2.label }}</label>
|
||||
{{ form.password2|add_class:"input input-bordered w-full" }}
|
||||
{{ form.password2 }}
|
||||
{{ form.password2.errors }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="{{ form.friend_code.id_for_label }}" class="block font-medium text-gray-700">{{ form.friend_code.label }}</label>
|
||||
{{ form.friend_code|add_class:"input input-bordered w-full" }}
|
||||
{{ form.friend_code }}
|
||||
{{ form.friend_code.errors }}
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-full">{% trans "Sign Up" %}</button>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
<!-- Tailwind CSS and Base stylesheet -->
|
||||
{% tailwind_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/base.css' %}">
|
||||
|
||||
<!-- Floating UI -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@floating-ui/core@1.6.9"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.6.13"></script>
|
||||
{% block css %}{% endblock %}
|
||||
|
||||
{% block javascript_head %}{% endblock %}
|
||||
|
|
@ -139,26 +143,23 @@
|
|||
</footer>
|
||||
|
||||
<!-- Dock -->
|
||||
<div class="dock bg-neutral text-neutral-content sm:hidden">
|
||||
<button>
|
||||
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><polyline points="1 11 12 2 23 11" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><path d="m5,13v7c0,1.105.895,2,2,2h10c1.105,0,2-.895,2-2v-7" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path><line x1="12" y1="22" x2="12" y2="18" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></line></g></svg>
|
||||
<span class="dock-label">Home</span>
|
||||
</button>
|
||||
|
||||
<button class="dock-active">
|
||||
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><polyline points="3 14 9 14 9 17 15 17 15 14 21 14" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><rect x="3" y="3" width="18" height="18" rx="2" ry="2" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></rect></g></svg>
|
||||
<span class="dock-label">Trades</span>
|
||||
</button>
|
||||
|
||||
<button>
|
||||
<svg class="size-[1.5em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" /> </g></svg>
|
||||
<span class="dock-label">Notifications</span>
|
||||
</button>
|
||||
|
||||
<button>
|
||||
{% if user.is_authenticated %}<div tabindex="0" role="button" class="avatar"><div class="w-6 rounded-full">{{ user.email|gravatar:40 }}</div></div>{% else %}<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></circle><path d="m22,13.25v-2.5l-2.318-.966c-.167-.581-.395-1.135-.682-1.654l.954-2.318-1.768-1.768-2.318.954c-.518-.287-1.073-.515-1.654-.682l-.966-2.318h-2.5l-.966,2.318c-.581.167-1.135.395-1.654.682l-2.318-.954-1.768,1.768.954,2.318c-.287.518-.515,1.073-.682,1.654l-2.318.966v2.5l2.318.966c.167.581.395,1.135.682,1.654l-.954,2.318,1.768,1.768,2.318-.954c.518.287,1.073.515,1.654.682l.966,2.318h2.5l.966-2.318c.581-.167,1.135-.395,1.654-.682l2.318.954,1.768-1.768-.954-2.318c.287-.518.515-1.073.682-1.654l2.318-.966Z" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path></g></svg>{% endif %}
|
||||
<span class="dock-label">Settings</span>
|
||||
</button>
|
||||
<div x-data class="dock bg-neutral text-neutral-content">
|
||||
<button @click="window.location.href = '{% url 'home' %}'" class="{% if request.path == '/' %}dock-active{% endif %}">
|
||||
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><polyline points="1 11 12 2 23 11" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><path d="m5,13v7c0,1.105.895,2,2,2h10c1.105,0,2-.895,2-2v-7" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path><line x1="12" y1="22" x2="12" y2="18" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></line></g></svg>
|
||||
<span class="dock-label">Home</span>
|
||||
</button>
|
||||
<button @click="window.location.href = '{% url 'trade_offer_list' %}'" class="{% if '/trades/all/' in request.path %}dock-active{% endif %}">
|
||||
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 0 1 0 3.75H5.625a1.875 1.875 0 0 1 0-3.75Z" /></svg>
|
||||
<span class="dock-label">All Offers</span>
|
||||
</button>
|
||||
<button @click="window.location.href = '{% url 'trade_offer_list' %}?my_trades=true'" class="{% if '/trades/my/' in request.path %}dock-active{% endif %}">
|
||||
<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" /></svg>
|
||||
<span class="dock-label">My Trades</span>
|
||||
</button>
|
||||
<button @click="window.location.href = '{% url 'settings' %}'" class="{% if '/settings/' in request.path %}dock-active{% endif %}">
|
||||
{% if user.is_authenticated %}<div tabindex="0" role="button" class="avatar"><div class="w-6 rounded-full">{{ user.email|gravatar:40 }}</div></div>{% else %}<svg class="size-[1.2em]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="currentColor" stroke-linejoin="miter" stroke-linecap="butt"><circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></circle><path d="m22,13.25v-2.5l-2.318-.966c-.167-.581-.395-1.135-.682-1.654l.954-2.318-1.768-1.768-2.318.954c-.518-.287-1.073-.515-1.654-.682l-.966-2.318h-2.5l-.966,2.318c-.581.167-1.135.395-1.654.682l-2.318-.954-1.768,1.768.954,2.318c-.287.518-.515,1.073-.682,1.654l-2.318.966v2.5l2.318.966c.167.581.395,1.135.682,1.654l-.954,2.318,1.768,1.768,2.318-.954c.518.287,1.073.515,1.654.682l.966,2.318h2.5l.966-2.318c.581-.167,1.135-.395,1.654-.682l2.318.954,1.768-1.768-.954-2.318c.287-.518.515-1.073.682-1.654l2.318-.966Z" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="2"></path></g></svg>{% endif %}
|
||||
<span class="dock-label">Settings</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Alpine Plugins -->
|
||||
|
|
@ -167,6 +168,8 @@
|
|||
<!-- Alpine Core -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js"></script>
|
||||
|
||||
<script defer src="{% static 'js/tooltip.js' %}"></script>
|
||||
|
||||
<script defer src="{% static 'js/base.js' %}"></script>
|
||||
{% block javascript %}{% endblock %}
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@
|
|||
- cards: a list of card objects
|
||||
- mode: a string that determines the render style.
|
||||
It should be "offered" for Most Offered Cards and "wanted" for Most Wanted Cards.
|
||||
- Optional 'show_zero' flag (default False): if True, also display cards with 0 offers.
|
||||
- Optional:
|
||||
'show_zero' flag (default False): if True, also display cards with 0 offers.
|
||||
'layout' variable: if set to "auto", use an auto-fit grid based on available horizontal space.
|
||||
{% endcomment %}
|
||||
{% if cards %}
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<div class="mx-4 grid gap-3 grid-cols-[repeat(auto-fit,minmax(150px,1fr))] justify-items-center">
|
||||
{% for card in cards %}
|
||||
{% if show_zero|default:False or card.offer_count > 0 %}
|
||||
{% if mode == "offered" %}
|
||||
<a href="?offered_cards={{ card.id }}"
|
||||
{% else %}
|
||||
<a href="?wanted_cards={{ card.id }}"
|
||||
{% endif %}
|
||||
class="flex justify-between items-center text-primary no-underline">
|
||||
{% card_badge card card.offer_count %}
|
||||
</a>
|
||||
{% if mode == "offered" %}
|
||||
<a href="?offered_cards={{ card.id }}"
|
||||
{% else %}
|
||||
<a href="?wanted_cards={{ card.id }}"
|
||||
{% endif %}
|
||||
class="flex justify-between items-center text-primary no-underline">
|
||||
{% card_badge card card.offer_count %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
|||
|
|
@ -16,115 +16,88 @@
|
|||
|
||||
<!-- Search Form Section -->
|
||||
<section id="trade-search" class="mb-8">
|
||||
<form method="post" action="." class="space-y-4">
|
||||
<form method="post" action="{% url 'trade_offer_search' %}" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
{% card_multiselect "have_cards" "Have:" "Select zero or more cards..." available_cards have_cards %}
|
||||
{% card_multiselect "have_cards" "Have:" "Select some cards..." available_cards have_cards %}
|
||||
</div>
|
||||
<div>
|
||||
{% card_multiselect "want_cards" "Want:" "Select zero or more cards..." available_cards want_cards %}
|
||||
{% card_multiselect "want_cards" "Want:" "Select some cards..." available_cards want_cards %}
|
||||
</div>
|
||||
</div>
|
||||
{% if user.is_authenticated %}
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<button type="submit" class="btn btn-primary flex-1">Find a Trade Offer</button>
|
||||
<a href="{% url 'trade_offer_create' %}" id="createTradeOfferBtn" class="btn btn-secondary flex-1 text-center">Create Trade Offer</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary w-full">Find a Trade Offer</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<button type="submit" class="btn btn-primary flex-1">
|
||||
Find a Trade Offer
|
||||
</button>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'trade_offer_create' %}" id="createTradeOfferBtn" class="btn btn-secondary flex-1 text-center">
|
||||
Create Trade Offer
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- Search Results Section -->
|
||||
<section id="search-results" class="mb-8">
|
||||
{% include "home/_search_results.html" %}
|
||||
</section>
|
||||
|
||||
<!-- Market Stats Section -->
|
||||
<section aria-labelledby="stats-heading" class="mb-8">
|
||||
<h2 id="stats-heading" class="text-2xl font-semibold mb-4">Market Stats</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<!-- Most Offered Cards -->
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Offered Cards</h5>
|
||||
|
||||
<!-- Market Stats Section -->
|
||||
<section aria-labelledby="stats-heading" class="mb-8">
|
||||
<h2 id="stats-heading" class="text-2xl font-semibold mb-4">Market Stats</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<!-- Most Offered Cards -->
|
||||
<div>
|
||||
<div class="card card-border bg-base-100 shadow-lg">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Offered Cards</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 most_offered_cards %}
|
||||
{% include "home/_card_list.html" with cards=most_offered_cards mode="wanted" %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 most_offered_cards %}
|
||||
{% include "home/_card_list.html" with cards=most_offered_cards mode="wanted" %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
<!-- Most Wanted Cards -->
|
||||
<div>
|
||||
<div class="card card-border bg-base-100 shadow-lg">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Wanted Cards</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 most_wanted_cards %}
|
||||
{% include "home/_card_list.html" with cards=most_wanted_cards mode="offered" %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Least Offered Cards (Last Group) -->
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="card card-border bg-base-100 shadow-lg">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Least Offered Cards</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 least_offered_cards %}
|
||||
{% include "home/_card_list.html" with cards=least_offered_cards mode="wanted" %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Most Wanted Cards -->
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Most Wanted Cards</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 most_wanted_cards %}
|
||||
{% include "home/_card_list.html" with cards=most_wanted_cards mode="offered" %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Least Offered Cards -->
|
||||
<div>
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Least Offered Cards</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-0">
|
||||
{% cache 3600 least_offered_cards %}
|
||||
{% include "home/_card_list.html" with cards=least_offered_cards mode="wanted" show_zero=True %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Featured Offers and Recent Offers Section -->
|
||||
<section class="mb-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- Featured Offers -->
|
||||
<div>
|
||||
{% cache 86400 featured_offers %}
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-header text-base-content p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Featured Offers</h5>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<!-- New pure-CSS tabs for Featured Offers -->
|
||||
<div class="featured-offers-tabs">
|
||||
<!-- Radio inputs for all tabs -->
|
||||
<input type="radio" name="featured_offers_tabs" id="tab-all" class="hidden" checked>
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
<input type="radio" name="featured_offers_tabs" id="tab-{{ forloop.counter }}" class="hidden">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<!-- Tab navigation: all tab labels appear together -->
|
||||
<div class="tabs tabs-box grid grid-cols-3 gap-2">
|
||||
<label for="tab-all" class="tab text-xs md:text-base">All</label>
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
<label for="tab-{{ forloop.counter }}" class="tab text-xs md:text-base">{{ rarity }}</label>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- All tab content panels are placed in one content container -->
|
||||
<div class="tab-contents">
|
||||
<!-- Panel for All offers -->
|
||||
<div class="tab-content" id="content-tab-all">
|
||||
<div>
|
||||
{% cache 86400 featured_offers %}
|
||||
<div class="p-4">
|
||||
<h5 class="text-xl text-center font-semibold whitespace-nowrap truncate mb-0">Featured Offers</h5>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<!-- Tab contents -->
|
||||
<div id="featured-tab-contents">
|
||||
<div class="tab-content" data-tab="featured-all">
|
||||
{% if featured_offers.All %}
|
||||
<div class="flex flex-col items-center gap-3 w-auto mx-auto">
|
||||
{% for offer in featured_offers.All %}
|
||||
|
|
@ -135,11 +108,9 @@
|
|||
<p class="text-center">No featured offers available.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Panels for each additional rarity -->
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
<div class="tab-content" id="content-tab-{{ forloop.counter }}">
|
||||
<div class="tab-content" data-tab="featured-{{ forloop.counter }}" style="display: none;">
|
||||
{% if offers %}
|
||||
<div class="flex flex-col items-center gap-3 w-auto mx-auto">
|
||||
{% for offer in offers %}
|
||||
|
|
@ -153,20 +124,30 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- DaisyUI Tabs for Featured Offers -->
|
||||
<div class="card card-border bg-base-100 shadow-lg w-96 md:w-80 lg:w-96 mt-8 mx-auto">
|
||||
<!-- Tabs navigation using daisyUI tabs-box -->
|
||||
<div class="tabs tabs-box bg-white dark:bg-base-100 grid grid-cols-3 gap-1.5 justify-items-stretch">
|
||||
<!-- Radio inputs for controlling tab state -->
|
||||
<input type="radio" class="tab text-xs font-bold md:text-sm w-full bg-base-100" name="featured_tabs" id="featured-all" checked="checked" aria-label="All">
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
<input type="radio" class="tab text-xs font-bold md:text-sm w-full bg-base-100" name="featured_tabs" id="featured-{{ forloop.counter }}" aria-label="{{ rarity }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcache %}
|
||||
</div>
|
||||
{% endcache %}
|
||||
</div>
|
||||
|
||||
<!-- Recent Offers -->
|
||||
<div>
|
||||
{% cache 60 recent_offers %}
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-header text-center text-base-content p-4">
|
||||
<div class="text-center text-base-content p-4">
|
||||
<h5 class="text-xl font-semibold whitespace-nowrap truncate mb-0">Recent Offers</h5>
|
||||
</div>
|
||||
<div class="card-body my-4 p-4">
|
||||
<div class="p-4">
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
{% for offer in recent_offers %}
|
||||
{% render_trade_offer offer %}
|
||||
|
|
@ -175,125 +156,15 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
||||
{% block css %}
|
||||
<style>
|
||||
/* Hide the hidden radio inputs */
|
||||
.featured-offers-tabs input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Styles for the tabs navigation */
|
||||
.tabs.tabs-box {
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tabs.tabs-box .tab {
|
||||
flex: 1; /* Each tab will equally expand */
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid transparent;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.tabs.tabs-box .tab:hover {
|
||||
border-color: currentColor;
|
||||
}
|
||||
|
||||
/* Active tab styling based on the radio input state */
|
||||
#tab-all:checked ~ .tabs.tabs-box label[for="tab-all"] {
|
||||
border-color: #2563eb; /* Example blue highlight */
|
||||
}
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
#tab-{{ forloop.counter }}:checked ~ .tabs.tabs-box label[for="tab-{{ forloop.counter }}"] {
|
||||
border-color: #2563eb;
|
||||
font-weight: bold;
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
/* Hide all content panels by default */
|
||||
.featured-offers-tabs .tab-contents > .tab-content {
|
||||
display: none;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Display the panel corresponding to the checked radio input */
|
||||
#tab-all:checked ~ .tab-contents #content-tab-all {
|
||||
display: block;
|
||||
}
|
||||
{% for rarity, offers in featured_offers.items %}
|
||||
{% if rarity != "All" %}
|
||||
#tab-{{ forloop.counter }}:checked ~ .tab-contents #content-tab-{{ forloop.counter }} {
|
||||
display: block;
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script defer>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// AJAX trade search form submission with vanilla JavaScript
|
||||
const tradeSearchForm = document.querySelector('#trade-search form');
|
||||
if (tradeSearchForm) {
|
||||
tradeSearchForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(tradeSearchForm);
|
||||
fetch(tradeSearchForm.action, {
|
||||
method: tradeSearchForm.method,
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(data => {
|
||||
document.querySelector('#search-results').innerHTML = data;
|
||||
})
|
||||
.catch(error => {
|
||||
alert("There was an error processing your search.");
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// AJAX pagination click handling
|
||||
document.addEventListener('click', function(e) {
|
||||
const target = e.target.closest('.ajax-page-link');
|
||||
if (target) {
|
||||
e.preventDefault();
|
||||
const page = target.getAttribute('data-page');
|
||||
let pageInput = document.getElementById('page');
|
||||
if (pageInput) {
|
||||
pageInput.value = page;
|
||||
} else {
|
||||
pageInput = document.createElement('input');
|
||||
pageInput.type = 'hidden';
|
||||
pageInput.id = 'page';
|
||||
pageInput.name = 'page';
|
||||
pageInput.value = page;
|
||||
tradeSearchForm.appendChild(pageInput);
|
||||
}
|
||||
tradeSearchForm.dispatchEvent(new Event('submit'));
|
||||
}
|
||||
});
|
||||
|
||||
// Updated: JS to carry over selections (including quantities) to the Create Trade Offer page.
|
||||
const createBtn = document.getElementById('createTradeOfferBtn');
|
||||
if (createBtn) {
|
||||
|
|
@ -326,6 +197,49 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
window.location.href = url.href;
|
||||
});
|
||||
}
|
||||
|
||||
// Minimal JavaScript for toggling Featured Offers tabs
|
||||
const featuredTabs = document.querySelectorAll('input[name="featured_tabs"]');
|
||||
const featuredTabContents = document.querySelectorAll('#featured-tab-contents .tab-content');
|
||||
|
||||
function updateFeaturedTabs() {
|
||||
featuredTabs.forEach(radio => {
|
||||
if (radio.checked) {
|
||||
const target = radio.id;
|
||||
featuredTabContents.forEach(content => {
|
||||
if (content.getAttribute('data-tab') === target) {
|
||||
content.style.display = 'block';
|
||||
} else {
|
||||
content.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
featuredTabs.forEach(radio => {
|
||||
radio.addEventListener('change', updateFeaturedTabs);
|
||||
});
|
||||
|
||||
// Initialize tabs on page load
|
||||
updateFeaturedTabs();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<style>
|
||||
.tabs-box .tab {
|
||||
z-index: 1;
|
||||
}
|
||||
.tabs-box .tab:checked,
|
||||
.tabs-box .tab.active {
|
||||
z-index: 2;
|
||||
background-color: var(--color-base-200);
|
||||
accent-color: var(--color-base-200);
|
||||
}
|
||||
.tabs-box .tab:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
{% load trade_offer_tags %}
|
||||
{% if offered_cards or wanted_cards %}
|
||||
<hr class="my-8 border-t border-gray-200">
|
||||
<hr class="my-8 border-t border-base-300">
|
||||
<h2 class="text-2xl font-bold mb-4">Results</h2>
|
||||
{% if search_results and search_results.object_list %}
|
||||
{% if search_results %}
|
||||
{% include "trades/_trade_offer_list.html" with offers=search_results %}
|
||||
{% else %}
|
||||
<div class="alert alert-info mt-4">No trade offers found.</div>
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
{% load trade_offer_tags %}
|
||||
{% comment %}
|
||||
This snippet renders a grid of trade offer cards along with pagination controls,
|
||||
using the trade_offer templatetag (i.e. {% render_trade_offer offer %}).
|
||||
|
||||
It expects a context variable:
|
||||
- offers: an iterable or a paginated page of TradeOffer objects.
|
||||
This snippet renders a grid of trade offer cards (or acceptance cards) along with pagination controls.
|
||||
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">
|
||||
{% for offer in offers %}
|
||||
<div class="flex flex-none">
|
||||
<a href="{% url 'trade_offer_detail' pk=offer.pk %}" class="no-underline">
|
||||
{% if offer.accepted_by %}
|
||||
{# Render a trade acceptance using our new tag #}
|
||||
{% render_trade_acceptance offer %}
|
||||
{% else %}
|
||||
{% render_trade_offer offer %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% empty %}
|
||||
<div>No trade offers available.</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,70 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load trade_offer_tags %}
|
||||
|
||||
{% block title %}Update Trade Acceptance{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto max-w-xl mt-6">
|
||||
<h2 class="text-2xl font-bold">Update Trade Acceptance</h2>
|
||||
<form method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</form>
|
||||
{% if form.errors %}
|
||||
<div class="text-center py-8">
|
||||
<ul class="steps">
|
||||
{% if object.is_thanked %}
|
||||
<li class="step step-primary">Accepted</li>
|
||||
<li class="step step-primary">Card Sent</li>
|
||||
<li class="step step-primary">Card Received</li>
|
||||
<li class="step step-primary">Thanks Sent</li>
|
||||
<li class="step step-primary">Thanks Received</li>
|
||||
<li class="step step-primary">Completed</li>
|
||||
{% elif object.is_rejected %}
|
||||
<li class="step step-primary">Accepted</li>
|
||||
<li class="step step-error">
|
||||
<span class="step-icon">X</span>{{ object.get_state_display }}
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="step step-primary">Accepted</li>
|
||||
<li class="step {% if object.get_step_number >= 2 %}step-primary{% endif %}">Card Sent</li>
|
||||
<li class="step {% if object.get_step_number >= 3 %}step-primary{% endif %}">Card Received</li>
|
||||
{% if object.state == 'THANKED_BY_INITIATOR' %}
|
||||
<li class="step step-primary">Thanked by Initiator</li>
|
||||
<li class="step">Thanked by Acceptor</li>
|
||||
<li class="step">Completed</li>
|
||||
{% elif object.state == 'THANKED_BY_ACCEPTOR' %}
|
||||
<li class="step step-primary">Thanked by Acceptor</li>
|
||||
<li class="step">Thanked by Initiator</li>
|
||||
<li class="step">Completed</li>
|
||||
{% elif object.state == 'THANKED_BY_BOTH' %}
|
||||
<li class="step step-primary">Thanked by Initiator</li>
|
||||
<li class="step step-primary">Thanked by Acceptor</li>
|
||||
<li class="step step-primary">Completed</li>
|
||||
{% else %}
|
||||
<li class="step">Thanked by Initiator</li>
|
||||
<li class="step">Thanked by Acceptor</li>
|
||||
<li class="step">Completed</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="py-8">
|
||||
{% render_trade_acceptance object %}
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<h3 class="text-xl font-semibold mb-4">Select an action:</h3>
|
||||
{% if form.fields.state.choices %}
|
||||
{% for state_value, state_label in form.fields.state.choices %}
|
||||
<form method="post" class="mb-2">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="state" value="{{ state_value }}">
|
||||
<button type="submit" class="btn btn-primary w-full">{{ state_label }}</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>No available actions.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if form and form.errors %}
|
||||
<div class="alert alert-error mt-4">
|
||||
<strong>Please correct the errors below:</strong>
|
||||
<ul>
|
||||
|
|
@ -25,8 +79,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-6">
|
||||
<a href="{% url 'trade_offer_detail' pk=object.trade_offer.pk %}" class="btn btn-secondary">Back to Offer Details</a>
|
||||
<a href="{% url 'trade_offer_detail' pk=object.trade_offer.pk %}" class="btn btn-secondary">
|
||||
Back to Offer Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
|
@ -9,10 +9,10 @@
|
|||
<form method="post" novalidate class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{# Use the DRY friend code selector fragment #}
|
||||
{# Use our DRY friend code selector #}
|
||||
{% include "trades/_friend_code_select.html" with friend_codes=friend_codes selected_friend_code=selected_friend_code field_name=form.initiated_by.html_name label="Initiated by" %}
|
||||
|
||||
<!-- Grid layout for Card Selectors: "Have" and "Want" -->
|
||||
<!-- Card Selectors: "Have" and "Want" -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="form-control">
|
||||
{% card_multiselect "have_cards" "Have:" "Select one or more cards..." available_cards form.initial.have_cards %}
|
||||
|
|
@ -67,8 +67,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Style the Choices control as needed
|
||||
choicesInstance.containerOuter.element.classList.add('bg-secondary', 'select', 'select-bordered', 'w-full');
|
||||
choicesInstance.containerInner.element.classList.add('bg-secondary', 'text-white');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
{% endif %}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<strong>Status:</strong> {% if object.is_active %}Open{% else %}Closed{% endif %}
|
||||
</p>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert {{ message.tags }}">{{ message }}</div>
|
||||
|
|
|
|||
|
|
@ -1,47 +1,14 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load trade_offer_tags %}
|
||||
|
||||
{% block title %}Trade Offer Detail{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto max-w-2xl mt-6">
|
||||
<h2 class="text-2xl font-bold">Trade Offer Details</h2>
|
||||
<div class="card bg-base-100 shadow-lg p-4">
|
||||
<p>
|
||||
<strong>Hash:</strong> {{ object.hash }}<br>
|
||||
<strong>Initiated By:</strong> {{ object.initiated_by }}<br>
|
||||
<strong>Cards You Have (Offer):</strong>
|
||||
{% for through in object.trade_offer_have_cards.all %}
|
||||
{{ through.card.name }} x{{ through.quantity }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}<br>
|
||||
<strong>Cards You Want:</strong>
|
||||
{% for through in object.trade_offer_want_cards.all %}
|
||||
{{ through.card.name }} x{{ through.quantity }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}<br>
|
||||
<strong>Created At:</strong> {{ object.created_at|date:"M d, Y H:i" }}<br>
|
||||
<strong>Updated At:</strong> {{ object.updated_at|date:"M d, Y H:i" }}<br>
|
||||
<strong>Status:</strong> {% if object.is_closed %}Closed{% else %}Open{% endif %}
|
||||
</p>
|
||||
<div>
|
||||
{% render_trade_offer object %}
|
||||
</div>
|
||||
|
||||
<h3 class="text-xl font-semibold mt-6">Acceptances</h3>
|
||||
{% if acceptances %}
|
||||
<ul class="space-y-2">
|
||||
{% for acceptance in acceptances %}
|
||||
<li class="card p-4">
|
||||
<p>
|
||||
<strong>Accepted By:</strong> {{ acceptance.accepted_by }}<br>
|
||||
<strong>Requested Card:</strong> {{ acceptance.requested_card.name }}<br>
|
||||
<strong>Offered Card:</strong> {{ acceptance.offered_card.name }}<br>
|
||||
<strong>State:</strong> {{ acceptance.get_state_display }}
|
||||
</p>
|
||||
<a href="{% url 'trade_acceptance_update' acceptance.pk %}" class="btn btn-sm">Update</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No acceptances yet.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if acceptance_form %}
|
||||
<h3 class="text-xl font-semibold mt-6">Accept This Offer</h3>
|
||||
<div class="card p-4">
|
||||
|
|
@ -54,10 +21,9 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="mt-6">
|
||||
<!-- Show delete/close button for the initiator -->
|
||||
{% if is_initiator %}
|
||||
<a href="{{ delete_close_url }}" class="btn btn-danger">Delete/Close Trade Offer</a>
|
||||
{% endif %}
|
||||
{% if is_initiator %}
|
||||
<a href="{{ delete_close_url }}" class="btn btn-danger">Delete/Close Trade Offer</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'trade_offer_list' %}" class="btn btn-secondary">Back to Trade Offers</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="container mx-auto max-w-4xl mt-6">
|
||||
<!-- Filter Form: Friend Code Selector + Toggle for Completed view -->
|
||||
<!-- Filter Form: Friend Code Selector + Toggle for Closed Offers -->
|
||||
<div class="flex justify-end mb-4">
|
||||
<form method="get" class="flex items-center space-x-4">
|
||||
{% include "trades/_friend_code_select.html" with friend_codes=friend_codes selected_friend_code=selected_friend_code field_name="friend_code" label="Filter by Friend Code" %}
|
||||
|
||||
<label class="cursor-pointer flex items-center space-x-2">
|
||||
<span class="font-medium">Only Completed</span>
|
||||
<input type="checkbox" name="show_completed" value="true" class="toggle toggle-primary" {% if show_completed %}checked{% endif %}>
|
||||
<span class="font-medium">Only Closed</span>
|
||||
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary" {% if show_closed %}checked{% endif %}>
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</form>
|
||||
|
|
@ -41,9 +41,9 @@
|
|||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- Section 2: Trade Acceptances Waiting For Your Response -->
|
||||
<!-- Section 2: Waiting for Your Response -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-4">Trade Acceptances Waiting For Your Response</h2>
|
||||
<h2 class="text-2xl font-bold mb-4">Waiting for Your Response</h2>
|
||||
{% if trade_acceptances_waiting_paginated.object_list %}
|
||||
{% include "trades/_trade_offer_list.html" with offers=trade_acceptances_waiting_paginated %}
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
|
|
@ -64,26 +64,26 @@
|
|||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- Section 3: Other Trade Acceptances -->
|
||||
<!-- Section 3: Waiting for Trade Partner's Response -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold mb-4">Other Trade Acceptances</h2>
|
||||
{% if other_trade_acceptances_paginated.object_list %}
|
||||
{% include "trades/_trade_offer_list.html" with offers=other_trade_acceptances_paginated %}
|
||||
<h2 class="text-2xl font-bold mb-4">Waiting for Trade Partner's Response</h2>
|
||||
{% if other_party_trade_acceptances_paginated.object_list %}
|
||||
{% include "trades/_trade_offer_list.html" with offers=other_party_trade_acceptances_paginated %}
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
{% if other_trade_acceptances_paginated.has_previous %}
|
||||
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_trade_acceptances_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
|
||||
{% if other_party_trade_acceptances_paginated.has_previous %}
|
||||
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.previous_page_number }}" class="btn btn-sm">Previous</a>
|
||||
{% else %}
|
||||
<span></span>
|
||||
{% endif %}
|
||||
<span>Page {{ other_trade_acceptances_paginated.number }} of {{ other_trade_acceptances_paginated.paginator.num_pages }}</span>
|
||||
{% if other_trade_acceptances_paginated.has_next %}
|
||||
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_trade_acceptances_paginated.next_page_number }}" class="btn btn-sm">Next</a>
|
||||
<span>Page {{ other_party_trade_acceptances_paginated.number }} of {{ other_party_trade_acceptances_paginated.paginator.num_pages }}</span>
|
||||
{% if other_party_trade_acceptances_paginated.has_next %}
|
||||
<a href="?{% for key, value in request.GET.items %}{% if key != 'other_page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}other_page={{ other_party_trade_acceptances_paginated.next_page_number }}" class="btn btn-sm">Next</a>
|
||||
{% else %}
|
||||
<span></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>No other acceptances found.</p>
|
||||
<p>No pending acceptances found.</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
|
|
|
|||
86
theme/templates/trades/trade_offer_search.html
Normal file
86
theme/templates/trades/trade_offer_search.html
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static trade_offer_tags card_badge cache card_multiselect %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="text-center text-4xl font-bold mb-8 pt-4">Trade Offer Search</h1>
|
||||
|
||||
<!-- Search Form Section -->
|
||||
<section id="trade-search" class="mb-8">
|
||||
<form method="post" action="{% url 'trade_offer_search' %}" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
{% card_multiselect "offered_cards" "Have:" "Select zero or more cards..." available_cards offered_cards %}
|
||||
</div>
|
||||
<div>
|
||||
{% card_multiselect "wanted_cards" "Want:" "Select zero or more cards..." available_cards wanted_cards %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<button type="submit" class="btn btn-primary flex-1">Find a Trade Offer</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- Search Results Section -->
|
||||
<section id="search-results" class="mb-8">
|
||||
{% include "trades/_search_results.html" %}
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<script defer>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tradeSearchForm = document.querySelector('#trade-search form');
|
||||
if (tradeSearchForm) {
|
||||
tradeSearchForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(tradeSearchForm);
|
||||
document.querySelector("#search-results").innerHTML = "<div class='text-center text-2xl font-bold'>Searching...</div>";
|
||||
fetch(tradeSearchForm.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(data => {
|
||||
document.querySelector("#search-results").innerHTML = data;
|
||||
})
|
||||
.catch(error => {
|
||||
alert("There was an error processing your search.");
|
||||
console.error("Error:", error);
|
||||
});
|
||||
});
|
||||
|
||||
// AJAX pagination click handling
|
||||
document.addEventListener('click', function(e) {
|
||||
const target = e.target.closest('.ajax-page-link');
|
||||
if (target) {
|
||||
e.preventDefault();
|
||||
const page = target.getAttribute('data-page');
|
||||
let pageInput = document.getElementById('page');
|
||||
if (pageInput) {
|
||||
pageInput.value = page;
|
||||
} else {
|
||||
pageInput = document.createElement('input');
|
||||
pageInput.type = 'hidden';
|
||||
pageInput.id = 'page';
|
||||
pageInput.name = 'page';
|
||||
pageInput.value = page;
|
||||
tradeSearchForm.appendChild(pageInput);
|
||||
}
|
||||
tradeSearchForm.dispatchEvent(new Event('submit'));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
{% for card in object.want_cards.all %}
|
||||
{{ card.name }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}<br>
|
||||
<strong>Current State:</strong> {{ object.get_state_display }}
|
||||
<strong>Status:</strong> {% if object.is_active %}Open{% else %}Closed{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
13
theme/templates/widgets/button_radio_select.html
Normal file
13
theme/templates/widgets/button_radio_select.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{% for group, options, index in widget.optgroups %}
|
||||
<div class="btn-group" role="group" aria-label="Trade Acceptance State">
|
||||
{% for option in options %}
|
||||
<label class="btn btn-outline-primary {% if option.selected %}btn-active{% endif %}">
|
||||
<input type="radio" name="{{ widget.name }}" value="{{ option.value }}"
|
||||
{% for attr, val in option.attrs.items %} {{ attr }}="{{ val }}" {% endfor %}
|
||||
autocomplete="off" style="display:none;"
|
||||
{% if option.selected %} checked {% endif %}>
|
||||
{{ option.label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue