headmin 0.4.2 → 0.5.2

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. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -3
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +78 -1
  5. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +12 -6
  6. data/app/assets/javascripts/headmin/controllers/filter_controller.js +61 -11
  7. data/app/assets/javascripts/headmin/controllers/filter_row_controller.js +50 -0
  8. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +2 -6
  9. data/app/assets/javascripts/headmin/controllers/media_controller.js +237 -0
  10. data/app/assets/javascripts/headmin/controllers/media_modal_controller.js +110 -0
  11. data/app/assets/javascripts/headmin/controllers/popup_controller.js +3 -1
  12. data/app/assets/javascripts/headmin/controllers/remote_modal_controller.js +10 -0
  13. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +16 -21
  14. data/app/assets/javascripts/headmin/controllers/textarea_controller.js +34 -0
  15. data/app/assets/javascripts/headmin/index.js +10 -0
  16. data/app/assets/javascripts/headmin.js +413 -38
  17. data/app/assets/stylesheets/headmin/filter.scss +74 -0
  18. data/app/assets/stylesheets/headmin/forms/file.scss +40 -5
  19. data/app/assets/stylesheets/headmin/forms/media.scss +10 -0
  20. data/app/assets/stylesheets/headmin/forms/repeater.scss +4 -0
  21. data/app/assets/stylesheets/headmin/forms.scss +7 -0
  22. data/app/assets/stylesheets/headmin/general.scss +0 -1
  23. data/app/assets/stylesheets/headmin/layout/body.scss +5 -0
  24. data/app/assets/stylesheets/headmin/layout/sidebar.scss +0 -1
  25. data/app/assets/stylesheets/headmin/media/index.scss +9 -0
  26. data/app/assets/stylesheets/headmin/media.scss +1 -0
  27. data/app/assets/stylesheets/headmin/popup.scss +0 -1
  28. data/app/assets/stylesheets/headmin/table.scss +15 -0
  29. data/app/assets/stylesheets/headmin.css +137 -9
  30. data/app/assets/stylesheets/headmin.scss +1 -0
  31. data/app/controllers/concerns/headmin/filterable.rb +27 -0
  32. data/app/controllers/headmin/media_controller.rb +52 -0
  33. data/app/controllers/headmin_controller.rb +2 -0
  34. data/app/models/concerns/headmin/field.rb +0 -1
  35. data/app/models/concerns/headmin/fieldable.rb +10 -1
  36. data/app/models/concerns/headmin/form/hintable.rb +6 -1
  37. data/app/models/headmin/blocks_view.rb +1 -1
  38. data/app/models/headmin/filter/base.rb +238 -0
  39. data/app/models/headmin/filter/base_view.rb +64 -0
  40. data/app/models/headmin/filter/boolean.rb +15 -0
  41. data/app/models/headmin/filter/boolean_view.rb +61 -0
  42. data/app/models/headmin/filter/button_view.rb +25 -0
  43. data/app/models/headmin/filter/conditional_view.rb +16 -0
  44. data/app/models/headmin/filter/date.rb +67 -0
  45. data/app/models/headmin/filter/date_view.rb +52 -0
  46. data/app/models/headmin/filter/flatpickr_view.rb +54 -0
  47. data/app/models/headmin/filter/menu_item_view.rb +6 -0
  48. data/app/models/headmin/filter/money.rb +13 -0
  49. data/app/models/headmin/filter/number.rb +27 -0
  50. data/app/models/headmin/filter/number_view.rb +54 -0
  51. data/app/models/headmin/filter/operator_view.rb +30 -0
  52. data/app/models/headmin/filter/options_view.rb +61 -0
  53. data/app/models/headmin/filter/row_view.rb +13 -0
  54. data/app/models/headmin/filter/search.rb +18 -0
  55. data/app/models/headmin/filter/search_view.rb +31 -0
  56. data/app/models/headmin/filter/text.rb +25 -0
  57. data/app/models/headmin/filter/text_view.rb +53 -0
  58. data/app/models/headmin/filters.rb +29 -0
  59. data/app/models/headmin/form/color_view.rb +48 -0
  60. data/app/models/headmin/form/datetime_range_view.rb +25 -0
  61. data/app/models/headmin/form/datetime_view.rb +45 -0
  62. data/app/models/headmin/form/flatpickr_range_view.rb +4 -15
  63. data/app/models/headmin/form/flatpickr_view.rb +3 -12
  64. data/app/models/headmin/form/media_view.rb +113 -0
  65. data/app/models/headmin/form/textarea_view.rb +6 -1
  66. data/app/models/view_model.rb +1 -1
  67. data/app/views/headmin/_blocks.html.erb +3 -3
  68. data/app/views/headmin/_breadcrumbs.html.erb +1 -1
  69. data/app/views/headmin/_dropdown.html.erb +1 -1
  70. data/app/views/headmin/_filters.html.erb +9 -9
  71. data/app/views/headmin/_heading.html.erb +1 -1
  72. data/app/views/headmin/_notifications.html.erb +1 -1
  73. data/app/views/headmin/_pagination.html.erb +2 -2
  74. data/app/views/headmin/dropdown/_devise.html.erb +7 -7
  75. data/app/views/headmin/dropdown/_list.html.erb +1 -1
  76. data/app/views/headmin/filters/_base.html.erb +95 -0
  77. data/app/views/headmin/filters/_boolean.html.erb +23 -0
  78. data/app/views/headmin/filters/_date.html.erb +14 -38
  79. data/app/views/headmin/filters/_flatpickr.html.erb +15 -48
  80. data/app/views/headmin/filters/_number.html.erb +23 -0
  81. data/app/views/headmin/filters/_options.html.erb +24 -0
  82. data/app/views/headmin/filters/_search.html.erb +14 -12
  83. data/app/views/headmin/filters/_text.html.erb +23 -0
  84. data/app/views/headmin/filters/filter/_button.html.erb +9 -10
  85. data/app/views/headmin/filters/filter/_conditional.html.erb +18 -0
  86. data/app/views/headmin/filters/filter/_menu_item.html.erb +5 -2
  87. data/app/views/headmin/filters/filter/_null_select.html.erb +8 -0
  88. data/app/views/headmin/filters/filter/_operator.html.erb +16 -0
  89. data/app/views/headmin/filters/filter/_row.html.erb +11 -0
  90. data/app/views/headmin/forms/_autocomplete.html.erb +2 -2
  91. data/app/views/headmin/forms/_blocks.html.erb +3 -3
  92. data/app/views/headmin/forms/_checkbox.html.erb +5 -5
  93. data/app/views/headmin/forms/_color.html.erb +32 -0
  94. data/app/views/headmin/forms/_date.html.erb +8 -8
  95. data/app/views/headmin/forms/_datetime.html.erb +41 -0
  96. data/app/views/headmin/forms/_datetime_range.html.erb +40 -0
  97. data/app/views/headmin/forms/_email.html.erb +9 -9
  98. data/app/views/headmin/forms/_file.html.erb +9 -9
  99. data/app/views/headmin/forms/_flatpickr.html.erb +1 -1
  100. data/app/views/headmin/forms/_flatpickr_range.html.erb +9 -10
  101. data/app/views/headmin/forms/_hidden.html.erb +1 -1
  102. data/app/views/headmin/forms/_hint.html.erb +7 -2
  103. data/app/views/headmin/forms/_media.html.erb +58 -0
  104. data/app/views/headmin/forms/_number.html.erb +8 -8
  105. data/app/views/headmin/forms/_password.html.erb +7 -7
  106. data/app/views/headmin/forms/_redactorx.html.erb +2 -2
  107. data/app/views/headmin/forms/_search.html.erb +9 -9
  108. data/app/views/headmin/forms/_select.html.erb +8 -8
  109. data/app/views/headmin/forms/_switch.html.erb +2 -2
  110. data/app/views/headmin/forms/_text.html.erb +9 -9
  111. data/app/views/headmin/forms/_textarea.html.erb +7 -7
  112. data/app/views/headmin/forms/_url.html.erb +9 -9
  113. data/app/views/headmin/forms/_validation.html.erb +1 -1
  114. data/app/views/headmin/forms/_wysiwyg.html.erb +2 -2
  115. data/app/views/headmin/forms/fields/_base.html.erb +1 -1
  116. data/app/views/headmin/forms/fields/_file.html.erb +1 -1
  117. data/app/views/headmin/forms/fields/_files.html.erb +1 -1
  118. data/app/views/headmin/forms/fields/_group.html.erb +2 -2
  119. data/app/views/headmin/forms/fields/_list.html.erb +1 -1
  120. data/app/views/headmin/forms/fields/_text.html.erb +1 -1
  121. data/app/views/headmin/forms/media/_item.html.erb +32 -0
  122. data/app/views/headmin/forms/media/_validation.html.erb +10 -0
  123. data/app/views/headmin/forms/repeater/_row.html.erb +12 -11
  124. data/app/views/headmin/layout/_footer.html.erb +1 -1
  125. data/app/views/headmin/layout/_main.html.erb +2 -0
  126. data/app/views/headmin/layout/_remote_modal.html.erb +1 -0
  127. data/app/views/headmin/layout/_sidebar.html.erb +1 -1
  128. data/app/views/headmin/media/_item.html.erb +17 -0
  129. data/app/views/headmin/media/_media_item_modal.html.erb +51 -0
  130. data/app/views/headmin/media/_modal.html.erb +35 -0
  131. data/app/views/headmin/media/create.turbo_stream.erb +5 -0
  132. data/app/views/headmin/media/index.html.erb +3 -0
  133. data/app/views/headmin/media/show.html.erb +9 -0
  134. data/app/views/headmin/media/update.turbo_stream.erb +3 -0
  135. data/app/views/headmin/nav/item/_devise.html.erb +7 -7
  136. data/app/views/headmin/table/_actions.html.erb +1 -4
  137. data/app/views/headmin/table/actions/_action.html.erb +3 -3
  138. data/app/views/headmin/table/actions/_delete.html.erb +2 -2
  139. data/app/views/headmin/table/actions/_export.html.erb +1 -1
  140. data/app/views/headmin/table/body/_color.html.erb +10 -0
  141. data/app/views/headmin/table/body/_image.html.erb +18 -0
  142. data/app/views/headmin/table/foot/_cell.html.erb +1 -1
  143. data/app/views/headmin/table/foot/_id.html.erb +1 -1
  144. data/app/views/headmin/views/devise/confirmations/_new.html.erb +2 -2
  145. data/app/views/headmin/views/devise/passwords/_edit.html.erb +2 -2
  146. data/app/views/headmin/views/devise/passwords/_new.html.erb +2 -2
  147. data/app/views/headmin/views/devise/registrations/_edit.html.erb +1 -1
  148. data/app/views/headmin/views/devise/registrations/_new.html.erb +2 -2
  149. data/app/views/headmin/views/devise/sessions/_new.html.erb +1 -1
  150. data/app/views/headmin/views/devise/unlocks/_new.html.erb +2 -2
  151. data/config/locales/devise/nl.yml +1 -1
  152. data/config/locales/en.yml +4 -0
  153. data/config/locales/headmin/dropdown/en.yml +6 -0
  154. data/config/locales/headmin/dropdown/nl.yml +6 -0
  155. data/config/locales/headmin/filters/en.yml +26 -1
  156. data/config/locales/headmin/filters/nl.yml +26 -1
  157. data/config/locales/headmin/forms/en.yml +8 -0
  158. data/config/locales/headmin/forms/nl.yml +8 -0
  159. data/config/locales/headmin/layout/en.yml +0 -9
  160. data/config/locales/headmin/layout/nl.yml +0 -9
  161. data/config/locales/headmin/media/en.yml +23 -0
  162. data/config/locales/headmin/media/nl.yml +22 -0
  163. data/config/locales/headmin/nav/en.yml +7 -0
  164. data/config/locales/headmin/nav/nl.yml +7 -0
  165. data/config/locales/headmin/table/en.yml +2 -0
  166. data/config/locales/headmin/table/nl.yml +2 -0
  167. data/config/locales/nl.yml +4 -0
  168. data/config/routes.rb +10 -0
  169. data/lib/generators/templates/views/auth/confirmations/new.html.erb +1 -1
  170. data/lib/generators/templates/views/auth/mailer/confirmation_instructions.html.erb +1 -1
  171. data/lib/generators/templates/views/auth/mailer/email_changed.html.erb +1 -1
  172. data/lib/generators/templates/views/auth/mailer/password_change.html.erb +1 -1
  173. data/lib/generators/templates/views/auth/mailer/reset_password_instructions.html.erb +1 -1
  174. data/lib/generators/templates/views/auth/mailer/unlock_instructions.html.erb +1 -1
  175. data/lib/generators/templates/views/auth/passwords/edit.html.erb +1 -1
  176. data/lib/generators/templates/views/auth/passwords/new.html.erb +1 -1
  177. data/lib/generators/templates/views/auth/registrations/edit.html.erb +1 -1
  178. data/lib/generators/templates/views/auth/registrations/new.html.erb +1 -1
  179. data/lib/generators/templates/views/auth/sessions/new.html.erb +1 -1
  180. data/lib/generators/templates/views/auth/unlocks/new.html.erb +1 -1
  181. data/lib/headmin/version.rb +1 -1
  182. data/package.json +1 -1
  183. metadata +70 -7
  184. data/.lock-487e157d270f3062a98b7b2a012753708-1272821827 +0 -0
  185. data/app/controllers/concerns/headmin/filter.rb +0 -5
  186. data/app/controllers/concerns/headmin/searchable.rb +0 -15
  187. data/app/views/headmin/filters/_select.html.erb +0 -45
  188. data/app/views/headmin/filters/filter/_template.html.erb +0 -13
