headmin 0.5.9 → 0.6.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile.lock +121 -117
  5. data/README.md +2 -2
  6. data/app/assets/javascripts/headmin/controllers/media_controller.js +38 -1
  7. data/app/assets/javascripts/headmin/controllers/textarea_controller.js +15 -1
  8. data/app/assets/javascripts/headmin.js +42 -2
  9. data/app/assets/stylesheets/headmin/overrides/redactorx.scss +2 -1
  10. data/app/assets/stylesheets/headmin.css +2 -1
  11. data/app/controllers/concerns/headmin/pagination.rb +1 -1
  12. data/app/models/concerns/headmin/attachment.rb +34 -0
  13. data/app/models/concerns/headmin/blob.rb +1 -1
  14. data/app/models/concerns/headmin/block.rb +6 -0
  15. data/app/models/concerns/headmin/fieldable.rb +10 -2
  16. data/app/models/headmin/filter/base.rb +2 -2
  17. data/app/models/headmin/form/blocks_view.rb +13 -0
  18. data/app/models/headmin/form/color_view.rb +1 -2
  19. data/app/models/headmin/form/media_view.rb +8 -4
  20. data/app/views/headmin/_blocks.html.erb +3 -6
  21. data/app/views/headmin/_filters.html.erb +2 -7
  22. data/app/views/headmin/_form.html.erb +1 -1
  23. data/app/views/headmin/_index.html.erb +1 -1
  24. data/app/views/headmin/forms/_blocks.html.erb +10 -3
  25. data/app/views/headmin/forms/_media.html.erb +7 -5
  26. data/app/views/headmin/forms/_repeater.html.erb +3 -1
  27. data/app/views/headmin/forms/blocks/_modal.html.erb +20 -0
  28. data/app/views/headmin/forms/fields/_base.html.erb +1 -1
  29. data/app/views/headmin/forms/fields/_group.html.erb +18 -11
  30. data/app/views/headmin/forms/fields/_list.html.erb +4 -1
  31. data/app/views/headmin/forms/media/_validation.html.erb +10 -0
  32. data/app/views/headmin/forms/repeater/_row.html.erb +2 -1
  33. data/app/views/headmin/layout/_content.html.erb +1 -1
  34. data/app/views/headmin/layout/_footer.html.erb +1 -1
  35. data/app/views/headmin/media/_media_item_modal.html.erb +26 -0
  36. data/app/views/headmin/nav/_item.html.erb +6 -1
  37. data/config/initializers/extend_active_storage_attachment.rb +3 -0
  38. data/config/locales/activerecord/en.yml +2 -0
  39. data/config/locales/activerecord/nl.yml +3 -0
  40. data/config/locales/headmin/forms/en.yml +12 -0
  41. data/config/locales/headmin/forms/nl.yml +13 -0
  42. data/config/locales/headmin/media/en.yml +1 -0
  43. data/config/locales/headmin/media/nl.yml +1 -0
  44. data/lib/generators/templates/migrations/create_blocks.rb +2 -0
  45. data/lib/headmin/version.rb +1 -1
  46. data/package.json +1 -1
  47. metadata +6 -2
@@ -26,7 +26,7 @@ module Headmin
26
26
  mimetypes.map.with_index do |mimetype, index|
27
27
  content_type = mimetype.tr("*", "%")
28
28
  query = where(arel_table[:content_type].matches(content_type))
29
- results = index == 0 ? query : results.or(query)
29
+ results = (index == 0) ? query : results.or(query)
30
30
  end
31
31
 
32
32
  results
@@ -5,6 +5,12 @@ module Headmin
5
5
  included do
6
6
  # Associations
7
7
  belongs_to :blockable, polymorphic: true, optional: true, touch: true
8
+
9
+ # Validations
10
+ validates :handle, uniqueness: {scope: :blockable_id}, allow_blank: true
11
+
12
+ # Scopes
13
+ scope :visible, -> { where("visible = true") }
8
14
  end
9
15
  end
10
16
  end
@@ -88,7 +88,7 @@ module Headmin
88
88
  fieldable: self,
89
89
  name: name,
90
90
  field_type: "list",
91
- fields: array.map { |item| ::Field.new(fieldable: self, name: "item", field_type: "group", fields: fields_for(item)) }
91
+ fields: array.map { |item| ::Field.new(fieldable: self, field_type: :list_item, fields: fields_for(item)) }
92
92
  )
