headmin 0.3.4 → 0.4.0

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 (157) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +27 -0
  3. data/.gitignore +14 -0
  4. data/.nvmrc +1 -0
  5. data/CHANGELOG.md +24 -0
  6. data/Gemfile +7 -4
  7. data/Gemfile.lock +171 -3
  8. data/README.md +7 -0
  9. data/Rakefile +1 -7
  10. data/app/assets/javascripts/headmin/config/i18n.js +9 -9
  11. data/app/assets/javascripts/headmin/controllers/autocomplete_controller.js +255 -0
  12. data/app/assets/javascripts/headmin/controllers/blocks_controller.js +74 -79
  13. data/app/assets/javascripts/headmin/controllers/date_range_controller.js +24 -24
  14. data/app/assets/javascripts/headmin/controllers/dropzone_controller.js +23 -25
  15. data/app/assets/javascripts/headmin/controllers/file_preview_controller.js +237 -237
  16. data/app/assets/javascripts/headmin/controllers/filter_controller.js +44 -44
  17. data/app/assets/javascripts/headmin/controllers/filters_controller.js +57 -61
  18. data/app/assets/javascripts/headmin/controllers/flatpickr_controller.js +29 -29
  19. data/app/assets/javascripts/headmin/controllers/hello_controller.js +3 -3
  20. data/app/assets/javascripts/headmin/controllers/notification_controller.js +7 -6
  21. data/app/assets/javascripts/headmin/controllers/popup_controller.js +51 -52
  22. data/app/assets/javascripts/headmin/controllers/redactorx_controller.js +36 -9
  23. data/app/assets/javascripts/headmin/controllers/repeater_controller.js +122 -125
  24. data/app/assets/javascripts/headmin/controllers/select_controller.js +40 -39
  25. data/app/assets/javascripts/headmin/controllers/table_actions_controller.js +100 -101
  26. data/app/assets/javascripts/headmin/controllers/table_controller.js +115 -115
  27. data/app/assets/javascripts/headmin/index.js +38 -35
  28. data/app/assets/javascripts/headmin.js +243 -34
  29. data/app/assets/stylesheets/headmin/forms/autocomplete.scss +21 -0
  30. data/app/assets/stylesheets/headmin/forms/file.scss +46 -0
  31. data/app/assets/stylesheets/headmin/forms/repeater.scss +62 -0
  32. data/app/assets/stylesheets/headmin/forms/search.scss +12 -0
  33. data/app/assets/stylesheets/headmin/forms.scss +11 -0
  34. data/app/assets/stylesheets/headmin/general.scss +5 -0
  35. data/app/assets/stylesheets/headmin/overrides/bootstrap.scss +5 -3
  36. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +74 -0
  37. data/app/assets/stylesheets/headmin/popup.scss +1 -0
  38. data/app/assets/stylesheets/headmin/syntax.scss +36 -349
  39. data/app/assets/stylesheets/headmin/table.scss +1 -1
  40. data/app/assets/stylesheets/headmin/utilities/buttons.scss +19 -0
  41. data/app/assets/stylesheets/headmin/utilities/dropzone.scss +72 -0
  42. data/app/assets/stylesheets/headmin/utilities.scss +2 -68
  43. data/app/assets/stylesheets/headmin.css +205 -205
  44. data/app/assets/stylesheets/headmin.scss +1 -1
  45. data/app/helpers/headmin/admin_helper.rb +0 -1
  46. data/app/helpers/headmin/form_helper.rb +2 -8
  47. data/app/models/concerns/headmin/blockable.rb +1 -1
  48. data/app/models/concerns/headmin/field.rb +1 -0
  49. data/app/models/concerns/headmin/form/autocompletable.rb +38 -0
  50. data/app/models/concerns/headmin/form/hintable.rb +19 -0
  51. data/app/models/concerns/headmin/form/input_groupable.rb +23 -0
  52. data/app/models/concerns/headmin/form/labelable.rb +33 -0
  53. data/app/models/concerns/headmin/form/listable.rb +28 -0
  54. data/app/models/concerns/headmin/form/placeholderable.rb +13 -0
  55. data/app/models/concerns/headmin/form/validatable.rb +40 -0
  56. data/app/models/concerns/headmin/form/wrappable.rb +21 -0
  57. data/app/models/headmin/.DS_Store +0 -0
  58. data/app/models/headmin/blocks_view.rb +15 -0
  59. data/app/models/headmin/form/blocks_view.rb +29 -0
  60. data/app/models/headmin/form/checkbox_view.rb +52 -0
  61. data/app/models/headmin/form/date_range_view.rb +25 -0
  62. data/app/models/headmin/form/date_view.rb +45 -0
  63. data/app/models/headmin/form/email_view.rb +48 -0
  64. data/app/models/headmin/form/file_view.rb +116 -0
  65. data/app/models/headmin/form/flatpickr_range_view.rb +102 -0
  66. data/app/models/headmin/form/flatpickr_view.rb +37 -0
  67. data/app/models/headmin/form/hidden_view.rb +10 -0
  68. data/app/models/headmin/form/hint_view.rb +6 -0
  69. data/app/models/headmin/form/input_group_view.rb +19 -0
  70. data/app/models/headmin/form/label_view.rb +24 -0
  71. data/app/models/headmin/form/number_view.rb +49 -0
  72. data/app/models/headmin/form/password_view.rb +44 -0
  73. data/app/models/headmin/form/redactorx_view.rb +59 -0
  74. data/app/models/headmin/form/search_view.rb +48 -0
  75. data/app/models/headmin/form/select_view.rb +62 -0
  76. data/app/models/headmin/form/switch_view.rb +23 -0
  77. data/app/models/headmin/form/text_view.rb +48 -0
  78. data/app/models/headmin/form/textarea_view.rb +44 -0
  79. data/app/models/headmin/form/url_view.rb +48 -0
  80. data/app/models/headmin/form/wrapper_view.rb +19 -0
  81. data/app/models/headmin/form/wysiwyg_view.rb +17 -0
  82. data/app/models/headmin/{thumbnail.rb → thumbnail_view.rb} +6 -1
  83. data/app/models/view_model.rb +58 -0
  84. data/app/views/headmin/_blocks.html.erb +13 -9
  85. data/app/views/headmin/_heading.html.erb +7 -1
  86. data/app/views/headmin/_thumbnail.html.erb +1 -37
  87. data/app/views/headmin/forms/_autocomplete.html.erb +11 -0
  88. data/app/views/headmin/forms/_blocks.html.erb +16 -17
  89. data/app/views/headmin/forms/_checkbox.html.erb +24 -29
  90. data/app/views/headmin/forms/_datalist.html.erb +3 -0
  91. data/app/views/headmin/forms/_date.html.erb +24 -24
  92. data/app/views/headmin/forms/_date_range.html.erb +19 -21
  93. data/app/views/headmin/forms/_email.html.erb +27 -32
  94. data/app/views/headmin/forms/_errors.html.erb +2 -3
  95. data/app/views/headmin/forms/_file.html.erb +84 -181
  96. data/app/views/headmin/forms/_flatpickr.html.erb +19 -20
  97. data/app/views/headmin/forms/_flatpickr_range.html.erb +28 -37
  98. data/app/views/headmin/forms/_hidden.html.erb +9 -10
  99. data/app/views/headmin/forms/_hint.html.erb +16 -0
  100. data/app/views/headmin/forms/_input_group.html.erb +21 -0
  101. data/app/views/headmin/forms/_label.html.erb +5 -13
  102. data/app/views/headmin/forms/_number.html.erb +23 -35
  103. data/app/views/headmin/forms/_password.html.erb +21 -30
  104. data/app/views/headmin/forms/_redactorx.html.erb +21 -40
  105. data/app/views/headmin/forms/_repeater.html.erb +55 -60
  106. data/app/views/headmin/forms/_search.html.erb +43 -0
  107. data/app/views/headmin/forms/_select.html.erb +24 -49
  108. data/app/views/headmin/forms/_switch.html.erb +29 -0
  109. data/app/views/headmin/forms/_text.html.erb +42 -96
  110. data/app/views/headmin/forms/_textarea.html.erb +21 -32
  111. data/app/views/headmin/forms/_url.html.erb +26 -31
  112. data/app/views/headmin/forms/_validation.html.erb +10 -13
  113. data/app/views/headmin/forms/_wrapper.html.erb +9 -0
  114. data/app/views/headmin/forms/_wysiwyg.html.erb +28 -0
  115. data/app/views/headmin/forms/autocomplete/_item.html.erb +3 -0
  116. data/app/views/headmin/forms/autocomplete/_list.html.erb +3 -0
  117. data/app/views/headmin/forms/fields/_group.html.erb +5 -3
  118. data/app/views/headmin/forms/repeater/_row.html.erb +4 -4
  119. data/bin/console +0 -1
  120. data/config/locales/headmin/forms/en.yml +0 -11
  121. data/config/locales/headmin/forms/nl.yml +0 -11
  122. data/esbuild-css.js +18 -18
  123. data/esbuild-js.js +8 -8
  124. data/headmin.gemspec +1 -3
  125. data/lib/generators/templates/controllers/auth/confirmations_controller.rb +0 -2
  126. data/lib/generators/templates/controllers/auth/omniauth_callbacks_controller.rb +0 -2
  127. data/lib/generators/templates/controllers/auth/passwords_controller.rb +0 -2
  128. data/lib/generators/templates/controllers/auth/registrations_controller.rb +0 -2
  129. data/lib/generators/templates/controllers/auth/sessions_controller.rb +0 -2
  130. data/lib/generators/templates/controllers/auth/unlocks_controller.rb +0 -2
  131. data/lib/headmin/version.rb +1 -3
  132. data/lib/headmin.rb +0 -2
  133. data/package-lock.json +5359 -0
  134. data/package.json +12 -4
  135. data/view_model_benchmark.rb +74 -0
  136. data/yarn-error.log +17 -12
  137. data/yarn.lock +1575 -31
  138. metadata +62 -24
  139. data/app/assets/stylesheets/headmin/form.scss +0 -132
  140. data/app/assets/stylesheets/headmin/overrides/redactorx.css +0 -3
  141. data/app/helpers/headmin/documentation_helper.rb +0 -35
  142. data/app/models/headmin/documentation_renderer.rb +0 -32
  143. data/app/models/headmin/form/base.rb +0 -78
  144. data/app/models/headmin/form/text.rb +0 -51
  145. data/app/services/block_service.rb +0 -72
  146. data/app/views/headmin/_card.html.erb +0 -52
  147. data/app/views/headmin/forms/_actions.html.erb +0 -28
  148. data/app/views/headmin/forms/_base.html.erb +0 -114
  149. data/app/views/headmin/forms/_image.html.erb +0 -21
  150. data/app/views/headmin/forms/_video.html.erb +0 -21
  151. data/app/views/headmin/forms/actions/_destroy.html.erb +0 -13
  152. data/app/views/headmin/forms/actions/_save.html.erb +0 -12
  153. data/app/views/headmin/forms/actions/_view.html.erb +0 -15
  154. data/docs/blocks-and-fields.md +0 -54
  155. data/docs/blocks.md +0 -48
  156. data/docs/devise.md +0 -41
  157. data/docs/fields.md +0 -79
