django-unfold 0.58.0__py3-none-any.whl → 0.59.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 (43) hide show
  1. {django_unfold-0.58.0.dist-info → django_unfold-0.59.0.dist-info}/METADATA +1 -1
  2. {django_unfold-0.58.0.dist-info → django_unfold-0.59.0.dist-info}/RECORD +43 -41
  3. unfold/checks.py +24 -2
  4. unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -2
  5. unfold/decorators.py +27 -13
  6. unfold/fields.py +1 -1
  7. unfold/forms.py +4 -2
  8. unfold/layout.py +16 -0
  9. unfold/mixins/action_model_admin.py +22 -14
  10. unfold/paginator.py +12 -1
  11. unfold/settings.py +8 -1
  12. unfold/sites.py +24 -0
  13. unfold/static/admin/js/admin/RelatedObjectLookups.js +9 -3
  14. unfold/static/unfold/css/styles.css +1 -1
  15. unfold/styles.css +9 -13
  16. unfold/templates/admin/base.html +1 -1
  17. unfold/templates/admin/change_form.html +2 -1
  18. unfold/templates/admin/edit_inline/stacked.html +1 -1
  19. unfold/templates/admin/includes/fieldset.html +9 -3
  20. unfold/templates/admin/login.html +1 -1
  21. unfold/templates/admin/pagination.html +1 -1
  22. unfold/templates/unfold/components/button.html +1 -1
  23. unfold/templates/unfold/helpers/account_links.html +14 -6
  24. unfold/templates/unfold/helpers/change_list_actions.html +2 -2
  25. unfold/templates/unfold/helpers/change_list_filter_actions.html +1 -1
  26. unfold/templates/unfold/helpers/edit_inline/tabular_heading.html +1 -1
  27. unfold/templates/unfold/helpers/empty_results.html +2 -2
  28. unfold/templates/unfold/helpers/header.html +1 -1
  29. unfold/templates/unfold/helpers/language_form.html +10 -0
  30. unfold/templates/unfold/helpers/language_switch.html +17 -19
  31. unfold/templates/unfold/helpers/navigation.html +1 -1
  32. unfold/templates/unfold/helpers/pagination_infinite.html +3 -3
  33. unfold/templates/unfold/helpers/theme_switch.html +29 -27
  34. unfold/templates/unfold/helpers/userlinks.html +2 -6
  35. unfold/templates/unfold/helpers/welcomemsg.html +9 -7
  36. unfold/templates/unfold/widgets/select.html +1 -1
  37. unfold/templates/unfold_crispy/layout/fieldset.html +3 -1
  38. unfold/templates/unfold_crispy/layout/fieldset_subheader.html +3 -0
  39. unfold/templatetags/unfold.py +6 -1
  40. unfold/utils.py +2 -2
  41. unfold/widgets.py +8 -2
  42. {django_unfold-0.58.0.dist-info → django_unfold-0.59.0.dist-info}/LICENSE.md +0 -0
  43. {django_unfold-0.58.0.dist-info → django_unfold-0.59.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 {
@@ -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,7 +17,7 @@
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 *:border-t first-of-type:border-t-0 *:border-base-200 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 %}>
@@ -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="bg-base-50 border-b border-base-200 border-t border-dashed font-semibold text-font-important-light px-3 py-2 dark:text-font-important-dark dark:bg-white/[.02] 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 %}
@@ -63,7 +63,7 @@
63
63
  {% url 'admin_password_reset' as password_reset_url %}
64
64
 
65
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">
66
+ <button type="submit" class="bg-primary-600 border border-transparent cursor-pointer flex flex-row font-semibold group items-center justify-center py-2 rounded-default text-sm text-white w-full">
67
67
  {% translate 'Log in' %}
68
68
 
69
69
  <span class="material-symbols-outlined ml-2 relative right-0 text-base transition-all group-hover:-right-1">arrow_forward</span>
@@ -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,4 @@
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="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 text-font-important-light dark:border-base-700 dark:bg-transparent dark:text-font-important-dark{% else %}bg-primary-600 border-transparent text-white{% endif %}{% if class %} {{ class }}{% endif %}" {% include "unfold/helpers/attrs.html" %}>
3
3
  {{ children }}
4
4
  </{% 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>
@@ -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 %}
@@ -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>
@@ -1,32 +1,34 @@
1
1
  {% load i18n %}
2
2
 
3
- <div class="relative" x-data="{ openTheme: false }">
4
- <a class="block cursor-pointer h-[18px] leading-none hover:text-base-700 dark:hover:text-base-200" x-on:click="openTheme = !openTheme">
5
- <span class="material-symbols-outlined">
6
- <span x-text="adminTheme == 'dark' && 'dark_mode' || adminTheme == 'light' && 'light_mode' || 'computer'"></span>
7
- </span>
8
- </a>
9
-
10
- <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-40 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openTheme" x-transition x-on:click.outside="openTheme = false">
11
- <a class="cursor-pointer flex flex-row leading-none mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
12
- x-on:click="adminTheme = 'dark'"
13
- x-bind:class="adminTheme == 'dark' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
14
- <span class="material-symbols-outlined mr-2">dark_mode</span>
15
- <span class="leading-none self-center">{% trans "Dark" %}</span>
3
+ {% if not theme %}
4
+ <div class="relative" x-data="{ openTheme: false }">
5
+ <a class="block cursor-pointer h-[18px] leading-none hover:text-base-700 dark:hover:text-base-200" x-on:click="openTheme = !openTheme">
6
+ <span class="material-symbols-outlined">
7
+ <span x-text="adminTheme == 'dark' && 'dark_mode' || adminTheme == 'light' && 'light_mode' || 'computer'"></span>
8
+ </span>
16
9
  </a>
17
10
 
18
- <a class="cursor-pointer flex flex-row mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
19
- x-on:click="adminTheme = 'light'"
20
- x-bind:class="adminTheme == 'light' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
21
- <span class="material-symbols-outlined mr-2">light_mode</span>
22
- <span class="leading-none self-center">{% trans "Light" %}</span>
23
- </a>
11
+ <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-40 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openTheme" x-transition x-on:click.outside="openTheme = false">
12
+ <a class="cursor-pointer flex flex-row leading-none mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
13
+ x-on:click="adminTheme = 'dark'"
14
+ x-bind:class="adminTheme == 'dark' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
15
+ <span class="material-symbols-outlined mr-2">dark_mode</span>
16
+ <span class="leading-none self-center">{% trans "Dark" %}</span>
17
+ </a>
24
18
 
25
- <a class="cursor-pointer flex flex-row mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
26
- x-on:click="adminTheme = 'auto'"
27
- x-bind:class="adminTheme == 'auto' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
28
- <span class="material-symbols-outlined mr-2">computer</span>
29
- <span class="leading-none self-center">{% trans "System" %}</span>
30
- </a>
31
- </nav>
32
- </div>
19
+ <a class="cursor-pointer flex flex-row mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
20
+ x-on:click="adminTheme = 'light'"
21
+ x-bind:class="adminTheme == 'light' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
22
+ <span class="material-symbols-outlined mr-2">light_mode</span>
23
+ <span class="leading-none self-center">{% trans "Light" %}</span>
24
+ </a>
25
+
26
+ <a class="cursor-pointer flex flex-row mx-1 px-3 py-1.5 rounded-default hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
27
+ x-on:click="adminTheme = 'auto'"
28
+ x-bind:class="adminTheme == 'auto' && 'text-primary-600 dark:text-primary-500 dark:hover:text-primary-500! hover:text-primary-600!'">
29
+ <span class="material-symbols-outlined mr-2">computer</span>
30
+ <span class="leading-none self-center">{% trans "System" %}</span>
31
+ </a>
32
+ </nav>
33
+ </div>
34
+ {% endif %}
@@ -11,13 +11,9 @@
11
11
  {{ extra_userlinks }}
12
12
  {% endif %}
13
13
 
14
- {% if show_languages %}
15
- {% include "unfold/helpers/language_switch.html" %}
16
- {% endif %}
14
+ {% include "unfold/helpers/language_switch.html" %}
17
15
 
18
- {% if not theme %}
19
- {% include "unfold/helpers/theme_switch.html" %}
20
- {% endif %}
16
+ {% include "unfold/helpers/theme_switch.html" %}
21
17
 
22
18
  {% include "unfold/helpers/account_links.html" %}
23
19
  </div>
@@ -1,15 +1,17 @@
1
1
  {% load unfold i18n %}
2
2
 
3
3
  <div class="flex flex-row grow font-semibold items-center min-w-0 mr-3">
4
- <span class="cursor-pointer flex flex-row items-center">
5
- <span class="material-symbols-outlined hidden! xl:block!" hx-get="{% url "admin:toggle_sidebar" %}" hx-swap="none" x-on:click="sidebarDesktopOpen = !sidebarDesktopOpen">
6
- dock_to_right
7
- </span>
4
+ {% if is_nav_sidebar_enabled %}
5
+ <span class="cursor-pointer flex flex-row items-center">
6
+ <span class="material-symbols-outlined hidden! xl:block!" hx-get="{% url "admin:toggle_sidebar" %}" hx-swap="none" x-on:click="sidebarDesktopOpen = !sidebarDesktopOpen">
7
+ dock_to_right
8
+ </span>
8
9
 
9
- <span class="material-symbols-outlined block! xl:hidden!" x-on:click="sidebarMobileOpen = !sidebarMobileOpen">
10
- dock_to_right
10
+ <span class="material-symbols-outlined block! xl:hidden!" x-on:click="sidebarMobileOpen = !sidebarMobileOpen">
11
+ dock_to_right
12
+ </span>
11
13
  </span>
12
- </span>
14
+ {% endif %}
13
15
 
14
16
  <span class="block bg-base-200 h-5 mx-3 w-px dark:bg-base-700"></span>
15
17
 
@@ -5,5 +5,5 @@
5
5
  </optgroup>{% endif %}{% endfor %}
6
6
  </select>
7
7
 
8
- <span class="material-symbols-outlined absolute group-[.primary]:text-white -ml-[31px] pointer-events-none text-base-400 top-0 top-1/2 hover:text-base-700 dark:text-base-500 dark:hover:text-base-200 -translate-y-1/2">expand_more</span>
8
+ <span class="material-symbols-outlined absolute group-[.primary]:text-white pointer-events-none mr-[12px] right-0 text-base-400 top-0 top-1/2 hover:text-base-700 dark:text-base-500 dark:hover:text-base-200 -translate-y-1/2">expand_more</span>
9
9
  </div>
@@ -5,5 +5,7 @@
5
5
  </legend>
6
6
  {% endif %}
7
7
 
8
- {{ fields|safe }}
8
+ <div class="flex flex-col gap-5">
9
+ {{ fields|safe }}
10
+ </div>
9
11
  </fieldset>
@@ -0,0 +1,3 @@
1
+ <div class="border-b border-t border-base-200 font-semibold -mx-3 py-2.5 px-3 text-font-important-light first:border-t-0 first:-mt-5 dark:border-base-800 dark:text-font-important-dark">
2
+ {{ title }}
3
+ </div>
@@ -4,7 +4,7 @@ from typing import Any, Optional, Union
4
4
 
5
5
  from django import template
6
6
  from django.contrib.admin.helpers import AdminForm, Fieldset
7
- from django.contrib.admin.views.main import ChangeList
7
+ from django.contrib.admin.views.main import PAGE_VAR, ChangeList
8
8
  from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
9
9
  from django.db.models import Model
10
10
  from django.db.models.options import Options
@@ -569,3 +569,8 @@ def changeform_condition(field: BoundField) -> BoundField:
569
569
  field.field.field.widget.attrs["x-model.fill"] = field.field.name
570
570
 
571
571
  return field
572
+
573
+
574
+ @register.simple_tag
575
+ def infinite_paginator_url(cl, i):
576
+ return cl.get_query_string({PAGE_VAR: i})
unfold/utils.py CHANGED
@@ -150,7 +150,7 @@ def hex_to_rgb(hex_color: str) -> list[int]:
150
150
  return (r, g, b)
151
151
 
152
152
 
153
- def prettify_json(data: Any) -> Optional[str]:
153
+ def prettify_json(data: Any, encoder: Any) -> Optional[str]:
154
154
  try:
155
155
  from pygments import highlight
156
156
  from pygments.formatters import HtmlFormatter
@@ -167,7 +167,7 @@ def prettify_json(data: Any) -> Optional[str]:
167
167
  )