93
93
  end
94
94
 
@@ -143,6 +143,8 @@ module Headmin
143
143
  case field.field_type.to_sym
144
144
  when :group
145
145
  parse_group_field(field, children)
146
+ when :list_item
147
+ parse_list_item_field(field, children)
146
148
  when :list
147
149
  parse_list_field(field, children)
148
150
  when :files
@@ -158,6 +160,10 @@ module Headmin
158
160
  parse_hash_tree(children)
159
161
  end
160
162
 
163
+ def parse_list_item_field(field, children)
164
+ parse_hash_tree(children)
165
+ end
166
+
161
167
  def parse_list_field(field, children)
162
168
  children.map do |child, grand_children|
163
169
  parse_field(child, grand_children)
@@ -165,7 +171,9 @@ module Headmin
165
171
  end
166
172
 
167
173
  def parse_files_field(field)
168
- field.files.all
174
+ files = field.files
175
+ files = files.order(:position) if ActiveStorage::Attachment.column_names.include?("position")
176
+ files
169
177
  end
170
178
 
171
179
  def parse_file_field(field)
@@ -135,7 +135,7 @@ module Headmin
135
135
  string = string.remove("+AND+").remove("+OR+")
136
136
 
137
137
  # Regex: takes out the value before the : character
138
- operator_raw = string.match(/^[^:]*/)[0] == string ? nil : string.match(/^[^:]*/)[0]
138
+ operator_raw = (string.match(/^[^:]*/)[0] == string) ? nil : string.match(/^[^:]*/)[0]
139
139
  value_raw = string.remove("#{operator_raw}:")
140
140
 
141
141
  [conditional_raw, operator_raw, value_raw]
@@ -237,7 +237,7 @@ module Headmin
237
237
 
238
238
  value = if instruction[:operator] == "is_null" || instruction[:operator] == "is_not_null"
239
239
  # In case of special operators (is_null & is_not_null), we intercept the value
240
- value == 1 ? I18n.t("headmin.filters.values.yes") : I18n.t("headmin.filters.values.no")
240
+ (value == 1) ? I18n.t("headmin.filters.values.yes") : I18n.t("headmin.filters.values.no")
241
241
  else
242
242
  display_value(value)
243
243
  end
@@ -15,6 +15,19 @@ module Headmin
15
15
  paths + ["admin/blocks", "blocks", ""]
16
16
  end
17
17
 
18
+ def badge_style(object)
19
+ visible = object.visible?
20
+ errors = object.errors.present?
21
+
22
+ if !visible && !errors
23
+ "bg-light text-secondary"
24
+ elsif errors
25
+ "bg-danger text-white"
26
+ else
27
+ "bg-light text-dark"
28
+ end
29
+ end
30
+
18
31
  private
19
32
 
20
33
  def default_repeater_options
@@ -28,8 +28,7 @@ module Headmin
28
28
 
29
29
  def wrapper_options
30
30
  default_wrapper_options.deep_merge(
31
- {
32
- }
31
+ {}
33
32
  ).deep_merge(@wrapper || {})
34
33
  end
35
34
 
@@ -66,7 +66,9 @@ module Headmin
66
66
  def association_object
67
67
  if attached.is_a?(ActiveStorage::Attached::Many)
68
68
  result = form.object.send(nested_attribute)
69
- result = result.order(position: :asc) if sort
69
+
70
+ # We sort the collection with ruby to prevent a new query to be made that would dispose of the objects in memory
71
+ result = result.sort_by { |item| item.position } if sort
70
72
  result
71
73
  else
72
74
  form.object.send(nested_attribute)
@@ -76,7 +78,9 @@ module Headmin
76
78
  def attachments
77
79
  if attached.is_a?(ActiveStorage::Attached::Many)
78
80
  result = form.object.send(nested_attribute)
79
- result = result.order(position: :asc) if sort
81
+
82
+ # We sort the collection with ruby to prevent a new query to be made that would dispose of the objects in memory
83
+ result = result.sort_by { |item| item.position } if sort
80
84
  result.to_a.compact
81
85
  else
82
86
  [form.object.send(nested_attribute)].compact
@@ -105,9 +109,9 @@ module Headmin
105
109
 
106
110
  def min
107
111
  if @required
