diff --git a/.gitignore b/.gitignore index e69de29..b9cbfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,58 @@ +# OS +.DS_Store +Thumbs.db +desktop.ini +$RECYCLE.BIN/ + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log + +# Node +node_modules/ +dist/ +build/ +out/ +coverage/ +.nyc_output/ + +# Environment +.env +.env.*.local + +# IDEs and editors +.vscode/ +.idea/ +*.sublime-workspace +*.sublime-project +*.code-workspace + +# Package managers +package-lock.json +.pnpm-store/ +# (keep yarn.lock if you rely on it; remove above line to keep package-lock.json in repo) + +# Python +__pycache__/ +*.py[cod] +venv/ +ENV/ +env/ + +# Java / JVM +target/ +*.class +*.jar +*.war +*.ear +*.iml + +# Misc +*.sqlite +*.db +*.swp +*~ \ No newline at end of file diff --git a/cards/admin.py b/cards/admin.py index cde885f..e804f4c 100644 --- a/cards/admin.py +++ b/cards/admin.py @@ -1,8 +1,15 @@ from django.contrib import admin -from .models import Dinosaur +from .models import Dinosaur, BackgroundImage @admin.register(Dinosaur) class DinosaurAdmin(admin.ModelAdmin): list_display = ('name', 'era', 'diet', 'speed', 'weight', 'intelligence') search_fields = ('name', 'era', 'diet') + + +@admin.register(BackgroundImage) +class BackgroundImageAdmin(admin.ModelAdmin): + list_display = ('__str__', 'is_active', 'uploaded_at') + list_filter = ('is_active',) + search_fields = ('title',) diff --git a/cards/migrations/0002_backgroundimage.py b/cards/migrations/0002_backgroundimage.py new file mode 100644 index 0000000..154f8c5 --- /dev/null +++ b/cards/migrations/0002_backgroundimage.py @@ -0,0 +1,26 @@ +# Generated by Django 6.0 on 2025-12-04 22:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cards', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='BackgroundImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(blank=True, max_length=200)), + ('image', models.ImageField(upload_to='backgrounds/')), + ('is_active', models.BooleanField(default=False, help_text='Mark as the active background')), + ('uploaded_at', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'ordering': ['-is_active', '-uploaded_at'], + }, + ), + ] diff --git a/cards/models.py b/cards/models.py index 23ed797..f63bc37 100644 --- a/cards/models.py +++ b/cards/models.py @@ -33,3 +33,29 @@ class Dinosaur(models.Model): def __str__(self): return self.name + + +class BackgroundImage(models.Model): + """Background images used behind card renders. + + Admins can upload multiple backgrounds and mark one as active. Templates + will use BackgroundImage.get_active() to obtain the active background. + """ + title = models.CharField(max_length=200, blank=True) + image = models.ImageField(upload_to='backgrounds/') + is_active = models.BooleanField(default=False, help_text='Mark as the active background') + uploaded_at = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ['-is_active', '-uploaded_at'] + + def __str__(self): + return self.title or f"Background #{self.pk}" + + @classmethod + def get_active(cls): + """Return the active BackgroundImage if set, otherwise the most recent one or None.""" + active = cls.objects.filter(is_active=True).order_by('-uploaded_at').first() + if active: + return active + return cls.objects.order_by('-uploaded_at').first() diff --git a/cards/templates/cards/_card_item.html b/cards/templates/cards/_card_item.html index 270086a..2889389 100644 --- a/cards/templates/cards/_card_item.html +++ b/cards/templates/cards/_card_item.html @@ -1,4 +1,5 @@ -
+

{{ card.name }}

@@ -20,4 +21,9 @@
+ {% if card.image %} +
+ {{ card.name }} +
+ {% endif %}
diff --git a/cards/templates/cards/_cards_list.html b/cards/templates/cards/_cards_list.html index a6252c0..b2d249a 100644 --- a/cards/templates/cards/_cards_list.html +++ b/cards/templates/cards/_cards_list.html @@ -2,7 +2,7 @@
{% for card in cards %}
- {% include 'cards/_card_item.html' with card=card %} + {% include 'cards/_card_item.html' with card=card background=background %}
{% empty %}
No dinosaurs yet — add one!
diff --git a/cards/templates/cards/base.html b/cards/templates/cards/base.html index dc83a45..5b1586f 100644 --- a/cards/templates/cards/base.html +++ b/cards/templates/cards/base.html @@ -7,19 +7,71 @@
-

