alchemy_cms 8.1.12 → 8.2.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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -1
  3. data/app/assets/builds/alchemy/admin.css +1 -1
  4. data/app/assets/builds/alchemy/alchemy_admin.min.js +1 -1
  5. data/app/assets/builds/alchemy/alchemy_admin.min.js.map +1 -1
  6. data/app/assets/builds/alchemy/dark-theme.css +1 -1
  7. data/app/assets/builds/alchemy/light-theme.css +1 -1
  8. data/app/assets/builds/alchemy/theme.css +1 -1
  9. data/app/assets/builds/alchemy/welcome.css +1 -1
  10. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  11. data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -1
  12. data/app/assets/images/alchemy/icons-sprite.svg +1 -1
  13. data/app/components/alchemy/admin/current_user_name.rb +34 -0
  14. data/app/components/alchemy/admin/locale_select.rb +12 -8
  15. data/app/components/alchemy/admin/page_node.html.erb +3 -2
  16. data/app/components/alchemy/admin/picture_thumbnail.rb +1 -1
  17. data/app/components/alchemy/admin/preview_time_select.rb +55 -0
  18. data/app/components/alchemy/admin/publish_element_button.html.erb +41 -0
  19. data/app/components/alchemy/admin/publish_element_button.rb +13 -0
  20. data/app/components/alchemy/admin/timezone_select.rb +47 -0
  21. data/app/components/alchemy/ingredients/select_editor.rb +6 -1
  22. data/app/controllers/alchemy/admin/attachments_controller.rb +0 -9
  23. data/app/controllers/alchemy/admin/base_controller.rb +1 -0
  24. data/app/controllers/alchemy/admin/elements_controller.rb +54 -34
  25. data/app/controllers/alchemy/admin/pages_controller.rb +1 -0
  26. data/app/controllers/alchemy/admin/pictures_controller.rb +2 -23
  27. data/app/controllers/alchemy/admin/resources_controller.rb +11 -6
  28. data/app/controllers/alchemy/pages_controller.rb +1 -2
  29. data/app/helpers/alchemy/admin/base_helper.rb +4 -7
  30. data/app/helpers/alchemy/url_helper.rb +2 -10
  31. data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +28 -27
  32. data/app/javascript/alchemy_admin/components/element_editor.js +11 -2
  33. data/app/javascript/alchemy_admin/components/message.js +5 -1
  34. data/app/javascript/alchemy_admin/components/picture_thumbnail.js +1 -0
  35. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +5 -5
  36. data/app/javascript/alchemy_admin/image_cropper.js +10 -6
  37. data/app/javascript/alchemy_admin/initializer.js +6 -33
  38. data/app/javascript/alchemy_admin/shoelace_theme.js +6 -2
  39. data/app/javascript/alchemy_admin/templates/compiled.js +1 -1
  40. data/app/javascript/alchemy_admin.js +12 -2
  41. data/app/models/alchemy/attachment.rb +1 -33
  42. data/app/models/alchemy/current.rb +5 -1
  43. data/app/models/alchemy/element/element_ingredients.rb +11 -3
  44. data/app/models/alchemy/element.rb +10 -0
  45. data/app/models/alchemy/ingredient.rb +2 -0
  46. data/app/models/alchemy/ingredients/select.rb +1 -2
  47. data/app/models/alchemy/page/etag_generator.rb +21 -0
  48. data/app/models/alchemy/page/url_path.rb +11 -2
  49. data/app/models/alchemy/page.rb +12 -2
  50. data/app/models/alchemy/page_version.rb +5 -5
  51. data/app/models/alchemy/picture.rb +19 -2
  52. data/app/models/alchemy/storage_adapter/active_storage.rb +9 -0
  53. data/app/models/alchemy/storage_adapter/dragonfly.rb +9 -0
  54. data/app/models/alchemy/storage_adapter.rb +1 -0
  55. data/app/models/concerns/alchemy/publishable.rb +20 -12
  56. data/app/models/concerns/alchemy/relatable_resource.rb +19 -15
  57. data/app/models/concerns/alchemy/touch_elements.rb +3 -3
  58. data/app/services/alchemy/element_preloader.rb +107 -0
  59. data/app/stylesheets/alchemy/_custom-properties.scss +1 -0
  60. data/app/stylesheets/alchemy/_mixins.scss +1 -1
  61. data/app/stylesheets/alchemy/_themes.scss +2 -0
  62. data/app/stylesheets/alchemy/admin/archive.scss +2 -2
  63. data/app/stylesheets/alchemy/admin/base.scss +2 -1
  64. data/app/stylesheets/alchemy/admin/elements.scss +22 -19
  65. data/app/stylesheets/alchemy/admin/form_fields.scss +3 -0
  66. data/app/stylesheets/alchemy/admin/forms.scss +14 -1
  67. data/app/stylesheets/alchemy/admin/frame.scss +9 -8
  68. data/app/stylesheets/alchemy/admin/images.scss +2 -2
  69. data/app/stylesheets/alchemy/admin/notices.scss +1 -10
  70. data/app/stylesheets/alchemy/admin/popover.scss +37 -0
  71. data/app/stylesheets/alchemy/admin/selects.scss +4 -0
  72. data/app/stylesheets/alchemy/admin/shoelace.scss +16 -4
  73. data/app/stylesheets/alchemy/admin/toolbar.scss +8 -0
  74. data/app/stylesheets/alchemy/admin.scss +1 -0
  75. data/app/views/alchemy/admin/_header.html.erb +4 -0
  76. data/app/views/alchemy/admin/_left_menu.html.erb +24 -0
  77. data/app/views/alchemy/admin/_main_navi.html.erb +6 -0
  78. data/app/views/alchemy/admin/_top_menu.html.erb +6 -0
  79. data/app/views/alchemy/admin/_user_info.html.erb +5 -0
  80. data/app/views/alchemy/admin/attachments/_files_list.html.erb +1 -1
  81. data/app/views/alchemy/admin/crop.html.erb +6 -11
  82. data/app/views/alchemy/admin/elements/_header.html.erb +16 -6
  83. data/app/views/alchemy/admin/elements/_schedule.html.erb +62 -0
  84. data/app/views/alchemy/admin/elements/_toolbar.html.erb +1 -15
  85. data/app/views/alchemy/admin/elements/publish.turbo_stream.erb +28 -0
  86. data/app/views/alchemy/admin/nodes/index.html.erb +1 -1
  87. data/app/views/alchemy/admin/pages/_locked_pages.html.erb +5 -0
  88. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +4 -4
  89. data/app/views/alchemy/admin/pages/_table.html.erb +2 -2
  90. data/app/views/alchemy/admin/pages/edit.html.erb +6 -2
  91. data/app/views/alchemy/admin/partials/_language_tree_select.html.erb +10 -10
  92. data/app/views/alchemy/admin/partials/_site_select.html.erb +6 -3
  93. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +3 -3
  94. data/app/views/alchemy/admin/pictures/_picture.html.erb +1 -1
  95. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +1 -1
  96. data/app/views/alchemy/admin/pictures/index.html.erb +2 -2
  97. data/app/views/alchemy/admin/tinymce/_setup.html.erb +9 -16
  98. data/app/views/alchemy/admin/uploader/_setup.html.erb +1 -6
  99. data/app/views/alchemy/language_links/_language.html.erb +1 -2
  100. data/app/views/layouts/alchemy/admin.html.erb +2 -45
  101. data/config/importmap.rb +7 -2
  102. data/config/locales/alchemy.en.yml +35 -5
  103. data/lib/alchemy/admin/preview_time.rb +23 -0
  104. data/lib/alchemy/admin/preview_url.rb +13 -2
  105. data/lib/alchemy/admin/timezone.rb +56 -0
  106. data/lib/alchemy/configurations/main.rb +13 -1
  107. data/lib/alchemy/test_support/factories/element_factory.rb +2 -2
  108. data/lib/alchemy/test_support/relatable_resource_examples.rb +2 -2
  109. data/lib/alchemy/test_support/shared_publishable_examples.rb +44 -2
  110. data/lib/alchemy/upgrader.rb +3 -1
  111. data/lib/alchemy/version.rb +1 -1
  112. data/lib/alchemy_cms.rb +2 -0
  113. data/lib/generators/alchemy/install/install_generator.rb +2 -1
  114. data/vendor/javascript/handlebars.min.js +4 -4
  115. data/vendor/javascript/shoelace.min.js +1419 -1323
  116. data/vendor/javascript/sortable.min.js +2 -2
  117. data/vendor/javascript/tinymce.min.js +1 -1
  118. metadata +33 -1
