django-unfold 0.40.0__py3-none-any.whl → 0.41.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. {django_unfold-0.40.0.dist-info → django_unfold-0.41.0.dist-info}/METADATA +6 -1
  2. {django_unfold-0.40.0.dist-info → django_unfold-0.41.0.dist-info}/RECORD +41 -38
  3. {django_unfold-0.40.0.dist-info → django_unfold-0.41.0.dist-info}/WHEEL +1 -1
  4. unfold/admin.py +5 -0
  5. unfold/contrib/filters/forms.py +2 -2
  6. unfold/contrib/forms/templates/unfold/forms/array.html +2 -2
  7. unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +1 -1
  8. unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_group.html +1 -1
  9. unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_user.html +1 -1
  10. unfold/contrib/import_export/templates/admin/import_export/export.html +1 -1
  11. unfold/contrib/import_export/templates/admin/import_export/import.html +1 -1
  12. unfold/contrib/simple_history/templates/simple_history/object_history_form.html +1 -1
  13. unfold/static/admin/js/inlines.js +439 -0
  14. unfold/static/unfold/css/styles.css +1 -1
  15. unfold/static/unfold/fonts/material-symbols/Material-Symbols-Outlined.woff2 +0 -0
  16. unfold/static/unfold/fonts/material-symbols/styles.css +1 -2
  17. unfold/static/unfold/js/alpine.sort.js +1 -0
  18. unfold/static/unfold/js/app.js +36 -10
  19. unfold/static/unfold/js/select2.init.js +1 -1
  20. unfold/styles.css +5 -1
  21. unfold/templates/admin/app_index.html +1 -1
  22. unfold/templates/admin/auth/user/change_password.html +1 -1
  23. unfold/templates/admin/base.html +1 -1
  24. unfold/templates/admin/change_form.html +1 -1
  25. unfold/templates/admin/change_list.html +46 -44
  26. unfold/templates/admin/delete_confirmation.html +4 -9
  27. unfold/templates/admin/delete_selected_confirmation.html +4 -8
  28. unfold/templates/admin/edit_inline/stacked.html +15 -6
  29. unfold/templates/admin/edit_inline/tabular.html +36 -19
  30. unfold/templates/admin/object_history.html +1 -1
  31. unfold/templates/admin/submit_line.html +8 -8
  32. unfold/templates/registration/password_change_done.html +1 -1
  33. unfold/templates/registration/password_change_form.html +1 -1
  34. unfold/templates/unfold/change_list_filter.html +7 -9
  35. unfold/templates/unfold/helpers/delete_submit_line.html +11 -0
  36. unfold/templates/unfold/helpers/display_header.html +8 -3
  37. unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  38. unfold/templates/unfold/helpers/fieldset_row.html +2 -0
  39. unfold/templates/unfold/layouts/skeleton.html +1 -0
  40. unfold/templates/unfold/widgets/url.html +7 -5
  41. {django_unfold-0.40.0.dist-info → django_unfold-0.41.0.dist-info}/LICENSE.md +0 -0
@@ -12,6 +12,21 @@ window.addEventListener("load", (e) => {
12
12
  warnWithoutSaving();
13
13
  });
14
14
 
15
+ /*************************************************************
16
+ * Alpine.sort.js callback after sorting
17
+ *************************************************************/
18
+ const sortRecords = (e) => {
19
+ const orderingField = e.from.dataset.orderingField;
20
+
21
+ const weightInputs = Array.from(
22
+ e.from.querySelectorAll(`.has_original input[name$=-${orderingField}]`)
23
+ );
24
+
25
+ weightInputs.forEach((input, index) => {
26
+ input.value = index;
27
+ });
28
+ };
29
+
15
30
  /*************************************************************
16
31
  * Warn without saving
17
32
  *************************************************************/
@@ -120,15 +135,26 @@ const dateTimeShortcutsOverlay = () => {
120
135
  * File upload path
121
136
  *************************************************************/
122
137
  const fileInputUpdatePath = () => {
123
- Array.from(document.querySelectorAll("input[type=file]")).forEach((input) => {
124
- input.addEventListener("change", (e) => {
125
- const parts = e.target.value.split("\\");
126
- const placeholder =
127
- input.parentNode.parentNode.parentNode.querySelector(
128
- "input[type=text]"
129
- );
130
- placeholder.setAttribute("value", parts[parts.length - 1]);
131
- });
138
+ const observer = new MutationObserver((mutations) => {
139
+ for (const mutation of mutations) {
140
+ if (mutation.type === "childList") {
141
+ for (const input of document.querySelectorAll("input[type=file]")) {
142
+ input.addEventListener("change", (e) => {
143
+ const parts = e.target.value.split("\\");
144
+ const placeholder =
145
+ input.parentNode.parentNode.parentNode.querySelector(
146
+ "input[type=text]"
147
+ );
148
+ placeholder.setAttribute("value", parts[parts.length - 1]);
149
+ });
150
+ }
151
+ }
152
+ }
153
+ });
154
+
155
+ observer.observe(document.body, {
156
+ childList: true,
157
+ subtree: true,
132
158
  });
133
159
  };
134
160
 
@@ -153,7 +179,7 @@ const submitSearch = () => {
153
179
  }, {});
154
180
 
155
181
  if (searchString) {
156
- queryParams["q"] = searchString;
182
+ queryParams["q"] = encodeURIComponent(searchString);
157
183
  }
158
184
 
159
185
  const result = Object.entries(queryParams)
@@ -10,6 +10,6 @@
10
10
  };
11
11
 
12
12
  $(function () {
13
- $(".admin-autocomplete").djangoCustomSelect2();
13
+ $(".unfold-admin-autocomplete.admin-autocomplete").djangoCustomSelect2();
14
14
  });
15
15
  }
unfold/styles.css CHANGED
@@ -60,6 +60,10 @@ html {
60
60
  @apply text-red-600;
61
61
  }
62
62
 
63
+ .sortable-ghost {
64
+ @apply opacity-50;
65
+ }
66
+
63
67
  /*******************************************************
64
68
  Icons
65
69
  *******************************************************/
@@ -287,7 +291,7 @@ h3 span:nth-child(3) {
287
291
  Autocomplete
288
292
  *******************************************************/
289
293
  .select2.select2-container {
290
- @apply bg-white border max-w-2xl relative rounded-md shadow-sm !w-full dark:bg-gray-900 dark:border-gray-700;
294
+ @apply bg-white border max-w-2xl !min-h-9.5 relative rounded-md shadow-sm !w-full dark:bg-gray-900 dark:border-gray-700;
291
295
  }
292
296
 
293
297
  .errors .select2.select2-container {
@@ -10,7 +10,7 @@
10
10
  {% block breadcrumbs %}
11
11
  <div class="px-12">
12
12
  <div class="container mb-12 mx-auto -my-3">
13
- <ul class="flex">
13
+ <ul class="flex flex-wrap">
14
14
  {% url 'admin:index' as link %}
15
15
  {% trans 'Home' as name %}
16
16
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -8,7 +8,7 @@
8
8
  {% block breadcrumbs %}
9
9
  <div class="px-12">
10
10
  <div class="container mb-12 mx-auto -my-3">
11
- <ul class="flex">
11
+ <ul class="flex flex-wrap">
12
12
  {% url 'admin:index' as link %}
13
13
  {% trans 'Home' as name %}
14
14
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -18,7 +18,7 @@
18
18
  {% block breadcrumbs %}
19
19
  <div class="px-4 lg:px-12">
20
20
  <div class="container mb-12 mx-auto -my-3">
21
- <ul class="flex">
21
+ <ul class="flex flex-wrap">
22
22
  {% url 'admin:index' as link %}
23
23
  {% trans 'Home' as name %}
24
24
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -13,7 +13,7 @@
13
13
  {% block breadcrumbs %}
14
14
  <div class="px-4 lg:px-12">
15
15
  <div class="container mb-6 mx-auto -my-3 lg:mb-12">
16
- <ul class="flex">
16
+ <ul class="flex flex-wrap">
17
17
  {% url 'admin:index' as link %}
18
18
  {% trans 'Home' as name %}
19
19
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -26,7 +26,7 @@
26
26
  {% block breadcrumbs %}
27
27
  <div class="px-4 lg:px-12">
28
28
  <div class="{% if not cl.model_admin.list_fullwidth %}container{% endif %} mb-6 mx-auto -my-3 lg:mb-12">
29
- <ul class="flex">
29
+ <ul class="flex flex-wrap">
30
30
  {% url 'admin:index' as link %}
31
31
  {% trans 'Home' as name %}
32
32
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -62,60 +62,62 @@
62
62
  {% endif %}
63
63
 
64
64
  <div class="flex -mx-4 module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
65
- <div class="changelist-form-container flex-grow min-w-0 px-4" x-data="{ filterOpen: false }">
66
- {% block date_hierarchy %}
67
- {% if cl.date_hierarchy %}
68
- {% date_hierarchy cl %}
65
+ <div class="changelist-form-container flex flex-row flex-grow gap-4 min-w-0 px-4" x-data="{ filterOpen: false }">
66
+ <div class="flex-grow min-w-0">
67
+ {% block date_hierarchy %}
68
+ {% if cl.date_hierarchy %}
69
+ {% date_hierarchy cl %}
70
+ {% endif %}
71
+ {% endblock %}
72
+
73
+ {% if cl.model_admin.list_before_template %}
74
+ {% include cl.model_admin.list_before_template %}
69
75
  {% endif %}
70
- {% endblock %}
71
76
 
72
- {% if cl.model_admin.list_before_template %}
73
- {% include cl.model_admin.list_before_template %}
74
- {% endif %}
77
+ <form id="changelist-form" method="post"{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>
78
+ {% csrf_token %}
75
79
 
76
- <form id="changelist-form" method="post"{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>
77
- {% csrf_token %}
80
+ {% if cl.formset %}
81
+ <div>{{ cl.formset.management_form }}</div>
82
+ {% endif %}
78
83
 
79
- {% if cl.formset %}
80
- <div>{{ cl.formset.management_form }}</div>
81
- {% endif %}
84
+ {% block result_list %}
85
+ {% if actions_on_top %}
86
+ {% if cl.search_fields or action_form or cl.has_filters %}
87
+ <div class="bg-gray-50 flex flex-col gap-3 mb-4 p-3 rounded-md lg:flex-row dark:bg-gray-800">
88
+ {% block search %}
89
+ {% search_form cl %}
90
+ {% endblock %}
82
91
 
83
- {% block result_list %}
84
- {% if actions_on_top %}
85
- {% if cl.search_fields or action_form or cl.has_filters %}
86
- <div class="bg-gray-50 flex flex-col gap-3 mb-4 p-3 rounded-md lg:flex-row dark:bg-gray-800">
87
- {% block search %}
88
- {% search_form cl %}
89
- {% endblock %}
90
-
91
- {% if action_form %}
92
- {% admin_actions %}
93
- {% endif %}
94
-
95
- {% block filters %}
96
- {% if cl.has_filters %}
97
- <a class="{% if cl.has_active_filters %}bg-primary-600 border-primary-600 text-white{% else %}bg-white dark:bg-gray-900 dark:border-gray-700{% endif %} border cursor-pointer flex font-medium group items-center px-3 py-2 rounded-md shadow-sm text-sm lg:ml-auto md:mt-0" x-on:click="filterOpen = true" x-on:keydown.escape.window="filterOpen = false">
98
- {% trans "Filters" %}
99
-
100
- <span class="material-symbols-outlined md-18 ml-auto -mr-1 pl-4 {% if cl.has_active_filters %}text-white{% else %}text-gray-400 group-hover:text-gray-500 dark:group-hover:text-gray-400 dark:text-gray-500{% endif %}">filter_list</span>
101
- </a>
92
+ {% if action_form %}
93
+ {% admin_actions %}
102
94
  {% endif %}
103
- {% endblock %}
104
- </div>
95
+
96
+ {% block filters %}
97
+ {% if cl.has_filters %}
98
+ <a class="{% if cl.has_active_filters %}bg-primary-600 border-primary-600 text-white{% else %}bg-white dark:bg-gray-900 dark:border-gray-700{% endif %} border cursor-pointer flex font-medium group items-center px-3 py-2 rounded-md shadow-sm text-sm lg:ml-auto md:mt-0 {% if not cl.model_admin.list_filter_sheet %}2xl:hidden{% endif %}" x-on:click="filterOpen = true" x-on:keydown.escape.window="filterOpen = false">
99
+ {% trans "Filters" %}
100
+
101
+ <span class="material-symbols-outlined md-18 ml-auto -mr-1 pl-4 {% if cl.has_active_filters %}text-white{% else %}text-gray-400 group-hover:text-gray-500 dark:group-hover:text-gray-400 dark:text-gray-500{% endif %}">filter_list</span>
102
+ </a>
103
+ {% endif %}
104
+ {% endblock %}
105
+ </div>
106
+ {% endif %}
105
107
  {% endif %}
106
- {% endif %}
107
108
 
108
- {% unfold_result_list cl %}
109
+ {% unfold_result_list cl %}
109
110
 
110
- {% block pagination %}
111
- {% pagination cl %}
111
+ {% block pagination %}
112
+ {% pagination cl %}
113
+ {% endblock %}
112
114
  {% endblock %}
113
- {% endblock %}
114
- </form>
115
+ </form>
115
116
 
116
- {% if cl.model_admin.list_after_template %}
117
- {% include cl.model_admin.list_after_template %}
118
- {% endif %}
117
+ {% if cl.model_admin.list_after_template %}
118
+ {% include cl.model_admin.list_after_template %}
119
+ {% endif %}
120
+ </div>
119
121
 
120
122
  {% if cl.has_filters %}
121
123
  {% include "unfold/change_list_filter.html" %}
@@ -10,9 +10,9 @@
10
10
  {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation{% endblock %}
11
11
 
12
12
  {% block breadcrumbs %}
13
- <div class="px-12">
14
- <div class="container mb-12 mx-auto -my-3">
15
- <ul class="flex">
13
+ <div class="px-4 lg:px-12">
14
+ <div class="container mb-6 mx-auto -my-3 lg:mb-12">
15
+ <ul class="flex flex-wrap">
16
16
  {% url 'admin:index' as link %}
17
17
  {% trans 'Home' as name %}
18
18
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -95,12 +95,7 @@
95
95
  <input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">
96
96
  {% endif %}
97
97
 
98
-
99
- <a href="#" class="border cancel-link font-medium hidden mb-3 px-3 py-2 rounded-md w-full hover:bg-gray-50 lg:block lg:mb-0 lg:mr-3 lg:w-auto dark:border-gray-700 dark:text-font-default-dark dark:hover:text-gray-200 dark:hover:bg-gray-900">
100
- {% translate "No, take me back" %}
101
- </a>
102
-
103
- <input type="submit" value="{% translate 'Yes, I’m sure' %}" class="bg-red-600 cursor-pointer font-medium ml-auto px-3 py-2 rounded-md text-white dark:bg-red-500/20 dark:text-red-500">
98
+ {% include "unfold/helpers/delete_submit_line.html" %}
104
99
  </div>
105
100
  </form>
106
101
  </div>
@@ -10,9 +10,9 @@
10
10
  {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %}
11
11
 
12
12
  {% block breadcrumbs %}
13
- <div class="px-12">
14
- <div class="container mb-12 mx-auto -my-3">
15
- <ul class="flex">
13
+ <div class="px-4 lg:px-12">
14
+ <div class="container mb-6 mx-auto -my-3 lg:mb-12">
15
+ <ul class="flex flex-wrap">
16
16
  {% url 'admin:index' as link %}
17
17
  {% trans 'Home' as name %}
18
18
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -89,11 +89,7 @@
89
89
  <input type="hidden" name="action" value="delete_selected">
90
90
  <input type="hidden" name="post" value="yes">
91
91
 
92
- <a href="#" class="border cancel-link font-medium hidden mb-3 px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:mb-0 lg:mr-3 lg:w-auto dark:border-gray-700 dark:text-font-default-dark dark:hover:text-gray-200 dark:hover:bg-gray-900">
93
- {% translate "No, take me back" %}
94
- </a>
95
-
96
- <input type="submit" value="{% translate 'Yes, I’m sure' %}" class="bg-red-600 cursor-pointer font-medium ml-auto px-3 py-2 rounded-md text-white dark:bg-red-500/20 dark:text-red-500">
92
+ {% include "unfold/helpers/delete_submit_line.html" %}
97
93
  </div>
98
94
  </form>
99
95
  </div>
@@ -13,15 +13,24 @@
13
13
  {{ inline_admin_formset.formset.management_form }}
14
14
  {% include "unfold/helpers/messages/error.html" with errors=inline_admin_formset.formset.non_form_errors %}
15
15
 
16
+ <div class="border border-gray-200 mb-6 overflow-hidden rounded-md shadow-sm w-full dark:border-gray-800 *:border-t first:*:border-t-0 *:border-gray-200 dark:*:border-gray-800"
17
+ {% if inline_admin_formset.opts.ordering_field %}
18
+ data-ordering-field="{{ inline_admin_formset.opts.ordering_field }}" x-on:end="sortRecords" x-sort.ghost
19
+ {% endif %}>
16
20
 
17
- <div class="border border-gray-200 mb-6 overflow-hidden rounded-md shadow-sm w-full dark:border-gray-800">
18
21
  {% for inline_admin_form in inline_admin_formset %}
19
- <div class="inline-related group inline-stacked {% 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 last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
22
+ <div x-sort:item class="inline-related group inline-stacked {% 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 last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
20
23
  {% if not inline_admin_formset.opts.hide_title or inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
21
- <h3 class="bg-gray-50 border-b {% if not forloop.first %}border-t{% endif %} border-gray-200 flex font-medium items-center mb-3 px-3 py-2 text-sm dark:bg-white/[.02] dark:border-gray-800">
22
- <span class="mr-2">
23
- {{ inline_admin_formset.opts.verbose_name|capfirst }}:
24
- </span>
24
+ <h3 class="bg-gray-50 border-b border-gray-200 flex font-medium items-center gap-2 mb-3 px-3 py-2 text-sm dark:bg-white/[.02] dark:border-gray-800">
25
+ {% if inline_admin_formset.opts.ordering_field %}
26
+ {% if inline_admin_form.original %}
27
+ <span class="material-symbols-outlined cursor-pointer" x-sort:handle>drag_indicator</span>
28
+ {% else %}
29
+ <span class="-mr-2" x-sort:handle></span>
30
+ {% endif %}
31
+ {% endif %}
32
+
33
+ {{ inline_admin_formset.opts.verbose_name|capfirst }}:
25
34
 
26
35
  <span class="inline_label font-semibold text-font-important-light dark:text-font-important-dark">
27
36
  {% if inline_admin_form.original and inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
@@ -16,12 +16,17 @@
16
16
  {{ inline_admin_formset.formset.non_form_errors }}
17
17
 
18
18
  <div class="border border-gray-200 mb-6 overflow-x-auto rounded-md shadow-sm dark:border-gray-800" data-simplebar data-simplebar-auto-hide="false">
19
- <table class="border-spacing-none border-separate w-full">
19
+ <table class="border-spacing-none border-separate w-full"
20
+ {% if inline_admin_formset.opts.ordering_field %}
21
+ data-ordering-field="{{ inline_admin_formset.opts.ordering_field }}"
22
+ x-on:end="sortRecords"
23
+ x-sort.ghost
24
+ {% endif %}>
20
25
  <thead class="hidden lg:table-header-group">
21
26
  <tr>
22
27
  {% for field in inline_admin_formset.fields %}
23
28
  {% if not field.widget.is_hidden %}
24
- <th class="column-{{ field.name }}{% if field.required %} required{% endif %} align-middle border-b border-gray-200 font-semibold px-3 py-2 text-left text-font-important-light text-sm whitespace-nowrap dark:text-font-important-dark dark:border-gray-800">
29
+ <th class="column-{{ field.name }}{% if field.required %} required{% endif %} align-middle border-b border-gray-200 font-semibold px-3 py-2 text-left text-font-important-light text-sm whitespace-nowrap dark:text-font-important-dark dark:border-gray-800 {% if inline_admin_formset.opts.ordering_field and field.name == inline_admin_formset.opts.ordering_field and inline_admin_formset.opts.hide_ordering_field %}hidden{% endif %}">
25
30
  <span class="flex flex-row items-center">
26
31
  {{ field.label|capfirst }}
27
32
 
@@ -41,8 +46,8 @@
41
46
  </tr>
42
47
  </thead>
43
48
 
44
- <tbody>
45
- {% for inline_admin_form in inline_admin_formset %}
49
+ {% for inline_admin_form in inline_admin_formset %}
50
+ <tbody x-sort:item>
46
51
  {% if inline_admin_form.form.non_field_errors %}
47
52
  <tr class="row-form-errors group inline-tabular">
48
53
  <td colspan="{{ inline_admin_form|cell_count }}">
@@ -118,20 +123,32 @@
118
123
  {% with is_last_col=forloop.last %}
119
124
  {% for field in line %}
120
125
  {% if field.is_readonly or not field.field.is_hidden %}
121
- <td{% if field.field.name %} class="field-{{ field.field.name }} group field-tabular {% if field.field.errors|length > 0 %} errors{% endif %}{% if inline_admin_form.original %} p-3 lg:py-3{% else %} py-3{% endif %}{% if field.is_checkbox %} align-middle{% else %} align-top{% endif %} {% if is_last_row and not inline_admin_formset.has_add_permission %}{% if is_last_col %}border-0 {% else %}border-b lg:border-0{% endif %}{% else %}border-b{% endif %} border-gray-200 flex items-center before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 before:pr-4 lg:before:hidden font-normal px-3 text-left text-sm lg:table-cell dark:border-gray-800 {% if field.field.is_hidden %} !hidden{% endif %}"{% endif %} data-label="{{ field.field.label }}">
122
- {% if field.is_readonly %}
123
- {% include "unfold/helpers/field_readonly_value.html" with tabular=1 %}
124
- {% else %}
125
- {{ field.field }}
126
-
127
- {% if field.field.errors|length > 0 %}
128
- <div class="mt-1 text-red-600 text-sm dark:text-red-500">
129
- {% for error in field.field.errors %}
130
- {{ error }}
131
- {% endfor %}
132
- </div>
126
+ <td{% if field.field.name %} class="field-{{ field.field.name }} group field-tabular {% if field.field.errors|length > 0 %} errors{% endif %}{% if inline_admin_form.original %} p-3 lg:py-3{% else %} py-3{% endif %}{% if field.is_checkbox %} align-middle{% else %} align-top{% endif %} {% if is_last_row and not inline_admin_formset.has_add_permission %}{% if is_last_col %}border-0 {% else %}border-b lg:border-0{% endif %}{% else %}border-b{% endif %} border-gray-200 flex items-center before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 before:pr-4 lg:before:hidden font-normal px-3 text-left text-sm lg:table-cell dark:border-gray-800 {% if field.field.is_hidden %} !hidden{% endif %} {% if inline_admin_formset.opts.ordering_field and field.field.name == inline_admin_formset.opts.ordering_field and inline_admin_formset.opts.hide_ordering_field %}!hidden{% endif %}"{% endif %} data-label="{{ field.field.label }}">
127
+ <div class="flex flex-row gap-3 items-center">
128
+ {% if forloop.parentloop.counter == 1 and forloop.counter == 1 %}
129
+ {% if inline_admin_formset.opts.ordering_field %}
130
+ {% if inline_admin_form.original %}
131
+ <span class="material-symbols-outlined cursor-pointer" x-sort:handle>drag_indicator</span>
132
+ {% else %}
133
+ <span class="-mr-3" x-sort:handle></span>
134
+ {% endif %}
135
+ {% endif %}
133
136
  {% endif %}
134
- {% endif %}
137
+
138
+ {% if field.is_readonly %}
139
+ {% include "unfold/helpers/field_readonly_value.html" with tabular=1 %}
140
+ {% else %}
141
+ {{ field.field }}
142
+
143
+ {% if field.field.errors|length > 0 %}
144
+ <div class="mt-1 text-red-600 text-sm dark:text-red-500">
145
+ {% for error in field.field.errors %}
146
+ {{ error }}
147
+ {% endfor %}
148
+ </div>
149
+ {% endif %}
150
+ {% endif %}
151
+ </div>
135
152
  </td>
136
153
  {% endif %}
137
154
  {% endfor %}
@@ -152,8 +169,8 @@
152
169
  {% endif %}
153
170
  {% endwith %}
154
171
  </tr>
155
- {% endfor %}
156
- </tbody>
172
+ </tbody>
173
+ {% endfor %}
157
174
  </table>
158
175
  </div>
159
176
  </fieldset>
@@ -4,7 +4,7 @@
4
4
  {% block breadcrumbs %}
5
5
  <div class="px-4 lg:px-12">
6
6
  <div class="container mb-12 mx-auto -my-3">
7
- <ul class="flex">
7
+ <ul class="flex flex-wrap">
8
8
  {% url 'admin:index' as link %}
9
9
  {% trans 'Home' as name %}
10
10
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -1,8 +1,8 @@
1
1
  {% load i18n admin_urls %}
2
2
 
3
- <div {% if not is_popup %}id="submit-row"{% endif %} class="relative z-20 {% if not is_popup %} mt-20 lg:mt-8{% endif %}">
4
- <div class="{% if not is_popup %}bottom-0 fixed left-0 right-0{% endif %}" {% if not is_popup %}x-bind:class="{'xl:left-0': !sidebarDesktopOpen, 'xl:left-72': sidebarDesktopOpen}"{% endif %}>
5
- <div class="bg-white dark:bg-gray-900 {% if not is_popup %}border-t px-4 py-4 relative scrollable-top lg:px-12 dark:border-gray-800{% endif %}">
3
+ <div {% if not is_popup %}id="submit-row"{% endif %} class="relative z-20 {% if not is_popup %} mt-8{% endif %}">
4
+ <div class="{% if not is_popup %}lg:bottom-0 lg:fixed lg:left-0 lg:right-0{% endif %}" {% if not is_popup %}x-bind:class="{'xl:left-0': !sidebarDesktopOpen, 'xl:left-72': sidebarDesktopOpen}"{% endif %}>
5
+ <div class="bg-white dark:bg-gray-900 {% if not is_popup %}lg:border-t lg:py-4 relative scrollable-top lg:px-12 dark:border-gray-800{% endif %}">
6
6
  <div class="container flex flex-col-reverse gap-3 items-center mx-auto lg:flex-row-reverse">
7
7
  {% block submit-row %}
8
8
  {% if show_save %}
@@ -18,7 +18,7 @@
18
18
  {% endfor %}
19
19
 
20
20
  {% if show_save_and_continue %}
21
- <button type="submit" name="_continue" class="border font-medium hidden px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
21
+ <button type="submit" name="_continue" class="border font-medium px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
22
22
  {% if can_change %}
23
23
  {% translate 'Save and continue editing' %}
24
24
  {% else %}
@@ -30,19 +30,19 @@
30
30
  {% if show_close %}
31
31
  {% url opts|admin_urlname:'changelist' as changelist_url %}
32
32
 
33
- <a href="{% add_preserved_filters changelist_url %}" class="border font-medium hidden px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
33
+ <a href="{% add_preserved_filters changelist_url %}" class="border font-medium px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
34
34
  {% translate 'Close' %}
35
35
  </a>
36
36
  {% endif %}
37
37
 
38
38
  {% if show_save_and_add_another %}
39
- <button type="submit" name="_addanother" class="border font-medium hidden px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
39
+ <button type="submit" name="_addanother" class="border font-medium px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
40
40
  {% translate 'Save and add another' %}
41
41
  </button>
42
42
  {% endif %}
43
43
 
44
44
  {% if show_save_as_new %}
45
- <button type="submit" name="_saveasnew" class="border font-medium hidden px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
45
+ <button type="submit" name="_saveasnew" class="border font-medium px-3 py-2 rounded-md transition-all w-full hover:bg-gray-50 lg:block lg:w-auto dark:border-gray-700 dark:hover:text-gray-200 dark:hover:bg-gray-900">
46
46
  {% translate 'Save as new' %}
47
47
  </button>
48
48
  {% endif %}
@@ -51,7 +51,7 @@
51
51
  {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
52
52
 
53
53
  <p class="deletelink-box mr-auto w-full lg:w-auto">
54
- <a href="{% add_preserved_filters delete_url %}" class="block border border-red-500 font-medium px-3 py-2 rounded-md text-center text-red-500 whitespace-nowrap dark:border-transparent dark:bg-red-500/20 dark:text-red-500">
54
+ <a href="{% add_preserved_filters delete_url %}" class="bg-red-600 flex items-center justify-center font-medium h-9.5 ml-auto px-3 py-2 rounded-md text-white dark:bg-red-500/20 dark:text-red-500">
55
55
  {% translate "Delete" %} {{ opts.verbose_name }}
56
56
  </a>
57
57
  </p>
@@ -7,7 +7,7 @@
7
7
  {% block breadcrumbs %}
8
8
  <div class="px-12">
9
9
  <div class="container mb-12 mx-auto -my-3">
10
- <ul class="flex">
10
+ <ul class="flex flex-wrap">
11
11
  {% url 'admin:index' as link %}
12
12
  {% trans 'Home' as name %}
13
13
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -7,7 +7,7 @@
7
7
  {% block breadcrumbs %}
8
8
  <div class="px-12">
9
9
  <div class="container mb-12 mx-auto -my-3">
10
- <ul class="flex">
10
+ <ul class="flex flex-wrap">
11
11
  {% url 'admin:index' as link %}
12
12
  {% trans 'Home' as name %}
13
13
  {% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
@@ -1,11 +1,11 @@
1
1
  {% load i18n admin_list %}
2
2
 
3
- <div id="changelist-filter" class="backdrop-blur-sm bg-opacity-80 bg-gray-900 flex fixed inset-0 z-50" x-show="filterOpen">
4
- <label for="show-filters" id="changelist-filter-close" class="flex-grow"></label>
3
+ <div id="changelist-filter" class="backdrop-blur-sm bg-opacity-80 bg-gray-900 flex inset-0 z-50 fixed {% if not cl.model_admin.list_filter_sheet %}2xl:bg-transparent 2xl:relative 2xl:!block 2xl:z-10{% endif %}" x-show="filterOpen">
4
+ <label for="show-filters" id="changelist-filter-close" class="flex-grow {% if not cl.model_admin.list_filter_sheet %}2xl:hidden{% endif %}" x-on:click="filterOpen = false"></label>
5
5
 
6
- <div class="bg-white flex mx-4 my-4 overflow-hidden rounded shadow-sm w-96 dark:bg-gray-800" x-on:click.outside="filterOpen = false">
6
+ <div class="bg-white flex m-4 overflow-hidden rounded shadow-sm w-80 dark:bg-gray-800 {% if not cl.model_admin.list_filter_sheet %} 2xl:border 2xl:sticky 2xl:top-4 2xl:dark:border-gray-800 2xl:bg-transparent 2xl:dark:!bg-transparent 2xl:m-0{% endif %}">
7
7
  <div class="flex-grow h-full overflow-auto relative">
8
- <h3 class="border-b flex font-semibold mb-6 px-6 py-4 text-font-important-light text-sm dark:text-font-important-dark dark:border-gray-700">
8
+ <h3 class="border-b flex font-semibold mb-4 px-4 py-4 text-font-important-light text-sm dark:text-font-important-dark dark:border-gray-800">
9
9
  {% trans "Filter" %}
10
10
 
11
11
  {% if cl.is_facets_optional %}
@@ -30,15 +30,14 @@
30
30
  </a>
31
31
  {% endif %}
32
32
 
33
- <a class="cursor-pointer material-symbols-outlined md-18 ml-auto pl-4 text-gray-400 transition-colors hover:text-gray-500 dark:text-gray-500 dark:hover:text-gray-400" x-on:click="filterOpen = false">
33
+ <a class="cursor-pointer material-symbols-outlined md-18 ml-auto pl-4 text-gray-400 transition-colors hover:text-gray-500 dark:text-gray-500 dark:hover:text-gray-400 {% if not cl.model_admin.list_filter_sheet %}2xl:hidden{% endif %}" x-on:click="filterOpen = false">
34
34
  close
35
35
  </a>
36
36
  </h3>
37
37
 
38
- <div class="px-6{% if cl.model_admin.list_filter_submit %} pb-16{% endif %}">
38
+ <div class="px-4{% if cl.model_admin.list_filter_submit %} {% endif %}">
39
39
  {% if cl.model_admin.list_filter_submit %}
40
40
  <form id="filter-form" method="get">
41
-
42
41
  {% if request.GET.q %}
43
42
  <input type="hidden" name="q" value="{{ request.GET.q }}">
44
43
  {% endif %}
@@ -48,13 +47,12 @@
48
47
  {% endif %}
49
48
  {% endif %}
50
49
 
51
-
52
50
  {% for spec in cl.filter_specs %}
53
51
  {% admin_list_filter cl spec %}
54
52
  {% endfor %}
55
53
 
56
54
  {% if cl.model_admin.list_filter_submit %}
57
- <div class="bg-gray-50 border-gray-200 border-t bottom-4 fixed px-6 py-3 right-4 rounded-b w-96 dark:bg-gray-700 dark:border-gray-600">
55
+ <div class="bottom-4 absolute left-4 right-4 {% if not cl.model_admin.list_filter_sheet %}2xl:left-0 2xl:right-0 2xl:relative 2xl:mt-8{% endif %}">
58
56
  <button type="submit" class="bg-primary-600 block border border-transparent font-medium px-3 py-2 rounded-md self-end text-sm text-white w-full">
59
57
  {% trans "Apply Filters" %}
60
58
  </button>
@@ -0,0 +1,11 @@
1
+ {% load i18n %}
2
+
3
+ <div class="flex flex-col gap-3 items-center w-full lg:flex-row">
4
+ <a href="#" class="border cancel-link flex items-center justify-center font-medium px-3 py-2 rounded-md w-full hover:bg-gray-50 lg:block lg:mb-0 lg:w-auto dark:border-gray-700 dark:text-font-default-dark dark:hover:text-gray-200 dark:hover:bg-gray-900">
5
+ {% translate "No, take me back" %}
6
+ </a>
7
+
8
+ <button type="submit" class="bg-red-600 cursor-pointer flex items-center justify-center font-medium h-9.5 ml-0 px-3 py-2 rounded-md text-white w-full lg:ml-auto lg:w-auto dark:bg-red-500/20 dark:text-red-500">
9
+ {% translate "Yes, I’m sure" %}
10
+ </button>
11
+ </div>
@@ -2,9 +2,14 @@
2
2
 
3
3
  <span class="flex gap-4 items-center">
4
4
  {% if value.3 and value.3.path %}
5
- <span class="bg-center bg-cover bg-white flex font-medium justify-center overflow-hidden dark:bg-gray-900 dark:border-gray-700 {% if value.3.squared %}rounded-sm{% else %}rounded-full{% endif %}{% if not value.3.borderless %} border{% endif %}{% if not value.3.width or not value.3.height %} h-8 max-w-8 min-w-8{% endif %}">
6
- <img loading="lazy" src="{{ value.3.path }}" class="max-w-none object-cover" {% if value.3.width %}width="{{ value.3.width }}"{% endif %} {% if value.3.height %}height="{{ value.3.height }}"{% endif %} alt="{% trans "Record picture" %}" />
7
- </span>
5
+ {% if value.3.as_background %}
6
+ <span class="block bg-center bg-contain bg-no-repeat {% if not value.3.width %}w-16{% endif %} {% if not value.3.height %}h-12{% endif %}" style="background-image: url({{ value.3.path }}); {% if value.3.height %}height: {{ value.3.height }}px;{% endif %} {% if value.3.width %}width: {{ value.3.width }}px;{% endif %}">
7
+ </span>
8
+ {% else %}
9
+ <span class="bg-center bg-cover bg-white flex font-medium justify-center overflow-hidden dark:bg-gray-900 dark:border-gray-700 {% if value.3.squared %}rounded-sm{% else %}rounded-full{% endif %}{% if not value.3.borderless %} border{% endif %}{% if not value.3.width or not value.3.height %} h-8 max-w-8 min-w-8{% endif %}">
10
+ <img loading="lazy" src="{{ value.3.path }}" class="max-w-none object-cover" {% if value.3.width %}width="{{ value.3.width }}"{% endif %} {% if value.3.height %}height="{{ value.3.height }}"{% endif %} alt="{% trans "Record picture" %}" />
11
+ </span>
12
+ {% endif %}
8
13
  {% elif value.2 %}
9
14
  <span class="bg-white border flex font-medium h-8 justify-center items-center rounded-full text-xs uppercase w-8 dark:bg-gray-900 dark:border-gray-700">
10
15
  {{ value.2 }}
@@ -1 +1 @@
1
- <div class="readonly max-w-4xl py-2 text-sm *:rounded-md {% if not adminform.model_admin.compressed_fields and not field.is_image %}bg-gray-50 border font-medium px-3 rounded-md shadow-sm dark:border-gray-700 dark:bg-gray-800{% endif %} {% if field.is_image %}inline-block [&_img]:rounded-md !py-0{% endif %}">{% if value %}{{ value }}{% elif field.contents %}{{ field.contents }}{% else %}-{% endif %}</div>
1
+ <div class="readonly {% if field.is_json %}max-w-4xl{% else %}max-w-2xl{% endif %} py-2 text-sm *:rounded-md {% if not adminform.model_admin.compressed_fields and not field.is_image %}bg-gray-50 border font-medium px-3 rounded-md shadow-sm dark:border-gray-700 dark:bg-gray-800{% endif %} {% if field.is_image %}inline-block [&_img]:rounded-md !py-0{% endif %}">{% if value %}{{ value }}{% elif field.contents %}{{ field.contents }}{% else %}-{% endif %}</div>
@@ -1,4 +1,6 @@
1
+
1
2
  <div class="form-row
3
+ {% for field in line %}{% if inline_admin_formset.opts.ordering_field and field.field.name == inline_admin_formset.opts.ordering_field and inline_admin_formset.opts.hide_ordering_field %} hidden{% endif %}{% endfor %}
2
4
  {% if adminform.model_admin.compressed_fields %} border-b border-gray-200 -mx-3 px-3 pt-3 first:pt-0 dark:border-gray-800 last:border-b-0{% endif %}
3
5
  {% if not line.fields|length == 1 %} flex flex-row flex-wrap gap-x-8{% endif %}
4
6
  {% if not line.has_visible_field %} hidden{% endif %}