accrete 0.0.150__py3-none-any.whl → 0.0.152__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 (43) hide show
  1. accrete/contrib/log/queries.py +3 -1
  2. accrete/contrib/ui/admin.py +9 -1
  3. accrete/contrib/ui/forms.py +57 -0
  4. accrete/contrib/ui/migrations/0001_initial.py +39 -0
  5. accrete/contrib/ui/migrations/0002_alter_theme_color_danger_alter_theme_color_link_and_more.py +38 -0
  6. accrete/contrib/ui/migrations/0003_alter_theme_check_user_or_tenant.py +21 -0
  7. accrete/contrib/ui/migrations/0004_theme_force_tenant_theme.py +18 -0
  8. accrete/contrib/ui/models.py +115 -1
  9. accrete/contrib/ui/response.py +11 -4
  10. accrete/contrib/ui/static/css/accrete.css +26 -57
  11. accrete/contrib/ui/static/css/accrete.css.map +1 -1
  12. accrete/contrib/ui/static/css/accrete.scss +80 -55
  13. accrete/contrib/ui/templates/django/forms/widgets/input.html +1 -1
  14. accrete/contrib/ui/templates/ui/custom_theme.html +19 -0
  15. accrete/contrib/ui/templates/ui/filter/query_input.html +1 -1
  16. accrete/contrib/ui/templates/ui/layout.html +9 -9
  17. accrete/contrib/ui/templates/ui/list.html +2 -2
  18. accrete/contrib/ui/templates/ui/message.html +2 -2
  19. accrete/contrib/ui/templates/ui/modal.html +3 -3
  20. accrete/contrib/ui/templates/ui/table.html +5 -5
  21. accrete/contrib/ui/templates/ui/templatetags/field.html +50 -11
  22. accrete/contrib/ui/templates/ui/widgets/date_weekday.html +1 -1
  23. accrete/contrib/ui/templates/ui/widgets/model_search_select.html +4 -3
  24. accrete/contrib/ui/templates/ui/widgets/model_search_select_multi.html +5 -4
  25. accrete/contrib/ui/templatetags/ui.py +34 -4
  26. accrete/contrib/ui/views.py +90 -2
  27. accrete/contrib/ui/widgets/search_select.py +2 -2
  28. accrete/contrib/user/forms.py +1 -1
  29. accrete/contrib/user/migrations/0009_alter_user_theme.py +18 -0
  30. accrete/contrib/user/migrations/0010_alter_user_theme.py +18 -0
  31. accrete/contrib/user/models.py +5 -3
  32. accrete/contrib/user/templates/user/login.html +3 -11
  33. accrete/contrib/user/templates/user/user_preferences.html +27 -15
  34. accrete/contrib/user/views.py +7 -2
  35. accrete/fields.py +4 -2
  36. accrete/managers.py +9 -0
  37. accrete/migrations/0009_alter_accessgroup_name.py +30 -0
  38. accrete/models.py +6 -4
  39. accrete/views.py +32 -20
  40. {accrete-0.0.150.dist-info → accrete-0.0.152.dist-info}/METADATA +1 -1
  41. {accrete-0.0.150.dist-info → accrete-0.0.152.dist-info}/RECORD +43 -34
  42. {accrete-0.0.150.dist-info → accrete-0.0.152.dist-info}/WHEEL +0 -0
  43. {accrete-0.0.150.dist-info → accrete-0.0.152.dist-info}/licenses/LICENSE +0 -0
@@ -1,34 +1,33 @@
1
- @import "../bulma/css/bulma.css";
1
+ @import "../bulma/css/bulma.min.css";
2
2
 
3
3
  :root {
4
4
  --bulma-body-size: .9em;
5
5
  --bulma-navbar-height: 40px;
6
- --bulma-menu-item-selected-h: --bulma-success-h;
7
- --accrete-detail-width: 500px;
6
+ --bulma-menu-item-selected-h: var(--bulma-primary-h);
7
+ --accrete-detail-width: 35em;
8
+ --bulma-primary-h: 153.28deg;
9
+ --bulma-primary-s: 52.89%;
10
+ --bulma-primary-l: 52.55%;
8
11
  --accrete-action-panel-width: 320px;
9
- --bulma-input-icon-focus-color: var(--bulma-success);
10
- --bulma-input-arrow: var(--bulma-success);
11
- --bulma-arrow-color: var(--bulma-success);
12
- --bulma-menu-nested-list-margin: .5em 0 0.5em 0.75em;
13
- --bulma-navbar-burger-color: var(--bulma-success);
12
+ --bulma-input-arrow: var(--bulma-primary);
13
+ --bulma-arrow-color: var(--bulma-primary);
14
14
  --accrete-hover-color: #F0F2F4;
15
-
16
15
  }
