django-smartbase-admin 0.2.47__py3-none-any.whl → 1.0.38__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 (188) hide show
  1. django_smartbase_admin/actions/admin_action_list.py +80 -51
  2. django_smartbase_admin/actions/advanced_filters.py +55 -20
  3. django_smartbase_admin/admin/admin_base.py +477 -89
  4. django_smartbase_admin/admin/site.py +104 -34
  5. django_smartbase_admin/admin/widgets.py +598 -26
  6. django_smartbase_admin/apps.py +2 -0
  7. django_smartbase_admin/engine/actions.py +34 -16
  8. django_smartbase_admin/engine/admin_base_view.py +253 -115
  9. django_smartbase_admin/engine/configuration.py +186 -4
  10. django_smartbase_admin/engine/const.py +7 -0
  11. django_smartbase_admin/engine/dashboard.py +44 -23
  12. django_smartbase_admin/engine/fake_inline.py +44 -7
  13. django_smartbase_admin/engine/field.py +54 -10
  14. django_smartbase_admin/engine/field_formatter.py +32 -9
  15. django_smartbase_admin/engine/filter_widgets.py +356 -21
  16. django_smartbase_admin/engine/menu_item.py +8 -5
  17. django_smartbase_admin/engine/modal_view.py +12 -7
  18. django_smartbase_admin/engine/request.py +2 -0
  19. django_smartbase_admin/integration/__init__.py +0 -0
  20. django_smartbase_admin/integration/django_cms.py +43 -0
  21. django_smartbase_admin/locale/sk/LC_MESSAGES/django.mo +0 -0
  22. django_smartbase_admin/locale/sk/LC_MESSAGES/django.po +268 -37
  23. django_smartbase_admin/migrations/0005_sbadminuserconfiguration.py +26 -0
  24. django_smartbase_admin/migrations/0006_alter_sbadminuserconfiguration_color_scheme.py +18 -0
  25. django_smartbase_admin/models.py +22 -0
  26. django_smartbase_admin/monkeypatch/admin_readonly_field_monkeypatch.py +96 -0
  27. django_smartbase_admin/monkeypatch/fake_inline_monkeypatch.py +1 -1
  28. django_smartbase_admin/querysets.py +3 -0
  29. django_smartbase_admin/services/configuration.py +30 -0
  30. django_smartbase_admin/services/thread_local.py +6 -19
  31. django_smartbase_admin/services/views.py +82 -27
  32. django_smartbase_admin/services/xlsx_export.py +6 -0
  33. django_smartbase_admin/static/sb_admin/build/tailwind.config.js +1 -0
  34. django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/colors.js +4 -0
  35. django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/spacing.js +1 -0
  36. django_smartbase_admin/static/sb_admin/build/webpack.common.js +11 -8
  37. django_smartbase_admin/static/sb_admin/css/ckeditor/ckeditor_content_dark.css +208 -0
  38. django_smartbase_admin/static/sb_admin/css/coloris/coloris.min.css +1 -0
  39. django_smartbase_admin/static/sb_admin/dist/calendar.js +1 -0
  40. django_smartbase_admin/static/sb_admin/dist/calendar_style.css +1 -0
  41. django_smartbase_admin/static/sb_admin/dist/calendar_style.js +0 -0
  42. django_smartbase_admin/static/sb_admin/dist/chart.js +1 -1
  43. django_smartbase_admin/static/sb_admin/dist/main.js +1 -1
  44. django_smartbase_admin/static/sb_admin/dist/main_style.css +1 -1
  45. django_smartbase_admin/static/sb_admin/dist/table.js +1 -1
  46. django_smartbase_admin/static/sb_admin/dist/table.js.LICENSE.txt +9 -0
  47. django_smartbase_admin/static/sb_admin/dist/tree_widget.js +1 -0
  48. django_smartbase_admin/static/sb_admin/dist/tree_widget_style.css +1 -0
  49. django_smartbase_admin/static/sb_admin/dist/tree_widget_style.js +0 -0
  50. django_smartbase_admin/static/sb_admin/fancytree/jquery.fancytree-all-deps.min.js +1 -0
  51. django_smartbase_admin/static/sb_admin/images/file_types/file-csv.svg +11 -0
  52. django_smartbase_admin/static/sb_admin/images/file_types/file-doc.svg +11 -0
  53. django_smartbase_admin/static/sb_admin/images/file_types/file-docx.svg +11 -0
  54. django_smartbase_admin/static/sb_admin/images/file_types/file-other.svg +13 -0
  55. django_smartbase_admin/static/sb_admin/images/file_types/file-pdf.svg +11 -0
  56. django_smartbase_admin/static/sb_admin/images/file_types/file-ppt.svg +11 -0
  57. django_smartbase_admin/static/sb_admin/images/file_types/file-xls.svg +11 -0
  58. django_smartbase_admin/static/sb_admin/images/file_types/file-xlsx.svg +11 -0
  59. django_smartbase_admin/static/sb_admin/images/file_types/file-zip.svg +18 -0
  60. django_smartbase_admin/static/sb_admin/images/flags/de-at.png +0 -0
  61. django_smartbase_admin/static/sb_admin/images/flags/de-ch.png +0 -0
  62. django_smartbase_admin/static/sb_admin/images/logo_light.svg +21 -0
  63. django_smartbase_admin/static/sb_admin/js/coloris/coloris.min.js +6 -0
  64. django_smartbase_admin/static/sb_admin/js/fullcalendar.min.js +14804 -0
  65. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Bolt-one.svg +3 -0
  66. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Calendar.svg +3 -0
  67. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Caution.svg +3 -0
  68. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Electric-drill.svg +3 -0
  69. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Fire-extinguisher.svg +3 -0
  70. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Gas.svg +3 -0
  71. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Lightning-fill.svg +3 -0
  72. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Moon.svg +3 -0
  73. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Phone-telephone.svg +3 -0
  74. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Printer.svg +3 -0
  75. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Pull.svg +3 -0
  76. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Sun-one.svg +3 -0
  77. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Time.svg +3 -0
  78. django_smartbase_admin/static/sb_admin/src/css/_base.css +5 -1
  79. django_smartbase_admin/static/sb_admin/src/css/_colors.css +257 -82
  80. django_smartbase_admin/static/sb_admin/src/css/_components.css +66 -13
  81. django_smartbase_admin/static/sb_admin/src/css/_datepicker.css +8 -1
  82. django_smartbase_admin/static/sb_admin/src/css/_filer.css +60 -0
  83. django_smartbase_admin/static/sb_admin/src/css/_inlines.css +51 -10
  84. django_smartbase_admin/static/sb_admin/src/css/_tabulator.css +8 -2
  85. django_smartbase_admin/static/sb_admin/src/css/calendar.css +162 -0
  86. django_smartbase_admin/static/sb_admin/src/css/components/_button.css +41 -1
  87. django_smartbase_admin/static/sb_admin/src/css/components/_dropdown.css +26 -8
  88. django_smartbase_admin/static/sb_admin/src/css/components/_input.css +62 -20
  89. django_smartbase_admin/static/sb_admin/src/css/components/_modal.css +1 -1
  90. django_smartbase_admin/static/sb_admin/src/css/components/_query-builder.css +21 -2
  91. django_smartbase_admin/static/sb_admin/src/css/components/_toggle.css +12 -1
  92. django_smartbase_admin/static/sb_admin/src/css/components/_tooltip.css +8 -22
  93. django_smartbase_admin/static/sb_admin/src/css/style.css +17 -0
  94. django_smartbase_admin/static/sb_admin/src/css/tree_widget.css +411 -0
  95. django_smartbase_admin/static/sb_admin/src/js/autocomplete.js +63 -5
  96. django_smartbase_admin/static/sb_admin/src/js/calendar.js +56 -0
  97. django_smartbase_admin/static/sb_admin/src/js/chart.js +8 -22
  98. django_smartbase_admin/static/sb_admin/src/js/choices.js +18 -8
  99. django_smartbase_admin/static/sb_admin/src/js/datepicker.js +97 -336
  100. django_smartbase_admin/static/sb_admin/src/js/datepicker_plugins.js +357 -0
  101. django_smartbase_admin/static/sb_admin/src/js/main.js +307 -26
  102. django_smartbase_admin/static/sb_admin/src/js/multiselect.js +50 -41
  103. django_smartbase_admin/static/sb_admin/src/js/range.js +3 -2
  104. django_smartbase_admin/static/sb_admin/src/js/sb_ajax_params_tabulator_modifier.js +21 -0
  105. django_smartbase_admin/static/sb_admin/src/js/table.js +38 -13
  106. django_smartbase_admin/static/sb_admin/src/js/table_modules/advanced_filter_module.js +43 -20
  107. django_smartbase_admin/static/sb_admin/src/js/table_modules/data_edit_module.js +8 -10
  108. django_smartbase_admin/static/sb_admin/src/js/table_modules/filter_module.js +3 -3
  109. django_smartbase_admin/static/sb_admin/src/js/table_modules/header_tabs_module.js +11 -11
  110. django_smartbase_admin/static/sb_admin/src/js/table_modules/selection_module.js +28 -8
  111. django_smartbase_admin/static/sb_admin/src/js/table_modules/table_params_module.js +6 -0
  112. django_smartbase_admin/static/sb_admin/src/js/table_modules/views_module.js +19 -3
  113. django_smartbase_admin/static/sb_admin/src/js/tree_widget.js +406 -0
  114. django_smartbase_admin/static/sb_admin/src/js/utils.js +56 -21
  115. django_smartbase_admin/templates/sb_admin/actions/change_form.html +169 -117
  116. django_smartbase_admin/templates/sb_admin/actions/dashboard.html +2 -2
  117. django_smartbase_admin/templates/sb_admin/actions/delete_selected_confirmation.html +56 -32
  118. django_smartbase_admin/templates/sb_admin/actions/list.html +79 -42
  119. django_smartbase_admin/templates/sb_admin/actions/object_history.html +2 -2
  120. django_smartbase_admin/templates/sb_admin/actions/partials/action_link.html +14 -0
  121. django_smartbase_admin/templates/sb_admin/actions/partials/selected_rows_actions.html +2 -2
  122. django_smartbase_admin/templates/sb_admin/actions/partials/tabulator_header_v2.html +2 -2
  123. django_smartbase_admin/templates/sb_admin/actions/tree_list.html +63 -0
  124. django_smartbase_admin/templates/sb_admin/authentification/login_base.html +5 -1
  125. django_smartbase_admin/templates/sb_admin/components/columns.html +1 -1
  126. django_smartbase_admin/templates/sb_admin/components/filters_v2.html +99 -85
  127. django_smartbase_admin/templates/sb_admin/config/view.html +0 -1
  128. django_smartbase_admin/templates/sb_admin/dashboard/calendar_widget.html +69 -0
  129. django_smartbase_admin/templates/sb_admin/dashboard/chart_widget.html +21 -2
  130. django_smartbase_admin/templates/sb_admin/dashboard/list_widget.html +6 -0
  131. django_smartbase_admin/templates/sb_admin/dashboard/widget_base.html +1 -1
  132. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/date_field.html +18 -8
  133. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/multiple_choice_field.html +1 -1
  134. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/tree_select_filter.html +2 -0
  135. django_smartbase_admin/templates/sb_admin/filter_widgets/date_field.html +18 -4
  136. django_smartbase_admin/templates/sb_admin/filter_widgets/multiple_choice_field.html +14 -0
  137. django_smartbase_admin/templates/sb_admin/filter_widgets/partials/clear.html +10 -5
  138. django_smartbase_admin/templates/sb_admin/filter_widgets/radio_choice_field.html +2 -2
  139. django_smartbase_admin/templates/sb_admin/filter_widgets/tree_select_filter.html +16 -0
  140. django_smartbase_admin/templates/sb_admin/includes/change_form_title.html +3 -1
  141. django_smartbase_admin/templates/sb_admin/includes/components.html +5 -1
  142. django_smartbase_admin/templates/sb_admin/includes/inline_fieldset.html +48 -39
  143. django_smartbase_admin/templates/sb_admin/includes/notifications.html +2 -1
  144. django_smartbase_admin/templates/sb_admin/includes/readonly_boolean_field.html +9 -0
  145. django_smartbase_admin/templates/sb_admin/includes/readonly_field.html +12 -0
  146. django_smartbase_admin/templates/sb_admin/includes/table_inline_delete_button.html +4 -5
  147. django_smartbase_admin/templates/sb_admin/inlines/stacked_inline.html +68 -40
  148. django_smartbase_admin/templates/sb_admin/inlines/table_inline.html +78 -36
  149. django_smartbase_admin/templates/sb_admin/integrations/filer/folder_list.html +18 -0
  150. django_smartbase_admin/templates/sb_admin/navigation.html +166 -158
  151. django_smartbase_admin/templates/sb_admin/partials/modal/modal_content.html +2 -6
  152. django_smartbase_admin/templates/sb_admin/sb_admin_base.html +49 -4
  153. django_smartbase_admin/templates/sb_admin/sb_admin_base_no_sidebar.html +35 -11
  154. django_smartbase_admin/templates/sb_admin/sb_admin_js_trans.html +3 -0
  155. django_smartbase_admin/templates/sb_admin/sprites/sb_admin.svg +1 -1
  156. django_smartbase_admin/templates/sb_admin/tailwind_whitelist.html +6 -3
  157. django_smartbase_admin/templates/sb_admin/widgets/array.html +0 -1
  158. django_smartbase_admin/templates/sb_admin/widgets/attributes.html +68 -0
  159. django_smartbase_admin/templates/sb_admin/widgets/autocomplete.html +13 -2
  160. django_smartbase_admin/templates/sb_admin/widgets/{checkbox_select.html → checkbox_dropdown.html} +2 -2
  161. django_smartbase_admin/templates/sb_admin/widgets/checkbox_group.html +15 -0
  162. django_smartbase_admin/templates/sb_admin/widgets/clearable_file_input.html +2 -2
  163. django_smartbase_admin/templates/sb_admin/widgets/color_field.html +30 -0
  164. django_smartbase_admin/templates/sb_admin/widgets/date.html +8 -1
  165. django_smartbase_admin/templates/sb_admin/widgets/filer_file.html +84 -0
  166. django_smartbase_admin/templates/sb_admin/widgets/html_read_only.html +1 -0
  167. django_smartbase_admin/templates/sb_admin/widgets/includes/related_item_buttons.html +38 -0
  168. django_smartbase_admin/templates/sb_admin/widgets/multiwidget.html +1 -1
  169. django_smartbase_admin/templates/sb_admin/widgets/radio.html +3 -2
  170. django_smartbase_admin/templates/sb_admin/widgets/radio_dropdown.html +30 -0
  171. django_smartbase_admin/templates/sb_admin/widgets/read_only_password_hash.html +3 -0
  172. django_smartbase_admin/templates/sb_admin/widgets/time.html +8 -1
  173. django_smartbase_admin/templates/sb_admin/widgets/toggle.html +1 -1
  174. django_smartbase_admin/templates/sb_admin/widgets/tree_base.html +59 -0
  175. django_smartbase_admin/templates/sb_admin/widgets/tree_select.html +24 -0
  176. django_smartbase_admin/templates/sb_admin/widgets/tree_select_inline.html +12 -0
  177. django_smartbase_admin/templatetags/sb_admin_tags.py +163 -4
  178. django_smartbase_admin/utils.py +22 -3
  179. django_smartbase_admin/views/dashboard_view.py +6 -0
  180. django_smartbase_admin/views/global_filter_view.py +8 -2
  181. django_smartbase_admin/views/translations_view.py +12 -5
  182. django_smartbase_admin/views/user_config_view.py +52 -0
  183. django_smartbase_admin-1.0.38.dist-info/METADATA +166 -0
  184. {django_smartbase_admin-0.2.47.dist-info → django_smartbase_admin-1.0.38.dist-info}/RECORD +186 -121
  185. {django_smartbase_admin-0.2.47.dist-info → django_smartbase_admin-1.0.38.dist-info}/WHEEL +1 -1
  186. django_smartbase_admin/templates/sb_admin/integrations/sorting/change_list.html +0 -401
  187. django_smartbase_admin-0.2.47.dist-info/METADATA +0 -25
  188. {django_smartbase_admin-0.2.47.dist-info → django_smartbase_admin-1.0.38.dist-info}/LICENSE.md +0 -0
