alchemy_cms 8.2.7 → 8.3.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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -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/preview.min.js +1 -1
  9. data/app/assets/builds/alchemy/theme.css +1 -1
  10. data/app/assets/builds/alchemy/welcome.css +1 -1
  11. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css +1 -1
  12. data/app/assets/builds/tinymce/skins/content/alchemy-dark/content.min.css +1 -1
  13. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
  14. data/app/assets/builds/tinymce/skins/ui/alchemy-dark/skin.min.css +1 -1
  15. data/app/assets/images/alchemy/admin/logo.svg +27 -0
  16. data/app/assets/images/alchemy/icons-sprite.svg +1 -1
  17. data/app/components/alchemy/admin/dashboard/widget.rb +40 -0
  18. data/app/components/alchemy/admin/dashboard/widgets/attachment_counts.rb +17 -0
  19. data/app/components/alchemy/admin/dashboard/widgets/element_usage.rb +37 -0
  20. data/app/components/alchemy/admin/dashboard/widgets/greeting.html.erb +13 -0
  21. data/app/components/alchemy/admin/dashboard/widgets/greeting.rb +21 -0
  22. data/app/components/alchemy/admin/dashboard/widgets/locked_pages.html.erb +54 -0
  23. data/app/components/alchemy/admin/dashboard/widgets/locked_pages.rb +20 -0
  24. data/app/components/alchemy/admin/dashboard/widgets/online_users.html.erb +22 -0
  25. data/app/components/alchemy/admin/dashboard/widgets/online_users.rb +19 -0
  26. data/app/components/alchemy/admin/dashboard/widgets/page_counts.rb +23 -0
  27. data/app/components/alchemy/admin/dashboard/widgets/page_usage.rb +46 -0
  28. data/app/components/alchemy/admin/dashboard/widgets/picture_counts.rb +17 -0
  29. data/app/components/alchemy/admin/dashboard/widgets/recent_pages.html.erb +41 -0
  30. data/app/components/alchemy/admin/dashboard/widgets/recent_pages.rb +16 -0
  31. data/app/components/alchemy/admin/dashboard/widgets/sites.html.erb +29 -0
  32. data/app/components/alchemy/admin/dashboard/widgets/sites.rb +15 -0
  33. data/app/components/alchemy/admin/dashboard/widgets/stat_widget.html.erb +23 -0
  34. data/app/components/alchemy/admin/dashboard/widgets/stat_widget.rb +19 -0
  35. data/app/components/alchemy/admin/dashboard/widgets/system_info.html.erb +32 -0
  36. data/app/components/alchemy/admin/dashboard/widgets/system_info.rb +37 -0
  37. data/app/components/alchemy/admin/dashboard/widgets/usage_widget.html.erb +42 -0
  38. data/app/components/alchemy/admin/dashboard/widgets/usage_widget.rb +66 -0
  39. data/app/components/alchemy/admin/dashboard/widgets/user_counts.rb +25 -0
  40. data/app/components/alchemy/admin/element_editor.html.erb +27 -20
  41. data/app/components/alchemy/admin/element_schedule_timestamps.rb +33 -0
  42. data/app/components/alchemy/admin/element_select.rb +4 -3
  43. data/app/components/alchemy/admin/page_node.html.erb +1 -20
  44. data/app/components/alchemy/admin/page_publication_fields.html.erb +30 -0
  45. data/app/components/alchemy/admin/page_publication_fields.rb +18 -0
  46. data/app/components/alchemy/admin/page_status_indicators.html.erb +29 -0
  47. data/app/components/alchemy/admin/page_status_indicators.rb +9 -0
  48. data/app/components/alchemy/admin/publish_element_button.html.erb +12 -4
  49. data/app/components/alchemy/ingredients/headline_editor.rb +1 -1
  50. data/app/controllers/alchemy/admin/dashboard/widgets_controller.rb +21 -0
  51. data/app/controllers/alchemy/admin/dashboard_controller.rb +3 -12
  52. data/app/controllers/alchemy/pages_controller.rb +5 -4
  53. data/app/helpers/alchemy/elements_block_helper.rb +1 -0
  54. data/app/javascript/alchemy_admin/components/auto_submit.js +15 -9
  55. data/app/javascript/alchemy_admin/components/char_counter.js +17 -7
  56. data/app/javascript/alchemy_admin/components/clipboard_button.js +2 -6
  57. data/app/javascript/alchemy_admin/components/color_select.js +13 -4
  58. data/app/javascript/alchemy_admin/components/datepicker.js +11 -14
  59. data/app/javascript/alchemy_admin/components/dialog_link.js +5 -2
  60. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +6 -3
  61. data/app/javascript/alchemy_admin/components/element_editor.js +45 -28
  62. data/app/javascript/alchemy_admin/components/element_select.js +7 -4
  63. data/app/javascript/alchemy_admin/components/elements_window.js +38 -31
  64. data/app/javascript/alchemy_admin/components/elements_window_handle.js +7 -3
  65. data/app/javascript/alchemy_admin/components/file_editor.js +5 -2
  66. data/app/javascript/alchemy_admin/components/ingredient_group.js +6 -4
  67. data/app/javascript/alchemy_admin/components/link_buttons/link_button.js +1 -2
  68. data/app/javascript/alchemy_admin/components/link_buttons/unlink_button.js +1 -2
  69. data/app/javascript/alchemy_admin/components/link_buttons.js +6 -2
  70. data/app/javascript/alchemy_admin/components/list_filter.js +44 -29
  71. data/app/javascript/alchemy_admin/components/message.js +22 -15
  72. data/app/javascript/alchemy_admin/components/overlay.js +5 -7
  73. data/app/javascript/alchemy_admin/components/page_publication_fields.js +38 -25
  74. data/app/javascript/alchemy_admin/components/picture_description_select.js +5 -2
  75. data/app/javascript/alchemy_admin/components/picture_editor.js +5 -10
  76. data/app/javascript/alchemy_admin/components/picture_thumbnail.js +4 -5
  77. data/app/javascript/alchemy_admin/components/preview_window.js +5 -10
  78. data/app/javascript/alchemy_admin/components/publish_page_button.js +2 -5
  79. data/app/javascript/alchemy_admin/components/remote_select.js +53 -23
  80. data/app/javascript/alchemy_admin/components/select.js +169 -26
  81. data/app/javascript/alchemy_admin/components/sortable_elements.js +1 -1
  82. data/app/javascript/alchemy_admin/components/spinner.js +11 -11
  83. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +9 -1
  84. data/app/javascript/alchemy_admin/components/tinymce.js +16 -22
  85. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +48 -45
  86. data/app/javascript/alchemy_admin/components/uploader/progress.js +70 -84
  87. data/app/javascript/alchemy_admin/components/uploader.js +71 -46
  88. data/app/javascript/alchemy_admin/dialog.js +3 -0
  89. data/app/javascript/alchemy_admin/hotkeys.js +0 -18
  90. data/app/javascript/alchemy_admin/image_cropper.js +7 -9
  91. data/app/javascript/alchemy_admin/initializer.js +21 -0
  92. data/app/javascript/alchemy_admin/utils/dispatch_page_dirty_event.js +7 -0
  93. data/app/javascript/tinymce/plugins/alchemy_link/index.js +9 -0
  94. data/app/jobs/alchemy/base_job.rb +2 -2
  95. data/app/jobs/alchemy/invalidate_elements_cache_job.rb +33 -0
  96. data/app/models/alchemy/page/page_naming.rb +28 -5
  97. data/app/models/alchemy/page/page_natures.rb +7 -2
  98. data/app/models/alchemy/page/page_scopes.rb +2 -2
  99. data/app/models/alchemy/page/url_path.rb +7 -2
  100. data/app/models/alchemy/page.rb +2 -2
  101. data/app/models/alchemy/page_definition.rb +1 -0
  102. data/app/models/alchemy/permissions.rb +1 -1
  103. data/app/models/concerns/alchemy/relatable_resource.rb +8 -0
  104. data/app/services/alchemy/page_finder.rb +88 -0
  105. data/app/stylesheets/alchemy/_custom-properties.scss +6 -4
  106. data/app/stylesheets/alchemy/_mixins.scss +1 -7
  107. data/app/stylesheets/alchemy/_themes.scss +13 -1
  108. data/app/stylesheets/alchemy/admin/_tom-select.scss +240 -0
  109. data/app/stylesheets/alchemy/admin/archive.scss +0 -1
  110. data/app/stylesheets/alchemy/admin/base.scss +0 -19
  111. data/app/stylesheets/alchemy/admin/dashboard.scss +395 -28
  112. data/app/stylesheets/alchemy/admin/elements.scss +14 -17
  113. data/app/stylesheets/alchemy/admin/form_fields.scss +3 -3
  114. data/app/stylesheets/alchemy/admin/forms.scss +107 -93
  115. data/app/stylesheets/alchemy/admin/icons.scss +28 -0
  116. data/app/stylesheets/alchemy/admin/image_library.scss +20 -10
  117. data/app/stylesheets/alchemy/admin/navigation.scss +4 -1
  118. data/app/stylesheets/alchemy/admin/popover.scss +3 -5
  119. data/app/stylesheets/alchemy/admin/resource_info.scss +11 -17
  120. data/app/stylesheets/alchemy/admin/shoelace.scss +8 -0
  121. data/app/stylesheets/alchemy/admin/sitemap.scss +5 -0
  122. data/app/stylesheets/alchemy/admin/tables.scss +32 -3
  123. data/app/stylesheets/alchemy/admin/toolbar.scss +0 -1
  124. data/app/stylesheets/alchemy/admin.scss +1 -0
  125. data/app/stylesheets/tinymce/skins/ui/alchemy/skin.scss +0 -4
  126. data/app/stylesheets/tinymce/skins/ui/alchemy-dark/skin.scss +0 -4
  127. data/app/types/alchemy/wildcard_url_type.rb +48 -0
  128. data/app/views/alchemy/_menubar.html.erb +1 -5
  129. data/app/views/alchemy/admin/attachments/edit.html.erb +6 -3
  130. data/app/views/alchemy/admin/dashboard/_dashboard.html.erb +3 -2
  131. data/app/views/alchemy/admin/dashboard/_footer.html.erb +22 -0
  132. data/app/views/alchemy/admin/dashboard/_stats.html.erb +7 -0
  133. data/app/views/alchemy/admin/dashboard/_top.html.erb +4 -12
  134. data/app/views/alchemy/admin/dashboard/_widgets.html.erb +7 -0
  135. data/app/views/alchemy/admin/dashboard/index.html.erb +0 -17
  136. data/app/views/alchemy/admin/dashboard/info.html.erb +1 -62
  137. data/app/views/alchemy/admin/dashboard/widgets/show.html.erb +3 -0
  138. data/app/views/alchemy/admin/elements/_form.html.erb +2 -1
  139. data/app/views/alchemy/admin/elements/_schedule.html.erb +2 -15
  140. data/app/views/alchemy/admin/elements/_schedule_fields.html.erb +2 -0
  141. data/app/views/alchemy/admin/layoutpages/edit.html.erb +6 -3
  142. data/app/views/alchemy/admin/nodes/_page_nodes.html.erb +10 -8
  143. data/app/views/alchemy/admin/pages/_form.html.erb +25 -19
  144. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +2 -32
  145. data/app/views/alchemy/admin/pages/_table.html.erb +1 -18
  146. data/app/views/alchemy/admin/pages/configure.html.erb +2 -2
  147. data/app/views/alchemy/admin/pages/info.html.erb +6 -0
  148. data/app/views/alchemy/admin/resources/_form.html.erb +7 -4
  149. data/app/views/alchemy/admin/resources/edit.html.erb +3 -1
  150. data/app/views/alchemy/admin/resources/new.html.erb +3 -1
  151. data/app/views/alchemy/admin/styleguide/index.html.erb +52 -30
  152. data/app/views/alchemy/admin/translations/_en.js +4 -0
  153. data/app/views/layouts/alchemy/admin.html.erb +3 -3
  154. data/config/importmap.rb +2 -0
  155. data/config/locales/alchemy.en.yml +15 -0
  156. data/config/routes.rb +1 -0
  157. data/lib/alchemy/configuration/class_option.rb +46 -3
  158. data/lib/alchemy/configuration/collection_option.rb +4 -0
  159. data/lib/alchemy/configurations/dashboard.rb +79 -0
  160. data/lib/alchemy/configurations/main.rb +15 -0
  161. data/lib/alchemy/engine.rb +9 -3
  162. data/lib/alchemy/sprockets/skip_builds_compression.rb +33 -0
  163. data/lib/alchemy/test_support/capybara_helpers.rb +17 -0
  164. data/lib/alchemy/test_support/relatable_resource_examples.rb +20 -0
  165. data/lib/alchemy/test_support/rspec_matchers.rb +8 -0
  166. data/lib/alchemy/test_support/shared_publishable_examples.rb +38 -31
  167. data/lib/alchemy/tinymce.rb +1 -1
  168. data/lib/alchemy/version.rb +17 -3
  169. data/vendor/javascript/cropperjs.min.js +1 -1
  170. data/vendor/javascript/flatpickr.min.js +1 -1
  171. data/vendor/javascript/floating-ui.min.js +1 -0
  172. data/vendor/javascript/keymaster.min.js +1 -1
  173. data/vendor/javascript/rails-ujs.min.js +1 -1
  174. data/vendor/javascript/shoelace.min.js +93 -93
  175. data/vendor/javascript/sortable.min.js +1 -1
  176. data/vendor/javascript/tinymce.min.js +5 -1
  177. data/vendor/javascript/tom-select.min.js +1 -0
  178. metadata +57 -18
  179. data/app/javascript/alchemy_admin/components/alchemy_html_element.js +0 -129
  180. data/app/views/alchemy/admin/dashboard/_left_column.html.erb +0 -4
  181. data/app/views/alchemy/admin/dashboard/_right_column.html.erb +0 -9
  182. data/app/views/alchemy/admin/dashboard/widgets/_locked_pages.html.erb +0 -52
  183. data/app/views/alchemy/admin/dashboard/widgets/_recent_pages.html.erb +0 -34
  184. data/app/views/alchemy/admin/dashboard/widgets/_sites.html.erb +0 -25
  185. data/app/views/alchemy/admin/dashboard/widgets/_users.html.erb +0 -21
  186. data/app/views/alchemy/admin/languages/edit.html.erb +0 -1
  187. data/app/views/alchemy/admin/languages/new.html.erb +0 -1
  188. data/app/views/alchemy/admin/sites/edit.html.erb +0 -1
  189. data/app/views/alchemy/admin/sites/new.html.erb +0 -1
