django-unfold 0.30.0__py3-none-any.whl → 0.31.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {django_unfold-0.30.0.dist-info → django_unfold-0.31.0.dist-info}/METADATA +59 -18
- {django_unfold-0.30.0.dist-info → django_unfold-0.31.0.dist-info}/RECORD +72 -71
- unfold/admin.py +30 -11
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +3 -3
- unfold/contrib/forms/templates/unfold/forms/array.html +3 -1
- unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +6 -6
- unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +1 -1
- unfold/contrib/forms/widgets.py +22 -11
- unfold/contrib/guardian/templates/unfold/guardian/group_form.html +4 -4
- unfold/contrib/guardian/templates/unfold/guardian/user_form.html +4 -4
- unfold/contrib/import_export/templates/admin/import_export/change_form.html +1 -1
- unfold/contrib/import_export/templates/admin/import_export/import_errors.html +1 -1
- unfold/contrib/import_export/templates/admin/import_export/import_preview.html +3 -3
- unfold/contrib/import_export/templates/admin/import_export/import_validation.html +4 -4
- unfold/contrib/inlines/forms.py +1 -2
- unfold/contrib/simple_history/templates/simple_history/object_history_list.html +9 -9
- unfold/contrib/simple_history/templates/simple_history/submit_line.html +1 -1
- unfold/dataclasses.py +10 -1
- unfold/fields.py +1 -1
- unfold/settings.py +1 -0
- unfold/sites.py +39 -15
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/alpine.anchor.js +1 -0
- unfold/static/unfold/js/alpine.js +2 -2
- unfold/static/unfold/js/alpine.persist.js +1 -1
- unfold/static/unfold/js/app.js +26 -3
- unfold/styles.css +10 -10
- unfold/templates/admin/actions.html +1 -1
- unfold/templates/admin/app_list.html +1 -1
- unfold/templates/admin/base.html +4 -4
- unfold/templates/admin/change_list.html +2 -2
- unfold/templates/admin/change_list_results.html +2 -2
- unfold/templates/admin/delete_confirmation.html +4 -4
- unfold/templates/admin/delete_selected_confirmation.html +4 -4
- unfold/templates/admin/edit_inline/stacked.html +2 -2
- unfold/templates/admin/edit_inline/tabular.html +3 -3
- unfold/templates/admin/filter.html +2 -2
- unfold/templates/admin/includes/fieldset.html +1 -1
- unfold/templates/admin/includes/object_delete_summary.html +1 -1
- unfold/templates/admin/login.html +8 -8
- unfold/templates/admin/object_history.html +4 -4
- unfold/templates/admin/search_form.html +1 -1
- unfold/templates/admin/submit_line.html +7 -5
- unfold/templates/auth/widgets/read_only_password_hash.html +1 -1
- unfold/templates/registration/logged_out.html +1 -1
- unfold/templates/unfold/change_list_filter.html +9 -1
- unfold/templates/unfold/helpers/account_links.html +2 -2
- unfold/templates/unfold/helpers/actions_row.html +4 -4
- unfold/templates/unfold/helpers/app_list.html +48 -38
- unfold/templates/unfold/helpers/app_list_default.html +4 -4
- unfold/templates/unfold/helpers/breadcrumb_item.html +1 -1
- unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
- unfold/templates/unfold/helpers/fieldset_row.html +6 -6
- unfold/templates/unfold/helpers/fieldsets_tabs.html +2 -2
- unfold/templates/unfold/helpers/header.html +1 -1
- unfold/templates/unfold/helpers/help_text.html +1 -1
- unfold/templates/unfold/helpers/history.html +1 -1
- unfold/templates/unfold/helpers/label.html +1 -1
- unfold/templates/unfold/helpers/search.html +7 -4
- unfold/templates/unfold/helpers/search_results.html +2 -2
- unfold/templates/unfold/helpers/tab_action.html +1 -1
- unfold/templates/unfold/helpers/tab_list.html +27 -5
- unfold/templates/unfold/helpers/theme_switch.html +2 -2
- unfold/templates/unfold/layouts/skeleton.html +6 -1
- unfold/templates/unfold/widgets/clearable_file_input.html +14 -6
- unfold/templates/unfold/widgets/clearable_file_input_small.html +4 -4
- unfold/templates/unfold/widgets/split_datetime.html +2 -2
- unfold/templatetags/unfold.py +33 -12
- unfold/templatetags/unfold_list.py +16 -6
- unfold/widgets.py +2 -2
- {django_unfold-0.30.0.dist-info → django_unfold-0.31.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.30.0.dist-info → django_unfold-0.31.0.dist-info}/WHEEL +0 -0
@@ -24,9 +24,14 @@
|
|
24
24
|
<link href="{{ style }}" rel="stylesheet">
|
25
25
|
{% endfor %}
|
26
26
|
|
27
|
+
{% for favicon in site_favicons %}
|
28
|
+
<link {% if favicon.rel %}rel="{{ favicon.rel }}"{% endif %} {% if favicon.href %}href="{{ favicon.href }}"{% endif %} {% if favicon.type %}type="{{ favicon.type }}"{% endif %} {% if favicon.sizes %}sizes="{{ favicon.sizes }}"{% endif %}>
|
29
|
+
{% endfor %}
|
30
|
+
|
27
31
|
<link href="{% static 'unfold/css/styles.css' %}" rel="stylesheet">
|
28
32
|
<link href="{% static 'unfold/css/simplebar.css' %}" rel="stylesheet">
|
29
33
|
|
34
|
+
<script src="{% static 'unfold/js/alpine.anchor.js' %}" defer></script>
|
30
35
|
<script src="{% static 'unfold/js/alpine.persist.js' %}" defer></script>
|
31
36
|
<script src="{% static 'unfold/js/alpine.js' %}" defer></script>
|
32
37
|
<script src="{% static 'unfold/js/htmx.js' %}"></script>
|
@@ -63,7 +68,7 @@
|
|
63
68
|
{% endif %}
|
64
69
|
</head>
|
65
70
|
|
66
|
-
<body class="antialiased bg-white font-sans text-gray-500 dark:bg-gray-900 dark:text-gray-
|
71
|
+
<body class="antialiased bg-white font-sans text-gray-500 dark:bg-gray-900 dark:text-gray-300 {% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}" data-admin-utc-offset="{% now "Z" %}" x-data="{ activeTab: 'general', sidebarMobileOpen: false, sidebarDesktopOpen: {% if request.session.toggle_sidebar == False %}false{% else %}true{% endif %} }">
|
67
72
|
{% block base %}{% endblock %}
|
68
73
|
|
69
74
|
<div id="modal-overlay" class="backdrop-blur-sm bg-opacity-80 bg-gray-900 bottom-0 fixed hidden left-0 mr-1 right-0 top-0 z-50"></div>
|
@@ -10,24 +10,32 @@
|
|
10
10
|
|
11
11
|
<div class="border flex items-center overflow-hidden rounded-md shadow-sm text-sm max-w-2xl dark:border-gray-700">
|
12
12
|
{% if widget.is_initial and not widget.required %}
|
13
|
-
<div class="bg-gray-50 border-r flex flex-none items-center self-stretch px-3 dark:bg-white/[.02] dark:border-gray-700 dark:text-gray-
|
13
|
+
<div class="bg-gray-50 border-r flex flex-none items-center self-stretch px-3 dark:bg-white/[.02] dark:border-gray-700 dark:text-gray-300">
|
14
14
|
<label for="{{ widget.checkbox_id }}" class="flex items-center">
|
15
15
|
<input type="checkbox"{% if widget.class %} class="{{ widget.class }}"{% endif %} name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}" />
|
16
16
|
|
17
|
-
<span class="ml-2 text-gray-500 dark:text-gray-
|
17
|
+
<span class="ml-2 text-gray-500 dark:text-gray-300">
|
18
18
|
{{ widget.clear_checkbox_label }}
|
19
19
|
</span>
|
20
20
|
</label>
|
21
21
|
</div>
|
22
22
|
{% endif %}
|
23
23
|
|
24
|
-
<input type="text" value="{% if widget.value %}{{ widget.value.url }}{% else %}{% trans 'Choose file to upload' %}{% endif %}" disabled class="bg-white flex-grow font-medium px-3 py-2 text-ellipsis dark:bg-gray-900 {% if widget.value %}text-gray-500 dark:text-gray-
|
24
|
+
<input type="text" value="{% if widget.value %}{{ widget.value.url }}{% else %}{% trans 'Choose file to upload' %}{% endif %}" disabled class="bg-white flex-grow font-medium px-3 py-2 text-ellipsis dark:bg-gray-900 {% if widget.value %}text-gray-500 dark:text-gray-300{% else %}text-gray-300 dark:text-gray-300{% endif %}">
|
25
25
|
|
26
26
|
<div class="flex flex-none items-center leading-none self-stretch">
|
27
|
-
<
|
27
|
+
<div class="hidden">
|
28
|
+
<input type="{{ widget.type }}" name="{{ widget.name }}" {% include "django/forms/widgets/attrs.html" %} />
|
29
|
+
</div>
|
30
|
+
|
31
|
+
{% if widget.is_initial %}
|
32
|
+
<a href="{{ widget.value.url }}" class="border-r cursor-pointer text-gray-400 px-3 hover:text-gray-700 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200" target="_blank">
|
33
|
+
<span class="material-symbols-outlined">download</span>
|
34
|
+
</a>
|
35
|
+
{% endif %}
|
28
36
|
|
29
|
-
<label for="{{ widget.
|
30
|
-
<span class="material-symbols-outlined">
|
37
|
+
<label for="{{ widget.attrs.id }}" class="cursor-pointer text-gray-400 px-3 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200">
|
38
|
+
<span class="material-symbols-outlined">upload</span>
|
31
39
|
</label>
|
32
40
|
</div>
|
33
41
|
</div>
|
@@ -7,19 +7,19 @@
|
|
7
7
|
<label for="{{ widget.checkbox_id }}" class="flex items-center">
|
8
8
|
<input type="checkbox"{% if widget.class %} class="{{ widget.class }}"{% endif %} name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}" />
|
9
9
|
|
10
|
-
<span class="ml-2 text-gray-500 dark:text-gray-
|
10
|
+
<span class="ml-2 text-gray-500 dark:text-gray-300">
|
11
11
|
{{ widget.clear_checkbox_label }}
|
12
12
|
</span>
|
13
13
|
</label>
|
14
14
|
</div>
|
15
15
|
{% endif %}
|
16
16
|
|
17
|
-
<input type="text" value="{% if widget.value %}{{ widget.value.url }}{% else %}{% trans 'Choose file to upload' %}{% endif %}" disabled class="bg-white flex-grow font-medium px-3 py-2 text-ellipsis dark:bg-gray-900 {% if widget.value %}text-gray-500 dark:text-gray-
|
17
|
+
<input type="text" value="{% if widget.value %}{{ widget.value.url }}{% else %}{% trans 'Choose file to upload' %}{% endif %}" disabled class="bg-white flex-grow font-medium px-3 py-2 text-ellipsis dark:bg-gray-900 {% if widget.value %}text-gray-500 dark:text-gray-300{% else %}text-gray-300 dark:text-gray-300{% endif %}">
|
18
18
|
|
19
19
|
<div class="flex flex-none items-center leading-none self-stretch">
|
20
|
-
<input
|
20
|
+
<input type="{{ widget.type }}" name="{{ widget.name }}" class="{{ widget.file_input_class }}" {% include "django/forms/widgets/attrs.html" %} />
|
21
21
|
|
22
|
-
<label for="{{ widget.
|
22
|
+
<label for="{{ widget.attrs.id }}" class="cursor-pointer text-gray-400 px-3 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200">
|
23
23
|
<span class="material-symbols-outlined">file_upload</span>
|
24
24
|
</label>
|
25
25
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div class="datetime flex flex-col gap-2 max-w-2xl lg:flex-row lg:group-[.field-row]:flex-row lg:group-[.field-row]:items-center lg:group-[.field-tabular]:flex-row lg:group-[.field-tabular]:items-center">
|
2
2
|
<div class="basis-1/2 flex flex-col lg:group-[.field-row]:flex-row group-[.field-row]:gap-2 lg:group-[.field-tabular]:flex-row group-[.field-tabular]:gap-2">
|
3
|
-
<div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-
|
3
|
+
<div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-300 group-[.field-row]:mb-0 group-[.field-row]:flex group-[.field-row]:items-center group-[.field-tabular]:mb-0 group-[.field-tabular]:flex group-[.field-tabular]:items-center">
|
4
4
|
{{ date_label }}
|
5
5
|
</div>
|
6
6
|
|
@@ -12,7 +12,7 @@
|
|
12
12
|
</div>
|
13
13
|
|
14
14
|
<div class="basis-1/2 flex flex-col lg:ml-auto md:mt-0 lg:group-[.field-row]:flex-row group-[.field-row]:gap-2 lg:group-[.field-tabular]:flex-row group-[.field-tabular]:gap-2">
|
15
|
-
<div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-
|
15
|
+
<div class="font-medium mb-2 text-gray-500 text-sm dark:text-gray-300 group-[.field-row]:mb-0 group-[.field-row]:flex group-[.field-row]:items-center group-[.field-tabular]:mb-0 group-[.field-tabular]:flex group-[.field-tabular]:items-center">
|
16
16
|
{{ time_label }}
|
17
17
|
</div>
|
18
18
|
|
unfold/templatetags/unfold.py
CHANGED
@@ -12,28 +12,49 @@ register = Library()
|
|
12
12
|
|
13
13
|
|
14
14
|
@register.simple_tag(name="tab_list", takes_context=True)
|
15
|
-
def tab_list(context, opts) -> str:
|
16
|
-
|
15
|
+
def tab_list(context, page, opts) -> str:
|
16
|
+
tabs_list = []
|
17
|
+
inlines_list = []
|
18
|
+
|
19
|
+
data = {
|
20
|
+
"nav_global": context.get("nav_global"),
|
21
|
+
"actions_detail": context.get("actions_detail"),
|
22
|
+
"actions_list": context.get("actions_list"),
|
23
|
+
"actions_items": context.get("actions_items"),
|
24
|
+
"is_popup": context.get("is_popup"),
|
25
|
+
}
|
17
26
|
|
18
27
|
for tab in context.get("tab_list", []):
|
19
28
|
if str(opts) in tab["models"]:
|
20
|
-
|
29
|
+
tabs_list = tab["items"]
|
21
30
|
break
|
22
31
|
|
32
|
+
if page == "changelist":
|
33
|
+
data["tabs_list"] = tabs_list
|
34
|
+
|
35
|
+
for inline in context.get("inline_admin_formsets", []):
|
36
|
+
if hasattr(inline.opts, "tab"):
|
37
|
+
inlines_list.append(inline)
|
38
|
+
|
39
|
+
if page == "changeform" and len(inlines_list) > 0:
|
40
|
+
data["inlines_list"] = inlines_list
|
41
|
+
|
23
42
|
return render_to_string(
|
24
43
|
"unfold/helpers/tab_list.html",
|
25
|
-
request=context
|
26
|
-
context=
|
27
|
-
"tab_list": tabs,
|
28
|
-
"nav_global": context.get("nav_global"),
|
29
|
-
"actions_detail": context.get("actions_detail"),
|
30
|
-
"actions_list": context.get("actions_list"),
|
31
|
-
"actions_items": context.get("actions_items"),
|
32
|
-
"is_popup": context.get("is_popup"),
|
33
|
-
},
|
44
|
+
request=context["request"],
|
45
|
+
context=data,
|
34
46
|
)
|
35
47
|
|
36
48
|
|
49
|
+
@register.simple_tag(name="has_nav_item_active")
|
50
|
+
def has_nav_item_active(items: list) -> bool:
|
51
|
+
for item in items:
|
52
|
+
if "active" in item and item["active"]:
|
53
|
+
return True
|
54
|
+
|
55
|
+
return False
|
56
|
+
|
57
|
+
|
37
58
|
@register.filter
|
38
59
|
def class_name(value: Any) -> str:
|
39
60
|
return value.__class__.__name__
|
@@ -63,8 +63,8 @@ ROW_CLASSES = [
|
|
63
63
|
"before:mr-auto",
|
64
64
|
"before:text-gray-500",
|
65
65
|
"first:border-t-0",
|
66
|
-
"dark:before:text-gray-
|
67
|
-
"dark:text-gray-
|
66
|
+
"dark:before:text-gray-300",
|
67
|
+
"dark:text-gray-300",
|
68
68
|
"lg:before:hidden",
|
69
69
|
"lg:first:border-t",
|
70
70
|
"lg:py-3",
|
@@ -90,7 +90,7 @@ CHECKBOX_CLASSES = [
|
|
90
90
|
"lg:border-t",
|
91
91
|
"lg:border-gray-200",
|
92
92
|
"lg:table-cell",
|
93
|
-
"dark:before:text-gray-
|
93
|
+
"dark:before:text-gray-300",
|
94
94
|
"dark:lg:border-gray-800",
|
95
95
|
]
|
96
96
|
|
@@ -254,7 +254,7 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
254
254
|
f, (models.DateField, models.TimeField, models.ForeignKey)
|
255
255
|
):
|
256
256
|
row_classes.append("nowrap")
|
257
|
-
|
257
|
+
|
258
258
|
# If list_display_links not defined, add the link tag to the first field
|
259
259
|
|
260
260
|
if link_in_col(first, field_name, cl):
|
@@ -287,7 +287,7 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
287
287
|
else "",
|
288
288
|
result_repr,
|
289
289
|
)
|
290
|
-
|
290
|
+
row_class = mark_safe(f' class="{" ".join(row_classes)}"')
|
291
291
|
yield format_html(
|
292
292
|
'<{}{} data-label="{}">{}</{}>',
|
293
293
|
table_tag,
|
@@ -309,7 +309,17 @@ def items_for_result(cl: ChangeList, result: HttpRequest, form) -> SafeText:
|
|
309
309
|
)
|
310
310
|
):
|
311
311
|
bf = form[field_name]
|
312
|
-
result_repr = mark_safe(
|
312
|
+
result_repr = mark_safe(
|
313
|
+
str(bf)
|
314
|
+
+ render_to_string(
|
315
|
+
"unfold/helpers/form_errors.html", {"errors": bf.errors}
|
316
|
+
)
|
317
|
+
)
|
318
|
+
|
319
|
+
if bf.errors:
|
320
|
+
row_classes += ["group", "errors"]
|
321
|
+
|
322
|
+
row_class = mark_safe(f' class="{" ".join(row_classes)}"')
|
313
323
|
|
314
324
|
if field_index != 0:
|
315
325
|
yield format_html(
|
unfold/widgets.py
CHANGED
@@ -63,7 +63,7 @@ BASE_CLASSES = [
|
|
63
63
|
"group-[.errors]:focus:ring-red-200",
|
64
64
|
"dark:bg-gray-900",
|
65
65
|
"dark:border-gray-700",
|
66
|
-
"dark:text-gray-
|
66
|
+
"dark:text-gray-300",
|
67
67
|
"dark:focus:border-primary-600",
|
68
68
|
"dark:focus:ring-primary-700",
|
69
69
|
"dark:focus:ring-opacity-50",
|
@@ -131,7 +131,7 @@ PROSE_CLASSES = [
|
|
131
131
|
"prose-strong:text-gray-700",
|
132
132
|
"dark:prose-pre:bg-gray-800",
|
133
133
|
"dark:prose-blockquote:border-gray-700",
|
134
|
-
"dark:prose-blockquote:text-gray-
|
134
|
+
"dark:prose-blockquote:text-gray-300",
|
135
135
|
"dark:prose-headings:text-gray-200",
|
136
136
|
"dark:prose-strong:text-gray-200",
|
137
137
|
]
|
File without changes
|
File without changes
|