lato_cms 3.1.3 → 3.1.5

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: c71453863fa3e56037214bc1884c628a66104e331cfd1b13804f2408964d332c
4
- data.tar.gz: 47f259f2406ed3913f15220c83395ffb6d8e592013980d278fa7e2649c4103aa
3
+ metadata.gz: 335542f7d3246d07af36c41b161ab638d26f9f923823d3bedc255a943bac2197
4
+ data.tar.gz: a36f8acf15e683688a5344090fc7cc023d12b57371411dcbcfaba436f4f04d1a
5
5
  SHA512:
6
- metadata.gz: cea16a860d7468d42ec2df54e32ecf18c1d923860f77f66ce3fda79548e637d3e436506fc90c1b9b5ea7b3e0641b45146f288a691bc805089a84be47a4afdf86
7
- data.tar.gz: 971a5d487ba77d10b7761cf20d976ec38c3ea3fb4bdfc7228a7c626888cb28345894bce7aef71dbca35f40d11f330b1da9b5334dc4334d6587aabb8ec7316051
6
+ metadata.gz: '04776471890c80fc97fb2ff07dd3b27eaffdc54dbe7273ed5ae7f099a7bed4083fa21c26dc96d460a245ce49741b46076c9dd720cbb7516f3edea34521742759'
7
+ data.tar.gz: 8730a9ead03c286df9540e72c1ea1eb13ac696c536331b5dad038efa26598bacee29ae1d998243f38536b8efadfa97af9db64c6881e1adb74d5524c13a3a62e0
@@ -2,45 +2,46 @@ import { Controller } from '@hotwired/stimulus'
2
2
 
3
3
  export default class extends Controller {
4
4
  connect () {
5
- this.handleShown = this.handleShown.bind(this)
6
- this.handleHidden = this.handleHidden.bind(this)
5
+ this.handleToggle = this.handleToggle.bind(this)
7
6
 
8
- this.element.addEventListener('shown.bs.collapse', this.handleShown)
9
- this.element.addEventListener('hidden.bs.collapse', this.handleHidden)
7
+ this.element.addEventListener('shown.bs.collapse', this.handleToggle)
8
+ this.element.addEventListener('hidden.bs.collapse', this.handleToggle)
10
9
 
11
10
  window.requestAnimationFrame(() => {
12
- this.broadcastInitiallyOpenComponent()
11
+ this.broadcastCurrentSelection()
13
12
  })
14
13
  }
15
14
 
16
15
  disconnect () {
17
- this.element.removeEventListener('shown.bs.collapse', this.handleShown)
18
- this.element.removeEventListener('hidden.bs.collapse', this.handleHidden)
16
+ this.element.removeEventListener('shown.bs.collapse', this.handleToggle)
17
+ this.element.removeEventListener('hidden.bs.collapse', this.handleToggle)
19
18
  }
20
19
 
21
- handleShown (event) {
22
- this.broadcastForCollapse(event.target)
23
- }
24
-
25
- // Repeater items are nested collapses without a template component id, and
26
- // their events bubble up here: closing one would otherwise deselect the
27
- // component that is still open. Same guard `broadcastForCollapse` applies.
28
- handleHidden (event) {
29
- if (!event.target.dataset.templateComponentId) return
30
-
31
- this.broadcastClosedComponent()
20
+ // Repeater items are nested collapses, so their events bubble up here, and
21
+ // opening one item closes its sibling: the events alone don't tell what ends
22
+ // up open. Read the selection off the DOM once it has settled instead.
23
+ handleToggle () {
24
+ window.requestAnimationFrame(() => {
25
+ this.broadcastCurrentSelection()
26
+ })
32
27
  }
33
28
 
34
- broadcastInitiallyOpenComponent () {
35
- const openCollapse = this.element.querySelector('.accordion-collapse.show')
36
- if (!openCollapse) return
29
+ // The open component, narrowed to the open repeater item when there is one.
30
+ broadcastCurrentSelection () {
31
+ const openComponent = this.element.querySelector('.accordion-collapse.show')
32
+ if (!openComponent) {
33
+ this.broadcastClosedComponent()
34
+ return
35
+ }
37
36
 
38
- this.broadcastForCollapse(openCollapse)
37
+ const openItem = openComponent.querySelector('.collapse.show[data-repeater-item-id]')
38
+ this.broadcastForCollapse(openItem || openComponent)
39
39
  }
40
40
 
41
41
  broadcastForCollapse (collapseElement) {
42
42
  const templateComponentId = collapseElement.dataset.templateComponentId
43
43
  const componentId = collapseElement.dataset.componentId
44
+ const repeaterItemId = collapseElement.dataset.repeaterItemId
44
45
 
45
46
  if (!templateComponentId) return
46
47
 
@@ -48,7 +49,8 @@ export default class extends Controller {
48
49
  detail: {
49
50
  id: templateComponentId,
50
51
  templateComponentId,
51
- componentId
52
+ componentId,
53
+ repeaterItemId: repeaterItemId || null
52
54
  }
53
55
  }))
54
56
  }
@@ -58,7 +60,8 @@ export default class extends Controller {
58
60
  detail: {
59
61
  id: null,
60
62
  templateComponentId: null,
61
- componentId: null
63
+ componentId: null,
64
+ repeaterItemId: null
62
65
  }
63
66
  }))
