This commit is contained in:
Ross
2025-12-05 12:08:08 +00:00
parent d55cd821b5
commit 78240090f1
9 changed files with 227 additions and 0 deletions
+19
View File
@@ -39,3 +39,22 @@ class BackgroundImageForm(forms.ModelForm):
'image': forms.ClearableFileInput(attrs={'class': 'file-input'}),
'is_active': forms.CheckboxInput(attrs={'class': 'checkbox'}),
}
from django.forms import modelformset_factory
# A simplified form used in the bulk edit table (only a few editable fields)
class DinosaurBulkForm(forms.ModelForm):
class Meta:
model = Dinosaur
fields = ['name', 'background', 'speed', 'weight', 'height', 'intelligence']
widgets = {
'name': forms.TextInput(attrs={'class': 'input'}),
'background': forms.Select(attrs={'class': 'input'}),
'speed': forms.NumberInput(attrs={'class': 'input', 'min': 0}),
'weight': forms.NumberInput(attrs={'class': 'input', 'min': 0}),
'height': forms.NumberInput(attrs={'class': 'input', 'step': '0.1'}),
'intelligence': forms.NumberInput(attrs={'class': 'input', 'min': 0, 'max': 100}),
}
DinosaurBulkFormSet = modelformset_factory(Dinosaur, form=DinosaurBulkForm, extra=0)
+3
View File
@@ -63,6 +63,9 @@
.background-picker .bg-option img{width:100%;height:100%;object-fit:cover;display:block;border-radius:2px}
.background-picker .bg-option.selected{outline:2px solid var(--accent);box-shadow:0 2px 6px rgba(0,0,0,0.08)}
.background-picker .bg-option[role="button"]{font-size:0.8rem;padding:6px 8px}
/* Bulk edit thumbnails */
.bulk-thumb{width:48px;height:48px;object-fit:cover;border-radius:6px;border:1px solid rgba(0,0,0,0.06);display:inline-block}
.bulk-thumb.empty{background:rgba(0,0,0,0.04);width:48px;height:48px;border-radius:6px}
.toptrump-card .title-band{background:var(--accent);color:#072027;padding:0.6rem 0.75rem;text-align:center;font-weight:700;font-size:1.05rem}
.toptrump-card .card-body{padding:0.75rem}
.toptrump-card .stat-row{display:flex;align-items:center;gap:0.75rem;padding:0.25rem 0}
+84
View File
@@ -0,0 +1,84 @@
{% extends "cards/base.html" %}
{% block content %}
<section class="section">
<div class="container">
<h2 class="title is-4">Cards overview — bulk edit</h2>
<p class="subtitle is-6">Edit multiple cards inline and save changes in one go.</p>
<form method="post" action="{% url 'cards:overview_bulk_update' %}">
{% csrf_token %}
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>Preview</th>
<th>Name</th>
<th>Background</th>
<th>Speed</th>
<th>Weight</th>
<th>Height</th>
<th>Intel</th>
<th></th>
</tr>
</thead>
<tbody>
{% if formset %}
{{ formset.management_form }}
{% for form in formset.forms %}
<tr>
<td>
{% if form.instance.image %}
<img class="bulk-thumb" src="{{ form.instance.image.url }}" alt="{{ form.instance.name }}">
{% else %}
<div class="bulk-thumb empty"></div>
{% endif %}
</td>
<td>{{ form.name }}</td>
<td>{{ form.background }}</td>
<td style="width:90px">{{ form.speed }}</td>
<td style="width:90px">{{ form.weight }}</td>
<td style="width:90px">{{ form.height }}</td>
<td style="width:90px">{{ form.intelligence }}</td>
<td style="width:90px">ID: {{ form.instance.pk }}</td>
</tr>
{% endfor %}
{% else %}
{% for card in cards %}
<tr>
<td>
{% if card.image %}
<img class="bulk-thumb" src="{{ card.image.url }}" alt="{{ card.name }}">
{% else %}
<div class="bulk-thumb empty"></div>
{% endif %}
</td>
<td><input class="input" name="name-{{ card.pk }}" value="{{ card.name }}"></td>
<td>
<div class="select"><select name="background-{{ card.pk }}">
<option value="">Site default</option>
{% for bg in backgrounds %}
<option value="{{ bg.pk }}"{% if card.background and card.background.pk == bg.pk %} selected{% endif %}>{{ bg.title|default:'Background' }}</option>
{% endfor %}
</select></div>
</td>
<td><input class="input" name="speed-{{ card.pk }}" value="{{ card.speed }}"></td>
<td><input class="input" name="weight-{{ card.pk }}" value="{{ card.weight }}"></td>
<td><input class="input" name="height-{{ card.pk }}" value="{{ card.height }}"></td>
<td><input class="input" name="intelligence-{{ card.pk }}" value="{{ card.intelligence }}"></td>
<td>ID: {{ card.pk }}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
<div class="field">
<div class="control">
<button class="button is-primary" type="submit">Save changes</button>
<a class="button is-light" href="{% url 'cards:list' %}">Back to list</a>
</div>
</div>
</form>
</div>
</section>
{% endblock %}
+3
View File
@@ -9,6 +9,9 @@
<div class="level-item">
<a class="button is-light" href="{% url 'cards:backgrounds' %}">Manage backgrounds</a>
</div>
<div class="level-item">
<a class="button is-light" href="{% url 'cards:overview' %}">Bulk edit</a>
</div>
</div>
</div>
+2
View File
@@ -13,4 +13,6 @@ urlpatterns = [
path('backgrounds/create/', views.background_create, name='background_create'),
path('backgrounds/<int:pk>/activate/', views.background_activate, name='background_activate'),
path('backgrounds/<int:pk>/delete/', views.background_delete, name='background_delete'),
path('overview/', views.cards_overview, name='overview'),
path('overview/bulk-update/', views.cards_bulk_update, name='overview_bulk_update'),
]
+26
View File
@@ -2,6 +2,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, BackgroundImage
from .forms import DinosaurBulkFormSet
from .forms import DinosaurForm
from .forms import BackgroundImageForm
@@ -143,3 +144,28 @@ def preview_card(request, pk):
if is_htmx(request):
return render(request, 'cards/_card_preview.html', {'card': card, 'background': background})
return render(request, 'cards/preview.html', {'card': card, 'background': background})
def cards_overview(request):
"""Overview page showing all cards in a table for quick edits."""
backgrounds = BackgroundImage.objects.all()
qs = Dinosaur.objects.order_by('name')
formset = None
return render(request, 'cards/bulk_edit.html', {'cards': qs, 'backgrounds': backgrounds})
def cards_bulk_update(request):
"""Handle POST from the bulk edit formset and save changes."""
if request.method != 'POST':
return HttpResponseBadRequest('Only POST allowed')
formset = None
try:
formset = DinosaurBulkFormSet(request.POST)
except Exception:
return HttpResponseBadRequest('Invalid submission')
if formset.is_valid():
formset.save()
return redirect('cards:overview')
# If invalid, re-render the overview with errors
backgrounds = BackgroundImage.objects.all()
return render(request, 'cards/bulk_edit.html', {'formset': formset, 'backgrounds': backgrounds})
+3
View File
@@ -56,6 +56,9 @@
.background-picker .bg-option img{max-width:100%;max-height:100%;display:block;border-radius:2px}
.background-picker .bg-option.selected{outline:2px solid var(--accent);box-shadow:0 2px 6px rgba(0,0,0,0.08)}
.background-picker .bg-option[role="button"]{font-size:0.8rem;padding:6px 8px}
/* Bulk edit thumbnails */
.bulk-thumb{width:48px;height:48px;object-fit:cover;border-radius:6px;border:1px solid rgba(0,0,0,0.06);display:inline-block}
.bulk-thumb.empty{background:rgba(0,0,0,0.04);width:48px;height:48px;border-radius:6px}
.toptrump-card .title-band{background:var(--accent);color:#072027;padding:0.6rem 0.75rem;text-align:center;font-weight:700;font-size:1.05rem}
.toptrump-card .card-body{padding:0.75rem}
.toptrump-card .stat-row{display:flex;align-items:center;gap:0.75rem;padding:0.25rem 0}
+84
View File
@@ -0,0 +1,84 @@
{% extends "cards/base.html" %}
{% block content %}
<section class="section">
<div class="container">
<h2 class="title is-4">Cards overview — bulk edit</h2>
<p class="subtitle is-6">Edit multiple cards inline and save changes in one go.</p>
<form method="post" action="{% url 'cards:overview_bulk_update' %}">
{% csrf_token %}
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>Preview</th>
<th>Name</th>
<th>Background</th>
<th>Speed</th>
<th>Weight</th>
<th>Height</th>
<th>Intel</th>
<th></th>
</tr>
</thead>
<tbody>
{% if formset %}
{{ formset.management_form }}
{% for form in formset.forms %}
<tr>
<td>
{% if form.instance.image %}
<img class="bulk-thumb" src="{{ form.instance.image.url }}" alt="{{ form.instance.name }}">
{% else %}
<div class="bulk-thumb empty"></div>
{% endif %}
</td>
<td>{{ form.name }}</td>
<td>{{ form.background }}</td>
<td style="width:90px">{{ form.speed }}</td>
<td style="width:90px">{{ form.weight }}</td>
<td style="width:90px">{{ form.height }}</td>
<td style="width:90px">{{ form.intelligence }}</td>
<td style="width:90px">ID: {{ form.instance.pk }}</td>
</tr>
{% endfor %}
{% else %}
{% for card in cards %}
<tr>
<td>
{% if card.image %}
<img class="bulk-thumb" src="{{ card.image.url }}" alt="{{ card.name }}">
{% else %}
<div class="bulk-thumb empty"></div>
{% endif %}
</td>
<td><input class="input" name="name-{{ card.pk }}" value="{{ card.name }}"></td>
<td>
<div class="select"><select name="background-{{ card.pk }}">
<option value="">Site default</option>
{% for bg in backgrounds %}
<option value="{{ bg.pk }}"{% if card.background and card.background.pk == bg.pk %} selected{% endif %}>{{ bg.title|default:'Background' }}</option>
{% endfor %}
</select></div>
</td>
<td><input class="input" name="speed-{{ card.pk }}" value="{{ card.speed }}"></td>
<td><input class="input" name="weight-{{ card.pk }}" value="{{ card.weight }}"></td>
<td><input class="input" name="height-{{ card.pk }}" value="{{ card.height }}"></td>
<td><input class="input" name="intelligence-{{ card.pk }}" value="{{ card.intelligence }}"></td>
<td>ID: {{ card.pk }}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
<div class="field">
<div class="control">
<button class="button is-primary" type="submit">Save changes</button>
<a class="button is-light" href="{% url 'cards:list' %}">Back to list</a>
</div>
</div>
</form>
</div>
</section>
{% endblock %}
+3
View File
@@ -9,6 +9,9 @@
<div class="level-item">
<a class="button is-light" href="{% url 'cards:backgrounds' %}">Manage backgrounds</a>
</div>
<div class="level-item">
<a class="button is-light" href="{% url 'cards:overview' %}">Bulk edit</a>
</div>
</div>
</div>