108
- @min.to_i < 1 ? 1 : @min.to_i
112
+ (@min.to_i < 1) ? 1 : @min.to_i
109
113
  else
110
- @min.to_i < 1 ? 0 : @min.to_i
114
+ (@min.to_i < 1) ? 0 : @min.to_i
111
115
  end
112
116
  end
113
117
 
@@ -18,11 +18,8 @@
18
18
  @lookup_context.prefixes = blocks.prefixes + @lookup_context.prefixes
19
19
  %>
20
20
 
21
- <% if blockable && blockable.respond_to?(:blocks) %>
22
- <% blockable.blocks.order(:position).each do |block| %>
23
-
24
- <!-- <%= block.name %> -->
21
+ <% blockable.blocks.visible.order(:position).each do |block| %>
22
+ <div class="block block-<%= block.name.dasherize %>" id="<%= block.handle.present? ? block.handle : "block-#{block.id}" %>">
25
23
  <%= render block.name, block: block %>
26
-
27
- <% end %>
24
+ </div>
28
25
  <% end %>
@@ -14,15 +14,10 @@
14
14
  # <%= render "headmin/filters", url: admin_polls_path %#>
15
15
 
16
16
  action = local_assigns.has_key?(:url) ? url : request.path
17
-
18
- begin
19
- model = controller_name.classify.constantize
20
- rescue
21
- raise "Cannot find class!"
22
- end
17
+ model = controller_name.classify.constantize rescue nil
23
18
  %>
24
19
 
25
- <%= form_with model: model.new, url: action, method: :get, data: {controller: "filters", filters_target: "form"} do |form| %>
20
+ <%= form_with model: model&.new, url: action, method: :get, data: {controller: "filters", filters_target: "form"} do |form| %>
26
21
  <%# Perform yield in order to capture content blocks, pass form so we can use headmin form inputs %>
27
22
  <%= yield(form) %>
28
23
 
@@ -58,7 +58,7 @@
58
58
  }
59
59
  %>
60
60
 
61
- <div class="container">
61
+ <div class="container py-4">
62
62
  <%= form_with model: model, scope: scope, url: url, format: format, **options do |form| %>
63
63
  <%= yield(form) %>
64
64
  <% end %>
@@ -8,6 +8,6 @@
8
8
  # <% end %#>
9
9
  %>
10
10
 
11
- <div class="container-fluid">
11
+ <div class="container-fluid py-4">
12
12
  <%= yield %>
13
13
  </div>
@@ -24,15 +24,22 @@
24
24
 
25
25
  <%= render "headmin/forms/repeater", blocks.repeater_options do |block_form, template| %>
26
26
  <% name = template || block_form.object.name %>
27
-
28
27
  <!-- Name input of the block -->
29
28
  <%= block_form.hidden_field :name, value: name %>
30
29
 
31
30
  <!-- Render block form fields -->
32
- <%= render name, form: block_form %>
31
+ <div class="<%= block_form.object.visible ? "" : "opacity-50" %>">
32
+ <%= render name, form: block_form %>
33
+ </div>
34
+ <% badge_style = blocks.badge_style(block_form.object) %>
33
35
 
34
36
  <!-- Label -->
35
- <span class="position-absolute top-0 end-0 badge bg-light text-dark">
37
+ <span class="position-absolute top-0 end-0 badge rounded-0 d-flex align-items-center gap-2 bg-danger <%= badge_style %>">
36
38
  <%= t("blocks.#{name}", default: name).humanize %>
39
+ <button type="button" class="btn p-0 <%= badge_style %>" data-bs-toggle="modal" data-bs-target="#modal-block-<%= block_form.object.id %>">
40
+ <%= bootstrap_icon("gear") %>
41
+ </button>
37
42
  </span>
43
+
44
+ <%= render "headmin/forms/blocks/modal", form: block_form, name: name %>
38
45
  <% end %>
@@ -7,11 +7,11 @@
7
7
  #
8
8
  # ==== Optional parameters
9
9
  # * +destroy+ - Adds delete buttons to the preview thumbnails
