adminita 0.1.7__py3-none-any.whl → 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adminita/static/adminita/action-fix.css +95 -0
- adminita/static/adminita/adminita-tailwind.css +1 -1
- adminita/static/src/input.css +47 -0
- adminita/templates/admin/actions.html +22 -0
- adminita/templates/admin/base.html +1 -0
- adminita/templates/admin/change_form.html +2 -60
- adminita/templates/admin/change_list.html +259 -131
- adminita/templates/admin/change_list_results.html +45 -0
- adminita/templates/admin/edit_inline/stacked.html +2 -4
- adminita/templates/admin/edit_inline/tabular.html +24 -70
- adminita/templates/admin/filter.html +28 -0
- adminita/templates/admin/includes/fieldset.html +79 -0
- adminita/templatetags/__init__.py +0 -0
- adminita/templatetags/adminita_tags.py +53 -0
- {adminita-0.1.7.dist-info → adminita-0.1.9.dist-info}/METADATA +36 -5
- adminita-0.1.9.dist-info/RECORD +36 -0
- adminita-0.1.7.dist-info/RECORD +0 -29
- {adminita-0.1.7.dist-info → adminita-0.1.9.dist-info}/WHEEL +0 -0
- /adminita-0.1.7.dist-info/licenses/LICENSE → /adminita-0.1.9.dist-info/licenses/LICENSE.md +0 -0
- {adminita-0.1.7.dist-info → adminita-0.1.9.dist-info}/top_level.txt +0 -0
|
@@ -12,168 +12,295 @@
|
|
|
12
12
|
{% block extrastyle %}
|
|
13
13
|
{{ block.super }}
|
|
14
14
|
{{ media.css }}
|
|
15
|
-
|
|
15
|
+
<style>
|
|
16
|
+
/* Actions bar styling for Adminita */
|
|
17
|
+
#changelist-form .actions {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: 0.75rem;
|
|
21
|
+
padding: 0.75rem 1.5rem;
|
|
22
|
+
border-bottom: 1px solid rgb(229, 231, 235);
|
|
23
|
+
background-color: rgb(249, 250, 251);
|
|
24
|
+
}
|
|
25
|
+
.dark #changelist-form .actions {
|
|
26
|
+
border-color: rgb(55, 65, 81);
|
|
27
|
+
background-color: rgb(31, 41, 55);
|
|
28
|
+
}
|
|
29
|
+
#changelist-form .actions label {
|
|
30
|
+
font-size: 0.875rem;
|
|
31
|
+
color: rgb(55, 65, 81);
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: 0.5rem;
|
|
35
|
+
}
|
|
36
|
+
.dark #changelist-form .actions label {
|
|
37
|
+
color: rgb(209, 213, 219);
|
|
38
|
+
}
|
|
39
|
+
#changelist-form .actions select {
|
|
40
|
+
padding: 0.5rem 2rem 0.5rem 0.75rem;
|
|
41
|
+
border: 1px solid rgb(209, 213, 219);
|
|
42
|
+
border-radius: 0.5rem;
|
|
43
|
+
background-color: white;
|
|
44
|
+
font-size: 0.875rem;
|
|
45
|
+
color: rgb(17, 24, 39);
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
appearance: none;
|
|
48
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
49
|
+
background-position: right 0.5rem center;
|
|
50
|
+
background-repeat: no-repeat;
|
|
51
|
+
background-size: 1.25rem;
|
|
52
|
+
}
|
|
53
|
+
.dark #changelist-form .actions select {
|
|
54
|
+
border-color: rgb(75, 85, 99);
|
|
55
|
+
background-color: rgb(55, 65, 81);
|
|
56
|
+
color: rgb(243, 244, 246);
|
|
57
|
+
}
|
|
58
|
+
#changelist-form .actions select:focus {
|
|
59
|
+
outline: none;
|
|
60
|
+
border-color: rgb(59, 130, 246);
|
|
61
|
+
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
|
|
62
|
+
}
|
|
63
|
+
#changelist-form .actions button {
|
|
64
|
+
padding: 0.5rem 1rem;
|
|
65
|
+
background-color: rgb(75, 85, 99);
|
|
66
|
+
color: white;
|
|
67
|
+
border: none;
|
|
68
|
+
border-radius: 0.5rem;
|
|
69
|
+
font-size: 0.875rem;
|
|
70
|
+
font-weight: 500;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
transition: background-color 0.15s;
|
|
73
|
+
}
|
|
74
|
+
#changelist-form .actions button:hover {
|
|
75
|
+
background-color: rgb(55, 65, 81);
|
|
76
|
+
}
|
|
77
|
+
#changelist-form .actions .action-counter {
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
color: rgb(107, 114, 128);
|
|
80
|
+
margin-left: 0.5rem;
|
|
81
|
+
}
|
|
82
|
+
.dark #changelist-form .actions .action-counter {
|
|
83
|
+
color: rgb(156, 163, 175);
|
|
84
|
+
}
|
|
85
|
+
#changelist-form .actions span.all,
|
|
86
|
+
#changelist-form .actions span.clear {
|
|
87
|
+
font-size: 0.875rem;
|
|
88
|
+
color: rgb(59, 130, 246);
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
margin-left: 0.25rem;
|
|
91
|
+
}
|
|
92
|
+
#changelist-form .actions span.all:hover,
|
|
93
|
+
#changelist-form .actions span.clear:hover {
|
|
94
|
+
text-decoration: underline;
|
|
95
|
+
}
|
|
96
|
+
#changelist-form .actions span.question {
|
|
97
|
+
font-size: 0.875rem;
|
|
98
|
+
color: rgb(107, 114, 128);
|
|
99
|
+
margin-left: 0.5rem;
|
|
100
|
+
}
|
|
101
|
+
#changelist-form .actions span.question a {
|
|
102
|
+
color: rgb(59, 130, 246);
|
|
103
|
+
}
|
|
104
|
+
.dark #changelist-form .actions span.question {
|
|
105
|
+
color: rgb(156, 163, 175);
|
|
106
|
+
}
|
|
107
|
+
.hidden { display: none !important; }
|
|
108
|
+
|
|
109
|
+
/* Table styling */
|
|
110
|
+
#result_list table td {
|
|
111
|
+
padding: 0.75rem 1.5rem;
|
|
112
|
+
font-size: 0.875rem;
|
|
113
|
+
color: rgb(55, 65, 81);
|
|
114
|
+
vertical-align: middle;
|
|
115
|
+
}
|
|
116
|
+
.dark #result_list table td {
|
|
117
|
+
color: rgb(209, 213, 219);
|
|
118
|
+
}
|
|
119
|
+
#result_list table td a {
|
|
120
|
+
color: rgb(37, 99, 235);
|
|
121
|
+
text-decoration: none;
|
|
122
|
+
}
|
|
123
|
+
#result_list table td a:hover {
|
|
124
|
+
text-decoration: underline;
|
|
125
|
+
}
|
|
126
|
+
.dark #result_list table td a {
|
|
127
|
+
color: rgb(96, 165, 250);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Checkbox column styling */
|
|
131
|
+
.action-checkbox-column {
|
|
132
|
+
width: 2rem;
|
|
133
|
+
padding: 0.75rem 1rem !important;
|
|
134
|
+
}
|
|
135
|
+
td.action-checkbox {
|
|
136
|
+
padding: 0.75rem 1rem !important;
|
|
137
|
+
width: 2rem;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Checkbox styling */
|
|
141
|
+
#action-toggle,
|
|
142
|
+
.action-select {
|
|
143
|
+
width: 1rem;
|
|
144
|
+
height: 1rem;
|
|
145
|
+
border-radius: 0.25rem;
|
|
146
|
+
border: 1px solid rgb(209, 213, 219);
|
|
147
|
+
background-color: white;
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
accent-color: rgb(59, 130, 246);
|
|
150
|
+
}
|
|
151
|
+
.dark #action-toggle,
|
|
152
|
+
.dark .action-select {
|
|
153
|
+
border-color: rgb(75, 85, 99);
|
|
154
|
+
background-color: rgb(55, 65, 81);
|
|
155
|
+
}
|
|
156
|
+
#action-toggle:checked,
|
|
157
|
+
.action-select:checked {
|
|
158
|
+
background-color: rgb(59, 130, 246);
|
|
159
|
+
border-color: rgb(59, 130, 246);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Selected row highlight */
|
|
163
|
+
tr.selected {
|
|
164
|
+
background-color: rgb(239, 246, 255) !important;
|
|
165
|
+
}
|
|
166
|
+
.dark tr.selected {
|
|
167
|
+
background-color: rgba(59, 130, 246, 0.1) !important;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Field-specific styling (list_display fields) */
|
|
171
|
+
td[class^="field-"] {
|
|
172
|
+
white-space: nowrap;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Boolean field icons */
|
|
176
|
+
td img[alt="True"], td img[alt="False"] {
|
|
177
|
+
width: 1rem;
|
|
178
|
+
height: 1rem;
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
16
181
|
{% endblock %}
|
|
17
182
|
|
|
18
183
|
{% block content %}
|
|
19
|
-
<div class="flex gap-6">
|
|
184
|
+
<div id="changelist" class="module flex gap-6">
|
|
20
185
|
|
|
21
186
|
<!-- MAIN CONTENT AREA -->
|
|
22
187
|
<div class="flex-1">
|
|
23
188
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
|
24
189
|
|
|
25
|
-
<!-- Toolbar -->
|
|
190
|
+
<!-- Toolbar: Search + Add -->
|
|
26
191
|
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex flex-wrap items-center justify-between gap-4">
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
39
|
-
<svg class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
40
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
|
41
|
-
</svg>
|
|
42
|
-
</div>
|
|
43
|
-
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors">
|
|
44
|
-
{% trans 'Search' %}
|
|
45
|
-
</button>
|
|
46
|
-
</form>
|
|
47
|
-
{% endif %}
|
|
48
|
-
{% endblock %}
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<!-- Actions -->
|
|
52
|
-
<div class="flex items-center space-x-3">
|
|
53
|
-
{% block object-tools %}
|
|
54
|
-
{% if has_add_permission %}
|
|
55
|
-
<a href="{% url cl.opts|admin_urlname:'add' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors">
|
|
56
|
-
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
57
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
|
|
192
|
+
{% block search %}
|
|
193
|
+
{% if cl.search_fields %}
|
|
194
|
+
<form id="changelist-search" method="get" class="flex items-center space-x-2 flex-1 min-w-[300px]">
|
|
195
|
+
<div class="relative flex-1">
|
|
196
|
+
<input type="search"
|
|
197
|
+
name="q"
|
|
198
|
+
value="{{ cl.query }}"
|
|
199
|
+
placeholder="{% trans 'Search' %}"
|
|
200
|
+
class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
201
|
+
<svg class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
202
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
|
58
203
|
</svg>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<!-- Results -->
|
|
67
|
-
<form id="changelist-form" method="post"{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>
|
|
68
|
-
{% csrf_token %}
|
|
69
|
-
{% if cl.formset %}{{ cl.formset.management_form }}{% endif %}
|
|
70
|
-
<!-- Actions Bar -->
|
|
71
|
-
{% if action_form and cl.show_admin_actions %}
|
|
72
|
-
<div class="actions px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex items-center gap-3">
|
|
73
|
-
<label class="text-sm text-gray-700 dark:text-gray-300">{% trans "Action:" %}</label>
|
|
74
|
-
<select name="action" class="text-sm">
|
|
75
|
-
<option value="">---------</option>
|
|
76
|
-
{% for action in action_form.fields.action.choices %}
|
|
77
|
-
{% if action.0 %}
|
|
78
|
-
<option value="{{ action.0 }}">{{ action.1 }}</option>
|
|
204
|
+
</div>
|
|
205
|
+
{% for key, value in cl.params.items %}
|
|
206
|
+
{% if key != 'q' and key != 'p' %}
|
|
207
|
+
<input type="hidden" name="{{ key }}" value="{{ value }}">
|
|
79
208
|
{% endif %}
|
|
80
209
|
{% endfor %}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
</
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{%
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
{% else %}
|
|
94
|
-
<div class="px-6 py-12 text-center">
|
|
95
|
-
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
96
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
97
|
-
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
|
|
210
|
+
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors">
|
|
211
|
+
{% trans 'Search' %}
|
|
212
|
+
</button>
|
|
213
|
+
</form>
|
|
214
|
+
{% endif %}
|
|
215
|
+
{% endblock %}
|
|
216
|
+
|
|
217
|
+
{% block object-tools %}
|
|
218
|
+
{% if has_add_permission %}
|
|
219
|
+
<a href="{% url cl.opts|admin_urlname:'add' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors">
|
|
220
|
+
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
221
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
|
|
98
222
|
</svg>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
</p>
|
|
102
|
-
</div>
|
|
223
|
+
{% trans 'Add' %} {{ cl.opts.verbose_name }}
|
|
224
|
+
</a>
|
|
103
225
|
{% endif %}
|
|
104
226
|
{% endblock %}
|
|
105
227
|
</div>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
228
|
+
|
|
229
|
+
<!-- Main Form: Actions + Results + Save -->
|
|
230
|
+
<form id="changelist-form" method="post" action=""{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>
|
|
231
|
+
{% csrf_token %}
|
|
232
|
+
|
|
233
|
+
<!-- Actions Bar - Using Django's built-in template tag -->
|
|
234
|
+
{% if action_form and actions_on_top %}
|
|
235
|
+
{% admin_actions %}
|
|
114
236
|
{% endif %}
|
|
115
|
-
</form>
|
|
116
237
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<div class="
|
|
121
|
-
{% if cl.result_count
|
|
122
|
-
|
|
238
|
+
{% if cl.formset %}{{ cl.formset.management_form }}{% endif %}
|
|
239
|
+
|
|
240
|
+
{# Results #}
|
|
241
|
+
<div id="result_list" class="overflow-x-auto">
|
|
242
|
+
{% if cl.result_count %}
|
|
243
|
+
{% result_list cl %}
|
|
123
244
|
{% else %}
|
|
124
|
-
|
|
245
|
+
<div class="p-12 text-center">
|
|
246
|
+
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
247
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M12 2a10 10 0 100 20 10 10 0 000-20z"/>
|
|
248
|
+
</svg>
|
|
249
|
+
<p class="mt-4 text-lg font-medium text-gray-900 dark:text-gray-100">{% trans 'No results found' %}</p>
|
|
250
|
+
{% if cl.query %}<p class="mt-2 text-sm text-gray-500">{% blocktrans with query=cl.query %}No matches for "{{ query }}"{% endblocktrans %}</p>{% endif %}
|
|
251
|
+
<a href="?" class="mt-4 inline-flex items-center text-sm text-blue-600 hover:underline">
|
|
252
|
+
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
|
|
253
|
+
{% trans 'Clear all filters' %}
|
|
254
|
+
</a>
|
|
255
|
+
</div>
|
|
125
256
|
{% endif %}
|
|
126
257
|
</div>
|
|
127
258
|
|
|
128
|
-
{
|
|
129
|
-
{% if
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<a href="?{% if cl.is_popup %}_popup=1&{% endif %}all="
|
|
133
|
-
class="px-3 py-1 text-sm text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
|
134
|
-
{% trans 'Show all' %}
|
|
135
|
-
</a>
|
|
136
|
-
{% endif %}
|
|
137
|
-
|
|
138
|
-
{% if cl.multi_page %}
|
|
139
|
-
<nav class="flex items-center space-x-1">
|
|
140
|
-
{% if cl.page_num > 0 %}
|
|
141
|
-
<a href="?p={{ cl.page_num|add:'-1' }}"
|
|
142
|
-
class="px-3 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
143
|
-
{% trans 'Previous' %}
|
|
144
|
-
</a>
|
|
145
|
-
{% endif %}
|
|
259
|
+
{# Actions at bottom too - standard Django behavior #}
|
|
260
|
+
{% if action_form and actions_on_bottom %}
|
|
261
|
+
{% admin_actions %}
|
|
262
|
+
{% endif %}
|
|
146
263
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
264
|
+
{# Save for list_editable #}
|
|
265
|
+
{% if cl.formset and cl.result_count %}
|
|
266
|
+
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end">
|
|
267
|
+
<input type="submit" name="_save" value="{% translate 'Save' %}" class="px-6 py-2.5 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium cursor-pointer">
|
|
268
|
+
</div>
|
|
269
|
+
{% endif %}
|
|
270
|
+
</form>
|
|
152
271
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
272
|
+
{# Pagination #}
|
|
273
|
+
{% block pagination %}
|
|
274
|
+
{% if cl.result_count %}
|
|
275
|
+
<div class="px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
|
276
|
+
<span class="text-sm text-gray-700 dark:text-gray-300">
|
|
277
|
+
{{ cl.result_count }} {{ cl.opts.verbose_name_plural }}
|
|
278
|
+
</span>
|
|
279
|
+
{% if cl.multi_page %}
|
|
280
|
+
<nav class="flex items-center space-x-1">
|
|
281
|
+
{% if cl.page_num > 0 %}
|
|
282
|
+
<a href="?{% for k,v in cl.params.items %}{% if k != 'p' %}{{ k }}={{ v }}&{% endif %}{% endfor %}p={{ cl.page_num|add:'-1' }}" class="px-3 py-1 text-sm border rounded hover:bg-gray-50 dark:hover:bg-gray-700">{% trans 'Previous' %}</a>
|
|
160
283
|
{% endif %}
|
|
161
|
-
|
|
284
|
+
<span class="px-3 py-1 text-sm">{% blocktrans with page=cl.page_num|add:1 pages=cl.paginator.num_pages %}{{ page }}/{{ pages }}{% endblocktrans %}</span>
|
|
285
|
+
{% if cl.page_num < cl.paginator.num_pages|add:"-1" %}
|
|
286
|
+
<a href="?{% for k,v in cl.params.items %}{% if k != 'p' %}{{ k }}={{ v }}&{% endif %}{% endfor %}p={{ cl.page_num|add:1 }}" class="px-3 py-1 text-sm border rounded hover:bg-gray-50 dark:hover:bg-gray-700">{% trans 'Next' %}</a>
|
|
287
|
+
{% endif %}
|
|
288
|
+
</nav>
|
|
162
289
|
{% endif %}
|
|
163
|
-
{% endblock %}
|
|
164
290
|
</div>
|
|
165
291
|
{% endif %}
|
|
292
|
+
{% endblock %}
|
|
166
293
|
</div>
|
|
167
294
|
</div>
|
|
168
295
|
|
|
169
|
-
|
|
296
|
+
{# FILTER SIDEBAR #}
|
|
297
|
+
{% block filters %}
|
|
170
298
|
{% if cl.has_filters %}
|
|
171
|
-
<
|
|
299
|
+
<aside class="w-64 flex-shrink-0" id="changelist-filter">
|
|
172
300
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 sticky top-20">
|
|
173
|
-
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750">
|
|
174
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-white uppercase tracking-wider">
|
|
175
|
-
|
|
176
|
-
</h3>
|
|
301
|
+
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750 flex items-center justify-between">
|
|
302
|
+
<h3 class="text-sm font-semibold text-gray-900 dark:text-white uppercase tracking-wider">{% trans 'Filter' %}</h3>
|
|
303
|
+
<a href="?" class="text-xs text-blue-600 dark:text-blue-400 hover:underline">{% trans 'Clear' %}</a>
|
|
177
304
|
</div>
|
|
178
305
|
<div class="p-4 space-y-4">
|
|
179
306
|
{% for spec in cl.filter_specs %}
|
|
@@ -181,8 +308,9 @@
|
|
|
181
308
|
{% endfor %}
|
|
182
309
|
</div>
|
|
183
310
|
</div>
|
|
184
|
-
</
|
|
311
|
+
</aside>
|
|
185
312
|
{% endif %}
|
|
313
|
+
{% endblock %}
|
|
186
314
|
|
|
187
315
|
</div>
|
|
188
316
|
{% endblock %}
|
|
@@ -190,4 +318,4 @@
|
|
|
190
318
|
{% block extrajs %}
|
|
191
319
|
{{ block.super }}
|
|
192
320
|
{{ media.js }}
|
|
193
|
-
{% endblock %}
|
|
321
|
+
{% endblock %}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{% load i18n admin_list %}
|
|
2
|
+
|
|
3
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
|
+
<thead class="bg-gray-50 dark:bg-gray-750">
|
|
5
|
+
<tr>
|
|
6
|
+
{% if result_hidden_fields %}
|
|
7
|
+
<td class="hidden">{% for item in result_hidden_fields %}{{ item }}{% endfor %}</td>
|
|
8
|
+
{% endif %}
|
|
9
|
+
{% for header in result_headers %}
|
|
10
|
+
<th scope="col"{{ header.class_attrib }}>
|
|
11
|
+
<div class="px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-300 uppercase tracking-wider">
|
|
12
|
+
{% if header.sortable %}
|
|
13
|
+
{% if header.sort_priority > 0 %}
|
|
14
|
+
<a href="{{ header.url_remove }}" class="inline-flex items-center hover:text-gray-900 dark:hover:text-white">
|
|
15
|
+
{{ header.text }}
|
|
16
|
+
{% if header.ascending %}
|
|
17
|
+
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"/></svg>
|
|
18
|
+
{% else %}
|
|
19
|
+
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
|
|
20
|
+
{% endif %}
|
|
21
|
+
</a>
|
|
22
|
+
{% else %}
|
|
23
|
+
<a href="{{ header.url_primary }}" class="hover:text-gray-900 dark:hover:text-white">
|
|
24
|
+
{{ header.text }}
|
|
25
|
+
</a>
|
|
26
|
+
{% endif %}
|
|
27
|
+
{% else %}
|
|
28
|
+
{# Non-sortable: action checkbox header or plain text #}
|
|
29
|
+
{{ header.text }}
|
|
30
|
+
{% endif %}
|
|
31
|
+
</div>
|
|
32
|
+
</th>
|
|
33
|
+
{% endfor %}
|
|
34
|
+
</tr>
|
|
35
|
+
</thead>
|
|
36
|
+
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
37
|
+
{% for result in results %}
|
|
38
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
|
|
39
|
+
{% for item in result %}
|
|
40
|
+
{{ item }}
|
|
41
|
+
{% endfor %}
|
|
42
|
+
</tr>
|
|
43
|
+
{% endfor %}
|
|
44
|
+
</tbody>
|
|
45
|
+
</table>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% load i18n admin_urls static %}
|
|
1
|
+
{% load i18n admin_urls static adminita_tags %}
|
|
2
2
|
<div class="js-inline-admin-formset inline-group dark:bg-gray-800"
|
|
3
3
|
id="{{ inline_admin_formset.formset.prefix }}-group"
|
|
4
4
|
data-inline-type="stacked"
|
|
@@ -44,8 +44,6 @@
|
|
|
44
44
|
{% if inline_admin_form.pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
|
|
45
45
|
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
47
|
{# Form errors #}
|
|
50
48
|
{% if inline_admin_form.form.non_field_errors %}
|
|
51
49
|
<div class="text-red-600 text-sm mb-4">{{ inline_admin_form.form.non_field_errors }}</div>
|
|
@@ -61,7 +59,7 @@
|
|
|
61
59
|
{% if field.field.required %}<span class="text-red-500">*</span>{% endif %}
|
|
62
60
|
</label>
|
|
63
61
|
{% if field.is_readonly %}
|
|
64
|
-
<div class="readonly-field text-gray-900 dark:text-gray-100 py-2">{{ field
|
|
62
|
+
<div class="readonly-field text-gray-900 dark:text-gray-100 py-2">{{ field|safe_contents }}</div>
|
|
65
63
|
{% else %}
|
|
66
64
|
{{ field.field }}
|
|
67
65
|
{% if field.field.errors %}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% load i18n admin_urls static %}
|
|
1
|
+
{% load i18n admin_urls static adminita_tags %}
|
|
2
2
|
<div class="js-inline-admin-formset inline-group"
|
|
3
3
|
id="{{ inline_admin_formset.formset.prefix }}-group"
|
|
4
4
|
data-inline-type="tabular"
|
|
@@ -45,29 +45,24 @@
|
|
|
45
45
|
{% endfor %}
|
|
46
46
|
|
|
47
47
|
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
|
|
48
|
-
<th scope="col" class="px-3 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-
|
|
48
|
+
<th scope="col" class="px-3 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-16">
|
|
49
49
|
{% translate "Delete" %}
|
|
50
50
|
</th>
|
|
51
51
|
{% endif %}
|
|
52
52
|
</tr>
|
|
53
53
|
</thead>
|
|
54
54
|
|
|
55
|
+
{# Table Body #}
|
|
55
56
|
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
56
57
|
{% for inline_admin_form in inline_admin_formset %}
|
|
57
|
-
<tr class="form-row {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form{% endif %}
|
|
58
|
+
<tr class="form-row {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form{% endif %}"
|
|
58
59
|
id="{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}">
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
</span>
|
|
65
|
-
{% else %}
|
|
66
|
-
<span class="inline-flex items-center justify-center w-6 h-6 text-xs font-medium bg-primary-100 dark:bg-primary-900 text-primary-600 dark:text-primary-400 rounded-full">
|
|
67
|
-
+
|
|
68
|
-
</span>
|
|
61
|
+
{# Row number / handle #}
|
|
62
|
+
<td class="original px-3 py-3 text-sm text-gray-500 dark:text-gray-400 font-medium">
|
|
63
|
+
{% if inline_admin_form.original or inline_admin_form.show_url %}
|
|
64
|
+
<span class="inline-num">{{ forloop.counter }}</span>
|
|
69
65
|
{% endif %}
|
|
70
|
-
|
|
71
66
|
{% if inline_admin_form.needs_explicit_pk_field %}
|
|
72
67
|
{{ inline_admin_form.pk_field.field }}
|
|
73
68
|
{% endif %}
|
|
@@ -84,7 +79,7 @@
|
|
|
84
79
|
{% if not field.field.is_hidden %}
|
|
85
80
|
<td class="px-3 py-3 {% if field.field.name %}field-{{ field.field.name }}{% endif %}">
|
|
86
81
|
{% if field.is_readonly %}
|
|
87
|
-
<div class="readonly-field text-gray-900 dark:text-gray-100">{{ field
|
|
82
|
+
<div class="readonly-field text-gray-900 dark:text-gray-100">{{ field|safe_contents }}</div>
|
|
88
83
|
{% if inline_admin_form.show_url %}
|
|
89
84
|
<a href="{{ inline_admin_form.absolute_url }}" class="text-xs text-primary-600 dark:text-primary-400 hover:underline ml-2">
|
|
90
85
|
{% translate "View" %}
|
|
@@ -108,69 +103,28 @@
|
|
|
108
103
|
<label class="sr-only" for="id_{{ inline_admin_formset.formset.prefix }}-{{ forloop.counter0 }}-DELETE">
|
|
109
104
|
{% translate "Delete" %}
|
|
110
105
|
</label>
|
|
111
|
-
|
|
112
|
-
<input type="checkbox"
|
|
113
|
-
name="{{ inline_admin_formset.formset.prefix }}-{{ forloop.counter0 }}-DELETE"
|
|
114
|
-
id="id_{{ inline_admin_formset.formset.prefix }}-{{ forloop.counter0 }}-DELETE"
|
|
115
|
-
class="delete-checkbox w-5 h-5 text-red-600 bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 rounded focus:ring-red-500 focus:ring-2 cursor-pointer"
|
|
116
|
-
title="{% translate 'Check to delete' %}">
|
|
117
|
-
</div>
|
|
106
|
+
{{ inline_admin_form.deletion_field.field }}
|
|
118
107
|
{% endif %}
|
|
119
108
|
</td>
|
|
120
109
|
{% endif %}
|
|
110
|
+
|
|
121
111
|
</tr>
|
|
122
112
|
{% endfor %}
|
|
123
113
|
</tbody>
|
|
124
114
|
</table>
|
|
125
115
|
</div>
|
|
126
116
|
|
|
117
|
+
{# Add Row Link #}
|
|
118
|
+
{% if inline_admin_formset.has_add_permission %}
|
|
119
|
+
<div class="add-row px-4 py-3 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750">
|
|
120
|
+
<a href="#" class="inline-flex items-center text-sm font-medium text-primary-600 dark:text-primary-400 hover:text-primary-800 dark:hover:text-primary-300">
|
|
121
|
+
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
122
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
|
|
123
|
+
</svg>
|
|
124
|
+
{% blocktranslate with verbose_name=inline_admin_formset.opts.verbose_name %}Add another {{ verbose_name }}{% endblocktranslate %}
|
|
125
|
+
</a>
|
|
126
|
+
</div>
|
|
127
|
+
{% endif %}
|
|
128
|
+
|
|
127
129
|
</fieldset>
|
|
128
|
-
|
|
129
|
-
{# Add Another Row - Outside fieldset for proper JS handling #}
|
|
130
|
-
{# Django's inlines.js will create the add-row dynamically #}
|
|
131
|
-
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
<style>
|
|
135
|
-
/* Style the add-row link to look like a simple link, not a button */
|
|
136
|
-
.add-row {
|
|
137
|
-
background: transparent;
|
|
138
|
-
border: none;
|
|
139
|
-
}
|
|
140
|
-
.add-row a,
|
|
141
|
-
.add-row a:link,
|
|
142
|
-
.add-row a:visited {
|
|
143
|
-
display: inline-flex;
|
|
144
|
-
align-items: center;
|
|
145
|
-
gap: 0.5rem;
|
|
146
|
-
font-size: 0.875rem;
|
|
147
|
-
font-weight: 500;
|
|
148
|
-
color: #2563eb;
|
|
149
|
-
text-decoration: none;
|
|
150
|
-
background: transparent !important;
|
|
151
|
-
border: none !important;
|
|
152
|
-
padding: 0 !important;
|
|
153
|
-
box-shadow: none !important;
|
|
154
|
-
}
|
|
155
|
-
.add-row a:hover {
|
|
156
|
-
color: #1d4ed8;
|
|
157
|
-
text-decoration: underline;
|
|
158
|
-
}
|
|
159
|
-
.add-row a::before {
|
|
160
|
-
content: "+";
|
|
161
|
-
font-size: 1.25rem;
|
|
162
|
-
font-weight: 400;
|
|
163
|
-
margin-right: 0.25rem;
|
|
164
|
-
}
|
|
165
|
-
/* Dark mode */
|
|
166
|
-
@media (prefers-color-scheme: dark) {
|
|
167
|
-
.add-row a,
|
|
168
|
-
.add-row a:link,
|
|
169
|
-
.add-row a:visited {
|
|
170
|
-
color: #60a5fa;
|
|
171
|
-
}
|
|
172
|
-
.add-row a:hover {
|
|
173
|
-
color: #93c5fd;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
</style>
|
|
130
|
+
</div>
|