64
67
  }
@@ -66,11 +66,14 @@ export default class extends Controller {
66
66
  const templateComponentId = openCollapse.dataset.templateComponentId
67
67
  if (!templateComponentId) return
68
68
 
69
+ const openItem = openCollapse.querySelector('.collapse.show[data-repeater-item-id]')
70
+
69
71
  document.dispatchEvent(new CustomEvent('lato-cms:component-change', {
70
72
  detail: {
71
73
  id: templateComponentId,
72
74
  templateComponentId,
73
- componentId: openCollapse.dataset.componentId
75
+ componentId: openCollapse.dataset.componentId,
76
+ repeaterItemId: openItem?.dataset.repeaterItemId || null
74
77
  }
75
78
  }))
76
79
  }
@@ -116,10 +116,13 @@ export default class extends Controller {
116
116
  const templateComponentId = openCollapse.dataset.templateComponentId
117
117
  if (!templateComponentId) return
118
118
 
119
+ const openItem = openCollapse.querySelector('.collapse.show[data-repeater-item-id]')
120
+
119
121
  this.activeComponent = {
120
122
  id: templateComponentId,
121
123
  templateComponentId,
122
- componentId: openCollapse.dataset.componentId
124
+ componentId: openCollapse.dataset.componentId,
125
+ repeaterItemId: openItem?.dataset.repeaterItemId || null
123
126
  }
124
127
 
125
128
  this.postActiveComponent()
@@ -12,7 +12,7 @@ module LatoCms
12
12
  sortable_columns: %i[name media_type created_at],
13
13
  searchable_columns: %i[name alt_text],
14
14
  default_sort_by: 'created_at|DESC',
15
- pagination: 24
15
+ pagination: 20
16
16
  )
17
17
  end
18
18
 
@@ -172,6 +172,21 @@ module LatoCms
172
172
  nil
173
173
  end
174
174
 
175
+ # Large uncropped variant for the admin detail view, where the 200x200
176
+ # square thumbnail is too small to actually judge the image. Falls back to
177
+ # the original blob when the file can't be processed (e.g. SVG).
178
+ def preview_url
179
+ return nil unless image? && file.attached?
180
+ return url unless file.variable?
181
+
182
+ Rails.application.routes.url_helpers.rails_representation_path(
183
+ file.variant(resize_to_limit: [1200, 1200]), only_path: true
184
+ )
185
+ rescue StandardError => e
186
+ Rails.logger.error("LatoCms: Failed to build preview for media #{id}: #{e.message}")
187
+ url
188
+ end
189
+
175
190
  # Builds a map of { size_name => variant_url } from a field's `settings.sizes`
176
191
  # config. The config is field-owned (different fields can request different