10
- # * +hint+ - Informative text to assist with data input. HTML markup is allowed.
11
- # * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label.
12
- # * +min+ - Limit the selection to a minimum amount of items.
13
- # * +max+ - Limit the selection to a maximum amount of items.
14
- # * +sort+ - Allow sorting by dragging items. `active_storage_attachments` must have a position column.
10
+ # * +hint+ - Informative text to assist with data input. HTML markup is allowed
11
+ # * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label
12
+ # * +min+ - Limit the selection to a minimum amount of items
13
+ # * +max+ - Limit the selection to a maximum amount of items
14
+ # * +sort+ - Allow sorting by dragging items. `active_storage_attachments` must have a position column
15
15
  # * +wrapper+ - Hash with all options for the surrounding html tag
16
16
  # * +width+ - Width of the thumbnail
17
17
  # * +height+ - Height of the thumbnail
@@ -31,6 +31,8 @@
31
31
  <%= render "headmin/forms/wrapper", media.wrapper_options do %>
32
32
  <%= render "headmin/forms/label", media.label_options if media.prepend_label? %>
33
33
  <div class="h-form-file-thumbnails" data-media-target="thumbnails">
34
+ <%= render "headmin/forms/media/validation", media.custom_validation_options %>
35
+
34
36
  <!-- Render previews for attachments -->
35
37
  <%= form.fields_for(media.nested_attribute, media.association_object) do |ff| %>
36
38
  <%= render "headmin/forms/media/item", media.item_options.merge(form: ff, url: headmin_media_url(name: media.name, ids: media.blob_ids, min: media.min, max: media.max, mimetype: media.accept)) %>
@@ -45,8 +45,10 @@
45
45
  association_model = object_model.reflect_on_association(attribute).class_name.constantize
46
46
  association_object = association_model.new
47
47
  with_positions = association_object.attributes.keys.include?("position")
48
+
49
+ # We sort the collection with ruby to prevent a new query to be made that would dispose of nested object in memory
48
50
  associations = form.object.send(attribute)
49
- associations = with_positions ? associations.order(:position) : associations
51
+ associations = with_positions ? associations.sort_by{|resource| resource.position} : associations
50
52
  repeater_id = form.object_id
51
53
  pass_thru = template_names.count == 1 ? "[data-template-name=\"#{template_names.first}\"]" : nil
52
54
  show_label = label != false
@@ -0,0 +1,20 @@
1
+ <div class="modal fade" tabindex="-1" id="modal-block-<%= form.object.id %>">
2
+ <div class="modal-dialog modal-lg modal-dialog-scrollable">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h5 class="modal-title">
6
+ <%= t(".title", name: name) %>
7
+ </h5>
8
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<%= t(".close") %>"></button>
9
+ </div>
10
+ <div class="modal-body">
11
+ <%= render "headmin/forms/text", form: form, attribute: :handle %>
12
+ <%= render "headmin/forms/checkbox", form: form, attribute: :visible %>
13
+ </div>
14
+ <div class="modal-footer">
15
+
16
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".close") %></button>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
@@ -11,7 +11,6 @@
11
11
  # <%= render "headmin/forms/fields/base", form: form, field_type: :text, name: name do |field, label| %#>
12
12
  # <%= render "headmin/forms/text", form: field, attribute: :value, label: label %#>
13
13
  # <% end %#>
14
-
15
14
  field = form.object.fields.detect { |field| field.name.to_s == name.to_s }
16
15
  field = field ? field : form.object.fields.new(field_type: field_type, name: name)
17
16
  label = t("attributes.#{name.to_s.parameterize}", default: field.name.to_s)
@@ -21,5 +20,6 @@
21
20
  <%= ff.hidden_field :id %>
22
21
  <%= ff.hidden_field :name %>
23
22
  <%= ff.hidden_field :field_type %>
23
+
24
24
  <%= yield ff, label %>
25
25
  <% end %>
@@ -5,6 +5,7 @@
5
5
  # * +form+ - Form object
6
6
  # * +name+ - Name for the field
7
7
  # * +label+ - Text to show as label. Label will be hidden if value is false
8
+ # * +named+ - Whether a group has to be wrapped around the passed block. If false, no group will be wrapped around the passed block.
8
9
  #
9
10
  # ==== Examples
10
11
  # Basic version
@@ -25,21 +26,27 @@
25
26
 
26
27
  label = local_assigns.has_key?(:label) ? label : nil
27
28
  wrapper = local_assigns.has_key?(:wrapper) ? local_assigns[:wrapper] : true
29
+ named = local_assigns.has_key?(:named) ? local_assigns[:named] : true
28
30
  show_label = label != false