@@ -260,11 +260,24 @@ form {
260
260
  }
261
261
 
262
262
  .submit {
263
+ display: flex;
263
264
  padding: var(--spacing-1) 0;
264
- text-align: right;
265
+ justify-content: space-between;
266
+
267
+ > button:last-of-type {
268
+ margin-left: auto;
269
+ }
270
+ }
271
+
272
+ &.simple_form {
273
+ .buttons {
274
+ margin-top: var(--spacing-1);
275
+ margin-left: var(--form-left-column-width);
276
+ }
265
277
  }
266
278
 
267
279
  .input-column {
280
+ width: 50%;
268
281
  padding: 0 var(--spacing-1);
269
282
 
270
283
  input[type] {
@@ -112,22 +112,23 @@ div#overlay_text_box {
112
112
  border-left: var(--border-default);
113
113
  white-space: nowrap;
114
114
  background-color: var(--toolbar-bg-color);
115
-
116
- select {
117
- background-color: transparent;
118
- border: none;
119
- border-radius: 0;
120
- border-left: var(--border-default);
121
- }
115
+ gap: var(--spacing-1);
122
116
 
123
117
  .current-user-name {
124
118
  display: flex;
125
119
  align-items: center;
126
120
  gap: var(--spacing-1);
127
- padding: 0 var(--spacing-3);
121
+ padding-left: var(--spacing-3);
128
122
 
129
123
  @media screen and (max-width: vars.$large-screen-break-point) {
130
124
  display: none;
131
125
  }
132
126
  }
133
127
  }
128
+
129
+ #admin_locale {
130
+ background-color: transparent;
131
+ border: none;
132
+ border-radius: 0;
133
+ border-left: var(--border-default);
134
+ }
@@ -1,11 +1,11 @@
1
1
  alchemy-picture-thumbnail {
2
2
  &[loading] {
3
- > img {
3
+ img {
4
4
  opacity: 0;
5
5
  }
6
6
  }
7
7
 
8
- > img {
8
+ img {
9
9
  opacity: 1;
10
10
  transition: opacity var(--transition-duration);
11
11
  }
@@ -11,7 +11,7 @@ alchemy-message {
11
11
  word-break: break-word;
12
12
  line-height: 1.5;
13
13
 
14
- turbo-frame & {
14
+ turbo-frame > & {
15
15
  margin: var(--spacing-2);
16
16
  }
17
17
 
@@ -73,15 +73,6 @@ alchemy-message {
73
73
  margin-top: 0;
74
74
  }
75
75
 
76
- h1,
77
- h2,
78
- h3,
79
- p {
80
- &:last-child {
81
- margin-bottom: 0;
82
- }
83
- }
84
-
85
76
  a[href] {
86
77
  text-decoration-color: inherit;
87
78
  text-decoration-thickness: 1px;
@@ -0,0 +1,37 @@
1
+ .alchemy-popover {
2
+ position: relative;
3
+ padding: var(--spacing-2);
4
+
5
+ alchemy-message {
6
+ margin-left: 0;
7
+ margin-right: 0;
8
+ margin-bottom: var(--spacing-3);
9
+ }
10
+
11
+ .timezone-select {
12
+ display: flex;
13
+ gap: var(--spacing-2);
14
+ align-items: center;
15
+
16
+ .alchemy_selectbox {
17
+ min-width: var(--select-x-large-width);
18
+ }
19
+ }
20
+
21
+ span.error {
22
+ display: block;
23
+ background-color: var(--notice-error-background-color);
24
+ color: var(--notice-error-text-color);
25
+ padding: var(--spacing-2);
26
+ border-radius: var(--border-radius_medium);
27
+ font-size: var(--font-size_small);
28
+ }
29
+
30
+ .submit {
31
+ gap: var(--spacing-2);
32
+
33
+ button {
34
+ width: 50%;
35
+ }
36
+ }
37
+ }
@@ -38,6 +38,10 @@ select {
38
38
  &.large {
39
39
  width: var(--select-large-width);
40
40
  }
41
+
42
+ &.x-large {
43
+ width: var(--select-x-large-width);
44
+ }
41
45
  }
42
46
 
43
47
  .select2-container {
@@ -106,9 +106,9 @@
106
106
  --sl-font-size-2x-small: 0.625rem; /* 10px */
107
107
  --sl-font-size-x-small: var(--font-size_small); /* 10px */
108
108
  --sl-font-size-small: var(--font-size_medium); /* 12px */
109
- --sl-font-size-medium: var(--font-size_large); /* 16px */
110
- --sl-font-size-large: 1.25rem; /* 20px */
111
- --sl-font-size-x-large: 1.5rem; /* 24px */
109
+ --sl-font-size-medium: var(--font-size_medium); /* 16px */
110
+ --sl-font-size-large: var(--font-size_medium); /* 20px */
111
+ --sl-font-size-x-large: var(--font-size_large); /* 24px */
112
112
  --sl-font-size-2x-large: 2.25rem; /* 36px */
113
113
  --sl-font-size-3x-large: 3rem; /* 48px */
114
114
  --sl-font-size-4x-large: 4.5rem; /* 72px */
@@ -285,6 +285,15 @@
285
285
  }
286
286
  }
287
287
 
288
+ sl-dropdown {
289
+ &::part(panel) {
290
+ background-color: var(--dialog-background-color);
291
+ box-shadow: none;
292
+ filter: drop-shadow(var(--dialog-box-shadow));
293
+ border: 1px solid var(--border-color);
294
+ }
295
+ }
296
+
288
297
  sl-tab-group {
289
298
  --indicator-color: var(--tabs_indicator-color);
290
299
  --track-color: var(--tabs_track-color);
@@ -326,6 +335,10 @@ sl-button {
326
335
  &[disabled]::part(base) {
327
336
  border-color: var(--button-disabled-border-color);
328
337
  }
338
+ &[variant="primary"]::part(base),
339
+ &[variant="default"]::part(base) {
340
+ --sl-color-neutral-0: var(--button-primary-text-color);
341
+ }
329
342
  }
330
343
 
331
344
  sl-dialog {
@@ -348,7 +361,6 @@ sl-dialog {
348
361
  }
349
362
 
350
363
  &::part(title) {
351
- --sl-font-size-large: var(--font-size_medium);
352
364
  color: var(--dialog-header-text-color);
353
365
  font-weight: var(--font-weight_bold);
354
366
  -webkit-font-smoothing: antialiased;
@@ -80,6 +80,14 @@
80
80
  margin-left: var(--spacing-1);
81
81
  }
82
82
 
83
+ #preview_time_select {
84
+ display: inline-flex;
85
+
86
+ select {
87
+ width: var(--select-x-large-width);
88
+ }
89
+ }
90
+
83
91
  #overlay_toolbar {
84
92
  @extend %gradiated-toolbar;
85
93
  }
@@ -29,6 +29,7 @@
29
29
  @use "admin/nodes";
30
30
  @use "admin/notices";
31
31
  @use "admin/pagination";
32
+ @use "admin/popover";
32
33
  @use "admin/preview_window";
33
34
  @use "admin/resource_info";
34
35
  @use "admin/search";
@@ -0,0 +1,4 @@
1
+ <div id="header">
2
+ <%= render "alchemy/admin/pages/locked_pages", locked_pages: locked_pages %>
3
+ <%= render "alchemy/admin/user_info" %>
4
+ </div>
@@ -0,0 +1,24 @@
1
+ <div id="left_menu">
2
+ <%= render "alchemy/admin/main_navi" %>
3
+
4
+ <div id="logout">
5
+ <div class="main_navi_entry">
6
+ <% if current_alchemy_user %>
7
+ <%= link_to_dialog(
8
+ %(
9
+ #{render_icon('logout-box-r', class: 'module')}
10
+ <label>#{Alchemy.t(:leave)}</label>
11
+ ).html_safe,
12
+ alchemy.leave_admin_path, {
13
+ size: "320x140",
14
+ title: Alchemy.t("Leave Alchemy")
15
+ }, {'data-alchemy-hotkey' => 'alt+q'}) %>
16
+ <% else %>
17
+ <%= link_to(alchemy.root_path) do %>
18
+ <%= render_icon "logout-box-r", size: "lg" %>
19
+ <label><%= Alchemy.t(:leave) %></label>
20
+ <% end %>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ </div>
@@ -0,0 +1,6 @@
1
+ <div id="main_navi">
2
+ <% sorted_alchemy_modules.each do |alchemy_module| %>
3
+ <%= alchemy_main_navigation_entry(alchemy_module) %>
4
+ <% end %>
5
+ <%= yield(:alchemy_main_navigation) %>
6
+ </div>
@@ -0,0 +1,6 @@
1
+ <div id="top_menu">
2
+ <%= render "alchemy/admin/header", locked_pages: locked_pages %>
3
+ <div id="toolbar">
4
+ <%= yield(:toolbar) %>
5
+ </div>
6
+ </div>
@@ -0,0 +1,5 @@
1
+ <div id="user_info">
2
+ <%= render Alchemy::Admin::CurrentUserName.new(user: current_alchemy_user) %>
3
+ <%= render Alchemy::Admin::TimezoneSelect.new %>
4
+ <%= render Alchemy::Admin::LocaleSelect.new %>
5
+ </div>
@@ -61,7 +61,7 @@
61
61
  file_attribute: 'file' %>
62
62
  <% end %>
63
63
  <% table.with_action(:destroy) do |attachment| %>
64
- <% if @deletable_attachment_ids.include?(attachment.id) %>
64
+ <% if attachment.deletable? %>
65
65
  <sl-tooltip content="<%= Alchemy.t(:delete_file) %>">
66
66
  <%= link_to_confirm_dialog render_icon(:minus),
67
67
  Alchemy.t(:confirm_to_delete_file),
@@ -18,19 +18,14 @@
18
18
  <% end %>
19
19
  <% if @settings %>
20
20
  <script type="module">
21
- import ImageCropper from "alchemy_admin/image_cropper";
21
+ import { ImageCropper } from "alchemy_admin/image_cropper";
22
22
 
23
23
  const image = document.getElementById("imageToCrop")?.querySelector("img");
24
24
 
25
- new ImageCropper(
26
- image,
27
- <%= @settings[:default_box].to_json %>,
28
- <%= @settings[:ratio] %>,
29
- [
30
- "<%= params[:crop_from_form_field_id] %>",
31
- "<%= params[:crop_size_form_field_id] %>",
32
- ],
33
- <%= @element.id %>
34
- );
25
+ new ImageCropper(image, <%== @settings.merge(
26
+ crop_from_form_field_id: params[:crop_from_form_field_id],
27
+ crop_size_form_field_id: params[:crop_size_form_field_id],
28
+ element_id: @element.id
29
+ ).to_json %>);
35
30
  </script>
36
31
  <% end %>
@@ -1,4 +1,4 @@
1
- <div class="element-header<%= ' has-hint' if element.has_hint? %>">
1
+ <div class="element-header<%= ' has-hint' if element.has_hint? %>" id="element-header-<%= element.id %>">
2
2
  <span class="element-handle<%= ' draggable' if can?(:order, element) %>">
3
3
  <% if element.definition.blank? %>
4
4
  <%= hint_with_tooltip Alchemy.t(:element_definition_missing), icon_class: "element-icon" %>
@@ -18,11 +18,21 @@
18
18
  <%= sanitize(element.preview_text.presence || '&nbsp;') %>
19
19
  </span>
20
20
  </span>
21
- <span class="element-hidden-icon">
22
- <%= render_icon("cloud-off", size: "1x") %>
23
- <span class="element-hidden-label">
24
- <%= Alchemy.t(:element_hidden) %>
25
- </span>
21
+ <span class="element-status-icons">
22
+ <% unless element.public? || element.scheduled? %>
23
+ <%= render_icon("cloud-off", size: "1x") %>
24
+ <span class="element-hidden-label">
25
+ <%= Alchemy.t(:element_hidden) %>
26
+ </span>
27
+ <% end %>
28
+ <sl-tooltip
29
+ class="element-scheduled-icon"
30
+ content="<%= Alchemy.t(element.public_on&.future? ? :public_on : :public_until, scope: :element_scheduled, public_on: element.public_on && l(element.public_on, format: :"alchemy.default"), public_until: element.public_until && l(element.public_until, format: :"alchemy.default")) %>"
31
+ <%= "hidden" if !element.scheduled? %>
32
+ >
33
+ <%= render_icon("calendar-schedule", size: "1x") %>
34
+ <%= element.public_on&.future? ? element.public_on && l(element.public_on, format: :"alchemy.short_datetime") : element.public_until && l(element.public_until, format: :"alchemy.short_datetime") %>
35
+ </sl-tooltip>
26
36
  </span>
27
37
  <sl-tooltip content="<%= Alchemy.t(element.folded? ? :show_element_content : :hide_element_content) %>">
28
38
  <%= button_tag(class: "element-toggle") do %>
@@ -0,0 +1,62 @@
1
+ <div id="element-<%= element.id %>-schedule">
2
+ <% if element.errors.any? %>
3
+ <alchemy-message type="error" icon="warn">
4
+ <%= Alchemy.t(:default_message, scope: "forms.error_notification") %>
5
+ </alchemy-message>
6
+ <% else %>
7
+ <alchemy-message type="info">
8
+ <% if element.public? %>
9
+ <p><%= sanitize t(".visibility_status.public_html") %></p>
10
+ <% if element.scheduled? && element.public_until.present? %>
11
+ <%= sanitize t(".public_scheduled_html",
12
+ public_until: l(element.public_until, format: :"alchemy.element_date")) %>
13
+ <% else %>
14
+ <%= t(".public_no_schedule") %>
15
+ <% end %>
16
+ <% else %>
17
+ <p><%= sanitize t(".visibility_status.hidden_html") %></p>
18
+ <% if element.scheduled? %>
19
+ <% if element.public_until.present? %>
20
+ <%= sanitize t(".hidden_window_html",
21
+ public_on: l(element.public_on, format: :"alchemy.element_date"),
22
+ public_until: l(element.public_until, format: :"alchemy.element_date")) %>
23
+ <% else %>
24
+ <%= sanitize t(".hidden_scheduled_html",
25
+ public_on: l(element.public_on, format: :"alchemy.element_date")) %>
26
+ <% end %>
27
+ <% else %>
28
+ <%= t(".hidden_no_schedule") %>
29
+ <% end %>
30
+ <% end %>
31
+ </alchemy-message>
32
+ <% end %>
33
+
34
+ <%= alchemy_form_for [:publish, :admin, element], remote: false, data: {turbo: true} do |f| %>
35
+ <div class="input">
36
+ <div class="input-row">
37
+ <div class="input-column">
38
+ <label for="element_public_on"><%= Alchemy::Element.human_attribute_name(:public_on) %></label>
39
+ <%= f.datetime_local_field :public_on, include_seconds: false %>
40
+ <%= f.error :public_on %>
41
+ </div>
42
+ <div class="input-column">
43
+ <label for="element_public_until"><%= Alchemy::Element.human_attribute_name(:public_until) %></label>
44
+ <%= f.datetime_local_field :public_until, include_seconds: false %>
45
+ <%= f.error :public_until %>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <div class="submit">
50
+ <button
51
+ type="button"
52
+ class="secondary"
53
+ onclick="this.form.querySelectorAll('input[type=datetime-local]').forEach((i) => i.value = '')">
54
+ <%= Alchemy.t(:clear_schedule) %>
55
+ </button>
56
+ <button type="submit">
57
+ <%= hidden_field_tag :alchemy_preview_time, params[:alchemy_preview_time] %>
58
+ <%= Alchemy.t(:save) %>
59
+ </button>
60
+ </div>
61
+ <% end %>
62
+ </div>
@@ -43,19 +43,5 @@
43
43
  </button>
44
44
  </alchemy-delete-element-button>
45
45
  </sl-tooltip>
46
- <sl-tooltip
47
- content="<%= element.public? ? Alchemy.t(:hide_element) : Alchemy.t(:show_element) %>"
48
- placement="top-end"
49
- <%= "disabled" if cannot?(:update, element) %>
50
- >
51
- <alchemy-publish-element-button>
52
- <sl-switch
53
- size="small"
54
- <%= "checked" if !element.public? %>
55
- <%= "disabled" if cannot?(:update, element) %>
56
- >
57
- <%= t(".hide") %>
58
- </sl-switch>
59
- </alchemy-publish-element-button>
60
- </sl-tooltip>
46
+ <%= render Alchemy::Admin::PublishElementButton.new(element:) %>
61
47
  </div>
@@ -0,0 +1,28 @@
1
+ <% if @element.errors.any? %>
2
+ <%= turbo_stream.replace "element-#{@element.id}-schedule",
3
+ partial: "schedule", locals: {element: @element} %>
4
+ <% else %>
5
+ <% if @element.scheduled? %>
6
+ <alchemy-growl>
7
+ <%= Alchemy.t(:successfully_scheduled_element) %>
8
+ </alchemy-growl>
9
+ <% end %>
10
+ <alchemy-action name="closeCurrentDialog"></alchemy-action>
11
+ <alchemy-action name="reloadPreview"></alchemy-action>
12
+ <%= turbo_stream.replace "element_#{@element.id}" do %>
13
+ <%= render Alchemy::Admin::ElementEditor.new(
14
+ element: @element
15
+ ) %>
16
+ <% end %>
17
+ <%= turbo_stream.replace "publish_page_button" do %>
18
+ <%= render Alchemy::Admin::PublishPageButton.new(
19
+ page: @element.page
20
+ ) %>
21
+ <% end %>
22
+ <%= turbo_stream.replace "preview_time_select" do %>
23
+ <%= render Alchemy::Admin::PreviewTimeSelect.new(
24
+ @element.page_version,
25
+ url: edit_admin_page_path(@element.page),
26
+ selected: params[:alchemy_preview_time]) %>
27
+ <% end %>
28
+ <% end %>
@@ -46,7 +46,7 @@
46
46
  </div>
47
47
 
48
48
  <script type="module">
49
- import NodeTree from "alchemy_admin/node_tree"
49
+ import { NodeTree } from "alchemy_admin/node_tree"
50
50
 
51
51
  NodeTree()
52
52
  </script>
@@ -0,0 +1,5 @@
1
+ <% if locked_pages.present? %>
2
+ <div id="locked_pages">
3
+ <%= render partial: 'alchemy/admin/pages/locked_page', collection: locked_pages %>
4
+ </div>
5
+ <% end %>
@@ -19,13 +19,13 @@
19
19
  'input-row'
20
20
  ] do %>
21
21
  <div class="input-column">
22
- <label><%= Alchemy::Page.human_attribute_name(:public_on) %></label>
23
- <%= alchemy_datepicker @page, :public_on, type: :datetime,
22
+ <%= label :page, :public_on %>
23
+ <%= datetime_local_field :page, :public_on, include_seconds: false,
24
24
  disabled: @page.attribute_fixed?(:public_on) %>
25
25
  </div>
26
26
  <div class="input-column">
27
- <label><%= Alchemy::Page.human_attribute_name(:public_until) %></label>
28
- <%= alchemy_datepicker @page, :public_until, type: :datetime,
27
+ <%= label :page, :public_until %>
28
+ <%= datetime_local_field :page, :public_until, include_seconds: false,
29
29
  disabled: @page.attribute_fixed?(:public_until) %>
30
30
  </div>
31
31
  <% end %>
@@ -6,7 +6,7 @@
6
6
  <%= render_icon "file-edit", size: "xl" %>
7
7
  </sl-tooltip>
8
8
  <% else %>
9
- <%= render_icon "file", size: "xl" %>
9
+ <%= render_icon "file-edit", size: "xl" %>
10
10
  <% end %>
11
11
  <% else %>
12
12
  <sl-tooltip class="like-hint-tooltip" content="<%= Alchemy.t("Your user role does not allow you to edit this page") %>" placement="bottom-start">
@@ -70,7 +70,7 @@
70
70
  alchemy.configure_admin_page_path(page, view: "list"),
71
71
  {
72
72
  title: Alchemy.t(:edit_page_properties),
73
- size: '450x680'
73
+ size: '530x680'
74
74
  },
75
75
  class: "icon_button"
76
76
  ) -%>
@@ -49,7 +49,7 @@
49
49
  alchemy.configure_admin_page_path(@page),
50
50
  {
51
51
  title: Alchemy.t(:page_properties),
52
- size: '500x680'
52
+ size: '530x680'
53
53
  },
54
54
  class: :icon_button,
55
55
  'data-alchemy-hotkey' => 'alt+e'
@@ -91,6 +91,10 @@
91
91
  </sl-tooltip>
92
92
  </div>
93
93
  <div class="toolbar_spacer"></div>
94
+ <%= render Alchemy::Admin::PreviewTimeSelect.new(
95
+ @page_version,
96
+ url: edit_admin_page_path(@page),
97
+ selected: params[:alchemy_preview_time]) %>
94
98
  <% if @preview_urls.many? %>
95
99
  <div class="select_with_label">
96
100
  <label><%= Alchemy.t(:preview_url) %></label>
@@ -132,7 +136,7 @@
132
136
  title="<%= Alchemy.t("Page preview") %>">
133
137
  </iframe>
134
138
 
135
- <%= turbo_frame_tag "alchemy_elements_window", src: alchemy.admin_elements_path(page_version_id: @page_version.id) do %>
139
+ <%= turbo_frame_tag "alchemy_elements_window", src: alchemy.admin_elements_path(page_version_id: @page_version.id, alchemy_preview_time: params[:alchemy_preview_time]) do %>
136
140
  <alchemy-spinner></alchemy-spinner>
137
141
  <% end %>
138
142
 
@@ -3,16 +3,16 @@
3
3
  <div class="toolbar_button">
4
4
  <sl-tooltip content="<%= Alchemy.t("Language tree") %>">
5
5
  <%= form_tag switch_admin_languages_path, method: 'get' do %>
6
- <%= select_tag(
7
- 'language_id',
8
- options_for_select(
9
- languages.map { |l| [l.name, l.id] },
10
- Alchemy::Current.language.id
11
- ),
12
- class: 'short',
13
- is: 'alchemy-select',
14
- data: {'auto-submit' => true}
15
- ) %>
6
+ <alchemy-auto-submit>
7
+ <%= select_tag(
8
+ :language_id,
9
+ options_for_select(
10
+ languages.map { |l| [l.name, l.id] },
11
+ Alchemy::Current.language.id
12
+ ),
13
+ class: "short"
14
+ ) %>
15
+ </alchemy-auto-submit>
16
16
  <% end %>
17
17
  </sl-tooltip>
18
18
  </div>
@@ -1,9 +1,12 @@
1
1
  <%- if multi_site? -%>
2
2
  <div class="toolbar_button">
3
3
  <sl-tooltip content="<%= Alchemy.t("Current site") %>">
4
- <%= select_tag 'change_site',
5
- options_for_select(sites_for_select, Alchemy::Current.site.id),
6
- is: 'alchemy-select' %>
4
+ <%= form_tag url_for, method: :get do %>
5
+ <alchemy-auto-submit>
6
+ <%= select_tag :site_id,
7
+ options_for_select(sites_for_select, Alchemy::Current.site.id) %>
8
+ </alchemy-auto-submit>
9
+ <% end %>
7
10
  </sl-tooltip>
8
11
  </div>
9
12
  <div class="toolbar_spacer"></div>
@@ -22,7 +22,7 @@
22
22
  search_filter_params.merge(
23
23
  size: "small",
24
24
  form_field_id: @form_field_id
25
- ).to_h
25
+ )
26
26
  ),
27
27
  class: "icon_button"
28
28
  ) %>
