django-unfold 0.25.0__py3-none-any.whl → 0.27.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.25.0.dist-info → django_unfold-0.27.0.dist-info}/METADATA +61 -7
- {django_unfold-0.25.0.dist-info → django_unfold-0.27.0.dist-info}/RECORD +44 -31
- unfold/admin.py +13 -157
- unfold/contrib/forms/templates/unfold/forms/array.html +31 -0
- unfold/contrib/forms/widgets.py +58 -3
- unfold/contrib/import_export/forms.py +17 -0
- unfold/contrib/import_export/templates/admin/import_export/change_form.html +10 -0
- unfold/contrib/import_export/templates/admin/import_export/export.html +38 -3
- unfold/contrib/import_export/templates/admin/import_export/import_form.html +8 -12
- unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html +1 -1
- unfold/contrib/inlines/__init__.py +0 -0
- unfold/contrib/inlines/admin.py +141 -0
- unfold/contrib/inlines/apps.py +6 -0
- unfold/contrib/inlines/checks.py +18 -0
- unfold/contrib/inlines/forms.py +43 -0
- unfold/decorators.py +3 -0
- unfold/fields.py +200 -0
- unfold/forms.py +6 -0
- unfold/static/unfold/css/simplebar.css +230 -0
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/simplebar.js +10 -0
- unfold/styles.css +9 -1
- unfold/templates/admin/app_list.html +1 -1
- unfold/templates/admin/change_form.html +11 -11
- unfold/templates/admin/change_list_results.html +2 -2
- unfold/templates/admin/edit_inline/stacked.html +6 -6
- unfold/templates/admin/edit_inline/tabular.html +7 -9
- unfold/templates/admin/includes/fieldset.html +2 -32
- unfold/templates/unfold/helpers/app_list.html +1 -1
- unfold/templates/unfold/helpers/display_header.html +11 -8
- unfold/templates/unfold/helpers/field.html +20 -6
- unfold/templates/unfold/helpers/field_readonly.html +1 -3
- unfold/templates/unfold/helpers/field_readonly_value.html +1 -0
- unfold/templates/unfold/helpers/fieldset_row.html +53 -0
- unfold/templates/unfold/helpers/fieldsets_tabs.html +4 -4
- unfold/templates/unfold/helpers/form_label.html +1 -1
- unfold/templates/unfold/layouts/skeleton.html +2 -0
- unfold/templates/unfold/widgets/clearable_file_input.html +1 -1
- unfold/templates/unfold/widgets/foreign_key_raw_id.html +15 -0
- unfold/templates/unfold/widgets/textarea.html +1 -7
- unfold/templates/unfold/widgets/textarea_expandable.html +7 -0
- unfold/widgets.py +36 -3
- unfold/contrib/import_export/admin.py +0 -37
- {django_unfold-0.25.0.dist-info → django_unfold-0.27.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.25.0.dist-info → django_unfold-0.27.0.dist-info}/WHEEL +0 -0
@@ -11,19 +11,19 @@
|
|
11
11
|
</h2>
|
12
12
|
|
13
13
|
{{ inline_admin_formset.formset.management_form }}
|
14
|
-
{
|
14
|
+
{% include "unfold/helpers/messages/error.html" with errors=inline_admin_formset.formset.non_form_errors %}
|
15
15
|
|
16
16
|
<div class="border border-gray-200 mb-6 overflow-hidden rounded-md shadow-sm text-gray-700 w-full dark:border-gray-800">
|
17
17
|
{% for inline_admin_form in inline_admin_formset %}
|
18
18
|
<div 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 %}">
|
19
|
-
<h3 class="border-b {% if not forloop.first %}border-t{% endif %} border-gray-200 flex font-medium items-center mb-3 px-3 py-2 text-gray-400 text-sm dark:border-gray-800">
|
19
|
+
<h3 class="bg-gray-50 border-b {% if not forloop.first %}border-t{% endif %} border-gray-200 flex font-medium items-center mb-3 px-3 py-2 text-gray-400 text-sm dark:bg-white/[.02] dark:border-gray-800">
|
20
20
|
<span class="mr-2">
|
21
21
|
{{ inline_admin_formset.opts.verbose_name|capfirst }}:
|
22
22
|
</span>
|
23
23
|
|
24
|
-
<span class="inline_label font-semibold text-gray-900">
|
24
|
+
<span class="inline_label font-semibold text-gray-900 dark:text-gray-200">
|
25
25
|
{% if inline_admin_form.original and inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
|
26
|
-
<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %} font-medium
|
26
|
+
<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %} font-medium text-primary-600 underline">
|
27
27
|
{{ inline_admin_form.original }}
|
28
28
|
</a>
|
29
29
|
{% else %}
|
@@ -42,7 +42,7 @@
|
|
42
42
|
{% endif %}
|
43
43
|
|
44
44
|
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}
|
45
|
-
<span class="delete flex items-center ml-auto text-gray-500">
|
45
|
+
<span class="delete flex gap-2 items-center ml-auto text-gray-500">
|
46
46
|
{{ inline_admin_form.deletion_field.field|add_css_class:form_classes.checkbox }} {{ inline_admin_form.deletion_field.label_tag }}
|
47
47
|
</span>
|
48
48
|
{% endif %}
|
@@ -52,7 +52,7 @@
|
|
52
52
|
|
53
53
|
{% for fieldset in inline_admin_form %}
|
54
54
|
<div class="px-3 -mb-5">
|
55
|
-
{% include 'admin/includes/fieldset.html' %}
|
55
|
+
{% include 'admin/includes/fieldset.html' with stacked=1 %}
|
56
56
|
</div>
|
57
57
|
{% endfor %}
|
58
58
|
|
@@ -16,18 +16,18 @@
|
|
16
16
|
{{ inline_admin_formset.formset.non_form_errors }}
|
17
17
|
|
18
18
|
<div>
|
19
|
-
{% if not inline_admin_formset.has_add_permission and inline_admin_formset.forms|
|
19
|
+
{% if not inline_admin_formset.has_add_permission and inline_admin_formset.forms|length == 0 %}
|
20
20
|
<p class="mb-6 text-gray-500 text-sm dark:text-gray-400">
|
21
21
|
{% trans "No records found." %}
|
22
22
|
</p>
|
23
23
|
{% else %}
|
24
|
-
<div class="border border-gray-200 mb-6 overflow-x-auto rounded-md shadow-sm dark:border-gray-800">
|
24
|
+
<div class="border border-gray-200 mb-6 overflow-x-auto rounded-md shadow-sm dark:border-gray-800" data-simplebar data-simplebar-auto-hide="false">
|
25
25
|
<table class="border-spacing-none border-separate text-gray-700 w-full">
|
26
26
|
<thead class="hidden lg:table-header-group">
|
27
27
|
<tr>
|
28
28
|
{% for field in inline_admin_formset.fields %}
|
29
29
|
{% if not field.widget.is_hidden %}
|
30
|
-
<th class="column-{{ field.name }}{% if field.required %} required{% endif %} align-middle border-b border-gray-200 font-medium px-3 py-2 text-left text-gray-400 text-sm dark:border-gray-800">
|
30
|
+
<th class="column-{{ field.name }}{% if field.required %} required{% endif %} align-middle border-b border-gray-200 font-medium px-3 py-2 text-left text-gray-400 text-sm whitespace-nowrap dark:border-gray-800">
|
31
31
|
<span class="flex flex-row items-center">
|
32
32
|
{{ field.label|capfirst }}
|
33
33
|
|
@@ -40,7 +40,7 @@
|
|
40
40
|
{% endfor %}
|
41
41
|
|
42
42
|
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
|
43
|
-
<th class="align-middle border-b border-gray-200 font-medium px-3 py-2 text-left text-gray-400 text-sm lg:w-px dark:border-gray-800">
|
43
|
+
<th class="align-middle border-b border-gray-200 font-medium px-3 py-2 text-left text-gray-400 text-sm whitespace-nowrap lg:w-px dark:border-gray-800">
|
44
44
|
{% translate "Delete?" %}
|
45
45
|
</th>
|
46
46
|
{% endif %}
|
@@ -59,12 +59,12 @@
|
|
59
59
|
|
60
60
|
{% if inline_admin_form.original or inline_admin_form.show_url %}
|
61
61
|
<tr>
|
62
|
-
<td class="original" colspan="10">
|
62
|
+
<td class="original {% if inline_admin_form.original or inline_admin_form.show_url %}{% if inline_admin_form.original and inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model and inline_admin_formset.has_change_permission %}bg-gray-50 border-b border-gray-200 dark:bg-white/[.02] dark:border-gray-800{% endif %}{% endif %}" colspan="10">
|
63
63
|
{% if inline_admin_form.original or inline_admin_form.show_url %}
|
64
64
|
<p class="align-middle flex font-normal items-center leading-none px-3 text-gray-500 text-left text-sm whitespace-nowrap">
|
65
65
|
{% if inline_admin_form.original %}
|
66
66
|
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
|
67
|
-
<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %} font-medium
|
67
|
+
<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink py-1.5{% else %}inlineviewlink mt-3{% endif %} font-medium text-primary-600 underline text-xs">
|
68
68
|
{{ inline_admin_form.original }}
|
69
69
|
</a>
|
70
70
|
{% endif %}
|
@@ -112,9 +112,7 @@
|
|
112
112
|
{% if field.is_readonly or not field.field.is_hidden %}
|
113
113
|
<td{% if field.field.name %} class="field-{{ field.field.name }}{% if field.field.errors|length > 0 %} errors{% endif %}{% if inline_admin_form.original %} p-3 lg:py-3{% else %} py-3{% endif %}{% if field.is_checkbox %} align-middle{% else %} align-top{% endif %} {% if is_last_row and not inline_admin_formset.has_add_permission %}{% if is_last_col %}border-0 {% else %}border-b lg:border-0{% endif %}{% else %}border-b{% endif %} border-gray-200 flex items-center before:capitalize before:content-[attr(data-label)] before:mr-auto before:text-gray-500 before:w-72 lg:before:hidden font-normal px-3 text-left text-sm lg:table-cell dark:border-gray-800 {% if field.field.is_hidden %} !hidden{% endif %}"{% endif %} data-label="{{ field.field.label }}">
|
114
114
|
{% if field.is_readonly %}
|
115
|
-
|
116
|
-
{{ field.contents }}
|
117
|
-
</div>
|
115
|
+
{% include "unfold/helpers/field_readonly_value.html" with tabular=1 %}
|
118
116
|
{% else %}
|
119
117
|
{{ field.field }}
|
120
118
|
|
@@ -13,39 +13,9 @@
|
|
13
13
|
</div>
|
14
14
|
{% endif %}
|
15
15
|
|
16
|
-
<div class="aligned border border-gray-200 mb-8 rounded-md pt-3 px-3 shadow-sm dark:border-gray-800">
|
16
|
+
<div class="aligned {% if stacked %}mb-5{% else %}border border-gray-200 mb-8 rounded-md pt-3 px-3 shadow-sm dark:border-gray-800{% endif %}">
|
17
17
|
{% for line in fieldset %}
|
18
|
-
|
19
|
-
{% for field in line %}
|
20
|
-
<div class="flex group {% if field.errors %}errors {% endif %}{% if not line.fields|length_is:1 %}lg:max-w-xs w-full {% endif %}{% if not forloop.parentloop.last %} mb-6 {% else %} mb-3{% endif %} {% if row %}flex-row items-center{% else %}flex-col{% endif %}">
|
21
|
-
{% if field.is_checkbox %}
|
22
|
-
<div class="flex flex-row items-center">
|
23
|
-
{{ field.field }}{{ field.label_tag }}
|
24
|
-
</div>
|
25
|
-
{% else %}
|
26
|
-
<div class="{% if row %} w-48{% endif %}">
|
27
|
-
{{ field.label_tag }}
|
28
|
-
</div>
|
29
|
-
|
30
|
-
{% if field.is_readonly %}
|
31
|
-
<div class="readonly bg-gray-50 border font-medium max-w-2xl px-3 py-2 rounded-md shadow-sm text-gray-500 text-sm dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800 {% if field.is_json %}truncate whitespace-pre-wrap{% endif %}">{% if field.contents %}{{ field.contents }}{% else %}-{% endif %}</div>
|
32
|
-
{% else %}
|
33
|
-
{{ field.field }}
|
34
|
-
{% endif %}
|
35
|
-
{% endif %}
|
36
|
-
|
37
|
-
{% if field.errors %}
|
38
|
-
<span class="mt-1 text-red-600 text-sm dark:text-red-500">
|
39
|
-
{{ field.errors }}
|
40
|
-
</span>
|
41
|
-
{% endif %}
|
42
|
-
|
43
|
-
{% if field.field.help_text %}
|
44
|
-
{% include "unfold/helpers/help_text.html" with help_text=field.field.help_text %}
|
45
|
-
{% endif %}
|
46
|
-
</div>
|
47
|
-
{% endfor %}
|
48
|
-
</div>
|
18
|
+
{% include "unfold/helpers/fieldset_row.html" %}
|
49
19
|
{% endfor %}
|
50
20
|
</div>
|
51
21
|
</fieldset>
|
@@ -1,20 +1,23 @@
|
|
1
|
-
<
|
1
|
+
<span class="flex gap-4 items-center">
|
2
2
|
{% if value.3 and value.3.path %}
|
3
|
-
<
|
4
|
-
|
3
|
+
<span class="bg-center bg-cover bg-white flex font-medium justify-center overflow-hidden dark:bg-gray-900 dark:border-gray-700 {% if value.3.squared %}rounded-sm{% else %}rounded-full{% endif %}{% if not value.3.borderless %} border{% endif %}{% if not value.3.width or not value.3.height %} h-8 max-w-8 min-w-8{% endif %}">
|
4
|
+
<img loading="lazy" src="{{ value.3.path }}" class="object-cover" {% if value.3.width %}width="{{ value.3.width }}"{% endif %} {% if value.3.height %}height="{{ value.3.height }}"{% endif %}/>
|
5
|
+
</span>
|
5
6
|
{% elif value.2 %}
|
6
|
-
<
|
7
|
+
<span class="bg-white border flex font-medium h-8 justify-center items-center rounded-full text-xs uppercase w-8 dark:bg-gray-900 dark:border-gray-700">
|
7
8
|
{{ value.2 }}
|
8
|
-
</
|
9
|
+
</span>
|
9
10
|
{% endif %}
|
10
11
|
|
11
|
-
<
|
12
|
-
|
12
|
+
<span class="flex flex-col text-right lg:text-left">
|
13
|
+
{% if value.0 %}
|
14
|
+
<h3>{{ value.0 }}</h3>
|
15
|
+
{% endif %}
|
13
16
|
|
14
17
|
{% if value.1 %}
|
15
18
|
<p class="text-gray-500">
|
16
19
|
{{ value.1 }}
|
17
20
|
</p>
|
18
21
|
{% endif %}
|
19
|
-
</
|
22
|
+
</span>
|
20
23
|
</div>
|
@@ -1,9 +1,23 @@
|
|
1
|
-
|
2
|
-
{%
|
1
|
+
{% if field.field.widget.input_type == "checkbox" %}
|
2
|
+
<div class="{% if field.errors %}errors {% endif %}flex flex-col group mb-6 last:mb-4">
|
3
|
+
<div class="flex flex-row gap-2 items-center">
|
4
|
+
{{ field }}
|
3
5
|
|
4
|
-
|
6
|
+
{% include "unfold/helpers/form_label.html" with field=field %}
|
7
|
+
</div>
|
5
8
|
|
6
|
-
|
9
|
+
{% include "unfold/helpers/form_errors.html" with errors=field.errors %}
|
7
10
|
|
8
|
-
|
9
|
-
</div>
|
11
|
+
{% include "unfold/helpers/help_text.html" with help_text=field.help_text %}
|
12
|
+
</div>
|
13
|
+
{% else %}
|
14
|
+
<div class="{% if field.errors %}errors {% endif %}flex flex-col group mb-6 last:mb-4">
|
15
|
+
{% include "unfold/helpers/form_label.html" with field=field %}
|
16
|
+
|
17
|
+
{{ field }}
|
18
|
+
|
19
|
+
{% include "unfold/helpers/form_errors.html" with errors=field.errors %}
|
20
|
+
|
21
|
+
{% include "unfold/helpers/help_text.html" with help_text=field.help_text %}
|
22
|
+
</div>
|
23
|
+
{% endif %}
|
@@ -3,7 +3,5 @@
|
|
3
3
|
{{ title }}
|
4
4
|
</label>
|
5
5
|
|
6
|
-
|
7
|
-
{{ value }}
|
8
|
-
</div>
|
6
|
+
{% include "unfold/helpers/field_readonly_value.html" %}
|
9
7
|
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class="readonly font-medium max-w-2xl py-2 text-gray-500 text-sm dark:text-gray-400 *:rounded-md {% if not adminform.model_admin.compressed_fields or tabular and not field.is_image %}bg-gray-50 border px-3 rounded-md shadow-sm dark:border-gray-700 dark:bg-gray-800{% endif %} {% if field.is_image %}inline-block{% endif %} {% if field.is_json %}truncate whitespace-pre-wrap{% endif %}">{% if value %}{{ value }}{% elif field.contents %}{{ field.contents }}{% else %}-{% endif %}</div>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<div class="form-row
|
2
|
+
{% if adminform.model_admin.compressed_fields %} border-b border-gray-200 -mx-3 px-3 pt-3 first:pt-0 last:border-b-0{% endif %}
|
3
|
+
{% if not line.fields|length == 1 %} flex flex-row flex-wrap gap-x-8{% endif %}
|
4
|
+
{% if not line.has_visible_field %} hidden{% endif %}
|
5
|
+
{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
|
6
|
+
{% for field in line %}
|
7
|
+
<div class="flex group {% if not line.fields|length == 1 and not adminform.model_admin.compressed_fields %} lg:max-w-xs flex-grow{% endif %}{% if field.errors %} errors {% endif %}{% if not forloop.parentloop.last %} {% if adminform.model_admin.compressed_fields %}mb-3{% else %}mb-6{% endif %}{% else %} pb-3{% endif %} {% if adminform.model_admin.compressed_fields %}flex-col lg:flex-row lg:gap-2 {% else %}flex-col{% endif %}">
|
8
|
+
{% if field.is_checkbox %}
|
9
|
+
<div class="flex flex-row">
|
10
|
+
{{ field.field }}
|
11
|
+
|
12
|
+
<div class="flex flex-col">
|
13
|
+
{{ field.label_tag }}
|
14
|
+
|
15
|
+
{% if field.field.help_text %}
|
16
|
+
<div class="ml-2 -mt-1">
|
17
|
+
{% include "unfold/helpers/help_text.html" with help_text=field.field.help_text %}
|
18
|
+
</div>
|
19
|
+
{% endif %}
|
20
|
+
|
21
|
+
{% if field.errors %}
|
22
|
+
<span class="mt-1 text-red-600 text-sm dark:text-red-500">
|
23
|
+
{{ field.errors }}
|
24
|
+
</span>
|
25
|
+
{% endif %}
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
{% else %}
|
29
|
+
<div class="{% if adminform.model_admin.compressed_fields %} min-w-48 mt-2 w-48{% endif %}">
|
30
|
+
{{ field.label_tag }}
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<div class="flex-grow">
|
34
|
+
{% if field.is_readonly %}
|
35
|
+
{% include "unfold/helpers/field_readonly_value.html" %}
|
36
|
+
{% else %}
|
37
|
+
{{ field.field }}
|
38
|
+
{% endif %}
|
39
|
+
|
40
|
+
{% if field.field.help_text and not field.is_checkbox %}
|
41
|
+
{% include "unfold/helpers/help_text.html" with help_text=field.field.help_text %}
|
42
|
+
{% endif %}
|
43
|
+
|
44
|
+
{% if field.errors %}
|
45
|
+
<span class="mt-1 text-red-600 text-sm dark:text-red-500">
|
46
|
+
{{ field.errors }}
|
47
|
+
</span>
|
48
|
+
{% endif %}
|
49
|
+
</div>
|
50
|
+
{% endif %}
|
51
|
+
</div>
|
52
|
+
{% endfor %}
|
53
|
+
</div>
|
@@ -7,8 +7,8 @@
|
|
7
7
|
{% for fieldset in tabs %}
|
8
8
|
<li>
|
9
9
|
<a class="cursor-pointer font-semibold hover:text-gray-700 dark:hover:text-white"
|
10
|
-
x-on:click="openTab = '{{ fieldset.name|slugify }}'"
|
11
|
-
x-bind:class="openTab == '{{ fieldset.name|slugify }}'{% if forloop.first %} || openTab == null{% endif %} ? 'text-gray-700 dark:text-white' : ''">
|
10
|
+
x-on:click="openTab = '{{ forloop.counter0 }}-{{ fieldset.name|slugify }}'"
|
11
|
+
x-bind:class="openTab == '{{ forloop.counter0 }}-{{ fieldset.name|slugify }}'{% if forloop.first %} || openTab == null{% endif %} ? 'text-gray-700 dark:text-white' : ''">
|
12
12
|
{{ fieldset.name }}
|
13
13
|
</a>
|
14
14
|
</li>
|
@@ -16,8 +16,8 @@
|
|
16
16
|
</ul>
|
17
17
|
|
18
18
|
{% for fieldset in tabs %}
|
19
|
-
<div class="tab-wrapper{% if fieldset.name %} fieldset-{{ fieldset.name|slugify }}{% endif %}"
|
20
|
-
x-show="openTab == '{{ fieldset.name|slugify }}'{% if forloop.first %} || openTab == null{% endif %}">
|
19
|
+
<div class="tab-wrapper{% if fieldset.name %} fieldset-{{ fieldset.name|slugify }} fieldset-{{ forloop.counter0 }}-{{ fieldset.name|slugify }}{% endif %}"
|
20
|
+
x-show="openTab == '{{ forloop.counter0 }}-{{ fieldset.name|slugify }}'{% if forloop.first %} || openTab == null{% endif %}">
|
21
21
|
{% include 'admin/includes/fieldset.html' %}
|
22
22
|
</div>
|
23
23
|
{% endfor %}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<label for="{{ field.id_for_label }}" class="block
|
1
|
+
<label for="{{ field.id_for_label }}" class="block text-gray-900 text-sm dark:text-gray-200{% if field.field.widget.input_type == "checkbox" %}{% else %} font-medium mb-2{% endif %}">
|
2
2
|
{{ field.label }}
|
3
3
|
|
4
4
|
{% if field.field.required %}
|
@@ -25,6 +25,7 @@
|
|
25
25
|
{% endfor %}
|
26
26
|
|
27
27
|
<link href="{% static 'unfold/css/styles.css' %}" rel="stylesheet">
|
28
|
+
<link href="{% static 'unfold/css/simplebar.css' %}" rel="stylesheet">
|
28
29
|
|
29
30
|
<script src="{% static 'unfold/js/alpine.persist.js' %}" defer></script>
|
30
31
|
<script src="{% static 'unfold/js/alpine.js' %}" defer></script>
|
@@ -66,6 +67,7 @@
|
|
66
67
|
{% block base %}{% endblock %}
|
67
68
|
|
68
69
|
<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>
|
70
|
+
<script src="{% static 'unfold/js/simplebar.js' %}"></script>
|
69
71
|
</body>
|
70
72
|
|
71
73
|
</html>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{% load i18n %}
|
2
2
|
|
3
3
|
{% if widget.attrs.accept == 'image/*' and widget.is_initial %}
|
4
|
-
<div class="
|
4
|
+
<div class="mb-4 max-w-48">
|
5
5
|
<a href="{{ widget.value.url }}" target="_blank">
|
6
6
|
<img src="{{ widget.value.url }}" alt="{% trans 'Image preview' %}" class="block rounded" />
|
7
7
|
</a>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class="flex flex-row">
|
2
|
+
{% include 'django/forms/widgets/input.html' %}
|
3
|
+
|
4
|
+
{% if related_url %}
|
5
|
+
<a href="{{ related_url }}" class="related-lookup related-widget-wrapper-link view-related bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm w-9.5 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200" id="lookup_id_{{ widget.name }}">
|
6
|
+
<span class="material-symbols-outlined text-sm">search</span>
|
7
|
+
</a>
|
8
|
+
{% endif %}
|
9
|
+
|
10
|
+
{% if link_label and link_url %}
|
11
|
+
<a href="{{ link_url }}" title="{{ link_label }}" class="bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-gray-400 text-sm w-9.5 hover:text-gray-700 dark:bg-gray-900 dark:border-gray-700 dark:text-gray-500 dark:hover:text-gray-200">
|
12
|
+
<span class="material-symbols-outlined text-sm">visibility</span>
|
13
|
+
</a>
|
14
|
+
{% endif %}
|
15
|
+
</div>
|
@@ -1,7 +1 @@
|
|
1
|
-
<
|
2
|
-
<div class="border break-words font-medium invisible max-w-4xl px-3 py-2 text-sm" style="min-height: 64px">
|
3
|
-
{% if widget.value %}{{ widget.value|linebreaks }}{% endif %}
|
4
|
-
</div>
|
5
|
-
|
6
|
-
<textarea onInput="this.previousElementSibling.innerText = this.value + String.fromCharCode(10)" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
|
7
|
-
</div>
|
1
|
+
<textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<div class="relative">
|
2
|
+
<div class="border break-words font-medium invisible max-w-4xl px-3 py-2 text-sm" style="min-height: 64px">
|
3
|
+
{% if widget.value %}{{ widget.value|linebreaks }}{% endif %}
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<textarea onInput="this.previousElementSibling.innerText = this.value + String.fromCharCode(10)" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</textarea>
|
7
|
+
</div>
|
unfold/widgets.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import Any, Callable, Dict, Optional, Tuple, Union
|
2
2
|
|
3
3
|
from django.contrib.admin.options import VERTICAL
|
4
|
+
from django.contrib.admin.sites import AdminSite
|
4
5
|
from django.contrib.admin.widgets import (
|
5
6
|
AdminBigIntegerFieldWidget,
|
6
7
|
AdminDateWidget,
|
@@ -13,8 +14,10 @@ from django.contrib.admin.widgets import (
|
|
13
14
|
AdminTextInputWidget,
|
14
15
|
AdminTimeWidget,
|
15
16
|
AdminUUIDInputWidget,
|
17
|
+
ForeignKeyRawIdWidget,
|
16
18
|
RelatedFieldWidgetWrapper,
|
17
19
|
)
|
20
|
+
from django.db.models.fields.reverse_related import ForeignObjectRel
|
18
21
|
from django.forms import (
|
19
22
|
CheckboxInput,
|
20
23
|
MultiWidget,
|
@@ -106,7 +109,6 @@ SELECT_CLASSES = [
|
|
106
109
|
"pr-8",
|
107
110
|
"max-w-2xl",
|
108
111
|
"appearance-none",
|
109
|
-
"truncate",
|
110
112
|
]
|
111
113
|
|
112
114
|
PROSE_CLASSES = [
|
@@ -358,6 +360,20 @@ class UnfoldAdminSingleTimeWidget(AdminTimeWidget):
|
|
358
360
|
class UnfoldAdminTextareaWidget(AdminTextareaWidget):
|
359
361
|
template_name = "unfold/widgets/textarea.html"
|
360
362
|
|
363
|
+
def __init__(self, attrs: Optional[Dict[str, Any]] = None) -> None:
|
364
|
+
attrs = attrs or {}
|
365
|
+
|
366
|
+
super().__init__(
|
367
|
+
attrs={
|
368
|
+
"class": "vLargeTextField " + " ".join(TEXTAREA_CLASSES),
|
369
|
+
**(attrs or {}),
|
370
|
+
}
|
371
|
+
)
|
372
|
+
|
373
|
+
|
374
|
+
class UnfoldAdminExpandableTextareaWidget(AdminTextareaWidget):
|
375
|
+
template_name = "unfold/widgets/textarea_expandable.html"
|
376
|
+
|
361
377
|
def __init__(self, attrs: Optional[Dict[str, Any]] = None) -> None:
|
362
378
|
attrs = attrs or {}
|
363
379
|
|
@@ -499,7 +515,7 @@ class UnfoldBooleanWidget(CheckboxInput):
|
|
499
515
|
if attrs is None:
|
500
516
|
attrs = {}
|
501
517
|
|
502
|
-
|
518
|
+
super().__init__(
|
503
519
|
{
|
504
520
|
**(attrs or {}),
|
505
521
|
"class": " ".join(CHECKBOX_CLASSES + [attrs.get("class", "")]),
|
@@ -512,10 +528,27 @@ class UnfoldBooleanSwitchWidget(CheckboxInput):
|
|
512
528
|
def __init__(
|
513
529
|
self, attrs: Optional[Dict[str, Any]] = None, check_test: Callable = None
|
514
530
|
) -> None:
|
515
|
-
|
531
|
+
super().__init__(
|
516
532
|
attrs={"class": " ".join(SWITCH_CLASSES), **(attrs or {})}, check_test=None
|
517
533
|
)
|
518
534
|
|
519
535
|
|
520
536
|
class UnfoldRelatedFieldWidgetWrapper(RelatedFieldWidgetWrapper):
|
521
537
|
template_name = "unfold/widgets/related_widget_wrapper.html"
|
538
|
+
|
539
|
+
|
540
|
+
class UnfoldForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
|
541
|
+
template_name = "unfold/widgets/foreign_key_raw_id.html"
|
542
|
+
|
543
|
+
def __init__(
|
544
|
+
self,
|
545
|
+
rel: ForeignObjectRel,
|
546
|
+
admin_site: AdminSite,
|
547
|
+
attrs: Optional[Dict] = None,
|
548
|
+
using: Optional[Any] = None,
|
549
|
+
) -> None:
|
550
|
+
attrs = {
|
551
|
+
"class": " ".join(["vForeignKeyRawIdAdminField"] + INPUT_CLASSES),
|
552
|
+
**(attrs or {}),
|
553
|
+
}
|
554
|
+
super().__init__(rel, admin_site, attrs, using)
|
@@ -1,37 +0,0 @@
|
|
1
|
-
from django import forms
|
2
|
-
from django.utils.translation import gettext_lazy as _
|
3
|
-
from import_export.admin import ExportActionModelAdmin as BaseExportActionModelAdmin
|
4
|
-
from unfold.admin import ActionForm
|
5
|
-
from unfold.widgets import SELECT_CLASSES
|
6
|
-
|
7
|
-
|
8
|
-
def export_action_form_factory(formats):
|
9
|
-
class _ExportActionForm(ActionForm):
|
10
|
-
format = forms.ChoiceField(
|
11
|
-
label=" ",
|
12
|
-
choices=formats,
|
13
|
-
required=False,
|
14
|
-
widget=forms.Select(
|
15
|
-
{"class": " ".join([*SELECT_CLASSES, "ml-3", "!w-auto", "lg:!w-40"])}
|
16
|
-
),
|
17
|
-
)
|
18
|
-
|
19
|
-
_ExportActionForm.__name__ = "ExportActionForm"
|
20
|
-
|
21
|
-
return _ExportActionForm
|
22
|
-
|
23
|
-
|
24
|
-
class ExportActionModelAdmin(BaseExportActionModelAdmin):
|
25
|
-
def __init__(self, *args, **kwargs):
|
26
|
-
super().__init__(*args, **kwargs)
|
27
|
-
|
28
|
-
choices = []
|
29
|
-
formats = self.get_export_formats()
|
30
|
-
if formats:
|
31
|
-
for i, f in enumerate(formats):
|
32
|
-
choices.append((str(i), f().get_title()))
|
33
|
-
|
34
|
-
if len(formats) > 1:
|
35
|
-
choices.insert(0, ("", _("Select format")))
|
36
|
-
|
37
|
-
self.action_form = export_action_form_factory(choices)
|
File without changes
|
File without changes
|