alchemy_cms 7.2.5 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -4
  3. data/Gemfile +4 -3
  4. data/Rakefile +1 -0
  5. data/alchemy_cms.gemspec +7 -7
  6. data/app/assets/builds/alchemy/admin/print.css +1 -0
  7. data/app/assets/builds/alchemy/admin/print.css.map +1 -0
  8. data/app/assets/builds/alchemy/admin.css +1 -0
  9. data/app/assets/builds/alchemy/admin.css.map +1 -0
  10. data/app/assets/builds/alchemy/welcome.css +1 -0
  11. data/app/assets/builds/alchemy/welcome.css.map +1 -0
  12. data/app/assets/builds/tinymce/skins/content/alchemy/content.css +1 -0
  13. data/app/assets/builds/tinymce/skins/content/alchemy/content.css.map +1 -0
  14. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -0
  15. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +1 -0
  16. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.css +1 -0
  17. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.css.map +1 -0
  18. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -0
  19. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +1 -0
  20. data/app/assets/config/alchemy_manifest.js +1 -5
  21. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +4 -0
  22. data/app/assets/stylesheets/alchemy/{_custom-properties.scss → _custom-properties.css} +28 -25
  23. data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +41 -0
  24. data/app/assets/stylesheets/alchemy/_deprecation.scss +17 -0
  25. data/app/assets/stylesheets/alchemy/_extends.scss +1 -1
  26. data/app/assets/stylesheets/alchemy/_mixins.scss +20 -23
  27. data/app/assets/stylesheets/alchemy/_variables.scss +98 -94
  28. data/app/assets/stylesheets/alchemy/{archive.scss → admin/archive.scss} +23 -23
  29. data/app/assets/stylesheets/alchemy/{attachment-select.scss → admin/attachment-select.scss} +2 -2
  30. data/app/assets/stylesheets/alchemy/{attachments.scss → admin/attachments.scss} +4 -4
  31. data/app/assets/stylesheets/alchemy/{base.scss → admin/base.scss} +9 -9
  32. data/app/assets/stylesheets/alchemy/{buttons.scss → admin/buttons.scss} +3 -3
  33. data/app/assets/stylesheets/alchemy/{clipboard.scss → admin/clipboard.scss} +9 -6
  34. data/app/assets/stylesheets/alchemy/{dashboard.scss → admin/dashboard.scss} +8 -8
  35. data/app/assets/stylesheets/alchemy/{dialogs.scss → admin/dialogs.scss} +20 -20
  36. data/app/assets/stylesheets/alchemy/{elements.scss → admin/elements.scss} +128 -88
  37. data/app/assets/stylesheets/alchemy/{errors.scss → admin/errors.scss} +22 -6
  38. data/app/assets/stylesheets/alchemy/{flash.scss → admin/flash.scss} +3 -3
  39. data/app/assets/stylesheets/alchemy/{flatpickr.scss → admin/flatpickr.scss} +55 -35
  40. data/app/assets/stylesheets/alchemy/{form_fields.scss → admin/form_fields.scss} +8 -6
  41. data/app/assets/stylesheets/alchemy/{forms.scss → admin/forms.scss} +20 -16
  42. data/app/assets/stylesheets/alchemy/{frame.scss → admin/frame.scss} +9 -9
  43. data/app/assets/stylesheets/alchemy/{image_library.scss → admin/image_library.scss} +34 -33
  44. data/app/assets/stylesheets/alchemy/admin/labels.scss +3 -0
  45. data/app/assets/stylesheets/alchemy/{list_filter.scss → admin/list_filter.scss} +4 -4
  46. data/app/assets/stylesheets/alchemy/{lists.scss → admin/lists.scss} +9 -7
  47. data/app/assets/stylesheets/alchemy/{navigation.scss → admin/navigation.scss} +17 -17
  48. data/app/assets/stylesheets/alchemy/{node-select.scss → admin/node-select.scss} +5 -5
  49. data/app/assets/stylesheets/alchemy/{nodes.scss → admin/nodes.scss} +11 -11
  50. data/app/assets/stylesheets/alchemy/{notices.scss → admin/notices.scss} +11 -7
  51. data/app/assets/stylesheets/alchemy/{page-select.scss → admin/page-select.scss} +10 -10
  52. data/app/assets/stylesheets/alchemy/{pagination.scss → admin/pagination.scss} +10 -10
  53. data/app/assets/stylesheets/alchemy/{print.scss → admin/print.scss} +2 -6
  54. data/app/assets/stylesheets/alchemy/{resource_info.scss → admin/resource_info.scss} +6 -7
  55. data/app/assets/stylesheets/alchemy/{search.scss → admin/search.scss} +6 -6
  56. data/app/assets/stylesheets/alchemy/{selects.scss → admin/selects.scss} +46 -39
  57. data/app/assets/stylesheets/alchemy/{shoelace.scss → admin/shoelace.scss} +10 -10
  58. data/app/assets/stylesheets/alchemy/{sitemap.scss → admin/sitemap.scss} +18 -19
  59. data/app/assets/stylesheets/alchemy/{tables.scss → admin/tables.scss} +26 -22
  60. data/app/assets/stylesheets/alchemy/admin/tags.scss +158 -0
  61. data/app/assets/stylesheets/alchemy/{toolbar.scss → admin/toolbar.scss} +10 -10
  62. data/app/assets/stylesheets/alchemy/{typography.scss → admin/typography.scss} +3 -3
  63. data/app/assets/stylesheets/alchemy/{upload.scss → admin/upload.scss} +1 -1
  64. data/app/assets/stylesheets/alchemy/admin.scss +40 -45
  65. data/app/assets/stylesheets/alchemy/welcome.scss +57 -0
  66. data/app/assets/stylesheets/tinymce/skins/content/alchemy/{content.min.scss → content.scss} +5 -4
  67. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/{skin.min.scss → skin.scss} +40 -40
  68. data/app/components/alchemy/admin/resource/action.rb +46 -0
  69. data/app/components/alchemy/admin/resource/cell.rb +34 -0
  70. data/app/components/alchemy/admin/resource/header.rb +46 -0
  71. data/app/components/alchemy/admin/resource/table.rb +153 -0
  72. data/app/components/alchemy/ingredients/datetime_view.rb +2 -2
  73. data/app/controllers/alchemy/admin/base_controller.rb +2 -1
  74. data/app/controllers/alchemy/admin/elements_controller.rb +7 -3
  75. data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +1 -1
  76. data/app/controllers/alchemy/admin/pages_controller.rb +1 -1
  77. data/app/controllers/alchemy/admin/pictures_controller.rb +2 -2
  78. data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
  79. data/app/controllers/alchemy/base_controller.rb +2 -0
  80. data/app/controllers/alchemy/messages_controller.rb +1 -0
  81. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +2 -11
  82. data/app/decorators/alchemy/ingredient_editor.rb +17 -0
  83. data/app/helpers/alchemy/admin/pages_helper.rb +6 -10
  84. data/app/helpers/alchemy/base_helper.rb +2 -2
  85. data/app/helpers/alchemy/elements_block_helper.rb +13 -1
  86. data/app/helpers/alchemy/elements_helper.rb +1 -1
  87. data/app/helpers/alchemy/pages_helper.rb +2 -2
  88. data/app/javascript/alchemy_admin/components/element_editor.js +23 -31
  89. data/app/javascript/alchemy_admin/components/preview_window.js +2 -3
  90. data/app/javascript/alchemy_admin/picture_selector.js +38 -10
  91. data/app/models/alchemy/attachment.rb +0 -8
  92. data/app/models/alchemy/element/dom_id.rb +1 -0
  93. data/app/models/alchemy/element/element_ingredients.rb +0 -73
  94. data/app/models/alchemy/element/presenters.rb +4 -1
  95. data/app/models/alchemy/element.rb +6 -0
  96. data/app/models/alchemy/elements_repository.rb +2 -2
  97. data/app/models/alchemy/ingredient_validator.rb +10 -0
  98. data/app/models/alchemy/page/page_scopes.rb +1 -1
  99. data/app/models/alchemy/page.rb +3 -3
  100. data/app/models/alchemy/picture.rb +0 -10
  101. data/app/views/alchemy/admin/attachments/_files_list.html.erb +74 -16
  102. data/app/views/alchemy/admin/clipboard/index.html.erb +38 -33
  103. data/app/views/alchemy/admin/dashboard/_dashboard.html.erb +3 -0
  104. data/app/views/alchemy/admin/dashboard/_left_column.html.erb +4 -0
  105. data/app/views/alchemy/admin/dashboard/_right_column.html.erb +9 -0
  106. data/app/views/alchemy/admin/dashboard/_top.html.erb +12 -0
  107. data/app/views/alchemy/admin/dashboard/index.html.erb +1 -25
  108. data/app/views/alchemy/admin/elements/_element.html.erb +1 -2
  109. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  110. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +10 -3
  111. data/app/views/alchemy/admin/ingredients/update.turbo_stream.erb +7 -0
  112. data/app/views/alchemy/admin/languages/_table.html.erb +16 -42
  113. data/app/views/alchemy/admin/nodes/_form.html.erb +1 -1
  114. data/app/views/alchemy/admin/pages/_table.html.erb +92 -27
  115. data/app/views/alchemy/admin/pages/edit.html.erb +6 -8
  116. data/app/views/alchemy/admin/pages/index.html.erb +0 -4
  117. data/app/views/alchemy/admin/pictures/_form.html.erb +14 -12
  118. data/app/views/alchemy/admin/pictures/index.html.erb +1 -11
  119. data/app/views/alchemy/admin/pictures/update.turbo_stream.erb +6 -0
  120. data/app/views/alchemy/admin/resources/_resource_table.html.erb +3 -0
  121. data/app/views/alchemy/admin/resources/_table.html.erb +2 -0
  122. data/app/views/alchemy/admin/resources/index.html.erb +1 -1
  123. data/app/views/alchemy/admin/sites/index.html.erb +1 -1
  124. data/app/views/alchemy/admin/styleguide/index.html.erb +0 -4
  125. data/app/views/alchemy/admin/tags/index.html.erb +15 -14
  126. data/app/views/alchemy/base/403.html.erb +6 -0
  127. data/app/views/alchemy/base/500.html.erb +14 -12
  128. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +13 -11
  129. data/app/views/alchemy/ingredients/_headline_editor.html.erb +29 -22
  130. data/app/views/alchemy/ingredients/_link_editor.html.erb +17 -11
  131. data/app/views/alchemy/ingredients/_page_editor.html.erb +1 -0
  132. data/app/views/alchemy/ingredients/_picture_editor.html.erb +3 -4
  133. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +5 -1
  134. data/app/views/alchemy/ingredients/_select_editor.html.erb +2 -1
  135. data/app/views/alchemy/ingredients/_text_editor.html.erb +20 -14
  136. data/app/views/alchemy/ingredients/shared/_picture_css_class.html.erb +6 -0
  137. data/app/views/layouts/alchemy/admin.html.erb +4 -2
  138. data/bin/setup +2 -0
  139. data/bin/start +1 -1
  140. data/bun.lockb +0 -0
  141. data/config/alchemy/config.yml +9 -0
  142. data/config/locales/alchemy.en.yml +8 -29
  143. data/config/routes.rb +22 -22
  144. data/lib/alchemy/config.rb +3 -3
  145. data/lib/alchemy/install/tasks.rb +5 -2
  146. data/lib/alchemy/resources_helper.rb +3 -1
  147. data/lib/alchemy/test_support/capybara_helpers.rb +8 -5
  148. data/lib/alchemy/test_support/shared_uploader_examples.rb +0 -1
  149. data/lib/alchemy/upgrader/seven_point_three.rb +52 -0
  150. data/lib/alchemy/version.rb +1 -1
  151. data/lib/alchemy_cms.rb +1 -1
  152. data/lib/generators/alchemy/install/files/article.css +25 -0
  153. data/lib/generators/alchemy/install/files/custom.css +4 -0
  154. data/lib/generators/alchemy/install/install_generator.rb +6 -6
  155. data/lib/tasks/alchemy/upgrade.rake +29 -1
  156. data/vendor/assets/stylesheets/alchemy_admin/select2.css +1 -0
  157. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +2 -0
  158. data/vendor/javascript/shoelace.min.js +62 -63
  159. data/vendor/javascript/tinymce.min.js +1 -1
  160. metadata +132 -105
  161. data/app/assets/images/alchemy/lupe.cur +0 -0
  162. data/app/assets/stylesheets/alchemy/labels.scss +0 -3
  163. data/app/assets/stylesheets/alchemy/tags.scss +0 -155
  164. data/app/assets/stylesheets/alchemy/welcome.sass +0 -49
  165. data/app/views/alchemy/admin/attachments/_attachment.html.erb +0 -81
  166. data/app/views/alchemy/admin/languages/_language.html.erb +0 -50
  167. data/app/views/alchemy/admin/pages/_table_row.html.erb +0 -111
  168. data/app/views/alchemy/admin/pages/list/_table.html.erb +0 -31
  169. data/app/views/alchemy/admin/pictures/update.js.erb +0 -6
  170. data/app/views/alchemy/admin/tags/_tag.html.erb +0 -32
  171. data/app/views/alchemy/base/update.js.erb +0 -5
  172. data/lib/generators/alchemy/install/files/all.css +0 -11
  173. data/lib/generators/alchemy/install/files/article.scss +0 -30
  174. data/package.json +0 -52
  175. data/vendor/assets/stylesheets/alchemy_admin/select2.scss +0 -741
  176. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +0 -2
  177. /data/app/assets/stylesheets/alchemy/{fonts.scss → _fonts.scss} +0 -0
  178. /data/app/assets/stylesheets/alchemy/{hints.scss → admin/hints.scss} +0 -0
  179. /data/app/assets/stylesheets/alchemy/{icons.scss → admin/icons.scss} +0 -0
  180. /data/app/assets/stylesheets/alchemy/{images.scss → admin/images.scss} +0 -0
  181. /data/app/assets/stylesheets/alchemy/{preview_window.scss → admin/preview_window.scss} +0 -0
  182. /data/app/assets/stylesheets/alchemy/{spinner.scss → admin/spinner.scss} +0 -0
  183. /data/app/views/alchemy/admin/dashboard/{_locked_pages.html.erb → widgets/_locked_pages.html.erb} +0 -0
  184. /data/app/views/alchemy/admin/dashboard/{_recent_pages.html.erb → widgets/_recent_pages.html.erb} +0 -0
  185. /data/app/views/alchemy/admin/dashboard/{_sites.html.erb → widgets/_sites.html.erb} +0 -0
  186. /data/app/views/alchemy/admin/dashboard/{_users.html.erb → widgets/_users.html.erb} +0 -0
