spree_storefront 5.2.5 → 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.
- checksums.yaml +4 -4
- data/Rakefile +5 -3
- data/app/controllers/concerns/spree/cart_methods.rb +4 -3
- data/app/controllers/concerns/spree/storefront/pagination_concern.rb +23 -0
- data/app/controllers/spree/account/gift_cards_controller.rb +1 -1
- data/app/controllers/spree/account/orders_controller.rb +2 -2
- data/app/controllers/spree/account/store_credits_controller.rb +4 -4
- data/app/controllers/spree/addresses_controller.rb +2 -2
- data/app/controllers/spree/checkout_controller.rb +14 -8
- data/app/controllers/spree/line_items_controller.rb +3 -3
- data/app/controllers/spree/order_status_controller.rb +1 -1
- data/app/controllers/spree/orders_controller.rb +3 -3
- data/app/controllers/spree/posts_controller.rb +1 -1
- data/app/controllers/spree/products_controller.rb +1 -0
- data/app/controllers/spree/search_controller.rb +1 -1
- data/app/controllers/spree/store_controller.rb +28 -33
- data/app/helpers/spree/canonical_url_helper.rb +27 -0
- data/app/helpers/spree/checkout_analytics_helper.rb +1 -4
- data/app/helpers/spree/checkout_helper.rb +3 -1
- data/app/helpers/spree/page_helper.rb +2 -4
- data/app/helpers/spree/products_helper.rb +31 -8
- data/app/helpers/spree/storefront_helper.rb +2 -1
- data/app/helpers/spree/taxons_helper.rb +3 -1
- data/app/helpers/spree/theme_helper.rb +1 -1
- data/app/views/devise/sessions/new.html.erb +1 -1
- data/app/views/spree/checkout/_address.html.erb +2 -2
- data/app/views/spree/checkout/_coupon_code.html.erb +2 -2
- data/app/views/spree/checkout/_delivery.html.erb +2 -2
- data/app/views/spree/checkout/_delivery_shipping_rate.html.erb +1 -1
- data/app/views/spree/checkout/_line_items.html.erb +3 -5
- data/app/views/spree/checkout/_payment_methods.html.erb +1 -1
- data/app/views/spree/products/index.html.erb +1 -1
- data/app/views/spree/search/show.html.erb +1 -1
- data/app/views/spree/shared/_load_more_products.turbo_stream.erb +1 -1
- data/app/views/spree/shared/_product_listing_page.html.erb +2 -2
- data/app/views/themes/default/spree/page_sections/_featured_product.html.erb +4 -4
- data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +4 -4
- data/app/views/themes/default/spree/page_sections/_footer.html.erb +6 -6
- data/app/views/themes/default/spree/page_sections/_header.html.erb +5 -2
- data/app/views/themes/default/spree/page_sections/_post_grid.html.erb +1 -1
- data/app/views/themes/default/spree/page_sections/_product_details.html.erb +2 -2
- data/app/views/themes/default/spree/posts/_pagination.html.erb +1 -1
- data/app/views/themes/default/spree/products/_add_to_cart_button.html.erb +16 -3
- data/app/views/themes/default/spree/products/_color_swatches.html.erb +1 -1
- data/app/views/themes/default/spree/products/_featured_image.html.erb +2 -1
- data/app/views/themes/default/spree/products/_json_ld.html.erb +4 -4
- data/app/views/themes/default/spree/products/_price.html.erb +3 -1
- data/app/views/themes/default/spree/products/_product.html.erb +3 -3
- data/app/views/themes/default/spree/products/_quantity_selector.html.erb +6 -4
- data/app/views/themes/default/spree/products/_show_more_button.html.erb +3 -3
- data/app/views/themes/default/spree/products/_swiper.html.erb +2 -2
- data/app/views/themes/default/spree/products/_variant_options.html.erb +6 -2
- data/app/views/themes/default/spree/products/_variant_picker.html.erb +5 -3
- data/app/views/themes/default/spree/shared/_custom_head.html.erb +7 -0
- data/app/views/themes/default/spree/shared/_line_item_options.html.erb +1 -1
- data/app/views/themes/default/spree/shared/_pagination.html.erb +7 -0
- data/app/views/themes/default/spree/shared/_search.html.erb +1 -1
- data/config/locales/en.yml +2 -0
- data/lib/generators/spree/storefront/install/install_generator.rb +12 -4
- data/lib/generators/spree/storefront/install/templates/application.css +45 -4
- data/lib/spree/storefront/configuration.rb +3 -0
- data/lib/spree/storefront.rb +3 -2
- metadata +33 -16
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<% if turbo_frame_request? && current_theme_preview.nil? %>
|
|
2
|
-
<%= render 'spree/page_sections/product_grid', products: storefront_products
|
|
2
|
+
<%= render 'spree/page_sections/product_grid', products: storefront_products, section: current_page.sections.find_by(type: 'Spree::PageSections::ProductGrid') %>
|
|
3
3
|
<% else %>
|
|
4
4
|
<%= render_page(
|
|
5
5
|
current_page,
|
|
6
6
|
taxon: @taxon,
|
|
7
7
|
collection: @collection,
|
|
8
|
-
products: storefront_products
|
|
8
|
+
products: storefront_products,
|
|
9
9
|
) %>
|
|
10
10
|
<% end %>
|
|
11
11
|
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
<div <%= block_attributes(block) %>>
|
|
48
48
|
<% case block.type %>
|
|
49
49
|
<% when 'Spree::PageBlocks::Products::Brand' %>
|
|
50
|
-
<% if presenter.product&.
|
|
51
|
-
<%= link_to spree_storefront_resource_url(presenter.product&.
|
|
50
|
+
<% if presenter.product&.brand_taxon&.page_builder_url %>
|
|
51
|
+
<%= link_to spree_storefront_resource_url(presenter.product&.brand_taxon), title: strip_tags(presenter.product&.brand_taxon&.name).strip, data: { turbo_frame: '_top' } do %>
|
|
52
52
|
<h3 class="text-sm uppercase font-semibold">
|
|
53
|
-
<%= presenter.product&.
|
|
53
|
+
<%= presenter.product&.brand_taxon&.name %>
|
|
54
54
|
</h3>
|
|
55
55
|
<% end %>
|
|
56
56
|
<% else %>
|
|
57
57
|
<h3 class="text-sm uppercase font-semibold">
|
|
58
|
-
<%= presenter.product&.
|
|
58
|
+
<%= presenter.product&.brand_taxon&.name %>
|
|
59
59
|
</h3>
|
|
60
60
|
<% end %>
|
|
61
61
|
<% when 'Spree::PageBlocks::Products::Title' %>
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
<%= page_builder_link_to link, title: link.label, class: 'group block overflow-hidden', target: link.open_in_new_tab.presence && '_blank' do %>
|
|
15
15
|
<% if link.linkable.page_builder_image&.attached? && link.linkable.page_builder_image&.variable? %>
|
|
16
16
|
<div class="flex space-y-2 flex-col">
|
|
17
|
-
<%= spree_image_tag(link.linkable.page_builder_image, height: 300, width: 300, class: 'h-full w-full object-cover object-center group-hover:opacity-75 rounded-md bg-
|
|
17
|
+
<%= spree_image_tag(link.linkable.page_builder_image, height: 300, width: 300, class: 'h-full w-full object-cover object-center group-hover:opacity-75 rounded-md bg-border', loading: :lazy, alt: link.label) %>
|
|
18
18
|
<span><%= link.label %></span>
|
|
19
19
|
</div>
|
|
20
20
|
<% else %>
|
|
21
|
-
<div class="aspect-1 w-full group-hover:bg-gray-100 bg-
|
|
21
|
+
<div class="aspect-1 w-full group-hover:bg-gray-100 bg-border rounded-md flex items-center justify-center relative">
|
|
22
22
|
<span><%= link.label %></span>
|
|
23
23
|
</div>
|
|
24
24
|
<% end %>
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
<%= page_builder_link_to link, title: link.label, class: 'group block overflow-hidden', target: link.open_in_new_tab.presence && '_blank' do %>
|
|
50
50
|
<% if link.linkable.page_builder_image.attached? %>
|
|
51
51
|
<div class="flex space-y-2 flex-col">
|
|
52
|
-
<%= spree_image_tag(link.linkable.page_builder_image, height: 200, width: 200, class: 'h-full w-full object-cover object-center group-hover:opacity-75 rounded-md bg-
|
|
52
|
+
<%= spree_image_tag(link.linkable.page_builder_image, height: 200, width: 200, class: 'h-full w-full object-cover object-center group-hover:opacity-75 rounded-md bg-border', loading: :lazy, alt: link.label) %>
|
|
53
53
|
</div>
|
|
54
54
|
<% else %>
|
|
55
|
-
<div class="aspect-1 w-full group-hover:bg-gray-100 bg-
|
|
55
|
+
<div class="aspect-1 w-full group-hover:bg-gray-100 bg-border flex items-center justify-center relative">
|
|
56
56
|
<span><%= link.label %></span>
|
|
57
57
|
</div>
|
|
58
58
|
<% end %>
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
</div>
|
|
13
13
|
<div class="grid grid-cols-1 lg:grid-cols-4 grow w-full">
|
|
14
14
|
<% section.blocks.includes(:links).each do |block| %>
|
|
15
|
-
<
|
|
15
|
+
<nav class="flex-grow gap-1 flex flex-col py-6 md:py-0 border-b md:border-none border-default lg:mb-6" aria-label="<%= block.preferred_label %>">
|
|
16
16
|
<div <%= block_attributes(block) %>>
|
|
17
|
-
<
|
|
17
|
+
<div class="text-sm py-2"><%= block.preferred_label %></div>
|
|
18
18
|
<ul class="uppercase text-sm tracking-wider !leading-4 flex flex-col gap-1">
|
|
19
19
|
<% block.links.each do |link| %>
|
|
20
20
|
<li class='py-2'>
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
<% end %>
|
|
26
26
|
</ul>
|
|
27
27
|
</div>
|
|
28
|
-
</
|
|
28
|
+
</nav>
|
|
29
29
|
<% end %>
|
|
30
30
|
</div>
|
|
31
|
-
<
|
|
31
|
+
<nav class="flex-grow gap-4 flex flex-col justify-between lg:w-60" aria-label="<%= Spree.t(:follow_us) %>">
|
|
32
32
|
<div class="gap-1 flex flex-col py-6 md:py-0">
|
|
33
|
-
<
|
|
33
|
+
<div class="text-sm py-2"><%= Spree.t(:follow_us) %></div>
|
|
34
34
|
<div class="flex flex-wrap gap-2 max-w-48 py-2">
|
|
35
35
|
<% cache spree_storefront_base_cache_scope.call(current_store) do %>
|
|
36
36
|
<% Spree::Store::SUPPORTED_SOCIAL_NETWORKS.each do |media| %>
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<% end %>
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
47
|
-
</
|
|
47
|
+
</nav>
|
|
48
48
|
</div>
|
|
49
49
|
<div class="flex justify-end w-full"></div>
|
|
50
50
|
</div>
|
|
@@ -103,11 +103,12 @@
|
|
|
103
103
|
<% if show_account_pane? %>
|
|
104
104
|
<button
|
|
105
105
|
data-action='click->slideover-account#toggle click@window->slideover-account#hide click->toggle-menu#hide touch->toggle-menu#hide'
|
|
106
|
+
aria-label='Open account panel'
|
|
106
107
|
>
|
|
107
108
|
<%= render 'spree/shared/icons/account', color: section.preferred_text_color, section: section %>
|
|
108
109
|
</button>
|
|
109
110
|
<% else %>
|
|
110
|
-
<%= link_to spree.account_path do %>
|
|
111
|
+
<%= link_to spree.account_path, 'aria-label': 'Open account panel' do %>
|
|
111
112
|
<%= render 'spree/shared/icons/account', color: section.preferred_text_color, section: section %>
|
|
112
113
|
<% end %>
|
|
113
114
|
<% end %>
|
|
@@ -117,12 +118,13 @@
|
|
|
117
118
|
<button
|
|
118
119
|
type="submit"
|
|
119
120
|
id="wishlist-icon"
|
|
121
|
+
aria-label='Open wishlist'
|
|
120
122
|
class="flex items-end">
|
|
121
123
|
<%= render 'spree/shared/wishlist_icon', wishlist: current_wishlist, background_color: section.preferred_background_color %>
|
|
122
124
|
</button>
|
|
123
125
|
<% end %>
|
|
124
126
|
<% else %>
|
|
125
|
-
<%= link_to spree.account_wishlist_path, id: "wishlist-icon" do %>
|
|
127
|
+
<%= link_to spree.account_wishlist_path, id: "wishlist-icon", 'aria-label': 'Open wishlist' do %>
|
|
126
128
|
<%= render 'spree/shared/wishlist_icon', background_color: section.preferred_background_color %>
|
|
127
129
|
<% end %>
|
|
128
130
|
<% end %>
|
|
@@ -141,6 +143,7 @@
|
|
|
141
143
|
data-toggle-menu-target='toggleable'
|
|
142
144
|
role='dialog'
|
|
143
145
|
aria-modal='true'
|
|
146
|
+
aria-label='Mobile menu'
|
|
144
147
|
>
|
|
145
148
|
<div
|
|
146
149
|
class='flex justify-between flex-col lg:hidden w-full transition-transform has-[.currency-and-locale-modal:not(.hidden)]:transform-none body header--mobile-menu'
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
</h1>
|
|
48
48
|
<% when 'Spree::PageBlocks::Products::Brand' %>
|
|
49
49
|
<% if product.brand_taxon %>
|
|
50
|
-
<%= link_to spree.nested_taxons_path(product.brand_taxon), title: product.
|
|
50
|
+
<%= link_to spree.nested_taxons_path(product.brand_taxon), title: product.brand_taxon.name do %>
|
|
51
51
|
<h3 class="text-sm lg:mt-0 inline-block mb-1">
|
|
52
|
-
<%= product.
|
|
52
|
+
<%= product.brand_taxon.name %>
|
|
53
53
|
</h3>
|
|
54
54
|
<% end %>
|
|
55
55
|
<% end %>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<%=
|
|
1
|
+
<%= render 'spree/shared/pagination' %>
|
|
@@ -5,11 +5,24 @@ options_param_name ||= :options
|
|
|
5
5
|
not_selected_options = product_not_selected_options(product, selected_variant, options_param_name: options_param_name)
|
|
6
6
|
all_options_selected = (params[options_param_name].present? || @variant_from_options.present?) && not_selected_options.empty?
|
|
7
7
|
not_all_options_selected = !all_options_selected && product.any_variant_available?(current_currency)
|
|
8
|
+
|
|
9
|
+
# Build pricing context for selected variant
|
|
10
|
+
if selected_variant
|
|
11
|
+
variant_pricing_context = pricing_context_for_variant(selected_variant)
|
|
12
|
+
variant_price = selected_variant.price_for(variant_pricing_context)
|
|
13
|
+
else
|
|
14
|
+
variant_price = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
8
17
|
variant_not_available = selected_variant.nil? ||
|
|
9
18
|
product.discontinued? ||
|
|
10
19
|
selected_variant.discontinued? ||
|
|
11
20
|
!selected_variant.purchasable? ||
|
|
12
|
-
|
|
21
|
+
variant_price&.amount.nil?
|
|
22
|
+
|
|
23
|
+
# Build pricing context for product
|
|
24
|
+
product_pricing_context = pricing_context_for_variant(product)
|
|
25
|
+
product_price = product.default_variant.price_for(product_pricing_context)
|
|
13
26
|
%>
|
|
14
27
|
|
|
15
28
|
<div class='<%= sticky_button_classes %> bottom-0 flex flex-col gap-4 z-10' data-sticky-button-target='stickyButton'>
|
|
@@ -22,7 +35,7 @@ variant_not_available = selected_variant.nil? ||
|
|
|
22
35
|
].compact.join(' '),
|
|
23
36
|
product_form_target: 'submit'
|
|
24
37
|
},
|
|
25
|
-
disabled:
|
|
38
|
+
disabled: product_price.zero? do %>
|
|
26
39
|
<% if not_selected_options.size == 1 %>
|
|
27
40
|
<span><%= Spree.t('storefront.variant_picker.please_choose', option_type: not_selected_options[0].presentation) %></span>
|
|
28
41
|
<% elsif not_all_options_selected %>
|
|
@@ -47,7 +60,7 @@ variant_not_available = selected_variant.nil? ||
|
|
|
47
60
|
].compact.join(' '),
|
|
48
61
|
product_form_target: 'submit'
|
|
49
62
|
},
|
|
50
|
-
disabled:
|
|
63
|
+
disabled: product_price.zero? do %>
|
|
51
64
|
<% if not_selected_options.size == 1 %>
|
|
52
65
|
<span><%= Spree.t('storefront.variant_picker.please_choose', option_type: not_selected_options[0].presentation) %></span>
|
|
53
66
|
<% elsif not_all_options_selected %>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
color_preview_container_class: "lg:w-[28px] lg:h-[28px]",
|
|
32
32
|
color_preview_class: "lg:top-[2px] lg:left-[2px]" %>
|
|
33
33
|
<% end %>
|
|
34
|
-
<% if selected_variant.default_image %>
|
|
34
|
+
<% if selected_variant.has_images? || selected_variant.default_image.present? %>
|
|
35
35
|
<template data-featured-image-template>
|
|
36
36
|
<%= render 'spree/products/featured_image',
|
|
37
37
|
object: selected_variant %>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<% with_cover_image ||= true %>
|
|
2
2
|
<% object ||= product %>
|
|
3
|
+
|
|
3
4
|
<% if object.default_image.present? && object.default_image.attached? %>
|
|
4
5
|
<% height ||= theme_setting('product_listing_image_height') %>
|
|
5
6
|
<% width ||= theme_setting('product_listing_image_width') %>
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"w-full group-hover:opacity-0 transition-opacity duration-500 z-10 relative h-full bg-background product-card !max-h-full #{object_class}" :
|
|
14
15
|
"w-full h-full !max-h-full #{object_class}" %>
|
|
15
16
|
<%= spree_image_tag(object.default_image, width: width, height: height, variant: :medium, loading: :lazy, alt: "#{object.name} #{Spree.t('storefront.products.primary_image', default: 'primary image')}", class: image_hover_class) %>
|
|
16
|
-
<% if object.secondary_image.present? && object.secondary_image.attached? %>
|
|
17
|
+
<% if object.has_images? && object.image_count > 1 && object.secondary_image.present? && object.secondary_image.attached? %>
|
|
17
18
|
<% secondary_image_class = "w-full absolute top-0 left-0 opacity-100 h-full !max-h-full #{object_class}" %>
|
|
18
19
|
<%= spree_image_tag(object.secondary_image, width: width, height: height, variant: :medium, loading: :lazy, alt: "#{object.name} #{Spree.t('storefront.products.secondary_image', default: 'secondary image')}", class: secondary_image_class) %>
|
|
19
20
|
<% end %>
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"@type": "Product",
|
|
6
6
|
"name": <%= product.name.to_json.html_safe %>,
|
|
7
7
|
"url": <%= spree.product_url(product, host: current_store.url_or_custom_domain).to_json.html_safe %>,
|
|
8
|
-
<% if product.
|
|
8
|
+
<% if product.has_images? %>
|
|
9
9
|
"image": [
|
|
10
|
-
<%= spree_image_url(product.
|
|
10
|
+
<%= spree_image_url(product.default_image, variant: :large).to_json.html_safe %>
|
|
11
11
|
],
|
|
12
12
|
<% end %>
|
|
13
13
|
<% if product.description.present? %>
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
<% elsif selected_variant %>
|
|
19
19
|
<% if selected_variant.sku.present? %>"sku": <%= selected_variant.sku.to_json.html_safe %>,<% end %>
|
|
20
20
|
<% end %>
|
|
21
|
-
<% if product.
|
|
21
|
+
<% if product.brand_taxon %>
|
|
22
22
|
"brand": {
|
|
23
23
|
"@type": "Brand",
|
|
24
|
-
"name": <%= product.
|
|
24
|
+
"name": <%= product.brand_taxon.name.to_json.html_safe %>
|
|
25
25
|
},
|
|
26
26
|
<% end %>
|
|
27
27
|
"offers": [
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
target ||= product
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
variant_for_context = target.is_a?(Spree::Product) ? target.default_variant : target
|
|
24
|
+
pricing_context = pricing_context_for_variant(variant_for_context)
|
|
25
|
+
price = variant_for_context.price_for(pricing_context)
|
|
24
26
|
money_price = price.display_amount
|
|
25
27
|
|
|
26
28
|
if target.is_a?(Spree::Product) && !use_variant && product.price_varies?(current_currency)
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
<%= render 'spree/products/label', product: product %>
|
|
25
25
|
</div>
|
|
26
26
|
<div class="product-card-inner">
|
|
27
|
-
<% if product.
|
|
27
|
+
<% if product.brand_taxon.present? %>
|
|
28
28
|
<h3 class="text-xs font-semibold uppercase inline-block product-card-brand">
|
|
29
|
-
<%= product.
|
|
29
|
+
<%= product.brand_taxon.name %>
|
|
30
30
|
</h3>
|
|
31
31
|
<% end %>
|
|
32
32
|
<h3 class="line-clamp-1 product-card-title">
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
</div>
|
|
56
56
|
<% end %>
|
|
57
57
|
<div class="absolute right-1 top-1 z-10" data-plp-variant-picker-target="addToWishlist">
|
|
58
|
-
<%= render 'spree/products/add_to_wishlist', variant:
|
|
58
|
+
<%= render 'spree/products/add_to_wishlist', variant: selected_variant %>
|
|
59
59
|
</div>
|
|
60
60
|
<%= render 'spree/products/color_swatches', product: product if product && (defined?(show_variant_picker) ? show_variant_picker : true) %>
|
|
61
61
|
</div>
|
|
@@ -5,19 +5,21 @@
|
|
|
5
5
|
<%= button_tag class: 'decrease-quantity',
|
|
6
6
|
type: 'button',
|
|
7
7
|
data: { action: 'click->quantity-picker#decrease',
|
|
8
|
-
'quantity-picker-target': 'decrease' }
|
|
8
|
+
'quantity-picker-target': 'decrease' },
|
|
9
|
+
aria: { label: Spree.t('storefront.products.decrease_quantity') } do %>
|
|
9
10
|
<%= render 'spree/shared/icons/minus' %>
|
|
10
11
|
<% end %>
|
|
11
12
|
<%= number_field_tag :quantity, 1,
|
|
12
13
|
min: 1,
|
|
13
14
|
max: selected_variant&.backorderable? ? nil : selected_variant&.total_on_hand,
|
|
14
15
|
class: 'quantity-input',
|
|
15
|
-
'
|
|
16
|
-
|
|
16
|
+
data: { 'quantity-picker-target': 'quantity' },
|
|
17
|
+
aria: { label: Spree.t(:quantity) } %>
|
|
17
18
|
<%= button_tag class: 'increase-quantity',
|
|
18
19
|
type: 'button',
|
|
19
20
|
data: { action: 'click->quantity-picker#increase',
|
|
20
|
-
'quantity-picker-target': 'increase' }
|
|
21
|
+
'quantity-picker-target': 'increase' },
|
|
22
|
+
aria: { label: Spree.t('storefront.products.increase_quantity') } do %>
|
|
21
23
|
<%= render 'spree/shared/icons/plus' %>
|
|
22
24
|
<% end %>
|
|
23
25
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<%
|
|
2
|
-
<%= turbo_frame_tag "next_page", src: url_for(params.to_unsafe_h.merge(page:
|
|
1
|
+
<% if storefront_pagy&.next %>
|
|
2
|
+
<%= turbo_frame_tag "next_page", src: url_for(params.to_unsafe_h.merge(page: storefront_pagy.next, format: :turbo_stream)), class: "block relative w-full", data: { controller: "infinite-scroll", infinite_scroll_offset_value: "1350px" }, loading: "lazy" do %>
|
|
3
3
|
<span class="flex justify-center gap-2 items-center py-4 left-0 w-full h-full">
|
|
4
|
-
|
|
4
|
+
<%= render 'spree/shared/icons/spinner' %>
|
|
5
5
|
<%= Spree.t(:loading) %>...
|
|
6
6
|
</span>
|
|
7
7
|
<% end %>
|
|
@@ -75,10 +75,10 @@
|
|
|
75
75
|
<% end %>
|
|
76
76
|
</div>
|
|
77
77
|
</div>
|
|
78
|
-
<%= button_tag class: "absolute p-2 bg-white rounded-full z-10 border border-accent left-0 disabled:hidden hover:border-primary ml-2 lg:ml-0 swiper-custom-button-prev-#{section.id} block #{arrows_on_top ? '' : 'md:hidden'} top-(--top) lg:top-(--desktop-top)",
|
|
78
|
+
<%= button_tag class: "absolute p-2 bg-white rounded-full z-10 border border-accent left-0 disabled:hidden hover:border-primary ml-2 lg:ml-0 swiper-custom-button-prev-#{section.id} block #{arrows_on_top ? '' : 'md:hidden'} top-(--top) lg:top-(--desktop-top)", style: "--top: calc(#{theme_setting('product_listing_image_height_mobile')}px/2); --desktop-top: calc(#{theme_setting('product_listing_image_height')}px/2); transform: translate(-50%, -50%);" do %>
|
|
79
79
|
<%= render 'spree/shared/icons/chevron' %>
|
|
80
80
|
<% end %>
|
|
81
|
-
<%= button_tag class: "absolute p-2 bg-white rounded-full z-10 border border-accent right-0 disabled:hidden hover:border-primary mr-2 lg:mr-0 swiper-custom-button-next-#{section.id} block #{arrows_on_top ? '' : 'md:hidden'} top-(--top) lg:top-(--desktop-top)",
|
|
81
|
+
<%= button_tag class: "absolute p-2 bg-white rounded-full z-10 border border-accent right-0 disabled:hidden hover:border-primary mr-2 lg:mr-0 swiper-custom-button-next-#{section.id} block #{arrows_on_top ? '' : 'md:hidden'} top-(--top) lg:top-(--desktop-top)", style: "--top: calc(#{theme_setting('product_listing_image_height_mobile')}px/2); --desktop-top: calc(#{theme_setting('product_listing_image_height')}px/2); transform: translate(50%, -50%);" do %>
|
|
82
82
|
<%= render 'spree/shared/icons/chevron_right' %>
|
|
83
83
|
<% end %>
|
|
84
84
|
</div>
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
<% end %>
|
|
33
33
|
<% end %>
|
|
34
34
|
<% if option_type.color? %>
|
|
35
|
-
<li>
|
|
36
|
-
<label class="cursor-pointer">
|
|
35
|
+
<li role="option" aria-label="<%= value.presentation %>">
|
|
36
|
+
<label class="cursor-pointer" aria-label="<%= value.presentation %>">
|
|
37
37
|
<%= radio_button_tag option_type.presentation, value.name, selected_option == value,
|
|
38
38
|
name: option_type.presentation,
|
|
39
39
|
id: "product-option-#{product.id}-#{position}-#{index}",
|
|
@@ -56,10 +56,14 @@
|
|
|
56
56
|
option_id: option_type.id
|
|
57
57
|
},
|
|
58
58
|
name: option_type.presentation,
|
|
59
|
+
role: 'menuitemradio',
|
|
60
|
+
aria: { label: value.presentation },
|
|
59
61
|
id: "product-option-#{product.id}-#{position}-#{index}"
|
|
60
62
|
%>
|
|
61
63
|
<label
|
|
62
64
|
for='product-option-<%= product.id %>-<%= position %>-<%= index %>'
|
|
65
|
+
role="menuitem"
|
|
66
|
+
aria-label="<%= value.presentation %>"
|
|
63
67
|
class='text-sm cursor-pointer flex items-center justify-between px-4 py-2.5 hover:bg-accent focus:outline-hidden focus:bg-accent transition duration-150 ease-in-out <%= option_disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-accent" %>'
|
|
64
68
|
>
|
|
65
69
|
<p><%=h value.presentation %></p>
|
|
@@ -7,19 +7,20 @@
|
|
|
7
7
|
<%= option_type_colors_preview_styles(option_type).html_safe %>
|
|
8
8
|
<fieldset data-option-id="<%= option_type.id %>" class="flex flex-col gap-y-2">
|
|
9
9
|
<span class="text-sm leading-4 uppercase tracking-widest"><%= option_type.presentation %>: <%= selected_option.presentation %></span>
|
|
10
|
-
<ul class="flex items-center flex-wrap gap-1">
|
|
10
|
+
<ul class="flex items-center flex-wrap gap-1" role="listbox" aria-label="<%= option_type.presentation %>">
|
|
11
11
|
<%= render 'spree/products/variant_options', product: product, option_type: option_type, position: index, selected_variant: selected_variant, options_param_name: options_param_name %>
|
|
12
12
|
</ul>
|
|
13
13
|
</fieldset>
|
|
14
14
|
<% else %>
|
|
15
15
|
<fieldset data-option-id="<%= option_type.id %>">
|
|
16
|
-
<div data-controller="dropdown" class="relative mb-2">
|
|
16
|
+
<div data-controller="dropdown" class="relative mb-2" role="group" aria-label="<%= option_type.presentation %>">
|
|
17
17
|
<div class="flex items-center justify-between">
|
|
18
18
|
<button
|
|
19
19
|
data-action="click->dropdown#toggle click@window->dropdown#hide"
|
|
20
20
|
type='button'
|
|
21
21
|
class='text-sm uppercase tracking-widest flex gap-2 items-center border border-default py-2 px-4 rounded-input dropdown-button'
|
|
22
|
-
data-dropdown-target="button"
|
|
22
|
+
data-dropdown-target="button"
|
|
23
|
+
aria-label="<%= selected_option ? option_type.presentation+":"+selected_option.presentation : Spree.t('storefront.variant_picker.please_choose', option_type: option_type.presentation) %>">
|
|
23
24
|
<legend class="mr-2" id="option-<%= option_type.id %>-value">
|
|
24
25
|
<% if selected_option %>
|
|
25
26
|
<%= option_type.presentation %>: <span class="option-value-text"><%= selected_option.presentation %></span>
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
data-transition-leave="transition ease-in"
|
|
38
39
|
data-transition-leave-from="opacity-100 translate-y-0"
|
|
39
40
|
data-transition-leave-to="opacity-0 translate-y-1"
|
|
41
|
+
role="menu"
|
|
40
42
|
class="hidden absolute top-11 left-0 z-[9999] flex w-screen max-w-max shadow-xs">
|
|
41
43
|
<div class="bg-background border-default border overflow-hidden w-72">
|
|
42
44
|
<%= render 'spree/products/variant_options', product: product, option_type: option_type, position: index, selected_variant: selected_variant, options_param_name: options_param_name %>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<link rel="preconnect" href="https://esm.sh" crossorigin>
|
|
2
|
+
<link rel="dns-prefetch" href="https://esm.sh">
|
|
3
|
+
|
|
4
|
+
<link rel="preload" href="https://esm.sh/swiper@11.2.2/swiper-bundle.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
5
|
+
<noscript><link rel="stylesheet" href="https://esm.sh/swiper@11.2.2/swiper-bundle.min.css"></noscript>
|
|
6
|
+
<link rel="preload" href="https://esm.sh/flag-icons@7.3.2/css/flag-icons.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
7
|
+
<noscript><link rel="stylesheet" href="https://esm.sh/flag-icons@7.3.2/css/flag-icons.min.css"></noscript>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<%# Renders pagination - supports both Pagy and Kaminari %>
|
|
2
|
+
<% if Spree::Storefront::Config[:use_kaminari_pagination] %>
|
|
3
|
+
<%= paginate @posts || @orders || @gift_cards || @store_credit_events || @storefront_products,
|
|
4
|
+
theme: 'storefront', outer_window: 1, inner_window: 2 %>
|
|
5
|
+
<% elsif @pagy && @pagy.pages > 1 %>
|
|
6
|
+
<%== @pagy.series_nav(aria_label: 'Pages') %>
|
|
7
|
+
<% end %>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div id="search-suggestions" role="dialog" aria-modal="true">
|
|
1
|
+
<div id="search-suggestions" role="dialog" aria-label="Search suggestions" aria-modal="true">
|
|
2
2
|
<div class='w-full flex flex-col border-b border-default' data-controller="search-suggestions" data-show-class="h-screen min-h-screen" data-search-suggestions-url-value="<%= spree.search_suggestions_path %>">
|
|
3
3
|
<div class='hidden lg:flex justify-center w-full mt-4 mb-3' id="header-logo">
|
|
4
4
|
<%= render 'spree/shared/logo', logo: logo, height: logo_height %>
|
data/config/locales/en.yml
CHANGED
|
@@ -59,6 +59,8 @@ en:
|
|
|
59
59
|
join: Email me about new products, sales, and more. You can unsubscribe at any time.
|
|
60
60
|
status: You are currently %{status} to the newsletters.
|
|
61
61
|
products:
|
|
62
|
+
decrease_quantity: Decrease quantity
|
|
63
|
+
increase_quantity: Increase quantity
|
|
62
64
|
pinch_to_zoom_html: Pinch to<br>zoom
|
|
63
65
|
primary_image: primary image
|
|
64
66
|
secondary_image: secondary image
|
|
@@ -6,6 +6,8 @@ module Spree
|
|
|
6
6
|
class InstallGenerator < Rails::Generators::Base
|
|
7
7
|
desc 'Installs Spree Storefront'
|
|
8
8
|
|
|
9
|
+
class_option :migrate, type: :boolean, default: true, banner: 'Run migrations'
|
|
10
|
+
|
|
9
11
|
def self.source_paths
|
|
10
12
|
[
|
|
11
13
|
File.expand_path('templates', __dir__),
|
|
@@ -14,10 +16,16 @@ module Spree
|
|
|
14
16
|
]
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
def install_page_builder
|
|
20
|
+
say_status :installing, 'page builder'
|
|
21
|
+
migrate_option = options[:migrate] == false ? ' --migrate=false' : ''
|
|
22
|
+
generate "spree:page_builder:install --force#{migrate_option}"
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
def install
|
|
18
26
|
empty_directory Rails.root.join('app/assets/tailwind') if Rails.root && !Rails.root.join('app/assets/tailwind').exist?
|
|
19
|
-
template 'application.css', 'app/assets/tailwind/application.css'
|
|
20
|
-
template 'tailwind.config.js', 'config/tailwind.config.js'
|
|
27
|
+
template 'application.css', 'app/assets/tailwind/application.css', force: options[:force]
|
|
28
|
+
template 'tailwind.config.js', 'config/tailwind.config.js', force: options[:force]
|
|
21
29
|
|
|
22
30
|
if Rails.root && Rails.root.join("Procfile.dev").exist?
|
|
23
31
|
append_to_file 'Procfile.dev', "\nstorefront_css: bin/rails tailwindcss:watch" unless File.read('Procfile.dev').include?('storefront_css:')
|
|
@@ -40,8 +48,8 @@ module Spree
|
|
|
40
48
|
append_to_file 'app/assets/config/manifest.js', "\n//= link_tree ../builds" unless File.read('app/assets/config/manifest.js').include?('//= link_tree ../builds')
|
|
41
49
|
end
|
|
42
50
|
|
|
43
|
-
# remove static robots.txt as
|
|
44
|
-
remove_file
|
|
51
|
+
# remove static robots.txt as storefront serves it dynamically via seo#robots
|
|
52
|
+
remove_file 'public/robots.txt'
|
|
45
53
|
end
|
|
46
54
|
end
|
|
47
55
|
end
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
@import url('https://esm.sh/swiper@11.2.2/swiper-bundle.min.css');
|
|
2
|
-
@import url('https://esm.sh/flag-icons@7.3.2/css/flag-icons.min.css');
|
|
3
|
-
|
|
4
1
|
@import 'tailwindcss';
|
|
5
2
|
@plugin "@tailwindcss/typography";
|
|
6
3
|
@plugin "@tailwindcss/forms";
|
|
@@ -135,7 +132,7 @@ html {
|
|
|
135
132
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
136
133
|
}
|
|
137
134
|
|
|
138
|
-
body .section-header {
|
|
135
|
+
body:not(.inside-page-builder) > div.section-header {
|
|
139
136
|
@apply sticky top-0 z-50;
|
|
140
137
|
}
|
|
141
138
|
|
|
@@ -1853,3 +1850,47 @@ body:has(.currency-and-locale-modal:not(.hidden)) .page-contents {
|
|
|
1853
1850
|
aspect-ratio: 1.77;
|
|
1854
1851
|
}
|
|
1855
1852
|
}
|
|
1853
|
+
|
|
1854
|
+
/* Pagy pagination styles */
|
|
1855
|
+
.pagy.series-nav {
|
|
1856
|
+
display: flex;
|
|
1857
|
+
align-items: center;
|
|
1858
|
+
justify-content: center;
|
|
1859
|
+
gap: 0.25rem;
|
|
1860
|
+
margin-top: 4rem;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
.pagy.series-nav a {
|
|
1864
|
+
display: inline-flex;
|
|
1865
|
+
justify-content: center;
|
|
1866
|
+
align-items: center;
|
|
1867
|
+
width: 2rem;
|
|
1868
|
+
text-align: center;
|
|
1869
|
+
padding: 0.25rem;
|
|
1870
|
+
border-radius: 0.25rem;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
.pagy.series-nav a[rel="prev"],
|
|
1874
|
+
.pagy.series-nav a[rel="next"] {
|
|
1875
|
+
width: auto;
|
|
1876
|
+
padding-left: 1rem;
|
|
1877
|
+
padding-right: 1rem;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
.pagy.series-nav a[aria-disabled="true"] {
|
|
1881
|
+
opacity: 0.5;
|
|
1882
|
+
cursor: default;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
.pagy.series-nav a[aria-current="page"] {
|
|
1886
|
+
font-weight: 600;
|
|
1887
|
+
text-decoration: underline;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
.pagy.series-nav a:not([aria-disabled="true"]):hover {
|
|
1891
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
.pagy.series-nav a[role="separator"] {
|
|
1895
|
+
width: 2rem;
|
|
1896
|
+
}
|
|
@@ -9,6 +9,9 @@ module Spree
|
|
|
9
9
|
preference :products_per_page, :integer, default: 20
|
|
10
10
|
|
|
11
11
|
preference :search_min_query_length, :integer, default: 2
|
|
12
|
+
|
|
13
|
+
# Pagination preference - set to true to use legacy Kaminari pagination
|
|
14
|
+
preference :use_kaminari_pagination, :boolean, default: false
|
|
12
15
|
end
|
|
13
16
|
end
|
|
14
17
|
end
|
data/lib/spree/storefront.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spree'
|
|
2
|
+
require 'spree_page_builder'
|
|
2
3
|
|
|
3
4
|
require 'active_link_to'
|
|
4
|
-
require 'canonical-rails'
|
|
5
5
|
require 'heroicon'
|
|
6
6
|
require 'importmap-rails'
|
|
7
7
|
require 'local_time'
|
|
@@ -10,6 +10,7 @@ require 'stimulus-rails'
|
|
|
10
10
|
require 'tailwindcss-rails'
|
|
11
11
|
require 'turbo-rails'
|
|
12
12
|
require 'inline_svg'
|
|
13
|
+
require 'pagy'
|
|
13
14
|
|
|
14
15
|
require 'spree/storefront/engine'
|
|
15
16
|
require 'spree/core/partials'
|