@@ -0,0 +1,96 @@
1
+ import django.contrib.admin.helpers
2
+ from django.contrib.admin.utils import lookup_field, display_for_field
3
+ from django.core.exceptions import ObjectDoesNotExist
4
+ from django.db import models
5
+ from django.db.models import ManyToManyRel, ForeignObjectRel, OneToOneField
6
+ from django.template.defaultfilters import linebreaksbr
7
+ from django.template.loader import render_to_string
8
+ from django.utils.html import conditional_escape
9
+ from django.utils.safestring import mark_safe
10
+
11
+ from django_smartbase_admin.admin.site import sb_admin_site
12
+
13
+
14
+ class SBAdminReadonlyField(django.contrib.admin.helpers.AdminReadonlyField):
15
+ readonly_template = "sb_admin/includes/readonly_field.html"
16
+ readonly_boolean_template = "sb_admin/includes/readonly_boolean_field.html"
17
+
18
+ def _boolean_field_content(self, value):
19
+ return mark_safe(
20
+ render_to_string(
21
+ template_name=self.readonly_boolean_template,
22
+ context={
23
+ "field_label": self.field.get("label"),
24
+ "field_name": self.field.get("name"),
25
+ "value": value,
26
+ },
27
+ ),
28
+ )
29
+
30
+ def contents(self, request=None):
31
+ if self.model_admin.admin_site.name != sb_admin_site.name:
32
+ return super().contents()
33
+
34
+ field, obj, model_admin = (
35
+ self.field["field"],
36
+ self.form.instance,
37
+ self.model_admin,
38
+ )
39
+ try:
40
+ f, attr, value = lookup_field(field, obj, model_admin)
41
+ except (AttributeError, ValueError, ObjectDoesNotExist):
42
+ result_repr = self.empty_value_display
43
+ else:
44
+ if field in self.form.fields:
45
+ widget = self.form[field].field.widget
46
+ # This isn't elegant but suffices for contrib.auth's
47
+ # ReadOnlyPasswordHashWidget.
48
+ if getattr(widget, "read_only", False):
49
+ return widget.render(field, value)
50
+ if f is None:
51
+ if getattr(attr, "boolean", False):
52
+ return self._boolean_field_content(value)
53
+ else:
54
+ if hasattr(value, "__html__"):
55
+ result_repr = value
56
+ else:
57
+ result_repr = linebreaksbr(value)
58
+ else:
59
+ base_field = self.form.fields.get(
60
+ field
61
+ ) or model_admin.all_base_fields_form.base_fields.get(field)
62
+ if isinstance(f.remote_field, ManyToManyRel) and value is not None:
63
+ # get label from widget if has base_field
64
+ if base_field:
65
+ result_repr = base_field.widget.get_label(
66
+ request, list(value.all())
67
+ )
68
+ else:
69
+ result_repr = ", ".join(map(str, value.all()))
70
+ elif (
71
+ isinstance(f.remote_field, (ForeignObjectRel, OneToOneField))
72
+ and value is not None
73
+ ):
74
+ # get label from widget if has base_field
75
+ if base_field:
76
+ result_repr = base_field.widget.get_label(
77
+ request, getattr(obj, field)
78
+ )
79
+ else:
80
+ result_repr = self.get_admin_url(f.remote_field, value)
81
+ else:
82
+ if isinstance(f, models.BooleanField):
83
+ return self._boolean_field_content(value)
84
+ result_repr = display_for_field(value, f, self.empty_value_display)
85
+ result_repr = linebreaksbr(result_repr)
86
+ return render_to_string(
87
+ template_name=self.readonly_template,
88
+ context={
89
+ "readonly_content": conditional_escape(result_repr),
90
+ "field_label": self.field.get("label"),
91
+ "field_label_suffix": self.form.label_suffix,
92
+ },
93
+ )
94
+
95
+
96
+ django.contrib.admin.helpers.AdminReadonlyField = SBAdminReadonlyField
@@ -14,7 +14,7 @@ def monkeypatch_get_foreign_key(fnc):
14
14
  result = models.ForeignKey(
15
15
  model.original_model, on_delete=models.DO_NOTHING
16
16
  )