@@ -0,0 +1,44 @@
1
+ module Headmin
2
+ module Form
3
+ class PasswordView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::InputGroupable
6
+ include Headmin::Form::Labelable
7
+ include Headmin::Form::Placeholderable
8
+ include Headmin::Form::Validatable
9
+ include Headmin::Form::Wrappable
10
+
11
+ def input_options
12
+ keys = attributes - %i[append attribute float form input_group label prepend validate wrapper]
13
+ options = to_h.slice(*keys)
14
+ default_input_options.merge(options)
15
+ end
16
+
17
+ def input_group_options
18
+ default_input_group_options
19
+ .merge(label_input_group_options)
20
+ .merge(@input_group || {})
21
+ end
22
+
23
+ def wrapper_options
24
+ default_wrapper_options.merge({
25
+ class: ["mb-3", ("form-floating" if float)]
26
+ }).merge(@wrapper || {})
27
+ end
28
+
29
+ private
30
+
31
+ def default_input_options
32
+ {
33
+ aria: {describedby: validation_id},
34
+ class: [form_control_class, validation_class],
35
+ placeholder: placeholder
36
+ }
37
+ end
38
+
39
+ def form_control_class
40
+ plaintext ? "form-control-plaintext" : "form-control"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ module Headmin
2
+ module Form
3
+ class RedactorxView < ViewModel
4
+ def options
5
+ default_options.merge(to_h)
6
+ end
7
+
8
+ private
9
+
10
+ def default_options
11
+ {
12
+ data: {
13
+ controller: "redactorx",
14
+ "redactor-options": redactor_options
15
+ }
16
+ }
17
+ end
18
+
19
+ def control
20
+ @control || (hybrid ? true : nil)
21
+ end
22
+
23
+ def context
24
+ @context || (hybrid ? true : nil)
25
+ end
26
+
27
+ def toolbar
28
+ @toolbar || (hybrid ? false : nil)
29
+ end
30
+
31
+ def addbar
32
+ @addbar || %w[paragraph image embed table quote pre line]
33
+ end
34
+
35
+ def plugins
36
+ @plugins || %w[shortcut]
37
+ end
38
+
39
+ attr_reader :topbar
40
+
41
+ def redactor_options
42
+ default_redactor_options.merge(redactor || {})
43
+ end
44
+
45
+ def default_redactor_options
46
+ {
47
+ control: control,
48
+ context: context,
49
+ toolbar: toolbar,
50
+ buttons: {
51
+ addbar: addbar,
52
+ plugins: plugins,
53
+ topbar: topbar
54
+ }
55
+ }.delete_if { |k, v| v.nil? }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,48 @@
1
+ module Headmin
2
+ module Form
3
+ class SearchView < ViewModel
4
+ include Headmin::Form::Autocompletable
5
+ include Headmin::Form::Hintable
6
+ include Headmin::Form::InputGroupable
7
+ include Headmin::Form::Labelable
8
+ include Headmin::Form::Listable
9
+ include Headmin::Form::Placeholderable
10
+ include Headmin::Form::Validatable
11
+ include Headmin::Form::Wrappable
12
+
13
+ def input_options
14
+ keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
+ options = to_h.slice(*keys)
16
+ options = default_input_options.merge(options)
17
+ options.merge(autocomplete_input_options)
18
+ end
19
+
20
+ def input_group_options
21
+ default_input_group_options
22
+ .merge(autocomplete_input_group_options)
23
+ .merge(label_input_group_options)
24
+ .merge(@input_group || {})
25
+ end
26
+
27
+ def wrapper_options
28
+ default_wrapper_options.merge({
29
+ class: ["mb-3", ("form-floating" if float)]
30
+ }).merge(@wrapper || {})
31
+ end
32
+
33
+ private
34
+
35
+ def default_input_options
36
+ {
37
+ aria: {describedby: validation_id},
38
+ class: [form_control_class, validation_class],
39
+ placeholder: placeholder
40
+ }
41
+ end
42
+
43
+ def form_control_class
44
+ plaintext ? "form-control-plaintext" : "form-control"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,62 @@
1
+ module Headmin
2
+ module Form
3
+ class SelectView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::InputGroupable
6
+ include Headmin::Form::Labelable
7
+ include Headmin::Form::Listable
8
+ include Headmin::Form::Placeholderable
9
+ include Headmin::Form::Validatable
10
+ include Headmin::Form::Wrappable
11
+
12
+ def input_options
13
+ keys = attributes - %i[append attribute collection float form input_group include_blank label prepend validate selected tags wrapper]
14
+ options = to_h.slice(*keys)
15
+ default_input_options.merge(options)
16
+ end
17
+
18
+ def input_group_options
19
+ default_input_group_options
20
+ .merge(label_input_group_options)
21
+ .merge(@input_group || {})
22
+ end
23
+
24
+ def wrapper_options
25
+ default_wrapper_options.merge({
26
+ class: ["mb-3", ("form-floating" if float)]
27
+ }).merge(@wrapper || {})
28
+ end
29
+
30
+ def select_options
31
+ keys = %i[include_blank selected]
32
+ options = to_h.slice(*keys)
33
+ default_options.merge(options)
34
+ end
35
+
36
+ private
37
+
38
+ def default_options
39
+ {
40
+ selected: form.object&.send(attribute)
41
+ }
42
+ end
43
+
44
+ def default_input_options
45
+ {
46
+ aria: {describedby: validation_id},
47
+ class: [form_control_class, validation_class],
48
+ data: {
49
+ tags: tags,
50
+ controller: "select"
51
+ },
52
+ multiple: tags,
53
+ placeholder: placeholder
54
+ }
55
+ end
56
+
57
+ def form_control_class
58
+ plaintext ? "form-control-plaintext" : "form-select"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,23 @@
1
+ module Headmin
2
+ module Form
3
+ class SwitchView < ViewModel
4
+ def options
5
+ default_options.merge(to_h)
6
+ end
7
+
8
+ private
9
+
10
+ def default_options
11
+ {
12
+ wrapper: default_wrapper_options
13
+ }
14
+ end
15
+
16
+ def default_wrapper_options
17
+ {
18
+ class: %w[form-check form-switch mb-3]
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ module Headmin
2
+ module Form
3
+ class TextView < ViewModel
4
+ include Headmin::Form::Autocompletable
5
+ include Headmin::Form::Hintable
6
+ include Headmin::Form::InputGroupable
7
+ include Headmin::Form::Labelable
8
+ include Headmin::Form::Listable
9
+ include Headmin::Form::Placeholderable
10
+ include Headmin::Form::Validatable
11
+ include Headmin::Form::Wrappable
12
+
13
+ def input_options
14
+ keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
+ options = to_h.slice(*keys)
16
+ options = default_input_options.merge(options)
17
+ options.merge(autocomplete_input_options)
18
+ end
19
+
20
+ def input_group_options
21
+ default_input_group_options
22
+ .merge(autocomplete_input_group_options)
23
+ .merge(label_input_group_options)
24
+ .merge(@input_group || {})
25
+ end
26
+
27
+ def wrapper_options
28
+ default_wrapper_options.merge({
29
+ class: ["mb-3", ("form-floating" if float)]
30
+ }).merge(@wrapper || {})
31
+ end
32
+
33
+ private
34
+
35
+ def default_input_options
36
+ {
37
+ aria: {describedby: validation_id},
38
+ class: [form_control_class, validation_class],
39
+ placeholder: placeholder
40
+ }
41
+ end
42
+
43
+ def form_control_class
44
+ plaintext ? "form-control-plaintext" : "form-control"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ module Headmin
2
+ module Form
3
+ class TextareaView < ViewModel
4
+ include Headmin::Form::Hintable
5
+ include Headmin::Form::InputGroupable
6
+ include Headmin::Form::Labelable
7
+ include Headmin::Form::Placeholderable
8
+ include Headmin::Form::Validatable
9
+ include Headmin::Form::Wrappable
10
+
11
+ def input_options
12
+ keys = attributes - %i[attribute float form input_group label validate wrapper]
13
+ options = to_h.slice(*keys)
14
+ default_input_options.merge(options)
15
+ end
16
+
17
+ def input_group_options
18
+ default_input_group_options
19
+ .merge(label_input_group_options)
20
+ .merge(@input_group || {})
21
+ end
22
+
23
+ def wrapper_options
24
+ default_wrapper_options.merge({
25
+ class: ["mb-3", ("form-floating" if float)]
26
+ }).merge(@wrapper || {})
27
+ end
28
+
29
+ private
30
+
31
+ def default_input_options
32
+ {
33
+ aria: {describedby: validation_id},
34
+ class: [form_control_class, validation_class],
35
+ placeholder: placeholder
36
+ }
37
+ end
38
+
39
+ def form_control_class
40
+ plaintext ? "form-control-plaintext" : "form-control"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ module Headmin
2
+ module Form
3
+ class UrlView < ViewModel
4
+ include Headmin::Form::Autocompletable
5
+ include Headmin::Form::Hintable
6
+ include Headmin::Form::InputGroupable
7
+ include Headmin::Form::Labelable
8
+ include Headmin::Form::Listable
9
+ include Headmin::Form::Placeholderable
10
+ include Headmin::Form::Validatable
11
+ include Headmin::Form::Wrappable
12
+
13
+ def input_options
14
+ keys = attributes - %i[append attribute collection float form input_group label prepend validate wrapper]
15
+ options = to_h.slice(*keys)
16
+ options = default_input_options.merge(options)
17
+ options.merge(autocomplete_input_options)
18
+ end
19
+
20
+ def input_group_options
21
+ default_input_group_options
22
+ .merge(autocomplete_input_group_options)
23
+ .merge(label_input_group_options)
24
+ .merge(@input_group || {})
25
+ end
26
+
27
+ def wrapper_options
28
+ default_wrapper_options.merge({
29
+ class: ["mb-3", ("form-floating" if float)]
30
+ }).merge(@wrapper || {})
31
+ end
32
+
33
+ private
34
+
35
+ def default_input_options
36
+ {
37
+ aria: {describedby: validation_id},
38
+ class: [form_control_class, validation_class],
39
+ placeholder: placeholder
40
+ }
41
+ end
42
+
43
+ def form_control_class
44
+ plaintext ? "form-control-plaintext" : "form-control"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ module Headmin
2
+ module Form
3
+ class WrapperView < ViewModel
4
+ def options
5
+ keys = attributes - %i[bypass]
6
+ options = to_h.slice(*keys)
7
+ default_options.merge(options)
8
+ end
9
+
10
+ private
11
+
12
+ def default_options
13
+ {
14
+ class: ["mb-3"]
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Headmin
2
+ module Form
3
+ class WysiwygView < ViewModel
4
+ def options
5
+ default_options.merge(to_h)
6
+ end
7
+
8
+ private
9
+
10
+ def default_options
11
+ {
12
+ hybrid: toolbar == false
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  module Headmin
2
- class Thumbnail
2
+ class ThumbnailView
3
3
  def initialize(local_assigns)
4
4
  @local_assigns = local_assigns
5
5
  end
@@ -22,6 +22,10 @@ module Headmin
22
22
  @local_assigns[:src]
23
23
  end
24
24
 
25
+ def icon
26
+ @local_assigns[:icon]
27
+ end
28
+
25
29
  def mime_type
26
30
  if src
27
31
  stripped_path = URI.parse(src).path
@@ -36,6 +40,7 @@ module Headmin
36
40
 
37
41
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
38
42
  def icon_name
43
+ return icon if icon
39
44
  type_map = {
40
45
  image: %w[image/bmp image/gif image/vnd.microsoft.icon image/jpeg image/png image/svg+xml image/tiff image/webp],
41
46
  play: %w[video/mp4 video/mpeg video/ogg video/mp2t video/webm video/3gpp video/3gpp2],
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ViewModel
4
+ # = View Model
5
+ #
6
+ # A View Model is a class that allows you to set an arbitrary hash of attributes and access all values by calling
7
+ # attribute methods.
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # model = ViewModel.new(a: 1, b: {b1: 1, b2: 2}, c: 3)
12
+ #
13
+ # model.a # => 1
14
+ # model.b # => {b1: 1, b2: 2}
15
+ # model.c # => 3
16
+ #
17
+ # Reserved methods or attributes are left untouched. If you want to access an attribute that collides with a reserved
18
+ # method, you can do it via the +to_hash+ method.
19
+ #
20
+ # model = ViewModel.new(class: "test")
21
+ #
22
+ # model.class # => ViewModel
23
+ # model.to_hash[:class] # => "test"
24
+
25
+ def initialize(hash = {})
26
+ hash.each do |key, value|
27
+ instance_variable_set("@#{key}", value)
28
+ end
29
+ end
30
+
31
+ def attributes
32
+ instance_variables.map { |instance_variable| instance_variable.to_s.delete("@").to_sym }
33
+ end
34
+
35
+ def to_hash
36
+ attributes.map { |attribute| {attribute => value_for(attribute)} }.inject(:merge)
37
+ end
38
+
39
+ alias_method :to_h, :to_hash
40
+
41
+ private
42
+
43
+ def value_for(attribute)
44
+ reserved_methods.include?(attribute) ? instance_variable_get("@#{attribute}") : send(attribute)
45
+ end
46
+
47
+ def method_missing(m, *args, &block)
48
+ instance_variable_get("@#{m}")
49
+ end
50
+
51
+ def respond_to_missing?
52
+ true
53
+ end
54
+
55
+ def reserved_methods
56
+ Class.methods + Class.private_methods
57
+ end
58
+ end
@@ -1,24 +1,28 @@
1
1
  <%
2
2
  # headmin/blocks
3
3
  #
4
- # ==== Options
4
+ # ==== Required parameters
5
5
  # * +blockable</tt> - Object with blocks association
6
- # * +path</tt> - Directory where to look for block templates
6
+ #
7
+ # ==== Optional parameters
8
+ # * +paths</tt> - Directories where to look for block templates
7
9
  #
8
10
  # ==== Examples
9
- # Basic version. This will only look for blocks in 'website/blocks'
11
+ # Basic version. (looks in views/website/blocks, views/blocks or views directory )
10
12
  # <%= render "headmin/blocks", blockable: @page %#>
11
13
  #
12
- # Define the path to look for block templates like this:
13
- # <%= render "headmin/blocks", blockable: @page, path: 'website/pages/blocks' %#>
14
+ # Define one ore more path where the templates could be located:
15
+ # <%= render "headmin/blocks", blockable: @page, paths: %w(website/pages/blocks) %#>
14
16
 
15
- blockable = local_assigns.has_key?(:blockable) ? blockable : nil
16
- path = local_assigns.has_key?(:path) ? path : nil
17
+ blocks = Headmin::BlocksView.new(local_assigns)
18
+ @lookup_context.prefixes = @lookup_context.prefixes + blocks.prefixes
17
19
  %>
18
20
 
19
21
  <% if blockable && blockable.respond_to?(:blocks) %>
20
22
  <% blockable.blocks.order(:position).each do |block| %>
21
- <% view_path = BlockService.frontend_view(block.name, path: path).gsub('/_', '/').split('.').first %>
22
- <%= render view_path, block: block %>
23
+
24
+ <!-- <%= block.name %> -->
25
+ <%= render block.name, block: block %>
26
+
23
27
  <% end %>
24
28
  <% end %>
@@ -1,10 +1,16 @@
1
1
  <%
2
2
  # headmin/heading
3
3
  #
4
+ # Accepts a block
5
+ #
6
+ # ==== References
7
+ # https://headmin.dev/docs/heading
8
+ # https://headmin.dev/preview/heading
9
+ #
4
10
  # ==== Examples
5
11
  # Basic version
6
12
  # <%= render "headmin/heading" do %#>
7
- # Your content
13
+ # Title
8
14
  # <% end %#>
9
15
  %>
10
16
 
@@ -1,40 +1,4 @@
1
- <!--
2
- <% documentation do %>
3
- # Thumbnail
4
- Render thumbnails for files. Whenever possible (e.g. images) previews are generated. Icons are used instead for other file types.
5
-
6
- ```erbx
7
- <%= render 'headmin/thumbnail', src: image_path("image.jpg") %>
8
- ```
9
-
10
- ## Parameters
11
- | Name | Required | Type | Description |
12
- | ------------ | -------- | ---------------- | ----------- |
13
- | src | yes | String | Source of the file. Can be a local or external URL |
14
- | width | no | Integer | Width of the thumbnail in px |
15
- | height | no | Integer | Height of the thumbnail in px |
16
-
17
- ## Examples
18
-
19
- ### Sizing
20
- ```erbx
21
- <%= render 'headmin/thumbnail', src: image_path("image.jpg"), width: 300, height: 100 %>
22
- ```
23
-
24
- ### Types
25
- ```erbx
26
- <%= render 'headmin/thumbnail', src: asset_path("document.pdf"), width: 100, height: 100 %>
27
- <%= render 'headmin/thumbnail', src: asset_path("document.docx"), width: 100, height: 100 %>
28
- <%= render 'headmin/thumbnail', src: asset_path("spreadsheet.xls"), width: 100, height: 100 %>
29
- <%= render 'headmin/thumbnail', src: asset_path("video.mp4"), width: 100, height: 100 %>
30
- ```
31
-
32
- ## References
33
- - [Bootstrap](https://getbootstrap.com/docs/5.1/content/images/#image-thumbnails)
34
- <% end %>
35
- -->
36
-
37
- <% thumbnail = Headmin::Thumbnail.new(local_assigns) %>
1
+ <% thumbnail = Headmin::ThumbnailView.new(local_assigns) %>
38
2
 
39
3
  <div class="<%= thumbnail.class_names %>" style="width: <%= thumbnail.width %>px; height: <%= thumbnail.height %>px;">
40
4
  <% if thumbnail.image? %>
@@ -0,0 +1,11 @@
1
+ <div class="h-autocomplete d-none" data-autocomplete-target="dropdown">
2
+ <% if collection.any? %>
3
+ <%= render "headmin/forms/autocomplete/list" do %>
4
+ <% collection.each do |value, name| %>
5
+ <%= render "headmin/forms/autocomplete/item", value: value do %>
6
+ <%= name %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
10
+ <% end %>
11
+ </div>
@@ -1,39 +1,38 @@
1
1
  <%
2
2
  # headmin/forms/blocks
3
3
  #
4
- # ==== Options
4
+ # ==== Required parameters
5
5
  # * +form</tt> - Form object
6
- # * +path</tt> - Directory where to look for block templates
7
- # * +allow</tt> - Names of block templates that can be added
6
+ # * +names</tt> - Names of block templates that can be added
7
+ #
8
+ # ==== Optional parameters
9
+ # * +paths</tt> - Directories where to look for block templates
8
10
  #
9
11
  # ==== Examples
10
- # Basic version. This will only look for blocks in 'admin/blocks'
11
- # <%= render "headmin/forms/blocks", form: form %#>
12
+ # Basic version. (looks in views/admin/blocks, views/blocks or views directory )
13
+ # <%= render "headmin/forms/blocks", form: form, names: %w(text image button) %#>
12
14
  #
13
- # Define the path to look for block templates like this:
14
- # <%= render "headmin/forms/blocks", form: form, path: 'admin/pages/blocks' %#>
15
+ # Define one ore more path where the templates could be located:
16
+ # <%= render "headmin/forms/blocks", form: form, names: %w(text image button), paths: %w(admin/pages/blocks) %#>
15
17
  #
16
18
  # Limit the types of blocks
17
- # <%= render "headmin/forms/blocks", form: form, allow: ['text', 'text-image'] %#>
18
-
19
- path = local_assigns.has_key?(:path) ? path : nil
20
- allowed_block_names = local_assigns.has_key?(:allow) ? allow.map(&:to_s) : BlockService.block_names(path: path)
19
+ # <%= render "headmin/forms/blocks", form: form, names: %w(text text_image list) %#>
21
20
 
22
- templates = allowed_block_names.map { |name| BlockService.form_view(name, path: path) }
21
+ blocks = Headmin::Form::BlocksView.new(local_assigns)
22
+ @lookup_context.prefixes = @lookup_context.prefixes + blocks.prefixes
23
23
  %>
24
24
 
25
- <%= render 'headmin/forms/repeater', form: form, attribute: :blocks, templates: templates, label: false do |block_form, template| %>
26
- <% name = template ? BlockService.view_name(template) : block_form.object.name %>
25
+ <%= render 'headmin/forms/repeater', blocks.repeater_options do |block_form, template| %>
26
+ <% name = template || block_form.object.name %>
27
27
 
28
28
  <!-- Name input of the block -->
29
29
  <%= block_form.hidden_field :name, value: name %>
30
30
 
31
31
  <!-- Render block form fields -->
32
- <% view_path = BlockService.form_view(name, path: path).gsub('/_', '/').split('.')[0] %>
33
- <%= render view_path, form: block_form %>
32
+ <%= render name, form: block_form %>
34
33
 
35
34
  <!-- Label -->
36
35
  <span class="position-absolute top-0 end-0 badge bg-light text-dark">
37
- <%= name.titleize %>
36
+ <%= t("blocks.#{name}", default: name).humanize %>
38
37
  </span>
39
38
  <% end %>