headmin 0.5.1 → 0.5.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -2
- data/Gemfile +14 -0
- data/Gemfile.lock +79 -2
- data/app/assets/javascripts/headmin/controllers/media_controller.js +237 -0
- data/app/assets/javascripts/headmin/controllers/media_modal_controller.js +110 -0
- data/app/assets/javascripts/headmin/controllers/remote_modal_controller.js +9 -0
- data/app/assets/javascripts/headmin/controllers/textarea_controller.js +34 -0
- data/app/assets/javascripts/headmin/index.js +8 -0
- data/app/assets/javascripts/headmin.js +294 -0
- data/app/assets/stylesheets/headmin/forms/file.scss +40 -5
- data/app/assets/stylesheets/headmin/forms/media.scss +10 -0
- data/app/assets/stylesheets/headmin/forms.scss +1 -0
- data/app/assets/stylesheets/headmin/layout/sidebar.scss +0 -1
- data/app/assets/stylesheets/headmin/media/index.scss +9 -0
- data/app/assets/stylesheets/headmin/media.scss +1 -0
- data/app/assets/stylesheets/headmin/overrides/redactorx.scss +1 -1
- data/app/assets/stylesheets/headmin/table.scss +8 -0
- data/app/assets/stylesheets/headmin/vendor/{tom-select-bootstrap.css → tom-select-bootstrap.scss} +0 -1
- data/app/assets/stylesheets/headmin.css +61 -8
- data/app/assets/stylesheets/headmin.scss +1 -0
- data/app/controllers/headmin/media_controller.rb +52 -0
- data/app/controllers/headmin_controller.rb +2 -0
- data/app/helpers/headmin/form_helper.rb +2 -2
- data/app/models/concerns/headmin/field.rb +2 -2
- data/app/models/concerns/headmin/fieldable.rb +19 -10
- data/app/models/concerns/headmin/form/hintable.rb +6 -1
- data/app/models/headmin/filter/association.rb +86 -0
- data/app/models/headmin/filter/association_view.rb +74 -0
- data/app/models/headmin/filter/base.rb +5 -2
- data/app/models/headmin/filter/boolean_view.rb +1 -0
- data/app/models/headmin/filter/date.rb +49 -1
- data/app/models/headmin/filter/date_view.rb +1 -0
- data/app/models/headmin/filter/flatpickr_view.rb +1 -0
- data/app/models/headmin/filter/number_view.rb +1 -0
- data/app/models/headmin/filter/operator_view.rb +3 -1
- data/app/models/headmin/filter/options_view.rb +1 -0
- data/app/models/headmin/filter/text_view.rb +1 -0
- data/app/models/headmin/form/association_view.rb +102 -0
- data/app/models/headmin/form/blocks_view.rb +4 -1
- data/app/models/headmin/form/file_view.rb +0 -8
- data/app/models/headmin/form/flatpickr_view.rb +2 -1
- data/app/models/headmin/form/media_item_view.rb +39 -0
- data/app/models/headmin/form/media_view.rb +137 -0
- data/app/models/headmin/form/select_view.rb +2 -1
- data/app/models/headmin/form/textarea_view.rb +6 -1
- data/app/models/headmin/thumbnail_view.rb +40 -19
- data/app/models/view_model.rb +4 -0
- data/app/views/examples/admin.html.erb +8 -8
- data/app/views/examples/auth.html.erb +2 -2
- data/app/views/headmin/_breadcrumbs.html.erb +2 -2
- data/app/views/headmin/_dropdown.html.erb +1 -1
- data/app/views/headmin/_filters.html.erb +12 -7
- data/app/views/headmin/_pagination.html.erb +2 -2
- data/app/views/headmin/_popup.html.erb +4 -4
- data/app/views/headmin/_table.html.erb +1 -1
- data/app/views/headmin/_thumbnail.html.erb +33 -9
- data/app/views/headmin/dropdown/_button.html.erb +2 -2
- data/app/views/headmin/dropdown/_item.html.erb +2 -2
- data/app/views/headmin/dropdown/_list.html.erb +3 -3
- data/app/views/headmin/dropdown/_locale.html.erb +5 -5
- data/app/views/headmin/filters/_association.html.erb +24 -0
- data/app/views/headmin/filters/_options.html.erb +1 -1
- data/app/views/headmin/filters/filter/_button.html.erb +2 -2
- data/app/views/headmin/filters/filter/_null_select.html.erb +2 -2
- data/app/views/headmin/forms/_association.html.erb +30 -0
- data/app/views/headmin/forms/_errors.html.erb +1 -1
- data/app/views/headmin/forms/_file.html.erb +10 -11
- data/app/views/headmin/forms/_hint.html.erb +6 -1
- data/app/views/headmin/forms/_media.html.erb +60 -0
- data/app/views/headmin/forms/_repeater.html.erb +18 -16
- data/app/views/headmin/forms/_textarea.html.erb +1 -1
- data/app/views/headmin/forms/_wrapper.html.erb +0 -1
- data/app/views/headmin/forms/fields/_list.html.erb +6 -4
- data/app/views/headmin/forms/media/_item.html.erb +38 -0
- data/app/views/headmin/forms/media/_validation.html.erb +10 -0
- data/app/views/headmin/forms/repeater/_row.html.erb +17 -15
- data/app/views/headmin/heading/_title.html.erb +2 -2
- data/app/views/headmin/layout/_main.html.erb +2 -0
- data/app/views/headmin/layout/_remote_modal.html.erb +1 -0
- data/app/views/headmin/layout/_sidebar.html.erb +1 -1
- data/app/views/headmin/media/_item.html.erb +16 -0
- data/app/views/headmin/media/_media_item_modal.html.erb +51 -0
- data/app/views/headmin/media/_modal.html.erb +35 -0
- data/app/views/headmin/media/create.turbo_stream.erb +5 -0
- data/app/views/headmin/media/index.html.erb +3 -0
- data/app/views/headmin/media/show.html.erb +9 -0
- data/app/views/headmin/media/update.turbo_stream.erb +3 -0
- data/app/views/headmin/nav/_dropdown.html.erb +7 -7
- data/app/views/headmin/nav/_item.html.erb +5 -5
- data/app/views/headmin/nav/item/_locale.html.erb +6 -6
- data/app/views/headmin/pagination/_per_page.html.erb +7 -7
- data/app/views/headmin/pagination/kaminari/_first_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_gap.html.erb +1 -1
- data/app/views/headmin/pagination/kaminari/_last_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_next_page.html.erb +3 -3
- data/app/views/headmin/pagination/kaminari/_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_paginator.html.erb +1 -1
- data/app/views/headmin/pagination/kaminari/_prev_page.html.erb +2 -2
- data/app/views/headmin/table/_actions.html.erb +9 -9
- data/app/views/headmin/table/_body.html.erb +1 -1
- data/app/views/headmin/table/actions/_action.html.erb +4 -4
- data/app/views/headmin/table/actions/_export.html.erb +1 -1
- data/app/views/headmin/table/body/_association.html.erb +17 -3
- data/app/views/headmin/table/body/_boolean.erb +4 -4
- data/app/views/headmin/table/body/_date.html.erb +2 -2
- data/app/views/headmin/table/body/_image.html.erb +18 -0
- data/app/views/headmin/table/body/_string.html.erb +1 -1
- data/app/views/headmin/table/head/_cell.html.erb +1 -1
- data/app/views/headmin/table/head/cell/_asc.html.erb +2 -2
- data/app/views/headmin/table/head/cell/_default.html.erb +1 -1
- data/app/views/headmin/table/head/cell/_desc.html.erb +1 -1
- data/app/views/headmin/views/devise/confirmations/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/passwords/_edit.html.erb +1 -1
- data/app/views/headmin/views/devise/passwords/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/registrations/_edit.html.erb +5 -5
- data/app/views/headmin/views/devise/registrations/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/sessions/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/shared/_links.html.erb +14 -20
- data/app/views/headmin/views/devise/unlocks/_new.html.erb +1 -1
- data/config/locales/activerecord/en.yml +1 -0
- data/config/locales/activerecord/nl.yml +1 -0
- data/config/locales/devise/nl.yml +1 -1
- data/config/locales/headmin/filters/en.yml +3 -1
- data/config/locales/headmin/filters/nl.yml +2 -0
- data/config/locales/headmin/forms/en.yml +8 -0
- data/config/locales/headmin/forms/nl.yml +8 -0
- data/config/locales/headmin/media/en.yml +23 -0
- data/config/locales/headmin/media/nl.yml +23 -0
- data/config/locales/headmin/table/en.yml +2 -0
- data/config/locales/headmin/table/nl.yml +2 -0
- data/config/routes.rb +10 -0
- data/lib/generators/templates/views/layouts/auth.html.erb +2 -2
- data/lib/headmin/version.rb +1 -1
- data/package.json +1 -1
- metadata +34 -3
@@ -45,16 +45,15 @@
|
|
45
45
|
next unless attachment
|
46
46
|
filename = attachment.blob.filename.to_s
|
47
47
|
size = number_to_human_size(attachment.blob.byte_size)
|
48
|
-
src = attachment.image? ? url_for(attachment.variant(resize_to_fill: [file.thumbnail_width, file.thumbnail_height])) : url_for(attachment)
|
49
48
|
%>
|
50
49
|
<div class="h-form-file-thumbnail" title="<%= "#{filename} (#{size})" %>" data-file-preview-target="thumbnail">
|
51
|
-
<%= ff.hidden_field(:id, disabled: file.destroy) %>
|
52
|
-
<%= ff.hidden_field(:_destroy, data: {
|
53
|
-
<%= render "headmin/thumbnail",
|
50
|
+
<%= ff.hidden_field(:id, disabled: !file.destroy) %>
|
51
|
+
<%= ff.hidden_field(:_destroy, data: {"file-preview-target": "thumbnailDestroy"}, disabled: !file.destroy) %>
|
52
|
+
<%= render "headmin/thumbnail", file: attachment %>
|
54
53
|
|
55
54
|
<% if file.destroy %>
|
56
55
|
<div class="h-form-file-thumbnail-remove" data-action="click->file-preview#remove" data-file-preview-name-param="<%= filename %>">
|
57
|
-
<%= bootstrap_icon(
|
56
|
+
<%= bootstrap_icon("x") %>
|
58
57
|
</div>
|
59
58
|
<% end %>
|
60
59
|
</div>
|
@@ -62,12 +61,12 @@
|
|
62
61
|
|
63
62
|
<!-- Placeholder -->
|
64
63
|
<% if file.dropzone %>
|
65
|
-
<div class="h-dropzone-placeholder <%=
|
66
|
-
<%= t(
|
64
|
+
<div class="h-dropzone-placeholder <%= "d-none" if file.attachments.any? %>" data-file-preview-target="placeholder" style="height: 100px;">
|
65
|
+
<%= t("headmin.forms.file.placeholder", count: file.number_of_files) %>
|
67
66
|
</div>
|
68
67
|
<% else %>
|
69
|
-
<div class="h-form-file-thumbnail <%=
|
70
|
-
<%= render "headmin/thumbnail",
|
68
|
+
<div class="h-form-file-thumbnail <%= "d-none" if file.attachments.any? %>" title="<%= t("headmin.forms.file.not_found") %>" data-file-preview-target="placeholder">
|
69
|
+
<%= render "headmin/thumbnail", icon: "plus" %>
|
71
70
|
</div>
|
72
71
|
<% end %>
|
73
72
|
</div>
|
@@ -76,11 +75,11 @@
|
|
76
75
|
<!-- Template -->
|
77
76
|
<template data-file-preview-target="template">
|
78
77
|
<div class="h-form-file-thumbnail" title="" data-file-preview-target="thumbnail">
|
79
|
-
<%= render "headmin/thumbnail"
|
78
|
+
<%= render "headmin/thumbnail" %>
|
80
79
|
|
81
80
|
<% if file.destroy %>
|
82
81
|
<div class="h-form-file-thumbnail-remove" data-action="click->file-preview#remove">
|
83
|
-
<%= bootstrap_icon(
|
82
|
+
<%= bootstrap_icon("x") %>
|
84
83
|
</div>
|
85
84
|
<% end %>
|
86
85
|
</div>
|
@@ -13,4 +13,9 @@
|
|
13
13
|
hint = Headmin::Form::HintView.new(local_assigns)
|
14
14
|
%>
|
15
15
|
|
16
|
-
<div class="form-text
|
16
|
+
<div class="form-text d-flex justify-content-between">
|
17
|
+
<div><%= raw(hint.content) %></div>
|
18
|
+
<% if hint.maxlength %>
|
19
|
+
<div data-textarea-target="count"></div>
|
20
|
+
<% end %>
|
21
|
+
</div>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<%
|
2
|
+
# headmin/forms/media
|
3
|
+
#
|
4
|
+
# ==== Required parameters
|
5
|
+
# * +attribute+ - Name of the attribute of the form model
|
6
|
+
# * +form+ - Form object
|
7
|
+
#
|
8
|
+
# ==== Optional parameters
|
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.
|
15
|
+
# * +wrapper+ - Hash with all options for the surrounding html tag
|
16
|
+
# * +width+ - Width of the thumbnail
|
17
|
+
# * +height+ - Height of the thumbnail
|
18
|
+
#
|
19
|
+
# ==== References
|
20
|
+
# https://headmin.dev/docs/forms/media
|
21
|
+
#
|
22
|
+
# ==== Examples
|
23
|
+
# Basic version
|
24
|
+
# <%= form_with do |form| %#>
|
25
|
+
# <%= render "headmin/forms/media", form: form, attribute: :file %#>
|
26
|
+
# <% end %#>
|
27
|
+
|
28
|
+
media = Headmin::Form::MediaView.new(local_assigns)
|
29
|
+
%>
|
30
|
+
|
31
|
+
<%= render "headmin/forms/wrapper", media.wrapper_options do %>
|
32
|
+
<%= render "headmin/forms/label", media.label_options if media.prepend_label? %>
|
33
|
+
<div class="h-form-file-thumbnails" data-media-target="thumbnails">
|
34
|
+
<%= render "headmin/forms/media/validation", media.custom_validation_options %>
|
35
|
+
|
36
|
+
<!-- Render previews for attachments -->
|
37
|
+
<%= form.fields_for(media.nested_attribute, media.association_object) do |ff| %>
|
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)) %>
|
39
|
+
<% end %>
|
40
|
+
|
41
|
+
<!-- Placeholder -->
|
42
|
+
<div class="<%= "d-none" if media.attachments.any? %>" data-media-target="placeholder">
|
43
|
+
<a href="<%= headmin_media_url(name: media.name, ids: media.blob_ids, min: media.min, max: media.max) %>" data-turbo-frame="remote_modal" data-media-target="modalButton">
|
44
|
+
<%= render "headmin/thumbnail", media.thumbnail_options %>
|
45
|
+
</a>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
|
49
|
+
<!-- Template -->
|
50
|
+
<% association_object = ActiveStorage::Attachment.new %>
|
51
|
+
<template data-media-target="template" data-template-id-regex="<%= association_object.object_id %>">
|
52
|
+
<%= form.fields_for(media.nested_attribute, ActiveStorage::Attachment.new, child_index: association_object.object_id) do |ff| %>
|
53
|
+
<%= 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)) %>
|
54
|
+
<% end %>
|
55
|
+
</template>
|
56
|
+
|
57
|
+
<%= render "headmin/forms/validation", media.validation_options if media.validate? %>
|
58
|
+
<%= render "headmin/forms/hint", media.hint_options if media.hint? %>
|
59
|
+
<%= render "headmin/forms/label", media.label_options if media.append_label? %>
|
60
|
+
<% end %>
|
@@ -2,12 +2,13 @@
|
|
2
2
|
# headmin/forms/repeater
|
3
3
|
#
|
4
4
|
# ==== Options
|
5
|
-
# * +form
|
6
|
-
# * +attribute
|
7
|
-
# * +header
|
5
|
+
# * +form+ - Form object
|
6
|
+
# * +attribute+ - Name of the attribute of the form model
|
7
|
+
# * +header+ - Name of the template to use as header
|
8
8
|
# * +label+ - Text to show as label. Label will be hidden if value is false
|
9
|
-
# * +templates
|
10
|
-
# * +flush
|
9
|
+
# * +templates+ - List of all views that can be used as a template for a new block
|
10
|
+
# * +flush+ - Set to true if you want the list items to sit flush with its parent.
|
11
|
+
# * +row+ - Pass hash with options to pass to the row template.
|
11
12
|
#
|
12
13
|
# ==== Examples
|
13
14
|
# # Basic version
|
@@ -21,12 +22,12 @@
|
|
21
22
|
# <% end %#>
|
22
23
|
#
|
23
24
|
# # With fixed header row. A header row can be used to show the labels, so you can omit them in the repeated fields
|
24
|
-
# <% render "headmin/forms/repeater", form: form, attribute: :questions, header:
|
25
|
+
# <% render "headmin/forms/repeater", form: form, attribute: :questions, header: "admin/questions/header" do |question| %#>
|
25
26
|
# <% render "admin/questions/fields, form: :question" %#>
|
26
27
|
# <% end %#>
|
27
28
|
#
|
28
29
|
# # Allow more than one type of fields to be inserted. You must specify the templates as an array of view paths
|
29
|
-
# <% templates = [
|
30
|
+
# <% templates = ["admin/questions/fields/type_1", "admin/questions/fields/type_2"] %#>
|
30
31
|
# <% render "headmin/forms/repeater", form: form, attribute: :questions, templates: templates do |question| %#>
|
31
32
|
# <% render "admin/questions/fields, form: :question" %#>
|
32
33
|
# <% end %#>
|
@@ -36,13 +37,14 @@
|
|
36
37
|
header = local_assigns.has_key?(:header) ? header : nil
|
37
38
|
templates = local_assigns.has_key?(:templates) ? templates : []
|
38
39
|
flush = local_assigns.has_key?(:flush) ? flush : true
|
40
|
+
row_options = local_assigns.has_key?(:row) ? row : {}
|
39
41
|
|
40
|
-
template_names = templates.map { |template| File.basename(template,
|
41
|
-
template_names = template_names.any? ? template_names : [
|
42
|
+
template_names = templates.map { |template| File.basename(template, ".html.erb") }
|
43
|
+
template_names = template_names.any? ? template_names : ["new"]
|
42
44
|
object_model = form.object.class
|
43
45
|
association_model = object_model.reflect_on_association(attribute).class_name.constantize
|
44
46
|
association_object = association_model.new
|
45
|
-
with_positions = association_object.attributes.keys.include?(
|
47
|
+
with_positions = association_object.attributes.keys.include?("position")
|
46
48
|
associations = form.object.send(attribute)
|
47
49
|
associations = with_positions ? associations.order(:position) : associations
|
48
50
|
repeater_id = form.object_id
|
@@ -55,7 +57,7 @@
|
|
55
57
|
<%= render "headmin/forms/label", form: form, attribute: attribute, text: label, required: required %>
|
56
58
|
<% end %>
|
57
59
|
|
58
|
-
<ul class="repeater list-group <%=
|
60
|
+
<ul class="repeater list-group <%= "list-group-flush" if flush %> mb-3" data-controller="repeater" data-repeater-target="list" data-repeater-id-value="<%= repeater_id %>">
|
59
61
|
|
60
62
|
<!-- Header -->
|
61
63
|
<% if header %>
|
@@ -66,7 +68,7 @@
|
|
66
68
|
|
67
69
|
<!-- Rows -->
|
68
70
|
<%= form.fields_for attribute, associations do |ff| %>
|
69
|
-
<%= render "headmin/forms/repeater/row", pass_thru: pass_thru, form: ff, repeater_id: repeater_id do %>
|
71
|
+
<%= render "headmin/forms/repeater/row", row_options.merge(pass_thru: pass_thru, form: ff, repeater_id: repeater_id) do %>
|
70
72
|
<%= yield(ff) %>
|
71
73
|
<% end %>
|
72
74
|
<% end %>
|
@@ -76,7 +78,7 @@
|
|
76
78
|
|
77
79
|
<!-- Empty notice -->
|
78
80
|
<div class="text-secondary invisible" data-repeater-target="empty">
|
79
|
-
<%= t(
|
81
|
+
<%= t(".empty") %>
|
80
82
|
</div>
|
81
83
|
|
82
84
|
<!-- Button -->
|
@@ -88,8 +90,8 @@
|
|
88
90
|
data-popup-pass-thru="<%= pass_thru %>"
|
89
91
|
data-action="click->repeater#resetButtonIndices click->popup#open"
|
90
92
|
>
|
91
|
-
<%= bootstrap_icon(
|
92
|
-
<%= t(
|
93
|
+
<%= bootstrap_icon("plus") %>
|
94
|
+
<%= t(".add", name: association_model.model_name.human) %>
|
93
95
|
</div>
|
94
96
|
|
95
97
|
<!-- Popup -->
|
@@ -114,7 +116,7 @@
|
|
114
116
|
<% template_names.each do |name| %>
|
115
117
|
<template data-repeater-target="template" data-template-name="<%= name %>" data-template-id-regex="<%= association_object.object_id %>">
|
116
118
|
<%= form.fields_for attribute, association_object, child_index: association_object.object_id do |ff| %>
|
117
|
-
<%= render "headmin/forms/repeater/row", form: ff, pass_thru: pass_thru, repeater_id: repeater_id do %>
|
119
|
+
<%= render "headmin/forms/repeater/row", row_options.merge(form: ff, pass_thru: pass_thru, repeater_id: repeater_id) do %>
|
118
120
|
<% yield(ff, name) %>
|
119
121
|
<% end %>
|
120
122
|
<% end %>
|
@@ -34,6 +34,6 @@
|
|
34
34
|
<%= form.text_area(textarea.attribute, textarea.input_options) %>
|
35
35
|
<% end %>
|
36
36
|
<%= render "headmin/forms/validation", textarea.validation_options if textarea.validate? %>
|
37
|
-
<%= render "headmin/forms/hint", textarea.hint_options if textarea.hint? %>
|
37
|
+
<%= render "headmin/forms/hint", textarea.hint_options if textarea.hint? || textarea.maxlength? %>
|
38
38
|
<%= render "headmin/forms/label", textarea.label_options if textarea.append_label? %>
|
39
39
|
<% end %>
|
@@ -19,8 +19,10 @@
|
|
19
19
|
%>
|
20
20
|
|
21
21
|
<%= render "headmin/forms/fields/base", form: form, name: name, field_type: :list do |list, field_label| %>
|
22
|
-
|
23
|
-
<%=
|
24
|
-
|
25
|
-
|
22
|
+
<div class="mb-3">
|
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 %>
|
25
|
+
<%= yield field %>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
26
28
|
<% end %>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<%
|
2
|
+
# headmin/forms/media/item
|
3
|
+
#
|
4
|
+
# ==== Required parameters
|
5
|
+
# * +form+ - Form object
|
6
|
+
# * +url+ - URL for the media modal
|
7
|
+
#
|
8
|
+
# ==== Optional parameters
|
9
|
+
# * +sort+ - Allow sorting by dragging items. `active_storage_attachments` must have a position column.
|
10
|
+
# * +width+ - Width of the thumbnail
|
11
|
+
# * +height+ - Height of the thumbnail
|
12
|
+
#
|
13
|
+
|
14
|
+
media_item = Headmin::Form::MediaItemView.new(local_assigns)
|
15
|
+
%>
|
16
|
+
|
17
|
+
<div class="h-form-file-thumbnail media-drag-sort-handle" title="<%= "#{media_item.filename} (#{media_item.size})" %>" data-media-target="item">
|
18
|
+
<%= form.hidden_field(:id) %>
|
19
|
+
<%= form.hidden_field(:blob_id) %>
|
20
|
+
<%= form.hidden_field(:position, value: media_item.position_value) if media_item.sort %>
|
21
|
+
<%= form.hidden_field(:_destroy) %>
|
22
|
+
|
23
|
+
<a href="<%= media_item.url %>" data-turbo-frame="remote_modal" data-media-target="modalButton">
|
24
|
+
<%= render "headmin/thumbnail", media_item.thumbnail_options %>
|
25
|
+
</a>
|
26
|
+
|
27
|
+
<div class="h-form-file-thumbnail-actions">
|
28
|
+
<!-- Edit -->
|
29
|
+
<a href="<%= headmin_media_item_url(id: media_item.id) %>" class="h-form-file-thumbnail-edit" data-turbo-frame="remote_modal" data-media-target="editButton">
|
30
|
+
<%= bootstrap_icon("pencil") %>
|
31
|
+
</a>
|
32
|
+
|
33
|
+
<!-- Remove -->
|
34
|
+
<div class="h-form-file-thumbnail-remove" data-action="click->media#destroy">
|
35
|
+
<%= bootstrap_icon("x") %>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
</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,9 +7,10 @@
|
|
7
7
|
|
8
8
|
draggable = form.object.respond_to?(:position)
|
9
9
|
destroyable = form.object.respond_to?(:destroy)
|
10
|
+
class_names = local_assigns.has_key?(:class) ? local_assigns[:class] : "repeater-row list-group-item"
|
10
11
|
%>
|
11
12
|
|
12
|
-
<div class="
|
13
|
+
<div class="<%= class_names %>"
|
13
14
|
data-repeater-target="row"
|
14
15
|
data-row-index="<%= form.options[:child_index] %>"
|
15
16
|
data-new-record="<%= form.object.new_record? %>"
|
@@ -18,34 +19,35 @@
|
|
18
19
|
<%= form.hidden_field :id %>
|
19
20
|
<%= form.hidden_field :_destroy if destroyable %>
|
20
21
|
<%= form.hidden_field :position if draggable %>
|
21
|
-
<%= yield %>
|
22
22
|
|
23
23
|
<!-- Drag handle -->
|
24
24
|
<% if draggable %>
|
25
25
|
<div class="repeater-row-handle">
|
26
|
-
<%= bootstrap_icon(
|
26
|
+
<%= bootstrap_icon("grip-vertical") %>
|
27
27
|
</div>
|
28
28
|
<% end %>
|
29
29
|
|
30
30
|
<!-- Add button-->
|
31
31
|
<div
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
class="repeater-row-add btn btn-link"
|
33
|
+
title="<%= t(".add") %>"
|
34
|
+
data-repeater-target="addButton"
|
35
|
+
data-popup-target="button"
|
36
|
+
data-popup-id="<%= "repeater-buttons-#{repeater_id}" %>"
|
37
|
+
data-popup-pass-thru="<%= pass_thru %>"
|
38
|
+
data-action="click->repeater#resetButtonIndices click->popup#open"
|
39
39
|
>
|
40
|
-
<%= bootstrap_icon(
|
40
|
+
<%= bootstrap_icon("plus-circle") %>
|
41
41
|
</div>
|
42
42
|
|
43
43
|
<!-- Remove button-->
|
44
44
|
<div
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
class="repeater-row-remove btn btn-link"
|
46
|
+
title="<%= t(".remove") %>"
|
47
|
+
data-action="click->repeater#removeRow"
|
48
48
|
>
|
49
|
-
<%= bootstrap_icon(
|
49
|
+
<%= bootstrap_icon("dash-circle") %>
|
50
50
|
</div>
|
51
|
+
|
52
|
+
<%= yield %>
|
51
53
|
</div>
|
@@ -13,11 +13,11 @@
|
|
13
13
|
<div class="h-heading-title">
|
14
14
|
<div class="d-flex align-items-center">
|
15
15
|
<h1 class="me-2">
|
16
|
-
<%= title ? title : t(
|
16
|
+
<%= title ? title : t(".new") %>
|
17
17
|
</h1>
|
18
18
|
<% if new_link %>
|
19
19
|
<a href="<%= new_link %>" class="btn btn-outline-primary btn-sm">
|
20
|
-
<%= t(
|
20
|
+
<%= t(".new") %>
|
21
21
|
</a>
|
22
22
|
<% end %>
|
23
23
|
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= turbo_frame_tag "remote_modal", target: "_top" %>
|
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
<div class="sidebar col-sm-12 col-md-1 col-lg-2 bg-dark overflow-y d-print-none">
|
9
9
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark w-100 h-100 flex-md-column">
|
10
|
-
<a href="<%= local_assigns[:url] %>" class="nav-brand mb-
|
10
|
+
<a href="<%= local_assigns[:url] %>" class="nav-brand mb-4 mt-3 me-lg-auto">
|
11
11
|
<%= local_assigns[:logo] %>
|
12
12
|
</a>
|
13
13
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar-nav" aria-controls="sidebar-nav" aria-expanded="false" aria-label="Toggle navigation">
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div data-media-modal-target="item" title="<%= "#{blob.filename} (#{l(blob.created_at, format: :long)})" %>">
|
2
|
+
<!-- Input -->
|
3
|
+
<input
|
4
|
+
id="media-item-<%= blob.id %>"
|
5
|
+
type="checkbox"
|
6
|
+
value="<%= blob.id %>"
|
7
|
+
<%= "checked" if params[:ids]&.include?(blob.id.to_s) %>
|
8
|
+
data-action="change->media-modal#inputChange"
|
9
|
+
data-media-modal-target="idCheckbox"
|
10
|
+
hidden>
|
11
|
+
|
12
|
+
<!-- Label -->
|
13
|
+
<label for="media-item-<%= blob.id %>">
|
14
|
+
<%= render "headmin/thumbnail", file: blob %>
|
15
|
+
</label>
|
16
|
+
</div>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%= turbo_frame_tag "modal_content" do %>
|
2
|
+
<%= form_with url: headmin_media_item_url(id: @blob.id), model: @blob do |form| %>
|
3
|
+
<div class="modal-header">
|
4
|
+
<h5 class="modal-title"><%= t(".edit") %></h5>
|
5
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<%= t(".close") %>"></button>
|
6
|
+
</div>
|
7
|
+
<div class="modal-body">
|
8
|
+
<%= render "headmin/notifications" %>
|
9
|
+
<div class="row">
|
10
|
+
<div class="col-4">
|
11
|
+
<%= render "headmin/thumbnail", file: @blob %>
|
12
|
+
</div>
|
13
|
+
<div class="col-8 d-flex flex-column justify-content-center">
|
14
|
+
<p class="small text-secondary m-0">
|
15
|
+
<strong><%= t(".uploaded_at") %>:</strong>
|
16
|
+
<%= l(@blob.created_at, format: :long) %>
|
17
|
+
</p>
|
18
|
+
<p class="small text-secondary m-0">
|
19
|
+
<strong><%= t(".type") %>:</strong>
|
20
|
+
<%= @blob.content_type %>
|
21
|
+
</p>
|
22
|
+
<p class="small text-secondary m-0">
|
23
|
+
<strong><%= t(".dimensions") %>:</strong>
|
24
|
+
<% if @blob.metadata[:width] && @blob.metadata[:height] %>
|
25
|
+
<%= "#{@blob.metadata[:width]}px x #{@blob.metadata[:height]}px" %>
|
26
|
+
<% else %>
|
27
|
+
<%= t(".not_analysed") %>
|
28
|
+
<% end %>
|
29
|
+
</p>
|
30
|
+
<p class="small text-secondary m-0">
|
31
|
+
<strong><%= t(".size") %>:</strong>
|
32
|
+
<% if @blob.byte_size > 0 %>
|
33
|
+
<%= number_to_human_size(@blob.byte_size) %>
|
34
|
+
<% else %>
|
35
|
+
<%= t(".not_analysed") %>
|
36
|
+
<% end %>
|
37
|
+
</p>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<div class="row mt-3">
|
41
|
+
<div class="col-12">
|
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
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
<div class="modal-footer">
|
47
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".close") %></button>
|
48
|
+
<%= form.submit t(".update"), class: "btn btn-primary" %>
|
49
|
+
</div>
|
50
|
+
<% end %>
|
51
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<div class="media-modal modal fade" tabindex="-1" data-controller="remote-modal media-modal" data-name="<%= name %>" data-min="<%= min %>" data-max="<%= max %>">
|
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", count: min.to_i < 1 ? 1 : min.to_i) %>
|
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
|
+
<%= turbo_frame_tag "thumbnails", class: "d-flex flex-wrap gap-2" do %>
|
12
|
+
<% @blobs.each do |blob| %>
|
13
|
+
<%= render "headmin/media/item", blob: blob %>
|
14
|
+
<% end %>
|
15
|
+
<div data-media-modal-target="placeholder" class="<%= "d-none" if !@blobs.empty? %>">
|
16
|
+
<p><%= t(".placeholder") %></p>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
<div class="modal-footer">
|
21
|
+
<%= form_with url: headmin_media_path, multipart: true, data: {"media-modal-target": "form"}, class: "me-auto" do |form| %>
|
22
|
+
<%= form.label :files, class: "btn h-btn-outline-light" do %>
|
23
|
+
<%= bootstrap_icon("upload") %>
|
24
|
+
<%= t(".upload") %>
|
25
|
+
<%= form.file_field :files, class: "d-none", multiple: true, data: {action: "change->media-modal#submitForm"} %>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
28
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(".close") %></button>
|
29
|
+
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" data-action="click->media-modal#select" data-media-modal-target="selectButton">
|
30
|
+
<%= t(".select") %> (<span data-media-modal-target="count">0</span><%= t(".maximum", count: max.to_i) if max.present? %>)
|
31
|
+
</button>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%= turbo_frame_tag "remote_modal" do %>
|
2
|
+
<div class="media-item-modal modal fade" tabindex="-1" data-controller="remote-modal">
|
3
|
+
<div class="modal-dialog modal-md modal-dialog-scrollable">
|
4
|
+
<div class="modal-content">
|
5
|
+
<%= render "headmin/media/media_item_modal" %>
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
<% end %>
|
@@ -9,12 +9,12 @@
|
|
9
9
|
#
|
10
10
|
# ==== Examples
|
11
11
|
# Basic version.
|
12
|
-
# <%= render "headmin/nav/dropdown", name:
|
13
|
-
# <%= render "headmin/nav/item", name:
|
14
|
-
# <%= render "headmin/nav/item", name:
|
12
|
+
# <%= render "headmin/nav/dropdown", name: "My Account", url: admin_user_path, icon: "person-circle" do %#>
|
13
|
+
# <%= render "headmin/nav/item", name: "Edit info", url: edit_admin_user_path(current_user) %#>
|
14
|
+
# <%= render "headmin/nav/item", name: "Log out", url: destroy_user_session_path(current_user) %#>
|
15
15
|
# <% end %#>
|
16
16
|
|
17
|
-
name = local_assigns.has_key?(:name) ? name :
|
17
|
+
name = local_assigns.has_key?(:name) ? name : ""
|
18
18
|
icon = local_assigns.has_key?(:icon) ? icon : nil
|
19
19
|
collapse_id = "nav-dropdown-#{name.parameterize}"
|
20
20
|
url = local_assigns.has_key?(:url) ? url : request.url
|
@@ -22,13 +22,13 @@
|
|
22
22
|
%>
|
23
23
|
|
24
24
|
<li class="nav-item">
|
25
|
-
<a class="nav-link d-flex align-items-center dropdown-toggle <%=
|
26
|
-
<%= bootstrap_icon(icon, class:
|
25
|
+
<a class="nav-link d-flex align-items-center dropdown-toggle <%= "active" if active %>" href="#<%= collapse_id %>" role="button" data-bs-toggle="collapse" aria-expanded="<%= active.to_s %>" aria-controls="<%= collapse_id %>">
|
26
|
+
<%= bootstrap_icon(icon, class: "me-2") if icon %>
|
27
27
|
<span class="d-block d-md-none d-lg-block">
|
28
28
|
<%= name %>
|
29
29
|
</span>
|
30
30
|
</a>
|
31
|
-
<ul class="collapse <%=
|
31
|
+
<ul class="collapse <%= "show" if active %>" id="<%= collapse_id %>">
|
32
32
|
<%= yield %>
|
33
33
|
</ul>
|
34
34
|
</li>
|
@@ -9,20 +9,20 @@
|
|
9
9
|
#
|
10
10
|
# ==== Examples
|
11
11
|
# Basic version.
|
12
|
-
# <%= render "headmin/nav/item", name:
|
12
|
+
# <%= render "headmin/nav/item", name: "Dashboard", url: admin_root_path %#>
|
13
13
|
#
|
14
14
|
# With icon
|
15
|
-
# <%= render "headmin/nav/item", name:
|
15
|
+
# <%= render "headmin/nav/item", name: "Dashboard", url: admin_root_path, icon: "speedometer" %#>
|
16
16
|
|
17
|
-
name = local_assigns.has_key?(:name) ? name :
|
17
|
+
name = local_assigns.has_key?(:name) ? name : ""
|
18
18
|
icon = local_assigns.has_key?(:icon) ? icon : nil
|
19
19
|
url = local_assigns.has_key?(:url) ? url : request.url
|
20
20
|
active = local_assigns.has_key?(:active) ? active : current_url?(url)
|
21
21
|
%>
|
22
22
|
|
23
23
|
<li class="nav-item">
|
24
|
-
<a class="nav-link d-flex align-items-center <%=
|
25
|
-
<%= bootstrap_icon(icon, class:
|
24
|
+
<a class="nav-link d-flex align-items-center <%= "active" if active %>" aria-current="page" href="<%= url %>">
|
25
|
+
<%= bootstrap_icon(icon, class: "me-2") if icon %>
|
26
26
|
<span class="d-block d-md-none d-lg-block">
|
27
27
|
<%= name %>
|
28
28
|
</span>
|
@@ -4,14 +4,14 @@
|
|
4
4
|
parameters: none
|
5
5
|
%>
|
6
6
|
|
7
|
-
<%= render "headmin/dropdown", class:
|
8
|
-
<%= render "headmin/dropdown/button", class:
|
9
|
-
<%= bootstrap_icon(
|
10
|
-
<%= t(
|
7
|
+
<%= render "headmin/dropdown", class: "nav-item" do %>
|
8
|
+
<%= render "headmin/dropdown/button", class: "nav-link", id: "nav-item-locale" do %>
|
9
|
+
<%= bootstrap_icon("globe", class: "me-2") %>
|
10
|
+
<%= t("language_name", locale: ::I18n.locale) %>
|
11
11
|
<% end %>
|
12
|
-
<%= render "headmin/dropdown/list", id:
|
12
|
+
<%= render "headmin/dropdown/list", id: "nav-item-locale" do %>
|
13
13
|
<% I18n.available_locales.each do |locale| %>
|
14
|
-
<%= render "headmin/dropdown/item", name: t(
|
14
|
+
<%= render "headmin/dropdown/item", name: t("language_name", locale: locale), url: url_for({locale: locale.to_s}) %>
|
15
15
|
<% end %>
|
16
16
|
<% end %>
|
17
17
|
<% end %>
|