17
- result.name = SBAdminFakeInlineMixin.fk_name
17
+ result.set_attributes_from_name(SBAdminFakeInlineMixin.fk_name)
18
18
 
19
19
  return result
20
20
 
@@ -2,6 +2,9 @@ from django.db import models
2
2
 
3
3
 
4
4
  class SBAdminListViewConfigurationQueryset(models.QuerySet):
5
+ def by_id(self, config_id):
6
+ return self.filter(id=config_id)
7
+
5
8
  def by_user_id(self, user_id):
6
9
  return self.filter(user_id=user_id)
7
10
 
@@ -20,3 +20,33 @@ class SBAdminConfigurationService(object):
20
20
  return slugify(view_id)
21
21
  else:
22
22
  return view_id
23
+
24
+
25
+ class SBAdminUserConfigurationService(object):
26
+ @classmethod
27
+ def get_user_config(cls, request):
28
+ """Delegate to the configuration class's get_user_config method."""
29
+ configuration_class = import_string(settings.SB_ADMIN_CONFIGURATION)
30
+ return configuration_class.get_user_config(request)
31
+
32
+ @classmethod
33
+ def get_saved_views(cls, request, view_id):
34
+ """Delegate to the configuration class's get_saved_views method."""
35
+ configuration_class = import_string(settings.SB_ADMIN_CONFIGURATION)
36
+ return configuration_class.get_saved_views(request, view_id)
37
+
38
+ @classmethod
39
+ def create_or_update_saved_view(
40
+ cls, request, view_id, config_id, config_name, url_params
41
+ ):
42
+ """Delegate to the configuration class's create_or_update_saved_view method."""
43
+ configuration_class = import_string(settings.SB_ADMIN_CONFIGURATION)
44
+ return configuration_class.create_or_update_saved_view(
45
+ request, view_id, config_id, config_name, url_params
46
+ )
47
+
48
+ @classmethod
49
+ def delete_saved_view(cls, request, view_id, config_id):
50
+ """Delegate to the configuration class's delete_saved_view method."""
51
+ configuration_class = import_string(settings.SB_ADMIN_CONFIGURATION)
52
+ return configuration_class.delete_saved_view(request, view_id, config_id)
@@ -1,26 +1,13 @@
1
- from threading import local
1
+ from contextvars import ContextVar
2
2
 