177
192
  # crops of the same reused Media); the mechanics live here since Media owns
@@ -5,9 +5,24 @@
5
5
  <%= lato_form_notices class: %w[mb-3] %>
6
6
  <%= lato_form_errors media, class: %w[mb-3] %>
7
7
 
8
- <div class="mb-3 d-flex align-items-center gap-2">
9
- <%= lato_cms_media_thumb(media, size: 64) %>
10
- <span class="text-muted small"><%= media.filename %></span>
8
+ <%# Preview: images/videos get a large view (the index thumbnail is too small
9
+ to judge a file by), everything else keeps the small type icon. %>
10
+ <div class="mb-3">
11
+ <% if media.image? %>
12
+ <%= link_to media.url, target: '_blank', rel: 'noopener', title: t('lato_cms.media_open_original'),
13
+ class: 'd-block bg-light rounded overflow-hidden' do %>
14
+ <%= image_tag media.preview_url, class: 'd-block mx-auto', style: 'max-width: 100%; max-height: 420px;', alt: media.alt_text %>
15
+ <% end %>
16
+ <% elsif media.video? %>
17
+ <video controls preload="metadata" class="d-block w-100 rounded bg-black" style="max-height: 420px;" src="<%= media.url %>"></video>
18
+ <% end %>
19
+
20
+ <div class="d-flex align-items-center gap-2 mt-2">
21
+ <% unless media.image? || media.video? %>
22
+ <%= lato_cms_media_thumb(media, size: 64) %>
23
+ <% end %>
24
+ <span class="text-muted small"><%= media.filename %></span>
25
+ </div>
11
26
  </div>
12
27
 
13
28
  <div class="mb-3">
@@ -16,7 +16,7 @@
16
16
  }
17
17
  }
18
18
  },
19
- pagination_options: [12, 24, 48, 96]
19
+ pagination_options: [10, 20, 50, 100]
20
20
  %>
21
21
  </div>
22
22
  </div>
@@ -14,7 +14,11 @@
14
14
  </button>
15
15
  </div>
16
16
 
17
- <div id="<%= collapse_id %>" class="collapse <%= 'show' if expanded %>" data-bs-parent="#<%= parent_id %>">
17
+ <%# The component ids travel on the item collapse too, so the live preview can
18
+ highlight the single item being edited (see lato_cms_component_accordion_controller). %>
19
+ <div id="<%= collapse_id %>" class="collapse <%= 'show' if expanded %>" data-bs-parent="#<%= parent_id %>"
20
+ data-template-component-id="<%= tc[:template_component_id] %>" data-component-id="<%= tc[:component_id] %>"
21
+ data-repeater-item-id="<%= item_id %>">
18
22
  <div class="card-body pb-2">
19
23
  <% tc[:fields].each do |field_id, field_config| %>
20
24
  <% page_field = item_fields[field_id.to_s] %>
@@ -99,6 +99,7 @@ en:
99
99
  media_create_title: Upload media
100
100
  media_create_cta: Upload
101
101
  media_update_title: Edit media
102
+ media_open_original: Open the original file in a new tab
102
103
  media_alt_text: Alt text
103
104
  media_alt_text_regenerate: Regenerate with AI
104
105
  media_alt_text_regenerate_confirm: "This will overwrite the current alt text in every language with a new AI-generated one. Continue?"
@@ -99,6 +99,7 @@ it:
99
99
  media_create_title: Carica media
100
100
  media_create_cta: Carica
101
101
  media_update_title: Modifica media
102
+ media_open_original: Apri il file originale in una nuova scheda
102
103
  media_alt_text: Testo alternativo
103
104
  media_alt_text_regenerate: Rigenera con AI
104
105
  media_alt_text_regenerate_confirm: "Il testo alternativo attuale in ogni lingua verrà sostituito con uno generato dall'AI. Continuare?"
@@ -1,3 +1,3 @@
1
1
  module LatoCms
2
- VERSION = "3.1.3"
2
+ VERSION = "3.1.5"
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.1.3
4
+ version: 3.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante