spree_page_builder 5.3.0.rc1

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 (219) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +43 -0
  3. data/Rakefile +18 -0
  4. data/app/controllers/concerns/spree/admin/page_builder_concern.rb +45 -0
  5. data/app/controllers/concerns/spree/admin/storefront_breadcrumb_concern.rb +12 -0
  6. data/app/controllers/spree/admin/page_blocks_controller.rb +58 -0
  7. data/app/controllers/spree/admin/page_links_controller.rb +60 -0
  8. data/app/controllers/spree/admin/page_sections_controller.rb +82 -0
  9. data/app/controllers/spree/admin/pages_controller.rb +39 -0
  10. data/app/controllers/spree/admin/storefront_controller.rb +41 -0
  11. data/app/controllers/spree/admin/themes_controller.rb +87 -0
  12. data/app/helpers/spree/admin/page_builder_helper.rb +125 -0
  13. data/app/helpers/spree/admin/themes_helper.rb +9 -0
  14. data/app/jobs/spree/page_builder/products/touch_taxons_job_decorator.rb +15 -0
  15. data/app/jobs/spree/themes/duplicate_components_job.rb +59 -0
  16. data/app/jobs/spree/themes/screenshot_job.rb +81 -0
  17. data/app/models/concerns/spree/has_page_links.rb +53 -0
  18. data/app/models/spree/page.rb +188 -0
  19. data/app/models/spree/page_block.rb +73 -0
  20. data/app/models/spree/page_blocks/buttons.rb +29 -0
  21. data/app/models/spree/page_blocks/heading.rb +18 -0
  22. data/app/models/spree/page_blocks/image.rb +20 -0
  23. data/app/models/spree/page_blocks/link.rb +21 -0
  24. data/app/models/spree/page_blocks/mega_nav.rb +33 -0
  25. data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +32 -0
  26. data/app/models/spree/page_blocks/metafields.rb +18 -0
  27. data/app/models/spree/page_blocks/nav.rb +15 -0
  28. data/app/models/spree/page_blocks/newsletter_form.rb +18 -0
  29. data/app/models/spree/page_blocks/products/brand.rb +15 -0
  30. data/app/models/spree/page_blocks/products/buy_buttons.rb +24 -0
  31. data/app/models/spree/page_blocks/products/description.rb +18 -0
  32. data/app/models/spree/page_blocks/products/price.rb +18 -0
  33. data/app/models/spree/page_blocks/products/quantity_selector.rb +20 -0
  34. data/app/models/spree/page_blocks/products/share.rb +8 -0
  35. data/app/models/spree/page_blocks/products/title.rb +19 -0
  36. data/app/models/spree/page_blocks/products/variant_picker.rb +13 -0
  37. data/app/models/spree/page_blocks/subheading.rb +17 -0
  38. data/app/models/spree/page_blocks/text.rb +16 -0
  39. data/app/models/spree/page_builder/policy_decorator.rb +17 -0
  40. data/app/models/spree/page_builder/post_decorator.rb +17 -0
  41. data/app/models/spree/page_builder/product_decorator.rb +17 -0
  42. data/app/models/spree/page_builder/store_decorator.rb +46 -0
  43. data/app/models/spree/page_builder/taxon_decorator.rb +45 -0
  44. data/app/models/spree/page_link.rb +60 -0
  45. data/app/models/spree/page_section.rb +222 -0
  46. data/app/models/spree/page_sections/announcement_bar.rb +28 -0
  47. data/app/models/spree/page_sections/breadcrumbs.rb +12 -0
  48. data/app/models/spree/page_sections/collection_banner.rb +18 -0
  49. data/app/models/spree/page_sections/custom_code.rb +11 -0
  50. data/app/models/spree/page_sections/featured_posts.rb +45 -0
  51. data/app/models/spree/page_sections/featured_product.rb +50 -0
  52. data/app/models/spree/page_sections/featured_taxon.rb +90 -0
  53. data/app/models/spree/page_sections/featured_taxons.rb +45 -0
  54. data/app/models/spree/page_sections/footer.rb +101 -0
  55. data/app/models/spree/page_sections/header.rb +62 -0
  56. data/app/models/spree/page_sections/image_banner.rb +55 -0
  57. data/app/models/spree/page_sections/image_with_text.rb +65 -0
  58. data/app/models/spree/page_sections/main_password_footer.rb +18 -0
  59. data/app/models/spree/page_sections/main_password_header.rb +20 -0
  60. data/app/models/spree/page_sections/newsletter.rb +54 -0
  61. data/app/models/spree/page_sections/page_title.rb +19 -0
  62. data/app/models/spree/page_sections/post_details.rb +19 -0
  63. data/app/models/spree/page_sections/post_grid.rb +19 -0
  64. data/app/models/spree/page_sections/product_details.rb +53 -0
  65. data/app/models/spree/page_sections/product_grid.rb +13 -0
  66. data/app/models/spree/page_sections/related_products.rb +58 -0
  67. data/app/models/spree/page_sections/rich_text.rb +31 -0
  68. data/app/models/spree/page_sections/taxon_banner.rb +18 -0
  69. data/app/models/spree/page_sections/taxon_grid.rb +17 -0
  70. data/app/models/spree/page_sections/video.rb +107 -0
  71. data/app/models/spree/pages/account.rb +19 -0
  72. data/app/models/spree/pages/cart.rb +19 -0
  73. data/app/models/spree/pages/checkout.rb +15 -0
  74. data/app/models/spree/pages/custom.rb +38 -0
  75. data/app/models/spree/pages/homepage.rb +72 -0
  76. data/app/models/spree/pages/login.rb +19 -0
  77. data/app/models/spree/pages/password.rb +59 -0
  78. data/app/models/spree/pages/post.rb +27 -0
  79. data/app/models/spree/pages/post_list.rb +36 -0
  80. data/app/models/spree/pages/product_details.rb +30 -0
  81. data/app/models/spree/pages/search_results.rb +43 -0
  82. data/app/models/spree/pages/shop_all.rb +40 -0
  83. data/app/models/spree/pages/taxon.rb +29 -0
  84. data/app/models/spree/pages/taxon_list.rb +41 -0
  85. data/app/models/spree/pages/wishlist.rb +15 -0
  86. data/app/models/spree/theme.rb +233 -0
  87. data/app/models/spree/themes/default.rb +97 -0
  88. data/app/services/spree/taxons/touch_featured_sections.rb +21 -0
  89. data/app/views/layouts/spree/page_builder.html.erb +46 -0
  90. data/app/views/spree/admin/dashboard/_store_preview.html.erb +38 -0
  91. data/app/views/spree/admin/page_blocks/_form_tab_buttons.html.erb +5 -0
  92. data/app/views/spree/admin/page_blocks/create.turbo_stream.erb +4 -0
  93. data/app/views/spree/admin/page_blocks/destroy.turbo_stream.erb +9 -0
  94. data/app/views/spree/admin/page_blocks/edit.html.erb +43 -0
  95. data/app/views/spree/admin/page_blocks/forms/_brand.html.erb +15 -0
  96. data/app/views/spree/admin/page_blocks/forms/_brand_logo.html.erb +4 -0
  97. data/app/views/spree/admin/page_blocks/forms/_buttons.html.erb +13 -0
  98. data/app/views/spree/admin/page_blocks/forms/_heading.html.erb +28 -0
  99. data/app/views/spree/admin/page_blocks/forms/_image.html.erb +10 -0
  100. data/app/views/spree/admin/page_blocks/forms/_link.html.erb +19 -0
  101. data/app/views/spree/admin/page_blocks/forms/_mega_nav.html.erb +14 -0
  102. data/app/views/spree/admin/page_blocks/forms/_mega_nav_with_subcategories.html.erb +9 -0
  103. data/app/views/spree/admin/page_blocks/forms/_metafields.html.erb +35 -0
  104. data/app/views/spree/admin/page_blocks/forms/_nav.html.erb +6 -0
  105. data/app/views/spree/admin/page_blocks/forms/_newsletter_form.html.erb +20 -0
  106. data/app/views/spree/admin/page_blocks/forms/_price.html.erb +15 -0
  107. data/app/views/spree/admin/page_blocks/forms/_share.html.erb +5 -0
  108. data/app/views/spree/admin/page_blocks/forms/_subheading.html.erb +26 -0
  109. data/app/views/spree/admin/page_blocks/forms/_text.html.erb +21 -0
  110. data/app/views/spree/admin/page_blocks/forms/_title.html.erb +20 -0
  111. data/app/views/spree/admin/page_blocks/forms/_variant_picker.html.erb +10 -0
  112. data/app/views/spree/admin/page_blocks/forms/products/_buy_buttons.html.erb +10 -0
  113. data/app/views/spree/admin/page_blocks/forms/products/_description.html.erb +0 -0
  114. data/app/views/spree/admin/page_blocks/forms/products/_quantity_selector.html.erb +10 -0
  115. data/app/views/spree/admin/page_blocks/move_higher.turbo_stream.erb +4 -0
  116. data/app/views/spree/admin/page_blocks/move_lower.turbo_stream.erb +4 -0
  117. data/app/views/spree/admin/page_blocks/show.html.erb +1 -0
  118. data/app/views/spree/admin/page_blocks/update.turbo_stream.erb +6 -0
  119. data/app/views/spree/admin/page_builder/_add_block.html.erb +22 -0
  120. data/app/views/spree/admin/page_builder/_color_palette.html.erb +17 -0
  121. data/app/views/spree/admin/page_builder/_color_picker.html.erb +26 -0
  122. data/app/views/spree/admin/page_builder/_header.html.erb +113 -0
  123. data/app/views/spree/admin/page_builder/_labeled_range_input.html.erb +10 -0
  124. data/app/views/spree/admin/page_builder/_pages_dropdown.html.erb +17 -0
  125. data/app/views/spree/admin/page_builder/_range_input.html.erb +12 -0
  126. data/app/views/spree/admin/page_builder/_sidebar.html.erb +12 -0
  127. data/app/views/spree/admin/page_builder/_sidebar_block.html.erb +30 -0
  128. data/app/views/spree/admin/page_builder/_sidebar_colors.html.erb +86 -0
  129. data/app/views/spree/admin/page_builder/_sidebar_fonts.html.erb +85 -0
  130. data/app/views/spree/admin/page_builder/_sidebar_section.html.erb +44 -0
  131. data/app/views/spree/admin/page_builder/_sidebar_sections.html.erb +38 -0
  132. data/app/views/spree/admin/page_builder/_sidebar_sections_toolbar.html.erb +180 -0
  133. data/app/views/spree/admin/page_links/_form.html.erb +10 -0
  134. data/app/views/spree/admin/page_links/_linkable_type_dropdown.html.erb +15 -0
  135. data/app/views/spree/admin/page_links/_list.html.erb +36 -0
  136. data/app/views/spree/admin/page_links/_refresh_theme_preview.turbo_stream.erb +5 -0
  137. data/app/views/spree/admin/page_links/create.turbo_stream.erb +10 -0
  138. data/app/views/spree/admin/page_links/destroy.turbo_stream.erb +15 -0
  139. data/app/views/spree/admin/page_links/edit.html.erb +27 -0
  140. data/app/views/spree/admin/page_links/update.turbo_stream.erb +14 -0
  141. data/app/views/spree/admin/page_sections/_form_tab_buttons.html.erb +8 -0
  142. data/app/views/spree/admin/page_sections/create.turbo_stream.erb +11 -0
  143. data/app/views/spree/admin/page_sections/destroy.turbo_stream.erb +16 -0
  144. data/app/views/spree/admin/page_sections/edit.html.erb +39 -0
  145. data/app/views/spree/admin/page_sections/fields/_background_color.html.erb +6 -0
  146. data/app/views/spree/admin/page_sections/fields/_border_bottom_width.html.erb +5 -0
  147. data/app/views/spree/admin/page_sections/fields/_border_color.html.erb +7 -0
  148. data/app/views/spree/admin/page_sections/fields/_border_top_width.html.erb +6 -0
  149. data/app/views/spree/admin/page_sections/fields/_bottom_padding.html.erb +5 -0
  150. data/app/views/spree/admin/page_sections/fields/_button.html.erb +15 -0
  151. data/app/views/spree/admin/page_sections/fields/_header_layout.html.erb +26 -0
  152. data/app/views/spree/admin/page_sections/fields/_height.html.erb +6 -0
  153. data/app/views/spree/admin/page_sections/fields/_text_color.html.erb +7 -0
  154. data/app/views/spree/admin/page_sections/fields/_top_padding.html.erb +6 -0
  155. data/app/views/spree/admin/page_sections/forms/_announcement_bar.html.erb +5 -0
  156. data/app/views/spree/admin/page_sections/forms/_brand_story.html.erb +0 -0
  157. data/app/views/spree/admin/page_sections/forms/_breadcrumbs.html.erb +0 -0
  158. data/app/views/spree/admin/page_sections/forms/_collection_banner.html.erb +0 -0
  159. data/app/views/spree/admin/page_sections/forms/_custom_code.html.erb +4 -0
  160. data/app/views/spree/admin/page_sections/forms/_featured_posts.html.erb +33 -0
  161. data/app/views/spree/admin/page_sections/forms/_featured_product.html.erb +4 -0
  162. data/app/views/spree/admin/page_sections/forms/_featured_taxon.html.erb +59 -0
  163. data/app/views/spree/admin/page_sections/forms/_featured_taxons.html.erb +13 -0
  164. data/app/views/spree/admin/page_sections/forms/_footer.html.erb +20 -0
  165. data/app/views/spree/admin/page_sections/forms/_header.html.erb +12 -0
  166. data/app/views/spree/admin/page_sections/forms/_image_banner.html.erb +13 -0
  167. data/app/views/spree/admin/page_sections/forms/_image_with_text.html.erb +28 -0
  168. data/app/views/spree/admin/page_sections/forms/_main_password_footer.html.erb +9 -0
  169. data/app/views/spree/admin/page_sections/forms/_main_password_header.erb +13 -0
  170. data/app/views/spree/admin/page_sections/forms/_newsletter.html.erb +15 -0
  171. data/app/views/spree/admin/page_sections/forms/_page_title.html.erb +4 -0
  172. data/app/views/spree/admin/page_sections/forms/_post_details.html.erb +0 -0
  173. data/app/views/spree/admin/page_sections/forms/_post_grid.html.erb +0 -0
  174. data/app/views/spree/admin/page_sections/forms/_product_details.html.erb +1 -0
  175. data/app/views/spree/admin/page_sections/forms/_product_grid.html.erb +1 -0
  176. data/app/views/spree/admin/page_sections/forms/_related_products.html.erb +32 -0
  177. data/app/views/spree/admin/page_sections/forms/_rich_text.html.erb +0 -0
  178. data/app/views/spree/admin/page_sections/forms/_taxon_banner.html.erb +0 -0
  179. data/app/views/spree/admin/page_sections/forms/_taxon_grid.html.erb +5 -0
  180. data/app/views/spree/admin/page_sections/forms/_video.html.erb +15 -0
  181. data/app/views/spree/admin/page_sections/move_higher.turbo_stream.erb +7 -0
  182. data/app/views/spree/admin/page_sections/move_lower.turbo_stream.erb +7 -0
  183. data/app/views/spree/admin/page_sections/new.html.erb +26 -0
  184. data/app/views/spree/admin/page_sections/remove_attachment.turbo_stream.erb +4 -0
  185. data/app/views/spree/admin/page_sections/restore_design_settings_to_defaults.turbo_stream.erb +4 -0
  186. data/app/views/spree/admin/page_sections/show.html.erb +1 -0
  187. data/app/views/spree/admin/page_sections/update.turbo_stream.erb +10 -0
  188. data/app/views/spree/admin/pages/_form.html.erb +20 -0
  189. data/app/views/spree/admin/pages/_table_header.html.erb +6 -0
  190. data/app/views/spree/admin/pages/_table_row.html.erb +28 -0
  191. data/app/views/spree/admin/pages/edit.html.erb +13 -0
  192. data/app/views/spree/admin/pages/filters.html.erb +7 -0
  193. data/app/views/spree/admin/pages/index.html.erb +11 -0
  194. data/app/views/spree/admin/pages/new.html.erb +1 -0
  195. data/app/views/spree/admin/storefront/edit.html.erb +89 -0
  196. data/app/views/spree/admin/themes/_theme.html.erb +56 -0
  197. data/app/views/spree/admin/themes/_theme_preview_image.html.erb +17 -0
  198. data/app/views/spree/admin/themes/edit.html.erb +14 -0
  199. data/app/views/spree/admin/themes/index.html.erb +80 -0
  200. data/app/views/spree/admin/themes/update.turbo_stream.erb +1 -0
  201. data/config/initializers/spree_admin_navigation.rb +46 -0
  202. data/config/initializers/spree_admin_partials.rb +3 -0
  203. data/config/locales/en.yml +42 -0
  204. data/config/routes.rb +43 -0
  205. data/db/migrate/20250120094216_create_page_builder_models.rb +78 -0
  206. data/db/migrate/20250305121352_remove_page_builder_indices.rb +11 -0
  207. data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +7 -0
  208. data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +10 -0
  209. data/lib/generators/spree/page_builder/install/install_generator.rb +23 -0
  210. data/lib/spree/page_builder/engine.rb +185 -0
  211. data/lib/spree/page_builder/testing_support/factories/page_block_factory.rb +22 -0
  212. data/lib/spree/page_builder/testing_support/factories/page_factory.rb +33 -0
  213. data/lib/spree/page_builder/testing_support/factories/page_link_factory.rb +7 -0
  214. data/lib/spree/page_builder/testing_support/factories/page_section_factory.rb +27 -0
  215. data/lib/spree/page_builder/testing_support/factories/theme_factory.rb +14 -0
  216. data/lib/spree/page_builder/testing_support/factories.rb +3 -0
  217. data/lib/spree/page_builder.rb +4 -0
  218. data/lib/spree_page_builder.rb +1 -0
  219. metadata +288 -0