3
- _thread_locals = local()
3
+ sb_admin_request = ContextVar("sb_admin_request")
4
4
 
5
5
 
6
6
  class SBAdminThreadLocalService:
7
- THREAD_DATA_KEY = "SB_ADMIN_DATA"
8
-
9
- @classmethod
10
- def get_wrapper(cls):
11
- return getattr(_thread_locals, cls.THREAD_DATA_KEY, {})
12
-
13
- @classmethod
14
- def get_data(cls, key):
15
- data_wrapper = cls.get_wrapper()
16
- return data_wrapper.get(key)
17
-
18
7
  @classmethod
19
- def set_data(cls, key, data):
20
- data_wrapper = cls.get_wrapper()
21
- data_wrapper[key] = data
8
+ def get_request(cls):
9
+ return sb_admin_request.get()
22
10
 
23
11
  @classmethod
24
- def clear_data(cls):
25
- if hasattr(_thread_locals, cls.THREAD_DATA_KEY):
26
- delattr(_thread_locals, cls.THREAD_DATA_KEY)
12
+ def set_request(cls, request):
13
+ sb_admin_request.set(request)
@@ -1,38 +1,101 @@
1
1
  import json
2
2
  import pickle
3
+ import urllib
3
4
 
4
- from django.db.models import Q, FilteredRelation, F, Value, CharField
5
+ from django.db.models import Q, FilteredRelation, F
5
6
  from django.shortcuts import redirect
7
+ from django.urls import reverse
6
8
 
7
9
  from django_smartbase_admin.engine.const import (
8
10
  BASE_PARAMS_NAME,
9
11
  FILTER_DATA_NAME,
12
+ FilterVersions,
13
+ ADVANCED_FILTER_DATA_NAME,
14
+ TABLE_PARAMS_SELECTED_FILTER_TYPE,
15
+ TABLE_TAB_ADVANCED_FITLERS,
10
16
  )
11
17
  from django_smartbase_admin.engine.request import SBAdminViewRequestData
12
18
  from django_smartbase_admin.services.translations import SBAdminTranslationsService
19
+ from django_smartbase_admin.templatetags.sb_admin_tags import SBAdminJSONEncoder
13
20
 
14
21
 
15
22
  class SBAdminViewService(object):
16
23
  @classmethod
17
24
  def json_dumps_for_url(cls, data):
18
- return json.dumps(data, separators=(",", ":"))
25
+ return json.dumps(data, separators=(",", ":"), cls=SBAdminJSONEncoder)
19
26
 
20
27
  @classmethod
21
28
  def json_dumps_and_replace(cls, data):
