alchemy_cms 7.4.5 → 8.0.0.a

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

Files changed (358) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/Gemfile +13 -6
  4. data/README.md +13 -5
  5. data/alchemy_cms.gemspec +14 -5
  6. data/app/assets/builds/alchemy/admin/page-select.css +1 -1
  7. data/app/assets/builds/alchemy/admin/print.css +1 -1
  8. data/app/assets/builds/alchemy/admin.css +2 -2
  9. data/app/assets/builds/alchemy/custom-properties.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/ui/alchemy/content.min.css +1 -0
  13. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css +1 -1
  14. data/app/assets/config/alchemy_manifest.js +0 -2
  15. data/app/assets/images/alchemy/icons-sprite.svg +1 -0
  16. data/app/components/alchemy/admin/resource/applied_filter.rb +29 -0
  17. data/app/components/alchemy/admin/resource/checkbox_filter.rb +36 -0
  18. data/app/components/alchemy/admin/resource/datepicker_filter.rb +42 -0
  19. data/app/components/alchemy/admin/resource/select_filter.rb +43 -0
  20. data/app/components/alchemy/admin/toolbar_button.rb +5 -2
  21. data/app/components/alchemy/ingredients/number_view.rb +18 -0
  22. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -15
  23. data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -6
  24. data/app/controllers/alchemy/admin/elements_controller.rb +1 -1
  25. data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
  26. data/app/controllers/alchemy/admin/pages_controller.rb +15 -15
  27. data/app/controllers/alchemy/admin/picture_descriptions_controller.rb +5 -1
  28. data/app/controllers/alchemy/admin/pictures_controller.rb +10 -5
  29. data/app/controllers/alchemy/admin/resources_controller.rb +16 -106
  30. data/app/controllers/alchemy/attachments_controller.rb +43 -14
  31. data/app/controllers/alchemy/messages_controller.rb +1 -1
  32. data/app/controllers/alchemy/pages_controller.rb +7 -2
  33. data/app/controllers/concerns/alchemy/admin/picture_descriptions_form_helper.rb +16 -0
  34. data/app/controllers/concerns/alchemy/admin/resource_filter.rb +92 -0
  35. data/app/decorators/alchemy/element_editor.rb +5 -48
  36. data/app/decorators/alchemy/ingredient_editor.rb +3 -53
  37. data/app/helpers/alchemy/admin/base_helper.rb +14 -84
  38. data/app/helpers/alchemy/admin/elements_helper.rb +4 -4
  39. data/app/helpers/alchemy/admin/pages_helper.rb +1 -1
  40. data/app/helpers/alchemy/base_helper.rb +0 -30
  41. data/app/helpers/alchemy/elements_block_helper.rb +0 -14
  42. data/app/helpers/alchemy/pages_helper.rb +1 -1
  43. data/{lib → app/helpers}/alchemy/resources_helper.rb +5 -45
  44. data/app/javascript/alchemy_admin/components/action.js +4 -0
  45. data/app/javascript/alchemy_admin/components/alchemy_html_element.js +3 -3
  46. data/app/javascript/alchemy_admin/components/datepicker.js +10 -2
  47. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +7 -7
  48. data/app/javascript/alchemy_admin/components/element_editor.js +1 -1
  49. data/app/javascript/alchemy_admin/components/growl.js +1 -0
  50. data/app/javascript/alchemy_admin/components/index.js +1 -0
  51. data/app/javascript/alchemy_admin/components/remote_select.js +4 -1
  52. data/app/javascript/alchemy_admin/components/tags_autocomplete.js +5 -1
  53. data/app/javascript/alchemy_admin/components/tinymce.js +4 -2
  54. data/app/javascript/alchemy_admin/components/update_check.js +42 -0
  55. data/app/javascript/alchemy_admin/components/uploader/file_upload.js +15 -8
  56. data/app/javascript/alchemy_admin/components/uploader/progress.js +12 -6
  57. data/app/javascript/alchemy_admin/components/uploader.js +4 -2
  58. data/app/javascript/alchemy_admin/confirm_dialog.js +27 -57
  59. data/app/javascript/alchemy_admin/dirty.js +3 -2
  60. data/app/javascript/alchemy_admin/i18n.js +15 -16
  61. data/app/javascript/alchemy_admin/initializer.js +1 -49
  62. data/app/javascript/alchemy_admin/utils/ajax.js +51 -44
  63. data/app/javascript/alchemy_admin.js +3 -8
  64. data/app/models/alchemy/admin/filters/base.rb +38 -0
  65. data/app/models/alchemy/admin/filters/checkbox.rb +24 -0
  66. data/app/models/alchemy/admin/filters/datepicker.rb +53 -0
  67. data/app/models/alchemy/admin/filters/select.rb +70 -0
  68. data/app/models/alchemy/admin/resource_name.rb +27 -0
  69. data/app/models/alchemy/attachment.rb +51 -34
  70. data/app/models/alchemy/base_record.rb +2 -0
  71. data/app/models/alchemy/element/definitions.rb +1 -1
  72. data/app/models/alchemy/element/element_ingredients.rb +6 -6
  73. data/app/models/alchemy/element/presenters.rb +3 -12
  74. data/app/models/alchemy/element.rb +9 -27
  75. data/app/models/alchemy/element_definition.rb +160 -0
  76. data/app/models/alchemy/ingredient.rb +10 -43
  77. data/app/models/alchemy/ingredient_definition.rb +134 -0
  78. data/app/models/alchemy/ingredient_validator.rb +7 -3
  79. data/app/models/alchemy/ingredients/number.rb +19 -0
  80. data/app/models/alchemy/language.rb +0 -14
  81. data/app/models/alchemy/message.rb +3 -7
  82. data/app/models/alchemy/node.rb +1 -1
  83. data/app/models/alchemy/page/{page_layouts.rb → definitions.rb} +12 -19
  84. data/app/models/alchemy/page/fixed_attributes.rb +1 -1
  85. data/app/models/alchemy/page/page_elements.rb +13 -14
  86. data/app/models/alchemy/page/page_natures.rb +7 -7
  87. data/app/models/alchemy/page/page_scopes.rb +1 -1
  88. data/app/models/alchemy/page.rb +11 -33
  89. data/app/models/alchemy/page_definition.rb +115 -0
  90. data/app/models/alchemy/picture.rb +69 -79
  91. data/app/models/alchemy/picture_variant.rb +115 -5
  92. data/{lib → app/models}/alchemy/resource.rb +4 -18
  93. data/{lib → app/models}/alchemy/searchable_resource.rb +15 -0
  94. data/app/models/alchemy/site/layout.rb +5 -5
  95. data/app/models/alchemy/site.rb +0 -15
  96. data/app/models/alchemy/storage_adapter/active_storage/attachment_url.rb +41 -0
  97. data/app/models/alchemy/storage_adapter/active_storage/picture_url.rb +55 -0
  98. data/app/models/alchemy/storage_adapter/active_storage/preprocessor.rb +40 -0
  99. data/app/models/alchemy/storage_adapter/active_storage.rb +173 -0
  100. data/app/models/alchemy/{attachment/url.rb → storage_adapter/dragonfly/attachment_url.rb} +12 -12
  101. data/app/models/alchemy/{picture/url.rb → storage_adapter/dragonfly/picture_url.rb} +28 -12
  102. data/app/models/alchemy/{picture → storage_adapter/dragonfly}/preprocessor.rb +4 -4
  103. data/app/models/alchemy/storage_adapter/dragonfly.rb +183 -0
  104. data/app/models/alchemy/storage_adapter.rb +74 -0
  105. data/app/models/concerns/alchemy/picture_thumbnails.rb +19 -6
  106. data/app/serializers/alchemy/element_serializer.rb +0 -1
  107. data/app/services/alchemy/dragonfly_to_image_processing.rb +100 -0
  108. data/app/stylesheets/alchemy/_defaults.scss +3 -0
  109. data/app/stylesheets/alchemy/_extends.scss +69 -0
  110. data/app/{assets/stylesheets → stylesheets}/alchemy/_mixins.scss +36 -49
  111. data/app/stylesheets/alchemy/_variables.scss +5 -0
  112. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/archive.scss +20 -37
  113. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/base.scss +16 -14
  114. data/app/stylesheets/alchemy/admin/buttons.scss +160 -0
  115. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/clipboard.scss +2 -2
  116. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dashboard.scss +13 -16
  117. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/dialogs.scss +23 -16
  118. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/elements.scss +150 -105
  119. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/errors.scss +5 -5
  120. data/app/stylesheets/alchemy/admin/filters.scss +58 -0
  121. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flatpickr.scss +53 -60
  122. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/form_fields.scss +21 -7
  123. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/forms.scss +31 -19
  124. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/frame.scss +20 -16
  125. data/app/stylesheets/alchemy/admin/hints.scss +5 -0
  126. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/icons.scss +10 -1
  127. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/image_library.scss +10 -8
  128. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/images.scss +1 -1
  129. data/app/stylesheets/alchemy/admin/labels.scss +5 -0
  130. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/lists.scss +3 -3
  131. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/navigation.scss +61 -55
  132. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/nodes.scss +21 -18
  133. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/notices.scss +18 -18
  134. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/page-select.scss +2 -2
  135. data/app/stylesheets/alchemy/admin/pagination.scss +144 -0
  136. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/preview_window.scss +8 -6
  137. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/print.scss +1 -1
  138. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/resource_info.scss +8 -5
  139. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/search.scss +9 -6
  140. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/selects.scss +49 -37
  141. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/shoelace.scss +5 -6
  142. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/sitemap.scss +38 -33
  143. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tables.scss +6 -4
  144. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/tags.scss +6 -4
  145. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/toolbar.scss +12 -6
  146. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/typography.scss +2 -2
  147. data/app/{assets/stylesheets → stylesheets}/alchemy/admin/upload.scss +7 -5
  148. data/app/stylesheets/alchemy/admin.scss +44 -0
  149. data/app/stylesheets/alchemy/custom-properties.css +244 -0
  150. data/app/stylesheets/alchemy/welcome.scss +75 -0
  151. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/content/alchemy/content.scss +8 -9
  152. data/app/stylesheets/tinymce/skins/ui/alchemy/content.scss +1 -0
  153. data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/skin.scss +133 -136
  154. data/app/views/alchemy/admin/attachments/_files_list.html.erb +2 -2
  155. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  156. data/app/views/alchemy/admin/{elements/_clipboard_button.html.erb → clipboard/_button.html.erb} +3 -5
  157. data/app/views/alchemy/admin/clipboard/_update_nested_element_button.turbo_stream.erb +11 -0
  158. data/app/views/alchemy/admin/clipboard/clear.turbo_stream.erb +4 -0
  159. data/app/views/alchemy/admin/clipboard/index.html.erb +15 -13
  160. data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +18 -0
  161. data/app/views/alchemy/admin/clipboard/remove.turbo_stream.erb +9 -0
  162. data/app/views/alchemy/admin/dashboard/info.html.erb +17 -31
  163. data/app/views/alchemy/admin/elements/_element.html.erb +4 -8
  164. data/app/views/alchemy/admin/elements/_form.html.erb +1 -1
  165. data/app/views/alchemy/admin/elements/_header.html.erb +1 -0
  166. data/app/views/alchemy/admin/elements/_toolbar.html.erb +4 -6
  167. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +2 -1
  168. data/app/views/alchemy/admin/elements/index.html.erb +2 -2
  169. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +3 -16
  170. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +0 -9
  171. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  172. data/app/views/alchemy/admin/languages/_table.html.erb +1 -1
  173. data/app/views/alchemy/admin/languages/index.html.erb +5 -2
  174. data/app/views/alchemy/admin/layoutpages/index.html.erb +1 -12
  175. data/app/views/alchemy/admin/pages/_form.html.erb +2 -2
  176. data/app/views/alchemy/admin/pages/_page.html.erb +2 -3
  177. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -15
  178. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  179. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +9 -12
  180. data/app/views/alchemy/admin/partials/_search_form.html.erb +4 -9
  181. data/app/views/alchemy/admin/picture_descriptions/_form.html.erb +5 -7
  182. data/app/views/alchemy/admin/picture_descriptions/edit.html.erb +2 -2
  183. data/app/views/alchemy/admin/pictures/_archive.html.erb +4 -7
  184. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +2 -1
  185. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +1 -1
  186. data/app/views/alchemy/admin/pictures/_form.html.erb +2 -2
  187. data/app/views/alchemy/admin/pictures/_picture_description_field.html.erb +21 -13
  188. data/app/views/alchemy/admin/pictures/index.html.erb +2 -7
  189. data/app/views/alchemy/admin/resources/_applied_filters.html.erb +8 -0
  190. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +11 -21
  191. data/app/views/alchemy/admin/resources/_pagination.html.erb +6 -0
  192. data/app/views/alchemy/admin/resources/_per_page_select.html.erb +4 -2
  193. data/app/views/alchemy/admin/resources/_resource_table.html.erb +1 -1
  194. data/app/views/alchemy/admin/resources/_table_header.html.erb +1 -15
  195. data/app/views/alchemy/admin/sites/index.html.erb +5 -1
  196. data/app/views/alchemy/admin/styleguide/index.html.erb +8 -0
  197. data/app/views/alchemy/admin/tags/index.html.erb +1 -1
  198. data/app/views/alchemy/admin/tinymce/_setup.html.erb +7 -7
  199. data/app/{javascript/alchemy_admin/locales/en.js → views/alchemy/admin/translations/_en.js} +5 -2
  200. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
  201. data/app/views/alchemy/admin/uploader/_setup.html.erb +4 -4
  202. data/app/views/alchemy/base/500.turbo_stream.erb +3 -0
  203. data/app/views/alchemy/base/redirect.js.erb +1 -1
  204. data/app/views/alchemy/ingredients/_number_editor.html.erb +24 -0
  205. data/app/views/alchemy/no_index.html.erb +31 -0
  206. data/app/views/alchemy/welcome.html.erb +12 -10
  207. data/app/views/kaminari/alchemy/_first_page.html.erb +5 -3
  208. data/app/views/kaminari/alchemy/_last_page.html.erb +5 -3
  209. data/app/views/kaminari/alchemy/_next_page.html.erb +5 -3
  210. data/app/views/kaminari/alchemy/_paginator.html.erb +18 -13
  211. data/app/views/kaminari/alchemy/_prev_page.html.erb +5 -3
  212. data/app/views/layouts/alchemy/admin.html.erb +5 -9
  213. data/bun.lockb +0 -0
  214. data/bundles/remixicon.mjs +153 -0
  215. data/config/alchemy/config.yml +3 -2
  216. data/config/initializers/dragonfly.rb +0 -1
  217. data/config/initializers/mime_types.rb +1 -0
  218. data/config/locales/alchemy.en.yml +32 -14
  219. data/config/routes.rb +0 -2
  220. data/db/migrate/20250626160259_add_unique_index_to_picture_descriptions.rb +7 -0
  221. data/eslint.config.js +2 -1
  222. data/lib/alchemy/admin/preview_url.rb +4 -5
  223. data/lib/alchemy/cache_digests/template_tracker.rb +6 -9
  224. data/lib/alchemy/config_missing.rb +14 -0
  225. data/lib/alchemy/configuration/base_option.rb +24 -0
  226. data/lib/alchemy/configuration/boolean_option.rb +16 -0
  227. data/lib/alchemy/configuration/class_option.rb +15 -0
  228. data/lib/alchemy/configuration/class_set_option.rb +46 -0
  229. data/lib/alchemy/configuration/integer_list_option.rb +13 -0
  230. data/lib/alchemy/configuration/integer_option.rb +12 -0
  231. data/lib/alchemy/configuration/list_option.rb +22 -0
  232. data/lib/alchemy/configuration/regexp_option.rb +11 -0
  233. data/lib/alchemy/configuration/string_list_option.rb +13 -0
  234. data/lib/alchemy/configuration/string_option.rb +11 -0
  235. data/lib/alchemy/configuration.rb +115 -0
  236. data/lib/alchemy/configuration_methods.rb +3 -1
  237. data/lib/alchemy/configurations/default_language.rb +12 -0
  238. data/lib/alchemy/configurations/default_site.rb +10 -0
  239. data/lib/alchemy/configurations/format_matchers.rb +11 -0
  240. data/lib/alchemy/configurations/mailer.rb +16 -0
  241. data/lib/alchemy/configurations/main.rb +216 -0
  242. data/lib/alchemy/configurations/preview.rb +32 -0
  243. data/lib/alchemy/configurations/sitemap.rb +10 -0
  244. data/lib/alchemy/configurations/uploader.rb +34 -0
  245. data/lib/alchemy/engine.rb +65 -17
  246. data/lib/alchemy/hints.rb +3 -7
  247. data/lib/alchemy/on_page_layout.rb +2 -2
  248. data/lib/alchemy/propshaft/tinymce_asset.rb +15 -0
  249. data/lib/alchemy/seeder.rb +2 -2
  250. data/lib/alchemy/tasks/usage.rb +4 -4
  251. data/lib/alchemy/test_support/config_stubbing.rb +1 -7
  252. data/lib/alchemy/test_support/factories/attachment_factory.rb +13 -2
  253. data/lib/alchemy/test_support/factories/language_factory.rb +1 -1
  254. data/lib/alchemy/test_support/factories/page_factory.rb +2 -3
  255. data/lib/alchemy/test_support/factories/picture_factory.rb +30 -2
  256. data/lib/alchemy/test_support/factories/site_factory.rb +2 -2
  257. data/lib/alchemy/test_support/having_crop_action_examples.rb +2 -2
  258. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +80 -26
  259. data/lib/alchemy/test_support/shared_ingredient_examples.rb +5 -5
  260. data/lib/alchemy/upgrader/.keep +0 -0
  261. data/lib/alchemy/upgrader/eight_zero.rb +14 -0
  262. data/lib/alchemy/upgrader.rb +33 -20
  263. data/lib/alchemy/version.rb +1 -1
  264. data/lib/alchemy.rb +192 -170
  265. data/lib/alchemy_cms.rb +1 -7
  266. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +0 -3
  267. data/lib/generators/alchemy/install/files/_article.html.erb +6 -4
  268. data/lib/generators/alchemy/install/files/alchemy.en.yml +22 -3
  269. data/lib/generators/alchemy/install/files/application.html.erb +5 -0
  270. data/lib/generators/alchemy/install/install_generator.rb +5 -14
  271. data/lib/generators/alchemy/install/templates/alchemy.rb.tt +196 -0
  272. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +0 -1
  273. data/lib/generators/alchemy/install/templates/elements.yml.tt +3 -1
  274. data/lib/generators/alchemy/install/templates/menus.yml.tt +1 -1
  275. data/lib/generators/alchemy/install/templates/page_layouts.yml.tt +2 -2
  276. data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +2 -2
  277. data/lib/tasks/alchemy/assets.rake +14 -0
  278. data/lib/tasks/alchemy/upgrade.rake +12 -47
  279. data/vendor/javascript/tinymce.min.js +1 -1
  280. data/vitest.config.js +21 -0
  281. metadata +184 -180
  282. data/app/assets/builds/alchemy/admin/page-select.css.map +0 -1
  283. data/app/assets/builds/alchemy/admin/print.css.map +0 -1
  284. data/app/assets/builds/alchemy/admin.css.map +0 -1
  285. data/app/assets/builds/alchemy/custom-properties.css.map +0 -1
  286. data/app/assets/builds/alchemy/welcome.css.map +0 -1
  287. data/app/assets/builds/tinymce/skins/content/alchemy/content.min.css.map +0 -1
  288. data/app/assets/builds/tinymce/skins/ui/alchemy/skin.min.css.map +0 -1
  289. data/app/assets/javascripts/alchemy/admin.js +0 -10
  290. data/app/assets/stylesheets/alchemy/_defaults.scss +0 -3
  291. data/app/assets/stylesheets/alchemy/_deprecated_variables.scss +0 -45
  292. data/app/assets/stylesheets/alchemy/_deprecation.scss +0 -17
  293. data/app/assets/stylesheets/alchemy/_extends.scss +0 -62
  294. data/app/assets/stylesheets/alchemy/_variables.scss +0 -201
  295. data/app/assets/stylesheets/alchemy/admin/buttons.scss +0 -124
  296. data/app/assets/stylesheets/alchemy/admin/hints.scss +0 -5
  297. data/app/assets/stylesheets/alchemy/admin/labels.scss +0 -3
  298. data/app/assets/stylesheets/alchemy/admin/pagination.scss +0 -92
  299. data/app/assets/stylesheets/alchemy/admin.scss +0 -42
  300. data/app/assets/stylesheets/alchemy/custom-properties.css +0 -98
  301. data/app/assets/stylesheets/alchemy/welcome.scss +0 -57
  302. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.css +0 -711
  303. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.css +0 -705
  304. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.inline.min.css +0 -7
  305. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.min.css +0 -7
  306. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.css +0 -29
  307. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/content.mobile.min.css +0 -7
  308. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.css +0 -677
  309. data/app/assets/stylesheets/tinymce/skins/ui/alchemy/skin.mobile.min.css +0 -7
  310. data/app/controllers/alchemy/elements_controller.rb +0 -32
  311. data/app/models/alchemy/element/dom_id.rb +0 -31
  312. data/app/models/alchemy/picture/calculations.rb +0 -49
  313. data/app/models/alchemy/picture/transformations.rb +0 -115
  314. data/app/views/alchemy/admin/attachments/destroy.js.erb +0 -1
  315. data/app/views/alchemy/admin/clipboard/clear.js.erb +0 -3
  316. data/app/views/alchemy/admin/clipboard/insert.js.erb +0 -29
  317. data/app/views/alchemy/admin/clipboard/remove.js.erb +0 -10
  318. data/app/views/alchemy/admin/resources/_filter.html.erb +0 -12
  319. data/app/views/alchemy/admin/resources/_resource.html.erb +0 -34
  320. data/app/views/alchemy/admin/resources/_table.html.erb +0 -29
  321. data/app/views/alchemy/elements/show.html.erb +0 -1
  322. data/app/views/alchemy/elements/show.js.erb +0 -1
  323. data/app/views/alchemy/ingredients/_audio_view.html.erb +0 -1
  324. data/app/views/alchemy/ingredients/_boolean_view.html.erb +0 -1
  325. data/app/views/alchemy/ingredients/_datetime_view.html.erb +0 -3
  326. data/app/views/alchemy/ingredients/_file_view.html.erb +0 -4
  327. data/app/views/alchemy/ingredients/_headline_view.html.erb +0 -4
  328. data/app/views/alchemy/ingredients/_html_view.html.erb +0 -1
  329. data/app/views/alchemy/ingredients/_link_view.html.erb +0 -4
  330. data/app/views/alchemy/ingredients/_node_view.html.erb +0 -1
  331. data/app/views/alchemy/ingredients/_page_view.html.erb +0 -1
  332. data/app/views/alchemy/ingredients/_picture_view.html.erb +0 -4
  333. data/app/views/alchemy/ingredients/_richtext_view.html.erb +0 -3
  334. data/app/views/alchemy/ingredients/_select_view.html.erb +0 -1
  335. data/app/views/alchemy/ingredients/_text_view.html.erb +0 -4
  336. data/app/views/alchemy/ingredients/_video_view.html.erb +0 -3
  337. data/babel.config.js +0 -12
  338. data/config/initializers/assets.rb +0 -4
  339. data/lib/alchemy/config.rb +0 -114
  340. data/lib/alchemy/element_definition.rb +0 -73
  341. data/lib/alchemy/page_layout.rb +0 -73
  342. data/lib/alchemy/resource_filter.rb +0 -40
  343. data/lib/alchemy/upgrader/seven_point_four.rb +0 -26
  344. data/lib/alchemy/upgrader/seven_point_three.rb +0 -52
  345. data/lib/generators/alchemy/ingredient/templates/view.html.erb +0 -1
  346. data/lib/generators/alchemy/install/files/alchemy_admin.js +0 -1
  347. data/lib/generators/alchemy/install/files/all.js +0 -11
  348. data/lib/generators/alchemy/install/files/article.css +0 -25
  349. data/vendor/assets/images/remixicon.symbol.svg +0 -11
  350. /data/app/{assets/stylesheets → stylesheets}/alchemy/_fonts.scss +0 -0
  351. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachment-select.scss +0 -0
  352. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/attachments.scss +0 -0
  353. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/flash.scss +0 -0
  354. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/list_filter.scss +0 -0
  355. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/node-select.scss +0 -0
  356. /data/app/{assets/stylesheets → stylesheets}/alchemy/admin/spinner.scss +0 -0
  357. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/skintool.json +0 -0
  358. /data/app/{assets/stylesheets → stylesheets}/tinymce/skins/ui/alchemy/fonts/tinymce-mobile.woff +0 -0