@@ -17,26 +17,41 @@
17
17
  display: flex;
18
18
  flex-wrap: wrap;
19
19
  gap: map-get($spacers, 2);
20
+
21
+ a, a:link, a:hover {
22
+ color: inherit;
23
+ text-decoration: inherit;
24
+ }
20
25
  }
21
26
 
22
27
  .h-form-file-thumbnail {
23
28
  position: relative;
24
29
  pointer-events: initial !important;
25
30
  display: flex;
31
+
32
+ &:hover {
33
+ .h-form-file-thumbnail-actions {
34
+ display: block;
35
+ }
36
+ }
37
+ }
38
+
39
+ .h-form-file-thumbnail-actions {
40
+ display: none;
26
41
  }
27
42
 
28
43
  .h-form-file-thumbnail-remove {
29
44
  position: absolute;
30
- top: 0;
31
- right: 0;
45
+ top: 5px;
46
+ right: 5px;
32
47
  background: $danger;
33
- width: 20px;
34
- height: 20px;
48
+ width: 25px;
49
+ height: 25px;
35
50
  display: flex;
36
51
  align-items: center;
37
52
  justify-content: center;
38
53
  color: white;
39
- border-radius: $border-radius;
54
+ border-radius: $border-radius-pill;
40
55
  z-index: 3;
41
56
  cursor: pointer;
42
57
 
@@ -44,3 +59,23 @@
44
59
  background: tint-color($danger, $btn-hover-bg-tint-amount)
45
60
  }
