django-unfold 0.47.0__py3-none-any.whl → 0.49.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 (37) hide show
  1. {django_unfold-0.47.0.dist-info → django_unfold-0.49.0.dist-info}/METADATA +1 -1
  2. {django_unfold-0.47.0.dist-info → django_unfold-0.49.0.dist-info}/RECORD +37 -31
  3. unfold/admin.py +17 -412
  4. unfold/dataclasses.py +8 -0
  5. unfold/decorators.py +14 -1
  6. unfold/fields.py +6 -5
  7. unfold/mixins/__init__.py +4 -0
  8. unfold/mixins/action_model_admin.py +329 -0
  9. unfold/mixins/base_model_admin.py +110 -0
  10. unfold/overrides.py +73 -0
  11. unfold/settings.py +2 -0
  12. unfold/sites.py +25 -5
  13. unfold/static/unfold/css/styles.css +1 -1
  14. unfold/static/unfold/fonts/inter/Inter-Bold.woff2 +0 -0
  15. unfold/static/unfold/fonts/inter/Inter-Medium.woff2 +0 -0
  16. unfold/static/unfold/fonts/inter/Inter-Regular.woff2 +0 -0
  17. unfold/static/unfold/fonts/inter/Inter-SemiBold.woff2 +0 -0
  18. unfold/templates/admin/app_index.html +1 -5
  19. unfold/templates/admin/base_site.html +1 -1
  20. unfold/templates/admin/index.html +1 -5
  21. unfold/templates/admin/login.html +1 -1
  22. unfold/templates/admin/search_form.html +4 -2
  23. unfold/templates/admin/submit_line.html +7 -1
  24. unfold/templates/unfold/helpers/account_links.html +1 -1
  25. unfold/templates/unfold/helpers/actions_row.html +14 -4
  26. unfold/templates/unfold/helpers/language_switch.html +1 -1
  27. unfold/templates/unfold/helpers/navigation_header.html +18 -5
  28. unfold/templates/unfold/helpers/site_branding.html +9 -0
  29. unfold/templates/unfold/helpers/site_dropdown.html +19 -0
  30. unfold/templates/unfold/helpers/site_icon.html +20 -10
  31. unfold/templates/unfold/helpers/tab_action.html +35 -2
  32. unfold/templates/unfold/helpers/theme_switch.html +1 -1
  33. unfold/templates/unfold/layouts/base.html +1 -5
  34. unfold/typing.py +2 -1
  35. unfold/widgets.py +2 -0
  36. {django_unfold-0.47.0.dist-info → django_unfold-0.49.0.dist-info}/LICENSE.md +0 -0
  37. {django_unfold-0.47.0.dist-info → django_unfold-0.49.0.dist-info}/WHEEL +0 -0
@@ -25,11 +25,7 @@
25
25
  {% endif %}
26
26
 
27
27
  {% block branding %}
28
- <h1 id="site-name">
29
- <a href="{% url 'admin:index' %}">
30
- {{ site_header|default:_('Django administration') }}
31
- </a>
32
- </h1>
28
+ {% include "unfold/helpers/site_branding.html" %}
33
29
  {% endblock %}
34
30
 
35
31
  {% block content %}
@@ -3,7 +3,7 @@
3
3
  {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
4
4
 
5
5
  {% block branding %}
6
- <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
6
+ {% include "unfold/helpers/site_branding.html" %}
7
7
  {% endblock %}
8
8
 
9
9
  {% block nav-global %}{% endblock %}
@@ -7,11 +7,7 @@
7
7
  {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
8
8
 
9
9
  {% block branding %}
10
- <h1 id="site-name">
11
- <a href="{% url 'admin:index' %}">
12
- {{ site_header|default:_('Django administration') }}
13
- </a>
14
- </h1>
10
+ {% include "unfold/helpers/site_branding.html" %}
15
11
  {% endblock %}
16
12
 
17
13
  {% block content %}
@@ -29,7 +29,7 @@
29
29
  <div class="w-full sm:w-96">
30
30
  <h1 class="font-semibold mb-10">
31
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 }}</span>
32
+ <span class="block text-primary-600 text-xl dark:text-primary-500">{{ site_title|default:_('Django site admin') }}</span>
33
33
  </h1>
34
34
 