29
31
  %>
30
32
 
31
- <%= render "headmin/forms/fields/base", form: form, name: name, field_type: :group do |group, field_label| %>
32
- <% if show_label %>
33
- <%= render "headmin/forms/label", form: form, attribute: :value, text: label || field_label %>
34
- <% end %>
33
+ <% if named %>
34
+ <%= render "headmin/forms/fields/base", form: form, name: name, field_type: :group do |group, field_label| %>
35
+ <% if show_label %>
36
+ <%= render "headmin/forms/label", form: form, attribute: :value, text: label || field_label %>
37
+ <% end %>
35
38
 
36
- <% if wrapper %>
37
- <ul class="list-group mb-3">
38
- <li class="list-group-item">
39
+ <% if wrapper %>
40
+ <ul class="list-group mb-3">
41
+ <li class="list-group-item">
42
+ <%= yield group %>
43
+ </li>
44
+ </ul>
45
+ <% else %>
39
46
  <%= yield group %>
40
- </li>
41
- </ul>
42
- <% else %>
43
- <%= yield group %>
47
+ <% end %>
44
48
  <% end %>
49
+
50
+ <% else %>
51
+ <%= yield form %>
45
52
  <% end %>
@@ -21,7 +21,10 @@
21
21
  <%= render "headmin/forms/fields/base", form: form, name: name, field_type: :list do |list, field_label| %>
22
22
  <div class="mb-3">
23
23
  <%= render "headmin/forms/repeater", form: list, attribute: :fields, label: show_label ? label || field_label : false, flush: false do |field| %>
24
- <%= field.hidden_field :field_type, value: :group %>
24
+
25
+ <%= field.hidden_field :field_type, value: :list_item %>
26
+ <%= field.hidden_field :name, value: :list_item %>
27
+
25
28
  <%= yield field %>
26
29
  <% end %>
27
30
  </div>
@@ -0,0 +1,10 @@
1
+ <!-- Custom validation field -->
2
+ <%= form.text_field :"validation_#{attribute}",
3
+ name: nil,
4
+ value: nil,
5
+ class: "h-form-media-validation",
6
+ data: {
7
+ "media-target": "validationInput",
8
+ "min-message": t(".min", count: min),
9
+ "max-message": t(".max", count: max),
10
+ } %>
@@ -7,10 +7,11 @@
7
7
 
8
8
  draggable = form.object.respond_to?(:position)
9
9
  destroyable = form.object.respond_to?(:destroy)
10
+ error_class = form.object.errors.present? ? "border border-danger" : ""
10
11
  class_names = local_assigns.has_key?(:class) ? local_assigns[:class] : "repeater-row list-group-item"
11
12
  %>
12
13
 
13
- <div class="<%= class_names %>"
14
+ <div class="<%= class_names %> <%= error_class %>"
14
15
  data-repeater-target="row"
15
16
  data-row-index="<%= form.options[:child_index] %>"
16
17
  data-new-record="<%= form.object.new_record? %>"
@@ -4,6 +4,6 @@
4
4
  parameters: none
5
5
  %>
6
6
 
7
- <div class="content py-4">
7
+ <div class="content">
8
8
  <%= yield %>
9
9
  </div>
@@ -10,7 +10,7 @@
10
10
  <div class="text-secondary">
11
11
  Headmin v.<%= Headmin::VERSION %>
12
12
  <span class="float-end">
13
- <%= yield %>
13
+ <%= yield unless content_for(:layout).eql?(yield) %>
14
14
  </span>
15
15
  </div>
16
16
  </div>
@@ -42,6 +42,32 @@
42
42
  <%= render "headmin/forms/text", form: form, attribute: :filename, append: "." + form.object.filename.to_s.rpartition(".").last, value: form.object.filename.to_s.rpartition(".").first %>
43
43
  </div>
44
44
  </div>
