lato_cms 3.4.0 → 3.5.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.
- checksums.yaml +4 -4
- data/README.md +137 -9
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_advanced_editor_controller.js +58 -6
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_color_field_controller.js +11 -1
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_component_form_controller.js +48 -5
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_component_toggle_controller.js +6 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_json_field_controller.js +3 -2
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_media_field_controller.js +40 -2
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_media_picker_controller.js +6 -5
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_media_reorder_controller.js +25 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_page_preview_controller.js +6 -1
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_repeater_controller.js +8 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_text_field_controller.js +2 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_upload_controller.js +4 -1
- data/app/assets/stylesheets/lato_cms/application.scss +57 -0
- data/app/controllers/lato_cms/application_controller.rb +23 -1
- data/app/controllers/lato_cms/media_controller.rb +4 -2
- data/app/controllers/lato_cms/pages_controller.rb +51 -22
- data/app/helpers/lato_cms/media_helper.rb +1 -1
- data/app/helpers/lato_cms/pages_helper.rb +15 -12
- data/app/jobs/lato_cms/export_sitemap_csv_job.rb +8 -1
- data/app/models/lato_cms/llm_client.rb +11 -0
- data/app/models/lato_cms/media.rb +41 -11
- data/app/models/lato_cms/page.rb +45 -7
- data/app/models/lato_cms/page_field.rb +64 -4
- data/app/models/lato_cms/template_manager.rb +49 -3
- data/app/views/lato_cms/media/_form_update.html.erb +9 -7
- data/app/views/lato_cms/media/_translations_field.html.erb +8 -5
- data/app/views/lato_cms/media/_upload_progress.html.erb +4 -2
- data/app/views/lato_cms/media/picker_action.html.erb +21 -14
- data/app/views/lato_cms/media/show.html.erb +2 -1
- data/app/views/lato_cms/pages/_component_accordion.html.erb +14 -8
- data/app/views/lato_cms/pages/_form_update.html.erb +5 -0
- data/app/views/lato_cms/pages/_repeater_item.html.erb +6 -4
- data/app/views/lato_cms/pages/_translations.html.erb +2 -1
- data/app/views/lato_cms/pages/fields/_color.html.erb +14 -6
- data/app/views/lato_cms/pages/fields/_json.html.erb +5 -2
- data/app/views/lato_cms/pages/fields/_media_field.html.erb +12 -5
- data/app/views/lato_cms/pages/fields/_media_item.html.erb +14 -3
- data/app/views/lato_cms/pages/fields/_text.html.erb +31 -22
- data/app/views/lato_cms/pages/index.html.erb +3 -2
- data/app/views/lato_cms/pages/show.html.erb +26 -9
- data/config/locales/en.yml +27 -1
- data/config/locales/it.yml +27 -1
- data/lib/lato_cms/config.rb +26 -1
- data/lib/lato_cms/version.rb +1 -1
- data/lib/tasks/lato_cms_tasks.rake +18 -11
- metadata +1 -15
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
<% input_name = lato_cms_field_input_name(field_id, input_name_prefix: local_assigns[:input_name_prefix]) %>
|
|
5
5
|
<% input_id = lato_cms_field_dom_id(field_id, dom_id_prefix: local_assigns[:dom_id_prefix]) %>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<%# Names the editable area through aria-labelledby: `for` cannot target a contenteditable, and the hidden input is not focusable. %>
|
|
8
|
+
<label class="form-label" id="<%= input_id %>_label">
|
|
8
9
|
<%= label %><%= ' *' if required %>
|
|
9
10
|
</label>
|
|
10
11
|
|
|
@@ -13,59 +14,66 @@
|
|
|
13
14
|
data-lato-cms-text-field-attributes-value="<%= LatoCms::PageField::RICH_TEXT_ATTRIBUTES.join(' ') %>">
|
|
14
15
|
|
|
15
16
|
<%# ── Toolbar ──────────────────────────────────────────────────────────── %>
|
|
16
|
-
<div
|
|
17
|
+
<div role="toolbar" aria-label="<%= t('lato_cms.field_text_toolbar_label') %>" aria-controls="<%= input_id %>_editor"
|
|
18
|
+
class="lato-cms-wysiwyg-toolbar border border-bottom-0 rounded-top bg-light px-2 py-1 d-flex flex-wrap gap-1 align-items-center"
|
|
17
19
|
data-lato-cms-text-field-target="toolbar">
|
|
18
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_bold') %>"
|
|
20
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_bold') %>" aria-label="<%= t('lato_cms.field_text_toolbar_bold') %>"
|
|
19
21
|
data-action="click->lato-cms-text-field#bold">
|
|
20
|
-
<i class="bi bi-type-bold"></i>
|
|
22
|
+
<i class="bi bi-type-bold" aria-hidden="true"></i>
|
|
21
23
|
</button>
|
|
22
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_italic') %>"
|
|
24
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_italic') %>" aria-label="<%= t('lato_cms.field_text_toolbar_italic') %>"
|
|
23
25
|
data-action="click->lato-cms-text-field#italic">
|
|
24
|
-
<i class="bi bi-type-italic"></i>
|
|
26
|
+
<i class="bi bi-type-italic" aria-hidden="true"></i>
|
|
25
27
|
</button>
|
|
26
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_underline') %>"
|
|
28
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_underline') %>" aria-label="<%= t('lato_cms.field_text_toolbar_underline') %>"
|
|
27
29
|
data-action="click->lato-cms-text-field#underline">
|
|
28
|
-
<i class="bi bi-type-underline"></i>
|
|
30
|
+
<i class="bi bi-type-underline" aria-hidden="true"></i>
|
|
29
31
|
</button>
|
|
30
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_strikethrough') %>"
|
|
32
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_strikethrough') %>" aria-label="<%= t('lato_cms.field_text_toolbar_strikethrough') %>"
|
|
31
33
|
data-action="click->lato-cms-text-field#strikethrough">
|
|
32
|
-
<i class="bi bi-type-strikethrough"></i>
|
|
34
|
+
<i class="bi bi-type-strikethrough" aria-hidden="true"></i>
|
|
33
35
|
</button>
|
|
34
36
|
<span class="vr mx-1"></span>
|
|
35
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_left') %>"
|
|
37
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_left') %>" aria-label="<%= t('lato_cms.field_text_toolbar_align_left') %>"
|
|
36
38
|
data-action="click->lato-cms-text-field#alignLeft">
|
|
37
|
-
<i class="bi bi-text-left"></i>
|
|
39
|
+
<i class="bi bi-text-left" aria-hidden="true"></i>
|
|
38
40
|
</button>
|
|
39
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_center') %>"
|
|
41
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_center') %>" aria-label="<%= t('lato_cms.field_text_toolbar_align_center') %>"
|
|
40
42
|
data-action="click->lato-cms-text-field#alignCenter">
|
|
41
|
-
<i class="bi bi-text-center"></i>
|
|
43
|
+
<i class="bi bi-text-center" aria-hidden="true"></i>
|
|
42
44
|
</button>
|
|
43
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_right') %>"
|
|
45
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_right') %>" aria-label="<%= t('lato_cms.field_text_toolbar_align_right') %>"
|
|
44
46
|
data-action="click->lato-cms-text-field#alignRight">
|
|
45
|
-
<i class="bi bi-text-right"></i>
|
|
47
|
+
<i class="bi bi-text-right" aria-hidden="true"></i>
|
|
46
48
|
</button>
|
|
47
49
|
<span class="vr mx-1"></span>
|
|
48
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_unordered_list') %>"
|
|
50
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_unordered_list') %>" aria-label="<%= t('lato_cms.field_text_toolbar_unordered_list') %>"
|
|
49
51
|
data-action="click->lato-cms-text-field#insertUnorderedList">
|
|
50
|
-
<i class="bi bi-list-ul"></i>
|
|
52
|
+
<i class="bi bi-list-ul" aria-hidden="true"></i>
|
|
51
53
|
</button>
|
|
52
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_ordered_list') %>"
|
|
54
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_ordered_list') %>" aria-label="<%= t('lato_cms.field_text_toolbar_ordered_list') %>"
|
|
53
55
|
data-action="click->lato-cms-text-field#insertOrderedList">
|
|
54
|
-
<i class="bi bi-list-ol"></i>
|
|
56
|
+
<i class="bi bi-list-ol" aria-hidden="true"></i>
|
|
55
57
|
</button>
|
|
56
58
|
|
|
57
59
|
<%# ── Source toggle ────────────────────────────────────────────────── %>
|
|
58
60
|
<span class="vr mx-1 ms-auto"></span>
|
|
59
|
-
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_toggle_html_source') %>"
|
|
61
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_toggle_html_source') %>" aria-label="<%= t('lato_cms.field_text_toolbar_toggle_html_source') %>"
|
|
60
62
|
data-action="click->lato-cms-text-field#toggleSource"
|
|
63
|
+
aria-pressed="false"
|
|
61
64
|
data-lato-cms-text-field-target="sourceBtn">
|
|
62
|
-
<i class="bi bi-code-slash"></i>
|
|
65
|
+
<i class="bi bi-code-slash" aria-hidden="true"></i>
|
|
63
66
|
</button>
|
|
64
67
|
</div>
|
|
65
68
|
|
|
66
69
|
<%# ── Editable area (WYSIWYG) ─────────────────────────────────────────── %>
|
|
67
70
|
<div class="form-control lato-cms-wysiwyg-editor rounded-0 rounded-bottom"
|
|
68
71
|
contenteditable="true"
|
|
72
|
+
id="<%= input_id %>_editor"
|
|
73
|
+
role="textbox"
|
|
74
|
+
aria-multiline="true"
|
|
75
|
+
aria-labelledby="<%= input_id %>_label"
|
|
76
|
+
<%= 'aria-required="true"'.html_safe if required %>
|
|
69
77
|
style="min-height: 150px; overflow-y: auto; line-height: 1.6;"
|
|
70
78
|
data-lato-cms-text-field-target="editor"><%= current_value.html_safe %></div>
|
|
71
79
|
|
|
@@ -73,6 +81,7 @@
|
|
|
73
81
|
<textarea class="form-control lato-cms-wysiwyg-source rounded-0 rounded-bottom font-monospace d-none"
|
|
74
82
|
style="min-height: 150px; font-size: 0.8rem; resize: vertical; white-space: pre;"
|
|
75
83
|
spellcheck="false"
|
|
84
|
+
aria-label="<%= label %> — <%= t('lato_cms.field_text_source_label') %>"
|
|
76
85
|
data-lato-cms-text-field-target="source"></textarea>
|
|
77
86
|
|
|
78
87
|
<%# ── Hidden input submitted with the form ───────────────────────────── %>
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
<% end %>
|
|
13
13
|
|
|
14
14
|
<div class="dropdown ms-auto" title="<%= t('lato_cms.cta_actions') %>" data-controller="lato-tooltip">
|
|
15
|
-
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown"
|
|
16
|
-
|
|
15
|
+
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"
|
|
16
|
+
aria-label="<%= t('lato_cms.cta_actions') %>">
|
|
17
|
+
<i class="bi bi-three-dots" aria-hidden="true"></i>
|
|
17
18
|
</button>
|
|
18
19
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
19
20
|
<li>
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
<%# h(): the title is user content and lato_page_head renders it raw. %>
|
|
2
|
+
<%= lato_page_head h(@page.title), [
|
|
2
3
|
{ label: t('lato_cms.pages_index_title'), path: lato_cms.pages_path },
|
|
3
4
|
{ label: @page.title }
|
|
4
5
|
] %>
|
|
5
6
|
|
|
6
|
-
<div data-controller="lato-cms-advanced-editor" data-lato-cms-advanced-editor-list-path-value="<%= lato_cms.pages_path %>"
|
|
7
|
+
<div data-controller="lato-cms-advanced-editor" data-lato-cms-advanced-editor-list-path-value="<%= lato_cms.pages_path %>"
|
|
8
|
+
data-lato-cms-advanced-editor-unsaved-message-value="<%= t('lato_cms.fields_unsaved_changes_confirm') %>">
|
|
7
9
|
<div class="row align-items-stretch lato-cms-advanced-editor__row lato-cms-advanced-editor__row--active">
|
|
8
10
|
|
|
9
11
|
<%# ── Preview column ─────────────────────────────────────────────────── %>
|
|
10
12
|
<div class="col-12 col-lg-6 mb-4 lato-cms-advanced-editor__preview-col">
|
|
11
|
-
<% if @page.
|
|
13
|
+
<% if (preview_url = @page.safe_frontend_url) %>
|
|
12
14
|
<div class="card h-100" style="overflow: hidden;" data-controller="lato-cms-page-preview">
|
|
13
15
|
<div class="card-header d-flex justify-content-between align-items-center py-2 gap-2">
|
|
14
|
-
<div class="btn-group btn-group-sm" role="group">
|
|
16
|
+
<div class="btn-group btn-group-sm" role="group" aria-label="<%= t('lato_cms.show_preview_devices_label') %>">
|
|
15
17
|
<button type="button" class="btn btn-outline-secondary active"
|
|
16
18
|
title="<%= t('lato_cms.show_preview_desktop_tooltip') %>"
|
|
19
|
+
aria-label="<%= t('lato_cms.show_preview_desktop_tooltip') %>"
|
|
20
|
+
aria-pressed="true"
|
|
17
21
|
data-controller="lato-tooltip"
|
|
18
22
|
data-action="click->lato-cms-page-preview#setDevice"
|
|
19
23
|
data-device="desktop"
|
|
@@ -22,6 +26,8 @@
|
|
|
22
26
|
</button>
|
|
23
27
|
<button type="button" class="btn btn-outline-secondary"
|
|
24
28
|
title="<%= t('lato_cms.show_preview_tablet_tooltip') %>"
|
|
29
|
+
aria-label="<%= t('lato_cms.show_preview_tablet_tooltip') %>"
|
|
30
|
+
aria-pressed="false"
|
|
25
31
|
data-controller="lato-tooltip"
|
|
26
32
|
data-action="click->lato-cms-page-preview#setDevice"
|
|
27
33
|
data-device="tablet"
|
|
@@ -30,6 +36,8 @@
|
|
|
30
36
|
</button>
|
|
31
37
|
<button type="button" class="btn btn-outline-secondary"
|
|
32
38
|
title="<%= t('lato_cms.show_preview_mobile_tooltip') %>"
|
|
39
|
+
aria-label="<%= t('lato_cms.show_preview_mobile_tooltip') %>"
|
|
40
|
+
aria-pressed="false"
|
|
33
41
|
data-controller="lato-tooltip"
|
|
34
42
|
data-action="click->lato-cms-page-preview#setDevice"
|
|
35
43
|
data-device="mobile"
|
|
@@ -40,6 +48,7 @@
|
|
|
40
48
|
<div class="d-flex align-items-center gap-2">
|
|
41
49
|
<div class="input-group input-group-sm" style="width: 130px;">
|
|
42
50
|
<input type="number" class="form-control" min="320" max="3840" step="1"
|
|
51
|
+
aria-label="<%= t('lato_cms.show_preview_custom_width_tooltip') %>"
|
|
43
52
|
placeholder="<%= t('lato_cms.show_preview_custom_width_placeholder') %>"
|
|
44
53
|
title="<%= t('lato_cms.show_preview_custom_width_tooltip') %>"
|
|
45
54
|
data-controller="lato-tooltip"
|
|
@@ -51,7 +60,13 @@
|
|
|
51
60
|
</div>
|
|
52
61
|
</div>
|
|
53
62
|
<div class="lato-cms-page-preview__viewport" data-lato-cms-page-preview-target="viewport">
|
|
54
|
-
|
|
63
|
+
<%# sandbox keeps the frontend from navigating the panel or opening
|
|
64
|
+
dialogs on it; scripts/same-origin stay on so the site renders
|
|
65
|
+
and the preview can postMessage the open component. %>
|
|
66
|
+
<iframe src="<%= preview_url %>" title="<%= t('lato_cms.show_preview_title') %>"
|
|
67
|
+
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
|
|
68
|
+
referrerpolicy="strict-origin-when-cross-origin"
|
|
69
|
+
data-lato-cms-page-preview-target="iframe"></iframe>
|
|
55
70
|
</div>
|
|
56
71
|
</div>
|
|
57
72
|
<% else %>
|
|
@@ -80,14 +95,15 @@
|
|
|
80
95
|
<span class="vr"></span>
|
|
81
96
|
<%= lato_cms_page_actions_dropdown(@page, show_edit: lato_cms_admin?, show_translations: lato_cms_admin?, show_delete: lato_cms_admin?, hide_show: true) %>
|
|
82
97
|
<span class="vr"></span>
|
|
83
|
-
<button class="btn btn-sm btn-outline-primary"
|
|
98
|
+
<button type="button" class="btn btn-sm btn-outline-primary"
|
|
84
99
|
title="<%= t('lato_cms.show_hide_panel_tooltip') %>"
|
|
100
|
+
aria-label="<%= t('lato_cms.show_hide_panel_tooltip') %>"
|
|
85
101
|
data-controller="lato-tooltip"
|
|
86
102
|
data-action="click->lato-cms-advanced-editor#toggleSidebar">
|
|
87
103
|
<i class="bi bi-layout-sidebar-reverse"></i>
|
|
88
104
|
</button>
|
|
89
105
|
<%= link_to lato_cms.pages_path, class: 'btn btn-sm btn-outline-danger',
|
|
90
|
-
title: t('lato_cms.show_back_to_list_tooltip'), data: { controller: 'lato-tooltip' } do %>
|
|
106
|
+
title: t('lato_cms.show_back_to_list_tooltip'), 'aria-label': t('lato_cms.show_back_to_list_tooltip'), data: { controller: 'lato-tooltip' } do %>
|
|
91
107
|
<i class="bi bi-box-arrow-left"></i>
|
|
92
108
|
<% end %>
|
|
93
109
|
</div>
|
|
@@ -106,7 +122,7 @@
|
|
|
106
122
|
<% elsif !@page.template_available? %>
|
|
107
123
|
<div class="alert alert-warning">
|
|
108
124
|
<i class="bi bi-exclamation-triangle me-1"></i>
|
|
109
|
-
<%= t('lato_cms.
|
|
125
|
+
<%= t('lato_cms.show_template_unavailable_html', template_id: @page.template_id) %>
|
|
110
126
|
<% if lato_cms_admin? %>
|
|
111
127
|
<%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-warning ms-2',
|
|
112
128
|
data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
|
|
@@ -137,9 +153,10 @@
|
|
|
137
153
|
</div>
|
|
138
154
|
|
|
139
155
|
<%# ── Re-open sidebar tab (visible only in advanced mode + sidebar closed) %>
|
|
140
|
-
<button class="lato-cms-advanced-editor__reopen-btn"
|
|
156
|
+
<button type="button" class="lato-cms-advanced-editor__reopen-btn"
|
|
141
157
|
hidden
|
|
142
158
|
title="<%= t('lato_cms.show_show_editor_panel_tooltip') %>"
|
|
159
|
+
aria-label="<%= t('lato_cms.show_show_editor_panel_tooltip') %>"
|
|
143
160
|
data-controller="lato-tooltip"
|
|
144
161
|
data-action="click->lato-cms-advanced-editor#toggleSidebar"
|
|
145
162
|
data-lato-cms-advanced-editor-target="reopenBtn">
|
data/config/locales/en.yml
CHANGED
|
@@ -63,7 +63,7 @@ en:
|
|
|
63
63
|
show_preview_custom_width_placeholder: Width
|
|
64
64
|
show_no_template_title: No template assigned
|
|
65
65
|
show_no_template_description: Assign a template to start editing fields.
|
|
66
|
-
|
|
66
|
+
show_template_unavailable_html: "The template <strong>%{template_id}</strong> is no longer available. Please assign a different template."
|
|
67
67
|
show_previously_saved_fields: "Previously saved fields:"
|
|
68
68
|
fields_component_not_found_badge: Component not found
|
|
69
69
|
component_required_badge: Required
|
|
@@ -162,3 +162,29 @@ en:
|
|
|
162
162
|
field_text_toolbar_unordered_list: Unordered list
|
|
163
163
|
field_text_toolbar_ordered_list: Ordered list
|
|
164
164
|
field_text_toolbar_toggle_html_source: Toggle HTML source
|
|
165
|
+
field_text_toolbar_label: Text formatting
|
|
166
|
+
field_text_source_label: HTML source
|
|
167
|
+
field_color_clear: Clear color
|
|
168
|
+
field_color_empty: No color
|
|
169
|
+
field_json_valid: Valid JSON
|
|
170
|
+
field_json_invalid: "Invalid JSON: %{error}"
|
|
171
|
+
field_render_error: "Field \"%{field_id}\" cannot be rendered. Check its configuration."
|
|
172
|
+
fields_saving: Saving...
|
|
173
|
+
fields_save_failed: Failed to save fields
|
|
174
|
+
fields_save_error: An error occurred while saving
|
|
175
|
+
fields_unsaved_changes_confirm: There are unsaved changes. Leave this page and lose them?
|
|
176
|
+
component_not_in_template: This component or one of its fields is not part of the page template
|
|
177
|
+
rate_limited: Too many requests, please wait a minute and try again.
|
|
178
|
+
cta_page_settings: Page settings
|
|
179
|
+
show_preview_title: Frontend preview
|
|
180
|
+
show_preview_devices_label: Preview size
|
|
181
|
+
form_template_change_warning: Fields saved under the current template are hidden if you switch template.
|
|
182
|
+
media_delete_confirm: Are you sure you want to delete this media?
|
|
183
|
+
media_content_type_not_allowed: "type %{content_type} is not allowed"
|
|
184
|
+
media_file_too_large: "is larger than the maximum size (%{size})"
|
|
185
|
+
media_search_label: Search media
|
|
186
|
+
media_search_cta: Search
|
|
187
|
+
media_move_before: Move before
|
|
188
|
+
media_move_after: Move after
|
|
189
|
+
media_field_select: "Select %{name}"
|
|
190
|
+
translation_select_label: "Page to link for %{locale}"
|
data/config/locales/it.yml
CHANGED
|
@@ -63,7 +63,7 @@ it:
|
|
|
63
63
|
show_preview_custom_width_placeholder: Larghezza
|
|
64
64
|
show_no_template_title: Nessun template assegnato
|
|
65
65
|
show_no_template_description: Assegna un template per iniziare a modificare i campi.
|
|
66
|
-
|
|
66
|
+
show_template_unavailable_html: "Il template <strong>%{template_id}</strong> non e piu disponibile. Assegna un template diverso."
|
|
67
67
|
show_previously_saved_fields: "Campi salvati in precedenza:"
|
|
68
68
|
fields_component_not_found_badge: Componente non trovato
|
|
69
69
|
component_required_badge: Obbligatoria
|
|
@@ -162,3 +162,29 @@ it:
|
|
|
162
162
|
field_text_toolbar_unordered_list: Elenco puntato
|
|
163
163
|
field_text_toolbar_ordered_list: Elenco numerato
|
|
164
164
|
field_text_toolbar_toggle_html_source: Mostra/nascondi sorgente HTML
|
|
165
|
+
field_text_toolbar_label: Formattazione testo
|
|
166
|
+
field_text_source_label: Sorgente HTML
|
|
167
|
+
field_color_clear: Rimuovi colore
|
|
168
|
+
field_color_empty: Nessun colore
|
|
169
|
+
field_json_valid: JSON valido
|
|
170
|
+
field_json_invalid: "JSON non valido: %{error}"
|
|
171
|
+
field_render_error: "Il campo \"%{field_id}\" non può essere mostrato. Controlla la sua configurazione."
|
|
172
|
+
fields_saving: Salvataggio...
|
|
173
|
+
fields_save_failed: Salvataggio dei campi non riuscito
|
|
174
|
+
fields_save_error: Si è verificato un errore durante il salvataggio
|
|
175
|
+
fields_unsaved_changes_confirm: Ci sono modifiche non salvate. Uscire dalla pagina e perderle?
|
|
176
|
+
component_not_in_template: Questo componente o uno dei suoi campi non fa parte del template della pagina
|
|
177
|
+
rate_limited: Troppe richieste, attendi un minuto e riprova.
|
|
178
|
+
cta_page_settings: Impostazioni pagina
|
|
179
|
+
show_preview_title: Anteprima del frontend
|
|
180
|
+
show_preview_devices_label: Dimensione anteprima
|
|
181
|
+
form_template_change_warning: Se cambi template, i campi salvati con quello attuale non vengono più mostrati.
|
|
182
|
+
media_delete_confirm: Sei sicuro di voler eliminare questo media?
|
|
183
|
+
media_content_type_not_allowed: "di tipo %{content_type} non è consentito"
|
|
184
|
+
media_file_too_large: "supera la dimensione massima (%{size})"
|
|
185
|
+
media_search_label: Cerca media
|
|
186
|
+
media_search_cta: Cerca
|
|
187
|
+
media_move_before: Sposta prima
|
|
188
|
+
media_move_after: Sposta dopo
|
|
189
|
+
media_field_select: "Seleziona %{name}"
|
|
190
|
+
translation_select_label: "Pagina da collegare per %{locale}"
|
data/lib/lato_cms/config.rb
CHANGED
|
@@ -5,7 +5,7 @@ module LatoCms
|
|
|
5
5
|
class Config
|
|
6
6
|
attr_accessor :locales, :templates_path, :admin_roles, :media_url_mode, :llm_api_url, :llm_model,
|
|
7
7
|
:llm_api_key, :llm_generate_alt_text, :llm_generate_title, :llm_alt_text_prompt,
|
|
8
|
-
:llm_title_prompt
|
|
8
|
+
:llm_title_prompt, :media_allowed_content_types, :media_max_file_size, :llm_max_image_size
|
|
9
9
|
|
|
10
10
|
# How the URLs of media files are built (see LatoCms::Media#url).
|
|
11
11
|
# - :redirect — Rails answers 302 with a signed URL that expires; on a
|
|
@@ -70,12 +70,37 @@ module LatoCms
|
|
|
70
70
|
# LLM_PROMPT_VARIABLES placeholders.
|
|
71
71
|
@llm_alt_text_prompt = nil
|
|
72
72
|
@llm_title_prompt = nil
|
|
73
|
+
|
|
74
|
+
# Server-side upload limits for the media library (the picker `accept`
|
|
75
|
+
# attribute is only a hint to the browser). Set either to nil to lift it.
|
|
76
|
+
@media_allowed_content_types = DEFAULT_MEDIA_ALLOWED_CONTENT_TYPES.dup
|
|
77
|
+
@media_max_file_size = 100.megabytes
|
|
78
|
+
|
|
79
|
+
# Images larger than this are not sent to the LLM: the whole file is
|
|
80
|
+
# read in memory and base64-encoded into the request.
|
|
81
|
+
@llm_max_image_size = 20.megabytes
|
|
73
82
|
end
|
|
74
83
|
|
|
84
|
+
# Media uploads accepted by default: images, audio, video, PDFs, plain
|
|
85
|
+
# text/CSV, office documents and zip archives. HTML and scripts are left
|
|
86
|
+
# out on purpose. A trailing `*` matches any subtype.
|
|
87
|
+
DEFAULT_MEDIA_ALLOWED_CONTENT_TYPES = %w[
|
|
88
|
+
image/* video/* audio/*
|
|
89
|
+
application/pdf text/plain text/csv application/zip
|
|
90
|
+
application/msword application/vnd.ms-excel application/vnd.ms-powerpoint
|
|
91
|
+
application/vnd.openxmlformats-officedocument.* application/vnd.oasis.opendocument.*
|
|
92
|
+
].freeze
|
|
93
|
+
|
|
75
94
|
def media_url_proxy?
|
|
76
95
|
media_url_mode.to_sym == :proxy
|
|
77
96
|
end
|
|
78
97
|
|
|
98
|
+
def media_content_type_allowed?(content_type)
|
|
99
|
+
return true if media_allowed_content_types.nil?
|
|
100
|
+
|
|
101
|
+
Array(media_allowed_content_types).any? { |pattern| File.fnmatch?(pattern.to_s, content_type.to_s) }
|
|
102
|
+
end
|
|
103
|
+
|
|
79
104
|
def llm_configured?
|
|
80
105
|
llm_api_url.present? && llm_model.present? && llm_api_key.present?
|
|
81
106
|
end
|
data/lib/lato_cms/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ namespace :lato_cms do
|
|
|
5
5
|
desc 'Install Lato CMS engine and create example templates'
|
|
6
6
|
# Usage: rails lato_cms:install:application
|
|
7
7
|
task application: :environment do
|
|
8
|
-
base_path = Rails.root.join(
|
|
8
|
+
base_path = Rails.root.join(LatoCms.config.templates_path)
|
|
9
9
|
templates_path = base_path.join('templates')
|
|
10
10
|
components_path = base_path.join('components')
|
|
11
11
|
|
|
@@ -34,10 +34,8 @@ namespace :lato_cms do
|
|
|
34
34
|
placeholder: "Enter a subtitle"
|
|
35
35
|
image:
|
|
36
36
|
name: Background Image
|
|
37
|
-
type:
|
|
37
|
+
type: image
|
|
38
38
|
required: false
|
|
39
|
-
settings:
|
|
40
|
-
accept: "image/*"
|
|
41
39
|
YAML
|
|
42
40
|
puts "Created #{component_file}"
|
|
43
41
|
else
|
|
@@ -105,17 +103,22 @@ namespace :lato_cms do
|
|
|
105
103
|
|
|
106
104
|
abort "Component file already exists: #{file}" if File.exist?(file)
|
|
107
105
|
|
|
108
|
-
|
|
106
|
+
# `custom` is left out: it needs a `render` partial path, which a
|
|
107
|
+
# field_id:type pair cannot carry (see the custom_field task).
|
|
108
|
+
valid_types = LatoCms::PagesHelper::BUILTIN_FIELD_TYPES
|
|
109
109
|
|
|
110
|
-
# Parse field pairs from extra args
|
|
110
|
+
# Parse field pairs from extra args. An unknown type aborts instead of
|
|
111
|
+
# silently becoming a string field.
|
|
111
112
|
fields = {}
|
|
112
113
|
(args.extras || []).each do |arg|
|
|
113
114
|
parts = arg.split(':')
|
|
114
|
-
|
|
115
|
+
abort "Invalid field definition \"#{arg}\": use field_id:type" unless parts.length == 2
|
|
115
116
|
|
|
116
117
|
field_id = parts[0].parameterize(separator: '_')
|
|
117
118
|
field_type = parts[1]
|
|
118
|
-
|
|
119
|
+
unless valid_types.include?(field_type)
|
|
120
|
+
abort "Unsupported field type \"#{field_type}\" for #{field_id}. Supported: #{valid_types.join(', ')}"
|
|
121
|
+
end
|
|
119
122
|
|
|
120
123
|
fields[field_id] = {
|
|
121
124
|
'name' => field_id.humanize,
|
|
@@ -155,20 +158,24 @@ namespace :lato_cms do
|
|
|
155
158
|
file = views_path.join("_#{field_id}.html.erb")
|
|
156
159
|
abort "Custom field partial already exists: #{file}" if File.exist?(file)
|
|
157
160
|
|
|
161
|
+
# Names and ids come from the engine helpers so the field also works
|
|
162
|
+
# inside a repeater (where both carry the item prefix).
|
|
158
163
|
File.write(file, <<~ERB)
|
|
159
164
|
<% label = field_config['name'] || field_id.humanize %>
|
|
160
165
|
<% required = field_config['required'] == true %>
|
|
161
166
|
<% settings = field_config['settings'] || {} %>
|
|
162
167
|
<% current_value = page_field&.value.to_s %>
|
|
168
|
+
<% input_name = lato_cms_field_input_name(field_id, input_name_prefix: local_assigns[:input_name_prefix]) %>
|
|
169
|
+
<% input_id = lato_cms_field_dom_id(field_id, dom_id_prefix: local_assigns[:dom_id_prefix]) %>
|
|
163
170
|
|
|
164
|
-
<label class="form-label" for="
|
|
171
|
+
<label class="form-label" for="<%= input_id %>">
|
|
165
172
|
<%= label %><%= ' *' if required %>
|
|
166
173
|
</label>
|
|
167
174
|
|
|
168
175
|
<input type="text"
|
|
169
176
|
class="form-control"
|
|
170
|
-
name="
|
|
171
|
-
id="
|
|
177
|
+
name="<%= input_name %>"
|
|
178
|
+
id="<%= input_id %>"
|
|
172
179
|
value="<%= current_value %>"
|
|
173
180
|
<%= 'required' if required %>
|
|
174
181
|
placeholder="<%= settings['placeholder'] %>">
|
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.
|
|
4
|
+
version: 3.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gregorio Galante
|
|
@@ -57,20 +57,6 @@ dependencies:
|
|
|
57
57
|
- - ">="
|
|
58
58
|
- !ruby/object:Gem::Version
|
|
59
59
|
version: 3.2.0
|
|
60
|
-
- !ruby/object:Gem::Dependency
|
|
61
|
-
name: jbuilder
|
|
62
|
-
requirement: !ruby/object:Gem::Requirement
|
|
63
|
-
requirements:
|
|
64
|
-
- - ">="
|
|
65
|
-
- !ruby/object:Gem::Version
|
|
66
|
-
version: '0'
|
|
67
|
-
type: :runtime
|
|
68
|
-
prerelease: false
|
|
69
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
70
|
-
requirements:
|
|
71
|
-
- - ">="
|
|
72
|
-
- !ruby/object:Gem::Version
|
|
73
|
-
version: '0'
|
|
74
60
|
- !ruby/object:Gem::Dependency
|
|
75
61
|
name: image_processing
|
|
76
62
|
requirement: !ruby/object:Gem::Requirement
|