35
35
  {% include "unfold/helpers/messages.html" %}
@@ -11,8 +11,10 @@
11
11
  </button>
12
12
  </div>
13
13
 
14
- {% for pair in cl.params.items %}
15
- {% if pair.0 != search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}">{% endif %}
14
+ {% for pair in cl.filter_params.items %}
15
+ {% for val in pair.1 %}
16
+ {% if pair.0 != search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ val }}">{% endif %}
17
+ {% endfor %}
16
18
  {% endfor %}
17
19
  </form>
18
20
  </div>
@@ -12,7 +12,13 @@
12
12
  {% endif %}
13
13
 
14
14
  {% for action in actions_submit_line %}
15
- <button type="submit" {% if not action.attrs.name %}name="{{ action.action_name }}"{% endif %} class="border border-base-200 font-medium px-3 py-2 rounded transition-all w-full hover:bg-base-50 lg:w-auto dark:border-base-700 dark:hover:text-base-200 dark:hover:bg-base-900" {% include "unfold/helpers/attrs.html" with attrs=action.attrs %}>
15
+ <button type="submit" {% if not action.attrs.name %}name="{{ action.action_name }}"{% endif %} class="border border-base-200 flex font-medium gap-2 items-center px-3 py-2 rounded transition-all w-full hover:bg-base-50 lg:w-auto dark:border-base-700 dark:hover:text-base-200 dark:hover:bg-base-900" {% include "unfold/helpers/attrs.html" with attrs=action.attrs %}>
16
+ {% if action.icon %}
17
+ <span class="material-symbols-outlined">
18
+ {{ action.icon }}
19
+ </span>
20
+ {% endif %}
21
+
16
22
  {{ action.description }}
17
23
  </button>
18
24
  {% endfor %}
@@ -5,7 +5,7 @@
5
5
  <span class="material-symbols-outlined">person</span>
6
6
  </a>
7
7
 
8
- <nav class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded shadow-lg top-7 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openUserLinks" @click.outside="openUserLinks = false">
8
+ <nav class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded 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
9
  <div class="border-b border-base-100 flex flex-row flex-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 %}
@@ -4,15 +4,25 @@
4
4
  <td data-label="{% trans "More actions" %}" class="field-actions_holder align-middle flex border-t border-base-200 font-normal px-3 py-2 text-left text-sm before:block before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-base-500 dark:before:text-base-300 lg:before:hidden lg:py-3 lg:table-cell dark:border-base-800 lg:w-px">
5
5
  {% with action_id=instance_pk|cut:"-" %}
6
6
  <div class="group/action leading-none relative" x-data="{ openActionsId{{ action_id }}: false }">
7
- <span x-ref="rowDropdown{{ action_id }}" class="cursor-pointer flex h-7 material-symbols-outlined md-18 -my-1 !leading-7 rounded text-center text-base-400 w-7 group-hover/action:bg-base-100 group-hover/action:text-base-700 dark:text-font-default-dark group-hover/action:dark:bg-base-800 group-hover/action:dark:text-white" @click="openActionsId{{ action_id }} = !openActionsId{{ action_id }}">
7
+ <span x-ref="rowDropdown{{ action_id }}" class="cursor-pointer flex h-7 material-symbols-outlined md-18 -my-1 !leading-7 rounded text-center text-base-400 w-7 group-hover/action:bg-base-100 group-hover/action:text-base-700 dark:text-font-default-dark group-hover/action:dark:bg-base-800 group-hover/action:dark:text-white"
8
+ x-on:click="openActionsId{{ action_id }} = !openActionsId{{ action_id }}"
9
+ x-bind:class="{'bg-base-100 text-base-700 dark:bg-base-800 dark:text-white': openActionsId{{ action_id }} }">
8
10
  more_horiz
9
11
  </span>
10
12
 
11
13
  <template x-teleport="body">
12
- <nav x-anchor.bottom-end.offset.4="$refs.rowDropdown{{ action_id }}" class="bg-white border flex flex-col leading-none py-1 rounded shadow-lg text-sm top-7 z-50 w-48 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openActionsId{{ action_id }}" @click.outside="openActionsId{{ action_id }} = false">
14
+ <nav x-anchor.bottom-end.offset.4="$refs.rowDropdown{{ action_id }}" class="bg-white border flex flex-col py-1 rounded shadow-lg text-sm top-7 z-50 w-48 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openActionsId{{ action_id }}" x-transition x-on:click.outside="openActionsId{{ action_id }} = false">
13
15
  {% for action in actions %}