46
61
  }
62
+
63
+ .h-form-file-thumbnail-edit {
64
+ position: absolute;
65
+ top: 5px;
66
+ right: 35px;
67
+ background-color: rgba(0, 0, 0, 0.7);
68
+ width: 25px;
69
+ height: 25px;
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ border-radius: $border-radius-pill;
74
+ z-index: 3;
75
+ cursor: pointer;
76
+ color: white !important;
77
+
78
+ &:hover {
79
+ background-color: rgba(0, 0, 0, 1);
80
+ }
81
+ }
@@ -0,0 +1,10 @@
1
+ .h-form-media-validation {
2
+ opacity: 0;
3
+ width: 100px;
4
+ height: 0;
5
+ padding: 0;
6
+ margin: 0;
7
+ position: absolute;
8
+ bottom: 0;
9
+ left: 0;
10
+ }
@@ -18,6 +18,10 @@
18
18
  visibility: visible;
19
19
  }
20
20
  }
21
+
22
+ .mb-3:last-of-type {
23
+ margin-bottom: 0 !important;
24
+ }
21
25
  }
22
26
 
23
27
  .repeater-row-remove {
@@ -5,7 +5,14 @@
5
5
  }
6
6
  }
7
7
 
8
+ .card-body {
9
+ .mb-3:last-child {
10
+ margin-bottom: 0 !important;
11
+ }
12
+ }
13
+
8
14
  @import "forms/autocomplete";
9
15
  @import "forms/file";
16
+ @import "forms/media";
10
17
  @import "forms/repeater";
11
18
  @import "forms/search";
@@ -1,6 +1,5 @@
1
1
  html {
2
2
  height: 100%;
3
- background: red;
4
3
  }
5
4
 
6
5
  .list-group-item {
@@ -2,5 +2,10 @@
2
2
  background: $card-cap-bg;
3
3
  height: 100vh;
4
4
  overflow-y: scroll;
5
+ display: flex;
6
+ flex-direction: column;
5
7
  }
6
8
 
9
+ .content {
10
+ flex-grow: 1
11
+ }
@@ -14,7 +14,6 @@
14
14
  .nav-brand {
15
15
  svg, img {
16
16
  max-width: 100%;
17
- height: 30px;
18
17
  }
19
18
  svg {
20
19
  fill: $white;
@@ -0,0 +1,9 @@
1
+ .media-modal {
2
+ .h-thumbnail {
3
+ cursor: pointer;
4
+ }
5
+
6
+ input[type="checkbox"]:checked + label .h-thumbnail {
7
+ background-color: #0d6efd;
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ @import "media/index";
@@ -2,7 +2,6 @@
2
2
  padding: 10px;
3
3
  background: $white;
4
4
  z-index: $zindex-popover;
5
- width: $popover-max-width;
6
5
  @include reset-text();
7
6
  @include font-size($popover-font-size);
8
7
  word-wrap: break-word;
@@ -34,3 +34,18 @@
34
34
  max-width: 100%;
35
35
  }
36
36
  }
37
+
38
+ .h-table-cell-image {
39
+ padding: 0.4rem 1rem !important;
40
+
41
+ img {
42
+ border-radius: 3px;
43
+ }
44
+ }
45
+
46
+ .h-table-cell-color {
47
+ width: 22px;
48
+ height: 22px;
49
+ border-radius: 3px;
50
+ background-color: var(--cell-color);
51
+ }
@@ -1,7 +1,7 @@
1
1
  @charset "UTF-8";
2
2
  @import "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css";
3
3
 
4
- /* sass-plugin-0:/opt/homebrew/var/www/headmin/src/scss/headmin.scss */
4
+ /* sass-plugin-0:/usr/local/var/www/headmin/src/scss/headmin.scss */
5
5
  :root {
6
6
  --bs-blue: #0d6efd;
7
7
  --bs-indigo: #6610f2;
@@ -12971,6 +12971,9 @@ span.flatpickr-weekday {
12971
12971
  content: " *";
12972
12972
  color: #dc3545;
12973
12973
  }
12974
+ .card-body .mb-3:last-child {
12975
+ margin-bottom: 0 !important;
12976
+ }
12974
12977
  .h-autocomplete {
12975
12978
  position: absolute;
12976
12979
  top: calc(100% + 2px);
@@ -13019,29 +13022,69 @@ span.flatpickr-weekday {
13019
13022
  flex-wrap: wrap;
13020
13023
  gap: 0.5rem;
13021
13024
  }
13025
+ .h-form-file-thumbnails a,
13026
+ .h-form-file-thumbnails a:link,
13027
+ .h-form-file-thumbnails a:hover {
13028
+ color: inherit;
13029
+ text-decoration: inherit;
13030
+ }
13022
13031
  .h-form-file-thumbnail {
13023
13032
  position: relative;
13024
13033
  pointer-events: initial !important;
13025
13034
  display: flex;
13026
13035
  }
13036
+ .h-form-file-thumbnail:hover .h-form-file-thumbnail-actions {
13037
+ display: block;
13038
+ }
13039
+ .h-form-file-thumbnail-actions {
13040
+ display: none;
13041
+ }
13027
13042
  .h-form-file-thumbnail-remove {
13028
13043
  position: absolute;
13029
- top: 0;
13030
- right: 0;
13044
+ top: 5px;
13045
+ right: 5px;
13031
13046
  background: #dc3545;
13032
- width: 20px;
13033
- height: 20px;
13047
+ width: 25px;
13048
+ height: 25px;
13034
13049
  display: flex;
13035
13050
  align-items: center;
13036
13051
  justify-content: center;
13037
13052
  color: white;
13038
- border-radius: 0.25rem;
13053
+ border-radius: 50rem;
13039
13054
  z-index: 3;
13040
13055
  cursor: pointer;
13041
13056
  }
13042
13057
  .h-form-file-thumbnail-remove:hover {
13043
13058
  background: #e15361;
13044
13059
  }
13060
+ .h-form-file-thumbnail-edit {
13061
+ position: absolute;
13062
+ top: 5px;
13063
+ right: 35px;
13064
+ background-color: rgba(0, 0, 0, 0.7);
13065
+ width: 25px;
13066
+ height: 25px;
13067
+ display: flex;
13068
+ align-items: center;
13069
+ justify-content: center;
13070
+ border-radius: 50rem;
13071
+ z-index: 3;
13072
+ cursor: pointer;
13073
+ color: white !important;
13074
+ }
13075
+ .h-form-file-thumbnail-edit:hover {
13076
+ background-color: black;
13077
+ }
13078
+ .h-form-media-validation {
13079
+ opacity: 0;
13080
+ width: 100px;
13081
+ height: 0;
13082
+ padding: 0;
13083
+ margin: 0;
13084
+ position: absolute;
13085
+ bottom: 0;
13086
+ left: 0;
13087
+ }
13045
13088
  .repeater {
13046
13089
  position: relative;
13047
13090
  }
@@ -13057,6 +13100,9 @@ span.flatpickr-weekday {
13057
13100
  .repeater-row:hover .repeater-row-handle {
13058
13101
  visibility: visible;
13059
13102
  }
13103
+ .repeater-row .mb-3:last-of-type {
13104
+ margin-bottom: 0 !important;
13105
+ }
13060
13106
  .repeater-row-remove {
13061
13107
  position: absolute;
13062
13108
  top: calc(50% - 17px);
@@ -13103,7 +13149,6 @@ input[type=search] {
13103
13149
  }
13104
13150
  html {
13105
13151
  height: 100%;
13106
- background: red;
13107
13152
  }
13108
13153
  .list-group-item.active .text-muted {
13109
13154
  color: #fff !important;
@@ -13117,6 +13162,11 @@ mark,
13117
13162
  background: rgba(0, 0, 0, 0.03);
13118
13163
  height: 100vh;
13119
13164
  overflow-y: scroll;
13165
+ display: flex;
13166
+ flex-direction: column;
13167
+ }
13168
+ .content {
13169
+ flex-grow: 1;
13120
13170
  }
13121
13171
  .sidebar {
13122
13172
  font-size: 0.99rem;
@@ -13134,7 +13184,6 @@ mark,
13134
13184
  .nav-brand svg,
13135
13185
  .nav-brand img {
13136
13186
  max-width: 100%;
13137
- height: 30px;
13138
13187
  }
13139
13188
  .nav-brand svg {
13140
13189
  fill: #ffffff;
@@ -13200,6 +13249,18 @@ body.empty {
13200
13249
  width: 300px;
13201
13250
  max-width: 100%;
13202
13251
  }
13252
+ .h-table-cell-image {
13253
+ padding: 0.4rem 1rem !important;
13254
+ }
13255
+ .h-table-cell-image img {
13256
+ border-radius: 3px;
13257
+ }
13258
+ .h-table-cell-color {
13259
+ width: 22px;
13260
+ height: 22px;
13261
+ border-radius: 3px;
13262
+ background-color: var(--cell-color);
13263
+ }
13203
13264
  .btn-link {
13204
13265
  text-decoration: none;
13205
13266
  }
@@ -13310,6 +13371,54 @@ body.empty {
13310
13371
  .h-filter-popup.closed {
13311
13372
  display: none;
13312
13373
  }
13374
+ .h-filter-row {
13375
+ padding: 0.5rem 0 0.5rem 0;
13376
+ position: relative;
13377
+ flex-wrap: unset;
13378
+ display: flex;
13379
+ gap: 10px;
13380
+ }
13381
+ .h-filter-row:first-child {
13382
+ padding-top: 0;
13383
+ }
13384
+ .h-filter-row:hover .h-filter-add-input,
13385
+ .h-filter-row:hover .h-filter-remove-input {
13386
+ display: block;
13387
+ }
13388
+ .h-filter-row input,
13389
+ .h-filter-row select:not(.h-filter-operator) {
13390
+ min-width: 200px;
13391
+ }
13392
+ .h-filter-operator {
13393
+ width: 62px;
13394
+ }
13395
+ .h-filter-conditional {
13396
+ position: relative;
13397
+ display: flex;
13398
+ justify-content: center;
13399
+ align-items: center;
13400
+ }
13401
+ .h-filter-conditional select {
13402
+ width: 50px;
13403
+ }
13404
+ .h-filter-conditional::before {
13405
+ content: "";
13406
+ position: absolute;
13407
+ top: calc(50% - 1px);
13408
+ left: 0;
13409
+ width: calc(50% - 35px);
13410
+ height: 1px;
13411
+ background: rgba(0, 0, 0, 0.2);
13412
+ }
13413
+ .h-filter-conditional::after {
13414
+ content: "";
13415
+ position: absolute;
13416
+ top: calc(50% - 1px);
13417
+ left: calc(50% + 35px);
13418
+ width: calc(50% - 35px);
13419
+ height: 1px;
13420
+ background: rgba(0, 0, 0, 0.2);
13421
+ }
13313
13422
  .h-filter-remove {
13314
13423
  border-left: 1px solid #d1d5db;
13315
13424
  padding-left: 8px;
@@ -13318,11 +13427,30 @@ body.empty {
13318
13427
  .h-filter-remove i::before {
13319
13428
  font-size: 0.8em;
13320
13429
  }
13430
+ .h-filter-add-input {
13431
+ position: absolute !important;
13432
+ top: calc(100% - 12px);
13433
+ left: calc(50% - 17px);
13434
+ z-index: 9;
13435
+ display: none;
13436
+ }
13437
+ .h-filter-remove-input {
13438
+ position: absolute !important;
13439
+ top: calc(50% - 15px);
13440
+ left: calc(100% - 4px);
13441
+ z-index: 9;
13442
+ display: none;
13443
+ }
13444
+ .media-modal .h-thumbnail {
13445
+ cursor: pointer;
13446
+ }
13447
+ .media-modal input[type=checkbox]:checked + label .h-thumbnail {
13448
+ background-color: #0d6efd;
13449
+ }
13321
13450
  .h-popup {
13322
13451
  padding: 10px;
13323
13452
  background: #ffffff;
13324
13453
  z-index: 1070;
13325
- width: 276px;
13326
13454
  font-family: var(--bs-font-sans-serif);
13327
13455
  font-style: normal;
13328
13456
  font-weight: 400;
@@ -60,6 +60,7 @@
60
60
  @import "headmin/table";
61
61
  @import "headmin/utilities";
62
62
  @import "headmin/filter";
63
+ @import "headmin/media";
63
64
  @import "headmin/popup";
64
65
  @import "headmin/thumbnail";
65
66
  @import "headmin/syntax";
@@ -0,0 +1,27 @@
1
+ module Headmin
2
+ module Filterable
3
+ # Will create a Headmin::Filters object with a default configuration for "id" and "search"
4
+ #
5
+ # Example:
6
+ #
7
+ # orders = Order
8
+ # orders = filter(orders, {
9
+ # status: :text,
10
+ # price: :number,
11
+ # in_stock: :boolean
12
+ # })
13
+ # @orders = orders.all
14
+
15
+ def filter(collection, filter_types = {})
16
+ type_hash = default_filter_types.merge(filter_types)
17
+ Headmin::Filters.new(params, type_hash).query(collection)
18
+ end
19
+
20
+ def default_filter_types
21
+ {
22
+ id: :number,
23
+ search: :search
24
+ }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ class Headmin::MediaController < HeadminController
2
+ layout false
3
+
4
+ def index
5
+ @blobs =
6
+ ActiveStorage::Blob
7
+ .left_outer_joins(:attachments)
8
+ .where.not(active_storage_attachments: {record_type: "ActiveStorage::VariantRecord"}) # Not a variant
9
+ .or(ActiveStorage::Blob.where(active_storage_attachments: {id: nil})) # Or an orphan
10
+ .order(created_at: :desc)
11
+ .group(:id)
12
+ .all
13
+ end
14
+
15
+ def create
16
+ blobs = []
17
+ media_params[:files].reject { |c| c.blank? }.each do |file|
18
+ blobs << ActiveStorage::Blob.create_and_upload!(io: file, filename: file.original_filename)
19
+ end
20
+
21
+ respond_to do |format|
22
+ format.turbo_stream {
23
+ @blobs = blobs
24
+ }
25
+ format.html { redirect_to root_path }
26
+ end
27
+ end
28
+
29
+ def show
30
+ @blob = ActiveStorage::Blob.find(params[:id])
31
+ end
32
+
33
+ def update
34
+ @blob = ActiveStorage::Blob.find(params[:id])
35
+ media_item_params[:filename] = media_item_params[:filename] + "." + @blob.filename.to_s.rpartition(".").last
36
+ if @blob.update(media_item_params)
37
+ flash.now[:notice] = t("admin.flash.updated", name: @blob.filename)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def media_params
44
+ params.permit(
45
+ files: []
46
+ )
47
+ end
48
+
49
+ def media_item_params
50
+ params.require(:blob).permit!
51
+ end
52
+ end
@@ -0,0 +1,2 @@
1
+ class HeadminController < ApplicationController
2
+ end
@@ -5,7 +5,6 @@ module Headmin
5
5
  included do
6
6
  # Configuration
7
7
  has_closure_tree
8
-
9
8
  # Associations
10
9
  belongs_to :fieldable, polymorphic: true, optional: true, touch: true
11
10
  belongs_to :field, optional: true, touch: true
@@ -17,10 +17,19 @@ module Headmin
17
17
  @fields_hash = hash
18
18
  end
19
19
 
20
+ def include_tables
21
+ []
22
+ end
23
+
24
+ def default_include_tables
25
+ [files_attachments: :blob]
26
+ end
27
+
20
28
  private
21
29
 
22
30
  def parse_fields
23
- fields.where(parent: nil).order(position: :asc).map { |field| parse_hash_tree(field.hash_tree) }.reduce({}, :merge)
31
+ hash_tree = fields.includes(default_include_tables | include_tables).order(position: :asc).hash_tree
32
+ parse_hash_tree(hash_tree)
24
33
  end
25
34
 
26
35
  def build_fields
@@ -8,9 +8,14 @@ module Headmin
8
8
  hint.present?
9
9
  end
10
10
 
11
+ def maxlength?
12
+ maxlength.present?
13
+ end
14
+
11
15
  def hint_options
12
16
  {
13
- content: hint
17
+ content: hint,
18
+ maxlength: maxlength
14
19
  }
15
20
  end
16
21
  end
@@ -9,7 +9,7 @@ module Headmin
9
9
  end
10
10
 
11
11
  def prefixes
12
- paths + ["website/blocks", "blocks", ""]
12
+ paths + ["website/blocks", "blocks"]
13
13
  end
14
14
  end
15
15
  end