lato_cms 3.0.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +6 -0
- data/app/assets/config/lato_cms_manifest.js +2 -0
- data/app/assets/javascripts/lato_cms/application.js +1 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_advanced_editor_controller.js +57 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_color_field_controller.js +9 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_component_accordion_controller.js +60 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_component_form_controller.js +96 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_component_toggle_controller.js +89 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_gallery_field_controller.js +136 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_image_field_controller.js +24 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_json_field_controller.js +27 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_page_preview_controller.js +86 -0
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_text_field_controller.js +74 -0
- data/app/assets/stylesheets/lato_cms/application.scss +252 -0
- data/app/controllers/lato_cms/api/pages_controller.rb +38 -0
- data/app/controllers/lato_cms/application_controller.rb +26 -0
- data/app/controllers/lato_cms/pages_controller.rb +194 -0
- data/app/helpers/lato_cms/application_helper.rb +4 -0
- data/app/helpers/lato_cms/pages_helper.rb +69 -0
- data/app/jobs/lato_cms/application_job.rb +4 -0
- data/app/mailers/lato_cms/application_mailer.rb +6 -0
- data/app/models/lato_cms/page.rb +133 -0
- data/app/models/lato_cms/page_field.rb +113 -0
- data/app/models/lato_cms/template_manager.rb +64 -0
- data/app/views/lato_cms/pages/_component_accordion.html.erb +97 -0
- data/app/views/lato_cms/pages/_fields_editor.html.erb +12 -0
- data/app/views/lato_cms/pages/_form_create.html.erb +26 -0
- data/app/views/lato_cms/pages/_form_update.html.erb +39 -0
- data/app/views/lato_cms/pages/create.html.erb +13 -0
- data/app/views/lato_cms/pages/fields/_boolean.html.erb +16 -0
- data/app/views/lato_cms/pages/fields/_color.html.erb +18 -0
- data/app/views/lato_cms/pages/fields/_date.html.erb +16 -0
- data/app/views/lato_cms/pages/fields/_datetime.html.erb +16 -0
- data/app/views/lato_cms/pages/fields/_file.html.erb +29 -0
- data/app/views/lato_cms/pages/fields/_gallery.html.erb +55 -0
- data/app/views/lato_cms/pages/fields/_image.html.erb +39 -0
- data/app/views/lato_cms/pages/fields/_json.html.erb +23 -0
- data/app/views/lato_cms/pages/fields/_multiselect.html.erb +25 -0
- data/app/views/lato_cms/pages/fields/_number.html.erb +18 -0
- data/app/views/lato_cms/pages/fields/_select.html.erb +23 -0
- data/app/views/lato_cms/pages/fields/_string.html.erb +18 -0
- data/app/views/lato_cms/pages/fields/_text.html.erb +80 -0
- data/app/views/lato_cms/pages/fields/_textarea.html.erb +16 -0
- data/app/views/lato_cms/pages/index.html.erb +32 -0
- data/app/views/lato_cms/pages/show.html.erb +105 -0
- data/app/views/lato_cms/pages/update.html.erb +13 -0
- data/config/importmap.rb +2 -0
- data/config/locales/en.yml +70 -0
- data/config/locales/it.yml +70 -0
- data/config/routes.rb +22 -0
- data/db/migrate/20250328072343_add_lato_cms_admin_to_lato_user.rb +5 -0
- data/db/migrate/20260320070819_create_lato_cms_pages.rb +13 -0
- data/db/migrate/20260323171241_create_lato_cms_page_fields.rb +13 -0
- data/lib/lato_cms/config.rb +13 -0
- data/lib/lato_cms/engine.rb +13 -0
- data/lib/lato_cms/version.rb +3 -0
- data/lib/lato_cms.rb +15 -0
- data/lib/tasks/lato_cms_tasks.rake +183 -0
- metadata +158 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% multiple = settings['multiple'] != false %>
|
|
5
|
+
<% accept = settings['accept'] %>
|
|
6
|
+
|
|
7
|
+
<label class="form-label">
|
|
8
|
+
<%= label %><%= ' *' if required %>
|
|
9
|
+
</label>
|
|
10
|
+
|
|
11
|
+
<% if page_field&.files&.attached? %>
|
|
12
|
+
<div class="mb-2">
|
|
13
|
+
<% page_field.files.each do |file| %>
|
|
14
|
+
<div class="form-check mb-1 p-2 ps-4 bg-light rounded">
|
|
15
|
+
<input type="checkbox" class="form-check-input" name="fields[<%= field_id %>][remove_file_ids][]" value="<%= file.id %>" id="remove_file_<%= file.id %>">
|
|
16
|
+
<label class="form-check-label small" for="remove_file_<%= file.id %>">
|
|
17
|
+
<i class="bi bi-paperclip me-1"></i><%= file.blob.filename %> (<%= number_to_human_size(file.blob.byte_size) %>) — <span class="text-danger"><%= t('lato_cms.field_file_remove') %></span>
|
|
18
|
+
</label>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<input type="file"
|
|
25
|
+
class="form-control"
|
|
26
|
+
name="fields[<%= field_id %>][files][]"
|
|
27
|
+
id="fields_<%= field_id %>_files"
|
|
28
|
+
<%= 'multiple' if multiple %>
|
|
29
|
+
<% if accept %>accept="<%= accept %>"<% end %>>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% accept = settings['accept'] || 'image/*' %>
|
|
5
|
+
|
|
6
|
+
<%# Build ordered file list from value JSON or default order %>
|
|
7
|
+
<% ordered_files = begin
|
|
8
|
+
if page_field&.files&.attached?
|
|
9
|
+
order = JSON.parse(page_field.value || '[]') rescue []
|
|
10
|
+
files = page_field.files.to_a
|
|
11
|
+
order.filter_map { |id| files.find { |f| f.id.to_s == id.to_s } } +
|
|
12
|
+
files.reject { |f| order.include?(f.id.to_s) }
|
|
13
|
+
else
|
|
14
|
+
[]
|
|
15
|
+
end
|
|
16
|
+
end %>
|
|
17
|
+
|
|
18
|
+
<label class="form-label">
|
|
19
|
+
<%= label %><%= ' *' if required %>
|
|
20
|
+
</label>
|
|
21
|
+
|
|
22
|
+
<div data-controller="lato-cms-gallery-field" data-lato-cms-gallery-field-field-id-value="<%= field_id %>">
|
|
23
|
+
<div class="lato-cms-gallery-field__grid mb-2"
|
|
24
|
+
data-lato-cms-gallery-field-target="grid"
|
|
25
|
+
data-action="dragover->lato-cms-gallery-field#onGridDragOver drop->lato-cms-gallery-field#onGridDrop">
|
|
26
|
+
<% ordered_files.each do |file| %>
|
|
27
|
+
<div class="lato-cms-gallery-field__item"
|
|
28
|
+
data-gallery-item
|
|
29
|
+
data-attachment-id="<%= file.id %>"
|
|
30
|
+
draggable="true"
|
|
31
|
+
data-action="dragstart->lato-cms-gallery-field#onDragStart dragend->lato-cms-gallery-field#onDragEnd">
|
|
32
|
+
<img src="<%= lato_cms_attachment_path(file) %>" class="lato-cms-gallery-field__thumb" alt="<%= file.filename %>">
|
|
33
|
+
<button type="button" class="lato-cms-gallery-field__remove" data-action="click->lato-cms-gallery-field#remove">
|
|
34
|
+
<i class="bi bi-x-lg"></i>
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<% if ordered_files.empty? %>
|
|
41
|
+
<p class="text-muted small mb-2" data-lato-cms-gallery-field-target="emptyMsg"><%= t('lato_cms.field_gallery_empty') %></p>
|
|
42
|
+
<% end %>
|
|
43
|
+
|
|
44
|
+
<label class="btn btn-sm btn-outline-secondary">
|
|
45
|
+
<i class="bi bi-plus-lg me-1"></i><%= t('lato_cms.field_gallery_add_images') %>
|
|
46
|
+
<input type="file"
|
|
47
|
+
class="d-none"
|
|
48
|
+
name="fields[<%= field_id %>][files][]"
|
|
49
|
+
accept="<%= accept %>"
|
|
50
|
+
multiple
|
|
51
|
+
data-lato-cms-gallery-field-target="fileInput"
|
|
52
|
+
data-action="change->lato-cms-gallery-field#addFiles">
|
|
53
|
+
</label>
|
|
54
|
+
<small class="text-muted ms-2"><%= t('lato_cms.field_gallery_drag_to_reorder') %></small>
|
|
55
|
+
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% accept = settings['accept'] || 'image/*' %>
|
|
5
|
+
<% current_file = page_field&.files&.attached? ? page_field.files.first : nil %>
|
|
6
|
+
|
|
7
|
+
<label class="form-label">
|
|
8
|
+
<%= label %><%= ' *' if required %>
|
|
9
|
+
</label>
|
|
10
|
+
|
|
11
|
+
<div data-controller="lato-cms-image-field">
|
|
12
|
+
<% if current_file %>
|
|
13
|
+
<div class="mb-2" data-lato-cms-image-field-target="currentContainer">
|
|
14
|
+
<div class="position-relative d-inline-block">
|
|
15
|
+
<img src="<%= lato_cms_attachment_path(current_file) %>" class="img-thumbnail lato-cms-image-field__thumb" data-lato-cms-image-field-target="currentImage" alt="<%= current_file.filename %>">
|
|
16
|
+
<label class="lato-cms-image-field__remove-btn" title="<%= t('lato_cms.field_image_remove') %>">
|
|
17
|
+
<input type="checkbox" class="d-none" name="fields[<%= field_id %>][remove_file_ids][]" value="<%= current_file.id %>" data-lato-cms-image-field-target="removeCheck" data-action="change->lato-cms-image-field#toggleRemove">
|
|
18
|
+
<i class="bi bi-x-lg"></i>
|
|
19
|
+
</label>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<div class="mb-2 d-none" data-lato-cms-image-field-target="newPreviewContainer">
|
|
25
|
+
<div class="position-relative d-inline-block">
|
|
26
|
+
<img src="" class="img-thumbnail lato-cms-image-field__thumb" data-lato-cms-image-field-target="newPreview" alt="">
|
|
27
|
+
<span class="badge bg-success lato-cms-image-field__new-badge"><%= t('lato_cms.field_image_new_badge') %></span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<input type="file"
|
|
32
|
+
class="form-control"
|
|
33
|
+
name="fields[<%= field_id %>][files][]"
|
|
34
|
+
id="fields_<%= field_id %>_files"
|
|
35
|
+
accept="<%= accept %>"
|
|
36
|
+
data-lato-cms-image-field-target="input"
|
|
37
|
+
data-action="change->lato-cms-image-field#preview"
|
|
38
|
+
<%= 'required' if required && !current_file %>>
|
|
39
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% current_value = page_field&.value || '' %>
|
|
5
|
+
<% if current_value.present? %>
|
|
6
|
+
<% begin; current_value = JSON.pretty_generate(JSON.parse(current_value)); rescue JSON::ParserError; end %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
10
|
+
<%= label %><%= ' *' if required %>
|
|
11
|
+
</label>
|
|
12
|
+
<div data-controller="lato-cms-json-field">
|
|
13
|
+
<textarea
|
|
14
|
+
class="form-control font-monospace"
|
|
15
|
+
name="fields[<%= field_id %>][value]"
|
|
16
|
+
id="fields_<%= field_id %>_value"
|
|
17
|
+
rows="<%= settings['rows'] || 6 %>"
|
|
18
|
+
data-lato-cms-json-field-target="input"
|
|
19
|
+
data-action="input->lato-cms-json-field#validate"
|
|
20
|
+
<%= 'required' if required %>
|
|
21
|
+
<% if settings['placeholder'] %>placeholder="<%= settings['placeholder'] %>"<% end %>><%= current_value %></textarea>
|
|
22
|
+
<div data-lato-cms-json-field-target="status" class="form-text"></div>
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% options = settings['options'] || [] %>
|
|
5
|
+
<% current_values = begin; page_field&.value.present? ? JSON.parse(page_field.value) : []; rescue; []; end %>
|
|
6
|
+
|
|
7
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
8
|
+
<%= label %><%= ' *' if required %>
|
|
9
|
+
</label>
|
|
10
|
+
<select
|
|
11
|
+
class="form-select"
|
|
12
|
+
name="fields[<%= field_id %>][value][]"
|
|
13
|
+
id="fields_<%= field_id %>_value"
|
|
14
|
+
multiple
|
|
15
|
+
size="<%= [options.length, 6].min %>"
|
|
16
|
+
<%= 'required' if required %>>
|
|
17
|
+
<% options.each do |option| %>
|
|
18
|
+
<% if option.is_a?(Hash) %>
|
|
19
|
+
<option value="<%= option['value'] %>" <%= 'selected' if current_values.include?(option['value'].to_s) %>><%= option['label'] %></option>
|
|
20
|
+
<% else %>
|
|
21
|
+
<option value="<%= option %>" <%= 'selected' if current_values.include?(option.to_s) %>><%= option %></option>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% end %>
|
|
24
|
+
</select>
|
|
25
|
+
<small class="form-text text-muted"><%= t('lato_cms.field_multiselect_hint') %></small>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% current_value = page_field&.value || '' %>
|
|
5
|
+
|
|
6
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
7
|
+
<%= label %><%= ' *' if required %>
|
|
8
|
+
</label>
|
|
9
|
+
<input type="number"
|
|
10
|
+
class="form-control"
|
|
11
|
+
name="fields[<%= field_id %>][value]"
|
|
12
|
+
id="fields_<%= field_id %>_value"
|
|
13
|
+
value="<%= current_value %>"
|
|
14
|
+
<%= 'required' if required %>
|
|
15
|
+
<% if settings['min'] %>min="<%= settings['min'] %>"<% end %>
|
|
16
|
+
<% if settings['max'] %>max="<%= settings['max'] %>"<% end %>
|
|
17
|
+
<% if settings['step'] %>step="<%= settings['step'] %>"<% end %>
|
|
18
|
+
<% if settings['placeholder'] %>placeholder="<%= settings['placeholder'] %>"<% end %>>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% options = settings['options'] || [] %>
|
|
5
|
+
<% current_value = page_field&.value || '' %>
|
|
6
|
+
|
|
7
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
8
|
+
<%= label %><%= ' *' if required %>
|
|
9
|
+
</label>
|
|
10
|
+
<select
|
|
11
|
+
class="form-select"
|
|
12
|
+
name="fields[<%= field_id %>][value]"
|
|
13
|
+
id="fields_<%= field_id %>_value"
|
|
14
|
+
<%= 'required' if required %>>
|
|
15
|
+
<option value=""><%= t('lato_cms.field_select_placeholder') %></option>
|
|
16
|
+
<% options.each do |option| %>
|
|
17
|
+
<% if option.is_a?(Hash) %>
|
|
18
|
+
<option value="<%= option['value'] %>" <%= 'selected' if current_value == option['value'].to_s %>><%= option['label'] %></option>
|
|
19
|
+
<% else %>
|
|
20
|
+
<option value="<%= option %>" <%= 'selected' if current_value == option.to_s %>><%= option %></option>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% end %>
|
|
23
|
+
</select>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% current_value = page_field&.value || '' %>
|
|
5
|
+
|
|
6
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
7
|
+
<%= label %><%= ' *' if required %>
|
|
8
|
+
</label>
|
|
9
|
+
<input type="text"
|
|
10
|
+
class="form-control"
|
|
11
|
+
name="fields[<%= field_id %>][value]"
|
|
12
|
+
id="fields_<%= field_id %>_value"
|
|
13
|
+
value="<%= current_value %>"
|
|
14
|
+
<%= 'required' if required %>
|
|
15
|
+
<% if settings['placeholder'] %>placeholder="<%= settings['placeholder'] %>"<% end %>
|
|
16
|
+
<% if settings['maxlength'] %>maxlength="<%= settings['maxlength'] %>"<% end %>
|
|
17
|
+
<% if settings['minlength'] %>minlength="<%= settings['minlength'] %>"<% end %>
|
|
18
|
+
<% if settings['pattern'] %>pattern="<%= settings['pattern'] %>"<% end %>>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% current_value = page_field&.value || '' %>
|
|
4
|
+
|
|
5
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
6
|
+
<%= label %><%= ' *' if required %>
|
|
7
|
+
</label>
|
|
8
|
+
|
|
9
|
+
<div data-controller="lato-cms-text-field">
|
|
10
|
+
|
|
11
|
+
<%# ── Toolbar ──────────────────────────────────────────────────────────── %>
|
|
12
|
+
<div 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"
|
|
13
|
+
data-lato-cms-text-field-target="toolbar">
|
|
14
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_bold') %>"
|
|
15
|
+
data-action="click->lato-cms-text-field#bold">
|
|
16
|
+
<i class="bi bi-type-bold"></i>
|
|
17
|
+
</button>
|
|
18
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_italic') %>"
|
|
19
|
+
data-action="click->lato-cms-text-field#italic">
|
|
20
|
+
<i class="bi bi-type-italic"></i>
|
|
21
|
+
</button>
|
|
22
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_underline') %>"
|
|
23
|
+
data-action="click->lato-cms-text-field#underline">
|
|
24
|
+
<i class="bi bi-type-underline"></i>
|
|
25
|
+
</button>
|
|
26
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_strikethrough') %>"
|
|
27
|
+
data-action="click->lato-cms-text-field#strikethrough">
|
|
28
|
+
<i class="bi bi-type-strikethrough"></i>
|
|
29
|
+
</button>
|
|
30
|
+
<span class="vr mx-1"></span>
|
|
31
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_left') %>"
|
|
32
|
+
data-action="click->lato-cms-text-field#alignLeft">
|
|
33
|
+
<i class="bi bi-text-left"></i>
|
|
34
|
+
</button>
|
|
35
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_center') %>"
|
|
36
|
+
data-action="click->lato-cms-text-field#alignCenter">
|
|
37
|
+
<i class="bi bi-text-center"></i>
|
|
38
|
+
</button>
|
|
39
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_align_right') %>"
|
|
40
|
+
data-action="click->lato-cms-text-field#alignRight">
|
|
41
|
+
<i class="bi bi-text-right"></i>
|
|
42
|
+
</button>
|
|
43
|
+
<span class="vr mx-1"></span>
|
|
44
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_unordered_list') %>"
|
|
45
|
+
data-action="click->lato-cms-text-field#insertUnorderedList">
|
|
46
|
+
<i class="bi bi-list-ul"></i>
|
|
47
|
+
</button>
|
|
48
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_ordered_list') %>"
|
|
49
|
+
data-action="click->lato-cms-text-field#insertOrderedList">
|
|
50
|
+
<i class="bi bi-list-ol"></i>
|
|
51
|
+
</button>
|
|
52
|
+
|
|
53
|
+
<%# ── Source toggle ────────────────────────────────────────────────── %>
|
|
54
|
+
<span class="vr mx-1 ms-auto"></span>
|
|
55
|
+
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1" title="<%= t('lato_cms.field_text_toolbar_toggle_html_source') %>"
|
|
56
|
+
data-action="click->lato-cms-text-field#toggleSource"
|
|
57
|
+
data-lato-cms-text-field-target="sourceBtn">
|
|
58
|
+
<i class="bi bi-code-slash"></i>
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<%# ── Editable area (WYSIWYG) ─────────────────────────────────────────── %>
|
|
63
|
+
<div class="form-control lato-cms-wysiwyg-editor rounded-0 rounded-bottom"
|
|
64
|
+
contenteditable="true"
|
|
65
|
+
style="min-height: 150px; overflow-y: auto; line-height: 1.6;"
|
|
66
|
+
data-lato-cms-text-field-target="editor"><%= current_value.html_safe %></div>
|
|
67
|
+
|
|
68
|
+
<%# ── Source view (raw HTML) ──────────────────────────────────────────── %>
|
|
69
|
+
<textarea class="form-control lato-cms-wysiwyg-source rounded-0 rounded-bottom font-monospace d-none"
|
|
70
|
+
style="min-height: 150px; font-size: 0.8rem; resize: vertical; white-space: pre;"
|
|
71
|
+
spellcheck="false"
|
|
72
|
+
data-lato-cms-text-field-target="source"></textarea>
|
|
73
|
+
|
|
74
|
+
<%# ── Hidden input submitted with the form ───────────────────────────── %>
|
|
75
|
+
<input type="hidden"
|
|
76
|
+
name="fields[<%= field_id %>][value]"
|
|
77
|
+
id="fields_<%= field_id %>_value"
|
|
78
|
+
data-lato-cms-text-field-target="input"
|
|
79
|
+
value="<%= CGI.escapeHTML(current_value) %>">
|
|
80
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% current_value = page_field&.value || '' %>
|
|
5
|
+
|
|
6
|
+
<label class="form-label" for="fields_<%= field_id %>_value">
|
|
7
|
+
<%= label %><%= ' *' if required %>
|
|
8
|
+
</label>
|
|
9
|
+
<textarea
|
|
10
|
+
class="form-control"
|
|
11
|
+
name="fields[<%= field_id %>][value]"
|
|
12
|
+
id="fields_<%= field_id %>_value"
|
|
13
|
+
rows="<%= settings['rows'] || 4 %>"
|
|
14
|
+
<%= 'required' if required %>
|
|
15
|
+
<% if settings['placeholder'] %>placeholder="<%= settings['placeholder'] %>"<% end %>
|
|
16
|
+
<% if settings['maxlength'] %>maxlength="<%= settings['maxlength'] %>"<% end %>><%= current_value %></textarea>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%= lato_page_head t('lato_cms.pages_index_title'), [{ label: t('lato_cms.pages_index_title') }] %>
|
|
2
|
+
|
|
3
|
+
<div class="card">
|
|
4
|
+
<div class="card-header d-flex gap-2">
|
|
5
|
+
<%= link_to lato_cms.pages_path, class: "btn btn-sm #{params[:locale].blank? ? 'btn-primary' : 'btn-outline-secondary'}" do %>
|
|
6
|
+
<i class="bi bi-globe me-1"></i><%= t('lato_cms.pages_filter_all') %>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% LatoCms.config.locales.each do |locale| %>
|
|
9
|
+
<%= link_to lato_cms.pages_path(locale: locale), class: "btn btn-sm #{params[:locale] == locale.to_s ? 'btn-primary' : 'btn-outline-secondary'}" do %>
|
|
10
|
+
<%= locale_to_flag(locale) %> <%= locale.to_s.upcase %>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="card-body">
|
|
15
|
+
<%= lato_index @pages,
|
|
16
|
+
custom_actions: {
|
|
17
|
+
create: {
|
|
18
|
+
path: lato_cms.pages_create_path,
|
|
19
|
+
icon: 'bi bi-plus',
|
|
20
|
+
title: t('lato_cms.page_create_cta'),
|
|
21
|
+
data: {
|
|
22
|
+
controller: 'lato-tooltip',
|
|
23
|
+
lato_action_target: 'trigger',
|
|
24
|
+
turbo_frame: dom_id(LatoCms::Page.new, 'form'),
|
|
25
|
+
action_title: t('lato_cms.page_create_title')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
pagination_options: [10, 20, 50, 100]
|
|
30
|
+
%>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<%= lato_page_head @page.title, [
|
|
2
|
+
{ label: t('lato_cms.pages_index_title'), path: lato_cms.pages_path },
|
|
3
|
+
{ label: @page.title }
|
|
4
|
+
] %>
|
|
5
|
+
|
|
6
|
+
<div data-controller="lato-cms-advanced-editor">
|
|
7
|
+
<div class="row align-items-stretch lato-cms-advanced-editor__row" data-lato-cms-advanced-editor-target="row">
|
|
8
|
+
|
|
9
|
+
<%# ── Preview column ─────────────────────────────────────────────────── %>
|
|
10
|
+
<div class="col-12 col-lg-6 mb-4 lato-cms-advanced-editor__preview-col" data-lato-cms-advanced-editor-target="previewCol">
|
|
11
|
+
<% if @page.frontend_url.present? %>
|
|
12
|
+
<div class="card h-100" style="overflow: hidden;" data-controller="lato-cms-page-preview">
|
|
13
|
+
<div class="card-body p-0">
|
|
14
|
+
<iframe src="<%= @page.frontend_url %>" data-lato-cms-page-preview-target="iframe" style="width: 100%; height: calc(100dvh - 180px); border: none; display: block;"></iframe>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<% else %>
|
|
18
|
+
<div class="card h-100">
|
|
19
|
+
<div class="card-body d-flex flex-column align-items-center justify-content-center text-muted" style="height: calc(100dvh - 180px);">
|
|
20
|
+
<i class="bi bi-globe fs-1 mb-3"></i>
|
|
21
|
+
<p class="mb-1"><%= t('lato_cms.show_no_preview_title') %></p>
|
|
22
|
+
<p class="small"><%= t('lato_cms.show_no_preview_description').html_safe %></p>
|
|
23
|
+
<%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
|
|
24
|
+
data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<%# ── Editor column ──────────────────────────────────────────────────── %>
|
|
31
|
+
<div class="col-12 col-lg-6 mb-4 lato-cms-advanced-editor__editor-col" data-lato-cms-advanced-editor-target="editorCol">
|
|
32
|
+
<div class="card h-100">
|
|
33
|
+
<div class="card-header d-flex justify-content-between align-items-center">
|
|
34
|
+
<h2 class="fs-5 mb-0"><%= t('lato_cms.show_editor_title') %></h2>
|
|
35
|
+
<div class="d-flex align-items-center gap-2">
|
|
36
|
+
<%= lato_cms_page_locale(@page) %>
|
|
37
|
+
<span class="vr"></span>
|
|
38
|
+
<%= lato_cms_page_actions(@page, show_edit: true, show_delete: true, hide_show: true) %>
|
|
39
|
+
<span class="vr"></span>
|
|
40
|
+
<button class="btn btn-sm btn-outline-secondary"
|
|
41
|
+
title="<%= t('lato_cms.show_advanced_editor_tooltip') %>"
|
|
42
|
+
data-controller="lato-tooltip"
|
|
43
|
+
data-action="click->lato-cms-advanced-editor#toggle"
|
|
44
|
+
data-lato-cms-advanced-editor-target="toggleBtn">
|
|
45
|
+
<i class="bi bi-fullscreen"></i>
|
|
46
|
+
</button>
|
|
47
|
+
<button class="btn btn-sm btn-outline-secondary d-none"
|
|
48
|
+
title="<%= t('lato_cms.show_hide_panel_tooltip') %>"
|
|
49
|
+
data-controller="lato-tooltip"
|
|
50
|
+
data-action="click->lato-cms-advanced-editor#toggleSidebar"
|
|
51
|
+
data-lato-cms-advanced-editor-target="collapseBtn">
|
|
52
|
+
<i class="bi bi-layout-sidebar-reverse"></i>
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="card-body" style="overflow-y: auto; max-height: calc(100dvh - 230px);">
|
|
57
|
+
<% if @page.template_id.blank? %>
|
|
58
|
+
<div class="text-center text-muted py-5">
|
|
59
|
+
<i class="bi bi-file-earmark-code fs-1 mb-3 d-block"></i>
|
|
60
|
+
<p class="mb-1"><%= t('lato_cms.show_no_template_title') %></p>
|
|
61
|
+
<p class="small"><%= t('lato_cms.show_no_template_description') %></p>
|
|
62
|
+
<%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-primary mt-2',
|
|
63
|
+
data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
|
|
64
|
+
</div>
|
|
65
|
+
<% elsif !@page.template_available? %>
|
|
66
|
+
<div class="alert alert-warning">
|
|
67
|
+
<i class="bi bi-exclamation-triangle me-1"></i>
|
|
68
|
+
<%= t('lato_cms.show_template_unavailable', template_id: @page.template_id) %>
|
|
69
|
+
<%= link_to t('lato_cms.show_edit_settings_cta'), lato_cms.pages_update_path(@page), class: 'btn btn-sm btn-outline-warning ms-2',
|
|
70
|
+
data: { lato_action_target: 'trigger', turbo_frame: dom_id(@page, 'form'), action_title: t('lato_cms.page_update_title') } %>
|
|
71
|
+
</div>
|
|
72
|
+
<% existing_fields = @page.fields.group_by(&:template_component_id) %>
|
|
73
|
+
<% if existing_fields.any? %>
|
|
74
|
+
<p class="text-muted small"><%= t('lato_cms.show_previously_saved_fields') %></p>
|
|
75
|
+
<% existing_fields.each do |tc_id, fields| %>
|
|
76
|
+
<div class="mb-3">
|
|
77
|
+
<h6 class="text-muted"><%= tc_id %></h6>
|
|
78
|
+
<% fields.each do |field| %>
|
|
79
|
+
<div class="mb-2 ps-3">
|
|
80
|
+
<small class="text-muted"><%= field.field_id %>:</small>
|
|
81
|
+
<span><%= field.value.present? ? field.value.truncate(100) : '-' %></span>
|
|
82
|
+
</div>
|
|
83
|
+
<% end %>
|
|
84
|
+
</div>
|
|
85
|
+
<% end %>
|
|
86
|
+
<% end %>
|
|
87
|
+
<% else %>
|
|
88
|
+
<%= render 'lato_cms/pages/fields_editor', page: @page, template_components: @template_components %>
|
|
89
|
+
<% end %>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<%# ── Re-open sidebar tab (visible only in advanced mode + sidebar closed) %>
|
|
97
|
+
<button class="lato-cms-advanced-editor__reopen-btn"
|
|
98
|
+
hidden
|
|
99
|
+
title="<%= t('lato_cms.show_show_editor_panel_tooltip') %>"
|
|
100
|
+
data-controller="lato-tooltip"
|
|
101
|
+
data-action="click->lato-cms-advanced-editor#toggleSidebar"
|
|
102
|
+
data-lato-cms-advanced-editor-target="reopenBtn">
|
|
103
|
+
<i class="bi bi-chevron-left"></i>
|
|
104
|
+
</button>
|
|
105
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<%= lato_page_head t('lato_cms.page_update_title'), [
|
|
2
|
+
{ label: t('lato_cms.pages_index_title'), path: lato_cms.pages_path },
|
|
3
|
+
{ label: t('lato_cms.page_update_title') }
|
|
4
|
+
] %>
|
|
5
|
+
|
|
6
|
+
<div class="card mb-4">
|
|
7
|
+
<div class="card-header">
|
|
8
|
+
<h2 class="fs-4 mb-0"><%= t('lato_cms.page_update_title') %></h2>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="card-body">
|
|
11
|
+
<%= render 'lato_cms/pages/form_update', page: @page %>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
data/config/importmap.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
en:
|
|
2
|
+
lato_cms:
|
|
3
|
+
cta_show: Show
|
|
4
|
+
cta_edit: Edit
|
|
5
|
+
cta_update: Update
|
|
6
|
+
cta_delete: Delete
|
|
7
|
+
cta_confirm: Confirm
|
|
8
|
+
cta_delete_confirm: Are you sure you want to delete this page?
|
|
9
|
+
page_created: Page created successfully
|
|
10
|
+
page_updated: Page updated successfully
|
|
11
|
+
fields_saved: Fields saved successfully
|
|
12
|
+
page_deleted: Page deleted successfully
|
|
13
|
+
unauthorized_section: You do not have access to this section.
|
|
14
|
+
page_delete_failed: Failed to delete page
|
|
15
|
+
api_page_not_found: Page not found
|
|
16
|
+
pages_index_title: Pages
|
|
17
|
+
pages_filter_all: All
|
|
18
|
+
page_create_title: New page
|
|
19
|
+
page_create_cta: Create
|
|
20
|
+
page_update_title: Edit page
|
|
21
|
+
form_frontend_url: Frontend URL
|
|
22
|
+
form_template: Template
|
|
23
|
+
form_no_template_option: "-- No template --"
|
|
24
|
+
form_template_unavailable: "The template \"%{template_id}\" is no longer available. Please select a different template."
|
|
25
|
+
action_view_frontend: View
|
|
26
|
+
show_no_preview_title: No preview available
|
|
27
|
+
show_no_preview_description: Set the <strong>Frontend URL</strong> to see the page preview.
|
|
28
|
+
show_edit_settings_cta: Edit page settings
|
|
29
|
+
show_editor_title: Editor
|
|
30
|
+
show_advanced_editor_tooltip: Advanced editor
|
|
31
|
+
show_hide_panel_tooltip: Hide panel
|
|
32
|
+
show_show_editor_panel_tooltip: Show editor panel
|
|
33
|
+
show_no_template_title: No template assigned
|
|
34
|
+
show_no_template_description: Assign a template to start editing fields.
|
|
35
|
+
show_template_unavailable: "The template <strong>%{template_id}</strong> is no longer available. Please assign a different template."
|
|
36
|
+
show_previously_saved_fields: "Previously saved fields:"
|
|
37
|
+
fields_component_not_found_badge: Component not found
|
|
38
|
+
component_required_badge: Required
|
|
39
|
+
component_disabled_badge: Disabled
|
|
40
|
+
component_enabled_label: Enabled
|
|
41
|
+
component_active_label: This component is active
|
|
42
|
+
component_inactive_label: This component is not active
|
|
43
|
+
component_disabled_alert: This component is disabled and will not be exposed by API.
|
|
44
|
+
component_state_updated: Component state updated
|
|
45
|
+
component_state_saving: Updating...
|
|
46
|
+
component_state_saved: State updated
|
|
47
|
+
component_state_save_error: Failed to update state
|
|
48
|
+
component_required_cannot_disable: Required component cannot be disabled
|
|
49
|
+
component_disabled_cannot_save: Disabled component cannot be saved
|
|
50
|
+
fields_save_component: Save
|
|
51
|
+
fields_component_missing_alert_html: "Component <strong>%{component_id}</strong> not found. The component configuration may have been removed."
|
|
52
|
+
fields_previously_saved_data: "Previously saved data:"
|
|
53
|
+
field_file_remove: Remove
|
|
54
|
+
field_gallery_empty: No images yet. Add images below.
|
|
55
|
+
field_gallery_add_images: Add images
|
|
56
|
+
field_gallery_drag_to_reorder: Drag to reorder
|
|
57
|
+
field_image_remove: Remove
|
|
58
|
+
field_image_new_badge: New
|
|
59
|
+
field_multiselect_hint: Hold Ctrl/Cmd to select multiple
|
|
60
|
+
field_select_placeholder: "-- Select --"
|
|
61
|
+
field_text_toolbar_bold: Bold
|
|
62
|
+
field_text_toolbar_italic: Italic
|
|
63
|
+
field_text_toolbar_underline: Underline
|
|
64
|
+
field_text_toolbar_strikethrough: Strikethrough
|
|
65
|
+
field_text_toolbar_align_left: Align left
|
|
66
|
+
field_text_toolbar_align_center: Align center
|
|
67
|
+
field_text_toolbar_align_right: Align right
|
|
68
|
+
field_text_toolbar_unordered_list: Unordered list
|
|
69
|
+
field_text_toolbar_ordered_list: Ordered list
|
|
70
|
+
field_text_toolbar_toggle_html_source: Toggle HTML source
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
it:
|
|
2
|
+
lato_cms:
|
|
3
|
+
cta_show: Visualizza
|
|
4
|
+
cta_edit: Modifica
|
|
5
|
+
cta_update: Aggiorna
|
|
6
|
+
cta_delete: Elimina
|
|
7
|
+
cta_confirm: Conferma
|
|
8
|
+
cta_delete_confirm: Sei sicuro di voler eliminare questa pagina?
|
|
9
|
+
page_created: Pagina creata con successo
|
|
10
|
+
page_updated: Pagina aggiornata con successo
|
|
11
|
+
fields_saved: Campi salvati con successo
|
|
12
|
+
page_deleted: Pagina eliminata con successo
|
|
13
|
+
unauthorized_section: Non hai accesso a questa sezione.
|
|
14
|
+
page_delete_failed: Impossibile eliminare la pagina
|
|
15
|
+
api_page_not_found: Pagina non trovata
|
|
16
|
+
pages_index_title: Pagine
|
|
17
|
+
pages_filter_all: Tutte
|
|
18
|
+
page_create_title: Nuova pagina
|
|
19
|
+
page_create_cta: Crea
|
|
20
|
+
page_update_title: Modifica pagina
|
|
21
|
+
form_frontend_url: URL Frontend
|
|
22
|
+
form_template: Template
|
|
23
|
+
form_no_template_option: "-- Nessun template --"
|
|
24
|
+
form_template_unavailable: "Il template \"%{template_id}\" non e piu disponibile. Seleziona un template diverso."
|
|
25
|
+
action_view_frontend: Anteprima
|
|
26
|
+
show_no_preview_title: Anteprima non disponibile
|
|
27
|
+
show_no_preview_description: Imposta il <strong>URL Frontend</strong> per visualizzare l'anteprima della pagina.
|
|
28
|
+
show_edit_settings_cta: Modifica impostazioni pagina
|
|
29
|
+
show_editor_title: Editor
|
|
30
|
+
show_advanced_editor_tooltip: Editor avanzato
|
|
31
|
+
show_hide_panel_tooltip: Nascondi pannello
|
|
32
|
+
show_show_editor_panel_tooltip: Mostra pannello editor
|
|
33
|
+
show_no_template_title: Nessun template assegnato
|
|
34
|
+
show_no_template_description: Assegna un template per iniziare a modificare i campi.
|
|
35
|
+
show_template_unavailable: "Il template <strong>%{template_id}</strong> non e piu disponibile. Assegna un template diverso."
|
|
36
|
+
show_previously_saved_fields: "Campi salvati in precedenza:"
|
|
37
|
+
fields_component_not_found_badge: Componente non trovato
|
|
38
|
+
component_required_badge: Obbligatoria
|
|
39
|
+
component_disabled_badge: Disattivata
|
|
40
|
+
component_enabled_label: Attiva
|
|
41
|
+
component_active_label: Questa componente e attiva
|
|
42
|
+
component_inactive_label: Questa componente non e attiva
|
|
43
|
+
component_disabled_alert: Questa componente e disattivata e non verra esposta dalle API.
|
|
44
|
+
component_state_updated: Stato componente aggiornato
|
|
45
|
+
component_state_saving: Aggiornamento in corso...
|
|
46
|
+
component_state_saved: Stato aggiornato
|
|
47
|
+
component_state_save_error: Errore durante aggiornamento stato
|
|
48
|
+
component_required_cannot_disable: Una componente obbligatoria non puo essere disattivata
|
|
49
|
+
component_disabled_cannot_save: Una componente disattivata non puo essere salvata
|
|
50
|
+
fields_save_component: Salva
|
|
51
|
+
fields_component_missing_alert_html: "Componente <strong>%{component_id}</strong> non trovato. La configurazione del componente potrebbe essere stata rimossa."
|
|
52
|
+
fields_previously_saved_data: "Dati salvati in precedenza:"
|
|
53
|
+
field_file_remove: Rimuovi
|
|
54
|
+
field_gallery_empty: Nessuna immagine presente. Aggiungi immagini qui sotto.
|
|
55
|
+
field_gallery_add_images: Aggiungi immagini
|
|
56
|
+
field_gallery_drag_to_reorder: Trascina per riordinare
|
|
57
|
+
field_image_remove: Rimuovi
|
|
58
|
+
field_image_new_badge: Nuovo
|
|
59
|
+
field_multiselect_hint: Tieni premuto Ctrl/Cmd per selezionare piu opzioni
|
|
60
|
+
field_select_placeholder: "-- Seleziona --"
|
|
61
|
+
field_text_toolbar_bold: Grassetto
|
|
62
|
+
field_text_toolbar_italic: Corsivo
|
|
63
|
+
field_text_toolbar_underline: Sottolineato
|
|
64
|
+
field_text_toolbar_strikethrough: Barrato
|
|
65
|
+
field_text_toolbar_align_left: Allinea a sinistra
|
|
66
|
+
field_text_toolbar_align_center: Allinea al centro
|
|
67
|
+
field_text_toolbar_align_right: Allinea a destra
|
|
68
|
+
field_text_toolbar_unordered_list: Elenco puntato
|
|
69
|
+
field_text_toolbar_ordered_list: Elenco numerato
|
|
70
|
+
field_text_toolbar_toggle_html_source: Mostra/nascondi sorgente HTML
|