feat(cards): Refactor card styling and implement JS multiselect

Refactors card styling by moving color data to the `CardSet` model, removing the `Card.style` and `Pack.hex_color` fields.

- Adds `hex_color` to `CardSet` and a `CardSetColorMapping` model to populate it during import.
- Card importer now uses correct filename regexes to identify sets and apply color mappings.
- Card badge styling is now derived from the `CardSet`'s color, simplifying the data model.

Replaces the old clunky card multiselect with a dynamic Alpine.js component for an improved user experience.

- Introduces an API endpoint (`cards/api/search/`) for asynchronous searching.
- Provides a modern search-as-you-type interface with a `<noscript>` fallback.
This commit is contained in:
badblocks 2025-06-20 00:30:03 -07:00
parent af2f48a491
commit ecb060af6d
No known key found for this signature in database
15 changed files with 668 additions and 533 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 5.1 on 2025-06-15 03:44
# Generated by Django 5.1 on 2025-06-20 07:14
import django.db.models.deletion
import parler.fields
@ -79,6 +79,35 @@ class Migration(migrations.Migration):
},
bases=(parler.models.TranslatableModelMixin, models.Model),
),
migrations.CreateModel(
name="CardSetColorMapping",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
(
"cardset_id",
models.CharField(
help_text="The cardset ID to match (e.g., 'A1').",
max_length=10,
unique=True,
),
),
(
"hex_color",
models.CharField(
help_text="The hex color code to use for this cardset.",
max_length=9,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
],
options={
"verbose_name": "Cardset Color Mapping",
"verbose_name_plural": "Cardset Color Mappings",
"ordering": ["cardset_id"],
},
),
migrations.CreateModel(
name="CardType",
fields=[
@ -216,7 +245,6 @@ class Migration(migrations.Migration):
name="Pack",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("hex_color", models.CharField(max_length=9)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
@ -271,14 +299,6 @@ class Migration(migrations.Migration):
null=True,
),
),
(
"style",
models.CharField(
blank=True,
help_text="Inline CSS style for the card, used for dynamic styling.",
max_length=255,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("deleted_at", models.DateTimeField(blank=True, null=True)),
@ -470,6 +490,15 @@ class Migration(migrations.Migration):
max_length=32,
),
),
(
"hex_color",
models.CharField(
blank=True,
help_text="The hex color code associated with this card set.",
max_length=9,
null=True,
),
),
(
"master",
parler.fields.TranslationsForeignKey(