django-unfold 0.47.0__py3-none-any.whl → 0.49.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
  ]