various small bugfixes; add cards list view
This commit is contained in:
parent
d5f8345581
commit
05a279fa3a
10 changed files with 264 additions and 23 deletions
|
|
@ -34,7 +34,7 @@ EXPOSE 8000
|
||||||
|
|
||||||
RUN python manage.py collectstatic --noinput
|
RUN python manage.py collectstatic --noinput
|
||||||
|
|
||||||
#RUN python manage.py createcachetable django_cache
|
#RUN python manage.py loaddata seed/* && python manage.py createcachetable django_cache
|
||||||
|
|
||||||
# Use gunicorn on port 8000
|
# Use gunicorn on port 8000
|
||||||
CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--timeout", "300"]
|
CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--timeout", "300"]
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@ from .views import (
|
||||||
CardDetailView,
|
CardDetailView,
|
||||||
TradeOfferHaveCardListView,
|
TradeOfferHaveCardListView,
|
||||||
TradeOfferWantCardListView,
|
TradeOfferWantCardListView,
|
||||||
|
CardListView,
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = "cards"
|
app_name = "cards"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('', CardListView.as_view(), name='card_list'),
|
||||||
path('<int:pk>/', CardDetailView.as_view(), name='card_detail'),
|
path('<int:pk>/', CardDetailView.as_view(), name='card_detail'),
|
||||||
path('<int:pk>/trade-offers-have/', TradeOfferHaveCardListView.as_view(), name='card_trade_offer_have_list'),
|
path('<int:pk>/trade-offers-have/', TradeOfferHaveCardListView.as_view(), name='card_trade_offer_have_list'),
|
||||||
path('<int:pk>/trade-offers-want/', TradeOfferWantCardListView.as_view(), name='card_trade_offer_want_list'),
|
path('<int:pk>/trade-offers-want/', TradeOfferWantCardListView.as_view(), name='card_trade_offer_want_list'),
|
||||||
|
|
|
||||||
109
cards/views.py
109
cards/views.py
|
|
@ -27,7 +27,7 @@ class TradeOfferHaveCardListView(ListView):
|
||||||
model = TradeOffer
|
model = TradeOffer
|
||||||
template_name = "cards/_trade_offer_list.html"
|
template_name = "cards/_trade_offer_list.html"
|
||||||
context_object_name = "trade_offers"
|
context_object_name = "trade_offers"
|
||||||
paginate_by = 2
|
paginate_by = 6
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
card_id = self.kwargs.get("pk")
|
card_id = self.kwargs.get("pk")
|
||||||
|
|
@ -47,7 +47,7 @@ class TradeOfferWantCardListView(ListView):
|
||||||
model = TradeOffer
|
model = TradeOffer
|
||||||
template_name = "cards/_trade_offer_list.html"
|
template_name = "cards/_trade_offer_list.html"
|
||||||
context_object_name = "trade_offers"
|
context_object_name = "trade_offers"
|
||||||
paginate_by = 2
|
paginate_by = 6
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
card_id = self.kwargs.get("pk")
|
card_id = self.kwargs.get("pk")
|
||||||
|
|
@ -62,3 +62,108 @@ class TradeOfferWantCardListView(ListView):
|
||||||
context['side'] = 'want'
|
context['side'] = 'want'
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
class CardListView(ListView):
|
||||||
|
model = Card
|
||||||
|
paginate_by = 100 # For non-grouped mode; grouping mode will override default pagination.
|
||||||
|
context_object_name = "cards"
|
||||||
|
|
||||||
|
def get_template_names(self):
|
||||||
|
if self.request.headers.get("x-requested-with") == "XMLHttpRequest":
|
||||||
|
return ["cards/_card_list.html"]
|
||||||
|
return ["cards/card_list.html"]
|
||||||
|
|
||||||
|
def get_ordering(self):
|
||||||
|
order = self.request.GET.get("order", "absolute")
|
||||||
|
if order == "alphabetical":
|
||||||
|
return "name"
|
||||||
|
elif order == "rarity":
|
||||||
|
return "-rarity_level"
|
||||||
|
else: # absolute ordering
|
||||||
|
return "id"
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super().get_queryset()
|
||||||
|
ordering = self.get_ordering()
|
||||||
|
qs = qs.order_by(ordering)
|
||||||
|
return qs.prefetch_related("decks").distinct()
|
||||||
|
|
||||||
|
def get_paginate_by(self, queryset):
|
||||||
|
group_by = self.request.GET.get("group_by")
|
||||||
|
if group_by in ("deck", "cardset", "rarity"):
|
||||||
|
# When grouping is enabled, we want to paginate manually so disable default pagination.
|
||||||
|
return None
|
||||||
|
return self.paginate_by
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
order = self.request.GET.get("order", "absolute")
|
||||||
|
group_by = self.request.GET.get("group_by")
|
||||||
|
context["order"] = order
|
||||||
|
context["group_by"] = group_by
|
||||||
|
|
||||||
|
if group_by in ("deck", "cardset", "rarity"):
|
||||||
|
# Fetch the complete queryset (no slicing)
|
||||||
|
full_qs = self.get_queryset()
|
||||||
|
all_cards = list(full_qs)
|
||||||
|
flat_cards = []
|
||||||
|
|
||||||
|
if group_by == "deck":
|
||||||
|
# Each card may belong to multiple decks – reproduce the existing logic.
|
||||||
|
for card in all_cards:
|
||||||
|
for deck in card.decks.all():
|
||||||
|
flat_cards.append({"group": deck.name, "card": card})
|
||||||
|
flat_cards.sort(key=lambda x: x["group"].lower())
|
||||||
|
elif group_by == "cardset":
|
||||||
|
for card in all_cards:
|
||||||
|
flat_cards.append({"group": card.cardset, "card": card})
|
||||||
|
flat_cards.sort(key=lambda x: x["group"].lower())
|
||||||
|
elif group_by == "rarity":
|
||||||
|
for card in all_cards:
|
||||||
|
flat_cards.append({"group": card.rarity_level, "card": card})
|
||||||
|
flat_cards.sort(key=lambda x: x["group"], reverse=True)
|
||||||
|
|
||||||
|
total_cards = len(flat_cards)
|
||||||
|
try:
|
||||||
|
page_number = int(self.request.GET.get("page", 1))
|
||||||
|
if page_number < 1:
|
||||||
|
page_number = 1
|
||||||
|
except ValueError:
|
||||||
|
page_number = 1
|
||||||
|
|
||||||
|
per_page = 96
|
||||||
|
start = (page_number - 1) * per_page
|
||||||
|
end = page_number * per_page
|
||||||
|
page_flat_cards = flat_cards[start:end]
|
||||||
|
|
||||||
|
# Reassemble the flat list into grouped structure for just this page.
|
||||||
|
page_groups = []
|
||||||
|
for item in page_flat_cards:
|
||||||
|
group_value = item["group"]
|
||||||
|
card_obj = item["card"]
|
||||||
|
if page_groups and page_groups[-1]["group"] == group_value:
|
||||||
|
page_groups[-1]["cards"].append(card_obj)
|
||||||
|
else:
|
||||||
|
page_groups.append({"group": group_value, "cards": [card_obj]})
|
||||||
|
context["groups"] = page_groups
|
||||||
|
|
||||||
|
# Set up custom pagination context.
|
||||||
|
from math import ceil
|
||||||
|
num_pages = ceil(total_cards / per_page)
|
||||||
|
page_obj = {
|
||||||
|
"number": page_number,
|
||||||
|
"has_previous": page_number > 1,
|
||||||
|
"has_next": page_number < num_pages,
|
||||||
|
"previous_page_number": page_number - 1 if page_number > 1 else None,
|
||||||
|
"next_page_number": page_number + 1 if page_number < num_pages else None,
|
||||||
|
"paginator": {
|
||||||
|
"num_pages": num_pages,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
context["page_obj"] = page_obj
|
||||||
|
context["is_paginated"] = total_cards > per_page
|
||||||
|
context["total_cards"] = total_cards
|
||||||
|
# Optionally, keep the full queryset in object_list.
|
||||||
|
context["object_list"] = full_qs
|
||||||
|
return context
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{% load static tailwind_tags gravatar %}
|
{% load static tailwind_tags gravatar %}
|
||||||
{% url 'home' as home_url %}
|
{% url 'home' as home_url %}
|
||||||
{% url 'trade_offer_list' as trade_offer_list_url %}
|
{% url 'trade_offer_list' as trade_offer_list_url %}
|
||||||
{% url 'trade_offer_my_list' as trade_offer_my_list_url %}
|
{% url 'cards:card_list' as cards_list_url %}
|
||||||
{% url 'settings' as settings_url %}
|
{% url 'settings' as settings_url %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
|
class="menu menu-sm dropdown-content bg-base-100 rounded-box z-1 mt-3 w-52 p-2 shadow">
|
||||||
<li><a href="{% url 'home' %}">Home</a></li>
|
<li><a href="{% url 'home' %}">Home</a></li>
|
||||||
|
<li><a href="{% url 'cards:card_list' %}">Cards</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a>Trades</a>
|
<a>Trades</a>
|
||||||
<ul class="p-2">
|
<ul class="p-2">
|
||||||
|
|
@ -87,6 +88,7 @@
|
||||||
<div class="navbar-center hidden md:flex">
|
<div class="navbar-center hidden md:flex">
|
||||||
<ul class="menu menu-horizontal px-1">
|
<ul class="menu menu-horizontal px-1">
|
||||||
<li><a href="{% url 'home' %}">Home</a></li>
|
<li><a href="{% url 'home' %}">Home</a></li>
|
||||||
|
<li><a href="{% url 'cards:card_list' %}">Cards</a></li>
|
||||||
<li>
|
<li>
|
||||||
<details>
|
<details>
|
||||||
<summary>Trades</summary>
|
<summary>Trades</summary>
|
||||||
|
|
@ -154,13 +156,13 @@
|
||||||
<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>
|
<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>
|
<span class="dock-label">Home</span>
|
||||||
</button>
|
</button>
|
||||||
<button @click="window.location.href = '{{ trade_offer_list_url }}'" class="{% if request.path == trade_offer_list_url %}dock-active{% endif %}">
|
<button @click="window.location.href = '{{ cards_list_url }}'" class="{% if request.path == cards_list_url %}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>
|
<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"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 0 0-2.25-2.25H6A2.25 2.25 0 0 0 3.75 6v8.25A2.25 2.25 0 0 0 6 16.5h2.25m8.25-8.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-7.5A2.25 2.25 0 0 1 8.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 0 0-2.25 2.25v6" /></svg>
|
||||||
<span class="dock-label">All Offers</span>
|
<span class="dock-label">Cards</span>
|
||||||
</button>
|
</button>
|
||||||
<button @click="window.location.href = '{{ trade_offer_my_list_url }}'" class="{% if request.path == trade_offer_my_list_url %}dock-active{% endif %}">
|
<button @click="window.location.href = '{{ trade_offer_list_url }}'" class="{% if request.path == trade_offer_list_url %}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>
|
<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"><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">My Trades</span>
|
<span class="dock-label">Trades</span>
|
||||||
</button>
|
</button>
|
||||||
<button @click="window.location.href = '{{ settings_url }}'" class="{% if request.path == settings_url %}dock-active{% endif %}">
|
<button @click="window.location.href = '{{ settings_url }}'" class="{% if request.path == settings_url %}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 %}
|
{% 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 %}
|
||||||
|
|
|
||||||
40
theme/templates/cards/_card_list.html
Normal file
40
theme/templates/cards/_card_list.html
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{% load card_badge %}
|
||||||
|
{% if group_by and groups %}
|
||||||
|
{% for group in groups %}
|
||||||
|
<div class="divider">{{ group.group }}</div>
|
||||||
|
<div class="flex justify-center flex-wrap gap-4">
|
||||||
|
{% for card in group.cards %}
|
||||||
|
<a href="{% url 'cards:card_detail' card.pk %}">
|
||||||
|
{% card_badge card "" %}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<div class="flex justify-center flex-wrap gap-4">
|
||||||
|
{% for card in cards %}
|
||||||
|
<a href="{% url 'cards:card_detail' card.pk %}">
|
||||||
|
{% card_badge card "" %}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pagination Controls -->
|
||||||
|
<div class="mt-6">
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="flex justify-center space-x-2">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<button class="btn btn-outline" @click="$dispatch('change-page', { page: {{ page_obj.previous_page_number }} })">
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
<span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<button class="btn btn-outline" @click="$dispatch('change-page', { page: {{ page_obj.next_page_number }} })">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
52
theme/templates/cards/card_list.html
Normal file
52
theme/templates/cards/card_list.html
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static card_badge %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mx-auto p-4"
|
||||||
|
x-data="{
|
||||||
|
order: '{{ order }}',
|
||||||
|
groupBy: '{{ group_by|default:'none' }}',
|
||||||
|
page: 1,
|
||||||
|
loadCards() {
|
||||||
|
// Construct URL using current pathname and query parameters.
|
||||||
|
let groupParam = this.groupBy === 'none' ? '' : this.groupBy;
|
||||||
|
let url = window.location.pathname + '?order=' + this.order + '&group_by=' + groupParam + '&page=' + this.page;
|
||||||
|
fetch(url, { headers: { 'x-requested-with': 'XMLHttpRequest' } })
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(html => { this.$refs.cardList.innerHTML = html; });
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
x-init="loadCards()"
|
||||||
|
x-on:change-page.window="page = $event.detail.page; loadCards()"
|
||||||
|
>
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Cards</h1>
|
||||||
|
<div class="flex flex-wrap items-center justify-between mb-6">
|
||||||
|
<!-- Sort Dropdown -->
|
||||||
|
<div class="dropdown dropdown-end m-1">
|
||||||
|
<div tabindex="0" class="btn">
|
||||||
|
<span x-text="order === 'absolute' ? 'Absolute' : (order === 'alphabetical' ? 'Alphabetical' : 'Rarity')"></span> 🞃
|
||||||
|
</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()">Absolute</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>
|
||||||
|
</div>
|
||||||
|
<!-- Grouping Dropdown -->
|
||||||
|
<div class="dropdown dropdown-end m-1">
|
||||||
|
<div tabindex="0" class="btn">
|
||||||
|
<span x-text="groupBy === 'none' ? 'No Group' : (groupBy.charAt(0).toUpperCase() + groupBy.slice(1))"></span> 🞃
|
||||||
|
</div>
|
||||||
|
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-52">
|
||||||
|
<li><a href="#" @click.prevent="groupBy = 'none'; page = 1; loadCards()">No Group</a></li>
|
||||||
|
<li><a href="#" @click.prevent="groupBy = 'deck'; page = 1; loadCards()">Deck</a></li>
|
||||||
|
<li><a href="#" @click.prevent="groupBy = 'cardset'; page = 1; loadCards()">Cardset</a></li>
|
||||||
|
<li><a href="#" @click.prevent="groupBy = 'rarity'; page = 1; loadCards()">Rarity</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Container for the partial card list -->
|
||||||
|
<div x-ref="cardList">
|
||||||
|
<!-- The contents of _card_list.html will be loaded here via AJAX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -92,7 +92,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
searchEnabled: true,
|
searchEnabled: true,
|
||||||
shouldSort: false,
|
shouldSort: false,
|
||||||
allowHTML: true,
|
allowHTML: true,
|
||||||
closeDropdownOnSelect: false,
|
closeDropdownOnSelect: true,
|
||||||
removeItemButton: true,
|
removeItemButton: true,
|
||||||
searchFields: ['label'],
|
searchFields: ['label'],
|
||||||
resetScrollPosition: false,
|
resetScrollPosition: false,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
{% load gravatar card_badge tailwind_tags %}<!DOCTYPE html>
|
{% load gravatar card_badge tailwind_tags %}<!DOCTYPE html>
|
||||||
<html>
|
<html style="background-color: transparent !important;">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{{base_url}}/static/css/dist/styles.css">
|
<style>
|
||||||
|
{% include 'static/css/dist/styles.css' %}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body style="background-color: transparent !important;">
|
||||||
<div class="trade-offer-card-screenshot p-4 h-full w-auto flex justify-center">
|
<div class="trade-offer-card-screenshot p-4 h-full w-auto flex justify-center" style="background-color: transparent !important;">
|
||||||
<div class="transition-all duration-500 trade-offer-card my-auto">
|
<div class="transition-all duration-500 trade-offer-card my-auto">
|
||||||
|
|
||||||
<!-- Flip container providing perspective -->
|
<!-- Flip container providing perspective -->
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,11 @@ def render_trade_offer_png(context, offer, show_friend_code=False):
|
||||||
image_width = base_width
|
image_width = base_width
|
||||||
image_height = int(round(image_width / aspect_ratio))
|
image_height = int(round(image_width / aspect_ratio))
|
||||||
|
|
||||||
base_url = context.get('request').build_absolute_uri('/')
|
request = context.get("request")
|
||||||
|
if request.get_host().startswith("localhost"):
|
||||||
|
base_url = "http://{0}".format(request.get_host())
|
||||||
|
else:
|
||||||
|
base_url = "https://{0}".format(request.get_host())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'offer_pk': offer.pk,
|
'offer_pk': offer.pk,
|
||||||
|
|
|
||||||
|
|
@ -618,26 +618,60 @@ class TradeOfferPNGView(View):
|
||||||
|
|
||||||
html = render_to_string("templatetags/trade_offer_png.html", tag_context)
|
html = render_to_string("templatetags/trade_offer_png.html", tag_context)
|
||||||
|
|
||||||
|
# If there's a query parameter 'debug' set to true, render the HTML to the response.
|
||||||
|
if request.GET.get('debug'):
|
||||||
|
return HttpResponse(html, content_type="text/html")
|
||||||
|
|
||||||
|
css = render_to_string("static/css/dist/styles.css")
|
||||||
|
|
||||||
# Launch Playwright to render the HTML and capture a screenshot.
|
# Launch Playwright to render the HTML and capture a screenshot.
|
||||||
with sync_playwright() as p:
|
with sync_playwright() as p:
|
||||||
|
print("Launching browser")
|
||||||
browser = p.chromium.launch(
|
browser = p.chromium.launch(
|
||||||
headless=True,
|
headless=True,
|
||||||
args=[
|
args=[
|
||||||
"--disable-gpu",
|
|
||||||
"--no-sandbox",
|
"--no-sandbox",
|
||||||
'--disable-setuid-sandbox',
|
"--disable-setuid-sandbox",
|
||||||
'--disable-dev-shm-usage',
|
"--disable-dev-shm-usage",
|
||||||
'--disable-accelerated-2d-canvas',
|
"--disable-accelerated-2d-canvas",
|
||||||
'--no-first-run',
|
"--disable-gpu",
|
||||||
'--disable-gpu'
|
#"--single-process",
|
||||||
|
"--no-zygote",
|
||||||
|
"--disable-audio-output",
|
||||||
|
#"--disable-software-rasterizer",
|
||||||
|
"--disable-webgl",
|
||||||
|
#"--disable-web-security",
|
||||||
|
#"--disable-features=LazyFrameLoading",
|
||||||
|
#"--disable-features=IsolateOrigins",
|
||||||
|
#"--disable-background-networking",
|
||||||
|
"--no-first-run",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
print("Launched browser, creating context")
|
||||||
context_browser = browser.new_context(viewport={"width": image_width, "height": image_height})
|
context_browser = browser.new_context(viewport={"width": image_width, "height": image_height})
|
||||||
|
print("Created context, creating page")
|
||||||
page = context_browser.new_page()
|
page = context_browser.new_page()
|
||||||
page.set_content(html, wait_until="networkidle")
|
print("Created page, setting content")
|
||||||
|
|
||||||
|
# Listen for all console logs, errors, and warnings
|
||||||
|
page.on("console", lambda msg: print(f"Console {msg.type}: {msg.text}"))
|
||||||
|
page.on("pageerror", lambda err: print(f"Page error: {err}"))
|
||||||
|
|
||||||
|
# Listen specifically for failed resource loads
|
||||||
|
page.on("requestfailed", lambda request: print(f"Failed to load: {request.url} - {request.failure.error_text}"))
|
||||||
|
|
||||||
|
# # Instead of using a link tag, let's inject the CSS directly
|
||||||
|
# css = render_to_string("static/css/dist/styles.css")
|
||||||
|
# page.add_style_tag(content=css)
|
||||||
|
|
||||||
|
page.set_content(html, wait_until="domcontentloaded")
|
||||||
|
print("Set content, waiting for element")
|
||||||
element = page.wait_for_selector(".trade-offer-card-screenshot")
|
element = page.wait_for_selector(".trade-offer-card-screenshot")
|
||||||
|
print("Found element, capturing screenshot")
|
||||||
screenshot_bytes = element.screenshot(type="png", omit_background=True)
|
screenshot_bytes = element.screenshot(type="png", omit_background=True)
|
||||||
|
print("Captured screenshot, closing browser")
|
||||||
browser.close()
|
browser.close()
|
||||||
|
print("Closed browser, returning screenshot")
|
||||||
|
|
||||||
return HttpResponse(screenshot_bytes, content_type="image/png")
|
return HttpResponse(screenshot_bytes, content_type="image/png")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue