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,45 @@
1
+ module Spree
2
+ module PageSections
3
+ class FeaturedPosts < Spree::PageSection
4
+ before_validation :make_heading_size_valid
5
+ before_validation :make_max_posts_to_show_valid
6
+ before_validation :make_alignment_valid
7
+ before_validation :make_posts_to_show_valid
8
+
9
+ preference :heading, :string, default: ''
10
+ preference :heading_size, :string, default: 'large'
11
+ preference :heading_alignment, :string, default: 'left'
12
+ preference :description_alignment, :string, default: 'left'
13
+ preference :posts_to_show, :string, default: 'newest'
14
+ preference :max_posts_to_show, :integer, default: 4
15
+
16
+ def icon_name
17
+ 'news'
18
+ end
19
+
20
+ def posts
21
+ Spree::Post.published.by_newest.limit(preferred_max_posts_to_show)
22
+ end
23
+
24
+ private
25
+
26
+ def make_posts_to_show_valid
27
+ self.preferred_posts_to_show = 'newest' unless %w[newest most_popular].include?(preferred_posts_to_show)
28
+ end
29
+
30
+ def make_alignment_valid
31
+ self.preferred_heading_alignment = 'left' unless %w[left center right].include?(preferred_heading_alignment)
32
+ self.preferred_description_alignment = 'left' unless %w[left center right].include?(preferred_description_alignment)
33
+ end
34
+
35
+ def make_max_posts_to_show_valid
36
+ self.preferred_max_posts_to_show = 2 if preferred_max_posts_to_show < 2
37
+ self.preferred_max_posts_to_show = 8 if preferred_max_posts_to_show > 8
38
+ end
39
+
40
+ def make_heading_size_valid
41
+ self.preferred_heading_size = 'small' unless %w[small medium large].include?(preferred_heading_size)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ module Spree
2
+ module PageSections
3
+ class FeaturedProduct < Spree::PageSection
4
+ preference :product_id, :string, default: ''
5
+
6
+ def icon_name
7
+ 'star'
8
+ end
9
+
10
+ def product
11
+ return @product if defined?(@product)
12
+
13
+ includes = [
14
+ { variants: { images: [], prices: [], stock_items: [], stock_locations: [], option_values: :option_type } },
15
+ ]
16
+
17
+ @product ||= store.products.includes(includes).find_by(id: preferred_product_id)
18
+ end
19
+
20
+ def vendor_name
21
+ return unless defined?(Spree::Vendor)
22
+
23
+ @vendor_name ||= product&.vendor&.display_name || 'Brand'
24
+ end
25
+
26
+ def product_name
27
+ product&.name
28
+ end
29
+
30
+ def default_blocks
31
+ [
32
+ Spree::PageBlocks::Products::Title.new,
33
+ Spree::PageBlocks::Products::Price.new(text: 'Price', preferred_text_alignment: 'left'),
34
+ Spree::PageBlocks::Products::VariantPicker.new,
35
+ Spree::PageBlocks::Products::QuantitySelector.new,
36
+ Spree::PageBlocks::Products::BuyButtons.new,
37
+ Spree::PageBlocks::Products::Share.new(text: 'Share')
38
+ ]
39
+ end
40
+
41
+ def blocks_available?
42
+ true
43
+ end
44
+
45
+ def can_sort_blocks?
46
+ true
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,90 @@
1
+ module Spree
2
+ module PageSections
3
+ class FeaturedTaxon < Spree::PageSection
4
+ scope :by_taxon_id, lambda { |taxon_ids|
5
+ queries = [*taxon_ids].map do |taxon_id|
6
+ where("#{Spree::PageSections::FeaturedTaxon.table_name}.preferences LIKE ?", "%taxon_id: '#{taxon_id}'%")
7
+ end
8
+
9
+ queries.reduce(:or)
10
+ }
11
+
12
+ before_validation :make_heading_size_valid
13
+ before_validation :make_alignment_valid
14
+ before_validation :make_taxon_id_valid
15
+
16
+ preference :heading, :string, default: Spree.t('page_sections.featured_taxon.heading_default')
17
+ preference :heading_size, :string, default: 'large'
18
+ preference :heading_alignment, :string, default: 'left'
19
+ preference :description_alignment, :string, default: 'left'
20
+ preference :use_description_from_admin, :boolean, default: true
21
+ preference :show_taxon_image, :boolean, default: true
22
+ preference :show_more_button, :boolean, default: true
23
+ preference :taxon_id, :string, default: ''
24
+ preference :max_products_to_show, :integer, default: 20
25
+ preference :button_style, :string, default: 'primary'
26
+ preference :button_text_color, :string, default: nil
27
+ preference :button_background_color, :string, default: nil
28
+ preference :button_text, :string, default: Spree.t('page_sections.featured_taxon.button_text_default')
29
+
30
+ def icon_name
31
+ 'tags'
32
+ end
33
+
34
+ def lazy?
35
+ !Rails.env.test?
36
+ end
37
+
38
+ def taxon
39
+ @taxon ||= store.taxons.find_by(id: preferred_taxon_id) if preferred_taxon_id.present?
40
+ end
41
+
42
+ def description_to_use
43
+ @description_to_use ||= preferred_use_description_from_admin && description.blank? ? taxon&.description : description
44
+ end
45
+
46
+ def display_name
47
+ @display_name ||= preferred_heading.present? ? "#{preferred_heading} - #{name}" : name
48
+ end
49
+
50
+ def products(currency)
51
+ Spree::Deprecation.warn(
52
+ 'FeaturedTaxon#products is deprecated and will be removed in Spree 5.5. ' \
53
+ 'Please use taxon_products(featured_taxon.taxon) helper method in views instead'
54
+ )
55
+
56
+ @products ||= begin
57
+ finder_params = {
58
+ store: store,
59
+ filter: { taxons: preferred_taxon_id },
60
+ currency: currency,
61
+ sort_by: 'default'
62
+ }
63
+
64
+ Spree.products_finder.new(scope: store.products, params: finder_params).execute.limit(preferred_max_products_to_show)
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def make_taxon_id_valid
71
+ self.preferred_taxon_id = preferred_taxon_id.presence || store.taxons.where(depth: 1).first&.id
72
+ end
73
+
74
+ def set_heading
75
+ return unless collection_id_changed?
76
+
77
+ self.heading = collection&.title
78
+ end
79
+
80
+ def make_alignment_valid
81
+ self.preferred_heading_alignment = 'left' unless %w[left center right].include?(preferred_heading_alignment)
82
+ self.preferred_description_alignment = 'left' unless %w[left center right].include?(preferred_description_alignment)
83
+ end
84
+
85
+ def make_heading_size_valid
86
+ self.preferred_heading_size = 'small' unless %w[small medium large].include?(preferred_heading_size)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,45 @@
1
+ module Spree
2
+ module PageSections
3
+ class FeaturedTaxons < Spree::PageSection
4
+ before_validation :make_heading_size_valid
5
+ before_validation :make_alignment_valid
6
+
7
+ preference :heading, :string, default: Spree.t('page_sections.featured_taxons.heading_default')
8
+ preference :heading_size, :string, default: 'large'
9
+ preference :heading_alignment, :string, default: 'left'
10
+
11
+ def icon_name
12
+ 'layout-grid'
13
+ end
14
+
15
+ def links_available?
16
+ true
17
+ end
18
+
19
+ def allowed_linkable_types
20
+ [
21
+ [Spree.t(:taxon), 'Spree::Taxon']
22
+ ]
23
+ end
24
+
25
+ def default_linkable_type
26
+ default_linkable_resource.class.to_s
27
+ end
28
+
29
+ def default_linkable_resource
30
+ @default_linkable_resource ||= Spree::Taxon.where(parent: store.taxonomies.first.root).first ||
31
+ store.theme_pages.find_by(type: 'Spree::Pages::Homepage')
32
+ end
33
+
34
+ private
35
+
36
+ def make_heading_size_valid
37
+ self.preferred_heading_size = 'small' unless %w[small medium large].include?(preferred_heading_size)
38
+ end
39
+
40
+ def make_alignment_valid
41
+ self.preferred_heading_alignment = 'left' unless %w[left center right].include?(preferred_heading_alignment)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,101 @@
1
+ module Spree
2
+ module PageSections
3
+ class Footer < Spree::PageSection
4
+ alias logo asset
5
+
6
+ BACKGROUND_COLOR_DEFAULT = '#F5F5F4'
7
+ TOP_PADDING_DEFAULT = 32
8
+ BOTTOM_PADDING_DEFAULT = 32
9
+ TOP_BORDER_WIDTH_DEFAULT = 0
10
+
11
+ preference :copyright_text_color, :string, default: '#FFFFFF'
12
+ preference :copyright_background_color, :string, default: '#000000'
13
+
14
+ def self.role
15
+ 'footer'
16
+ end
17
+
18
+ def icon_name
19
+ 'layout-bottombar'
20
+ end
21
+
22
+ def can_sort_blocks?
23
+ true
24
+ end
25
+
26
+ def blocks_available?
27
+ true
28
+ end
29
+
30
+ def available_blocks_to_add
31
+ [Spree::PageBlocks::Nav]
32
+ end
33
+
34
+ def default_blocks
35
+ shop_default_links = [
36
+ Spree::PageLink.new(
37
+ linkable: pages.find_by(type: 'Spree::Pages::ShopAll')
38
+ )
39
+ ]
40
+
41
+ collections_taxonomy = store.taxonomies.find_by(name: Spree.t(:taxonomy_collections_name))
42
+
43
+ if collections_taxonomy.present?
44
+ on_sale_collection = collections_taxonomy.taxons.automatic.find_by(name: Spree.t('automatic_taxon_names.on_sale'))
45
+ new_arrivals_collection = collections_taxonomy.taxons.automatic.find_by(name: Spree.t('automatic_taxon_names.new_arrivals'))
46
+
47
+ shop_default_links << Spree::PageLink.new(linkable: on_sale_collection) if on_sale_collection.present?
48
+ shop_default_links << Spree::PageLink.new(linkable: new_arrivals_collection) if new_arrivals_collection.present?
49
+ end
50
+
51
+ default_info_links = []
52
+
53
+ if store.policies.find_by(name: Spree.t('terms_of_service')).present?
54
+ default_info_links << Spree::PageLink.new(
55
+ label: Spree.t('terms_of_service'),
56
+ linkable: store.policies.find_by(name: Spree.t('terms_of_service'))
57
+ )
58
+ end
59
+
60
+ if store.policies.find_by(name: Spree.t('privacy_policy')).present?
61
+ default_info_links << Spree::PageLink.new(
62
+ label: Spree.t('privacy_policy'),
63
+ linkable: store.policies.find_by(name: Spree.t('privacy_policy'))
64
+ )
65
+ end
66
+
67
+ [
68
+ Spree::PageBlocks::Nav.new(
69
+ preferred_label: 'Shop',
70
+ default_links: shop_default_links
71
+ ),
72
+ Spree::PageBlocks::Nav.new(
73
+ preferred_label: Spree.t('account'),
74
+ default_links: [
75
+ Spree::PageLink.new(
76
+ label: Spree.t('my_account'),
77
+ linkable: pages.find_by(type: 'Spree::Pages::Account')
78
+ ),
79
+ Spree::PageLink.new(
80
+ label: 'Favorites',
81
+ linkable: pages.find_by(type: 'Spree::Pages::Wishlist')
82
+ )
83
+ ]
84
+ ),
85
+ Spree::PageBlocks::Nav.new(
86
+ preferred_label: 'Company',
87
+ default_links: []
88
+ ),
89
+ Spree::PageBlocks::Nav.new(
90
+ preferred_label: 'Info',
91
+ default_links: default_info_links
92
+ )
93
+ ]
94
+ end
95
+
96
+ def pages
97
+ @pages ||= theme.pages
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,62 @@
1
+ module Spree
2
+ module PageSections
3
+ class Header < Spree::PageSection
4
+ alias logo asset
5
+
6
+ TOP_PADDING_DEFAULT = 15
7
+ BOTTOM_PADDING_DEFAULT = 15
8
+ TOP_BORDER_WIDTH_DEFAULT = 0
9
+
10
+ preference :layout, :string, default: 'logo-centered'
11
+ preference :desktop_logo_height, :integer, default: 0
12
+
13
+ def self.role
14
+ 'header'
15
+ end
16
+
17
+ def can_sort_blocks?
18
+ true
19
+ end
20
+
21
+ def blocks_available?
22
+ true
23
+ end
24
+
25
+ def available_blocks_to_add
26
+ [Spree::PageBlocks::MegaNavWithSubcategories, Spree::PageBlocks::MegaNav, Spree::PageBlocks::Link]
27
+ end
28
+
29
+ def icon_name
30
+ 'layout-navbar'
31
+ end
32
+
33
+ def links_available?
34
+ true
35
+ end
36
+
37
+ def default_links
38
+ links = [
39
+ Spree::PageLink.new(linkable: pages.find_by(type: 'Spree::Pages::ShopAll'))
40
+ ]
41
+
42
+ collections_taxonomy = store.taxonomies.find_by(name: Spree.t(:taxonomy_collections_name))
43
+
44
+ if collections_taxonomy.present?
45
+ on_sale_collection = collections_taxonomy.taxons.automatic.find_by(name: Spree.t('automatic_taxon_names.on_sale'))
46
+ new_arrivals_collection = collections_taxonomy.taxons.automatic.find_by(name: Spree.t('automatic_taxon_names.new_arrivals'))
47
+
48
+ links << Spree::PageLink.new(linkable: on_sale_collection) if on_sale_collection.present?
49
+ links << Spree::PageLink.new(linkable: new_arrivals_collection) if new_arrivals_collection.present?
50
+ end
51
+
52
+ links << Spree::PageLink.new(linkable: pages.find_by(type: 'Spree::Pages::PostList'))
53
+
54
+ links
55
+ end
56
+
57
+ def pages
58
+ @pages ||= theme.pages
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,55 @@
1
+ module Spree
2
+ module PageSections
3
+ class ImageBanner < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
6
+ TOP_PADDING_DEFAULT = 0
7
+ BOTTOM_PADDING_DEFAULT = 0
8
+
9
+ preference :overlay_transparency, :integer, default: 40
10
+ preference :height, :integer, default: 384
11
+ preference :vertical_alignment, :string, default: :middle
12
+ preference :image_alt, :string
13
+
14
+ def default_blocks
15
+ [
16
+ Spree::PageBlocks::Heading.new(
17
+ text: Spree.t('page_sections.image_banner.heading_default'),
18
+ preferred_text_alignment: 'center',
19
+ preferred_container_alignment: 'center',
20
+ preferred_width_desktop: 50
21
+ ),
22
+ Spree::PageBlocks::Text.new(
23
+ text: Spree.t('page_sections.image_banner.text_default'),
24
+ preferred_text_alignment: 'center',
25
+ preferred_container_alignment: 'center',
26
+ preferred_width_desktop: 50
27
+ ),
28
+ Spree::PageBlocks::Buttons.new
29
+ ]
30
+ end
31
+
32
+ def available_blocks_to_add
33
+ [
34
+ Spree::PageBlocks::Buttons,
35
+ Spree::PageBlocks::Heading,
36
+ Spree::PageBlocks::Text
37
+ ]
38
+ end
39
+
40
+ def blocks_available?
41
+ true
42
+ end
43
+
44
+ def can_sort_blocks?
45
+ true
46
+ end
47
+
48
+ def icon_name
49
+ 'slideshow'
50
+ end
51
+
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ module Spree
2
+ module PageSections
3
+ class ImageWithText < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
6
+ TOP_PADDING_DEFAULT = 16
7
+ BOTTOM_PADDING_DEFAULT = 16
8
+
9
+ preference :desktop_image_alignment, :string, default: 'right'
10
+ preference :vertical_alignment, :string, default: :middle
11
+ preference :image_alt, :string
12
+
13
+ has_one :link, ->(ps) { ps.links }, class_name: 'Spree::PageLink', as: :parent, dependent: :destroy, inverse_of: :parent
14
+ accepts_nested_attributes_for :link
15
+
16
+ def default_blocks
17
+ @default_blocks.presence || [
18
+ Spree::PageBlocks::Heading.new(
19
+ text: Spree.t('page_sections.image_with_text.heading_default'),
20
+ preferred_text_alignment: 'left',
21
+ preferred_bottom_padding: 8,
22
+ preferred_top_padding: 24
23
+ ),
24
+ Spree::PageBlocks::Text.new(
25
+ text: Spree.t('page_sections.image_with_text.text_default', store_name: store.name),
26
+ preferred_text_alignment: 'left',
27
+ preferred_bottom_padding: 16
28
+ ),
29
+ Spree::PageBlocks::Buttons.new(preferred_text_alignment: 'left')
30
+ ]
31
+ end
32
+
33
+ def available_blocks_to_add
34
+ [
35
+ Spree::PageBlocks::Buttons,
36
+ Spree::PageBlocks::Heading,
37
+ Spree::PageBlocks::Text
38
+ ]
39
+ end
40
+
41
+ def default_links
42
+ @default_links.presence || [
43
+ Spree::PageLink.new(
44
+ label: Spree.t(:shop_all),
45
+ linkable: theme.pages.find_by(type: 'Spree::Pages::ShopAll')
46
+ )
47
+ ]
48
+ end
49
+
50
+ def blocks_available?
51
+ true
52
+ end
53
+
54
+ def can_sort_blocks?
55
+ true
56
+ end
57
+
58
+ def icon_name
59
+ 'photo'
60
+ end
61
+
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module PageSections
3
+ class MainPasswordFooter < Spree::PageSection
4
+ alias logo asset
5
+
6
+ TOP_PADDING_DEFAULT = 32
7
+ BOTTOM_PADDING_DEFAULT = 32
8
+
9
+ def self.role
10
+ 'footer'
11
+ end
12
+
13
+ def icon_name
14
+ 'layout-bottombar'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Spree
2
+ module PageSections
3
+ class MainPasswordHeader < Spree::PageSection
4
+ alias logo asset
5
+
6
+ TOP_PADDING_DEFAULT = 15
7
+ BOTTOM_PADDING_DEFAULT = 15
8
+
9
+ preference :desktop_logo_height, :integer, default: 0
10
+
11
+ def self.role
12
+ 'header'
13
+ end
14
+
15
+ def icon_name
16
+ 'layout-navbar'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ module Spree
2
+ module PageSections
3
+ class Newsletter < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
6
+ preference :overlay_transparency, :integer, default: 40
7
+ preference :image_alt, :string
8
+
9
+ def default_blocks
10
+ @default_blocks.presence || [
11
+ Spree::PageBlocks::Heading.new(
12
+ text: Spree.t('page_sections.newsletter.heading_default'),
13
+ preferred_width_desktop: 50, # in %
14
+ preferred_text_alignment: 'center',
15
+ preferred_container_alignment: 'center',
16
+ preferred_bottom_padding: 8
17
+ ),
18
+ Spree::PageBlocks::Text.new(
19
+ text: Spree.t('page_sections.newsletter.text_default'),
20
+ preferred_text_alignment: 'center',
21
+ preferred_bottom_padding: 32,
22
+ preferred_width_desktop: 50,
23
+ preferred_container_alignment: 'center'
24
+ ),
25
+ Spree::PageBlocks::NewsletterForm.new
26
+ ]
27
+ end
28
+
29
+ def self.role
30
+ 'footer'
31
+ end
32
+
33
+ def lazy?
34
+ !Rails.env.test?
35
+ end
36
+
37
+ def blocks_available?
38
+ true
39
+ end
40
+
41
+ def available_blocks_to_add
42
+ [Spree::PageBlocks::Image, Spree::PageBlocks::Heading, Spree::PageBlocks::Text, Spree::PageBlocks::NewsletterForm]
43
+ end
44
+
45
+ def can_sort_blocks?
46
+ true
47
+ end
48
+
49
+ def icon_name
50
+ 'mail'
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module PageSections
3
+ class PageTitle < Spree::PageSection
4
+ preference :title, :string
5
+
6
+ def icon_name
7
+ 'heading'
8
+ end
9
+
10
+ def display_name
11
+ if pageable.is_a?(Spree::Page) && pageable.custom?
12
+ pageable.name
13
+ else
14
+ Spree.t('page_sections.page_title.display_name')
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module PageSections
3
+ class PostDetails < Spree::PageSection
4
+ DISPLAY_NAME = Spree.t(:post).freeze
5
+
6
+ def icon_name
7
+ 'article'
8
+ end
9
+
10
+ def self.role
11
+ 'system'
12
+ end
13
+
14
+ def display_name
15
+ DISPLAY_NAME
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module PageSections
3
+ class PostGrid < Spree::PageSection
4
+ DISPLAY_NAME = Spree.t(:posts).freeze
5
+
6
+ def icon_name
7
+ 'news'
8
+ end
9
+
10
+ def self.role
11
+ 'system'
12
+ end
13
+
14
+ def display_name
15
+ DISPLAY_NAME
16
+ end
17
+ end
18
+ end
19
+ end