TopTrumps — Dinosaurs

+
+
+

TopTrumps — Dinosaurs

+
+
+
+ +
+
+
{% block content %}{% endblock %}
+ diff --git a/cards/views.py b/cards/views.py index bb76ab8..f0664ad 100644 --- a/cards/views.py +++ b/cards/views.py @@ -1,7 +1,7 @@ from django.shortcuts import render, get_object_or_404, redirect from django.http import HttpResponse, HttpResponseBadRequest from django.template.loader import render_to_string -from .models import Dinosaur +from .models import Dinosaur, BackgroundImage from .forms import DinosaurForm @@ -11,18 +11,21 @@ def is_htmx(request): def card_list(request): cards = Dinosaur.objects.all() + background = BackgroundImage.get_active() if BackgroundImage.objects.exists() else None if is_htmx(request): - return render(request, 'cards/_cards_list.html', {'cards': cards}) - return render(request, 'cards/list.html', {'cards': cards}) + return render(request, 'cards/_cards_list.html', {'cards': cards, 'background': background}) + return render(request, 'cards/list.html', {'cards': cards, 'background': background}) def card_create(request): + background = BackgroundImage.get_active() if BackgroundImage.objects.exists() else None + if request.method == 'POST': form = DinosaurForm(request.POST, request.FILES) if form.is_valid(): card = form.save() if is_htmx(request): - card_html = render_to_string('cards/_card_item.html', {'card': card}, request=request) + card_html = render_to_string('cards/_card_item.html', {'card': card, 'background': background}, request=request) # Also return an out-of-band fragment to replace/clear the form container form_html = render_to_string('cards/_form.html', {'form': DinosaurForm()}, request=request) oob = f'
{form_html}
' @@ -37,17 +40,18 @@ def card_create(request): else: form = DinosaurForm() - return render(request, 'cards/_form.html', {'form': form}) + return render(request, 'cards/_form.html', {'form': form, 'background': background}) def card_edit(request, pk): card = get_object_or_404(Dinosaur, pk=pk) + background = BackgroundImage.get_active() if BackgroundImage.objects.exists() else None if request.method == 'POST': form = DinosaurForm(request.POST, request.FILES, instance=card) if form.is_valid(): card = form.save() if is_htmx(request): - card_html = render_to_string('cards/_card_item.html', {'card': card}, request=request) + card_html = render_to_string('cards/_card_item.html', {'card': card, 'background': background}, request=request) # Clear the form container via OOB so the edit form disappears after successful save oob = '
' return HttpResponse(card_html + oob) @@ -60,7 +64,7 @@ def card_edit(request, pk): else: form = DinosaurForm(instance=card) - return render(request, 'cards/_form.html', {'form': form, 'card': card}) + return render(request, 'cards/_form.html', {'form': form, 'card': card, 'background': background}) def card_delete(request, pk): diff --git a/db.sqlite3 b/db.sqlite3 index 7bda041..eeddcfd 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/templates/cards/_card_item.html b/templates/cards/_card_item.html index 270086a..2889389 100644 --- a/templates/cards/_card_item.html +++ b/templates/cards/_card_item.html @@ -1,4 +1,5 @@ -
+

{{ card.name }}

@@ -20,4 +21,9 @@
+ {% if card.image %} +
+ {{ card.name }} +
+ {% endif %}
diff --git a/templates/cards/_cards_list.html b/templates/cards/_cards_list.html index a6252c0..b2d249a 100644 --- a/templates/cards/_cards_list.html +++ b/templates/cards/_cards_list.html @@ -2,7 +2,7 @@
{% for card in cards %}
- {% include 'cards/_card_item.html' with card=card %} + {% include 'cards/_card_item.html' with card=card background=background %}
{% empty %}
No dinosaurs yet — add one!
diff --git a/templates/cards/base.html b/templates/cards/base.html index dc83a45..5b1586f 100644 --- a/templates/cards/base.html +++ b/templates/cards/base.html @@ -7,19 +7,71 @@
-

TopTrumps — Dinosaurs

+
+
+

TopTrumps — Dinosaurs

+
+
+
+ +
+
+
{% block content %}{% endblock %}
+