14
- <a href="{% url action.raw_path instance_pk %}" class="mx-1 px-3 py-2 rounded truncate hover:bg-base-100 dark:hover:bg-base-700 dark:hover:text-base-200"{% for attr_name, attr_value in action.attrs.items %} {{ attr_name }}="{{ attr_value }}"{% endfor %}>
15
- {{ action.title }}
16
+ <a href="{% url action.raw_path instance_pk %}" class="flex items-center gap-2 mx-1 px-3 py-2 max-h-[30px] rounded hover:bg-base-100 dark:hover:bg-base-700 dark:hover:text-base-200"{% for attr_name, attr_value in action.attrs.items %} {{ attr_name }}="{{ attr_value }}"{% endfor %}>
17
+ {% if action.icon %}
18
+ <span class="material-symbols-outlined">
19
+ {{ action.icon }}
20
+ </span>
21
+ {% endif %}
22
+
23
+ <span class="grow truncate">
24
+ {{ action.title }}
25
+ </span>
16
26
  </a>
17
27
  {% endfor %}
18
28
  </nav>
@@ -10,7 +10,7 @@
10
10
  <span class="material-symbols-outlined">translate</span>
11
11
  </a>
12
12
 
13
- <div class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded shadow-lg top-7 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openLanguageLinks" @click.outside="openLanguageLinks = false">
13
+ <div class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded 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
14
  {% for language in languages %}
15
15
  <form action="{% url 'set_language' %}" method="post" class="flex w-full">
16
16
  {% csrf_token %}
@@ -1,13 +1,26 @@
1
- <div class="border-b border-base-200 mb-5 py-3 dark:border-base-800">
2
- <div class="flex font-semibold gap-3 h-10 items-center px-6">
1
+ <div class="border-b border-base-200 flex gap-3 items-center h-[65px] mb-5 dark:border-base-800 px-3" {% if site_dropdown %}x-data="{ openDropdown: false }"{% endif %}>
2
+ <div class="bg-transparent border border-transparent flex font-semibold gap-3 grow min-w-0 -mx-px h-[48px] items-center px-3 {% if site_dropdown %}cursor-pointer rounded transition-all hover:bg-white hover:border-base-200 hover:shadow-sm hover:dark:bg-base-800 hover:dark:border-base-700{% endif %}"
3
+ {% if site_dropdown %}
4
+ x-on:click="openDropdown = !openDropdown"
5
+ x-bind:class="{'bg-white border-base-200 shadow-sm dark:bg-base-800 dark:border-base-700': openDropdown, 'bg-transparent border-transparent': !openDropdown}"
6
+ {% endif %}
7
+ >
3
8
  {% if site_logo %}
4
9
  {% include "unfold/helpers/site_logo.html" %}
5
10
  {% elif branding %}
6
11
  {% include "unfold/helpers/site_icon.html" %}
7
12
  {% endif %}
8
13
 
9
- <div class="block cursor-pointer h-4.5 ml-auto xl:!hidden hover:text-base-700 dark:hover:text-base-200" x-on:click="sidebarMobileOpen = !sidebarMobileOpen">
10
- <span class="material-symbols-outlined">close</span>
11
- </div>
14
+ {% if site_dropdown %}
15
+ <span class="material-symbols-outlined ml-auto select-none">
16
+ unfold_more
17
+ </span>
18
+ {% endif %}
12
19
  </div>
20
+
21
+ <span class="material-symbols-outlined block cursor-pointer h-4.5 xl:!hidden hover:text-base-700 dark:hover:text-base-200" x-on:click="sidebarMobileOpen = !sidebarMobileOpen">
22
+ close
23
+ </span>
24
+
25
+ {% include "unfold/helpers/site_dropdown.html" %}
13
26
  </div>