168
168
  return highlight(response, JsonLexer(), formatter)
169
169
 
170
- response = json.dumps(data, sort_keys=True, indent=4)
170
+ response = json.dumps(data, sort_keys=True, indent=4, cls=encoder)
171
171
 
172
172
  return mark_safe(
173
173
  f'<div class="block dark:hidden">{format_response(response, "colorful")}</div>'
unfold/widgets.py CHANGED
@@ -123,9 +123,10 @@ TEXTAREA_EXPANDABLE_CLASSES = [
123
123
 
124
124
  SELECT_CLASSES = [
125
125
  *BASE_INPUT_CLASSES,
126
- "pr-8",
126
+ "pr-8!",
127
127
  "max-w-2xl",
128
128
  "appearance-none",
129
+ "truncate",
129
130
  ]
130
131
 
131
132
  PROSE_CLASSES = [
@@ -759,8 +760,13 @@ try:
759
760
  template_name = "unfold/widgets/split_money.html"
760
761
 
761
762
  def __init__(self, *args, **kwargs):
763
+ if "attrs" in kwargs:
764
+ attrs = kwargs.pop("attrs")
765
+ else:
766
+ attrs = {}
767
+
762
768
  super().__init__(
763
- amount_widget=UnfoldAdminTextInputWidget,
769
+ amount_widget=UnfoldAdminTextInputWidget(attrs=attrs),
764
770
  currency_widget=UnfoldAdminSelectWidget(
765
771
  choices=CURRENCY_CHOICES,
766
772
  attrs={