45
+ <% attachments = @blob.attachments.not_a_variant.all %>
46
+ <% if attachments.any? %>
47
+ <hr>
48
+ <h6><%= t(".attachment_used_by") %>:</h6>
49
+ <table class="table table-sm">
50
+ <tbody>
51
+ <% attachments.each do |attachment| %>
52
+ <% context_resource = attachment.record_hierarchy.last %>
53
+ <% context_resource_path = polymorphic_path([:admin, context_resource]) rescue nil %>
54
+ <tr>
55
+ <td width="40%">
56
+ <% if context_resource_path.present? %>
57
+ <%= link_to truncate(context_resource.to_s), context_resource_path, title: context_resource %>
58
+ <% else %>
59
+ <%= context_resource %>
60
+ <% end %>
61
+ </td>
62
+ <td width="25%"><%= "#{context_resource.model_name.human(count: 1)} (#{attachment.class.human_attribute_name(attachment.name.to_sym)})" %></td>
63
+ <td width="35%">
64
+ <small class="text-secondary"><%= l(attachment.created_at, format: :long) %></small>
65
+ </td>
66
+ </tr>
67
+ <% end %>
68
+ </tbody>
69
+ </table>
70
+ <% end %>
45
71
  </div>
46
72
  <div class="modal-footer">
47
73
  <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".close") %></button>
@@ -5,6 +5,7 @@
5
5
  # * +name</tt> - Name of the nav item
6
6
  # * +url</tt> - URL for this nav item
7
7
  # * +icon</tt> - Optional Bootstrap icon name
8
+ # * +locked</tt> - Item becomes unclickable and a lock icon appears at the end of the item
8
9
  # * +active</tt> - Set to true if this nav item needs to be highlighted
9
10
  #
10
11
  # ==== Examples
@@ -17,14 +18,18 @@
17
18
  name = local_assigns.has_key?(:name) ? name : ""
18
19
  icon = local_assigns.has_key?(:icon) ? icon : nil
19
20
  url = local_assigns.has_key?(:url) ? url : request.url
21
+ locked = local_assigns.has_key?(:locked) ? locked : false
20
22
  active = local_assigns.has_key?(:active) ? active : current_url?(url)
21
23
  %>
22
24
 
23
25
  <li class="nav-item">
24
- <a class="nav-link d-flex align-items-center <%= "active" if active %>" aria-current="page" href="<%= url %>">
26
+ <a class="nav-link d-flex align-items-center <%= "active" if active %> <%= "disabled" if locked %>" aria-current="page" href="<%= url %>">
25
27
  <%= bootstrap_icon(icon, class: "me-2") if icon %>
26
28
  <span class="d-block d-md-none d-lg-block">
27
29
  <%= name %>
28
30
  </span>
31
+ <% if locked %>
32
+ <%= bootstrap_icon("lock", class: "fs-6 ms-2") %>
33
+ <% end %>
29
34
  </a>
30
35
  </li>
@@ -0,0 +1,3 @@
1
+ Rails.configuration.to_prepare do
2
+ ActiveStorage::Attachment.include Headmin::Attachment
3
+ end
@@ -3,8 +3,10 @@ en:
3
3
  created_at: Created at
4
4
  email: Email
5
5
  filename: Filename
6
+ handle: Handle
6
7
  password: Password
7
8
  password_confirmation: Password confirmation
8
9
  remember_me: Stay logged in
9
10
  updated_at: Updated at
10
11
  value: Value
12
+ visible: Visible?
@@ -3,8 +3,11 @@ nl:
3
3
  created_at: Aangemaakt
4
4
  email: E-mailadres
5
5
  filename: Bestandsnaam
6
+ handle: Naam
6
7
  password: Wachtwoord
7
8
  password_confirmation: Wachtwoord bevestiging
8
9
  remember_me: Aangemeld blijven
9
10
  updated_at: Aangepast
10
11
  value: Waarde
12
+ visible: Zichtbaar?
13
+
@@ -18,6 +18,18 @@ en:
18
18
  remove:
19
19
  title: Delete
20
20
  confirm: Are you sure you want to delete this?
21
+ modal:
22
+ close: Close
23
+ title: "Edit block '%{name}'"
24
+ media:
25
+ validation:
26
+ min:
27
+ one: Please select at least 1 item
28
+ other: "Please select at least %{count} items"
29
+ max:
30
+ one: Please limit your selection to maximum 1 item
31
+ other: "Please limit your selection to maximum %{count} items"
32
+
21
33
  select:
22
34
  blank: Make a choice
23
35
  repeater:
@@ -9,6 +9,7 @@ nl:
9
9
  group:
10
10
  save: Opslaan
11
11
  blocks:
12
+ add: "%{name} toevoegen"
12
13
  empty:
