django-unfold 0.59.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.
- {django_unfold-0.59.0.dist-info → django_unfold-0.60.0.dist-info}/METADATA +3 -2
- {django_unfold-0.59.0.dist-info → django_unfold-0.60.0.dist-info}/RECORD +33 -25
- unfold/admin.py +45 -13
- unfold/contrib/inlines/admin.py +11 -6
- unfold/contrib/inlines/forms.py +3 -1
- unfold/contrib/location_field/__init__.py +0 -0
- unfold/contrib/location_field/apps.py +6 -0
- unfold/contrib/location_field/templates/location_field/map_widget.html +5 -0
- unfold/fields.py +17 -19
- unfold/forms.py +95 -1
- unfold/mixins/base_model_admin.py +15 -1
- unfold/sites.py +3 -29
- unfold/static/admin/js/admin/RelatedObjectLookups.js +2 -2
- unfold/static/unfold/css/styles.css +1 -1
- unfold/styles.css +3 -3
- unfold/templates/admin/app_list.html +4 -1
- unfold/templates/admin/edit_inline/stacked.html +12 -8
- unfold/templates/admin/edit_inline/tabular.html +2 -0
- unfold/templates/admin/includes/fieldset.html +1 -1
- unfold/templates/admin/login.html +45 -88
- unfold/templates/unfold/components/button.html +10 -1
- unfold/templates/unfold/helpers/app_list.html +5 -2
- unfold/templates/unfold/helpers/app_list_default.html +2 -1
- unfold/templates/unfold/helpers/field.html +5 -3
- unfold/templates/unfold/helpers/pagination_inline.html +28 -0
- unfold/templates/unfold/helpers/unauthenticated_header.html +15 -0
- unfold/templates/unfold/helpers/unauthenticated_title.html +11 -0
- unfold/templates/unfold/layouts/unauthenticated.html +37 -0
- unfold/templates/unfold/widgets/text.html +28 -0
- unfold/templatetags/unfold.py +31 -1
- unfold/widgets.py +41 -1
- {django_unfold-0.59.0.dist-info → django_unfold-0.60.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.59.0.dist-info → django_unfold-0.60.0.dist-info}/WHEEL +0 -0
unfold/styles.css
CHANGED
@@ -197,7 +197,7 @@ table tr.selected th {
|
|
197
197
|
}
|
198
198
|
|
199
199
|
.timezonewarning {
|
200
|
-
@apply absolute block items-center right-
|
200
|
+
@apply absolute block items-center right-11 top-2 text-base-500 truncate;
|
201
201
|
font-size: 0;
|
202
202
|
}
|
203
203
|
|
@@ -218,7 +218,7 @@ table tr.selected th {
|
|
218
218
|
Selector
|
219
219
|
*******************************************************/
|
220
220
|
.selector {
|
221
|
-
@apply flex flex-col grow items-center md:flex-row;
|
221
|
+
@apply flex flex-col grow items-center max-w-5xl md:flex-row;
|
222
222
|
}
|
223
223
|
|
224
224
|
.selector .selector-available-title label,
|
@@ -319,7 +319,7 @@ table tr.selected th {
|
|
319
319
|
}
|
320
320
|
|
321
321
|
[data-inline-type="stacked"] .add-row {
|
322
|
-
@apply
|
322
|
+
@apply overflow-hidden;
|
323
323
|
}
|
324
324
|
|
325
325
|
.add-row td {
|
@@ -44,5 +44,8 @@
|
|
44
44
|
{% endfor %}
|
45
45
|
</div>
|
46
46
|
{% else %}
|
47
|
-
<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 %}
|
@@ -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
|
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="
|
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
|
-
{%
|
86
|
-
|
87
|
-
{%
|
88
|
-
|
89
|
-
|
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>
|
@@ -3,7 +3,7 @@
|
|
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
5
|
{% if stacked == 1 %}
|
6
|
-
<h2 class="
|
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
7
|
{{ fieldset.name }}
|
8
8
|
</h2>
|
9
9
|
{% else %}
|
@@ -1,105 +1,62 @@
|
|
1
|
-
{% extends 'unfold/layouts/
|
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
|
10
|
+
{% block title %}
|
11
|
+
{{ title }} | {{ site_title }}
|
12
|
+
{% endblock %}
|
11
13
|
|
12
|
-
{% block
|
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
|
-
{%
|
17
|
+
{% include "unfold/helpers/messages.html" %}
|
15
18
|
|
16
|
-
{%
|
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
|
-
{%
|
23
|
+
{% include "unfold/helpers/messages/error.html" with errors=form.non_field_errors %}
|
19
24
|
|
20
|
-
{%
|
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
|
-
{%
|
23
|
-
|
24
|
-
|
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
|
-
{%
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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 cursor-pointer 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
|
-
|
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 %}
|
@@ -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="
|
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%}>
|
@@ -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>
|
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
|
-
{%
|
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 %}
|
@@ -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
|
17
|
-
|
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
|
-
|
20
|
+
{{ field }}
|
21
|
+
</div>
|
20
22
|
|
21
23
|
{% include "unfold/helpers/form_errors.html" with errors=field.errors %}
|
22
24
|
|
@@ -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 %}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{% load i18n %}
|
2
|
+
|
3
|
+
<div class="absolute flex flex-row items-center justify-between left-0 m-4 right-0 top-0">
|
4
|
+
{% if site_url %}
|
5
|
+
<a href="{{ site_url }}" class="flex font-medium items-center text-sm text-primary-600 dark:text-primary-500">
|
6
|
+
<span class="material-symbols-outlined mr-2">arrow_back</span> {% trans 'Return to site' %}
|
7
|
+
</a>
|
8
|
+
{% endif %}
|
9
|
+
|
10
|
+
{% if not theme %}
|
11
|
+
<div class="ml-auto">
|
12
|
+
{% include "unfold/helpers/theme_switch.html" %}
|
13
|
+
</div>
|
14
|
+
{% endif %}
|
15
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{% load i18n %}
|
2
|
+
|
3
|
+
<div class="border-b border-base-200 mb-8 pb-6 dark:border-base-800">
|
4
|
+
<h1 class="font-semibold">
|
5
|
+
{% if subtitle %}
|
6
|
+
<span class="block text-font-important-light dark:text-font-important-dark">{{ subtitle }} </span>
|
7
|
+
{% endif %}
|
8
|
+
|
9
|
+
<span class="block text-primary-600 text-xl dark:text-primary-500">{{ title }}</span>
|
10
|
+
</h1>
|
11
|
+
</div>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
{% extends 'unfold/layouts/skeleton.html' %}
|
2
|
+
|
3
|
+
{% load i18n static unfold %}
|
4
|
+
|
5
|
+
|
6
|
+
{% block bodyclass %}{{ block.super }}bg-base-50 login dark:bg-base-900{% endblock %}
|
7
|
+
|
8
|
+
{% block usertools %}{% endblock %}
|
9
|
+
|
10
|
+
{% block nav-global %}{% endblock %}
|
11
|
+
|
12
|
+
{% block nav-sidebar %}{% endblock %}
|
13
|
+
|
14
|
+
{% block content_title %}{% endblock %}
|
15
|
+
|
16
|
+
{% block breadcrumbs %}{% endblock %}
|
17
|
+
|
18
|
+
{% block title %}
|
19
|
+
{{ title }} | {{ site_title }}
|
20
|
+
{% endblock %}
|
21
|
+
|
22
|
+
{% block base %}
|
23
|
+
<div id="page" class="bg-white flex min-h-screen dark:bg-base-900 ">
|
24
|
+
<div class="flex grow items-center justify-center mx-auto px-4 relative">
|
25
|
+
<div class="w-full sm:w-96">
|
26
|
+
{% block content %}{% endblock %}
|
27
|
+
</div>
|
28
|
+
|
29
|
+
{% include "unfold/helpers/unauthenticated_header.html" %}
|
30
|
+
</div>
|
31
|
+
|
32
|
+
{% if login_image %}
|
33
|
+
<div class="bg-cover grow hidden max-w-3xl xl:max-w-4xl xl:block" style="background-image: url('{{ login_image }}')">
|
34
|
+
</div>
|
35
|
+
{% endif %}
|
36
|
+
</div>
|
37
|
+
{% endblock %}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
<div class="max-w-2xl relative">
|
3
|
+
{% if widget.prefix %}
|
4
|
+
<span class="absolute left-3 top-0 bottom-0 flex items-center justify-center">
|
5
|
+
{{ widget.prefix }}
|
6
|
+
</span>
|
7
|
+
{% endif %}
|
8
|
+
|
9
|
+
{% if widget.prefix_icon %}
|
10
|
+
<span class="material-symbols-outlined absolute left-3 top-0 bottom-0 flex items-center justify-center text-base-400 dark:text-base-500">
|
11
|
+
{{ widget.prefix_icon }}
|
12
|
+
</span>
|
13
|
+
{% endif %}
|
14
|
+
|
15
|
+
{% include "django/forms/widgets/input.html" %}
|
16
|
+
|
17
|
+
{% if widget.suffix %}
|
18
|
+
<span class="absolute right-3 top-0 bottom-0 flex items-center justify-center">
|
19
|
+
{{ widget.suffix }}
|
20
|
+
</span>
|
21
|
+
{% endif %}
|
22
|
+
|
23
|
+
{% if widget.suffix_icon %}
|
24
|
+
<span class="material-symbols-outlined absolute right-3 top-0 bottom-0 flex items-center justify-center text-base-400 dark:text-base-500">
|
25
|
+
{{ widget.suffix_icon }}
|
26
|
+
</span>
|
27
|
+
{% endif %}
|
28
|
+
</div>
|
unfold/templatetags/unfold.py
CHANGED
@@ -6,10 +6,11 @@ from django import template
|
|
6
6
|
from django.contrib.admin.helpers import AdminForm, Fieldset
|
7
7
|
from django.contrib.admin.views.main import PAGE_VAR, ChangeList
|
8
8
|
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
9
|
+
from django.core.paginator import Paginator
|
9
10
|
from django.db.models import Model
|
10
11
|
from django.db.models.options import Options
|
11
12
|
from django.forms import BoundField, CheckboxSelectMultiple, Field
|
12
|
-
from django.http import HttpRequest
|
13
|
+
from django.http import HttpRequest, QueryDict
|
13
14
|
from django.template import Context, Library, Node, RequestContext, TemplateSyntaxError
|
14
15
|
from django.template.base import NodeList, Parser, Token, token_kwargs
|
15
16
|
from django.template.loader import render_to_string
|
@@ -574,3 +575,32 @@ def changeform_condition(field: BoundField) -> BoundField:
|
|
574
575
|
@register.simple_tag
|
575
576
|
def infinite_paginator_url(cl, i):
|
576
577
|
return cl.get_query_string({PAGE_VAR: i})
|
578
|
+
|
579
|
+
|
580
|
+
@register.simple_tag
|
581
|
+
def elided_page_range(
|
582
|
+
paginator: Paginator, number: int
|
583
|
+
) -> Optional[list[Union[int, str]]]:
|
584
|
+
if not paginator or not number:
|
585
|
+
return None
|
586
|
+
|
587
|
+
return paginator.get_elided_page_range(number=number)
|
588
|
+
|
589
|
+
|
590
|
+
@register.simple_tag(takes_context=True)
|
591
|
+
def querystring_params(
|
592
|
+
context: RequestContext, query_key: str, query_value: str
|
593
|
+
) -> str:
|
594
|
+
request = context.get("request")
|
595
|
+
result = QueryDict(mutable=True)
|
596
|
+
|
597
|
+
for key, values in request.GET.lists():
|
598
|
+
if key == query_key:
|
599
|
+
continue
|
600
|
+
|
601
|
+
for value in values:
|
602
|
+
result[key] = value
|
603
|
+
|
604
|
+
result[query_key] = query_value
|
605
|
+
|
606
|
+
return result.urlencode()
|
unfold/widgets.py
CHANGED
@@ -288,7 +288,47 @@ FILE_CLASSES = [
|
|
288
288
|
]
|
289
289
|
|
290
290
|
|
291
|
-
class
|
291
|
+
class UnfoldPrefixSuffixMixin:
|
292
|
+
def get_context(self, name, value, attrs):
|
293
|
+
widget = {}
|
294
|
+
|
295
|
+
if "prefix" in self.attrs:
|
296
|
+
widget["prefix"] = self.attrs["prefix"]
|
297
|
+
del self.attrs["prefix"]
|
298
|
+
|
299
|
+
if "prefix_icon" in self.attrs:
|
300
|
+
widget["prefix_icon"] = self.attrs["prefix_icon"]
|
301
|
+
self.attrs["class"] = " ".join([self.attrs["class"], "pl-9"])
|
302
|
+
del self.attrs["prefix_icon"]
|
303
|
+
|
304
|
+
if "suffix" in self.attrs:
|
305
|
+
widget["suffix"] = self.attrs["suffix"]
|
306
|
+
del self.attrs["suffix"]
|
307
|
+
|
308
|
+
if "suffix_icon" in self.attrs:
|
309
|
+
widget["suffix_icon"] = self.attrs["suffix_icon"]
|
310
|
+
self.attrs["class"] = " ".join([self.attrs["class"], "pr-9"])
|
311
|
+
del self.attrs["suffix_icon"]
|
312
|
+
|
313
|
+
widget.update(
|
314
|
+
{
|
315
|
+
"name": name,
|
316
|
+
"is_hidden": self.is_hidden,
|
317
|
+
"required": self.is_required,
|
318
|
+
"value": self.format_value(value),
|
319
|
+
"attrs": self.build_attrs(self.attrs, attrs),
|
320
|
+
"template_name": self.template_name,
|
321
|
+
}
|
322
|
+
)
|
323
|
+
|
324
|
+
return {
|
325
|
+
"widget": widget,
|
326
|
+
}
|
327
|
+
|
328
|
+
|
329
|
+
class UnfoldAdminTextInputWidget(UnfoldPrefixSuffixMixin, AdminTextInputWidget):
|
330
|
+
template_name = "unfold/widgets/text.html"
|
331
|
+
|
292
332
|
def __init__(self, attrs: Optional[dict[str, Any]] = None) -> None:
|
293
333
|
super().__init__(
|
294
334
|
attrs={
|
File without changes
|
File without changes
|