@@ -0,0 +1,9 @@
1
+ <h1 id="site-name">
2
+ {% if site_dropdown %}
3
+ {{ site_header|default:_('Django administration') }}
4
+ {% else %}
5
+ <a href="{% url 'admin:index' %}">
6
+ {{ site_header|default:_('Django administration') }}
7
+ </a>
8
+ {% endif %}
9
+ </h1>
@@ -0,0 +1,19 @@
1
+ {% load i18n %}
2
+
3
+ {% if site_dropdown %}
4
+ <div class="absolute bg-white border flex flex-col left-3 py-1 rounded shadow-lg top-[73px] w-[264px] z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openDropdown" x-transition x-on:click.outside="openDropdown = false">
5
+ {% for item in site_dropdown %}
6
+ <a href="{{ item.link }}" class="flex flex-row items-center gap-3 max-h-[30px] mx-1 px-2 py-2 rounded hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200">
7
+ {% if item.icon %}
8
+ <span class="material-symbols-outlined">
9
+ {{ item.icon }}
10
+ </span>
11
+ {% endif %}
12
+
13
+ <span class="grow truncate">
14
+ {{ item.title }}
15
+ </span>
16
+ </a>
17
+ {% endfor %}
18
+ </div>
19
+ {% endif %}
@@ -1,21 +1,31 @@
1
1
  {% load i18n %}
2
2
 
3
3
  {% if site_icon %}
4
- <a href="{% url "admin:index" %}">
5
- {% if site_icon.light and site_icon.dark %}
6
- <img src="{{ site_icon.dark }}" alt="{% trans 'Home' %}" class="h-8 hidden dark:block"/>
4
+ <div class="shrink-0">
5
+ <a href="{% url "admin:index" %}">
6
+ {% if site_icon.light and site_icon.dark %}
7
+ <img src="{{ site_icon.dark }}" alt="{% trans 'Home' %}" class="h-8 hidden dark:block"/>
7
8
 
8
- <img src="{{ site_icon.light }}" alt="{% trans 'Home' %}" class="block h-8 dark:hidden" />
9
- {% else %}
10
- <img src="{{ site_icon }}" class="h-8" alt="{% trans 'Home' %}" />
11
- {% endif %}
12
- </a>
9
+ <img src="{{ site_icon.light }}" alt="{% trans 'Home' %}" class="block h-8 dark:hidden" />
10
+ {% else %}
11
+ <img src="{{ site_icon }}" class="h-8" alt="{% trans 'Home' %}" />
12
+ {% endif %}
13
+ </a>
14
+ </div>
13
15
  {% else %}
14
16
  <a href="{% url "admin:index" %}" class="bg-primary-600 flex h-8 items-center justify-center rounded text-white text-xs w-8">
15
17
  <span class="material-symbols-outlined md-18">{% if site_symbol %}{{ site_symbol }}{% else %}settings{% endif %}</span>
16
18
  </a>
17
19
  {% endif %}
18
20
 
19
- <div class="text-font-important-light tracking-tight dark:text-font-important-dark xl:text-base">
20
- {{ branding }}
21
+ <div class="flex flex-col grow min-w-0">
22
+ <div class="text-font-important-light leading-normal tracking-tight dark:text-font-important-dark *:leading-none {% if site_subheader %}xl:text-sm{% else %}xl:text-base{% endif %}">
23
+ {{ branding }}
24
+ </div>
25
+
26
+ {% if site_subheader %}
27
+ <div class="font-normal leading-normal text-font-subtle-light text-xs truncate dark:text-font-subtle-dark">
28
+ {{ site_subheader }}
29
+ </div>
30
+ {% endif %}
21
31
  </div>
@@ -1,5 +1,38 @@
1
- <li class="border-b flex-grow text-center md:border-b-0 md:border-r last:border-0 dark:border-base-700">
2
- <a href="{{ link }}" class="block px-4 py-2 text-left whitespace-nowrap hover:text-primary-600 dark:hover:text-primary-500"{% if blank %} target="_blank"{% endif %} {% include "unfold/helpers/attrs.html" with attrs=action.attrs %}>
1
+ {% load unfold %}
2
+
3
+ <li class="border-b flex-grow relative text-center md:border-b-0 md:border-r last:border-0 dark:border-base-700" {% if not link %}x-data="{actionDropdownOpen: false}"{% endif %}>
4
+ <a {% if link %}href="{{ link }}"{% endif %}class="cursor-pointer flex items-center gap-2 px-4 py-2 text-left whitespace-nowrap hover:text-primary-600 dark:hover:text-primary-500"{% if blank %} target="_blank"{% endif %} {% include "unfold/helpers/attrs.html" with attrs=action.attrs %} {% if not link %}x-on:click="actionDropdownOpen = !actionDropdownOpen" x-bind:class="{'text-primary-600 dark:text-primary-500': actionDropdownOpen }"{% endif %}>
5
+
6
+ {% if action.icon %}
7
+ <span class="material-symbols-outlined -ml-1">
8
+ {{ action.icon }}
9
+ </span>
10
+ {% endif %}
11
+
3
12
  {{ title }}
