django-unfold 0.58.0__py3-none-any.whl → 0.60.0__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.
Files changed (60) hide show
  1. {django_unfold-0.58.0.dist-info → django_unfold-0.60.0.dist-info}/METADATA +3 -2
  2. {django_unfold-0.58.0.dist-info → django_unfold-0.60.0.dist-info}/RECORD +60 -50
  3. unfold/admin.py +45 -13
  4. unfold/checks.py +24 -2
  5. unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -2
  6. unfold/contrib/inlines/admin.py +11 -6
  7. unfold/contrib/inlines/forms.py +3 -1
  8. unfold/contrib/location_field/__init__.py +0 -0
  9. unfold/contrib/location_field/apps.py +6 -0
  10. unfold/contrib/location_field/templates/location_field/map_widget.html +5 -0
  11. unfold/decorators.py +27 -13
  12. unfold/fields.py +18 -20
  13. unfold/forms.py +99 -3
  14. unfold/layout.py +16 -0
  15. unfold/mixins/action_model_admin.py +22 -14
  16. unfold/mixins/base_model_admin.py +15 -1
  17. unfold/paginator.py +12 -1
  18. unfold/settings.py +8 -1
  19. unfold/sites.py +27 -29
  20. unfold/static/admin/js/admin/RelatedObjectLookups.js +9 -3
  21. unfold/static/unfold/css/styles.css +1 -1
  22. unfold/styles.css +12 -16
  23. unfold/templates/admin/app_list.html +4 -1
  24. unfold/templates/admin/base.html +1 -1
  25. unfold/templates/admin/change_form.html +2 -1
  26. unfold/templates/admin/edit_inline/stacked.html +12 -8
  27. unfold/templates/admin/edit_inline/tabular.html +2 -0
  28. unfold/templates/admin/includes/fieldset.html +9 -3
  29. unfold/templates/admin/login.html +45 -88
  30. unfold/templates/admin/pagination.html +1 -1
  31. unfold/templates/unfold/components/button.html +10 -1
  32. unfold/templates/unfold/helpers/account_links.html +14 -6
  33. unfold/templates/unfold/helpers/app_list.html +5 -2
  34. unfold/templates/unfold/helpers/app_list_default.html +2 -1
  35. unfold/templates/unfold/helpers/change_list_actions.html +2 -2
  36. unfold/templates/unfold/helpers/change_list_filter_actions.html +1 -1
  37. unfold/templates/unfold/helpers/edit_inline/tabular_heading.html +1 -1
  38. unfold/templates/unfold/helpers/empty_results.html +2 -2
  39. unfold/templates/unfold/helpers/field.html +5 -3
  40. unfold/templates/unfold/helpers/header.html +1 -1
  41. unfold/templates/unfold/helpers/language_form.html +10 -0
  42. unfold/templates/unfold/helpers/language_switch.html +17 -19
  43. unfold/templates/unfold/helpers/navigation.html +1 -1
  44. unfold/templates/unfold/helpers/pagination_infinite.html +3 -3
  45. unfold/templates/unfold/helpers/pagination_inline.html +28 -0
  46. unfold/templates/unfold/helpers/theme_switch.html +29 -27
  47. unfold/templates/unfold/helpers/unauthenticated_header.html +15 -0
  48. unfold/templates/unfold/helpers/unauthenticated_title.html +11 -0
  49. unfold/templates/unfold/helpers/userlinks.html +2 -6
  50. unfold/templates/unfold/helpers/welcomemsg.html +9 -7
  51. unfold/templates/unfold/layouts/unauthenticated.html +37 -0
  52. unfold/templates/unfold/widgets/select.html +1 -1
  53. unfold/templates/unfold/widgets/text.html +28 -0
  54. unfold/templates/unfold_crispy/layout/fieldset.html +3 -1
  55. unfold/templates/unfold_crispy/layout/fieldset_subheader.html +3 -0
  56. unfold/templatetags/unfold.py +37 -2
  57. unfold/utils.py +2 -2
  58. unfold/widgets.py +49 -3
  59. {django_unfold-0.58.0.dist-info → django_unfold-0.60.0.dist-info}/LICENSE.md +0 -0
  60. {django_unfold-0.58.0.dist-info → django_unfold-0.60.0.dist-info}/WHEEL +0 -0
unfold/styles.css CHANGED
@@ -1,6 +1,14 @@
1
1
  @import 'tailwindcss';
2
2
  @plugin '@tailwindcss/typography';
3
- @custom-variant dark (&:where(.dark, .dark *));
3
+
4
+ @custom-variant dark {
5
+ @media not print {
6
+ &:where(.dark, .dark *) {
7
+ @slot
8
+ }
9
+ }
10
+ }
11
+
4
12
  @source inline("h-3 w-3 h-[64px] w-[65px]! left-[65px] dark:hover:bg-white/[.06] translate-x-1/4 -translate-y-1/4");