13
14
  title: Er zijn nog geen blokken toegevoegd.
14
15
  add: Blok toevoegen
@@ -17,6 +18,18 @@ nl:
17
18
  remove:
18
19
  title: Verwijderen
19
20
  confirm: Ben je zeker dat je dit wil verwijderen?
21
+ modal:
22
+ close: Sluiten
23
+ title: "Wijzig blok '%{name}'"
24
+ media:
25
+ validation:
26
+ min:
27
+ one: Gelieve minstens 1 item te selecteren
28
+ other: "Gelieve minstens %{count} items te selecteren"
29
+ max:
30
+ one: Gelieve maximum 1 item te selecteren
31
+ other: "Gelieve maximum %{count} items te selecteren"
32
+
20
33
  select:
21
34
  blank: Maak een keuze
22
35
  repeater:
@@ -13,6 +13,7 @@ en:
13
13
  unlimited: unlimited
14
14
  upload: Upload new files
15
15
  media_item_modal:
16
+ attachment_used_by: Used by
16
17
  close: Close
17
18
  dimensions: Dimensions
18
19
  edit: Edit Media item
@@ -13,6 +13,7 @@ nl:
13
13
  unlimited: onbeperkt
14
14
  upload: Nieuwe bestanden uploaden
15
15
  media_item_modal:
16
+ attachment_used_by: Gebruikt door
16
17
  close: Sluiten
17
18
  dimensions: Afmetingen
18
19
  edit: Media item wijzigen
@@ -3,7 +3,9 @@ class CreateBlocks < ActiveRecord::Migration[6.1]
3
3
  create_table :blocks do |t|
4
4
  t.references :blockable, polymorphic: true
5
5
  t.string :name
6
+ t.string :handle
6
7
  t.integer :position
8
+ t.boolean :visible, default: true
7
9
  t.timestamps
8
10
  end
9
11
  end
@@ -1,3 +1,3 @@
1
1
  module Headmin
2
- VERSION = "0.5.9"
2
+ VERSION = "0.6.1"
3
3
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "headmin",
3
- "version": "0.5.8",
3
+ "version": "0.6.0",
4
4
  "description": "Admin component library",
5
5
  "module": "app/assets/javascripts/headmin.js",
6
6
  "main": "app/assets/javascripts/headmin.js",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: headmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.9
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jef Vlamings
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-29 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: closure_tree
@@ -244,6 +244,7 @@ files:
244
244
  - app/helpers/headmin/form_helper.rb
245
245
  - app/helpers/headmin/notification_helper.rb
246
246
  - app/helpers/headmin/request_helper.rb
247
+ - app/models/concerns/headmin/attachment.rb
247
248
  - app/models/concerns/headmin/blob.rb
248
249
  - app/models/concerns/headmin/block.rb
249
250
  - app/models/concerns/headmin/blockable.rb
@@ -387,6 +388,7 @@ files:
387
388
  - app/views/headmin/forms/_wysiwyg.html.erb
388
389
  - app/views/headmin/forms/autocomplete/_item.html.erb
389
390
  - app/views/headmin/forms/autocomplete/_list.html.erb
391
+ - app/views/headmin/forms/blocks/_modal.html.erb
390
392
  - app/views/headmin/forms/fields/_base.html.erb
391
393
  - app/views/headmin/forms/fields/_file.html.erb
392
394
  - app/views/headmin/forms/fields/_files.html.erb
@@ -394,6 +396,7 @@ files:
394
396
  - app/views/headmin/forms/fields/_list.html.erb
395
397
  - app/views/headmin/forms/fields/_text.html.erb
396
398
  - app/views/headmin/forms/media/_item.html.erb
399
+ - app/views/headmin/forms/media/_validation.html.erb
397
400
  - app/views/headmin/forms/repeater/_row.html.erb
398
401
  - app/views/headmin/heading/_title.html.erb
399
402
  - app/views/headmin/layout/_body.html.erb
@@ -466,6 +469,7 @@ files:
466
469
  - bin/setup
467
470
  - config/importmap.rb
468
471
  - config/initializers/customize_input_error.rb
472
+ - config/initializers/extend_active_storage_attachment.rb
469
473
  - config/initializers/extend_active_storage_blob.rb
470
474
  - config/locales/activerecord/en.yml
471
475
  - config/locales/activerecord/nl.yml