lato_cms 3.0.2 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 527556e5bf27156bab801e7f0c23c53f9ac9e0565d051da5a0fa1c9500954357
4
- data.tar.gz: dfcbcca5925d763f06d2043e497e128d84d3fcd200059990f9cb8fc1718699cc
3
+ metadata.gz: 319316314172ac5393d5d560741b331e00a8570fe476090f607cf3c583addce4
4
+ data.tar.gz: c8566ef62e7af5280fd4627a376d79b1dabbef383eeb365d7f3720ad9b3d5dba
5
5
  SHA512:
6
- metadata.gz: 37384b79131f97266d82434b290a2bdd3ce4b844d1bf9c63bb6363f4877cfa8379ebe1d1fb4ffe2f6bcbc2a00cc69b8e13124b6e9fa9293025ab98606a4690e4
7
- data.tar.gz: e9ce262f6bbfc70a07554edba5e18ffe9f1c028250da9f6ac5a5b7962977b2f408222e8fddd2eb949f4d48fb1bf2d319c420b1f76ccf3d0675d6a1e39d80c5bb
6
+ metadata.gz: 6be7fac9bc254c30c2302b9bdd8351c7e20809b0a1f39cfaad773c74d82ead10bd7db204816f02ca86809eb46f03afb98ecbe516e474ad93a7a7cc2e01b7c9c8
7
+ data.tar.gz: 139e9d97bacf5cb8eb36542674c84483c4296964359799440689fc604a0705449c0e48531ad286d961569a115cef5b5fbdb2d2fd0ca08441a5e33f01ea939f43
@@ -106,8 +106,8 @@ export default class extends Controller {
106
106
  <span class="text-muted small">(${this.humanSize(file.size)})</span>
107
107
  <span class="badge bg-success">${this.newBadgeLabel}</span>
108
108
  </div>
109
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-file-field#remove">
110
- <i class="bi bi-trash me-1"></i>${this.removeLabel}
109
+ <button type="button" class="lato-cms-attachment-field__remove" title="${this.removeLabel}" aria-label="${this.removeLabel}" data-action="lato-cms-file-field#remove">
110
+ <i class="bi bi-trash"></i>
111
111
  </button>
112
112
  `
113
113
  return item
@@ -150,8 +150,8 @@ export default class extends Controller {
150
150
  <span>${this.escapeHtml(attachment.filename)}</span>
151
151
  <span class="text-muted small">(${this.humanSize(attachment.byte_size || 0)})</span>
152
152
  </div>
153
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-file-field#remove">
154
- <i class="bi bi-trash me-1"></i>${this.removeLabel}
153
+ <button type="button" class="lato-cms-attachment-field__remove" title="${this.removeLabel}" aria-label="${this.removeLabel}" data-action="lato-cms-file-field#remove">
154
+ <i class="bi bi-trash"></i>
155
155
  </button>
156
156
  <div class="lato-cms-file-field__removed d-none" data-lato-cms-file-field-target="removedNotice">
157
157
  <span class="text-danger small">
@@ -136,8 +136,8 @@ export default class extends Controller {
136
136
  div.setAttribute('data-action', 'dragstart->lato-cms-gallery-field#onDragStart dragend->lato-cms-gallery-field#onDragEnd')
137
137
  div.innerHTML = `
138
138
  <img src="${src}" class="lato-cms-gallery-field__thumb" alt="">
139
- <button type="button" class="lato-cms-gallery-field__remove" data-action="click->lato-cms-gallery-field#remove">
140
- <i class="bi bi-x-lg"></i>
139
+ <button type="button" class="lato-cms-attachment-field__remove lato-cms-gallery-field__remove" title="${this.removeLabel}" aria-label="${this.removeLabel}" data-action="click->lato-cms-gallery-field#remove">
140
+ <i class="bi bi-trash"></i>
141
141
  </button>
142
142
  `
143
143
  return div
@@ -165,4 +165,8 @@ export default class extends Controller {
165
165
  return field.persisted_field_id === this.fieldIdValue || field.field_id === this.fieldIdValue
166
166
  })
167
167
  }
168
+
169
+ get removeLabel() {
170
+ return this.element.dataset.removeLabel || 'Remove'
171
+ }
168
172
  }
@@ -42,7 +42,7 @@ export default class extends Controller {
42
42
  remove() {
43
43
  if (!this.hasCurrentContainerTarget) return
44
44
 
45
- this.currentContainerTarget.classList.add('lato-cms-image-field--removing')
45
+ this.currentContainerTarget.classList.add('lato-cms-file-field__item--removing')
46
46
  this.removedNoticeTarget.classList.remove('d-none')
47
47
  this.ensureRemoveInput()
48
48
  }
@@ -50,7 +50,7 @@ export default class extends Controller {
50
50
  undo() {
51
51
  if (!this.hasCurrentContainerTarget) return
52
52
 
53
- this.currentContainerTarget.classList.remove('lato-cms-image-field--removing')
53
+ this.currentContainerTarget.classList.remove('lato-cms-file-field__item--removing')
54
54
  this.removedNoticeTarget.classList.add('d-none')
55
55
  this.removeInput?.remove()
56
56
  this.removeInput = null
@@ -104,10 +104,10 @@ export default class extends Controller {
104
104
  <span>${this.escapeHtml(attachment.filename)}</span>
105
105
  <span class="text-muted small">(${this.humanSize(attachment.byte_size || 0)})</span>
106
106
  </div>
107
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-image-field#remove">
108
- <i class="bi bi-trash me-1"></i>${this.removeLabel}
107
+ <button type="button" class="lato-cms-attachment-field__remove" title="${this.removeLabel}" aria-label="${this.removeLabel}" data-action="lato-cms-image-field#remove">
108
+ <i class="bi bi-trash"></i>
109
109
  </button>
110
- <div class="lato-cms-image-field__removed d-none" data-lato-cms-image-field-target="removedNotice">
110
+ <div class="lato-cms-file-field__removed d-none" data-lato-cms-image-field-target="removedNotice">
111
111
  <span class="text-danger small">
112
112
  <i class="bi bi-trash me-1"></i>${this.removePendingLabel}
113
113
  </span>
@@ -189,6 +189,28 @@ body.lato-cms-advanced-editor--open {
189
189
  width: 100%;
190
190
  }
191
191
 
192
+ .lato-cms-attachment-field__remove {
193
+ align-items: center;
194
+ align-self: center;
195
+ background: #f8d7da;
196
+ border: 0;
197
+ border-radius: 50%;
198
+ color: var(--bs-danger);
199
+ display: inline-flex;
200
+ flex: 0 0 auto;
201
+ height: 32px;
202
+ justify-content: center;
203
+ padding: 0;
204
+ transition: background 0.15s, color 0.15s;
205
+ width: 32px;
206
+
207
+ &:hover,
208
+ &:focus {
209
+ background: #f1aeb5;
210
+ color: var(--bs-danger);
211
+ }
212
+ }
213
+
192
214
  .lato-cms-file-field__item--removing {
193
215
  background: rgba(220, 53, 69, 0.06);
194
216
  border-color: rgba(220, 53, 69, 0.35);
@@ -196,6 +218,7 @@ body.lato-cms-advanced-editor--open {
196
218
 
197
219
  .lato-cms-file-field__info,
198
220
  .lato-cms-image-field__preview,
221
+ .lato-cms-attachment-field__remove,
199
222
  > .btn {
200
223
  display: none;
201
224
  }
@@ -259,23 +282,6 @@ body.lato-cms-advanced-editor--open {
259
282
  }
260
283
  }
261
284
 
262
- .lato-cms-image-field__removed {
263
- align-items: center;
264
- display: flex;
265
- gap: 0.75rem;
266
- justify-content: space-between;
267
- width: 100%;
268
- }
269
-
270
- .lato-cms-image-field--removing {
271
- .lato-cms-image-field__preview,
272
- .lato-cms-file-field__info,
273
- .lato-cms-image-field__remove-btn,
274
- > .btn {
275
- display: none;
276
- }
277
- }
278
-
279
285
  .lato-cms-image-field__new-badge {
280
286
  position: absolute;
281
287
  bottom: 4px;
@@ -318,26 +324,8 @@ body.lato-cms-advanced-editor--open {
318
324
 
319
325
  .lato-cms-gallery-field__remove {
320
326
  position: absolute;
321
- top: 3px;
322
- right: 3px;
323
- width: 20px;
324
- height: 20px;
325
- border-radius: 50%;
326
- border: none;
327
- background: rgba(220, 53, 69, 0.85);
328
- color: #fff;
329
- display: flex;
330
- align-items: center;
331
- justify-content: center;
332
- font-size: 9px;
333
- padding: 0;
334
- cursor: pointer;
335
- line-height: 1;
336
- transition: background 0.15s;
337
-
338
- &:hover {
339
- background: rgb(220, 53, 69);
340
- }
327
+ right: 4px;
328
+ top: 4px;
341
329
  }
342
330
 
343
331
  .controller-pages-show {
@@ -92,12 +92,12 @@ module LatoCms
92
92
  result[:attachments] = files.map { |f| attachment_as_json(f) }
93
93
  when 'image'
94
94
  attached = files.first
95
- result[:attachments] = attached ? [attachment_as_json(attached)] : []
95
+ result[:attachments] = attached ? [attachment_as_json(attached, with_variants: true)] : []
96
96
  when 'gallery'
97
97
  order = value ? (JSON.parse(value) rescue []) : []
98
98
  all_files = files.to_a
99
99
  ordered = order.any? ? all_files.sort_by { |f| order.index(f.id.to_s) || Float::INFINITY } : all_files
100
- result[:attachments] = ordered.map { |f| attachment_as_json(f) }
100
+ result[:attachments] = ordered.map { |f| attachment_as_json(f, with_variants: true) }
101
101
  else
102
102
  result[:value] = parsed_value
103
103
  end
@@ -107,14 +107,49 @@ module LatoCms
107
107
 
108
108
  private
109
109
 
110
- def attachment_as_json(attachment)
111
- {
110
+ def attachment_as_json(attachment, with_variants: false)
111
+ json = {
112
112
  id: attachment.id,
113
113
  filename: attachment.filename.to_s,
114
114
  content_type: attachment.content_type,
115
115
  byte_size: attachment.byte_size,
116
116
  url: Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)
117
117
  }
118
+ json[:sizes] = attachment_variant_urls(attachment) if with_variants
119
+ json
120
+ end
121
+
122
+ # Builds a map of { size_name => variant_url } from the field's `settings.sizes`.
123
+ # Variants are processed lazily by Active Storage on first request to their URL.
124
+ def attachment_variant_urls(attachment)
125
+ sizes = field_settings['sizes']
126
+ return {} if sizes.blank? || !sizes.respond_to?(:each_pair) || !attachment.variable?
127
+
128
+ url_helpers = Rails.application.routes.url_helpers
129
+ sizes.each_with_object({}) do |(name, opts), acc|
130
+ transformation = variant_transformation(opts)
131
+ next if transformation.blank?
132
+
133
+ variant = attachment.variant(transformation)
134
+ acc[name] = url_helpers.rails_representation_path(variant, only_path: true)
135
+ end
136
+ rescue StandardError => e
137
+ Rails.logger.error("LatoCms: Failed to build image variants for attachment #{attachment.id}: #{e.message}")
138
+ {}
139
+ end
140
+
141
+ # Maps a size config (width/height/resize) to an Active Storage variant transformation.
142
+ # resize modes: "limit" (default, scale down only), "fit" (scale to fit), "fill" (crop to exact size).
143
+ def variant_transformation(opts)
144
+ opts = {} unless opts.respond_to?(:[])
145
+ dimensions = [opts['width'] || opts[:width], opts['height'] || opts[:height]]
146
+ return nil if dimensions.compact.empty?
147
+
148
+ case (opts['resize'] || opts[:resize] || 'limit').to_s
149
+ when 'fill' then { resize_to_fill: dimensions }
150
+ when 'fit' then { resize_to_fit: dimensions }
151
+ else { resize_to_limit: dimensions }
152
+ end
118
153
  end
119
154
 
120
155
  def parse_value
@@ -27,8 +27,8 @@
27
27
  <span><%= file.blob.filename %></span>
28
28
  <span class="text-muted small">(<%= number_to_human_size(file.blob.byte_size) %>)</span>
29
29
  </div>
30
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-file-field#remove">
31
- <i class="bi bi-trash me-1"></i><%= t('lato_cms.field_file_remove') %>
30
+ <button type="button" class="lato-cms-attachment-field__remove" title="<%= t('lato_cms.field_file_remove') %>" aria-label="<%= t('lato_cms.field_file_remove') %>" data-action="lato-cms-file-field#remove">
31
+ <i class="bi bi-trash"></i>
32
32
  </button>
33
33
  <div class="lato-cms-file-field__removed d-none" data-lato-cms-file-field-target="removedNotice">
34
34
  <span class="text-danger small">
@@ -20,7 +20,7 @@ end %>
20
20
  <%= label %><%= ' *' if required %>
21
21
  </label>
22
22
 
23
- <div data-controller="lato-cms-gallery-field" data-lato-cms-gallery-field-field-id-value="<%= field_id %>" data-lato-cms-gallery-field-input-name-prefix-value="<%= local_assigns[:input_name_prefix].presence || "fields[#{field_id}]" %>">
23
+ <div data-controller="lato-cms-gallery-field" data-lato-cms-gallery-field-field-id-value="<%= field_id %>" data-lato-cms-gallery-field-input-name-prefix-value="<%= local_assigns[:input_name_prefix].presence || "fields[#{field_id}]" %>" data-remove-label="<%= t('lato_cms.field_file_remove') %>">
24
24
  <div class="lato-cms-gallery-field__grid mb-2"
25
25
  data-lato-cms-gallery-field-target="grid"
26
26
  data-action="dragover->lato-cms-gallery-field#onGridDragOver drop->lato-cms-gallery-field#onGridDrop">
@@ -31,8 +31,8 @@ end %>
31
31
  draggable="true"
32
32
  data-action="dragstart->lato-cms-gallery-field#onDragStart dragend->lato-cms-gallery-field#onDragEnd">
33
33
  <img src="<%= lato_cms_attachment_path(file) %>" class="lato-cms-gallery-field__thumb" alt="<%= file.filename %>">
34
- <button type="button" class="lato-cms-gallery-field__remove" data-action="click->lato-cms-gallery-field#remove">
35
- <i class="bi bi-x-lg"></i>
34
+ <button type="button" class="lato-cms-attachment-field__remove lato-cms-gallery-field__remove" title="<%= t('lato_cms.field_file_remove') %>" aria-label="<%= t('lato_cms.field_file_remove') %>" data-action="click->lato-cms-gallery-field#remove">
35
+ <i class="bi bi-trash"></i>
36
36
  </button>
37
37
  </div>
38
38
  <% end %>
@@ -27,10 +27,10 @@
27
27
  <span><%= current_file.blob.filename %></span>
28
28
  <span class="text-muted small">(<%= number_to_human_size(current_file.blob.byte_size) %>)</span>
29
29
  </div>
30
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-image-field#remove">
31
- <i class="bi bi-trash me-1"></i><%= t('lato_cms.field_image_remove') %>
30
+ <button type="button" class="lato-cms-attachment-field__remove" title="<%= t('lato_cms.field_image_remove') %>" aria-label="<%= t('lato_cms.field_image_remove') %>" data-action="lato-cms-image-field#remove">
31
+ <i class="bi bi-trash"></i>
32
32
  </button>
33
- <div class="lato-cms-image-field__removed d-none" data-lato-cms-image-field-target="removedNotice">
33
+ <div class="lato-cms-file-field__removed d-none" data-lato-cms-image-field-target="removedNotice">
34
34
  <span class="text-danger small">
35
35
  <i class="bi bi-trash me-1"></i><%= t('lato_cms.field_image_remove_pending') %>
36
36
  </span>
@@ -51,8 +51,8 @@
51
51
  <span class="text-muted small" data-lato-cms-image-field-target="newPreviewSize"></span>
52
52
  <span class="badge bg-success"><%= t('lato_cms.field_image_new_badge') %></span>
53
53
  </div>
54
- <button type="button" class="btn btn-sm btn-outline-danger" data-action="lato-cms-image-field#removeNew">
55
- <i class="bi bi-trash me-1"></i><%= t('lato_cms.field_image_remove') %>
54
+ <button type="button" class="lato-cms-attachment-field__remove" title="<%= t('lato_cms.field_image_remove') %>" aria-label="<%= t('lato_cms.field_image_remove') %>" data-action="lato-cms-image-field#removeNew">
55
+ <i class="bi bi-trash"></i>
56
56
  </button>
57
57
  </div>
58
58
 
@@ -1,3 +1,3 @@
1
1
  module LatoCms
2
- VERSION = "3.0.2"
2
+ VERSION = "3.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lato_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: image_processing
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.2'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '1.2'
68
82
  description: A Rails engine to manage application users on Lato projects!
69
83
  email:
70
84
  - me@gregoriogalante.com