@@ -14,10 +14,6 @@ form {
14
14
  padding: 0;
15
15
  }
16
16
 
17
- &.edit_page textarea {
18
- height: 67px;
19
- }
20
-
21
17
  .control-label {
22
18
  @include mixins.form-label;
23
19
  }
@@ -29,37 +25,27 @@ form {
29
25
  }
30
26
 
31
27
  .input {
28
+ display: grid;
29
+ grid-template-columns: var(--form-left-column-width) minmax(
30
+ 0,
31
+ var(--form-right-column-width)
32
+ );
33
+ align-items: baseline;
34
+ gap: 0 var(--spacing-2);
32
35
  padding: var(--spacing-1) 0;
33
- @include mixins.clearfix;
34
-
35
- input[type="url"],
36
- input[type="number"],
37
- input[type="text"],
38
- input[type="email"],
39
- input[type="password"],
40
- textarea,
41
- select,
42
- .select2-container,
43
- .autocomplete_tag_list,
44
- .tinymce_container {
45
- width: var(--form-right-column-width);
46
- float: right;
47
- }
48
36
 
49
37
  textarea {
50
38
  padding-top: 7px;
39
+ height: 6rem;
51
40
  }
52
41
 
53
- .input > select,
54
- .input > .select2-container {
55
- width: 100%;
42
+ .input-row {
43
+ margin: 0;
56
44
  }
57
45
 
58
- > .autocomplete_tag_list {
59
- .select2-container,
60
- .select2-choices {
61
- width: 100%;
62
- }
46
+ .select2-container,
47
+ .select2-choices {
48
+ width: 100%;
63
49
  }
64
50
 
65
51
  ::-webkit-input-placeholder {
@@ -68,39 +54,46 @@ form {
68
54
 
69
55
  select,
70
56
  .select2-container {
71
- margin: var(--spacing-1) 0;
57
+ margin: var(--form-field-margin);
58
+ }
59
+
60
+ &:has(.select2-container:not(.select2-container-multi)) {
61
+ .control-label {
62
+ align-self: center;
63
+ }
72
64
  }
73
65
 
74
66
  &.boolean {
75
- margin-left: var(--form-left-column-width);
67
+ height: var(--form-field-height);
68
+
69
+ input,
70
+ label {
71
+ grid-column: 2;
72
+ grid-row: 1;
73
+ width: max-content;
74
+ align-self: center;
75
+ margin: var(--form-field-margin);
76
+ }
76
77
 
77
78
  input {
78
- margin: 0;
79
- margin-right: var(--spacing-0);
80
- margin-left: 1px;
81
- vertical-align: middle;
79
+ margin-left: var(--spacing-0);
82
80
  }
83
81
 
84
82
  label {
85
- width: 100%;
86
- text-align: left;
87
- padding: 0;
88
- margin: 0;
89
- float: none;
90
- margin-left: var(--spacing-1);
91
- vertical-align: middle;
83
+ margin-left: var(--spacing-6);
92
84
  }
93
85
  }
94
86
 
95
87
  label.checkbox {
96
88
  display: flex;
97
- align-items: center;
89
+ align-items: baseline;
98
90
  gap: var(--spacing-1);
99
- margin: var(--spacing-0) 0 var(--spacing-2);
91
+ margin: var(--spacing-1) 0;
92
+ width: max-content;
100
93
 
101
94
  input {
102
- margin-right: var(--spacing-0);
103
- margin-left: 1px;
95
+ align-self: center;
96
+ margin: 0 var(--spacing-0) 0 1px;
104
97
  }
105
98
  }
106
99
 
@@ -112,6 +105,19 @@ form {
112
105
  );
113
106
  text-align: left;
114
107
  }
108
+
109
+ &.tags {
110
+ .control_group {
111
+ gap: 0;
112
+ }
113
+ }
114
+
115
+ &.tinymce_container {
116
+ label {
117
+ position: relative;
118
+ top: calc(-1 * var(--spacing-1));
119
+ }
120
+ }
115
121
  }
116
122
 
117
123
  .field_with_errors {
@@ -146,9 +152,8 @@ form {
146
152
  small.error {
147
153
  color: var(--notice-error-text-color);
148
154
  display: block;
149
- margin-left: var(--form-left-column-width);
150
155
  line-height: 1.5em;
151
- clear: both;
156
+ grid-column: 2;
152
157
  text-align: right;
153
158
  margin-bottom: 0.25em;
154
159
  }
@@ -204,47 +209,35 @@ form {
204
209
  }
205
210
 
206
211
  .inline-input {
212
+ display: grid;
207
213
  align-items: center;
208
- display: flex;
214
+ grid-template-columns: var(--form-right-column-width) var(
215
+ --form-left-column-width
216
+ );
209
217
  margin: 0 calc(-1 * var(--spacing-1));
218
+ gap: var(--spacing-1);
210
219
 
211
220
  .left-column,
212
221
  .right-column {
213
- padding: 0 var(--spacing-1);
214
- }
215
-
216
- .left-column {
217
- width: var(--form-right-column-width);
218
- }
219
-
220
- .right-column {
221
- width: var(--form-left-column-width);
222
+ min-width: 0;
222
223
  }
223
224
 
224
225
  button,
225
226
  .button,
226
- input[type="url"],
227
- input[type="text"],
228
- input[type="email"],
229
- input[type="submit"],
230
- input[type="password"] {
227
+ input[type="submit"] {
231
228
  width: 100%;
232
229
  }
233
230
  }
234
231
 
235
232
  .control_group {
236
- width: var(--form-right-column-width);
237
- padding-top: var(--spacing-1);
238
- float: right;
239
- }
240
-
241
- .check_boxes .control_group {
242
- padding-top: 0.6em;
233
+ display: flex;
234
+ flex-direction: column;
235
+ gap: var(--spacing-1);
236
+ margin: var(--spacing-1) 0;
243
237
  }
244
238
 
245
239
  .input .hint {
246
240
  @include mixins.form-hint;
247
- margin-left: var(--form-left-column-width);
248
241
 
249
242
  a[href] {
250
243
  color: var(--hint-text-link-color);
@@ -260,12 +253,33 @@ form {
260
253
  }
261
254
 
262
255
  .submit {
263
- display: flex;
264
- padding: var(--spacing-1) 0;
265
- justify-content: space-between;
256
+ display: grid;
257
+ grid-template-columns: var(--form-left-column-width) var(
258
+ --form-right-column-width
259
+ );
260
+ margin: var(--spacing-1) 0;
261
+ gap: 0 var(--spacing-2);
262
+
263
+ > button {
264
+ grid-column: 2;
265
+ grid-row: 1;
266
+ width: max-content;
267
+
268
+ &:last-of-type {
269
+ margin-left: auto;
270
+ }
271
+ }
272
+ }
273
+
274
+ &.full_width .submit {
275
+ grid-template-columns: 1fr 1fr;
266
276
 
267
- > button:last-of-type {
268
- margin-left: auto;
277
+ button {
278
+ width: 100%;
279
+
280
+ &:first-of-type {
281
+ grid-column: 1;
282
+ }
269
283
  }
270
284
  }
271
285
 
@@ -277,31 +291,31 @@ form {
277
291
  }
278
292
 
279
293
  .input-column {
294
+ display: flex;
295
+ flex-direction: column;
296
+ min-width: 0;
280
297
  width: 50%;
281
- padding: 0 var(--spacing-1);
282
298
 
283
- input[type] {
284
- float: none;
285
- width: 100%;
299
+ > label {
300
+ display: inline-block;
301
+ margin-bottom: var(--spacing-1);
302
+ text-align: left;
303
+ }
304
+
305
+ select,
306
+ .select2-container {
307
+ margin: var(--form-field-margin);
286
308
  }
287
309
  }
288
310
 
311
+ &.full_width .input-column {
312
+ width: 100%;
313
+ }
314
+
289
315
  .input-row {
290
316
  display: flex;
291
-
292
- .input-column {
293
- &:first-of-type {
294
- padding-left: 0;
295
- }
296
-
297
- &:last-of-type {
298
- padding-right: 0;
299
- }
300
- }
317
+ gap: var(--spacing-2);
318
+ justify-content: space-between;
319
+ margin: var(--spacing-2) 0;
301
320
  }
302
321
  }
303
-
304
- .input-column > label {
305
- display: block;
306
- margin-top: calc(var(--spacing-1) + 1);
307
- }
@@ -2,6 +2,34 @@ alchemy-icon {
2
2
  display: inline-flex;
3
3
  align-items: center;
4
4
  justify-content: center;
5
+ width: var(--icon-size, var(--icon-size-md));
6
+ height: var(--icon-size, var(--icon-size-md));
7
+ opacity: 1;
8
+ transition: opacity var(--transition-duration) var(--transition-easing);
9
+
10
+ &:not(:defined) {
11
+ opacity: 0;
12
+ }
13
+
14
+ &[size="xs"] {
15
+ width: var(--icon-size-xs);
16
+ height: var(--icon-size-xs);
17
+ }
18
+
19
+ &[size="sm"] {
20
+ width: var(--icon-size-sm);
21
+ height: var(--icon-size-sm);
22
+ }
23
+
24
+ &[size="1x"] {
25
+ width: var(--icon-size-1x);
26
+ height: var(--icon-size-1x);
27
+ }
28
+
29
+ &[size="xl"] {
30
+ width: var(--icon-size-xl);
31
+ height: var(--icon-size-xl);
32
+ }
5
33
 
6
34
  &.disabled {
7
35
  opacity: 0.3;
@@ -111,18 +111,28 @@
111
111
  padding: var(--spacing-2) var(--spacing-4) var(--spacing-2) var(--spacing-1);
112
112
  overflow: auto;
113
113
 
114
- form .control-label {
115
- text-align: left;
116
- }
114
+ form {
115
+ .control-label {
116
+ display: block;
117
+ text-align: left;
118
+ line-height: var(--form-field-height);
119
+ }
117
120
 
118
- form .input .hint {
119
- margin-left: 0;
120
- }
121
+ .input {
122
+ display: block;
123
+
124
+ alchemy-picture-description-select select {
125
+ margin: 0;
126
+ }
121
127
 
122
- form .input .select2-container,
123
- form .input input[type="text"],
124
- form .input textarea {
125
- width: 100%;
128
+ .hint {
129
+ margin-left: 0;
130
+ }
131
+
132
+ .select2-container {
133
+ width: 100%;
134
+ }
135
+ }
126
136
  }
127
137
  }
128
138
 
@@ -7,7 +7,6 @@
7
7
  top: 0;
8
8
  margin-left: var(--main-menu-width);
9
9
  padding-right: var(--main-menu-width);
10
- z-index: 20;
11
10
  width: 100%;
12
11
  height: var(--top-menu-height);
13
12
  @extend .disable-user-select;
@@ -308,3 +307,7 @@
308
307
  text-transform: uppercase;
309
308
  }
310
309
  }
310
+
311
+ .alchemy-timezone-select {
312
+ width: 30px; // Reduce FOUC
313
+ }
@@ -27,11 +27,9 @@
27
27
  font-size: var(--font-size_small);
28
28
  }
29
29
 
30
- .submit {
31
- gap: var(--spacing-2);
32
-
33
- button {
34
- width: 50%;
30
+ form {
31
+ label {
32
+ font-size: var(--font-size_small);
35
33
  }
36
34
  }
37
35
  }
@@ -4,8 +4,6 @@
4
4
  .resource-details {
5
5
  display: flex;
6
6
  gap: var(--spacing-5);
7
- --form-left-column-width: 30%;
8
- --form-right-column-width: 70%;
9
7
 
10
8
  > .resource-preview {
11
9
  flex-grow: 0;
@@ -29,10 +27,6 @@
29
27
  aside {
30
28
  width: 50%;
31
29
  }
32
-
33
- .resource_info .value p {
34
- --max-width: 287px;
35
- }
36
30
  }
37
31
  }
38
32
 
@@ -49,15 +43,22 @@
49
43
  .resource_info {
50
44
  .value {
51
45
  position: relative;
52
- @include mixins.clearfix;
46
+ display: grid;
47
+ grid-template-columns: var(--form-left-column-width) var(
48
+ --form-right-column-width
49
+ );
50
+ align-items: baseline;
51
+ gap: 0 var(--spacing-2);
53
52
 
54
53
  > label {
55
54
  @include mixins.form-label;
55
+
56
+ alchemy-icon {
57
+ vertical-align: middle;
58
+ }
56
59
  }
57
60
 
58
61
  > p {
59
- float: right;
60
- width: var(--form-right-column-width);
61
62
  margin: var(--form-field-margin);
62
63
  padding: var(--spacing-1) var(--spacing-2);
63
64
  line-height: 21px;
@@ -66,7 +67,7 @@
66
67
  border-radius: var(--border-radius_medium);
67
68
 
68
69
  &:not(.value-block) {
69
- @include mixins.truncate(var(--form-right-column-width), $wrap: nowrap);
70
+ @include mixins.truncate(100%, $wrap: nowrap);
70
71
  }
71
72
 
72
73
  &.value-block {
@@ -81,7 +82,6 @@
81
82
  > p {
82
83
  white-space: nowrap;
83
84
  padding-right: var(--spacing-10);
84
- max-width: var(--max-width, 328px);
85
85
  }
86
86
  }
87
87
  }
@@ -109,12 +109,6 @@
109
109
  &.file-infos .value {
110
110
  label {
111
111
  text-align: left;
112
- width: 30%;
113
- }
114
-
115
- p {
116
- max-width: 70%;
117
- width: 70%;
118
112
  }
119
113
  }
120
114
  }
@@ -292,6 +292,14 @@ sl-dropdown {
292
292
  filter: drop-shadow(var(--dialog-box-shadow));
293
293
  border: 1px solid var(--border-color);
294
294
  }
295
+
296
+ // Until sl-dropdown upgrades it has no shadow DOM, so its default-slot panel
297
+ // (the .alchemy-popover) renders inline and visible; on definition Shoelace
298
+ // hides the panel, collapsing it and shifting the layout. Hide the panel
299
+ // content until defined — the [slot="trigger"] stays visible.
300
+ &:not(:defined) > :not([slot="trigger"]) {
301
+ display: none;
302
+ }
295
303
  }
296
304
 
297
305
  sl-tab-group {
@@ -247,6 +247,11 @@ alchemy-sitemap {
247
247
  justify-content: center;
248
248
  align-items: center;
249
249
  gap: var(--spacing-1);
250
+
251
+ alchemy-icon {
252
+ position: relative;
253
+ top: 0.1ex;
254
+ }
250
255
  }
251
256
 
252
257
  #page_filter_result {
@@ -51,7 +51,7 @@ table {
51
51
  }
52
52
 
53
53
  &.icon {
54
- width: 16px;
54
+ width: var(--spacing-6);
55
55
  text-align: center;
56
56
  background-color: transparent;
57
57
  }
@@ -132,6 +132,11 @@ th,
132
132
 
133
133
  td,
134
134
  .table .col {
135
+ &.button {
136
+ width: 40px;
137
+ text-align: center;
138
+ }
139
+
135
140
  &.file_name {
136
141
  white-space: nowrap;
137
142
  }
@@ -156,6 +161,10 @@ td,
156
161
  width: 150px;
157
162
  }
158
163
 
164
+ &.name {
165
+ width: 200px;
166
+ }
167
+
159
168
  &.email {
160
169
  width: 270px;
161
170
  }
@@ -172,17 +181,35 @@ td,
172
181
  width: 10%;
173
182
  }
174
183
 
175
- &.url {
184
+ &.url,
185
+ &.url_path {
176
186
  width: 15%;
177
187
  white-space: nowrap;
178
188
  }
179
189
 
190
+ &.site_name {
191
+ width: 200px;
192
+ }
193
+
194
+ &.locale {
195
+ width: 60px;
196
+ text-align: center;
197
+ }
198
+
180
199
  &.status {
181
200
  width: 5%;
182
201
  white-space: nowrap;
183
202
 
184
203
  .page_status {
185
204
  margin: 0 var(--spacing-1);
205
+
206
+ &:first-of-type {
207
+ margin-left: 0;
208
+ }
209
+
210
+ &:last-of-type {
211
+ margin-right: 0;
212
+ }
186
213
  }
187
214
  }
188
215
 
@@ -204,8 +231,10 @@ td.count {
204
231
  padding-right: var(--spacing-4);
205
232
  }
206
233
 
234
+ th.taggings_types,
207
235
  td.taggings_types {
208
- width: 15%;
236
+ width: auto;
237
+ text-align: right;
209
238
  }
210
239
 
211
240
  .list .login_status {
@@ -5,7 +5,6 @@
5
5
  @extend %gradiated-toolbar;
6
6
  align-items: center;
7
7
  gap: var(--spacing-2);
8
- z-index: 10;
9
8
  margin-right: 0px;
10
9
  position: relative;
11
10
 
@@ -39,6 +39,7 @@
39
39
  @use "admin/spinner";
40
40
  @use "admin/tables";
41
41
  @use "admin/tags";
42
+ @use "admin/tom-select";
42
43
  @use "admin/toolbar";
43
44
  @use "admin/typography";
44
45
  @use "admin/upload";
@@ -1943,10 +1943,6 @@ body.tox-dialog__disable-scroll {
1943
1943
  overflow: hidden;
1944
1944
  }
1945
1945
 
1946
- .tox .tox-editor-header {
1947
- z-index: 1;
1948
- }
1949
-
1950
1946
  .tox:not(.tox-tinymce-inline) .tox-editor-header {
1951
1947
  box-shadow: none;
1952
1948
  transition: box-shadow 0.5s;
@@ -1943,10 +1943,6 @@ body.tox-dialog__disable-scroll {
1943
1943
  overflow: hidden;
1944
1944
  }
1945
1945
 
1946
- .tox .tox-editor-header {
1947
- z-index: 1;
1948
- }
1949
-
1950
1946
  .tox:not(.tox-tinymce-inline) .tox-editor-header {
1951
1947
  box-shadow: none;
1952
1948
  transition: box-shadow 0.5s;
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class WildcardUrlType < ActiveModel::Type::Value
5
+ def cast(value)
6
+ case value
7
+ when nil then nil
8
+ when Symbol, String then normalize(value)
9
+ else value
10
+ end
11
+ end
12
+
13
+ def assert_valid_value(value)
14
+ case value
15
+ when nil
16
+ nil
17
+ when Symbol, String
18
+ assert_valid_param!(normalize(value))
19
+ else
20
+ raise ArgumentError, "#{value.inspect} is not a valid wildcard_url. Must be a Symbol or String."
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ # Normalizes a wildcard_url input to a String. Symbols are turned into a
27
+ # dynamic segment with a leading colon (`:slug` => `":slug"`).
28
+ #
29
+ # @param value [String, Symbol]
30
+ # @return [String]
31
+ def normalize(value)
32
+ value.is_a?(Symbol) ? ":#{value}" : value.to_s
33
+ end
34
+
35
+ def assert_valid_param!(value)
36
+ if value.include?("/")
37
+ raise ArgumentError,
38
+ "wildcard_url #{value.inspect}: cannot contain \"/\". " \
39
+ "Must be a single URL segment."
40
+ end
41
+
42
+ unless value.match?(/:\w+/)
43
+ raise ArgumentError,
44
+ "wildcard_url #{value.inspect}: must contain a dynamic segment, e.g. \":id\"."
45
+ end
46
+ end
47
+ end
48
+ end
@@ -114,14 +114,10 @@
114
114
 
115
115
  <script type="module" data-turbo-eval="false">
116
116
  class Menubar extends HTMLElement {
117
- constructor() {
118
- super()
117
+ connectedCallback() {
119
118
  const template = this.querySelector("template")
120
119
  const attachedShadowRoot = this.attachShadow({ mode: "open" })
121
120
  attachedShadowRoot.appendChild(template.content.cloneNode(true))
122
- }
123
-
124
- connectedCallback() {
125
121
  const width = this.bar.offsetWidth
126
122
  this.bar.style = `--panel-width: ${width}px; --left-offset: calc(var(--icon-size) + 32px);`
127
123
  this.bar.addEventListener("touchstart", this, { passive: false })