@@ -34,7 +34,7 @@
34
34
  search_filter_params.merge(
35
35
  size: "medium",
36
36
  form_field_id: @form_field_id
37
- ).to_h
37
+ )
38
38
  ),
39
39
  class: "icon_button"
40
40
  ) %>
@@ -46,7 +46,7 @@
46
46
  search_filter_params.merge(
47
47
  size: "large",
48
48
  form_field_id: @form_field_id
49
- ).to_h
49
+ )
50
50
  ),
51
51
  class: "icon_button"
52
52
  ) %>
@@ -2,7 +2,7 @@
2
2
  <span class="picture_tool select">
3
3
  <%= check_box_tag "picture_ids[]", picture.id %>
4
4
  </span>
5
- <% if @deletable_picture_ids.include?(picture.id) && can?(:destroy, picture) %>
5
+ <% if picture.deletable? && can?(:destroy, picture) %>
6
6
  <div class="picture_tool delete">
7
7
  <sl-tooltip content="<%= Alchemy.t('Delete image') %>">
8
8
  <%= link_to_confirm_dialog(
@@ -10,7 +10,7 @@
10
10
  onclick: '$(self).attr("href", "#").off("click"); return false',
11
11
  method: 'put',
12
12
  ) do %>
13
- <%= render Alchemy::Admin::PictureThumbnail.new(picture_to_assign, size: size) %>
13
+ <%= render Alchemy::Admin::PictureThumbnail.new(picture_to_assign) %>
14
14
  <% end %>
15
15
  </sl-tooltip>
16
16
  <% else %>
@@ -72,8 +72,8 @@
72
72
 
73
73
  <% content_for :javascripts do %>
74
74
  <script type="module">
75
- import ImageOverlay from "alchemy_admin/image_overlay";
76
- import pictureSelector from "alchemy_admin/picture_selector";
75
+ import { ImageOverlay } from "alchemy_admin/image_overlay";
76
+ import { pictureSelector } from "alchemy_admin/picture_selector";
77
77
  import { on } from "alchemy_admin/utils/events";
78
78
 
79
79
  pictureSelector();