@@ -0,0 +1,153 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import SVGSpriter from "svg-sprite"
4
+ import { consola } from "consola"
5
+
6
+ const icons = [
7
+ "Arrows/arrow-down-line",
8
+ "Arrows/arrow-down-s-line",
9
+ "Arrows/arrow-left-right-line",
10
+ "Arrows/arrow-left-s-line",
11
+ "Arrows/arrow-left-wide-line",
12
+ "Arrows/arrow-right-s-line",
13
+ "Arrows/arrow-right-wide-line",
14
+ "Arrows/arrow-up-line",
15
+ "Arrows/contract-right-line",
16
+ "Arrows/contract-up-down-line",
17
+ "Arrows/expand-left-line",
18
+ "Arrows/expand-right-line",
19
+ "Arrows/skip-left-line",
20
+ "Arrows/skip-right-line",
21
+ "Buildings/home-2-line",
22
+ "Business/archive-drawer-line",
23
+ "Business/bookmark-fill",
24
+ "Business/bookmark-line",
25
+ "Business/calendar-line",
26
+ "Business/cloud-line",
27
+ "Business/cloud-off-line",
28
+ "Business/global-line",
29
+ "Business/mail-line",
30
+ "Business/profile-line",
31
+ "Business/shake-hands-line",
32
+ "Business/stack-line",
33
+ "Business/window-line",
34
+ "Design/crop-line",
35
+ "Design/edit-line",
36
+ "Design/eraser-line",
37
+ "Design/palette-line",
38
+ "Design/pencil-ruler-2-line",
39
+ "Design/scissors-cut-line",
40
+ "Design/table-line",
41
+ "Development/bug-line",
42
+ "Device/computer-line",
43
+ "Document/article-line",
44
+ "Document/book-3-line",
45
+ "Document/clipboard-fill",
46
+ "Document/clipboard-line",
47
+ "Document/file-3-line",
48
+ "Document/file-add-line",
49
+ "Document/file-cloud-line",
50
+ "Document/file-copy-line",
51
+ "Document/file-edit-line",
52
+ "Document/file-excel-2-line",
53
+ "Document/file-forbid-line",
54
+ "Document/file-image-line",
55
+ "Document/file-line",
56
+ "Document/file-music-line",
57
+ "Document/file-pdf-2-line",
58
+ "Document/file-ppt-2-line",
59
+ "Document/file-text-line",
60
+ "Document/file-upload-line",
61
+ "Document/file-video-line",
62
+ "Document/file-word-2-line",
63
+ "Document/file-zip-line",
64
+ "Document/folder-line",
65
+ "Document/folder-open-line",
66
+ "Document/newspaper-line",
67
+ "Document/pages-line",
68
+ "Editor/draggable",
69
+ "Editor/link-m",
70
+ "Editor/link-unlink-m",
71
+ "Editor/sort-asc",
72
+ "Editor/sort-desc",
73
+ "Editor/translate-2",
74
+ "Finance/price-tag-3-line",
75
+ "Finance/shopping-cart-line",
76
+ "Finance/ticket-line",
77
+ "Media/camera-line",
78
+ "Media/image-add-line",
79
+ "Media/image-line",
80
+ "System/add-line",
81
+ "System/alert-line",
82
+ "System/check-line",
83
+ "System/checkbox-multiple-line",
84
+ "System/close-line",
85
+ "System/delete-bin-2-line",
86
+ "System/download-2-line",
87
+ "System/external-link-line",
88
+ "System/information-line",
89
+ "System/lock-line",
90
+ "System/lock-unlock-line",
91
+ "System/logout-box-r-line",
92
+ "System/menu-2-line",
93
+ "System/menu-add-line",
94
+ "System/menu-fold-line",
95
+ "System/menu-unfold-line",
96
+ "System/more-line",
97
+ "System/more-2-line",
98
+ "System/prohibited-line",
99
+ "System/question-line",
100
+ "System/refresh-line",
101
+ "System/search-line",
102
+ "System/settings-3-line",
103
+ "System/upload-2-line",
104
+ "System/upload-cloud-2-line",
105
+ "System/zoom-in-line",
106
+ "System/zoom-out-line",
107
+ "User & Faces/group-line",
108
+ "User & Faces/user-fill",
109
+ "User & Faces/user-line",
110
+ "User & Faces/robot-2-line"
111
+ ]
112
+
113
+ const config = {
114
+ dest: "app/assets/images/alchemy",
115
+ mode: {
116
+ symbol: {
117
+ dest: "",
118
+ sprite: "icons-sprite.svg"
119
+ }
120
+ },
121
+ shape: {
122
+ id: {
123
+ generator: (name) => {
124
+ const id = name.replace(".svg", "")
125
+ return `ri-${id}`
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ const spriter = new SVGSpriter(config)
132
+
133
+ consola.start(`Building svg sprite of ${icons.length} icons`)
134
+
135
+ icons.forEach((icon) => {
136
+ const name = icon.replace(/^.+\/(.+)$/, "$1")
137
+ consola.info(`Adding ${name}.svg`)
138
+ spriter.add(
139
+ path.resolve(`node_modules/remixicon/icons/${icon}.svg`),
140
+ `${name}.svg`,
141
+ fs.readFileSync(`node_modules/remixicon/icons/${icon}.svg`, "utf-8")
142
+ )
143
+ })
144
+
145
+ spriter.compile((error, result, _data) => {
146
+ if (error) consola.error(error)
147
+
148
+ for (const type of Object.values(result.symbol)) {
149
+ fs.mkdirSync(path.dirname(type.path), { recursive: true })
150
+ consola.success(`Writing ${type.path}`)
151
+ fs.writeFileSync(type.path, type.contents)
152
+ }
153
+ })
@@ -13,7 +13,7 @@ auto_logout_time: 30
13
13
  #
14
14
  # Enable/Disable page caching globally.
15
15
  #
16
- # NOTE: You can enable/disable page caching for single Alchemy::PageLayouts in the page_layout.yml file.
16
+ # NOTE: You can enable/disable page caching for single Alchemy::Definitions in the page_layout.yml file.
17
17
  #
18
18
  cache_pages: true
19
19
 
@@ -87,6 +87,7 @@ items_per_page: 15
87
87
  output_image_quality: 85
88
88
  preprocess_image_resize:
89
89
  image_output_format: original
90
+ sharpen_images: false
90
91
 
91
92
  # This is used by the seeder to create the default site.
92
93
  default_site:
@@ -110,7 +111,7 @@ default_language:
110
111
  #
111
112
  # ==== Options:
112
113
  #
113
- # page_layout_name: [String] # A +Alchemy::PageLayout+ name. Used to render the contactform on a page with this layout.
114
+ # page_layout_name: [String] # A +Alchemy::PageDefinition+ name. Used to render the contactform on a page with this layout.
114
115
  # fields: [Array] # An Array of fieldnames.
115
116
  # validate_fields: [Array] # An Array of fieldnames to be validated on presence.
116
117
  #
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dragonfly_svg"
4
3
  require "alchemy/dragonfly/processors/crop_resize"
5
4
  require "alchemy/dragonfly/processors/auto_orient"
6
5
  require "alchemy/dragonfly/processors/thumbnail"
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Mime::Type.register "image/svg+xml", :svg
4
+ Mime::Type.register "image/webp", :webp
@@ -89,6 +89,7 @@ en:
89
89
  image/tiff: TIFF Image
90
90
  image/x-psd: Photoshop File
91
91
  image/svg+xml: SVG Image
92
+ image/webp: WebP Image
92
93
  text/plain: Plain Text Document
93
94
  text/x-vcard: vCard
94
95
  video/mp4: MPEG-4 Video
@@ -104,41 +105,57 @@ en:
104
105
  filters:
105
106
  page:
106
107
  by_page_layout:
108
+ all: All page types
107
109
  name: Page Type
108
110
  status:
111
+ all: Do not filter
109
112
  name: Status
110
113
  values:
111
114
  not_public: Unpublished
112
115
  published: Published
113
116
  restricted: Restricted
117
+ not_public:
118
+ name: Unpublished
119
+ published:
120
+ name: Published
121
+ restricted:
122
+ name: Restricted
123
+ updated_at_lteq:
124
+ name: Updated before
125
+ updated_at_gteq:
126
+ name: Updated after
114
127
  picture:
115
128
  by_file_format:
129
+ all: Show all file types
116
130
  name: File Type
117
131
  values:
132
+ <<: *mime_types
118
133
  gif: GIF Image
119
134
  jpeg: JPG Image
120
135
  png: PNG Image
121
136
  svg: SVG Image
122
137
  tiff: TIFF Image
123
138
  webp: WebP Image
124
- misc:
125
- name: Miscellaneous
126
- values:
127
- last_upload: Last upload only
128
- recent: Recently uploaded only
129
- without_tag: Without tag
130
- deletable: Not linked by file content
139
+ last_upload:
140
+ name: Last upload only
141
+ recent:
142
+ name: Recently uploaded only
143
+ without_tag:
144
+ name: Without tag
145
+ deletable:
146
+ name: Not linked by file content
131
147
  attachment:
132
148
  by_file_type:
133
149
  name: File Type
134
150
  values:
135
151
  <<: *mime_types
136
- misc:
137
- name: Miscellaneous
138
- values:
139
- last_upload: Last upload only
140
- recent: Recently uploaded only
141
- without_tag: Without tag
152
+ all: Show all file types
153
+ last_upload:
154
+ name: Last upload only
155
+ recent:
156
+ name: Recently uploaded only
157
+ without_tag:
158
+ name: Without tag
142
159
 
143
160
  default_ingredient_texts:
144
161
  lorem: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
@@ -681,7 +698,7 @@ en:
681
698
  time:
682
699
  formats:
683
700
  alchemy:
684
- default: "%m.%d.%Y %H:%M"
701
+ default: "%Y-%m-%d %H:%M"
685
702
  ingredient_date: "%Y-%m-%d"
686
703
  page_status: "%m.%d.%Y %H:%M"
687
704
  short_datetime: "%d %b %H:%M"
@@ -719,6 +736,7 @@ en:
719
736
  attributes:
720
737
  image_file:
721
738
  blank: "Please attach a picture."
739
+ too_big: must not be larger than %{maximum}MB
722
740
  alchemy/user:
723
741
  attributes:
724
742
  email:
data/config/routes.rb CHANGED
@@ -68,7 +68,6 @@ Alchemy::Engine.routes.draw do
68
68
 
69
69
  resources :attachments, except: [:new] do
70
70
  member do
71
- get :download
72
71
  put :assign
73
72
  end
74
73
  end
@@ -114,7 +113,6 @@ Alchemy::Engine.routes.draw do
114
113
  as: :show_attachment
115
114
 
116
115
  resources :messages, only: [:index, :new, :create]
117
- resources :elements, only: :show
118
116
 
119
117
  namespace :api, defaults: {format: "json"} do
120
118
  resources :attachments, only: [:index]
@@ -0,0 +1,7 @@
1
+ class AddUniqueIndexToPictureDescriptions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_index :alchemy_picture_descriptions, [:picture_id, :language_id],
4
+ name: "alchemy_picture_descriptions_on_picture_id_and_language_id",
5
+ unique: true
6
+ end
7
+ end
data/eslint.config.js CHANGED
@@ -1,5 +1,6 @@
1
- module.exports = [
1
+ export default [
2
2
  {
3
+ ignores: ["spec/**/*"],
3
4
  rules: {
4
5
  "no-restricted-imports": [
5
6
  "error",
@@ -41,7 +41,6 @@ module Alchemy
41
41
 
42
42
  def url_for(page)
43
43
  @preview_config = preview_config_for(page)
44
-
45
44
  if @preview_config && uri
46
45
  uri_class.build(
47
46
  host: uri.host,
@@ -60,10 +59,10 @@ module Alchemy
60
59
  attr_reader :routes
61
60
 
62
61
  def preview_config_for(page)
63
- preview_config = Alchemy::Config.get(:preview)
62
+ preview_config = Alchemy.config.preview
64
63
  return unless preview_config
65
64
 
66
- preview_config[page.site.name] || preview_config
65
+ preview_config.for_site(page.site) || preview_config
67
66
  end
68
67
 
69
68
  def uri
@@ -81,8 +80,8 @@ module Alchemy
81
80
  end
82
81
 
83
82
  def userinfo
84
- auth = @preview_config["auth"]
85
- auth ? "#{auth["username"]}:#{auth["password"]}" : nil
83
+ auth = @preview_config.auth
84
+ auth.username ? "#{auth["username"]}:#{auth["password"]}" : nil
86
85
  end
87
86
  end
88
87
  end
@@ -14,15 +14,12 @@ module Alchemy
14
14
  def dependencies
15
15
  case @name.to_s
16
16
  when /^alchemy\/pages\/show/
17
- PageLayout.all.map { |p| "alchemy/page_layouts/_#{p["name"]}" }
17
+ PageDefinition.all.map { "alchemy/page_layouts/_#{_1.name}" }
18
18
  when /^alchemy\/page_layouts\/_(\w+)/
19
- page_layout = PageLayout.get($1)
20
- layout_elements = page_layout.fetch("elements", [])
21
- layout_elements.map { |name| "alchemy/elements/_#{name}" }
19
+ page_definition = PageDefinition.get($1)
20
+ page_definition.elements.map { "alchemy/elements/_#{_1}" }
22
21
  when /^alchemy\/elements\/_(\w+)/
23
- ingredient_types($1).map { |type|
24
- "alchemy/ingredients/_#{type.underscore}_view"
25
- }.uniq
22
+ ingredient_types($1).map { "alchemy/ingredients/_#{_1.underscore}_view" }.tap(&:uniq!)
26
23
  else
27
24
  ActionView::DependencyTracker::ERBTracker.call(@name, @template)
28
25
  end
@@ -31,10 +28,10 @@ module Alchemy
31
28
  private
32
29
 
33
30
  def ingredient_types(name)
34
- element = Element.definitions.detect { |e| e["name"] == name }
31
+ element = Element.definitions.detect { _1.name == name }
35
32
  return [] unless element
36
33
 
37
- element.fetch("ingredients", []).collect { |c| c["type"] }
34
+ element.ingredients.map(&:type)
38
35
  end
39
36
  end
40
37
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module ConfigMissing
5
+ def const_missing(missing_const_name)
6
+ if missing_const_name == :Config
7
+ Alchemy::Deprecation.warn("Alchemy::Config is deprecated. Use Alchemy.config instead.")
8
+ Alchemy.config
9
+ else
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class Configuration
5
+ class BaseOption
6
+ def self.value_class
7
+ raise NotImplementedError
8
+ end
9
+
10
+ def initialize(value:, name:, **args)
11
+ @name = name
12
+ @value = validate(value) unless value.nil?
13
+ end
14
+ attr_reader :name, :value
15
+
16
+ private
17
+
18
+ def validate(value)
19
+ raise TypeError, "#{name} must be set as a #{self.class.value_class.name}, given #{value.inspect}" unless value.is_a?(self.class.value_class)
20
+ value
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/base_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class BooleanOption < BaseOption
8
+ private
9
+
10
+ def validate(value)
11
+ raise TypeError, "#{name} must be a Boolean, given #{value.inspect}" unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
12
+ value
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/base_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class ClassOption < BaseOption
8
+ def self.value_class
9
+ String
10
+ end
11
+
12
+ def value = @value.constantize
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/base_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class ClassSetOption < BaseOption
8
+ include Enumerable
9
+
10
+ def value = self
11
+
12
+ def <<(klass)
13
+ @value << klass.to_s
14
+ end
15
+
16
+ def concat(klasses)
17
+ klasses.each do |klass|
18
+ self << klass
19
+ end
20
+
21
+ self
22
+ end
23
+
24
+ delegate :clear, :empty?, to: :@value
25
+
26
+ def delete(object)
27
+ @value.delete(object.to_s)
28
+ end
29
+
30
+ def each
31
+ @value.each do |klass|
32
+ yield klass.constantize
33
+ end
34
+ end
35
+
36
+ def as_json = @value
37
+
38
+ private
39
+
40
+ def validate(value)
41
+ raise TypeError, "each #{name} must be set as a String" unless value.all? { _1.is_a?(String) }
42
+ value
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/list_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class IntegerListOption < ListOption
8
+ def self.item_class
9
+ Integer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/base_option"
4
+ module Alchemy
5
+ class Configuration
6
+ class IntegerOption < BaseOption
7
+ def self.value_class
8
+ Integer
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/base_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class ListOption < BaseOption
8
+ def self.item_class
9
+ raise NotImplementedError
10
+ end
11
+
12
+ private
13
+
14
+ def validate(value)
15
+ unless value.is_a?(Array) && value.all? { _1.is_a?(self.class.item_class) }
16
+ raise TypeError, "#{@name} must be an Array of #{self.class.item_class.name.downcase.pluralize}, given #{value.inspect}"
17
+ end
18
+ value
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class Configuration
5
+ class RegexpOption < BaseOption
6
+ def self.value_class
7
+ Regexp
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "alchemy/configuration/list_option"
4
+
5
+ module Alchemy
6
+ class Configuration
7
+ class StringListOption < ListOption
8
+ def self.item_class
9
+ String
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class Configuration
5
+ class StringOption < BaseOption
6
+ def self.value_class
7
+ String
8
+ end
9
+ end
10
+ end
11
+ end