@@ -1,30 +1,95 @@
1
- <table class="list">
2
- <thead>
3
- <tr>
4
- <th class="icon"></th>
5
- <th class="string name">
6
- <%= sort_link [:alchemy, @query],
7
- "name",
8
- Alchemy::Page.human_attribute_name(:name),
9
- default_order: "asc" %>
10
- </th>
11
- <th><%= Alchemy::Page.human_attribute_name(:urlname) %></th>
12
- <th><%= Alchemy::Page.human_attribute_name(:page_type) %></th>
13
- <th><%= Alchemy::Page.human_attribute_name(:tag_list) %></th>
14
- <th>
15
- <%= sort_link [:alchemy, @query],
16
- :updated_at,
17
- Alchemy::Page.human_attribute_name(:updated_at),
18
- default_order: "desc" %>
19
- </th>
20
- <th class="status right"><%= Alchemy::Page.human_attribute_name(:status) %></th>
21
- <th class="tools"></th>
22
- </tr>
23
- </thead>
24
- <tbody>
25
- <%= render partial: "table_row", collection: @pages, as: "page" %>
26
- </tbody>
27
- </table>
1
+ <%= render Alchemy::Admin::Resource::Table.new(@pages, query: @query, search_filter_params: search_filter_params) do |table| %>
2
+ <% table.column :icon, header: "" do |page| %>
3
+ <% if can?(:edit_content, page) %>
4
+ <% if page.locked? %>
5
+ <sl-tooltip class="like-hint-tooltip" content="<%= Alchemy.t("This page is locked", name: page.locker_name) %>" placement="bottom-start">
6
+ <%= render_icon "file-edit", size: "xl" %>
7
+ </sl-tooltip>
8
+ <% else %>
9
+ <%= render_icon "file-edit", size: "xl" %>
10
+ <% end %>
11
+ <% else %>
12
+ <sl-tooltip class="like-hint-tooltip" content="<%= Alchemy.t("Your user role does not allow you to edit this page") %>" placement="bottom-start">
13
+ <%= render_icon "file-forbid", size: "xl" %>
14
+ </sl-tooltip>
15
+ <% end %>
16
+ <% end %>
17
+ <% table.column :name, sortable: true do |page| %>
18
+ <%= link_to_if(
19
+ can?(:edit_content, page),
20
+ page.name,
21
+ alchemy.edit_admin_page_path(page),
22
+ title: Alchemy.t(:edit_page),
23
+ ) { content_tag(:span, page.name) } -%>
24
+ <% end %>
25
+ <% table.column :url_path, header: Alchemy::Page.human_attribute_name(:urlname) %>
26
+ <% table.column :page_type do |page| %>
27
+ <%= Alchemy.t(page.page_layout, scope: "page_layout_names", default: page.page_layout.to_s.humanize) %>
28
+ <% end %>
29
+ <% table.column :tag_list, class_name: "tags" do |page| %>
30
+ <% page.tag_list.each do |tag| %>
31
+ <%= content_tag(:span, tag, class: "tag") %>
32
+ <% end %>
33
+ <% end %>
34
+ <% table.column :updated_at, sortable: true %>
35
+ <% table.column :status, class_name: :right do |page| %>
36
+ <% if page.locked? %>
37
+ <span class="page_status locked">
38
+ <%= render_icon(:edit, size: "1x") %>
39
+ <%= page.status_title(:locked) %>
40
+ </span>
41
+ <% end %>
42
+ <% if page.restricted? %>
43
+ <span class="page_status">
44
+ <%= render_icon(:lock, size: "1x") %>
45
+ <%= page.status_title(:restricted) %>
46
+ </span>
47
+ <% end %>
48
+ <% unless page.public? %>
49
+ <span class="page_status">
50
+ <%= render_icon("cloud-off", size: "1x") %>
51
+ <%= page.status_title(:public) %>
52
+ </span>
53
+ <% end %>
54
+ <% end %>
55
+
56
+ <% table.with_action :info, Alchemy.t(:page_infos) do |page| %>
57
+ <%= link_to_dialog(
58
+ render_icon('info-circle'),
59
+ alchemy.info_admin_page_path(page),
60
+ {
61
+ title: Alchemy.t(:page_infos),
62
+ size: '520x290'
63
+ },
64
+ class: "icon_button"
65
+ ) %>
66
+ <% end %>
67
+ <% table.with_action :configure, Alchemy.t(:edit_page_properties) do |page| %>
68
+ <%= link_to_dialog(
69
+ render_icon(:cog),
70
+ alchemy.configure_admin_page_path(page),
71
+ {
72
+ title: Alchemy.t(:edit_page_properties),
73
+ size: '450x680'
74
+ },
75
+ class: "icon_button"
76
+ ) -%>
77
+ <% end %>
78
+ <% table.with_action :copy, Alchemy.t(:copy_page) do |page| %>
79
+ <%= link_to(
80
+ render_icon(:copy),
81
+ alchemy.insert_admin_clipboard_path(
82
+ remarkable_type: :pages,
83
+ remarkable_id: page.id,
84
+ ),
85
+ remote: true,
86
+ method: :post,
87
+ class: "icon_button"
88
+ ) %>
89
+ <% end %>
90
+ <% table.delete_button tooltip: Alchemy.t(:delete_page), confirm_message: Alchemy.t(:confirm_to_delete_page) %>
91
+ <% end %>
92
+
28
93
 