@@ -0,0 +1,28 @@
1
+ <div class="trix-container">
2
+ <%= f.rich_text_area :text, data: {
3
+ action: 'trix-change->auto-submit#submit'
4
+ }, class: 'mb-6' %>
5
+ </div>
6
+
7
+ <% content_for(:design_tab) do %>
8
+ <div class="form-group">
9
+ <%= f.label :preferred_size %>
10
+ <%= f.select :preferred_size, options_for_select(['small', 'medium', 'large'], @page_block.preferred_size), { }, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
11
+ </div>
12
+
13
+ <% unless @page_block.section.is_a? Spree::PageSections::Video %>
14
+ <div class="form-group">
15
+ <%= f.label :preferred_text_alignment %>
16
+ <%= f.select :preferred_text_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_text_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
17
+ </div>
18
+
19
+ <div class="form-group">
20
+ <%= f.label :preferred_container_alignment %>
21
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
22
+ </div>
23
+ <% end %>
24
+
25
+ <%= render 'spree/admin/page_builder/labeled_range_input',
26
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max heading width on desktop'
27
+ %>
28
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%= f.spree_file_field :asset, width: 512, height: 512, auto_submit: true %>
2
+ <%= f.spree_text_field :preferred_image_alt, label: Spree.t(:alt_text), data: { action: 'auto-submit#submit' } %>
3
+ <% content_for(:design_tab) do %>
4
+ <%= render 'spree/admin/page_builder/labeled_range_input',
5
+ f: f, field: :preferred_height, min: 1, max: 1024, unit: 'px', _label: 'Max image height on desktop'
6
+ %>
7
+ <%= render 'spree/admin/page_builder/labeled_range_input',
8
+ f: f, field: :preferred_mobile_height, min: 1, max: 512, unit: 'px', _label: 'Max image height on mobile'
9
+ %>
10
+ <% end %>
@@ -0,0 +1,19 @@
1
+ <%= f.fields_for :link do |lf| %>
2
+ <div class="form-group">
3
+ <%= lf.label :linkable_type, 'Link' %>
4
+ <%= lf.select :linkable_type, @page_block.allowed_linkable_types, { include_blank: false }, { class: 'form-select mb-6', data: { action: 'auto-submit#submit' } } %>
5
+ <div id="linkable_type_dropdown">
6
+ <%= render 'spree/admin/page_links/linkable_type_dropdown', page_link: lf.object, form_name: 'page_block[link_attributes]' %>
7
+ </div>
8
+ </div>
9
+
10
+ <div class="form-group">
11
+ <%= lf.label :label %>
12
+ <%= lf.text_field :label, class: 'form-input', data: { action: 'blur->auto-submit#submit' }, placeholder: 'eg. About us', required: true %>
13
+ </div>
14
+
15
+ <div class="custom-control form-checkbox mb-6">
16
+ <%= lf.check_box :open_in_new_tab, class: 'custom-control-input', data: { action: 'auto-submit#submit' } %>
17
+ <%= lf.label :open_in_new_tab, class: 'custom-control-label' %>
18
+ </div>
19
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <h5 class="font-bold"><%= Spree.t(:title_link) %></h5>
2
+ <%= render 'spree/admin/page_blocks/forms/link', f: f %>
3
+
4
+ <%= render 'spree/admin/page_links/list', parent: @page_block, show_add_link_button: true %>
5
+
6
+ <h5 class="font-bold"><%= Spree.t(:featured_taxon) %></h5>
7
+ <div class="form-group">
8
+ <%= tom_select_tag 'page_block[preferred_featured_taxon_id]',
9
+ active_option: @page_block.preferred_featured_taxon_id,
10
+ class: 'w-full',
11
+ url: spree.admin_taxons_select_options_path(format: :json),
12
+ select_data: { action: 'auto-submit#submit' },
13
+ include_blank: "" %>
14
+ </div>
@@ -0,0 +1,9 @@
1
+ <h5 class="font-bold"><%= Spree.t(:category) %></h5>
2
+ <div class="form-group">
3
+ <%= tom_select_tag 'page_block[preferred_taxon_id]', active_option: @page_block.preferred_taxon_id, class: 'w-full', url: spree.admin_taxons_select_options_path(format: :json), select_data: { action: 'auto-submit#submit' } %>
4
+ </div>
5
+
6
+ <h5 class="font-bold"><%= Spree.t(:featured_taxon) %></h5>
7
+ <div class="form-group">
8
+ <%= tom_select_tag 'page_block[preferred_featured_taxon_id]', active_option: @page_block.preferred_featured_taxon_id, class: 'w-full', url: spree.admin_taxons_select_options_path(format: :json), select_data: { action: 'auto-submit#submit' } %>
9
+ </div>
@@ -0,0 +1,35 @@
1
+ <div class="form-group">
2
+ <div class="mb-4">
3
+ <label class="form-label"><%= Spree.t(:metafields) %></label>
4
+ <div class="p-1 border rounded-lg flex flex-col gap-1 mb-6"
5
+ data-controller="sortable-auto-submit"
6
+ data-sortable-auto-submit-handle-value=".handle"
7
+ >
8
+ <%= hidden_field_tag "#{f.object_name}[preferred_metafield_definition_ids][]", "" %>
9
+ <% selected_keys = f.object.preferred_metafield_definition_ids.map(&:to_s) %>
10
+ <% sorted_definitions = f.object.available_metafield_definitions.sort_by { |definition| selected_keys.index(definition.id.to_s) || selected_keys.length } %>
11
+ <% sorted_definitions.each do |definition| %>
12
+ <div class="rounded-md hover:bg-gray-25 pl-4 pr-1 py-1 flex items-center justify-between"
13
+ id="<%= spree_dom_id(definition) %>"
14
+ >
15
+ <div class="custom-control form-checkbox grow flex">
16
+ <input type="checkbox"
17
+ class="custom-control-input"
18
+ name="<%= "#{f.object_name}[preferred_metafield_definition_ids][]" %>"
19
+ id="<%= "#{f.object_name}_preferred_metafield_definition_ids_#{definition.id}" %>"
20
+ value="<%= definition.id %>"
21
+ data-action="change->auto-submit#submit"
22
+ <%= 'checked' if selected_keys.include?(definition.id.to_s) %>>
23
+ <label class="custom-control-label grow" for="<%= "#{f.object_name}_preferred_metafield_definition_ids_#{definition.id}" %>" data-controller="tooltip">
24
+ <%= definition.name %>
25
+ <%= tooltip(definition.full_key) %>
26
+ </label>
27
+ </div>
28
+ <button class="btn btn-sm pr-0 handle hover:bg-gray-100 h-full mr-1 px-1" type="button">
29
+ <%= icon('grip-vertical', class: 'mr-0') %>
30
+ </button>
31
+ </div>
32
+ <% end %>
33
+ </div>
34
+ </div>
35
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="form-group">
2
+ <%= f.label :preferred_label %>
3
+ <%= f.text_field :preferred_label, data: { action: 'auto-submit#submit' }, class: 'form-input' %>
4
+ </div>
5
+
6
+ <%= render 'spree/admin/page_links/list', parent: @page_block, show_add_link_button: true %>
@@ -0,0 +1,20 @@
1
+ <div class="form-group">
2
+ <%= f.label :preferred_button_text %>
3
+ <%= f.text_field :preferred_button_text, data: { action: 'auto-submit#submit' }, class: 'form-input' %>
4
+ </div>
5
+
6
+ <div class="form-group">
7
+ <%= f.label :preferred_placeholder %>
8
+ <%= f.text_field :preferred_placeholder, data: { action: 'auto-submit#submit' }, class: 'form-input' %>
9
+ </div>
10
+
11
+ <% content_for(:design_tab) do %>
12
+ <div class="form-group">
13
+ <%= f.label :preferred_justify %>
14
+ <%= f.select :preferred_justify, options_for_select(['start', 'center', 'end'], @page_block.preferred_justify), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
15
+ </div>
16
+ <div class="form-group">
17
+ <%= f.label :preferred_button_style %>
18
+ <%= f.select :preferred_button_style, options_for_select(['primary', 'secondary'], @page_block.preferred_button_style), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
19
+ </div>
20
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <% content_for(:design_tab) do %>
2
+ <div class="form-group">
3
+ <%= f.label :preferred_text_alignment %>
4
+ <%= f.select :preferred_text_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_text_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
5
+ </div>
6
+
7
+ <div class="form-group">
8
+ <%= f.label :preferred_container_alignment %>
9
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
10
+ </div>
11
+
12
+ <%= render 'spree/admin/page_builder/labeled_range_input',
13
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max text width on desktop'
14
+ %>
15
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <div class="trix-container">
2
+ <%= f.rich_text_area :text, data: {
3
+ action: 'trix-change->auto-submit#submit'
4
+ }, class: 'mb-6' %>
5
+ </div>
@@ -0,0 +1,26 @@
1
+ <div class="trix-container">
2
+ <%= f.rich_text_area :text, data: {
3
+ action: 'trix-change->auto-submit#submit'
4
+ }, class: 'mb-6' %>
5
+ </div>
6
+
7
+ <% content_for(:design_tab) do %>
8
+ <div class="form-group">
9
+ <%= f.label :preferred_size %>
10
+ <%= f.select :preferred_size, options_for_select(['small', 'medium', 'large'], @page_block.preferred_size), { }, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
11
+ </div>
12
+
13
+ <div class="form-group">
14
+ <%= f.label :preferred_text_alignment %>
15
+ <%= f.select :preferred_text_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_text_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
16
+ </div>
17
+
18
+ <div class="form-group">
19
+ <%= f.label :preferred_container_alignment %>
20
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
21
+ </div>
22
+
23
+ <%= render 'spree/admin/page_builder/labeled_range_input',
24
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max subheading width on desktop'
25
+ %>
26
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <div class="trix-container">
2
+ <%= f.rich_text_area :text, data: {
3
+ action: 'trix-change->auto-submit#submit'
4
+ }, class: 'mb-6' %>
5
+ </div>
6
+
7
+ <% content_for(:design_tab) do %>
8
+ <div class="form-group">
9
+ <%= f.label :preferred_text_alignment %>
10
+ <%= f.select :preferred_text_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_text_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
11
+ </div>
12
+
13
+ <div class="form-group">
14
+ <%= f.label :preferred_container_alignment %>
15
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
16
+ </div>
17
+
18
+ <%= render 'spree/admin/page_builder/labeled_range_input',
19
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max text width on desktop'
20
+ %>
21
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <% content_for(:design_tab) do %>
2
+ <div class="form-group">
3
+ <%= f.label :preferred_size %>
4
+ <%= f.select :preferred_size, options_for_select(['small', 'medium', 'large'], @page_block.preferred_size), { }, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
5
+ </div>
6
+
7
+ <div class="form-group">
8
+ <%= f.label :preferred_text_alignment %>
9
+ <%= f.select :preferred_text_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_text_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
10
+ </div>
11
+
12
+ <div class="form-group">
13
+ <%= f.label :preferred_container_alignment %>
14
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
15
+ </div>
16
+
17
+ <%= render 'spree/admin/page_builder/labeled_range_input',
18
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%',_label: 'Max heading width on desktop'
19
+ %>
20
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <% content_for(:design_tab) do %>
2
+ <div class="form-group">
3
+ <%= f.label :preferred_container_alignment %>
4
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
5
+ </div>
6
+
7
+ <%= render 'spree/admin/page_builder/labeled_range_input',
8
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max text width on desktop'
9
+ %>
10
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <% content_for(:design_tab) do %>
2
+ <div class="form-group">
3
+ <%= f.label :preferred_container_alignment %>
4
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
5
+ </div>
6
+
7
+ <%= render 'spree/admin/page_builder/labeled_range_input',
8
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max text width on desktop'
9
+ %>
10
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <% content_for(:design_tab) do %>
2
+ <div class="form-group">
3
+ <%= f.label :preferred_container_alignment %>
4
+ <%= f.select :preferred_container_alignment, options_for_select(['left', 'center', 'right'], @page_block.preferred_container_alignment), {}, { class: 'form-select', data: { action: 'auto-submit#submit' } } %>
5
+ </div>
6
+
7
+ <%= render 'spree/admin/page_builder/labeled_range_input',
8
+ f: f, field: :preferred_width_desktop, min: 1, max: 100, unit: '%', _label: 'Max text width on desktop'
9
+ %>
10
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <%= turbo_stream.replace dom_id(@page_block.section) do %>
2
+ <%= render 'spree/admin/page_builder/sidebar_section', section: @page_block.section %>
3
+ <% end %>
4
+ <%= refresh_theme_preview %>
@@ -0,0 +1,4 @@
1
+ <%= turbo_stream.replace dom_id(@page_block.section) do %>
2
+ <%= render 'spree/admin/page_builder/sidebar_section', section: @page_block.section %>
3
+ <% end %>
4
+ <%= refresh_theme_preview %>
@@ -0,0 +1 @@
1
+ <%= render 'spree/admin/page_builder/sidebar_block', block: @page_block %>
@@ -0,0 +1,6 @@
1
+ <%= refresh_theme_preview(@page_block.section, @page_block) %>
2
+ <% if @page_block.respond_to?(:link) %>
3
+ <%= turbo_stream.update :linkable_type_dropdown do %>
4
+ <%= render 'spree/admin/page_links/linkable_type_dropdown', page_link: @page_block.link, form_name: 'page_block[link_attributes]' %>
5
+ <% end %>
6
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <%= form_for section.blocks.new, url: spree.admin_page_section_blocks_path(section), html: { class: 'list-group-item sidebar-page-block px-0 py-1 border-0 rounded'}, data: { controller: 'block-form', block_form_target: :form } do |f| %>
2
+ <%= f.hidden_field :type, data: { block_form_target: 'type' } %>
3
+
4
+ <%= dropdown portal: false do %>
5
+ <%= dropdown_toggle class: 'btn-sm btn-secondary flex-inline' do %>
6
+ <%= icon("circle-plus") %>
7
+ <%= Spree.t(:add_page_block) %>
8
+ <% end %>
9
+ <%= dropdown_menu do %>
10
+ <% section.available_blocks_to_add.each do |block_class| %>
11
+ <a href="#" class="dropdown-item btn-sm"
12
+ data-action="click->block-form#addBlock"
13
+ data-block-form-type-param="<%= block_class %>"
14
+ >
15
+ <% block_instance = block_class.new %>
16
+ <%= icon block_instance.icon_name, height: 18, class: 'mr-2' if block_class.new.icon_name.present? %>
17
+ <%= block_instance.display_name.presence || block_class.to_s.demodulize.titleize %>
18
+ </a>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
22
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <% active ||= false %>
2
+ <div
3
+ data-action="click->color-palette#selectPalette"
4
+ data-color-palette-primary-color-param="<%= primary_color %>"
5
+ data-color-palette-text-color-param="<%= text_color %>"
6
+ data-color-palette-button-text-color-param="<%= button_text_color %>"
7
+ data-color-palette-border-color-param="<%= border_color %>"
8
+ data-color-palette-background-color-param="<%= background_color %>"
9
+ class="mb-4 block w-full rounded-lg overflow-hidden border cursor-pointer <% if active %>border-2 border-primary<% end %>" style="height: 40px">
10
+ <div class="row mx-0 h-full">
11
+ <div class="col" style="background-color: <%= primary_color %>"></div>
12
+ <div class="col" style="background-color: <%= text_color %>"></div>
13
+ <div class="col" style="background-color: <%= button_text_color %>"></div>
14
+ <div class="col" style="background-color: <%= border_color %>"></div>
15
+ <div class="col" style="background-color: <%= background_color %>"></div>
16
+ </div>
17
+ </div>
@@ -0,0 +1,26 @@
1
+ <% color_picker_value ||= value || @theme_preview&.try(:send, field) %>
2
+
3
+ <div
4
+ class="mb-4 form-group"
5
+ data-controller="color-picker"
6
+ data-color-picker-clear-value="<%= defined?(clear) ? clear : false %>"
7
+ data-color-picker-default-color-value="<%= color_picker_value %>">
8
+ <div class="flex items-center">
9
+ <%= f.hidden_field field, class: 'form-input mr-1', data: {
10
+ 'color-picker-target': 'input',
11
+ 'color-palette-target': field.to_s.camelize(:lower),
12
+ action: action,
13
+ }, value: value %>
14
+ <div>
15
+ <label class="mb-0"><%= label %></label>
16
+ <br />
17
+ <span data-color-picker-target="value" class="text-gray-600">
18
+ <%= color_picker_value&.upcase || Spree.t('admin.page_builder.not_set') %>
19
+ </span>
20
+ </div>
21
+ <div class="ml-auto flex items-center" style="width:40px">
22
+ <div data-color-picker-target="picker" class="border inline-block rounded-full <% unless color_picker_value.present? %>checkered-background<% end %>" style="height: 40px;width: 40px; background-color: <%= color_picker_value %>;">
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
@@ -0,0 +1,113 @@
1
+ <header id="page-builder-header" class="fixed-top">
2
+ <nav class="navbar navbar-expand-lg">
3
+ <div data-controller="tooltip">
4
+ <% back_url = @page.custom? ? spree.admin_pages_path : spree.admin_themes_path %>
5
+ <%= link_to back_url, class: 'btn hover:bg-gray-100 shadow-none px-2' do %>
6
+ <%= icon('x', class: 'mr-0') %>
7
+ <% end %>
8
+ <%= tooltip(Spree.t('admin.back_to_dashboard')) %>
9
+ </div>
10
+ <% if @page.custom? %>
11
+ <div class="px-3">
12
+ <span class="text-gray-600 mr-1"><%= I18n.t('activerecord.models.spree/page.one') %>:</span>
13
+ <strong><%= @page.display_name %></strong>
14
+ </div>
15
+
16
+ <%= link_to_with_icon 'settings', Spree.t(:settings), spree.edit_admin_page_path(@page.id), class: 'btn btn-light', data: { turbo_frame: 'dialog', action: 'dialog#open' } %>
17
+ <% else %>
18
+ <div class="px-3">
19
+ <span class="text-gray-600 mr-1"><%= Spree.t(:theme) %>:</span>
20
+ <strong class="mr-1"><%= @theme.name %></strong>
21
+ &nbsp;
22
+ <% if @theme.default? %>
23
+ <span class="badge badge-success">
24
+ <%= icon('check') %>
25
+ <%= Spree.t(:live) %>
26
+ </span>
27
+ <% else %>
28
+ <span class="badge badge-warning">
29
+ <%= Spree.t(:draft) %>
30
+ </span>
31
+ <% end %>
32
+ </div>
33
+ <%= render 'spree/admin/page_builder/pages_dropdown' %>
34
+
35
+ <ul class="nav nav-pills" role="tablist">
36
+ <li class="nav-item" role="presentation">
37
+ <button class="nav-link active"
38
+ data-controller="tooltip"
39
+ data-tabs-target="tab"
40
+ data-action="click->tabs#select"
41
+ type="button"
42
+ role="tab"
43
+ aria-controls="sections"
44
+ aria-selected="true"
45
+ data-trigger="hover"
46
+ id="sidebar-icon-page">
47
+ <%= icon 'section', class: 'mr-0' %>
48
+ <%= tooltip("Page sections") %>
49
+ </button>
50
+ </li>
51
+ <li class="nav-item" role="presentation">
52
+ <button class="nav-link"
53
+ data-controller="tooltip"
54
+ data-tabs-target="tab"
55
+ data-action="click->tabs#select"
56
+ type="button"
57
+ role="tab"
58
+ aria-controls="theme"
59
+ aria-selected="false"
60
+ data-trigger="hover"
61
+ id="sidebar-icon-colors">
62
+ <%= icon 'palette', class: 'mr-0' %>
63
+ <%= tooltip(Spree.t(:theme)) %>
64
+ </button>
65
+ </li>
66
+ <li class="nav-item" role="presentation">
67
+ <button class="nav-link"
68
+ data-controller="tooltip"
69
+ type="button"
70
+ data-tabs-target="tab"
71
+ data-action="click->tabs#select"
72
+ type="button"
73
+ role="tab"
74
+ aria-controls="fonts"
75
+ aria-selected="false"
76
+ data-trigger="hover"
77
+ id="sidebar-icon-fonts">
78
+ <%= icon 'typography', class: 'mr-0' %>
79
+ <%= tooltip("Fonts") %>
80
+ </button>
81
+ </li>
82
+ </ul>
83
+ <% end %>
84
+
85
+ <ul class="nav nav-pills ml-auto" role="tablist">
86
+ <li class="nav-item" role="presentation">
87
+ <button class="nav-link" type="button"
88
+ data-controller="tooltip"
89
+ data-trigger="hover"
90
+ data-action="click->page-builder#setResponsiveBreakpoint"
91
+ data-page-builder-target="mobileButton"
92
+ data-page-builder-breakpoint-param="mobile">
93
+ <%= icon 'device-mobile', class: 'mr-0' %>
94
+ <%= tooltip("Mobile") %>
95
+ </button>
96
+ </li>
97
+ <li class="nav-item" role="presentation">
98
+ <button class="nav-link active" type="button"
99
+ data-controller="tooltip"
100
+ data-action="click->page-builder#setResponsiveBreakpoint"
101
+ data-page-builder-breakpoint-param="desktop"
102
+ data-trigger="hover"
103
+ data-page-builder-target="desktopButton">
104
+ <%= icon 'device-laptop', class: 'mr-0' %>
105
+ <%= tooltip("Desktop") %>
106
+ </button>
107
+ </li>
108
+ </ul>
109
+
110
+ <%= link_to_with_icon 'eye', Spree.t(:preview), @page.preview_url(@theme_preview, @page_preview), class: 'btn btn-light ml-auto', target: '_blank' %>
111
+ <%= turbo_save_button_tag(@theme.default? ? icon('cloud-up') + Spree.t('actions.publish') : icon('pencil-check') + Spree.t('actions.save')) %>
112
+ </nav>
113
+ </header>
@@ -0,0 +1,10 @@
1
+ <div class="mb-4 form-group">
2
+ <div data-controller="better-slider">
3
+ <label><%= _label %>: <span data-better-slider-target="currentValueLabel"></span><%= unit %></label>
4
+ <div class="flex flex-row w-full">
5
+ <span class="mr-2"><%= min %><%= unit %></span>
6
+ <%= f.range_field field, class: "custom-range", min: min, max: max, step: 1, data: {'better-slider-target': 'rangeInput', action: 'change->auto-submit#submit'} %>
7
+ <span class="ml-2"><%= max %><%= unit %></span>
8
+ </div>
9
+ </div>
10
+ </div>
@@ -0,0 +1,17 @@
1
+ <%= dropdown id: 'pages_dropdown', direction: 'left' do %>
2
+ <%= dropdown_toggle class: 'btn-light' do %>
3
+ <span class="flex items-center pr-12">
4
+ <%= icon @page.icon_name, class: 'mr-2' %>
5
+ <%= @page.display_name %>
6
+ </span>
7
+ <%= icon 'selector', class: 'mr-0 ml-2 mb-0 text-gray-600' %>
8
+ <% end %>
9
+ <%= dropdown_menu style: 'min-width: 250px' do %>
10
+ <% @theme.pages.standard.order(name: :asc).find_all(&:customizable?).each do |page| %>
11
+ <%= active_link_to spree.edit_admin_theme_path(@theme, theme_preview_id: @theme_preview.id, page_id: page.id), class: 'dropdown-item', active: @page == page, data: { turbo_prefetch: false } do %>
12
+ <%= icon page.icon_name, class: 'mr-2' %>
13
+ <%= page.display_name %>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <% label ||= nil %>
2
+ <% label_for_min_value ||= nil %>
3
+ <% action ||= 'change->auto-submit#submit' %>
4
+ <div class="mb-4 form-group">
5
+ <div data-controller="better-slider" data-better-slider-label-for-min-value="<%= label_for_min_value %>" data-better-slider-unit-value="<%= unit %>">
6
+ <label><%= label.presence || field.to_s.humanize %></label>
7
+ <div class="flex flex-row w-full">
8
+ <%= f.range_field field, class: "custom-range", min: min, max: max, step: 1, data: {'better-slider-target': 'rangeInput', action: action} %>
9
+ </div>
10
+ <span data-better-slider-target="currentValueLabel"></span>
11
+ </div>
12
+ </div>
@@ -0,0 +1,12 @@
1
+ <aside id="page-builder-sidebar" class="overflow-y-scroll">
2
+ <div data-tabs-target="panel" id="sections" role="tabpanel" aria-labelledby="sidebar-icon-page" class="animate-fade-in">
3
+ <%= render 'spree/admin/page_builder/sidebar_sections' %>
4
+ <%= render 'spree/admin/page_builder/sidebar_sections_toolbar' %>
5
+ </div>
6
+ <div data-tabs-target="panel" role="tabpanel" aria-labelledby="sidebar-icon-colors" id="colors" hidden class="animate-fade-in">
7
+ <%= render 'spree/admin/page_builder/sidebar_colors' %>
8
+ </div>
9
+ <div data-tabs-target="panel" role="tabpanel" aria-labelledby="sidebar-icon-fonts" id="fonts" hidden class="animate-fade-in">
10
+ <%= render 'spree/admin/page_builder/sidebar_fonts' %>
11
+ </div>
12
+ </aside>
@@ -0,0 +1,30 @@
1
+ <% if block.persisted? %>
2
+ <%= turbo_frame_tag dom_id(block), class: 'list-group-item sidebar-page-block px-0 py-0 border-0 rounded',
3
+ data: {
4
+ action: 'mouseover->page-builder#toggleHighlightElement mouseout->page-builder#toggleHighlightElement',
5
+ page_builder_editor_id_param: "block-#{block.id}",
6
+ sortable_update_url: spree.admin_page_section_block_path(block.section, block, format: :turbo_stream)
7
+ } do %>
8
+ <div class="flex items-center justify-between sidebar-block-title p-1 rounded-md">
9
+ <div class="flex items-center flex-1">
10
+ <%= link_to(edit_admin_page_section_block_path(block.section, block),
11
+ class: 'block-edit-link flex-1 text-gray-900',
12
+ data: {
13
+ turbo_frame: :page_sidebar,
14
+ action: 'click->page-builder#makeOverlayActive',
15
+ page_builder_editor_id_param: "block-#{block.id}"
16
+ }) do %>
17
+ <%= icon "#{block.icon_name}", class: 'mr-2' if block.icon_name.present? %>
18
+ <%= block.display_name %>
19
+ <% end %>
20
+ </div>
21
+ <div class="flex items-center hidden">
22
+ <% if block.section.can_sort_blocks? %>
23
+ <button class="btn btn-sm pr-0 handle hover:bg-gray-100 h-full px-1 handle-block shadow-none">
24
+ <%= icon('grip-vertical', class: 'mr-0') %>
25
+ </button>
26
+ <% end %>
27
+ </div>
28
+ </div>
29
+ <% end %>
30
+ <% end %>