progress on conversion to tailwind

This commit is contained in:
badblocks 2025-03-06 21:28:36 -08:00
parent 6a872124c6
commit 6e2843c60e
110 changed files with 4997 additions and 1691 deletions

View file

@ -0,0 +1,92 @@
# Generated by Django 5.1.2 on 2025-03-07 01:04
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Card',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('cardnum', models.IntegerField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='CardSet',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='Rarity',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('icons', models.CharField(max_length=64)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='CardNameTranslation',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('language', models.CharField(max_length=64)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('card', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='name_translations', to='cards.card')),
],
),
migrations.AddField(
model_name='card',
name='cardset',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='cards', to='cards.cardset'),
),
migrations.CreateModel(
name='Deck',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('hex_color', models.CharField(max_length=9)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('cardset', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='decks', to='cards.cardset')),
],
),
migrations.AddField(
model_name='card',
name='decks',
field=models.ManyToManyField(to='cards.deck'),
),
migrations.CreateModel(
name='DeckNameTranslation',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('language', models.CharField(max_length=64)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('deck', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='name_translations', to='cards.deck')),
],
),
migrations.AddField(
model_name='card',
name='rarity',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='cards', to='cards.rarity'),
),
]

View file

@ -52,6 +52,15 @@ class Rarity(models.Model):
def __str__(self):
return self.name
@property
def normalized_id(self):
"""
For trading equivalence: treat Special Art Rare (pk 7) and Super Rare (pk 6) as the same.
"""
if self.pk in (6, 7):
return 6
return self.pk
class Card(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64)
@ -63,4 +72,12 @@ class Card(models.Model):
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name + " " + self.rarity.icons + " " + self.cardset.name
# For display, we show the original rarity icons.
return f"{self.name} {self.rarity.icons} {self.cardset.name}"
@property
def normalized_rarity(self):
"""
Returns the canonical rarity id for trade logic.
"""
return self.rarity.normalized_id

View file

@ -1,11 +1,28 @@
from django import template
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
register = template.Library()
@register.inclusion_tag("includes/card_badge.html")
def card_badge(card):
@register.inclusion_tag("templatetags/card_badge.html")
def card_badge(card, quantity=1, show_single_count=True):
return {
'card': card,
'quantity': quantity,
'decks': card.decks.all() if card else None,
'dropdown': card is None
}
'dropdown': card is None,
'show_single_count': show_single_count,
}
@register.filter
def card_badge_inline(card, quantity=1):
"""
Renders an inline card badge.
"""
html = render_to_string("templatetags/card_badge.html", {
'card': card,
'quantity': quantity,
'decks': card.decks.all() if card else None,
'dropdown': card is None,
})
return mark_safe(html)

View file

@ -3,46 +3,69 @@ from cards.models import Card
register = template.Library()
@register.inclusion_tag('includes/card_multiselect.html')
def card_multiselect(field_name, label, available_cards, placeholder, selected_values=None, cache_timeout=86400, cache_key="available_cards_options"):
@register.inclusion_tag('templatetags/card_multiselect.html')
def card_multiselect(field_name, label, placeholder, card_filter=None, selected_values=None, cache_timeout=86400, cache_key="available_cards_options"):
"""
Renders a Select2 field for choosing cards.
Renders a multiselect field for choosing cards, storing the card ID only as the option's value and
the quantity in a dedicated data attribute.
Parameters:
- field_name: The name attribute for the select tag.
- label: Label text to show above the selector.
- available_cards: A queryset or list of card objects that will populate the options.
- placeholder: Placeholder text to show in the select.
- selected_values: (Optional) A list of selected card IDs (will be compared as strings).
- card_filter: (Optional) A dictionary of filter parameters to apply on the Card query.
- selected_values: (Optional) A list of selected card values; if a value includes a quantity
it should be in the format "card_id:quantity".
- cache_timeout: (Optional) Cache timeout (in seconds) for the options block.
- cache_key: (Optional) Cache keyby default both select fields use the same key so that caching is shared.
"""
if selected_values is None:
selected_values = []
# Normalize selected_values to strings.
selected_values = [str(val) for val in selected_values]
# Map the selected values into a dictionary: { card_id (str): quantity (str) }
selected_cards = {}
for val in selected_values:
parts = str(val).split(':')
card_id = parts[0]
quantity = parts[1] if len(parts) > 1 else "1"
selected_cards[card_id] = quantity
# If a card_filter is provided, use it; otherwise retrieve all cards.
if card_filter:
available_cards_qs = Card.objects.filter(**card_filter)
else:
available_cards_qs = Card.objects.all()
# --- Available cards for the search form ---
available_cards = list(
Card.objects.order_by("name", "rarity__pk")
available_cards_qs.order_by("name", "rarity__pk")
.select_related("rarity", "cardset")
.prefetch_related("decks")
)
for card in available_cards:
if card.decks.count() == 1:
card.style = "background-color: " + card.decks.all()[0].hex_color + "; color: white;"
elif card.decks.count() == 2:
card.style = "background: linear-gradient(to right, " + card.decks.all()[0].hex_color + ", " + card.decks.all()[1].hex_color + "); color: white;"
elif card.decks.count() >= 3:
card.style = "background: linear-gradient(to right, " + card.decks.all()[0].hex_color + ", " + card.decks.all()[1].hex_color + ", " + card.decks.all()[2].hex_color + "); color: white;"
# Apply styling based on deck count.
deck_count = card.decks.count()
if deck_count == 1:
card.style = f"background-color: {card.decks.all()[0].hex_color}; color: white;"
elif deck_count == 2:
decks = card.decks.all()
card.style = f"background: linear-gradient(to right, {decks[0].hex_color}, {decks[1].hex_color}); color: white;"
elif deck_count >= 3:
decks = card.decks.all()
card.style = f"background: linear-gradient(to right, {decks[0].hex_color}, {decks[1].hex_color}, {decks[2].hex_color}); color: white;"
# Attach selected_quantity only if the card is preselected.
pk_str = str(card.pk)
if pk_str in selected_cards:
card.selected_quantity = selected_cards[pk_str]
return {
'field_name': field_name,
'field_id': field_name, # using the name as id for simplicity
'label': label,
'available_cards': available_cards,
'placeholder': placeholder,
'selected_values': selected_values,
# For caching/selection checks, pass a list of the preselected card IDs.
'selected_values': list(selected_cards.keys()),
'cache_timeout': cache_timeout,
'cache_key': cache_key,
}