29
94
  <script type="text/javascript">
30
95
  $(function() {
@@ -94,10 +94,12 @@
94
94
  <% end %>
95
95
  <div class="toolbar_spacer"></div>
96
96
  <div class="select_with_label">
97
- <label><%= Alchemy.t(:preview_size) %></label>
98
- <%= select_tag 'preview_size',
99
- preview_sizes_for_select,
100
- class: 'medium', is: 'alchemy-select' %>
97
+ <sl-tooltip content="<%= Alchemy.t(:preview_size) %>" placement="top-start">
98
+ <%= render_icon(:computer) %>
99
+ <%= select_tag "preview_size",
100
+ options_for_select(preview_sizes_for_select),
101
+ include_blank: Alchemy.t("auto", scope: "preview_sizes") %>
102
+ </sl-tooltip>
101
103
  </div>
102
104
  <div class="toolbar_spacer"></div>
103
105
  <% if @preview_urls.many? %>
@@ -129,10 +131,6 @@
129
131
  </div>
130
132
  <% end %>
131
133
 
132
- <% content_for :javascript_includes do %>
133
- <meta name="turbo-cache-control" content="no-cache">
134
- <% end %>
135
-
136
134
  <iframe
137
135
  url="<%= @preview_url %>"
138
136
  id="alchemy_preview_window"
@@ -1,7 +1,3 @@
1
- <% content_for :javascript_includes do %>
2
- <meta name="turbo-cache-control" content="no-cache">
3
- <% end %>
4
-
5
1
  <% content_for :toolbar do %>
6
2
  <%= render "alchemy/admin/pages/toolbar" %>
7
3
  <% end %>
@@ -1,14 +1,16 @@
1
- <%= alchemy_form_for [:admin, @picture] do |f| %>
2
- <%= f.input :name %>
3
- <%= render "picture_description_field", f: f %>
4
- <%= render Alchemy::Admin::TagsAutocomplete.new(additional_class: "input") do %>
5
- <%= f.label :tag_list %>
6
- <%= f.text_field :tag_list, value: f.object.tag_list.join(",") %>
7
- <small class="hint"><%= Alchemy.t('Please seperate the tags with commata') %></small>
1
+ <%= turbo_frame_tag(@picture) do %>
2
+ <%= alchemy_form_for [:admin, @picture] do |f| %>
3
+ <%= f.input :name %>
4
+ <%= render "picture_description_field", f: f %>
5
+ <%= render Alchemy::Admin::TagsAutocomplete.new(additional_class: "input") do %>
6
+ <%= f.label :tag_list %>
7
+ <%= f.text_field :tag_list, value: f.object.tag_list.join(",") %>
8
+ <small class="hint"><%= Alchemy.t('Please seperate the tags with commata') %></small>
9
+ <% end %>
10
+ <%= hidden_field_tag :q, search_filter_params[:q] %>
11
+ <%= hidden_field_tag :size, @size %>
12
+ <%= hidden_field_tag :tagged_with, search_filter_params[:tagged_with] %>
13
+ <%= hidden_field_tag :filter, search_filter_params[:filter] %>
14
+ <%= f.submit Alchemy.t(:save) %>
8
15
  <% end %>
9
- <%= hidden_field_tag :q, search_filter_params[:q] %>
10
- <%= hidden_field_tag :size, @size %>
11
- <%= hidden_field_tag :tagged_with, search_filter_params[:tagged_with] %>
12
- <%= hidden_field_tag :filter, search_filter_params[:filter] %>
13
- <%= f.submit Alchemy.t(:save) %>
14
16
  <% end %>
@@ -89,17 +89,7 @@
89
89
  <script type="text/javascript" charset="utf-8">
90
90
  $(function() {
91
91
  Alchemy.pictureSelector();
92
- $('#select_all_pictures').on('click', function(e) {
93
- $(this).toggleClass("active")
94
- $('.picture_tool.select :checkbox')
95
- .prop('checked', function(_i, val) { return !val })
96
- .closest(".picture_thumbnail")
97
- .toggleClass("active");
98
- e.preventDefault;
99
- $(".selected_item_tools").toggleClass("hidden")
100
- return false;
101
- });
102
- $('.thumbnail_background').on("click", function(event) {
92
+ $('#picture_archive').on("click", ".thumbnail_background", function(event) {
103
93
  var url = $(this).attr('href');
104
94
  var overlay = new Alchemy.ImageOverlay(url);
105
95
  overlay.open();
@@ -0,0 +1,6 @@
1
+ <alchemy-growl type=<%= @message[:type] %>>
2
+ <%= @message[:body] %>
3
+ </alchemy-growl>
4
+ <%= turbo_stream.replace("picture_#{@picture.id}") do %>
5
+ <%= render "picture", picture: @picture %>
6
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <%= render Alchemy::Admin::Resource::Table.new(resources_instance_variable, query: @query, search_filter_params: search_filter_params, icon: local_assigns[:icon]) %>
2
+
3
+ <%= paginate resources_instance_variable, scope: resource_url_proxy, theme: 'alchemy' %>
@@ -1,3 +1,5 @@
1
+ <% Alchemy::Deprecation.warn "The `alchemy/admin/resources/_table` partial is deprecated. Please `render 'alchemy/admin/resources/_resource_table'` instead and update it to your needs." %>
2
+
1
3
  <% if resources_instance_variable.any? %>
2
4
  <table class="list" id="<%= resource_handler.resources_name %>_list">
3
5
  <thead>
@@ -29,7 +29,7 @@
29
29
 
30
30
  <div id="archive_all" class="resources-table-wrapper<%= ' with_tag_filter' if resource_has_tags || resource_has_filters %>">
31
31
  <%= render 'alchemy/admin/resources/table_header' %>
32
- <%= render 'table' %>
32
+ <%= render 'resource_table' %>
33
33
 
34
34
  <% if resource_has_tags || resource_has_filters %>
35
35
  <div id="library_sidebar">
@@ -22,7 +22,7 @@
22
22
  <div id="archive_all" class="resources-table-wrapper">
23
23
  <% if @sites.any? %>
24
24
  <%= render 'alchemy/admin/resources/table_header' %>
25
- <%= render 'table', icon: "global" %>
25
+ <%= render 'alchemy/admin/resources/resource_table', icon: "global" %>
26
26
  <% elsif search_filter_params[:q].present? %>
27
27
  <%= render_message { Alchemy.t('Nothing found') } %>
28
28
  <% else %>
@@ -2,10 +2,6 @@
2
2
  <%= "Styleguide" %>
3
3
  <% end %>
4
4
 
5
- <% content_for :javascript_includes do %>
6
- <meta name="turbo-cache-control" content="no-cache">
7
- <% end %>
8
-
9
5
  <% content_for(:toolbar) do %>
10
6
  <%= render Alchemy::Admin::ToolbarButton.new(
11
7
  icon: :info,
@@ -21,20 +21,21 @@
21
21
  <%= render 'alchemy/admin/resources/table_header' %>
22
22
  <% if @tags.any? %>
23
23
 
24
- <table class="list">
25
- <thead>
26
- <tr>
27
- <th class="icon"></th>
28
- <th class="name"><%= sort_link(@query, :name) %></th>
29
- <th style="width: 15%"><%= Gutentag::Tag.human_attribute_name(:taggings_types) %></th>
30
- <th class="count"><%= sort_link(@query, :taggings_count) %></th>
31
- <th class="tools"></th>
32
- </tr>
33
- </thead>
34
- <tbody>
35
- <%= render partial: 'tag', collection: @tags %>
36
- </tbody>
37
- </table>
24
+ <%= render Alchemy::Admin::Resource::Table.new(@tags, query: @query, search_filter_params: search_filter_params) do |table| %>
25
+ <% table.icon_column "tag" %>
26
+ <% table.column :name, sortable: true %>
27
+ <% table.column :taggings_types do |tag| %>
28
+ <% tag.taggings.collect(&:taggable).compact.uniq(&:class).each do |taggable| %>
29
+ <span class="label">
30
+ <%= taggable.class.model_name.human %>
31
+ </span>
32
+ <% end %>
33
+ <% end %>
34
+ <% table.column :taggings_count, sortable: true, class_name: "count" %>
35
+
36
+ <% table.delete_button tooltip: Alchemy.t(:delete_tag), confirm_message: Alchemy.t(:do_you_really_want_to_delete_this_tag?) %>
37
+ <% table.edit_button tooltip: Alchemy.t(:edit_tag), dialog_size: "360x410" %>
38
+ <% end %>
38
39
 
39
40
  <%= paginate @tags, theme: 'alchemy' %>
40
41
 
@@ -0,0 +1,6 @@
1
+ <%= turbo_frame_tag request.headers["Turbo-Frame"] do %>
2
+ <%= render_message(:warning) do %>
3
+ <h1><%= Alchemy.t("You are not authorized.") %></h1>
4
+ <p><%= Alchemy.t("Your current user role is not permitted to access this resource.") %></p>
5
+ <% end %>
6
+ <% end %>
@@ -12,16 +12,18 @@
12
12
 
13
13
  <% content_for(:alchemy_body_class) { 'error' } %>
14
14
 
15
- <%= render_message(:error) do %>
16
- <h1><%= Alchemy.t('An error happened') %></h1>
17
- <h2>
18
- <%= @error.class %>
19
- <%= @notice %>
20
- </h2>
21
- <details>
22
- <summary><%= Alchemy.t('Show error details') %></summary>
23
- <% @trace.each do |line| %>
24
- <%= line %><br>
25
- <% end %>
26
- </details>
15
+ <%= turbo_frame_tag request.headers["Turbo-Frame"] do %>
16
+ <%= render_message(:error) do %>
17
+ <h1><%= Alchemy.t('An error happened') %></h1>
18
+ <h2>
19
+ <%= @error.class %>
20
+ <%= @notice %>
21
+ </h2>
22
+ <details>
23
+ <summary><%= Alchemy.t('Show error details') %></summary>
24
+ <% @trace.each do |line| %>
25
+ <%= line %><br>
26
+ <% end %>
27
+ </details>
28
+ <% end %>
27
29
  <% end %>
@@ -3,16 +3,18 @@
3
3
  data: datetime_editor.data_attributes do %>
4
4
  <%= element_form.fields_for(:ingredients, datetime_editor.ingredient) do |f| %>
5
5
  <%= ingredient_label(datetime_editor) %>
6
- <%= alchemy_datepicker(
7
- datetime_editor, :value, {
8
- name: datetime_editor.form_field_name,
9
- id: datetime_editor.form_field_id,
10
- value: datetime_editor.value,
11
- type: datetime_editor.settings[:input_type]
12
- }
13
- ) %>
6
+ <div class="input-field">
7
+ <%= alchemy_datepicker(
8
+ datetime_editor, :value, {
9
+ name: datetime_editor.form_field_name,
10
+ id: datetime_editor.form_field_id,
11
+ value: datetime_editor.value,
12
+ type: datetime_editor.settings[:input_type]
13
+ }
14
+ ) %>
15
+ <label for="<%= datetime_editor.form_field_id %>" class="ingredient-date--label">
16
+ <%= render_icon "calendar" %>
17
+ </label>
18
+ </div>
14
19
  <% end %>
15
- <label for="<%= datetime_editor.form_field_id %>" class="ingredient-date--label">
16
- <%= render_icon "calendar" %>
17
- </label>
18
20
  <% end %>
@@ -6,32 +6,39 @@
6
6
  data: headline_editor.data_attributes do %>
7
7
  <%= element_form.fields_for(:ingredients, headline_editor.ingredient) do |f| %>
8
8
  <%= ingredient_label(headline_editor) %>
9
- <%= f.text_field :value, id: headline_editor.form_field_id %>
10
9
 
11
- <% if headline_editor.settings[:anchor] %>
12
- <%= render "alchemy/ingredients/shared/anchor", ingredient_editor: headline_editor %>
13
- <% end %>
10
+ <div class="input-field">
11
+ <%= f.text_field :value,
12
+ minlength: headline_editor.length_validation&.fetch(:minimum, nil),
13
+ maxlength: headline_editor.length_validation&.fetch(:maximum, nil),
14
+ required: headline_editor.presence_validation?,
15
+ pattern: headline_editor.format_validation,
16
+ id: headline_editor.form_field_id %>
17
+ <% if headline_editor.settings[:anchor] %>
18
+ <%= render "alchemy/ingredients/shared/anchor", ingredient_editor: headline_editor %>
19
+ <% end %>
14
20
 
15
- <div class="input-addon right<%= " second" if has_size_select %>">
16
- <sl-tooltip content="<%= f.object.class.human_attribute_name(:level) %>">
17
- <%= f.select :level,
18
- options_for_select(headline_editor.level_options, headline_editor.level),
19
- {},
20
- {
21
- class: "custom-select",
22
- disabled: !has_level_select
23
- } %>
24
- </sl-tooltip>
25
- </div>
26
-
27
- <% if has_size_select %>
28
- <div class="input-addon right">
29
- <sl-tooltip content="<%= f.object.class.human_attribute_name(:size) %>">
30
- <%= f.select :size, options_for_select(headline_editor.size_options, headline_editor.size),
21
+ <div class="input-addon right<%= " second" if has_size_select %>">
22
+ <sl-tooltip content="<%= f.object.class.human_attribute_name(:level) %>">
23
+ <%= f.select :level,
24
+ options_for_select(headline_editor.level_options, headline_editor.level),
31
25
  {},
32
- { class: "custom-select" } %>
26
+ {
27
+ class: "custom-select",
28
+ disabled: !has_level_select
29
+ } %>
33
30
  </sl-tooltip>
34
31
  </div>
35
- <% end %>
32
+
33
+ <% if has_size_select %>
34
+ <div class="input-addon right">
35
+ <sl-tooltip content="<%= f.object.class.human_attribute_name(:size) %>">
36
+ <%= f.select :size, options_for_select(headline_editor.size_options, headline_editor.size),
37
+ {},
38
+ { class: "custom-select" } %>
39
+ </sl-tooltip>
40
+ </div>
41
+ <% end %>
42
+ </div>
36
43
  <% end %>
37
44
  <% end %>
@@ -3,18 +3,24 @@
3
3
  data: link_editor.data_attributes do %>
4
4
  <%= element_form.fields_for(:ingredients, link_editor.ingredient) do |f| %>
5
5
  <%= ingredient_label(link_editor) %>
6
- <%= f.text_field :value,
7
- class: "thin_border text_with_icon readonly",
8
- id: link_editor.form_field_id,
9
- "data-link-value": true,
10
- readonly: true,
11
- tabindex: -1
12
- %>
13
- <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
14
- <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
15
- <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
6
+ <div class="input-field">
7
+ <%= f.text_field :value,
8
+ class: "thin_border text_with_icon readonly",
9
+ id: link_editor.form_field_id,
10
+ "data-link-value": true,
11
+ minlength: link_editor.length_validation&.fetch(:minimum, nil),
12
+ maxlength: link_editor.length_validation&.fetch(:maximum, nil),
13
+ required: link_editor.presence_validation?,
14
+ pattern: link_editor.format_validation,
15
+ readonly: true,
16
+ tabindex: -1
17
+ %>
18
+ <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
19
+ <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
20
+ <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
21
+ <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: link_editor, wrapper_class: "ingredient_link_buttons" %>
22
+ </div>
16
23
  <% end %>
17
- <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: link_editor, wrapper_class: "ingredient_link_buttons" %>
18
24
  <% end %>
19
25
 
20
26
  <script>
@@ -7,6 +7,7 @@
7
7
  <%= f.text_field :page_id,
8
8
  value: page_editor.page&.id,
9
9
  id: page_editor.form_field_id(:page_id),
10
+ required: page_editor.presence_validation?,
10
11
  class: 'full_width' %>
11
12
  <% end %>
12
13
  <% end %>
@@ -32,10 +32,9 @@
32
32
  </div>
33
33
  </div>
34
34
  <%- if picture_editor.css_class.present? -%>
35
- <div class="picture_ingredient_css_class">
36
- <%= Alchemy.t("alchemy.picture_ingredients.css_classes.#{picture_editor.css_class}",
37
- default: picture_editor.css_class.camelcase) %>
38
- </div>
35
+ <%= render "alchemy/ingredients/shared/picture_css_class", {
36
+ css_class: picture_editor.css_class
37
+ } %>
39
38
  <%- end -%>
40
39
  <div class="edit_images_bottom">
41
40
  <%= render "alchemy/ingredients/shared/picture_tools", {
@@ -6,7 +6,11 @@
6
6
 
7
7
  <%- custom_tinymce_config = richtext_editor.custom_tinymce_config.inject({}) { |obj, (k, v)| obj[k.to_s.dasherize] = v.to_json; obj} %>
8
8
  <%= content_tag("alchemy-tinymce", custom_tinymce_config) do %>
9
- <%= f.text_area :value, id: richtext_editor.form_field_id(:value) %>
9
+ <%= f.text_area :value,
10
+ minlength: richtext_editor.length_validation&.fetch(:minimum, nil),
11
+ maxlength: richtext_editor.length_validation&.fetch(:maximum, nil),
12
+ required: richtext_editor.presence_validation?,
13
+ id: richtext_editor.form_field_id(:value) %>
10
14
  <% end %>
11
15
  <% end %>
12
16
  <% end %>
@@ -24,7 +24,8 @@
24
24
  <%= f.select :value, options_tags, {}, {
25
25
  id: select_editor.form_field_id,
26
26
  class: ["ingredient-editor-select"],
27
- is: "alchemy-select"
27
+ is: "alchemy-select",
28
+ required: select_editor.presence_validation?
28
29
  } %>
29
30
  <% end %>
30
31
  <% end %>
@@ -5,19 +5,25 @@
5
5
  ], data: text_editor.data_attributes do %>
6
6
  <%= element_form.fields_for(:ingredients, text_editor.ingredient) do |f| %>
7
7
  <%= ingredient_label(text_editor) %>
8
- <%= f.text_field :value,
9
- class: text_editor.settings[:linkable] ? "text_with_icon" : "",
10
- id: text_editor.form_field_id,
11
- type: text_editor.settings[:input_type] || "text" %>
12
- <% if text_editor.settings[:anchor] %>
13
- <%= render "alchemy/ingredients/shared/anchor", ingredient_editor: text_editor %>
14
- <% end %>
15
- <% if text_editor.settings[:linkable] %>
16
- <%= f.hidden_field :link, "data-link-value": true, id: nil %>
17
- <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
18
- <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
19
- <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
20
- <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: text_editor, wrapper_class: "ingredient_link_buttons" %>
21
- <% end %>
8
+ <div class="input-field">
9
+ <%= f.text_field :value,
10
+ class: text_editor.settings[:linkable] ? "text_with_icon" : "",
11
+ id: text_editor.form_field_id,
12
+ minlength: text_editor.length_validation&.fetch(:minimum, nil),
13
+ maxlength: text_editor.length_validation&.fetch(:maximum, nil),
14
+ required: text_editor.presence_validation?,
15
+ pattern: text_editor.format_validation,
16
+ type: text_editor.settings[:input_type] || "text" %>
17
+ <% if text_editor.settings[:anchor] %>
18
+ <%= render "alchemy/ingredients/shared/anchor", ingredient_editor: text_editor %>
19
+ <% end %>
20
+ <% if text_editor.settings[:linkable] %>
21
+ <%= f.hidden_field :link, "data-link-value": true, id: nil %>
22
+ <%= f.hidden_field :link_title, "data-link-title": true, id: nil %>
23
+ <%= f.hidden_field :link_class_name, "data-link-class": true, id: nil %>
24
+ <%= f.hidden_field :link_target, "data-link-target": true, id: nil %>
25
+ <%= render "alchemy/ingredients/shared/link_tools", ingredient_editor: text_editor, wrapper_class: "ingredient_link_buttons" %>
26
+ <% end %>
27
+ </div>
22
28
  <% end %>
23
29
  <% end %>
@@ -0,0 +1,6 @@
1
+ <div class="picture_ingredient_css_class">
2
+ <%= render_icon "pencil-ruler-2", style: "line", size: "1x" %>
3
+ <%= Alchemy.t(css_class,
4
+ scope: "picture_ingredients.css_classes",
5
+ default: css_class.camelcase) %>
6
+ </div>
@@ -9,8 +9,10 @@
9
9
  <meta name="robots" content="noindex">
10
10
  <meta name="alchemy-icon-sprite" content="<%= asset_path("remixicon.symbol.svg") %>">
11
11
  <meta name="turbo-prefetch" content="false">
12
- <%= stylesheet_link_tag('alchemy/admin/all', media: 'screen', 'data-turbo-track' => true) %>
13
- <%= stylesheet_link_tag('alchemy/print', media: 'print', 'data-turbo-track' => true) %>
12
+ <meta name="turbo-cache-control" content="no-cache">
13
+ <%= stylesheet_link_tag('alchemy/admin', media: 'screen', 'data-turbo-track' => true) %>
14
+ <%= stylesheet_link_tag('alchemy/admin/print', media: 'print', 'data-turbo-track' => true) %>
15
+ <%= stylesheet_link_tag('alchemy/admin/custom', 'data-turbo-track' => true) %>
14
16
  <%= yield :stylesheets %>
15
17
  <script>
16
18
  // Global Alchemy JavaScript object.
data/bin/setup CHANGED
@@ -14,6 +14,8 @@ end
14
14
  FileUtils.chdir GEM_ROOT do
15
15
  system! "gem install bundler --conservative"
16
16
  system("bundle check") || system!("bundle install")
17
+ system("bun -v &> /dev/null") || system!("curl -fsSL https://bun.sh/install | bash")
18
+ system!("bun install")
17
19
  end
18
20
 
19
21
  FileUtils.chdir APP_ROOT do
data/bin/start CHANGED
@@ -13,5 +13,5 @@ end
13
13
 
14
14
  FileUtils.chdir APP_ROOT do
15
15
  puts "\n== Starting dummy app =="
16
- system! "bin/rails server"
16
+ system! "bin/dev"
17
17
  end
data/bun.lockb ADDED
Binary file
@@ -205,3 +205,12 @@ format_matchers:
205
205
 
206
206
  # The layout used for rendering the +alchemy/admin/pages#show+ action.
207
207
  admin_page_preview_layout: application
208
+
209
+ # The sizes for the preview size select in the page editor.
210
+ page_preview_sizes:
211
+ - 360
212
+ - 640
213
+ - 768
214
+ - 1024
215
+ - 1280
216
+ - 1440