22
- return cls.json_dumps_for_url(data).replace('"', '\\"')
29
+ return cls.json_dumps_for_url(data)
23
30
 
24
31
  @classmethod
25
32
  def build_list_url(cls, view_id, url_params):
26
- params = {view_id: url_params}
27
- return f"{BASE_PARAMS_NAME}={cls.json_dumps_for_url(params)}"
33
+ params = {BASE_PARAMS_NAME: cls.json_dumps_for_url({view_id: url_params})}
34
+ return urllib.parse.urlencode(params)
28
35
 
29
36
  @classmethod
30
- def build_list_params_url(cls, view_id, filter_data=None):
37
+ def process_url_params(cls, view_id, url_params, filter_version):
38
+ url_params = url_params or {}
39
+ filter_data = SBAdminViewService.process_filter_data_url(
40
+ view_id=view_id,
41
+ filter_data=url_params.get(FILTER_DATA_NAME, {}),
42
+ filter_version=filter_version,
43
+ )
44
+ url_params_processed = {**url_params}
45
+ if filter_data:
46
+ url_params_processed[FILTER_DATA_NAME] = filter_data
47
+ return url_params_processed
48
+
49
+ @classmethod
50
+ def process_filter_data_url(cls, view_id, filter_data, filter_version):
51
+ if filter_version == FilterVersions.FILTERS_VERSION_2:
52
+ filter_data_processed = []
53
+ for key, value in filter_data.items():
54
+ filter_value = {
55
+ "id": f"{view_id}-{key}",
56
+ "field": key,
57
+ "type": "string",
58
+ "input": "text",
59
+ "operator": "contains",
60
+ }
61
+ filter_value.update(value)
62
+ filter_data_processed.append(filter_value)
63
+ return filter_data_processed
64
+ else:
65
+ filter_data_processed = {}
66
+ for filter_key, filter_value in filter_data.items():
67
+ if isinstance(filter_value, str):
68
+ filter_data_processed[filter_key] = filter_value
69
+ else:
70
+ filter_data_processed[filter_key] = cls.json_dumps_and_replace(
71
+ filter_value
72
+ )
73
+ return filter_data_processed
74
+
75
+ @classmethod
76
+ def build_list_params_url(cls, view_id, filter_data=None, filter_version=None):
77
+ if filter_version == FilterVersions.FILTERS_VERSION_2:
78
+ filter_dict = {
79
+ ADVANCED_FILTER_DATA_NAME: {
80
+ "condition": "AND",
81
+ "rules": [],
82
+ "valid": True,
83
+ },
84
+ FILTER_DATA_NAME: {
85
+ TABLE_PARAMS_SELECTED_FILTER_TYPE: TABLE_TAB_ADVANCED_FITLERS
86
+ },
87
+ }
88
+ filter_dict[ADVANCED_FILTER_DATA_NAME]["rules"].extend(
89
+ cls.process_filter_data_url(view_id, filter_data, filter_version)
90
+ )
91
+ params = {BASE_PARAMS_NAME: cls.json_dumps_for_url({view_id: filter_dict})}
92
+ return urllib.parse.urlencode(params)
31
93
  filter_data = filter_data or {}
32
- filter_data_processed = {}
33
- for filter_key, filter_value in filter_data.items():
34
- filter_data_processed[filter_key] = cls.json_dumps_and_replace(filter_value)
35
- view_params = {FILTER_DATA_NAME: filter_data_processed}
94
+ view_params = {
95
+ FILTER_DATA_NAME: cls.process_filter_data_url(
96
+ view_id, filter_data, filter_version
97
+ )
98
+ }
36
99
  return cls.build_list_url(view_id, view_params)
37
100
 
38
101
  @classmethod
@@ -46,7 +109,10 @@ class SBAdminViewService(object):
46
109
  response.render()
47
110
  response.content = (
48
111
  response.content.decode()
49
- .replace('href="/admin/', 'href="/sb-admin/')
112
+ .replace(
113
+ f'href="{reverse("admin:index")}',
114
+ f'href="{reverse("sb_admin:index")}',
115
+ )
50
116
  .encode()
51
117
  )
52
118
  return response
@@ -78,7 +144,7 @@ class SBAdminViewService(object):
78
144
  )
79
145
 
80
146
  @classmethod
81
- def has_permission(cls, request, view, model=None, obj=None, permission=None):
147
+ def has_permission(cls, request, view=None, model=None, obj=None, permission=None):
82
148
  return request.request_data.configuration.has_permission(
83
149
  request, request.request_data, view, model, obj, permission
84
150
  )
@@ -91,8 +157,9 @@ class SBAdminViewService(object):
91
157
  request_data,
92
158
  global_filter=True,
93
159
  global_filter_data_map=None,
160
+ qs=None,
94
161
  ):
95
- qs = model.objects.all()
162
+ qs = qs or model.objects.all()
96
163
  if global_filter:
97
164
  qs = cls.apply_global_filter_to_queryset(
98
165
  qs, request, request_data, global_filter_data_map
@@ -152,7 +219,6 @@ class SBAdminViewService(object):
152
219
  def get_annotates(cls, model, values, fields):
153
220
  field_annotates = {}
154
221
  lang_annotates = {}
155
- supporting_annotates = {}
156
222
  visible_fields = []
157
223
  for field in fields:
158
224
  if field.field in values:
@@ -160,18 +226,7 @@ class SBAdminViewService(object):
160
226
  visible_fields.append(field.filter_field)
161
227
  else:
162
228
  visible_fields.append(field.field)
163
- if field.annotate:
164
- field_annotates[field.field] = field.annotate
165
- if field.annotate_function:
166
- function_result = field.annotate_function(field, values)
167
- if function_result:
168
- field_annotates[field.field] = function_result
169
- else:
170
- field_annotates[field.field] = Value(
171
- None, output_field=CharField()
172
- )
173
- if field.supporting_annotates:
174
- supporting_annotates.update(field.supporting_annotates)
229
+ field_annotates.update(field.get_field_annotates(values))
175
230
  main_language_code = SBAdminTranslationsService.get_main_lang_code()
176
231
  for (
177
232
  translation_model,
@@ -188,4 +243,4 @@ class SBAdminViewService(object):
188
243
  lang_annotates[model_field.name] = F(
189
244
  f"{annotate_name}__{model_field.name}"
190
245
  )
191
- return {**lang_annotates, **supporting_annotates, **field_annotates}
246
+ return {**lang_annotates, **field_annotates}
@@ -2,6 +2,7 @@ import datetime
2
2
  import io
3
3
  import re
4
4
  from copy import copy
5
+ from html import unescape
5
6
 
6
7
  import xlsxwriter
7
8
  from django.http import HttpResponse
@@ -96,8 +97,13 @@ class SBAdminXLSXExportService(object):
96
97
  except ValueError:
97
98
  pass
98
99
  if column_formatter == Formatter.HTML.value:
100
+ # remove newlines
101
+ data_col = re.sub(r"\n", "", str(data_col))
102
+ data_col = re.sub(r"\r\n", "", str(data_col))
99
103
  # replace all possible variants of <br> with new line
100
104
  data_col = re.sub(r"<br\s*/?>", "\n", str(data_col))
105
+ # unescape
106
+ data_col = unescape(data_col)
101
107
  data_col = strip_tags(data_col).strip()
102
108
  if not image_write:
103
109
  if (
@@ -8,6 +8,7 @@ module.exports = {
8
8
  'src/django_smartbase_admin/templates/**/*.html',
9
9
  'src/django_smartbase_admin/static/sb_admin/src/js/**/*.js',
10
10
  ],
11
+ darkMode: 'class',
11
12
  corePlugins: {
12
13
  container: false,
13
14
  },
@@ -25,7 +25,11 @@ module.exports = {
25
25
  colors: {
26
26
  current: 'currentColor',
27
27
  light: 'var(--color-light)',
28
+ 'light-a': 'rgb(var(--color-light-a) / <alpha-value>)',
28
29
  'transparent': 'var(--color-transparent)',
29
30
  ...createColorConfig(),
31
+ 'bg': 'var(--color-bg)',
32
+ 'bg-elevated': 'var(--color-bg-elevated)',
33
+ 'bg-input': 'var(--color-bg-input)',
30
34
  }
31
35
  }
@@ -35,6 +35,7 @@ const spacing = {
35
35
  '88': '5.5rem',
36
36
  '96': '6rem',
37
37
  '128': '8rem',
38
+ '136': '8.5rem',
38
39
  '160': '10rem',
39
40
  '192': '12rem',
40
41
  '224': '14rem',
@@ -1,19 +1,22 @@
1
- const path = require('path');
2
- const webpack = require('webpack');
3
- const MiniCssExtractPlugin = require('mini-css-extract-plugin');
4
- const BundleTracker = require('webpack-bundle-tracker');
5
- const ESLintPlugin = require('eslint-webpack-plugin');
1
+ const path = require('path')
2
+ const webpack = require('webpack')
3
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
4
+ const ESLintPlugin = require('eslint-webpack-plugin')
6
5
 
7
6
  const entries = {
8
7
  main: './src/django_smartbase_admin/static/sb_admin/src/js/main.js',
9
8
  table: './src/django_smartbase_admin/static/sb_admin/src/js/table.js',
10
9
  chart: './src/django_smartbase_admin/static/sb_admin/src/js/chart.js',
10
+ calendar: './src/django_smartbase_admin/static/sb_admin/src/js/calendar.js',
11
11
  main_style: './src/django_smartbase_admin/static/sb_admin/src/css/style.css',
12
12
  translations: './src/django_smartbase_admin/static/sb_admin/src/js/translations.js',
13
13
  confirmation_modal: './src/django_smartbase_admin/static/sb_admin/src/js/confirmation_modal.js',
14
- };
14
+ tree_widget: './src/django_smartbase_admin/static/sb_admin/src/js/tree_widget.js',
15
+ tree_widget_style: './src/django_smartbase_admin/static/sb_admin/src/css/tree_widget.css',
16
+ calendar_style: './src/django_smartbase_admin/static/sb_admin/src/css/calendar.css',
17
+ }
15
18
 
16
- const projectRoot = process.env.PWD || process.cwd();
19
+ const projectRoot = process.env.PWD || process.cwd()
17
20
 
18
21
  module.exports = {
19
22
  resolve: {
@@ -74,4 +77,4 @@ module.exports = {
74
77
  'process.env.BUILD': JSON.stringify('web'),
75
78
  }),
76
79
  ]
77
- };
80
+ }
@@ -0,0 +1,208 @@
1
+ body
2
+ {
3
+ /* Font */
4
+ /* Emoji fonts are added to visualise them nicely in Internet Explorer. */
5
+ font-family: sans-serif, Arial, Verdana, "Trebuchet MS", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
6
+ font-size: 12px;
7
+
8
+ /* Text color */
9
+ color: #ffffff;
10
+
11
+ /* Remove the background color to make it transparent. */
12
+ background-color: #2B3645;
13
+
14
+ margin: 20px;
15
+ }
16
+
17
+ .cke_panel_listItem.cke_selected a, .cke_panel_listItem a:hover, .cke_panel_listItem a:focus, .cke_panel_listItem a:active {
18
+ background-color: #111827;
19
+ }
20
+
21
+
22
+ .cke_editable
23
+ {
24
+ font-size: 13px;
25
+ line-height: 1.6;
26
+
27
+ /* Fix for missing scrollbars with RTL texts. (#10488) */
28
+ word-wrap: break-word;
29
+ }
30
+
31
+ blockquote
32
+ {
33
+ font-style: italic;
34
+ font-family: Georgia, Times, "Times New Roman", serif;
35
+ padding: 2px 0;
36
+ border-style: solid;
37
+ border-color: #ccc;
38
+ border-width: 0;
39
+ }
40
+
41
+ .cke_contents_ltr blockquote
42
+ {
43
+ padding-left: 20px;
44
+ padding-right: 8px;
45
+ border-left-width: 5px;
46
+ }
47
+
48
+ .cke_contents_rtl blockquote
49
+ {
50
+ padding-left: 8px;
51
+ padding-right: 20px;
52
+ border-right-width: 5px;
53
+ }
54
+
55
+ a
56
+ {
57
+ color: #0782C1;
58
+ }
59
+
60
+ ol,ul,dl
61
+ {
62
+ /* IE7: reset rtl list margin. (#7334) */
63
+ *margin-right: 0px;
64
+ /* Preserved spaces for list items with text direction different than the list. (#6249,#8049)*/
65
+ padding: 0 40px;
66
+ }
67
+
68
+ h1,h2,h3,h4,h5,h6
69
+ {
70
+ font-weight: normal;
71
+ line-height: 1.2;
72
+ }
73
+
74
+ hr
75
+ {
76
+ border: 0px;
77
+ border-top: 1px solid #ccc;
78
+ }
79
+
80
+ img.right
81
+ {
82
+ border: 1px solid #ccc;
83
+ float: right;
84
+ margin-left: 15px;
85
+ padding: 5px;
86
+ }
87
+
88
+ img.left
89
+ {
90
+ border: 1px solid #ccc;
91
+ float: left;
92
+ margin-right: 15px;
93
+ padding: 5px;
94
+ }
95
+
96
+ pre
97
+ {
98
+ white-space: pre-wrap; /* CSS 2.1 */
99
+ word-wrap: break-word; /* IE7 */
100
+ -moz-tab-size: 4;
101
+ tab-size: 4;
102
+ }
103
+
104
+ .marker
105
+ {
106
+ background-color: Yellow;
107
+ }
108
+
109
+ span[lang]
110
+ {
111
+ font-style: italic;
112
+ }
113
+
114
+ figure
115
+ {
116
+ text-align: center;
117
+ outline: solid 1px #ccc;
118
+ background: rgba(0,0,0,0.05);
119
+ padding: 10px;
120
+ margin: 10px 20px;
121
+ display: inline-block;
122
+ }
123
+
124
+ figure > figcaption
125
+ {
126
+ text-align: center;
127
+ display: block; /* For IE8 */
128
+ }
129
+
130
+ a > img {
131
+ padding: 1px;
132
+ margin: 1px;
133
+ border: none;
134
+ outline: 1px solid #0782C1;
135
+ }
136
+
137
+ /* Widget Styles */
138
+ .code-featured
139
+ {
140
+ border: 5px solid red;
141
+ }
142
+
143
+ .math-featured
144
+ {
145
+ padding: 20px;
146
+ box-shadow: 0 0 2px rgba(200, 0, 0, 1);
147
+ background-color: rgba(255, 0, 0, 0.05);
148
+ margin: 10px;
149
+ }
150
+
151
+ .image-clean
152
+ {
153
+ border: 0;
154
+ background: none;
155
+ padding: 0;
156
+ }
157
+
158
+ .image-clean > figcaption
159
+ {
160
+ font-size: .9em;
161
+ text-align: right;
162
+ }
163
+
164
+ .image-grayscale
165
+ {
166
+ background-color: white;
167
+ color: #666;
168
+ }
169
+
170
+ .image-grayscale img, img.image-grayscale
171
+ {
172
+ filter: grayscale(100%);
173
+ }
174
+
175
+ .embed-240p
176
+ {
177
+ max-width: 426px;
178
+ max-height: 240px;
179
+ margin:0 auto;
180
+ }
181
+
182
+ .embed-360p
183
+ {
184
+ max-width: 640px;
185
+ max-height: 360px;
186
+ margin:0 auto;
187
+ }
188
+
189
+ .embed-480p
190
+ {
191
+ max-width: 854px;
192
+ max-height: 480px;
193
+ margin:0 auto;
194
+ }
195
+
196
+ .embed-720p
197
+ {
198
+ max-width: 1280px;
199
+ max-height: 720px;
200
+ margin:0 auto;
201
+ }
202
+
203
+ .embed-1080p
204
+ {
205
+ max-width: 1920px;
206
+ max-height: 1080px;
207
+ margin:0 auto;
208
+ }
@@ -0,0 +1 @@
1
+ .clr-picker{display:none;flex-wrap:wrap;position:absolute;width:200px;z-index:1000;border-radius:10px;background-color:#fff;justify-content:flex-end;direction:ltr;box-shadow:0 0 5px rgba(0,0,0,.05),0 5px 20px rgba(0,0,0,.1);-moz-user-select:none;-webkit-user-select:none;user-select:none}.clr-picker.clr-open,.clr-picker[data-inline=true]{display:flex}.clr-picker[data-inline=true]{position:relative}.clr-gradient{position:relative;width:100%;height:100px;margin-bottom:15px;border-radius:3px 3px 0 0;background-image:linear-gradient(rgba(0,0,0,0),#000),linear-gradient(90deg,#fff,currentColor);cursor:pointer}.clr-marker{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border:1px solid #fff;border-radius:50%;background-color:currentColor;cursor:pointer}.clr-picker input[type=range]::-webkit-slider-runnable-track{width:100%;height:16px}.clr-picker input[type=range]::-webkit-slider-thumb{width:16px;height:16px;-webkit-appearance:none}.clr-picker input[type=range]::-moz-range-track{width:100%;height:16px;border:0}.clr-picker input[type=range]::-moz-range-thumb{width:16px;height:16px;border:0}.clr-hue{background-image:linear-gradient(to right,red 0,#ff0 16.66%,#0f0 33.33%,#0ff 50%,#00f 66.66%,#f0f 83.33%,red 100%)}.clr-alpha,.clr-hue{position:relative;width:calc(100% - 40px);height:8px;margin:5px 20px;border-radius:4px}.clr-alpha span{display:block;height:100%;width:100%;border-radius:inherit;background-image:linear-gradient(90deg,rgba(0,0,0,0),currentColor)}.clr-alpha input[type=range],.clr-hue input[type=range]{position:absolute;width:calc(100% + 32px);height:16px;left:-16px;top:-4px;margin:0;background-color:transparent;opacity:0;cursor:pointer;appearance:none;-webkit-appearance:none}.clr-alpha div,.clr-hue div{position:absolute;width:16px;height:16px;left:0;top:50%;margin-left:-8px;transform:translateY(-50%);border:2px solid #fff;border-radius:50%;background-color:currentColor;box-shadow:0 0 1px #888;pointer-events:none}.clr-alpha div:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border-radius:50%;background-color:currentColor}.clr-format{display:none;order:1;width:calc(100% - 40px);margin:0 20px 20px}.clr-segmented{display:flex;position:relative;width:100%;margin:0;padding:0;border:1px solid #ddd;border-radius:15px;box-sizing:border-box;color:#999;font-size:12px}.clr-segmented input,.clr-segmented legend{position:absolute;width:100%;height:100%;margin:0;padding:0;border:0;left:0;top:0;opacity:0;pointer-events:none}.clr-segmented label{flex-grow:1;margin:0;padding:4px 0;font-size:inherit;font-weight:400;line-height:initial;text-align:center;cursor:pointer}.clr-segmented label:first-of-type{border-radius:10px 0 0 10px}.clr-segmented label:last-of-type{border-radius:0 10px 10px 0}.clr-segmented input:checked+label{color:#fff;background-color:#666}.clr-swatches{order:2;width:calc(100% - 32px);margin:0 16px}.clr-swatches div{display:flex;flex-wrap:wrap;padding-bottom:12px;justify-content:center}.clr-swatches button{position:relative;width:20px;height:20px;margin:0 4px 6px 4px;padding:0;border:0;border-radius:50%;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;cursor:pointer}.clr-swatches button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}input.clr-color{order:1;width:calc(100% - 80px);height:32px;margin:15px 20px 20px auto;padding:0 10px;border:1px solid #ddd;border-radius:16px;color:#444;background-color:#fff;font-family:sans-serif;font-size:14px;text-align:center;box-shadow:none}input.clr-color:focus{outline:0;border:1px solid #1e90ff}.clr-clear,.clr-close{display:none;order:2;height:24px;margin:0 20px 20px;padding:0 20px;border:0;border-radius:12px;color:#fff;background-color:#666;font-family:inherit;font-size:12px;font-weight:400;cursor:pointer}.clr-close{display:block;margin:0 20px 20px auto}.clr-preview{position:relative;width:32px;height:32px;margin:15px 0 20px 20px;border-radius:50%;overflow:hidden}.clr-preview:after,.clr-preview:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border:1px solid #fff;border-radius:50%}.clr-preview:after{border:0;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}.clr-preview button{position:absolute;width:100%;height:100%;z-index:1;margin:0;padding:0;border:0;border-radius:50%;outline-offset:-2px;background-color:transparent;text-indent:-9999px;cursor:pointer;overflow:hidden}.clr-alpha div,.clr-color,.clr-hue div,.clr-marker{box-sizing:border-box}.clr-field{display:inline-block;position:relative;color:transparent}.clr-field input{margin:0;direction:ltr}.clr-field.clr-rtl input{text-align:right}.clr-field button{position:absolute;width:30px;height:100%;right:0;top:50%;transform:translateY(-50%);margin:0;padding:0;border:0;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;pointer-events:none}.clr-field.clr-rtl button{right:auto;left:0}.clr-field button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 1px rgba(0,0,0,.5)}.clr-alpha,.clr-alpha div,.clr-field button,.clr-preview:before,.clr-swatches button{background-image:repeating-linear-gradient(45deg,#aaa 25%,transparent 25%,transparent 75%,#aaa 75%,#aaa),repeating-linear-gradient(45deg,#aaa 25%,#fff 25%,#fff 75%,#aaa 75%,#aaa);background-position:0 0,4px 4px;background-size:8px 8px}.clr-marker:focus{outline:0}.clr-keyboard-nav .clr-alpha input:focus+div,.clr-keyboard-nav .clr-hue input:focus+div,.clr-keyboard-nav .clr-marker:focus,.clr-keyboard-nav .clr-segmented input:focus+label{outline:0;box-shadow:0 0 0 2px #1e90ff,0 0 2px 2px #fff}.clr-picker[data-alpha=false] .clr-alpha{display:none}.clr-picker[data-minimal=true]{padding-top:16px}.clr-picker[data-minimal=true] .clr-alpha,.clr-picker[data-minimal=true] .clr-color,.clr-picker[data-minimal=true] .clr-gradient,.clr-picker[data-minimal=true] .clr-hue,.clr-picker[data-minimal=true] .clr-preview{display:none}.clr-dark{background-color:#444}.clr-dark .clr-segmented{border-color:#777}.clr-dark .clr-swatches button:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}.clr-dark input.clr-color{color:#fff;border-color:#777;background-color:#555}.clr-dark input.clr-color:focus{border-color:#1e90ff}.clr-dark .clr-preview:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}.clr-dark .clr-alpha,.clr-dark .clr-alpha div,.clr-dark .clr-preview:before,.clr-dark .clr-swatches button{background-image:repeating-linear-gradient(45deg,#666 25%,transparent 25%,transparent 75%,#888 75%,#888),repeating-linear-gradient(45deg,#888 25%,#444 25%,#444 75%,#888 75%,#888)}.clr-picker.clr-polaroid{border-radius:6px;box-shadow:0 0 5px rgba(0,0,0,.1),0 5px 30px rgba(0,0,0,.2)}.clr-picker.clr-polaroid:before{content:'';display:block;position:absolute;width:16px;height:10px;left:20px;top:-10px;border:solid transparent;border-width:0 8px 10px 8px;border-bottom-color:currentColor;box-sizing:border-box;color:#fff;filter:drop-shadow(0 -4px 3px rgba(0,0,0,.1));pointer-events:none}.clr-picker.clr-polaroid.clr-dark:before{color:#444}.clr-picker.clr-polaroid.clr-left:before{left:auto;right:20px}.clr-picker.clr-polaroid.clr-top:before{top:auto;bottom:-10px;transform:rotateZ(180deg)}.clr-polaroid .clr-gradient{width:calc(100% - 20px);height:120px;margin:10px;border-radius:3px}.clr-polaroid .clr-alpha,.clr-polaroid .clr-hue{width:calc(100% - 30px);height:10px;margin:6px 15px;border-radius:5px}.clr-polaroid .clr-alpha div,.clr-polaroid .clr-hue div{box-shadow:0 0 5px rgba(0,0,0,.2)}.clr-polaroid .clr-format{width:calc(100% - 20px);margin:0 10px 15px}.clr-polaroid .clr-swatches{width:calc(100% - 12px);margin:0 6px}.clr-polaroid .clr-swatches div{padding-bottom:10px}.clr-polaroid .clr-swatches button{width:22px;height:22px}.clr-polaroid input.clr-color{width:calc(100% - 60px);margin:10px 10px 15px auto}.clr-polaroid .clr-clear{margin:0 10px 15px 10px}.clr-polaroid .clr-close{margin:0 10px 15px auto}.clr-polaroid .clr-preview{margin:10px 0 15px 10px}.clr-picker.clr-large{width:275px}.clr-large .clr-gradient{height:150px}.clr-large .clr-swatches button{width:22px;height:22px}.clr-picker.clr-pill{width:380px;padding-left:180px;box-sizing:border-box}.clr-pill .clr-gradient{position:absolute;width:180px;height:100%;left:0;top:0;margin-bottom:0;border-radius:3px 0 0 3px}.clr-pill .clr-hue{margin-top:20px}