17
16
 
18
17
  html[data-theme='light'] {
19
- --bulma-menu-item-h: var(--bulma-success-h);
20
- --bulma-menu-item-s: var(--bulma-success-s);
21
- --bulma-menu-item-l: var(--bulma-success-l);
22
- --bulma-menu-item-background-l: 50%;
23
- --bulma-menu-item-color-l: 10%;
24
- --bulma-navbar-burger-color: var(--bulma-success);
25
- --bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
26
- --accrete-hover-color: #F0F2F4;
18
+ //--bulma-menu-item-h: var(--bulma-success-h);
19
+ //--bulma-menu-item-s: var(--bulma-success-s);
20
+ //--bulma-menu-item-l: var(--bulma-success-l);
21
+ //--bulma-menu-item-background-l: 50%;
22
+ //--bulma-menu-item-color-l: 10%;
23
+ //--bulma-navbar-burger-color: var(--bulma-success);
24
+ //--bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
25
+ //--accrete-hover-color: #F0F2F4;
27
26
  }
28
27
 
29
28
  html[data-theme='dark'] {
30
- --bulma-navbar-burger-color: var(--bulma-success);
31
- --bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
29
+ //--bulma-navbar-burger-color: var(--bulma-success);
30
+ //--bulma-input-disabled-border-color: var(--bulma-input-border-color) !important;
32
31
  --accrete-hover-color: #1E2128;
33
32
 
34
33
  .button.is-light {
@@ -70,6 +69,10 @@ a {
70
69
  color: black;
71
70
  }
72
71
 
72
+ .button {
73
+ box-shadow: none;
74
+ }
75
+
73
76
  .button.is-subtle {
74
77
  box-shadow: none;
75
78
  border-top-color: transparent;
@@ -78,21 +81,22 @@ a {
78
81
  border-left-color: transparent;
79
82
  }
80
83
 
81
- .input {
82
- border-top: none;
83
- border-right: none;
84
- border-left: none;
85
- border-top-left-radius: 0;
86
- border-top-right-radius: 0;
87
- border-bottom-right-radius: 0;
88
- border-bottom-left-radius: 0;
89
- box-shadow: none;
90
- font-weight: bold;
91
- }
84
+ //.input {
85
+ // border-top: none;
86
+ // border-right: none;
87
+ // border-left: none;
88
+ // border-top-left-radius: 0;
89
+ // border-top-right-radius: 0;
90
+ // border-bottom-right-radius: 0;
91
+ // border-bottom-left-radius: 0;
92
+ // box-shadow: none;
93
+ // //box-shadow: inset 0 -10px 10px -16px #000000;
94
+ // font-weight: bold;
95
+ //}
92
96
 
93
97
  .input:focus, .input:focus-within {
94
98
  box-shadow: none;
95
- border-bottom: 1px solid var(--bulma-success);
99
+ border: 1px solid var(--bulma-primary);
96
100
  //border-color: var(--bulma-success);
97
101
  }
98
102
 
@@ -110,7 +114,7 @@ textarea {
110
114
  }
111
115
 
112
116
  textarea:focus {
113
- border-color: var(--bulma-success) !important;
117
+ border-color: var(--bulma-primary) !important;
114
118
  }
115
119
 
116
120
  .is-small.textarea, .is-small.input {
@@ -118,29 +122,52 @@ textarea:focus {
118
122
  font-size: var(--bulma-size-small);
119
123
  }
120
124
 
125
+ td:first-child > .input {
126
+ //border-top-left-radius: var(--bulma-radius);
127
+ //border-bottom-left-radius: var(--bulma-radius);
128
+
129
+ //border-right: 0;
130
+ //border-top: none!important;
131
+ //border-right: none!important;
132
+ //border-bottom: none!important;
133
+ //border-left: none!important;
134
+ }
135
+
136
+ td:last-child > .input {
137
+ //border-top-right-radius: var(--bulma-radius);
138
+ //border-bottom-right-radius: var(--bulma-radius);
139
+
140
+ //border-right: 0;
141
+ //border-top: none!important;
142
+ //border-right: none!important;
143
+ //border-bottom: none!important;
144
+ //border-left: none!important;
145
+ }
146
+
121
147
  td > .input, td * .input, td * select, td * .select {
122
- border-top: none!important;
123
- border-right: none!important;
124
- border-bottom: none!important;
125
- border-left: none!important;
148
+ //border-top: none!important;
149
+ //border-right: none!important;
150
+ //border-bottom: none!important;
151
+ //border-left: none!important;
152
+ border-radius: 0;
126
153
  }
127
154
 
128
155
  td:has(.input:focus) {
129
- border-bottom: 1px solid var(--bulma-success)!important;
156
+ //border-bottom: 1px solid var(--bulma-primary)!important;
130
157
  }
131
158
 
132
159
  select {
133
- border-top: transparent !important;
134
- border-right: transparent !important;
135
- border-left: transparent !important;
136
- border-radius: 0 !important;
160
+ //border-top: transparent !important;
161
+ //border-right: transparent !important;
162
+ //border-left: transparent !important;
163
+ //border-radius: 0 !important;
137
164
  box-shadow: none !important;
138
- font-weight: bold;
165
+ //font-weight: bold;
139
166
  }
140
167
 
141
168
  select:focus {
142
169
  box-shadow: none;
143
- border-bottom: 1px solid var(--bulma-success)!important;
170
+ border: 1px solid var(--bulma-primary)!important;
144
171
  }
145
172
 
146
173
  #detail-container {
@@ -195,7 +222,7 @@ select:focus {
195
222
  }
196
223
 
197
224
  .list-entry > .box:hover, .box.selected {
198
- box-shadow: 0 0 5px 2px var(--bulma-success);
225
+ box-shadow: 0 0 5px 2px var(--bulma-primary);
199
226
  }
200
227
 
201
228
  .helptext {
@@ -234,12 +261,12 @@ select:focus {
234
261
  border-top: 1px solid var(--bulma-grey-light);
235
262
  }
236
263
 
237
- table.can-compact * tr.is-success {
238
- background-color: var(--bulma-success);
264
+ table.can-compact * tr.is-primary {
265
+ background-color: var(--bulma-primary);
239
266
  }
240
267
 
241
- table.can-compact * tr.is-success:hover {
242
- background-color: var(--bulma-success)!important;
268
+ table.can-compact * tr.is-primary:hover {
269
+ background-color: var(--bulma-primary)!important;
243
270
  }
244
271
 
245
272
  table.can-compact > thead {
@@ -258,8 +285,6 @@ select:focus {
258
285
  @media screen and (min-width: 769px) {
259
286
  .modal-card {
260
287
  max-width: 100%;
261
- //min-width: var(--bulma-modal-content-width);
262
- //width: unset;
263
288
  }
264
289
  }
265
290
 
@@ -305,11 +330,11 @@ select:focus {
305
330
  }
306
331
 
307
332
  .menu-list a.is-active, .menu-list a.is-selected, .menu-list button.is-active, .menu-list button.is-selected, .menu-list .menu-item.is-active, .menu-list .menu-item.is-selected {
308
- --bulma-menu-item-h: var(--bulma-success-h);
309
- --bulma-menu-item-s: var(--bulma-success-s);
310
- --bulma-menu-item-l: var(--bulma-success-l);
311
- --bulma-menu-item-background-l: var(--bulma-success-l);
312
- --bulma-menu-item-color-l: var(--bulma-success-invert-l);
333
+ --bulma-menu-item-h: var(--bulma-primary-h);
334
+ --bulma-menu-item-s: var(--bulma-primary-s);
335
+ --bulma-menu-item-l: var(--bulma-primary-l);
336
+ --bulma-menu-item-background-l: var(--bulma-primary-l);
337
+ --bulma-menu-item-color-l: var(--bulma-primary-invert-l);
313
338
  }
314
339
 
315
340
  .hoverable *:hover {
@@ -1 +1 @@
1
- <input class="{% if widget.type != 'checkbox' %}input{% endif %}" type="{{ widget.type }}" name="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
1
+ <input class="{% if widget.type != 'checkbox' and widget.type != 'radio' %}input{% endif %}" type="{{ widget.type }}" name="{{ widget.name }}" autocomplete="off" {% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
@@ -0,0 +1,19 @@
1
+ <style>
2
+ :root {
3
+ --bulma-primary-h: {{ primary.h }}deg;
4
+ --bulma-primary-s: {{ primary.s }}%;
5
+ --bulma-primary-l: {{ primary.l }}%;
6
+ --bulma-success-h: {{ success.h }}deg;
7
+ --bulma-success-s: {{ success.s }}%;
8
+ --bulma-success-l: {{ success.l }}%;
9
+ --bulma-link-h: {{ link.h }}deg;
10
+ --bulma-link-s: {{ link.s }}%;
11
+ --bulma-link-l: {{ link.l }}%;
12
+ --bulma-warning-h: {{ warning.h }}deg;
13
+ --bulma-warning-s: {{ warning.s }}%;
14
+ --bulma-warning-l: {{ warning.l }}%;
15
+ --bulma-danger-h: {{ danger.h }}deg;
16
+ --bulma-danger-s: {{ danger.s }}%;
17
+ --bulma-danger-l: {{ danger.l }}%;
18
+ }
19
+ </style>
@@ -23,7 +23,7 @@
23
23
  {% endif %}
24
24
  </p>
25
25
  <p class="control">
26
- <button class="button is-subtle" style="border-radius: var(--bulma-radius-medium)" x-on:click="addTag();">
26
+ <button class="button" x-on:click="addTag();">
27
27
  <span class="icon"><i class="fa fa-right-long"></i></span>
28
28
  </button>
29
29
  </p>
@@ -4,17 +4,17 @@
4
4
  {% load partials %}
5
5
  {% load ui %}
6
6
 
7
- <html lang="en" style="overflow: hidden" {% block theme %}{% if request.user.theme %}data-theme="{{ request.user.theme }}"{% endif %}{% endblock %}>
7
+ <html lang="en" style="overflow: hidden;" {% block theme %}{% if request.user.theme %}data-theme="{{ request.user.theme }}"{% endif %}{% endblock %}>
8
8
 
9
9
  <head>
10
10
  {% block head %}
11
11
  <meta charset="utf-8">
12
12
  <meta name="viewport" content="width=device-width, initial-scale=1">
13
13
  {% include 'ui/favicon.html' %}
14
- <link rel="stylesheet" type="text/css" href="{% static "css/accrete.css" %}?v=0.0.144">
14
+ <link rel="stylesheet" type="text/css" href="{% static "css/accrete.css" %}?v=0.0.152">
15
15
  <link rel="stylesheet" type="text/css" href="{% static "css/icons.css" %}">
16
16
  <link rel="stylesheet" type="text/css" href="{% static "css/fa.css" %}">
17
-
17
+ {% custom_theme request.user %}
18
18
  <script src="{% static "js/filter.js" %}" type="text/javascript"></script>
19
19
  <script src="{% static "js/htmx.min.js" %}" defer type="text/javascript"></script>
20
20
  <script src="{% static "js/alpine-focus-3.14.9.js" %}" defer type="text/javascript"></script>
@@ -51,7 +51,7 @@
51
51
  <body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' data-tenant-id="{{ tenant.id }}" hx-boost="true" hx-history="false"
52
52
  x-data="{ showPanel: false, openPanel() { if(window.innerWidth >= 1216) {this.showPanel = true} } }"
53
53
  >
54
- <nav id="navbar" class="navbar is-success is-fixed-top" role="navigation" aria-label="main navigation">
54
+ <nav id="navbar" class="navbar is-primary is-fixed-top" role="navigation" aria-label="main navigation">
55
55
  <div class="navbar-brand">
56
56
  {% if has_panel %}
57
57
  <div class="navbar-item is-hidden-widescreen pr-2" x-on:click.stop="$dispatch('toggle-panel')">
@@ -131,7 +131,7 @@
131
131
  <div id="message" class="" style="position: fixed; top: calc(var(--bulma-navbar-height) + 5px); left: 50%; transform: translateX(-50%); z-index: 999">
132
132
  {% for message in messages %}
133
133
  <div class="mb-2" style="min-width: 330px; max-width: 330px" x-data="{ show: false }" x-show="show" x-cloak="" x-init="show = true; setTimeout(() => show = false, 4000)" x-transition.duration.200ms>
134
- <div class="notification is-light has-text-centered {{ message|message_class }}" style="box-shadow: 2px 2px 5px">
134
+ <div class="notification is-light has-text-centered" style="box-shadow: 2px 2px 5px">
135
135
  {{ message }}
136
136
  </div>
137
137
  </div>
@@ -148,9 +148,9 @@
148
148
  <div id="overview-container" class="table-container is-flex is-flex-grow-1 is-flex-direction-column mb-0" x-bind:class="showContentRight ? 'is-hidden-mobile' : ''">
149
149
  <div id="overview-header">
150
150
  <div class="is-flex is-justify-content-space-between is-flex-wrap-wrap {% if is_centered %}container{% endif %}">
151
- <div class="is-flex is-flex-wrap-wrap is-flex-grow-5 is-align-self-center py-2 header-items">
151
+ <div class="is-flex is-flex-wrap-wrap is-flex-grow-5 is-align-self-center py-2 mx-1 header-items">
152
152
  {% block overview_header %}
153
- <div class="ml-0" style="align-self: center">
153
+ <div class="" style="align-self: center">
154
154
  <p class="title is-5">{{ title }}</p>
155
155
  </div>
156
156
  {% if header_template %}{% include header_template %}{% endif %}
@@ -197,9 +197,9 @@
197
197
  </section>
198
198
  </div>
199
199
  </div>
200
-
200
+
201
201
  <div id="detail-container" x-show="showContentRight" {% if show_content_right != 'true' %}style="display: none;"{% endif %}
202
- x-transition:enter.duration.200ms x-transition:leave.duration.50ms
202
+ x-transition:enter.duration.200ms x-transition:leave.duration.50ms
203
203
  >
204
204
  <div id="detail-indicator" class="htmx-indicator">
205
205
  <progress class="progress is-success" max="100"></progress>
@@ -8,8 +8,8 @@
8
8
  {% partialdef entry inline=True %}
9
9
  <div id="list-entry-{{ instance.pk }}" class="list-entry cell pb-0" style="height: {{ column_height }}">
10
10
  <div class="box p-3"
11
- style="word-break: break-word; height: 100%; overflow-y: auto; {% if instance.get_absolute_url %}cursor:pointer;{% endif %}"
12
- {% if instance.get_absolute_url %}
11
+ style="word-break: break-word; height: 100%; overflow-y: auto; {% if instance.get_absolute_url and detail_enabled %}cursor:pointer;{% endif %}"
12
+ {% if instance.get_absolute_url and detail_enabled %}
13
13
  hx-get="{{ instance.get_absolute_url }}{% querystring %}" hx-swap="none" hx-indicator="#detail-indicator" hx-replace-url="{% querystring detail=instance.pk %}"
14
14
  x-on:click="$dispatch('unselect-list-entry'); selected = true; $nextTick(() => { $el.scrollIntoView({block: 'nearest'}) });" x-bind:class="selected ? 'selected' : ''"
15
15
  {% endif %}
@@ -4,8 +4,8 @@
4
4
  {% for message in messages %}
5
5
  <div hx-swap-oob="{% if append %}beforeend:#message{% else %}innerHTML:#message{% endif %}">
6
6
  <div class="mb-2" style="min-width: 340px; max-width: 340px" x-data="{ show: false }" x-show="show" x-cloak="" x-init="show = true; {% if not persistent %}setTimeout(() => show = false, 4000){% endif %}" x-transition.duration.200ms>
7
- <div class="notification is-light has-text-centered {{ message|message_class }}" style="box-shadow: 2px 2px 5px">
8
- {% if persistent %}<button class="delete" x-on:click="show = false;"></button>{% endif %}
7
+ <div class="notification has-text-centered " style="box-shadow: 2px 2px 5px">
8
+ <button class="delete" x-on:click="show = false;"></button>
9
9
  {{ message }}
10
10
  </div>
11
11
  </div>
@@ -1,13 +1,13 @@
1
1
  {% load i18n %}
2
2
  {% load ui %}
3
3
 
4
- <div hx-swap-oob="{% if is_update %}outerHTML:#{{ modal_id }}{% else %}beforeend:body{% endif %}">
5
- <div id="{{ modal_id }}" x-data="{showModal: false, close() {$dispatch('close-modal-{{ modal_id }}')} }" x-ref="modal" class="modal is-active is-justify-content-flex-start"
4
+ <div hx-swap-oob="{% if is_update %}innerHTML:#{{ modal_id }}{% else %}beforeend:body{% endif %}">
5
+ <div id="{{ modal_id }}" x-data="{showModal: false, close() {$dispatch('close-modal-{{ modal_id }}')} }" x-ref="modal" x-trap="true" class="modal is-active is-justify-content-flex-start"
6
6
  style="padding-top: calc(var(--bulma-navbar-height) + 20px); padding-bottom: 40px;"
7
7
  @close-modal-{{ modal_id }}.window="showModal = false; setTimeout(() => $refs.modal.remove(), 200);"
8
8
  @close-modals.window="showModal = false; setTimeout(() => $refs.modal.remove(), 200);"
9
9
  {% if not is_blocking %}@keyup.escape.window="if (! $refs.{{ modal_id|xrefsave }}Indicator.classList.contains('htmx-request')) {$dispatch('close-modal-{{ modal_id }}')}"{% endif %}
10
- {% if is_blocking %}{% endif %}hx-indicator="#{{ modal_id }}-indicator" hx-disabled-elt="#{{ modal_id }}-background"
10
+ hx-indicator="#{{ modal_id }}-indicator" hx-disabled-elt="#{{ modal_id }}-background"
11
11
  >
12
12
  <button id="{{ modal_id }}-background" class="modal-background" {% if not is_blocking %}@click="$dispatch('close-modal-{{ modal_id }}')"{% endif %} style="cursor: default"></button>
13
13
 
@@ -5,7 +5,7 @@
5
5
  <table id="content-table" class="table can-compact is-fullwidth is-hoverable is-narrow my-0" hx-indicator=".htmx-indicator" x-data="">
6
6
  <thead style="position: sticky; top: 0; z-index: 10; background-color: var(--bulma-scheme-main)">
7
7
  <tr>
8
- <th>{{ instance_label }}</th>
8
+ {% if instance_label %}<th>{{ instance_label }}</th>{% endif %}
9
9
  {% for field in fields %}
10
10
  <th style="text-align: {{ page.object_list|table_alignment:field }}">{{ page.object_list|verbose_field_name:field }}</th>
11
11
  {% endfor %}
@@ -20,14 +20,14 @@
20
20
  hx-get="{{ instance.get_absolute_url }}{% querystring %}" hx-swap="none"
21
21
  hx-replace-url="{% querystring detail=instance.pk %}"
22
22
  x-data="{selected: false}" @unselect-tr.window="selected = false"
23
- x-on:click="$dispatch('unselect-tr'); selected = true; $nextTick(() => { $el.scrollIntoView( {block: 'nearest'} ) });" x-bind:class="selected ? 'is-success' : ''"
23
+ x-on:click="$dispatch('unselect-tr'); selected = true; $nextTick(() => { $el.scrollIntoView( {block: 'nearest'} ) });" x-bind:class="selected ? 'is-primary' : ''"
24
24
  {% endif %}
25
25
  >
26
26
  {% partialdef td inline=True %}
27
- <td>{{ instance }}</td>
27
+ {% if instance_label %}<td>{{ instance }}</td>{% endif %}
28
28
  {% for field in fields %}
29
29
  <td style="text-align: {{ instance|table_alignment:field }}">
30
- <span class="">
30
+ <span>
31
31
  <span class="responsive-heading has-text-weight-light" style="margin-right: .2rem">{{ instance|verbose_field_name:field }}:</span>
32
32
  {{ instance|table_display:field|default_if_none:'' }}
33
33
  </span>
@@ -72,4 +72,4 @@
72
72
  {% endif %}
73
73
  >
74
74
  </div>
75
- <progress id="endless-scroll-indicator" class="htmx-indicator progress is-small is-success" max="100">15%</progress>
75
+ <progress id="endless-scroll-indicator" class="htmx-indicator progress is-small is-primary" max="100">15%</progress>
@@ -1,27 +1,66 @@
1
1
  {% load ui %}
2
2
  {% load partials %}
3
3
 
4
+ {#{% partialdef form_field %}#}
5
+ {# <label class="label mt-2 mb-5">#}
6
+ {# {{ field.label }}#}
7
+ {# {{ field }}#}
8
+ {# <span class="has-text-danger is-size-6">{{ field.errors }}</span>#}
9
+ {# <span class="helptext is-size-7">{{ field.help_text }}</span>#}
10
+ {# <span class="helptext is-size-7">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>#}
11
+ {# </label>#}
12
+ {#{% endpartialdef %}#}
13
+
14
+ {#{% partialdef form_field %}#}
15
+ {# <label class="label mt-2 mb-5" style="border: 1px solid; border-radius: var(--bulma-radius);">#}
16
+ {# <span style="justify-content: left" class="is-fullwidth button is-static helptext is-size-7 {% if field.field.required %}has-text-weight-bold{% endif %}">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>#}
17
+ {# {{ field }}#}
18
+ {# <span class="has-text-danger is-size-6">{{ field.errors }}Testmessage</span>#}
19
+ {##}
20
+ {# </label>#}
21
+ {#{% endpartialdef %}#}
22
+
4
23
  {% partialdef form_field %}
5
- <label class="label mt-2 mb-5">
6
- {{ field }}
24
+ <div class="mb-5">
25
+ <label class="label mb-0 {% if field.field.required %}has-text-weight-medium{% endif %}" for="{{ field.id_for_label }}">{{ field.label }}</label>
26
+ <div class="field has-addons mb-0">
27
+ {% if icon %}
28
+ <p class="control">
29
+ <button tabindex="-1" type="button" class="button is-static"><span class="icon"><i class="{{ icon }}"></i></span></button>
30
+ </p>
31
+ {% endif %}
32
+ <div class="control is-expanded">{{ field }}</div>
33
+ </div>
7
34
  <span class="has-text-danger is-size-6">{{ field.errors }}</span>
8
- <span class="helptext {% if field.field.required %}has-text-weight-bold{% endif %}">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>
9
- </label>
35
+ <span class="helptext is-size-7">{{ field.help_text|default_if_falsy:'' }}</span>
36
+ </div>
10
37
  {% endpartialdef %}
11
38
 
12
39
  {% partialdef textarea %}
13
40
  <label class="label mt-2 mb-5">
14
- <span class="helptext {% if field.field.required %}has-text-weight-bold{% endif %}">{% if label %}{{ label }}{% else %}{{ field.help_text|default_if_falsy:field.label }}{% endif %}</span>
41
+ <span class="{% if field.field.required %}has-text-weight-normal{% endif %}">{{ field.label }}</span>
15
42
  <span class="has-text-danger is-size-6">{{ field.errors }}</span>
16
43
  {{ field }}
17
44
  </label>
18
45
  {% endpartialdef %}
19
46
 
20
47
  {% partialdef model_field %}
21
- <label class="label mt-2 mb-5">
22
- <span class="field has-addons mb-0">
23
- <span class="control input has-text-weight-normal">{{ value|default_if_none:'' }}</span>
24
- </span>
25
- <span class="helptext {% if required %}has-text-weight-bold{% endif %}">{{ label }}</span>
26
- </label>
48
+ {# <label class="label mt-2 mb-5">#}
49
+ {# <span class="field has-addons mb-0">#}
50
+ {# <span class="control input has-text-weight-bold">{{ value|default_if_none:'' }}</span>#}
51
+ {# </span>#}
52
+ {# <span class="helptext">{{ label }}</span>#}
53
+ {# </label>#}
54
+ <div class="mb-5">
55
+ <label class="label mb-0 {% if field.field.required %}has-text-weight-bold{% endif %}" for="{{ field.id_for_label }}">{{ label }}</label>
56
+ <div class="field has-addons mb-0">
57
+ {% if icon %}
58
+ <p class="control">
59
+ <button tabindex="-1" type="button" class="button is-static"><span class="icon"><i class="{{ icon }}"></i></span></button>
60
+ </p>
61
+ {% endif %}
62
+ <div class="control input is-expanded">{{ value|default_if_none:'' }}</div>
63
+ </div>
64
+ <span class="helptext is-size-7">{{ field.help_text|default_if_falsy:'' }}</span>
65
+ </div>
27
66
  {% endpartialdef %}
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div class="field has-addons mb-0">
4
4
  <p class="control">
5
- <p class="control"><a class="button is-subtle" style="height: 100%; border-top-left-radius: var(--bulma-radius-medium); border-bottom-left-radius: var(--bulma-radius-medium);">{{ widget.value|weekday:'' }}</a></p>
5
+ <p class="control"><a class="button is-static" style="height: 100%; border-top-left-radius: var(--bulma-radius-medium); border-bottom-left-radius: var(--bulma-radius-medium);">{{ widget.value|weekday:'' }}</a></p>
6
6
  </p>
7
7
  <p class="control is-expanded">
8
8
  <input class="{% if widget.type != 'checkbox' %}input{% endif %} is-fullwidth" name="{{ widget.name }}" type="{{ widget.type }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %} {% include "django/forms/widgets/attrs.html" %}>
@@ -11,12 +11,13 @@
11
11
  >
12
12
  <input id="id_{{ widget.name }}_display" class="input" type="text" readonly x-ref="inputDisplay" value="{{ widget.value_display }}" aria-label="inputDisplay"
13
13
  style="padding-right: 30px"
14
+ {% include "django/forms/widgets/attrs.html" %}
14
15
  x-on:keydown="if (!open && [38, 40].includes($event.keyCode)) {}; if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
15
16
  x-on:click.stop="if (open) {open = false; } else {open = true; $refs.searchInput.focus()}"
16
17
  >
17
- <div style="position: relative; top: 1.5rem; z-index: 90;">
18
- <div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" x-cloak="" class="box pt-1 px-3 mb-2" x-ref="dropdownContent" tabindex="-1" x-transition style="position: absolute; width: 100%">
19
- <input id="id_{{ widget.name }}_search" type="search" autocomplete="off" class="input mb-2" x-ref="searchInput" aria-label="search"
18
+ <div style="position: relative; top: .5rem; z-index: 90;">
19
+ <div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" x-cloak="" class="box pt-3 px-3 mb-2" x-ref="dropdownContent" tabindex="-1" x-transition style="position: absolute; width: 100%">
20
+ <input id="id_{{ widget.name }}_search" type="search" autocomplete="off" class="input my-2" x-ref="searchInput" aria-label="search"
20
21
  name="{{ widget.search_parameter }}"
21
22
  placeholder="{% translate 'Type to search' %}"
22
23
  hx-get="{{ widget.search_url }}"
@@ -10,8 +10,8 @@
10
10
  <option selected value="{{ obj.pk }}"></option>
11
11
  {% endfor %}
12
12
  </select>
13
- <div id="{{ widget.attrs.id }}_display" class="input select py-1 pl-1" tabindex="0" x-ref="inputDisplay" aria-label="inputDisplay"
14
- style="padding-right: 30px; border-radius: 0; border-top: 0; border-right:0; border-left: 0; min-height: var(--bulma-control-height); height: fit-content; width: 100%"
13
+ <div id="{{ widget.attrs.id }}_display" class="input select py-1" tabindex="0" x-ref="inputDisplay" aria-label="inputDisplay"
14
+ style="padding-right: 30px; min-height: var(--bulma-control-height); height: fit-content; width: 100%"
15
15
  x-on:keydown="if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
16
16
  x-on:click.stop="if (!$event.target.classList.contains('delete')) {if (open) {open = false; } else {open = true; $refs.searchInput.focus();}}"
17
17
  >
@@ -33,8 +33,8 @@
33
33
  {% endfor %}
34
34
  </div>
35
35
  </div>
36
- <div style="position: relative; top: 1.5rem; z-index: 9">
37
- <div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" class="box pt-1 px-3 mb-2" x-ref="dropdownContent" x-cloak="" tabindex="-1" x-transition style="position: absolute; width: 100%">
36
+ <div style="position: relative; top: .5rem; z-index: 9">
37
+ <div x-show="open" x-effect="if (open) {$nextTick(() => { $refs.dropdownContent.scrollIntoView(true) });}" class="box pt-3 px-3 mb-2" x-ref="dropdownContent" x-cloak="" tabindex="-1" x-transition style="position: absolute; width: 100%">
38
38
  <input id="id_{{ widget.uuid }}_search" type="search" autocomplete="off" class="input mb-2" x-ref="searchInput" aria-label="search"
39
39
  name="{{ widget.search_parameter }}"
40
40
  placeholder="{% translate 'Type to search' %}"
@@ -42,6 +42,7 @@
42
42
  hx-trigger="input changed delay:300ms, search"
43
43
  hx-target="#id_{{ widget.uuid }}_dropdown_items"
44
44
  hx-swap="innerHTML"
45
+ style="border-radius: var(--bulma-radius)"
45
46
  x-on:keydown="if (![9, 27, 38, 40].includes($event.keyCode)) {$refs.searchInput.focus();}"
46
47
  @change.stop=""
47
48
  >
@@ -2,16 +2,22 @@ import logging
2
2
  import re
3
3
  from datetime import datetime, date, timedelta
4
4
 
5
+ from django.contrib.auth import get_user_model
5
6
  from django.utils.translation import gettext_lazy as _
6
7
  from django import template
7
- from django.db.models import Manager, DecimalField, IntegerField, FloatField, Model
8
+ from django.db.models import (
9
+ Manager, DecimalField, IntegerField, FloatField, Model, Q
10
+ )
8
11
  from django.apps import apps
9
12
  from django.template.loader import render_to_string
10
13
  from django.utils.safestring import mark_safe
11
14
  from django.forms import widgets
15
+ from accrete.contrib.ui.models import Theme
16
+ from accrete.tenant import get_tenant
12
17
 
13
18
  _logger = logging.getLogger(__name__)
14
19
  register = template.Library()
20
+ User = get_user_model()
15
21
 
16
22
 
17
23
  @register.simple_tag(name='combine_templates')
@@ -153,11 +159,17 @@ def x_ref_save(param: str):
153
159
 
154
160
 
155
161
  @register.filter(name='wrap_form_field')
156
- def wrap_form_fields(field, label=None):
162
+ def wrap_form_fields(field, icon=None):
157
163
  if isinstance(field.field.widget, widgets.Textarea):
158
- html = render_to_string('ui/templatetags/field.html#textarea', {'field': field, 'label': label})
164
+ html = render_to_string(
165
+ 'ui/templatetags/field.html#textarea',
166
+ {'field': field, 'icon': None}
167
+ )
159
168
  return mark_safe(html)
160
- html = render_to_string('ui/templatetags/field.html#form_field', {'field': field, 'label': label})
169
+ html = render_to_string(
170
+ 'ui/templatetags/field.html#form_field',
171
+ {'field': field, 'icon': icon}
172
+ )
161
173
  return mark_safe(html)
162
174
 
163
175
 
@@ -181,3 +193,21 @@ def default_if_falsy(value, default):
181
193
  if bool(value):
182
194
  return value
183
195
  return default
196
+
197
+
198
+ @register.simple_tag(name='custom_theme')
199
+ def custom_theme(user: User) -> str:
200
+ if user.is_anonymous:
201
+ return ''
202
+ tenant = get_tenant()
203
+ tenant_theme = Theme.objects.filter(
204
+ tenant=tenant, tenant__isnull=False
205
+ ).first()
206
+ if tenant_theme and tenant_theme.force_tenant_theme:
207
+ return mark_safe(tenant_theme.theme_markup)
208
+ if user.theme == 'custom':
209
+ theme = Theme.objects.filter(user=user).first()
210
+ return theme and mark_safe(theme.theme_markup) or ''
211
+ if user.theme == 'preset' and tenant_theme:
212
+ return mark_safe(tenant_theme.theme_markup)
213
+ return ''