fix card badges to have better rarity visibility and other bugfixes
This commit is contained in:
parent
37d8bd5981
commit
262f0ea190
14 changed files with 4515 additions and 1255 deletions
|
|
@ -23,7 +23,7 @@ COPY .env.production /code/.env
|
|||
ENV HOME=/code
|
||||
|
||||
# Install NPM & node.js
|
||||
RUN apt-get update && apt-get install -y nodejs npm xvfb
|
||||
RUN apt-get update && apt-get install -y nodejs npm xvfb netcat-openbsd
|
||||
|
||||
RUN playwright install-deps && playwright install
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from accounts.models import CustomUser, FriendCode
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Seed default friend codes for TestUsers after friend codes have been loaded."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
users_updated = 0
|
||||
for user in CustomUser.objects.all():
|
||||
# Automatically select the earliest friend code added for the user:
|
||||
default_code = FriendCode.objects.filter(user=user).order_by('created_at').first()
|
||||
if default_code:
|
||||
user.default_friend_code = default_code
|
||||
user.save(update_fields=["default_friend_code"])
|
||||
self.stdout.write(f"Set default friend code for user {user.username} to {default_code.friend_code}.")
|
||||
users_updated += 1
|
||||
else:
|
||||
self.stdout.write(f"No friend code found for user {user.username}.")
|
||||
self.stdout.write(self.style.SUCCESS(f"Seeded default friend codes for {users_updated} user(s)."))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 5.1.2 on 2025-03-31 22:48
|
||||
# Generated by Django 5.1.2 on 2025-04-07 04:19
|
||||
|
||||
import accounts.models
|
||||
import django.contrib.auth.models
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 5.1.2 on 2025-03-31 22:48
|
||||
# Generated by Django 5.1.2 on 2025-04-07 04:19
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
|
|
|||
|
|
@ -45,5 +45,7 @@ def update_card_style(sender, instance, action, **kwargs):
|
|||
else:
|
||||
instance.style = "background: linear-gradient(to right, #AAAAAA, #AAAAAA, #AAAAAA);"
|
||||
if not color_is_dark(decks.first().hex_color):
|
||||
instance.style += "color: var(--color-gray-700);"
|
||||
instance.style += "color: var(--color-gray-700); text-shadow: 0 0 0 var(--color-gray-700);"
|
||||
else:
|
||||
instance.style += "text-shadow: 0 0 0 #fff;"
|
||||
instance.save(update_fields=["style"])
|
||||
File diff suppressed because it is too large
Load diff
2248
seed/M4R9zUMD.txt
Normal file
2248
seed/M4R9zUMD.txt
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -104,27 +104,27 @@
|
|||
<div x-show="activeTab === 'profile'">
|
||||
<div class="card card-border bg-base-100 shadow-lg mx-auto p-6 mb-4">
|
||||
{% with gravatar_profile=request.user.email|gravatar_profile_data %}
|
||||
{% if gravatar_profile %}
|
||||
|
||||
<div class="hovercard-profile mb-4 text-center">
|
||||
<img src="{{ gravatar_profile.thumbnailUrl }}" alt="{{ gravatar_profile.displayName|default:request.user.username }}" class="rounded-full mb-2 mx-auto" />
|
||||
<div class="avatar block mx-auto w-32">
|
||||
<div class="W-32 rounded-full">
|
||||
{{ request.user.email|gravatar:128 }}
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://gravatar.com/profile/avatars" target="_blank" rel="noopener noreferrer" class="btn btn-primary mt-4">
|
||||
Edit Avatar on Gravatar
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-center">{{ _('No Gravatar profile data available.') }}</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="divider"></div>
|
||||
<h2 class="text-base font-semibold pt-0">What is Gravatar?</h2>
|
||||
<p class="mb-4 text-sm">Gravatar (Globally Recognized Avatar) is a free service that links your email address to a profile picture. Many websites, including this one, use Gravatar to display your preferred avatar automatically.</p>
|
||||
|
||||
<h2 class="text-base font-semibold">How does it work?</h2>
|
||||
<p class="mb-4 text-sm">If you've set up a Gravatar, your profile picture will appear here whenever you use your email on supported sites. If you don't have a Gravatar yet, you'll see a default image instead.</p>
|
||||
<p class="mb-4 text-sm">If you've set up a Gravatar, your profile picture will appear here whenever you use your email on supported sites. If you don't have a Gravatar yet, you'll see a default randomly-generated avatar instead.</p>
|
||||
|
||||
<h2 class="text-base font-semibold">Is it safe? What about privacy?</h2>
|
||||
<p class="mb-4 text-sm">Gravatar is completely optional, opt-in, and prioritizes your security and privacy. Your email is never visible to anyone and only a hashed version is shown on the page and sent to Gravatar, protecting your identity while ensuring that your email address is not exposed to bots or scrapers.</p>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static card_badge %}
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4"
|
||||
<div class="container mx-auto"
|
||||
x-data="{
|
||||
order: '{{ order }}',
|
||||
groupBy: '{{ group_by|default:'none' }}',
|
||||
|
|
@ -15,10 +15,7 @@
|
|||
.then(html => { this.$refs.cardList.innerHTML = html; });
|
||||
}
|
||||
}"
|
||||
x-init="loadCards()"
|
||||
x-on:change-page.window="page = $event.detail.page; loadCards()"
|
||||
>
|
||||
|
||||
x-on:change-page.window="page = $event.detail.page; loadCards()">
|
||||
<div class="flex flex-wrap items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold">Cards</h1>
|
||||
|
|
@ -57,7 +54,7 @@
|
|||
</div>
|
||||
<!-- Container for the partial card list -->
|
||||
<div x-ref="cardList">
|
||||
|
||||
{% include "cards/_card_list.html" with cards=cards page_obj=page_obj %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -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-2 flex-wrap justify-center items-start">
|
||||
<div class="flex flex-row gap-6 md:gap-2 lg:gap-6 flex-wrap justify-center items-start py-6">
|
||||
{% for offer in offers %}
|
||||
<div class="flex flex-none">
|
||||
{% if offer.accepted_by %}
|
||||
|
|
|
|||
|
|
@ -5,63 +5,41 @@
|
|||
|
||||
{% block content %}
|
||||
<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 }},
|
||||
loadOffers() {
|
||||
let url = new URL('{% url 'trade_offer_list' %}', window.location.origin);
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
params.set('page', this.page);
|
||||
// Include the expanded state if active
|
||||
if (this.allExpanded) {
|
||||
params.set('expanded', 'true');
|
||||
} else {
|
||||
params.delete('expanded');
|
||||
}
|
||||
url.search = params.toString();
|
||||
fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' }})
|
||||
.then(response => response.text())
|
||||
.then(html => { this.$refs.offersContainer.innerHTML = html; });
|
||||
},
|
||||
// Update the URL so that navigation preserves our expanded state.
|
||||
updateUrl() {
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
if (this.allExpanded) {
|
||||
params.set('expanded', 'true');
|
||||
} else {
|
||||
params.delete('expanded');
|
||||
}
|
||||
history.replaceState(null, '', window.location.pathname + '?' + params.toString());
|
||||
}
|
||||
}"
|
||||
x-init="loadOffers()"
|
||||
x-on:change-page.window="page = $event.detail.page; loadOffers()">
|
||||
|
||||
<!-- Header with the toggle -->
|
||||
<!-- Header without Expand All -->
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h1 class="text-2xl font-bold">Trade Offers</h1>
|
||||
<div>
|
||||
<div class="flex items-center gap-4">
|
||||
<form method="get" class="flex items-center gap-4" x-data>
|
||||
<label class="cursor-pointer flex items-center gap-2">
|
||||
<span x-text="allExpanded ? 'Collapse All' : 'Expand All'"></span>
|
||||
<input type="checkbox" name="all_expanded" value="true" class="toggle toggle-primary"
|
||||
@click="allExpanded = !allExpanded; $dispatch('toggle-all', { expanded: allExpanded }); updateUrl();">
|
||||
</label>
|
||||
<label class="cursor-pointer flex items-center gap-2">
|
||||
<span>Only Closed</span>
|
||||
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary" @change="$el.form.submit()" {% if show_closed %}checked{% endif %}>
|
||||
<input type="checkbox" name="show_closed" value="true" class="toggle toggle-primary"
|
||||
@change="$el.form.submit()" {% if show_closed %}checked{% endif %}>
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary" x-show="false">Apply</button>
|
||||
</form>
|
||||
<div>
|
||||
<a href="{% url 'trade_offer_create' %}" class="btn btn-success">Create New Offer</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Trade Offers -->
|
||||
<section class="mb-12">
|
||||
<div class="flex justify-end mb-4">
|
||||
<a href="{% url 'trade_offer_create' %}" class="btn btn-success">Create New Offer</a>
|
||||
</div>
|
||||
|
||||
<div id="all-trade-offers" x-ref="offersContainer">
|
||||
{% include "trades/_trade_offer_list.html" with offers=offers page_obj=page_obj expanded=expanded %}
|
||||
{% include "trades/_trade_offer_list.html" with offers=offers page_obj=page_obj %}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<div class="relative 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 self-start font-semibold leading-tight text-sm">{{ name }}</div>
|
||||
<div class="row-start-2 col-start-1 col-span-3 truncate self-end text-xs">{{ rarity }}</div>
|
||||
<div class="row-start-2 col-start-1 col-span-3 truncate self-end text-xs text-transparent">{{ rarity }}</div>
|
||||
<div class="row-start-2 col-start-4 col-span-1 self-end text-right truncate font-semibold leading-tight text-sm">{{ cardset }}</div>
|
||||
{% if quantity != None %}<div class="row-start-1 col-start-4 self-start 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>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
{% load gravatar card_badge cache %}
|
||||
|
||||
{% cache 60 trade_offer offer_pk %}
|
||||
<div x-data="{ flipped: {{flipped|lower}}, offerExpanded: true, acceptanceExpanded: false }" x-ref="tradeOffer" class="transition-all duration-500 trade-offer-card my-auto h-full w-auto justify-center">
|
||||
<div x-data="{ flipped: {{flipped|lower}}, offerExpanded: {{flipped|yesno:'false,true'}}, acceptanceExpanded: {{flipped|lower}} }" x-ref="tradeOffer" class="transition-all duration-500 trade-offer-card my-auto h-full w-auto justify-center">
|
||||
<div class="flip-container">
|
||||
<div{% if not on_detail_page %} @click="window.location.href = '{% url 'trade_offer_detail' pk=offer_pk %}'"{% endif %} class="flip-inner grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg w-90 transform transition-transform duration-500 ease-in-out{% if not on_detail_page %} cursor-pointer{% endif %}"
|
||||
<div{% if not on_detail_page %} @click="window.location.href = '{% url 'trade_offer_detail' pk=offer_pk %}'"{% endif %} class="flip-inner grid grid-cols-1 grid-rows-1 card bg-base-100 card-border shadow-lg w-90 transform transition-transform duration-500 ease-in-out{% if not on_detail_page %} cursor-pointer{% endif %}{%if flipped %} rotate-y-180{% endif %}"
|
||||
:class="{'rotate-y-180': flipped}">
|
||||
<div class="flip-face front col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between">
|
||||
<div class="flip-face front rotate-y-0 col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between">
|
||||
<div class="flip-face-header self-start">
|
||||
<div class="relative mt-6 mb-4 mx-2 sm:mx-4">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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 class="flip-face back col-start-1 row-start-1 grid grid-cols-1 auto-rows-min gap-2 content-between rotate-y-180">
|
||||
<div class="flip-face-header self-start">
|
||||
<div class="relative mt-6 mb-4 mx-2 sm:mx-4">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
|
|
@ -144,7 +144,7 @@
|
|||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
.flip-face.front {
|
||||
.rotate-y-0 {
|
||||
transform: rotateY(0);
|
||||
}
|
||||
.rotate-y-180 {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 5.1.2 on 2025-03-31 22:48
|
||||
# Generated by Django 5.1.2 on 2025-04-07 04:19
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue