From befa61e1e99473cbd43c2f42b246a5407ba7e5d5 Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Tue, 24 Mar 2026 22:25:25 -0400 Subject: [PATCH] several fixes, incl. location of templates/apps/epic/tarot_deck.html to apps/gameboard/tarot_deck.html; added this convention to CLAUDE.md; Game Kit applet items now plentiful enough to bother w. text wrapping in _gameboard.scss; unlocked_decks differentiates from equipped_deck in apps.lyric.models; new migrations accordingly; apps.gameboard.views accounts for only unlocked_decks in deck_variants now; apps.epic.views redirected to new tarot_deck.html location --- CLAUDE.md | 8 ++++++++ src/apps/epic/views.py | 4 ++-- src/apps/gameboard/views.py | 4 ++-- .../migrations/0015_user_unlocked_decks.py | 19 +++++++++++++++++++ src/apps/lyric/models.py | 5 +++++ src/static_src/scss/_gameboard.scss | 4 +++- .../apps/{epic => gameboard}/tarot_deck.html | 0 7 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/apps/lyric/migrations/0015_user_unlocked_decks.py rename src/templates/apps/{epic => gameboard}/tarot_deck.html (100%) diff --git a/CLAUDE.md b/CLAUDE.md index 1b13422..830275b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -73,6 +73,14 @@ src/ functional_tests/ ``` +### Template directory convention +Templates live under `templates/apps//`, not under the backend app that owns the view logic. Specifically: +- `lyric/` views → `templates/apps/dashboard/` +- `epic/` views → `templates/apps/gameboard/` +- `drama/` views → `templates/apps/billboard/` + +Backend apps (`lyric`, `epic`, `drama`) have **no** `templates/` subdirectory. + ## Dev Commands ```bash # Dev server (ASGI — required for WebSockets; no npm/webpack build step) diff --git a/src/apps/epic/views.py b/src/apps/epic/views.py index 0b80075..a8cd006 100644 --- a/src/apps/epic/views.py +++ b/src/apps/epic/views.py @@ -476,7 +476,7 @@ def tarot_deck(request, room_id): room=room, defaults={"deck_variant": deck_variant}, ) - return render(request, "apps/epic/tarot_deck.html", { + return render(request, "apps/gameboard/tarot_deck.html", { "room": room, "deck": deck, "remaining": deck.remaining_count, @@ -499,7 +499,7 @@ def tarot_deal(request, room_id): } for i, (card, is_reversed) in enumerate(drawn) ] - return render(request, "apps/epic/tarot_deck.html", { + return render(request, "apps/gameboard/tarot_deck.html", { "room": room, "deck": deck, "remaining": deck.remaining_count, diff --git a/src/apps/gameboard/views.py b/src/apps/gameboard/views.py index 1f9acc8..8cd59d0 100644 --- a/src/apps/gameboard/views.py +++ b/src/apps/gameboard/views.py @@ -32,7 +32,7 @@ def gameboard(request): "carte": carte, "equipped_trinket_id": str(request.user.equipped_trinket_id or ""), "equipped_deck_id": str(request.user.equipped_deck_id or ""), - "deck_variants": list(DeckVariant.objects.all()), + "deck_variants": list(request.user.unlocked_decks.all()), "free_tokens": free_tokens, "free_count": len(free_tokens), "applets": applet_context(request.user, "gameboard"), @@ -62,7 +62,7 @@ def toggle_game_applets(request): "carte": request.user.tokens.filter(token_type=Token.CARTE).first(), "equipped_trinket_id": str(request.user.equipped_trinket_id or ""), "equipped_deck_id": str(request.user.equipped_deck_id or ""), - "deck_variants": list(DeckVariant.objects.all()), + "deck_variants": list(request.user.unlocked_decks.all()), "free_tokens": list(request.user.tokens.filter( token_type=Token.FREE, expires_at__gt=timezone.now() ).order_by("expires_at")), diff --git a/src/apps/lyric/migrations/0015_user_unlocked_decks.py b/src/apps/lyric/migrations/0015_user_unlocked_decks.py new file mode 100644 index 0000000..be20c1f --- /dev/null +++ b/src/apps/lyric/migrations/0015_user_unlocked_decks.py @@ -0,0 +1,19 @@ +# Generated by Django 6.0 on 2026-03-25 02:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('epic', '0010_seed_deck_variants_and_earthman'), + ('lyric', '0014_user_equipped_deck'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='unlocked_decks', + field=models.ManyToManyField(blank=True, related_name='unlocked_by', to='epic.deckvariant'), + ), + ] diff --git a/src/apps/lyric/models.py b/src/apps/lyric/models.py index d04c0a1..eafd52c 100644 --- a/src/apps/lyric/models.py +++ b/src/apps/lyric/models.py @@ -41,6 +41,9 @@ class User(AbstractBaseUser): "epic.DeckVariant", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) + unlocked_decks = models.ManyToManyField( + "epic.DeckVariant", blank=True, related_name="unlocked_by", + ) is_staff = models.BooleanField(default=False) is_superuser = models.BooleanField(default=False) @@ -175,3 +178,5 @@ def create_wallet_and_tokens(sender, instance, created, **kwargs): earthman = DeckVariant.objects.filter(slug="earthman").first() instance.equipped_deck = earthman instance.save(update_fields=['equipped_trinket', 'equipped_deck']) + if earthman: + instance.unlocked_decks.add(earthman) diff --git a/src/static_src/scss/_gameboard.scss b/src/static_src/scss/_gameboard.scss index f0ff858..2e511a2 100644 --- a/src/static_src/scss/_gameboard.scss +++ b/src/static_src/scss/_gameboard.scss @@ -68,8 +68,10 @@ body.page-gameboard { position: relative; display: flex; flex-direction: row; + flex-wrap: wrap; align-items: center; - justify-content: space-evenly; + justify-content: center; + gap: 0.75rem; overflow-x: visible; scrollbar-width: none; &::-webkit-scrollbar { display: none; } diff --git a/src/templates/apps/epic/tarot_deck.html b/src/templates/apps/gameboard/tarot_deck.html similarity index 100% rename from src/templates/apps/epic/tarot_deck.html rename to src/templates/apps/gameboard/tarot_deck.html