5
13
  @source inline("{-,}{top,bottom,left,right}-{0..6}");
6
14
  @source inline("rounded rounded-{t,r,b,l} rounded-{t,r,b,l}-default");
@@ -145,18 +153,6 @@ select:after {
145
153
  /*******************************************************
146
154
  Table
147
155
  *******************************************************/
148
- table select {
149
- @apply appearance-none bg-no-repeat border border-base-200 block cursor-pointer font-medium px-3 py-2 pr-5 rounded-default shadow-xs text-base-500;
150
-
151
- background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="rgb(156, 163, 175)"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7 10l5 5 5-5H7z"/></svg>');
152
- background-size: 1.125rem 1.125rem;
153
- background-position: right 0.5rem center;
154
- }
155
-
156
-
157
- table select:focus {
158
- @apply border-primary-600;
159
- }
160
156
 
161
157
  table tr.selected td,
162
158
  table tr.selected th {
@@ -201,7 +197,7 @@ table tr.selected th {
201
197
  }
202
198
 
203
199
  .timezonewarning {
204
- @apply absolute block items-center right-20 top-2.5 text-base-500 truncate;
200
+ @apply absolute block items-center right-11 top-2 text-base-500 truncate;
205
201
  font-size: 0;
206
202
  }
207
203
 
@@ -222,7 +218,7 @@ table tr.selected th {
222
218
  Selector
223
219
  *******************************************************/
224
220
  .selector {
225
- @apply flex flex-col grow items-center md:flex-row;
221
+ @apply flex flex-col grow items-center max-w-5xl md:flex-row;
226
222
  }
227
223
 
228
224
  .selector .selector-available-title label,
@@ -323,7 +319,7 @@ table tr.selected th {
323
319
  }
324
320
 
325
321
  [data-inline-type="stacked"] .add-row {
326
- @apply border-t border-base-200 overflow-hidden dark:border-base-800;
322
+ @apply overflow-hidden;
327
323
  }
328
324
 
329
325
  .add-row td {
@@ -44,5 +44,8 @@
44
44
  {% endfor %}
45
45
  </div>
46
46
  {% else %}
47
- <p>{% translate 'You don’t have permission to view or edit anything.' %}</p>
47
+ <p>
48
+ {% trans "You don’t have permission to view or edit anything." as error_message %}
49
+ {% include "unfold/helpers/messages/error.html" with error=error_message %}
50
+ </p>
48
51
  {% endif %}
@@ -38,7 +38,7 @@
38
38
  </div>
39
39
  {% endblock messages %}
40
40
 
41
- <div class="px-4 pb-8 grow">
41
+ <div class="px-4 pb-4 grow">
42
42
  <div id="content" class="{% if not cl.model_admin.list_fullwidth %}container{% endif %} mx-auto {% block coltype %}colM{% endblock %}">
43
43
  {% if cl %}
44
44
  {% tab_list "changelist" cl.opts %}
@@ -93,8 +93,9 @@
93
93
  {% include 'admin/includes/fieldset.html' %}
94
94
  {% endif %}
95
95
  {% endfor %}
96
+
97
+ {% include "unfold/helpers/fieldsets_tabs.html" %}
96
98
  {% endwith %}
97
- {% include "unfold/helpers/fieldsets_tabs.html" %}
98
99
  {% endblock %}
99
100
 
100
101
  {% block after_field_sets %}{% endblock %}
@@ -17,15 +17,15 @@
17
17
  {{ inline_admin_formset.formset.management_form }}
18
18
  {% include "unfold/helpers/messages/error.html" with errors=inline_admin_formset.formset.non_form_errors %}
19
19
 
20
- <div class="border border-base-200 mb-6 overflow-hidden rounded-default shadow-xs w-full dark:border-base-800 *:border-t *:first:border-t-0 *:border-base-200 dark:*:border-base-800"
20
+ <div class="border border-base-200 mb-6 overflow-hidden rounded-default shadow-xs w-full dark:border-base-800"
21
21
  {% if inline_admin_formset.opts.ordering_field %}
22
22
  data-ordering-field="{{ inline_admin_formset.opts.ordering_field }}" x-on:end="sortRecords" x-sort.ghost
23
23
  {% endif %}>
24
24
 
25
25
  {% for inline_admin_form in inline_admin_formset %}
26
- <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 %}">
26
+ <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 %}" {% if inline_admin_formset.opts.collapsible and inline_admin_form.original %}x-data="{ open: {% if inline_admin_form.errors %}true{% else %}false{% endif %} }"{% endif %}>
27
27
  {% if not inline_admin_formset.opts.hide_title or inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
28
- <h3 class="bg-base-50 border-b border-base-200 flex font-medium items-center gap-2 px-3 py-2 text-sm dark:bg-white/[.02] dark:border-base-800">
28
+ <h3 class="border-b border-base-200 flex font-medium items-center gap-2 px-3 py-2 text-sm dark:border-base-800 {% if inline_admin_formset.opts.collapsible and inline_admin_form.original %}cursor-pointer{% endif %}" {% if inline_admin_formset.opts.collapsible and inline_admin_form.original %}x-on:click="open = !open"{% endif %}>
29
29
  {% if inline_admin_formset.opts.ordering_field %}
30
30
  {% if inline_admin_form.original %}
31
31
  <span class="material-symbols-outlined cursor-pointer" x-sort:handle>drag_indicator</span>
@@ -82,11 +82,13 @@
82
82
 
83
83
  {% include "unfold/helpers/messages/error.html" with errors=inline_admin_form.form.non_field_errors %}
84
84
 
85
- {% for fieldset in inline_admin_form %}
86
- <div class="{% if inline_admin_formset.opts.hide_title %}{% if not inline_admin_formset.formset.can_delete or not inline_admin_formset.has_delete_permission %}pt-3{% endif %}{% endif %}">
87
- {% include 'admin/includes/fieldset.html' with stacked=1 %}
88
- </div>
89
- {% endfor %}
85
+ <div class="border-b border-base-200 dark:border-base-800" {% if inline_admin_formset.opts.collapsible and inline_admin_form.original %}x-show="open"{% endif %}>
86
+ {% for fieldset in inline_admin_form %}
87
+ <div class="{% if inline_admin_formset.opts.hide_title %}{% if not inline_admin_formset.formset.can_delete or not inline_admin_formset.has_delete_permission %}pt-3{% endif %}{% endif %}">
88
+ {% include 'admin/includes/fieldset.html' with stacked=1 %}
89
+ </div>
90
+ {% endfor %}
91
+ </div>
90
92
 
91
93
  {% if inline_admin_form.needs_explicit_pk_field %}
92
94
  {{ inline_admin_form.pk_field.field }}
@@ -99,4 +101,6 @@
99
101
 
100
102
  {% if inline_admin_formset.is_collapsible %}</details>{% endif %}
101
103
  </fieldset>
104
+
105
+ {% include "unfold/helpers/pagination_inline.html" %}
102
106
  </div>
@@ -36,5 +36,7 @@
36
36
 
37
37
  {% if inline_admin_formset.is_collapsible %}</details>{% endif %}
38
38
  </fieldset>
39
+
40
+ {% include "unfold/helpers/pagination_inline.html" %}
39
41
  </div>
40
42
  </div>
@@ -2,9 +2,15 @@
2
2
 
3
3
  <fieldset class="module{% if fieldset.classes %} {{ fieldset.classes }}{% endif %}" {% if stacked != 1 %}x-show="activeTab == 'general'"{% endif %}>
4
4
  {% if fieldset.name and "tab" not in fieldset.classes %}
5
- <h2 class="bg-base-100 font-semibold mb-6 px-4 py-3 rounded-default text-font-important-light text-sm 2xl:-mx-4 dark:bg-white/[.02] dark:text-font-important-dark">
6
- {{ fieldset.name }}
7
- </h2>
5
+ {% if stacked == 1 %}
6
+ <h2 class="border-b border-base-200 border-t border-dashed font-semibold text-font-important-light px-3 py-4.5 dark:text-font-important-dark dark:border-base-800">
7
+ {{ fieldset.name }}
8
+ </h2>
9
+ {% else %}
10
+ <h2 class="bg-base-100 font-semibold mb-6 px-4 py-3 rounded-default text-font-important-light text-sm 2xl:-mx-4 dark:bg-white/[.02] dark:text-font-important-dark">
11
+ {{ fieldset.name }}
12
+ </h2>
13
+ {% endif %}
8
14
  {% endif %}
9
15
 
10
16
  {% if fieldset.description %}
@@ -1,105 +1,62 @@
1
- {% extends 'unfold/layouts/skeleton.html' %}
1
+ {% extends 'unfold/layouts/unauthenticated.html' %}
2
2
 
3
- {% load i18n static %}
3
+ {% load i18n static unfold %}
4
4
 
5
5
  {% block extrastyle %}
6
6
  {{ block.super }}
7
7
  {{ form.media }}
8
8
  {% endblock %}
9
9
 
10
- {% block bodyclass %}{{ block.super }}bg-base-50 login dark:bg-base-900{% endblock %}
10
+ {% block title %}
11
+ {{ title }} | {{ site_title }}
12
+ {% endblock %}
11
13
 
12
- {% block usertools %}{% endblock %}
14
+ {% block content %}
15
+ {% include "unfold/helpers/unauthenticated_title.html" with title=site_title|default:_('Django site admin') subtitle=_('Welcome back to') %}
13
16
 
14
- {% block nav-global %}{% endblock %}
17
+ {% include "unfold/helpers/messages.html" %}
15
18
 
16
- {% block nav-sidebar %}{% endblock %}
19
+ {% if form.errors or form.non_field_errors %}
20
+ <div class="flex flex-col gap-4 mb-8 *:mb-0">
21
+ {% include "unfold/helpers/messages/errornote.html" with errors=form.errors %}
17
22
 
18
- {% block content_title %}{% endblock %}
23
+ {% include "unfold/helpers/messages/error.html" with errors=form.non_field_errors %}
19
24
 
20
- {% block breadcrumbs %}{% endblock %}
25
+ {% if user.is_authenticated %}
26
+ {% blocktranslate trimmed asvar message %}
27
+ You are authenticated as {{ username }}, but are not authorized to
28
+ access this page. Would you like to login to a different account?
29
+ {% endblocktranslate %}
21
30
 
22
- {% block title %}
23
- {{ title }} | {{ site_title }}
24
- {% endblock %}
31
+ {% include "unfold/helpers/messages/error.html" with error=message %}
32
+ {% endif %}
33
+ </div>
34
+ {% endif %}
35
+
36
+ {% block login_before %}{% endblock %}
37
+
38
+ <form action="{{ app_path }}" method="post" id="login-form">
39
+ {% csrf_token %}
40
+
41
+ {% include "unfold/helpers/field.html" with field=form.username %}
42
+
43
+ {% include "unfold/helpers/field.html" with field=form.password %}
44
+
45
+ <div class="flex flex-col gap-3 mt-6">
46
+ {% component "unfold/components/button.html" with submit=1 variant="primary" class="submit-row w-full" %}
47
+ {% translate 'Log in' %} <span class="material-symbols-outlined ml-2 relative right-0 transition-all group-hover:-right-1">arrow_forward</span>
48
+ {% endcomponent %}
49
+
50
+ {% url 'admin_password_reset' as password_reset_url %}
51
+ {% url 'admin:admin_password_reset' as unfold_password_reset_url %}
25
52
 
26
- {% block base %}
27
- <div id="page" class="bg-white flex min-h-screen dark:bg-base-900 ">
28
- <div class="flex grow items-center justify-center mx-auto px-4 relative">
29
- <div class="w-full sm:w-96">
30
- <h1 class="font-semibold mb-10">
31
- <span class="block text-font-important-light dark:text-font-important-dark">{% trans 'Welcome back to' %}</span>
32
- <span class="block text-primary-600 text-xl dark:text-primary-500">{{ site_title|default:_('Django site admin') }}</span>
33
- </h1>
34
-
35
- {% include "unfold/helpers/messages.html" %}
36
-
37
- {% if form.errors or form.non_field_errors %}
38
- <div class="flex flex-col gap-4 mb-8 *:mb-0">
39
- {% include "unfold/helpers/messages/errornote.html" with errors=form.errors %}
40
-
41
- {% include "unfold/helpers/messages/error.html" with errors=form.non_field_errors %}
42
-
43
- {% if user.is_authenticated %}
44
- {% blocktranslate trimmed asvar message %}
45
- You are authenticated as {{ username }}, but are not authorized to
46
- access this page. Would you like to login to a different account?
47
- {% endblocktranslate %}
48
-
49
- {% include "unfold/helpers/messages/error.html" with error=message %}
50
- {% endif %}
51
- </div>
52
- {% endif %}
53
-
54
- {% block login_before %}{% endblock %}
55
-
56
- <form action="{{ app_path }}" method="post" id="login-form">
57
- {% csrf_token %}
58
-
59
- {% include "unfold/helpers/field.html" with field=form.username %}
60
-
61
- {% include "unfold/helpers/field.html" with field=form.password %}
62
-
63
- {% url 'admin_password_reset' as password_reset_url %}
64
-
65
- <div class="submit-row">
66
- <button type="submit" class="bg-primary-600 border border-transparent flex flex-row font-semibold group items-center justify-center py-2 rounded-default text-sm text-white w-full">
67
- {% translate 'Log in' %}
68
-
69
- <span class="material-symbols-outlined ml-2 relative right-0 text-base transition-all group-hover:-right-1">arrow_forward</span>
70
- </button>
71
- </div>
72
-
73
- {% if password_reset_url %}
74
- <div class="password-reset-link">
75
- <a href="{{ password_reset_url }}" class="border border-base-200 font-medium hidden mt-4 px-3 py-2 rounded-default text-center text-sm text-base-500 transition-all w-full hover:bg-base-50 lg:block lg:w-auto dark:border-base-700 dark:text-font-default-dark dark:hover:text-base-200 dark:hover:bg-base-900">
76
- {% translate 'Forgotten your password or username?' %}
77
- </a>
78
- </div>
79
- {% endif %}
80
- </form>
81
-
82
- {% block login_after %}{% endblock %}
83
- </div>
84
-
85
- <div class="absolute flex flex-row items-center justify-between left-0 m-4 right-0 top-0">
86
- {% if site_url %}
87
- <a href="{{ site_url }}" class="flex font-medium items-center text-sm text-primary-600 dark:text-primary-500">
88
- <span class="material-symbols-outlined mr-2">arrow_back</span> {% trans 'Return to site' %}
89
- </a>
90
- {% endif %}
91
-
92
- {% if not theme %}
93
- <div class="ml-auto">
94
- {% include "unfold/helpers/theme_switch.html" %}
95
- </div>
96
- {% endif %}
97
- </div>
53
+ {% if password_reset_url or unfold_password_reset_url %}
54
+ {% component "unfold/components/button.html" with href=password_reset_url|default:unfold_password_reset_url variant="secondary" class="password-reset-link w-full" %}
55
+ {% translate 'Forgotten your password or username?' %}
56
+ {% endcomponent %}
57
+ {% endif %}
98
58
  </div>
59
+ </form>
99
60
 
100
- {% if image %}
101
- <div class="bg-cover grow hidden max-w-3xl xl:max-w-4xl xl:block" style="background-image: url('{{ image }}')">
102
- </div>
103
- {% endif %}
104
- </div>
61
+ {% block login_after %}{% endblock %}
105
62
  {% endblock %}
@@ -15,7 +15,7 @@
15
15
 
16
16
  {% if cl.formset and cl.result_count %}
17
17
  <div class="ml-auto">
18
- <button type="submit" name="_save" form="changelist-form" class="bg-primary-600 block border border-transparent font-medium px-3 py-2 rounded-default text-white w-full">
18
+ <button type="submit" name="_save" form="changelist-form" class="bg-primary-600 block border border-transparent cursor-pointer font-medium px-3 py-2 rounded-default text-white w-full">
19
19
  {% translate 'Save' %}
20
20
  </button>
21
21
  </div>
@@ -1,4 +1,13 @@
1
1
  <{% if href %}a href="{{ href }}"{% else %}button{% endif%} {% if submit %}type="submit"{% endif%} {% if name %}name="{{ name }}"{% endif %}
2
- class="border border-base-200 font-medium flex items-center gap-2 px-3 py-2 rounded-default justify-center whitespace-nowrap {% if attrs.disabled %}cursor-not-allowed opacity-50{% endif %} {% if variant == "default" %}bg-white dark:border-base-700 dark:bg-transparent dark:text-white{% else %}bg-primary-600 border-transparent text-white{% endif %}{% if class %} {{ class }}{% endif %}" {% include "unfold/helpers/attrs.html" %}>
2
+ class="font-medium flex group items-center gap-2 px-3 py-2 rounded-default justify-center whitespace-nowrap {% if attrs.disabled %}cursor-not-allowed opacity-50{% else %}cursor-pointer{% endif %}
3
+ {% if variant == "default" %}
4
+ border border-base-200 bg-white text-font-important-light dark:border-base-700 dark:bg-transparent dark:text-font-important-dark
5
+ {% elif variant == "secondary" %}
6
+ bg-gray-100 border border-transparent dark:bg-base-800
7
+ {% elif variant == "ghost" %}
8
+ bg-transparent text-font-important-light dark:text-font-important-dark
9
+ {% else %}
10
+ border border-base-200 bg-primary-600 border-transparent text-white
11
+ {% endif %}{% if class %} {{ class }}{% endif %}" {% include "unfold/helpers/attrs.html" %}>
3
12
  {{ children }}
4
13
  </{% if href %}a{% else %}button{% endif%}>
@@ -6,7 +6,7 @@
6
6
  </a>
7
7
 
8
8
  <nav class="absolute bg-white border border-base-200 flex flex-col leading-none py-1 -right-2 rounded-default shadow-lg top-7 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openUserLinks" x-transition x-on:click.outside="openUserLinks = false">
9
- <div class="border-b border-base-100 flex flex-row shrink-0 items-start justify-start mb-1 pb-1 dark:border-base-700">
9
+ <div class="border-b border-base-200 flex flex-row shrink-0 items-start justify-start mb-1 pb-1 dark:border-base-700">
10
10
  <span class="block mx-1 px-3 py-2 truncate">
11
11
  {% firstof user.get_short_name user.get_username %}
12
12
  </span>
@@ -18,17 +18,25 @@
18
18
  </a>
19
19
  {% endif %}
20
20
 
21
- {% if user.has_usable_password %}
22
- <a href="{% url 'admin:password_change' %}" class="mx-1 px-3 py-2 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200">
23
- {% translate 'Change password' %}
24
- </a>
21
+ {% if account_links %}
22
+ {% for link in account_links %}
23
+ <a href="{{ link.link }}" class="mx-1 px-3 py-2 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200">
24
+ {{ link.title }}
25
+ </a>
26
+ {% endfor %}
27
+ {% else %}
28
+ {% if user.has_usable_password %}
29
+ <a href="{% url 'admin:password_change' %}" class="mx-1 px-3 py-2 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200">
30
+ {% translate 'Change password' %}
31
+ </a>
32
+ {% endif %}
25
33
  {% endif %}
26
34
 
27
35
  <div class="border-t border-base-200 mt-1 pt-1 dark:border-base-700">
28
36
  <form id="logout-form" method="post" action="{% url 'admin:logout' %}" class="mx-1">
29
37
  {% csrf_token %}
30
38
 
31
- <button type="submit" class="bg-none block px-3 py-2 text-left text-red-500 rounded-default w-full hover:bg-red-100 dark:hover:bg-red-500/20 dark:hover:text-red-500">
39
+ <button type="submit" class="bg-none block cursor-pointer px-3 py-2 text-left text-red-500 rounded-default w-full hover:bg-red-100 dark:hover:bg-red-500/20 dark:hover:text-red-500">
32
40
  {% translate 'Log out' %}
33
41
  </button>
34
42
  </form>
@@ -57,7 +57,7 @@
57
57
  {% endfor %}
58
58
  </div>
59
59
 
60
- {% if sidebar_show_all_applications %}
60
+ {% if sidebar_show_all_applications and app_list|length > 0 %}
61
61
  <div class="mt-auto" x-data="{ openAllApplications: false }">
62
62
  <a class="cursor-pointer flex items-center h-[64px] px-6 py-3 text-sm dark:text-font-default-dark hover:text-primary-600 dark:hover:text-primary-500" x-on:click="openAllApplications = !openAllApplications">
63
63
  <span class="material-symbols-outlined md-18 mr-3">
@@ -95,5 +95,8 @@
95
95
  </div>
96
96
  {% endif %}
97
97
  {% else %}
98
- <p>{% translate "You don’t have permission to view or edit anything." %}</p>
98
+ <p>
99
+ {% trans "You don’t have permission to view or edit anything." as error_message %}
100
+ {% include "unfold/helpers/messages/error.html" with error=error_message %}
101
+ </p>
99
102
  {% endif %}
@@ -56,6 +56,7 @@
56
56
  {% endfor %}
57
57
  {% else %}
58
58
  <p>
59
- {% translate 'You don’t have permission to view or edit anything.' %}
59
+ {% trans "You don’t have permission to view or edit anything." as error_message %}
60
+ {% include "unfold/helpers/messages/error.html" with error=error_message %}
60
61
  </p>
61
62
  {% endif %}
@@ -2,8 +2,8 @@
2
2
 
3
3
  {% if actions_on_top %}
4
4
  {% if cl.search_fields or action_form or cl.has_filters %}
5
- <div class="bottom-0 left-0 right-0 hidden bg-primary-600 group-has-[input.action-select:checked]:flex fixed gap-3 lg:h-[71px] items-center p-3 z-50 lg:flex-row dark:bg-primary-500">
6
- <div id="changelist-actions-wrapper" class="grow lg:px-4" {% if not is_popup %}x-bind:class="{'xl:ml-0': !sidebarDesktopOpen, 'xl:ml-72': sidebarDesktopOpen}"{% endif %}>
5
+ <div class="bottom-0 left-0 right-0 hidden bg-primary-600 group-has-[input.action-select:checked]:flex fixed gap-3 lg:h-[64px] items-center p-3 z-50 lg:flex-row dark:bg-primary-500">
6
+ <div id="changelist-actions-wrapper" class="grow" {% if not is_popup %}x-bind:class="{'xl:ml-0': !sidebarDesktopOpen, 'xl:ml-72': sidebarDesktopOpen}"{% endif %}>
7
7
  {% if action_form %}
8
8
  {% admin_actions %}
9
9
  {% endif %}
@@ -12,7 +12,7 @@
12
12
  <span id="changelist-filter-extra-actions" class="flex flex-row gap-2 items-center mt-2">
13
13
  {% if cl.is_facets_optional %}
14
14
  {% if cl.add_facets %}
15
- <a href="{{ cl.remove_facet_link }}" class="hidelink border grow font-medium px-3 py-2 rounded-default text-center transition-all w-full hover:bg-base-50 lg:w-auto dark:border-base-700 dark:hover:text-base-200">
15
+ <a href="{{ cl.remove_facet_link }}" class="hidelink border border-base-200 grow font-medium px-3 py-2 rounded-default text-center transition-all w-full lg:w-auto dark:border-base-700 dark:hover:text-base-200">
16
16
  {% trans "Hide counts" %}
17
17
  </a>
18
18
  {% else %}
@@ -9,7 +9,7 @@
9
9
  {{ field.label|capfirst }}
10
10
 
11
11
  {% if field.help_text %}
12
- <span class="cursor-pointer material-symbols-outlined ml-2 text-base-400 dark:text-base-500" title="{{ field.help_text|striptags }}">help</span>
12
+ <span class="cursor-help material-symbols-outlined ml-2 text-base-400 dark:text-base-500" title="{{ field.help_text|striptags }}">help</span>
13
13
  {% endif %}
14
14
  </span>
15
15
  </th>
@@ -25,8 +25,8 @@
25
25
  {% endif %}
26
26
 
27
27
 
28
- {% if cl.has_filters %}
29
- <a href="{{ cl.clear_all_filters_qs }}" class="border border-base-200 flex flex-row font-medium gap-2 group/button h-[38px] items-center justify-center px-3 py-2 rounded-default w-full hover:text-primary-600 lg:w-auto dark:border-base-700 dark:hover:bg-base-900 dark:hover:text-primary-500">
28
+ {% if cl.has_filters or cl.query %}
29
+ <a href="?" class="border border-base-200 flex flex-row font-medium gap-2 group/button h-[38px] items-center justify-center px-3 py-2 rounded-default w-full hover:text-primary-600 lg:w-auto dark:border-base-700 dark:hover:bg-base-900 dark:hover:text-primary-500">
30
30
  <span class="material-symbols-outlined ml-1">filter_list_off</span> {% trans "Reset filters" %}
31
31
  </a>
32
32
  {% endif %}
@@ -13,10 +13,12 @@
13
13
  {% include "unfold/helpers/help_text.html" with help_text=field.help_text %}
14
14
  </div>
15
15
  {% else %}
16
- <div class="{% if field.errors %}errors {% endif %}flex flex-col gap-2 group mb-5 last:mb-4">
17
- {% include "unfold/helpers/form_label.html" with field=field %}
16
+ <div class="{% if field.errors %}errors {% endif %}flex flex-col group mb-5 last:mb-4">
17
+ <div class="flex flex-col gap-2">
18
+ {% include "unfold/helpers/form_label.html" with field=field %}
18
19
 
19
- {{ field }}
20
+ {{ field }}
21
+ </div>
20
22
 
21
23
  {% include "unfold/helpers/form_errors.html" with errors=field.errors %}
22
24
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  {% if not is_popup %}
4
4
  {% block header %}
5
- <div class="bg-white border-b border-base-200 mb-6 px-4 z-40 dark:bg-base-900 dark:border-base-800 {% element_classes 'header' %}">
5
+ <div class="bg-white border-b border-base-200 mb-6 px-4 z-40 dark:bg-base-900 dark:border-base-800 dark:text-font-default-dark {% element_classes 'header' %}">
6
6
  <div class="{% if not cl.model_admin.list_fullwidth %}container{% endif %} flex items-center h-16 mx-auto py-4">
7
7
  <div id="header-inner" class="flex items-center w-full">
8
8
  <div class="flex items-center w-full">
@@ -0,0 +1,10 @@
1
+ <form action="{% if languages_action %}{{ languages_action }}{% else %}{% url 'set_language' %}{% endif %}" method="post" class="flex w-full">
2
+ {% csrf_token %}
3
+
4
+ <input name="next" type="hidden" value="{{ redirect_to }}">
5
+ <input name="language" type="hidden" value="{{ language.code }}">
6
+
7
+ <button type="submit" class="block cursor-pointer grow mx-1 px-3 py-2 rounded-default text-left hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200 {% if language.code == LANGUAGE_CODE %}text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!{% endif %}">
8
+ {{ language.name_local }} ({{ language.code }})
9
+ </button>
10
+ </form>
@@ -4,24 +4,22 @@
4
4
  {% get_available_languages as LANGUAGES %}
5
5
  {% get_language_info_list for LANGUAGES as languages %}
6
6
 
7
+ {% if show_languages %}
8
+ <div class="relative" x-data="{ openLanguageLinks: false }">
9
+ <a class="block cursor-pointer h-[18px] hover:text-base-700 dark:hover:text-base-200" x-on:click="openLanguageLinks = !openLanguageLinks">
10
+ <span class="material-symbols-outlined">translate</span>
11
+ </a>
7
12
 
8
- <div class="relative" x-data="{ openLanguageLinks: false }">
9
- <a class="block cursor-pointer h-[18px] hover:text-base-700 dark:hover:text-base-200" x-on:click="openLanguageLinks = !openLanguageLinks">
10
- <span class="material-symbols-outlined">translate</span>
11
- </a>
12
-
13
- <div class="absolute bg-white border border-base-200 flex flex-col leading-none py-1 -right-2 rounded-default shadow-lg top-7 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openLanguageLinks" x-transition x-on:click.outside="openLanguageLinks = false">
14
- {% for language in languages %}
15
- <form action="{% url 'set_language' %}" method="post" class="flex w-full">
16
- {% csrf_token %}
17
-
18
- <input name="next" type="hidden" value="{{ redirect_to }}">
19
- <input name="language" type="hidden" value="{{ language.code }}">
20
-
21
- <button type="submit" class="block grow mx-1 px-3 py-2 rounded-default text-left hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200 {% if language.code == LANGUAGE_CODE %}text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!{% endif %}">
22
- {{ language.name_local }} ({{ language.code }})
23
- </button>
24
- </form>
25
- {% endfor %}
13
+ <div class="absolute bg-white border border-base-200 flex flex-col leading-none py-1 -right-2 rounded-default shadow-lg top-7 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openLanguageLinks" x-transition x-on:click.outside="openLanguageLinks = false">
14
+ {% if languages_list %}
15
+ {% for language in languages_list %}
16
+ {% include "unfold/helpers/language_form.html" with language=language %}
17
+ {% endfor %}
18
+ {% else %}
19
+ {% for language in languages %}
20
+ {% include "unfold/helpers/language_form.html" with language=language %}
21
+ {% endfor %}
22
+ {% endif %}
23
+ </div>
26
24
  </div>
27
- </div>
25
+ {% endif %}
@@ -1,6 +1,6 @@
1
1
  {% load i18n unfold %}
2
2
 
3
- <nav id="nav-sidebar-inner" class="bg-base-50 flex flex-col min-h-screen dark:bg-base-950/20 {% element_classes 'navigation_inner' %}">
3
+ <nav id="nav-sidebar-inner" class="bg-base-50 flex flex-col min-h-screen dark:text-font-default-dark dark:bg-base-950/20 {% element_classes 'navigation_inner' %}">
4
4
  {% include "unfold/helpers/navigation_header.html" %}
5
5
 
6
6
  {% include "unfold/helpers/search.html" %}
@@ -1,11 +1,11 @@
1
- {% load unfold_list i18n %}
1
+ {% load unfold unfold_list i18n %}
2
2
 
3
3
  <div class="flex flex-row gap-4">
4
- <a {% if cl.page_num != 1 %}href="?p={{ cl.page_num|add:-1 }}"{% endif %} class="{% if cl.page_num != 1 %}hover:text-primary-600 dark:hover:text-primary-500{% endif %}">
4
+ <a {% if cl.page_num != 1 %}href="{% infinite_paginator_url cl cl.page_num|add:-1 %}"{% endif %} class="{% if cl.page_num != 1 %}hover:text-primary-600 dark:hover:text-primary-500{% endif %}">
5
5
  {% trans "Previous" %}
6
6
  </a>
7
7
 
8
- <a href="?p={{ cl.page_num|add:1 }}" class="hover:text-primary-600 dark:hover:text-primary-500">
8
+ <a {% if cl.result_list|length %}href="{% infinite_paginator_url cl cl.page_num|add:1 %}"{% endif %} class="{% if cl.result_list|length %}hover:text-primary-600 dark:hover:text-primary-500{% endif %}">
9
9
  {% trans "Next" %}
10
10
  </a>
11
11
  </div>
@@ -0,0 +1,28 @@
1
+ {% load i18n admin_urls unfold %}
2
+
3
+ {% with page_obj=inline_admin_formset.formset.page has_tab=inline_admin_formset.opts.tab pagination_key=inline_admin_formset.formset.get_pagination_key %}
4
+ {% elided_page_range page_obj.paginator page_obj.number as elided_page_range %}
5
+ <input type="hidden" name="{{ inline_admin_formset.formset.get_pagination_key }}" value="{{ page_obj.number }}" />
6
+
7
+ {% if page_obj.paginator.count and page_obj.paginator.num_pages > 1%}
8
+ <div class="flex items-center gap-2 mb-6">
9
+ {% for i in elided_page_range %}
10
+ {% if i == page_obj.paginator.ELLIPSIS %}
11
+ <span>{{ page_obj.paginator.ELLIPSIS }}</span>
12
+ {% elif i == page_obj.number %}
13
+ <span class="font-medium text-primary-600">{{ i }}</span>
14
+ {% else %}
15
+ <a href="?{% querystring_params pagination_key i %}{% if has_tab %}#{{ inline_admin_formset.formset.prefix|slugify }}{% endif %}">
16
+ {{ i }}
17
+ </a>
18
+ {% endif %}
19
+ {% endfor %}
20
+
21
+ <div>-</div>
22
+
23
+ <div>
24
+ {{ page_obj.paginator.count }} {% if page_obj.paginator.count == 1 %}{{ inline_admin_formset.opts.verbose_name }}{% else %}{{ inline_admin_formset.opts.verbose_name_plural }}{% endif %}
25
+ </div>
26
+ </div>
27
+ {% endif %}
28
+ {% endwith %}