13
+
14
+ {% if not link %}
15
+ <span class="material-symbols-outlined -mr-1 rotate-90">
16
+ chevron_right
17
+ </span>
18
+ {% endif %}
4
19
  </a>
20
+
21
+ {% if not link %}
22
+ <nav class="absolute bg-white border flex flex-col -mr-px py-1 right-0 rounded shadow-lg top-10 w-52 z-50 dark:bg-base-800 dark:border-base-700" x-transition x-show="actionDropdownOpen" x-on:click.outside="actionDropdownOpen = false">
23
+ {% for item in action.items %}
24
+ <a href="{{ item.path }}" class="flex items-center font-normal gap-2 max-h-[30px] mx-1 px-3 py-2 rounded text-left hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"{% if blank %} target="_blank"{% endif %} {% include "unfold/helpers/attrs.html" with attrs=action.attrs %}>
25
+ {% if item.icon %}
26
+ <span class="material-symbols-outlined -ml-1">
27
+ {{ item.icon }}
28
+ </span>
29
+ {% endif %}
30
+
31
+ <span class="grow truncate">
32
+ {{ item.title }}
33
+ </span>
34
+ </a>
35
+ {% endfor %}
36
+ </nav>
37
+ {% endif %}
5
38
  </li>
@@ -7,7 +7,7 @@
7
7
  </span>
8
8
  </a>
9
9
 
10
- <nav class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded shadow-lg top-7 w-40 z-50 dark:bg-base-800 dark:border-base-700" x-cloak x-show="openTheme" @click.outside="openTheme = false">
10
+ <nav class="absolute bg-white border flex flex-col leading-none py-1 -right-2 rounded 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
11
  <a class="cursor-pointer flex flex-row leading-none mx-1 px-3 py-1.5 rounded hover:bg-base-100 hover:text-base-700 dark:hover:bg-base-700 dark:hover:text-base-200"
12
12
  x-on:click="adminTheme = 'dark'"
13
13
  x-bind:class="adminTheme == 'dark' && 'text-primary-600 dark:text-primary-500 dark:hover:!text-primary-500 hover:!text-primary-600'">
@@ -1,11 +1,7 @@
1
1
  {% extends "unfold/layouts/base_simple.html" %}
2
2
 
3
3
  {% block branding %}
4
- <h1 id="site-name">
5
- <a href="{% url 'admin:index' %}">
6
- {{ site_header|default:_('Django administration') }}
7
- </a>
8
- </h1>
4
+ {% include "unfold/helpers/site_branding.html" %}
9
5
  {% endblock %}
10
6
 
11
7
  {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
unfold/typing.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Iterable
2
- from typing import Any, Protocol, Union
2
+ from typing import Any, Optional, Protocol, Union
3
3
 
4
4
 
5
5
  class ActionFunction(Protocol):
@@ -13,6 +13,7 @@ class ActionFunction(Protocol):
13
13
  short_description: str
14
14
  url_path: str
15
15
  attrs: dict[str, Any]
16
+ icon: Optional[str] = None
16
17
 
17
18
  def __call__(self, *args, **kwargs):
18
19
  pass
unfold/widgets.py CHANGED
@@ -177,7 +177,9 @@ CHECKBOX_CLASSES = [
177
177
  "after:w-4",
178
178
  "after:dark:text-base-700",
179
179
  "checked:bg-primary-600",
180
+ "checked:dark:bg-primary-600",
180
181
  "checked:border-primary-600",
182
+ "checked:dark:border-primary-600",
181
183
  "checked:transition-all",
182
184
  "checked:hover:border-primary-600",
183
185
  ]