spree_storefront 5.0.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 +7 -0
- data/LICENSE.md +13 -0
- data/Rakefile +15 -0
- data/app/assets/config/spree_storefront_manifest.js +6 -0
- data/app/assets/stylesheets/storefront_page_builder.css +51 -0
- data/app/controllers/concerns/spree/cart_methods.rb +40 -0
- data/app/controllers/concerns/spree/locale_urls.rb +23 -0
- data/app/controllers/concerns/spree/password_protected.rb +17 -0
- data/app/controllers/concerns/spree/theme_concern.rb +29 -0
- data/app/controllers/spree/account/addresses_controller.rb +16 -0
- data/app/controllers/spree/account/base_controller.rb +20 -0
- data/app/controllers/spree/account/newsletter_controller.rb +34 -0
- data/app/controllers/spree/account/orders_controller.rb +34 -0
- data/app/controllers/spree/account/profile_controller.rb +23 -0
- data/app/controllers/spree/account/store_credits_controller.rb +23 -0
- data/app/controllers/spree/account/wished_items_controller.rb +45 -0
- data/app/controllers/spree/addresses_controller.rb +101 -0
- data/app/controllers/spree/checkout_controller.rb +365 -0
- data/app/controllers/spree/contacts_controller.rb +46 -0
- data/app/controllers/spree/digital_links_controller.rb +48 -0
- data/app/controllers/spree/home_controller.rb +5 -0
- data/app/controllers/spree/line_items_controller.rb +96 -0
- data/app/controllers/spree/newsletter_subscribers_controller.rb +43 -0
- data/app/controllers/spree/order_status_controller.rb +32 -0
- data/app/controllers/spree/orders_controller.rb +104 -0
- data/app/controllers/spree/page_sections_controller.rb +17 -0
- data/app/controllers/spree/pages_controller.rb +13 -0
- data/app/controllers/spree/password_controller.rb +21 -0
- data/app/controllers/spree/policies_controller.rb +17 -0
- data/app/controllers/spree/posts_controller.rb +76 -0
- data/app/controllers/spree/products_controller.rb +99 -0
- data/app/controllers/spree/search_controller.rb +39 -0
- data/app/controllers/spree/seo_controller.rb +25 -0
- data/app/controllers/spree/settings_controller.rb +68 -0
- data/app/controllers/spree/store_controller.rb +247 -0
- data/app/controllers/spree/taxonomies_controller.rb +30 -0
- data/app/controllers/spree/taxons_controller.rb +46 -0
- data/app/controllers/spree/wishlists_controller.rb +19 -0
- data/app/finders/spree/storefront/variant_finder.rb +80 -0
- data/app/helpers/spree/analytics_helper.rb +28 -0
- data/app/helpers/spree/cart_helper.rb +48 -0
- data/app/helpers/spree/checkout_analytics_helper.rb +77 -0
- data/app/helpers/spree/checkout_helper.rb +58 -0
- data/app/helpers/spree/filters_helper.rb +180 -0
- data/app/helpers/spree/fonts_helper.rb +58 -0
- data/app/helpers/spree/orders_helper.rb +7 -0
- data/app/helpers/spree/page_helper.rb +67 -0
- data/app/helpers/spree/posts_helper.rb +42 -0
- data/app/helpers/spree/products_helper.rb +205 -0
- data/app/helpers/spree/storefront_helper.rb +86 -0
- data/app/helpers/spree/storefront_locale_helper.rb +42 -0
- data/app/helpers/spree/theme_helper.rb +244 -0
- data/app/helpers/spree/turbo_helper.rb +13 -0
- data/app/helpers/spree/turbo_stream_actions_helper.rb +13 -0
- data/app/helpers/spree/wishlist_helper.rb +7 -0
- data/app/javascript/spree/storefront/application.js +156 -0
- data/app/javascript/spree/storefront/controllers/accordion_controller.js +25 -0
- data/app/javascript/spree/storefront/controllers/account_nav_controller.js +10 -0
- data/app/javascript/spree/storefront/controllers/card_validation_controller.js +103 -0
- data/app/javascript/spree/storefront/controllers/carousel_controller.js +44 -0
- data/app/javascript/spree/storefront/controllers/cart_controller.js +10 -0
- data/app/javascript/spree/storefront/controllers/checkout_address_book_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/checkout_delivery_controller.js +39 -0
- data/app/javascript/spree/storefront/controllers/checkout_promotions_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/checkout_summary_controller.js +46 -0
- data/app/javascript/spree/storefront/controllers/clear_input_controller.js +23 -0
- data/app/javascript/spree/storefront/controllers/copy_input_controller.js +19 -0
- data/app/javascript/spree/storefront/controllers/dropdown_controller.js +14 -0
- data/app/javascript/spree/storefront/controllers/header_controller.js +33 -0
- data/app/javascript/spree/storefront/controllers/infinite_scroll_controller.js +31 -0
- data/app/javascript/spree/storefront/controllers/lightbox_controller.js +138 -0
- data/app/javascript/spree/storefront/controllers/mobile_nav_controller.js +17 -0
- data/app/javascript/spree/storefront/controllers/modal_controller.js +15 -0
- data/app/javascript/spree/storefront/controllers/no_ui_slider_controller.js +55 -0
- data/app/javascript/spree/storefront/controllers/pdp_desktop_gallery_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/plp_variant_picker_controller.js +151 -0
- data/app/javascript/spree/storefront/controllers/product_form_controller.js +136 -0
- data/app/javascript/spree/storefront/controllers/quantity_picker_controller.js +43 -0
- data/app/javascript/spree/storefront/controllers/search_suggestions_controller.js +61 -0
- data/app/javascript/spree/storefront/controllers/searchable_list_controller.js +25 -0
- data/app/javascript/spree/storefront/controllers/slideover_controller.js +40 -0
- data/app/javascript/spree/storefront/controllers/sticky_button_controller.js +32 -0
- data/app/javascript/spree/storefront/controllers/toggle_menu_controller.js +32 -0
- data/app/javascript/spree/storefront/controllers/turbo_stream_form_controller.js +51 -0
- data/app/javascript/spree/storefront/controllers/wished_item_controller.js +69 -0
- data/app/javascript/spree/storefront/helpers/lazy_load_controllers_with_manifest.js +78 -0
- data/app/javascript/spree/storefront/helpers/show_flash_message.js +25 -0
- data/app/models/spree/color_names.rb +35 -0
- data/app/models/spree/contact.rb +24 -0
- data/app/presenters/spree/colors_preview_styles_presenter.rb +84 -0
- data/app/presenters/spree/featured_product_presenter.rb +42 -0
- data/app/presenters/spree/mega_nav_presenter.rb +55 -0
- data/app/views/devise/passwords/edit.html.erb +22 -0
- data/app/views/devise/passwords/new.html.erb +16 -0
- data/app/views/devise/registrations/_form.html.erb +21 -0
- data/app/views/devise/registrations/edit.html.erb +24 -0
- data/app/views/devise/registrations/new.html.erb +27 -0
- data/app/views/devise/sessions/new.html.erb +25 -0
- data/app/views/devise/shared/_links.html.erb +22 -0
- data/app/views/layouts/spree/checkout.html.erb +58 -0
- data/app/views/layouts/spree/password.html.erb +34 -0
- data/app/views/layouts/spree/storefront.html.erb +38 -0
- data/app/views/spree/account/wished_items/create.turbo_stream.erb +8 -0
- data/app/views/spree/account/wished_items/destroy.turbo_stream.erb +20 -0
- data/app/views/spree/addresses/destroy.turbo_stream.erb +1 -0
- data/app/views/spree/addresses/edit.html.erb +57 -0
- data/app/views/spree/addresses/new.html.erb +71 -0
- data/app/views/spree/checkout/_address.html.erb +153 -0
- data/app/views/spree/checkout/_button_processing.html.erb +7 -0
- data/app/views/spree/checkout/_coupon_code.html.erb +55 -0
- data/app/views/spree/checkout/_credit_card.html.erb +12 -0
- data/app/views/spree/checkout/_delivery.html.erb +70 -0
- data/app/views/spree/checkout/_line_item.html.erb +26 -0
- data/app/views/spree/checkout/_line_items.html.erb +7 -0
- data/app/views/spree/checkout/_missing_all_line_items.html.erb +17 -0
- data/app/views/spree/checkout/_missing_line_items.html.erb +28 -0
- data/app/views/spree/checkout/_payment.html.erb +35 -0
- data/app/views/spree/checkout/_payment_methods.html.erb +72 -0
- data/app/views/spree/checkout/_payment_sources.html.erb +24 -0
- data/app/views/spree/checkout/_quick_checkout.html.erb +1 -0
- data/app/views/spree/checkout/_sidebar.html.erb +34 -0
- data/app/views/spree/checkout/_store_credit.html.erb +21 -0
- data/app/views/spree/checkout/_summary.html.erb +116 -0
- data/app/views/spree/checkout/_user_account.html.erb +9 -0
- data/app/views/spree/checkout/apply_coupon_code.turbo_stream.erb +45 -0
- data/app/views/spree/checkout/apply_store_credit.turbo_stream.erb +19 -0
- data/app/views/spree/checkout/edit.html.erb +98 -0
- data/app/views/spree/checkout/payment/_check.html.erb +0 -0
- data/app/views/spree/checkout/payment/_gateway.html.erb +74 -0
- data/app/views/spree/checkout/payment/_store_credit.html.erb +13 -0
- data/app/views/spree/checkout/remove_coupon_code.turbo_stream.erb +34 -0
- data/app/views/spree/checkout/remove_store_credit.turbo_stream.erb +19 -0
- data/app/views/spree/checkout/update.turbo_stream.erb +25 -0
- data/app/views/spree/home/index.html.erb +1 -0
- data/app/views/spree/line_items/create.turbo_stream.erb +13 -0
- data/app/views/spree/line_items/destroy.turbo_stream.erb +11 -0
- data/app/views/spree/line_items/update.turbo_stream.erb +10 -0
- data/app/views/spree/newsletter_subscribers/create.turbo_stream.erb +7 -0
- data/app/views/spree/order_status/new.html.erb +16 -0
- data/app/views/spree/page_sections/show.html.erb +3 -0
- data/app/views/spree/pages/show.html.erb +1 -0
- data/app/views/spree/password/show.html.erb +1 -0
- data/app/views/spree/posts/index.html.erb +1 -0
- data/app/views/spree/posts/related_products.html.erb +7 -0
- data/app/views/spree/posts/show.html.erb +1 -0
- data/app/views/spree/products/index.html.erb +1 -0
- data/app/views/spree/products/index.turbo_stream.erb +1 -0
- data/app/views/spree/products/related.html.erb +3 -0
- data/app/views/spree/products/show.html.erb +1 -0
- data/app/views/spree/search/show.html.erb +6 -0
- data/app/views/spree/search/show.turbo_stream.erb +1 -0
- data/app/views/spree/search/suggestions.turbo_stream.erb +8 -0
- data/app/views/spree/seo/robots.text.erb +31 -0
- data/app/views/spree/seo/sitemap.xml.erb +25 -0
- data/app/views/spree/shared/_fonts.html.erb +14 -0
- data/app/views/spree/shared/_head.html.erb +36 -0
- data/app/views/spree/shared/_load_more_products.turbo_stream.erb +7 -0
- data/app/views/spree/shared/_product_listing_page.html.erb +11 -0
- data/app/views/spree/shared/_products.html.erb +1 -0
- data/app/views/spree/taxonomies/show.html.erb +1 -0
- data/app/views/spree/taxons/show.html.erb +1 -0
- data/app/views/spree/taxons/show.turbo_stream.erb +1 -0
- data/app/views/spree/waitlists/create.turbo_stream.erb +9 -0
- data/app/views/themes/default/kaminari/storefront/_first_page.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_gap.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_last_page.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_next_page.html.erb +13 -0
- data/app/views/themes/default/kaminari/storefront/_page.html.erb +10 -0
- data/app/views/themes/default/kaminari/storefront/_paginator.html.erb +27 -0
- data/app/views/themes/default/kaminari/storefront/_prev_page.html.erb +13 -0
- data/app/views/themes/default/spree/account/_account_nav.html.erb +46 -0
- data/app/views/themes/default/spree/account/_order.html.erb +39 -0
- data/app/views/themes/default/spree/account/_orders.html.erb +16 -0
- data/app/views/themes/default/spree/account/addresses/_address.html.erb +42 -0
- data/app/views/themes/default/spree/account/addresses/index.html.erb +28 -0
- data/app/views/themes/default/spree/account/newsletter/_newsletter_settings.html.erb +13 -0
- data/app/views/themes/default/spree/account/newsletter/edit.html.erb +16 -0
- data/app/views/themes/default/spree/account/newsletter/update.html.erb +1 -0
- data/app/views/themes/default/spree/account/orders/index.html.erb +24 -0
- data/app/views/themes/default/spree/account/orders/show.html.erb +22 -0
- data/app/views/themes/default/spree/account/profile/edit.html.erb +36 -0
- data/app/views/themes/default/spree/account/store_credits/_store_credit_event.html.erb +29 -0
- data/app/views/themes/default/spree/account/store_credits/index.html.erb +31 -0
- data/app/views/themes/default/spree/checkout/_footer.html.erb +10 -0
- data/app/views/themes/default/spree/checkout/complete.html.erb +84 -0
- data/app/views/themes/default/spree/contacts/new.html.erb +23 -0
- data/app/views/themes/default/spree/orders/_cart.html.erb +14 -0
- data/app/views/themes/default/spree/orders/_empty.html.erb +11 -0
- data/app/views/themes/default/spree/orders/_line_item.html.erb +47 -0
- data/app/views/themes/default/spree/orders/_line_item_quantity.html.erb +11 -0
- data/app/views/themes/default/spree/orders/_summary.html.erb +41 -0
- data/app/views/themes/default/spree/orders/edit.html.erb +18 -0
- data/app/views/themes/default/spree/orders/show.html.erb +6 -0
- data/app/views/themes/default/spree/page_sections/_announcement_bar.html.erb +10 -0
- data/app/views/themes/default/spree/page_sections/_custom_code.html.erb +5 -0
- data/app/views/themes/default/spree/page_sections/_featured_product.html.erb +136 -0
- data/app/views/themes/default/spree/page_sections/_featured_taxon.html.erb +116 -0
- data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +71 -0
- data/app/views/themes/default/spree/page_sections/_footer.html.erb +62 -0
- data/app/views/themes/default/spree/page_sections/_header.html.erb +166 -0
- data/app/views/themes/default/spree/page_sections/_image_banner.html.erb +57 -0
- data/app/views/themes/default/spree/page_sections/_image_with_text.html.erb +66 -0
- data/app/views/themes/default/spree/page_sections/_main_password_footer.html.erb +64 -0
- data/app/views/themes/default/spree/page_sections/_main_password_header.html.erb +54 -0
- data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +47 -0
- data/app/views/themes/default/spree/page_sections/_page_title.html.erb +7 -0
- data/app/views/themes/default/spree/page_sections/_post_details.html.erb +19 -0
- data/app/views/themes/default/spree/page_sections/_post_grid.html.erb +11 -0
- data/app/views/themes/default/spree/page_sections/_product_details.html.erb +102 -0
- data/app/views/themes/default/spree/page_sections/_product_grid.html.erb +52 -0
- data/app/views/themes/default/spree/page_sections/_related_products.html.erb +15 -0
- data/app/views/themes/default/spree/page_sections/_rich_text.html.erb +18 -0
- data/app/views/themes/default/spree/page_sections/_taxon_banner.html.erb +37 -0
- data/app/views/themes/default/spree/page_sections/_taxon_grid.html.erb +103 -0
- data/app/views/themes/default/spree/page_sections/_video.html.erb +27 -0
- data/app/views/themes/default/spree/page_sections/nav/_desktop.html.erb +49 -0
- data/app/views/themes/default/spree/page_sections/nav/_mobile.html.erb +136 -0
- data/app/views/themes/default/spree/policies/show.html.erb +11 -0
- data/app/views/themes/default/spree/posts/_json_ld.html.erb +20 -0
- data/app/views/themes/default/spree/posts/_pagination.html.erb +1 -0
- data/app/views/themes/default/spree/posts/_post.html.erb +13 -0
- data/app/views/themes/default/spree/products/_add_to_cart_button.html.erb +58 -0
- data/app/views/themes/default/spree/products/_add_to_waitlist.html.erb +36 -0
- data/app/views/themes/default/spree/products/_add_to_wishlist.html.erb +33 -0
- data/app/views/themes/default/spree/products/_breadcrumbs.html.erb +23 -0
- data/app/views/themes/default/spree/products/_color_picker.html.erb +19 -0
- data/app/views/themes/default/spree/products/_color_swatches.html.erb +61 -0
- data/app/views/themes/default/spree/products/_details.html.erb +55 -0
- data/app/views/themes/default/spree/products/_featured_image.html.erb +37 -0
- data/app/views/themes/default/spree/products/_filters.html.erb +45 -0
- data/app/views/themes/default/spree/products/_json_ld.html.erb +38 -0
- data/app/views/themes/default/spree/products/_json_ld_list.html.erb +9 -0
- data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +10 -0
- data/app/views/themes/default/spree/products/_label.html.erb +26 -0
- data/app/views/themes/default/spree/products/_media_gallery.html.erb +94 -0
- data/app/views/themes/default/spree/products/_price.html.erb +59 -0
- data/app/views/themes/default/spree/products/_product.html.erb +62 -0
- data/app/views/themes/default/spree/products/_quantity_selector.html.erb +32 -0
- data/app/views/themes/default/spree/products/_returns_policy_modal.html.erb +22 -0
- data/app/views/themes/default/spree/products/_show_more_button.html.erb +8 -0
- data/app/views/themes/default/spree/products/_sort.html.erb +45 -0
- data/app/views/themes/default/spree/products/_swiper.html.erb +85 -0
- data/app/views/themes/default/spree/products/_tags.html.erb +0 -0
- data/app/views/themes/default/spree/products/_variant_options.html.erb +71 -0
- data/app/views/themes/default/spree/products/_variant_picker.html.erb +50 -0
- data/app/views/themes/default/spree/products/filters/_availability.html.erb +32 -0
- data/app/views/themes/default/spree/products/filters/_colors.html.erb +23 -0
- data/app/views/themes/default/spree/products/filters/_generic.html.erb +75 -0
- data/app/views/themes/default/spree/products/filters/_price.html.erb +35 -0
- data/app/views/themes/default/spree/products/filters/_taxons.erb +78 -0
- data/app/views/themes/default/spree/search/_suggestions.html.erb +92 -0
- data/app/views/themes/default/spree/settings/show.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_account_pane.html.erb +28 -0
- data/app/views/themes/default/spree/shared/_address.html.erb +35 -0
- data/app/views/themes/default/spree/shared/_cart_icon.html.erb +13 -0
- data/app/views/themes/default/spree/shared/_cart_pane.html.erb +38 -0
- data/app/views/themes/default/spree/shared/_css_variables.html.erb +54 -0
- data/app/views/themes/default/spree/shared/_custom_head.html.erb +0 -0
- data/app/views/themes/default/spree/shared/_error_messages.html.erb +9 -0
- data/app/views/themes/default/spree/shared/_error_messages_without_base_attribute.html.erb +15 -0
- data/app/views/themes/default/spree/shared/_flash.html.erb +16 -0
- data/app/views/themes/default/spree/shared/_flashes.html.erb +10 -0
- data/app/views/themes/default/spree/shared/_json_ld.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_line_item_options.html.erb +18 -0
- data/app/views/themes/default/spree/shared/_logo.html.erb +42 -0
- data/app/views/themes/default/spree/shared/_meta_tags.html.erb +45 -0
- data/app/views/themes/default/spree/shared/_order_details.html.erb +106 -0
- data/app/views/themes/default/spree/shared/_order_line_item.html.erb +65 -0
- data/app/views/themes/default/spree/shared/_order_shipment.html.erb +71 -0
- data/app/views/themes/default/spree/shared/_search.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_title.html.erb +3 -0
- data/app/views/themes/default/spree/shared/_wishlist_icon.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_account.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_arrow-left.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_arrow-right.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_bell.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_cart.html.erb +10 -0
- data/app/views/themes/default/spree/shared/icons/_cart_48.html.erb +6 -0
- data/app/views/themes/default/spree/shared/icons/_check.html.erb +4 -0
- data/app/views/themes/default/spree/shared/icons/_chevron.html.erb +15 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_down.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_right.html.erb +15 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_up.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_close.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_cross.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_delete.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_delivery.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_disabled.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_edit.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_facebook.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_filter.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_heart.html.erb +12 -0
- data/app/views/themes/default/spree/shared/icons/_info.html.erb +7 -0
- data/app/views/themes/default/spree/shared/icons/_instagram.html.erb +18 -0
- data/app/views/themes/default/spree/shared/icons/_lock.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_menu.html.erb +10 -0
- data/app/views/themes/default/spree/shared/icons/_minus.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_pinch.html.erb +6 -0
- data/app/views/themes/default/spree/shared/icons/_pinterest.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_plus.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_return.html.erb +11 -0
- data/app/views/themes/default/spree/shared/icons/_search.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_spinner.html.erb +1 -0
- data/app/views/themes/default/spree/shared/icons/_spotify.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_tiktok.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_twitter.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_youtube.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_zoom.html.erb +10 -0
- data/app/views/themes/default/spree/wishlists/_no_wished_items.html.erb +10 -0
- data/app/views/themes/default/spree/wishlists/_wished_item.html.erb +38 -0
- data/app/views/themes/default/spree/wishlists/show.html.erb +17 -0
- data/config/i18n-tasks.yml +176 -0
- data/config/importmap.rb +22 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/heroicon.rb +10 -0
- data/config/locales/en.yml +76 -0
- data/config/routes.rb +88 -0
- data/lib/generators/spree/storefront/install/install_generator.rb +45 -0
- data/lib/generators/spree/storefront/install/templates/application.tailwind.css +1760 -0
- data/lib/generators/spree/storefront/install/templates/dev +16 -0
- data/lib/generators/spree/storefront/install/templates/tailwind.config.js +128 -0
- data/lib/generators/spree/storefront/theme/templates/model.rb.tt +12 -0
- data/lib/generators/spree/storefront/theme/theme_generator.rb +41 -0
- data/lib/spree/storefront/configuration.rb +11 -0
- data/lib/spree/storefront/engine.rb +51 -0
- data/lib/spree/storefront/testing_support/capybara_utils.rb +13 -0
- data/lib/spree/storefront.rb +16 -0
- data/lib/spree_storefront.rb +1 -0
- data/vendor/colornames.json +1 -0
- data/vendor/javascript/@kanety--stimulus-accordion.js +4 -0
- data/vendor/javascript/@stimulus-components--carousel.js +4 -0
- data/vendor/javascript/card-validator.js +4 -0
- data/vendor/javascript/credit-card-type.js +4 -0
- data/vendor/javascript/headroom.js.js +19 -0
- data/vendor/javascript/nouislider.js +4 -0
- data/vendor/javascript/photoswipe--dist--photoswipe-lightbox.esm.js.js +667 -0
- data/vendor/javascript/photoswipe.js +1675 -0
- data/vendor/javascript/stimulus-read-more.js +4 -0
- data/vendor/javascript/stimulus-scroll-to.js +4 -0
- data/vendor/javascript/swiper--bundle.js +4 -0
- metadata +567 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
<%
|
2
|
+
sticky_button_classes ||= ''
|
3
|
+
without_fixed_button ||= false
|
4
|
+
options_param_name ||= :options
|
5
|
+
not_selected_options = product_not_selected_options(product, selected_variant, options_param_name: options_param_name)
|
6
|
+
all_options_selected = (params[options_param_name].present? || @variant_from_options.present?) && not_selected_options.empty?
|
7
|
+
not_all_options_selected = !all_options_selected && product.any_variant_available?(current_currency)
|
8
|
+
variant_not_available = selected_variant.nil? ||
|
9
|
+
product.discontinued? ||
|
10
|
+
selected_variant.discontinued? ||
|
11
|
+
!selected_variant.purchasable? ||
|
12
|
+
selected_variant.price_in(current_currency).amount.nil?
|
13
|
+
%>
|
14
|
+
|
15
|
+
<div class='<%= sticky_button_classes %> bottom-0 flex flex-col gap-4 z-10' data-sticky-button-target='stickyButton'>
|
16
|
+
<%= button_tag type: (variant_not_available || not_all_options_selected ? 'button' : 'submit'),
|
17
|
+
class: 'btn-primary btn-icon w-full h-12 add-to-cart-button',
|
18
|
+
data: {
|
19
|
+
action: ('modal#open' if variant_not_available),
|
20
|
+
product_form_target: 'submit'
|
21
|
+
},
|
22
|
+
disabled: product.price_in(current_currency).zero? do %>
|
23
|
+
<% if not_selected_options.size == 1 %>
|
24
|
+
<span><%= Spree.t(:please_select, option: not_selected_options[0].presentation) %></span>
|
25
|
+
<% elsif not_all_options_selected %>
|
26
|
+
<span><%= Spree.t(:please_select_all_options) %></span>
|
27
|
+
<% elsif variant_not_available %>
|
28
|
+
<span><%= Spree.t(:notify_me_when_available) %></span>
|
29
|
+
<%= render 'spree/shared/icons/bell' %>
|
30
|
+
<% else %>
|
31
|
+
<span><%= Spree.t(:add_to_cart) %></span>
|
32
|
+
<%= render 'spree/shared/icons/cart' %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
<% unless without_fixed_button %>
|
37
|
+
<div class='p-4 fixed-pdp-button bg-background fixed bottom-0 border-t border-default hidden w-full z-40 left-0' data-sticky-button-target='fixedButton'>
|
38
|
+
<%= button_tag type: (variant_not_available || not_all_options_selected ? 'button' : 'submit'),
|
39
|
+
class: 'btn-primary btn-icon w-full h-12 add-to-cart-button',
|
40
|
+
data: {
|
41
|
+
action: ('modal#open' if variant_not_available),
|
42
|
+
product_form_target: 'submit'
|
43
|
+
},
|
44
|
+
disabled: product.price_in(current_currency).zero? do %>
|
45
|
+
<% if not_selected_options.size == 1 %>
|
46
|
+
<span><%= Spree.t(:please_select, option: not_selected_options[0].presentation) %></span>
|
47
|
+
<% elsif not_all_options_selected %>
|
48
|
+
<span><%= Spree.t(:please_select_all_options) %></span>
|
49
|
+
<% elsif variant_not_available %>
|
50
|
+
<span><%= Spree.t(:notify_me_when_available) %></span>
|
51
|
+
<%= render 'spree/shared/icons/bell' %>
|
52
|
+
<% else %>
|
53
|
+
<span><%= Spree.t(:add_to_cart) %></span>
|
54
|
+
<%= render 'spree/shared/icons/cart' %>
|
55
|
+
<% end %>
|
56
|
+
<% end %>
|
57
|
+
</div>
|
58
|
+
<% end %>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<div
|
2
|
+
data-modal-target="container"
|
3
|
+
data-action="waitlist:created@window->modal#close click->modal#closeBackground keyup@window->modal#closeWithKeyboard"
|
4
|
+
class="hidden animate-fadeIn fixed inset-0 overflow-y-auto flex items-end md:items-center justify-center z-[9999] h-dvh w-full"
|
5
|
+
style="animation-duration: 150ms;">
|
6
|
+
<div class="w-full lg:w-[600px] relative h-auto lg:max-h-screen flex justify-center flex-col gap-4 bg-background p-5 ">
|
7
|
+
<button
|
8
|
+
type="button"
|
9
|
+
data-waitlist-close-button
|
10
|
+
data-action="modal#close"
|
11
|
+
class="absolute top-5 right-5">
|
12
|
+
<%= render 'spree/shared/icons/close' %>
|
13
|
+
</button>
|
14
|
+
<div>
|
15
|
+
<h4 class="text-xl">
|
16
|
+
<%= Spree.t(:product_sold_out)%>
|
17
|
+
</h4>
|
18
|
+
<p>
|
19
|
+
<%= Spree.t(:add_to_waitlist_description) %>
|
20
|
+
</p>
|
21
|
+
</div>
|
22
|
+
<%= form_for :waitlist, url: spree.waitlists_path, method: :post, class: "flex w-full gap-4 flex-col", data: { product_form_target: 'addToWaitlistForm', controller: 'turbo-stream-form enable-button' } do |f| %>
|
23
|
+
<div class="w-full">
|
24
|
+
<%= f.hidden_field :variant_id, value: variant.id %>
|
25
|
+
<%= f.email_field :email, value: try_spree_current_user&.email, class: 'w-full', required: true, placeholder: Spree.t(:email), data: { enable_button_target: 'input' } %>
|
26
|
+
</div>
|
27
|
+
<div class="flex flex-col gap-2">
|
28
|
+
<label class="flex items-center gap-2 cursor-pointer group text-sm">
|
29
|
+
<%= f.check_box :subscribe_to_newsletter, class: 'input-checkbox group-focus-within:outline' %>
|
30
|
+
<%= Spree.t('storefront.newsletter_subscription.join') %>
|
31
|
+
</label>
|
32
|
+
<%= f.button Spree.t(:add_to_waitlist), type: 'submit', class: 'btn-primary w-full btn-icon h-12', disabled: true, data: { enable_button_target: 'button' } %>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
</div>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<% css_classes ||= 'btn-icon btn--wishlist' %>
|
2
|
+
<% icon_size ||= 18 %>
|
3
|
+
<% variant ||= nil %>
|
4
|
+
<div class="add-to-wishlist">
|
5
|
+
<% if variant %>
|
6
|
+
<div class="wished-item-<%= variant.id %> h-full"
|
7
|
+
data-controller="wished-item"
|
8
|
+
data-wished-item-variant-id-value="<%= variant.id %>"
|
9
|
+
>
|
10
|
+
<%= button_tag type: 'submit',
|
11
|
+
class: "#{css_classes} disabled:animate-pulse",
|
12
|
+
data: { 'wished-item-target': 'add', action: 'wished-item#add' },
|
13
|
+
aria: { label: Spree.t('storefront.wished_items.add') } do %>
|
14
|
+
<%= render 'spree/shared/icons/heart', width: icon_size, height: icon_size %>
|
15
|
+
<span class="sr-only"><%= Spree.t('storefront.wished_items.add') %></span>
|
16
|
+
<% end %>
|
17
|
+
<%= button_tag type: 'submit',
|
18
|
+
class: "#{css_classes} disabled:animate-pulse",
|
19
|
+
data: { 'wished-item-target': 'remove', action: 'wished-item#remove' },
|
20
|
+
aria: { label: Spree.t('storefront.wished_items.remove') } do %>
|
21
|
+
<%= render 'spree/shared/icons/heart', active: true, width: icon_size, height: icon_size %>
|
22
|
+
<span class="sr-only"><%= Spree.t('storefront.wished_items.remove') %></span>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
<% else %>
|
26
|
+
<%= button_tag class: "#{css_classes} disabled:text-accent",
|
27
|
+
data: { action: 'product-form#showNotSelectedOptions', 'product-form-target': 'addToWishlist' },
|
28
|
+
aria: { label: Spree.t('storefront.wished_items.select_variant') } do %>
|
29
|
+
<%= render 'spree/shared/icons/heart', width: icon_size, height: icon_size %>
|
30
|
+
<span class="sr-only"><%= Spree.t('storefront.wished_items.select_variant') %></span>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<nav id="breadcrumbs" aria-label="breadcrumbs">
|
2
|
+
<!-- desktop -->
|
3
|
+
<ul class="hidden md:inline-flex space-x-3 mb-4 lg:mb-5 text-sm">
|
4
|
+
<% taxons.each_with_index do |taxon, index| %>
|
5
|
+
<li class="opacity-50"><%= link_to taxon.name, spree.nested_taxons_path(taxon), title: taxon.name %></li>
|
6
|
+
<div class="breadcrumb-square opacity-50"></div>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<li class="text-text opacity-100"><%= product.name %></li>
|
10
|
+
</ul>
|
11
|
+
|
12
|
+
<!-- mobile -->
|
13
|
+
<% if taxons.any? %>
|
14
|
+
<ul class="md:hidden mb-4 text-sm">
|
15
|
+
<li class="opacity-50">
|
16
|
+
<%= link_to spree.nested_taxons_path(taxons.last), title: taxons.last.name, class: 'inline-flex items-center gap-1' do %>
|
17
|
+
<strong><%= render 'spree/shared/icons/chevron', size: 16 %></strong>
|
18
|
+
<%= taxons.last.name %>
|
19
|
+
<% end %>
|
20
|
+
</li>
|
21
|
+
</ul>
|
22
|
+
<% end %>
|
23
|
+
</nav>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<% color_preview_class ||= '' %>
|
2
|
+
<% color_preview_container_class ||= '' %>
|
3
|
+
<% disabled ||= false %>
|
4
|
+
<% with_name ||= false %>
|
5
|
+
|
6
|
+
<div class='border border-default peer-checked:border-primary peer-checked:border-solid p-0.5 inline-flex items-center gap-2 label-container hover:border-dashed hover:border-primary rounded-full'>
|
7
|
+
<div class='color-preview w-[24px] h-[24px] shrink-0 lg:block relative rounded-full <%= color_preview_container_class %> <%= 'opacity-50' if disabled %>'>
|
8
|
+
<% if disabled %>
|
9
|
+
<div class='absolute <%= color_preview_class %>'>
|
10
|
+
<%= render 'spree/shared/icons/disabled', stroke: "var(--border-default-color)" %>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
<% if with_name %>
|
15
|
+
<span class='color-label !leading-[30px] text-sm lg:!block lg:pr-2'>
|
16
|
+
<%= h(color) %>
|
17
|
+
</span>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<% color_option = product.option_types.find { |option_type| option_type.color? } %>
|
2
|
+
<% variants_with_color = product.variants.find_all { |variant| variant.option_values.find { |ov| ov.option_type_id == color_option.id } } if color_option.present? %>
|
3
|
+
|
4
|
+
<% if color_option.present? && variants_with_color.length > 0 %>
|
5
|
+
<% cache spree_base_cache_scope.call(variants_with_color) do %>
|
6
|
+
<% color_values = product.option_values.find_all { |ov| ov.option_type_id == color_option.id }.uniq %>
|
7
|
+
<%= raw(Spree::ColorsPreviewStylesPresenter.new(color_values.map { |o| { name: o.presentation, filter_name: o.name } }).to_s) %>
|
8
|
+
|
9
|
+
<div class="product-card-color-swatches pt-2 flex flex-wrap gap-0.5" data-plp-variant-picker-target="colorsContainer">
|
10
|
+
<% color_values.each do |color_value| %>
|
11
|
+
<% selected_variant = variants_with_color.find { |variant| variant.option_values.include?(color_value) } %>
|
12
|
+
<% next if selected_variant.blank? %>
|
13
|
+
|
14
|
+
<% cache spree_base_cache_scope.call(selected_variant) do %>
|
15
|
+
<div
|
16
|
+
data-variant-id="<%= selected_variant.id %>"
|
17
|
+
class="[&:nth-of-type(n+4)]:hidden [&:nth-of-type(n+4)]:md:block [&:nth-of-type(n+8)]:md:hidden cursor-pointer"
|
18
|
+
data-action="mouseenter->plp-variant-picker#handlePreview click->plp-variant-picker#redirectToVariant touch->plp-variant-picker#redirectToVariant"
|
19
|
+
data-color="<%= color_value.presentation %>">
|
20
|
+
<% if selected_variant.available? %>
|
21
|
+
<%= render 'spree/products/color_picker',
|
22
|
+
with_name: false,
|
23
|
+
color: color_value.presentation,
|
24
|
+
color_preview_container_class: "lg:w-[28px] lg:h-[28px]",
|
25
|
+
color_preview_class: "lg:top-[2px] lg:left-[2px]" %>
|
26
|
+
<% else %>
|
27
|
+
<%= render 'spree/products/color_picker',
|
28
|
+
with_name: false,
|
29
|
+
color: color_value.presentation,
|
30
|
+
disabled: true,
|
31
|
+
color_preview_container_class: "lg:w-[28px] lg:h-[28px]",
|
32
|
+
color_preview_class: "lg:top-[2px] lg:left-[2px]" %>
|
33
|
+
<% end %>
|
34
|
+
<% if selected_variant.default_image %>
|
35
|
+
<template data-featured-image-template>
|
36
|
+
<%= render 'spree/products/featured_image',
|
37
|
+
object: selected_variant %>
|
38
|
+
</template>
|
39
|
+
<% end %>
|
40
|
+
<template data-add-to-wishlist-template>
|
41
|
+
<%= render 'spree/products/add_to_wishlist', selected_variant: selected_variant %>
|
42
|
+
</template>
|
43
|
+
<template data-price-template>
|
44
|
+
<%= render 'spree/products/price',
|
45
|
+
product: product,
|
46
|
+
selected_variant: selected_variant,
|
47
|
+
use_variant: true,
|
48
|
+
price_class: "mt-2 font-light product-card-price" %>
|
49
|
+
</template>
|
50
|
+
<% end %>
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
<% # Plus Button %>
|
54
|
+
<% colors_count = color_values.length %>
|
55
|
+
<%= button_tag class: "border border-default peer-checked:border-primary peer-checked:border-solid p-0.5 items-center justify-center hover:border-dashed hover:border-primary rounded-full h-[30px] w-[30px] md:h-[34px] md:w-[34px] #{colors_count < 4 ? 'hidden' : 'inline-flex'} #{colors_count < 8 ? 'md:hidden' : 'md:inline-flex'}",
|
56
|
+
data: { action: "click->plp-variant-picker#showMoreColors" } do %>
|
57
|
+
<%= render 'spree/shared/icons/plus', class: "pointer-events-none" %>
|
58
|
+
<% end %>
|
59
|
+
</div>
|
60
|
+
<% end %>
|
61
|
+
<% end %>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<% cache spree_base_cache_scope.call(product) do %>
|
2
|
+
<% if product.storefront_description.present? %>
|
3
|
+
<% description_text = strip_tags(product.storefront_description) %>
|
4
|
+
<div data-controller="read-more" class="py-4 flex flex-col gap-4" data-read-more-more-text-value="<%= Spree.t(:read_more) %>" data-read-more-less-text-value="Read less">
|
5
|
+
<div class="prose product-description text-sm <%= 'product-description-truncated' if description_text.size > 250 %>" data-read-more-target="content">
|
6
|
+
<%= raw(product.storefront_description) %>
|
7
|
+
</div>
|
8
|
+
<% if description_text.size > 250 %>
|
9
|
+
<%= button_tag Spree.t(:read_more), data: { action: "read-more#toggle" }, class: "font-bold underline text-sm" %>
|
10
|
+
<% end %>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="st-accordion" data-controller="accordion">
|
15
|
+
<% short_description = product.property('short_description') %>
|
16
|
+
|
17
|
+
<% if short_description.present? %>
|
18
|
+
<div class="product-property py-4 border-b border-default">
|
19
|
+
<%= link_to '#property_details', class: 'text-sm uppercase tracking-widest inline-flex w-full justify-between !border-b-transparent', data: { action: 'accordion#toggle' } do %>
|
20
|
+
<%= Spree.t(:details) %>
|
21
|
+
<%= render 'spree/shared/icons/chevron_down' %>
|
22
|
+
<% end %>
|
23
|
+
<div class="text-sm st-accordion__content" data-accordion-id="property_details">
|
24
|
+
<div class="pt-4"><%= product.description %></div>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<% shipping_policy = current_store.customer_shipping_policy %>
|
30
|
+
<% if shipping_policy.present? %>
|
31
|
+
<div class="product-property py-4 border-b border-default">
|
32
|
+
<%= link_to "#property_shipping_policy", class: 'text-sm uppercase tracking-widest inline-flex w-full justify-between !border-b-transparent', data: { action: 'accordion#toggle' } do %>
|
33
|
+
<%= Spree.t(:shipping_policy) %>
|
34
|
+
<%= render 'spree/shared/icons/chevron_down' %>
|
35
|
+
<% end %>
|
36
|
+
<div class="text-sm st-accordion__content" data-accordion-id="property_shipping_policy">
|
37
|
+
<div class="pt-4"><%= shipping_policy %></div>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<% product.product_properties.joins(:property).merge(Spree::Property.available_on_front_end).sort_by_property_position.each do |product_property| %>
|
43
|
+
<div class="product-property py-4 border-b border-default">
|
44
|
+
|
45
|
+
<%= link_to "#property_#{product_property.id}", class: 'text-sm uppercase tracking-widest inline-flex w-full justify-between !border-b-transparent', data: { action: 'accordion#toggle' } do %>
|
46
|
+
<%= product_property.property.presentation %>
|
47
|
+
<%= render 'spree/shared/icons/chevron_down' %>
|
48
|
+
<% end %>
|
49
|
+
<div class="text-sm st-accordion__content" data-accordion-id="property_<%= product_property.id %>">
|
50
|
+
<div class="pt-4"><%= simple_format(product_property.value) %></div>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
<% end %>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<% with_cover_image ||= true %>
|
2
|
+
<% object ||= product %>
|
3
|
+
|
4
|
+
<% if object.default_image.present? && object.default_image.attached? %>
|
5
|
+
<% height ||= theme_setting('product_listing_image_height') %>
|
6
|
+
<% width ||= theme_setting('product_listing_image_width') %>
|
7
|
+
|
8
|
+
<figure class="group <%= 'aspect-1' if height == width %> card-product-featured-images-container bg-transparent h-full">
|
9
|
+
<% if with_cover_image %>
|
10
|
+
<% object_class = 'object-cover object-center' %>
|
11
|
+
<% else %>
|
12
|
+
<% object_class = 'object-contain object-top' %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<% image_variant_options = spree_image_variant_options(resize_and_pad: [width * 2, height * 2, { alpha: true }]) %>
|
16
|
+
|
17
|
+
<% image_hover_class = object.secondary_image.present? && object.secondary_image.attached? ?
|
18
|
+
"w-full group-hover:opacity-0 transition-opacity duration-500 z-10 relative h-full bg-background product-card !max-h-full #{object_class}" :
|
19
|
+
"w-full h-full !max-h-full #{object_class}" %>
|
20
|
+
|
21
|
+
<%= image_tag main_app.cdn_image_url(object.default_image.variant(image_variant_options)),
|
22
|
+
loading: :lazy,
|
23
|
+
alt: object.default_image.alt,
|
24
|
+
class: image_hover_class %>
|
25
|
+
|
26
|
+
<% if object.secondary_image.present? && object.secondary_image.attached? %>
|
27
|
+
<% secondary_image_class = "w-full absolute top-0 left-0 opacity-100 h-full !max-h-full #{object_class}" %>
|
28
|
+
|
29
|
+
<%= image_tag main_app.cdn_image_url(object.secondary_image.variant(image_variant_options)),
|
30
|
+
loading: :lazy,
|
31
|
+
alt: object.secondary_image.alt,
|
32
|
+
class: secondary_image_class %>
|
33
|
+
<% end %>
|
34
|
+
</figure>
|
35
|
+
<% else %>
|
36
|
+
<div class="w-full aspect-1 bg-accent"></div>
|
37
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<div
|
2
|
+
id="slideover-filters"
|
3
|
+
data-slideover-target="menu"
|
4
|
+
class="sidebar-pane relative flex-1 !flex flex-col w-full pt-4 bg-background md:border-r border-default transition duration-300 -translate-x-full">
|
5
|
+
<div class="flex-shrink-0 flex items-center justify-between pb-4 px-4 border-b border-default">
|
6
|
+
<span class="text-xl uppercase font-medium"><%= Spree.t(:filter) %></span>
|
7
|
+
<%= button_tag type: 'button',
|
8
|
+
class: "flex items-center justify-center rounded-full focus:outline-none focus:bg-background",
|
9
|
+
aria: { label: Spree.t(:close_sidebar) },
|
10
|
+
data: { action: "slideover#toggle" } do %>
|
11
|
+
<%= render 'spree/shared/icons/cross' %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
<%= form_with url: canonical_path, method: :get, class: "pt-4 lg:pt-10 flex-1 h-0 overflow-y-auto" do |f| %>
|
15
|
+
<%= f.hidden_field :q, value: params[:q] %>
|
16
|
+
<%= f.hidden_field :sort_by, value: params[:sort_by] %>
|
17
|
+
<nav class="flex flex-col justify-between h-full">
|
18
|
+
<div class="flex flex-col gap-4">
|
19
|
+
<%= render 'spree/products/filters/availability', f: f %>
|
20
|
+
<%= render 'spree/products/filters/price', f: f %>
|
21
|
+
|
22
|
+
<% current_store.taxonomies.order(:position).each do |taxonomy| %>
|
23
|
+
<%= render 'spree/products/filters/taxons', taxonomy: taxonomy, f: f %>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% Spree::OptionType.filterable.order(:position).includes(:option_values).each do |filter| %>
|
27
|
+
<% if filter.color? %>
|
28
|
+
<%= render 'spree/products/filters/colors', filter: filter, f: f %>
|
29
|
+
<% else %>
|
30
|
+
<%= render 'spree/products/filters/generic', filter: filter, f: f %>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
<div class="bg-accent p-4 lg:py-6 lg:px-10 flex flex-row justify-between gap-8 sticky bottom-0 left-0 mt-4">
|
35
|
+
<%= f.button Spree.t(:apply), class: "btn-primary block text-center flex-grow", type: "submit" %>
|
36
|
+
<% if current_taxon || params[:filter].present? %>
|
37
|
+
<%= link_to url_for(permitted_products_params.except(:page, :filter)), class: "inline-flex items-center justify-center gap-3 font-semibold text-sm tracking-widest", data: { turbo_method: :get, turbo_frame: "_top" } do %>
|
38
|
+
<span><%= Spree.t(:clear_all) %></span>
|
39
|
+
<%= render 'spree/shared/icons/cross', width: 20, height: 20 %>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</nav>
|
44
|
+
<% end %>
|
45
|
+
</div>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<script type="application/ld+json" data-test-id="product-json-ld">
|
2
|
+
<% first_or_default_variant = product.first_or_default_variant(current_currency) %>
|
3
|
+
{
|
4
|
+
"@context": "https://schema.org/",
|
5
|
+
"@type": "Product",
|
6
|
+
"name": <%= product.name.to_json.html_safe %>,
|
7
|
+
"url": <%= spree.product_url(product).to_json.html_safe %>,
|
8
|
+
<% if product.featured_image %>
|
9
|
+
"image": [
|
10
|
+
<%= main_app.cdn_image_url(product.featured_image.variant(spree_image_variant_options(resize_to_limit: [1260, 1260]))).to_json.html_safe %>
|
11
|
+
],
|
12
|
+
<% end %>
|
13
|
+
<% if product.description.present? %>
|
14
|
+
"description": <%= strip_tags(product.description).to_json.html_safe %>,
|
15
|
+
<% end %>
|
16
|
+
<% if !product.has_variants? %>
|
17
|
+
<% if first_or_default_variant.sku.present? %>"sku": <%= first_or_default_variant.sku.to_json.html_safe %>,<% end %>
|
18
|
+
<% elsif selected_variant %>
|
19
|
+
<% if selected_variant.sku.present? %>"sku": <%= selected_variant.sku.to_json.html_safe %>,<% end %>
|
20
|
+
<% end %>
|
21
|
+
<% if product.brand %>
|
22
|
+
"brand": {
|
23
|
+
"@type": "Brand",
|
24
|
+
"name": <%= product.brand_name.to_json.html_safe %>
|
25
|
+
},
|
26
|
+
<% end %>
|
27
|
+
"offers": [
|
28
|
+
<% if product.has_variants? %>
|
29
|
+
<%= render partial: "spree/products/json_ld_variant", collection: product.variants, as: :variant, locals: { product: product }, cached: spree_base_cache_scope %>
|
30
|
+
<% else %>
|
31
|
+
<%= render "spree/products/json_ld_variant", product: product, variant: first_or_default_variant %>
|
32
|
+
<% end %>
|
33
|
+
]
|
34
|
+
}
|
35
|
+
</script>
|
36
|
+
<script type="application/ld+json">
|
37
|
+
<%= product_json_ld_breadcrumbs(product).to_json.html_safe %>
|
38
|
+
</script>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<% cache [spree_base_cache_key, products,'json-ld-list'], expires_in: 1.day do %>
|
2
|
+
<script type="application/ld+json" data-test-id="product-list-json-ld">
|
3
|
+
{
|
4
|
+
"@context": "https://schema.org",
|
5
|
+
"@type": "ItemList",
|
6
|
+
"itemListElement": <%= product_list_json_ld_elements(products.to_a.pluck(:slug)).to_json.html_safe %>
|
7
|
+
}
|
8
|
+
</script>
|
9
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
{
|
2
|
+
"@type": "Offer",
|
3
|
+
<% if variant.sku.present? %>
|
4
|
+
"sku": <%= variant.sku.to_json.html_safe %>,
|
5
|
+
<% end %>
|
6
|
+
"availability": "http://schema.org/<%= variant.available? ? 'InStock' : 'OutOfStock' %>",
|
7
|
+
"price": <%= variant.amount_in(current_currency).to_json.html_safe %>,
|
8
|
+
"priceCurrency": <%= current_currency.to_json.html_safe %>,
|
9
|
+
"url": <%= spree.product_url(product, variant_id: variant.id).to_json.html_safe %>
|
10
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<% shared_class = "label rounded-full px-3 py-1 text-sm uppercase z-10 left-2 product-label" %>
|
2
|
+
<% mobile_pdp ||= false %>
|
3
|
+
|
4
|
+
<% if mobile_pdp %>
|
5
|
+
<% shared_class += ' bottom-2' %>
|
6
|
+
<% else %>
|
7
|
+
<% shared_class += ' top-2' %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<% if !product.available? || (@variant_from_options.present? && !@variant_from_options.in_stock?) %>
|
11
|
+
<div class='<%= shared_class %> bg-neutral-400 text-background product-label--sold-out'>
|
12
|
+
<%= Spree.t(:sold_out) %>
|
13
|
+
</div>
|
14
|
+
<% elsif product.on_sale?(current_currency) && !@all_options_selected %>
|
15
|
+
<div class='<%= shared_class %> bg-danger text-background product-label--sale'>
|
16
|
+
<%= Spree.t(:sale) %>
|
17
|
+
</div>
|
18
|
+
<% elsif @variant_from_options&.on_sale?(current_currency) && @all_options_selected %>
|
19
|
+
<div class='<%= shared_class %> bg-danger text-background product-label--sale'>
|
20
|
+
<%= Spree.t(:sale) %>
|
21
|
+
</div>
|
22
|
+
<% elsif product.taggings.find { |tagging| tagging.context == 'labels' } %>
|
23
|
+
<div class='<%= shared_class %> bg-background border border-primary product-label--custom' data-title="<%= product.labels.first.name.strip.downcase.truncate(20) %>">
|
24
|
+
<%= product.labels.first.name.truncate(20) %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
@@ -0,0 +1,94 @@
|
|
1
|
+
<% desktop ||= false %>
|
2
|
+
|
3
|
+
<% cache [*spree_base_cache_scope.call(product), images, desktop].compact do %>
|
4
|
+
<% if desktop == true %>
|
5
|
+
<div
|
6
|
+
class="media-gallery w-full h-full media-gallery-desktop"
|
7
|
+
id="media-gallery-<%= product.id %>-desktop"
|
8
|
+
data-controller="lightbox pdp-desktop-gallery">
|
9
|
+
<div class="grid grid-cols-[6.5rem,_1fr] grid-rows-1 gap-2 w-full media-gallery-desktop__wrapper">
|
10
|
+
<div class="flex flex-col h-full w-full aspect-1 overflow-hidden">
|
11
|
+
<%= button_tag class: "w-full bg-background py-2 flex justify-center items-center disabled:opacity-50 media-gallery-desktop-arrow", data: { pdp_desktop_gallery_target: "prevArrow" } do %>
|
12
|
+
<span class="rotate-180">
|
13
|
+
<%= render 'spree/shared/icons/chevron_down' %>
|
14
|
+
</span>
|
15
|
+
<% end %>
|
16
|
+
<div class="swiper h-full w-full block" data-pdp-desktop-gallery-target="imagesThumbsSlider">
|
17
|
+
<div class="swiper-wrapper w-full h-full block">
|
18
|
+
<% images.each do |image| %>
|
19
|
+
<div class="swiper-slide !h-min cursor-pointer w-full">
|
20
|
+
<div
|
21
|
+
class="relative aspect-1 w-full block "
|
22
|
+
id="thumb-desktop-product-image-<%= image.id %>"
|
23
|
+
data-turbo-permanent>
|
24
|
+
<%= image_tag main_app.cdn_image_url(image.variant(spree_image_variant_options(resize_to_fill: [200, 200]))), alt: image_alt(image), class: 'w-full h-full' %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
<%= button_tag class: "w-full bg-background py-2 flex justify-center items-center disabled:opacity-50 media-gallery-desktop-arrow", data: { pdp_desktop_gallery_target: "nextArrow" } do %>
|
31
|
+
<%= render 'spree/shared/icons/chevron_down' %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
<div data-pdp-desktop-gallery-target="imagesSlider" class="overflow-hidden swiper relative w-full h-min">
|
35
|
+
<div class="swiper-wrapper w-full h-min">
|
36
|
+
<% images.each do |image| %>
|
37
|
+
<div class="swiper-slide w-full">
|
38
|
+
<div
|
39
|
+
class="product-image relative w-full aspect-1"
|
40
|
+
id="main-desktop-product-image-<%= image.id %>"
|
41
|
+
data-turbo-permanent>
|
42
|
+
<%= link_to main_app.cdn_image_url(image.variant(spree_image_variant_options(resize_to_fill: [2000, 2000]))), data: { pswp_width: "2000", pswp_height: "2000" } do %>
|
43
|
+
<div class="zoom-icon hidden absolute bottom-2 right-2 p-4 bg-background rounded-full opacity-75 hover:opacity-100">
|
44
|
+
<%= render 'spree/shared/icons/zoom' %>
|
45
|
+
</div>
|
46
|
+
<%= image_tag main_app.cdn_image_url(image.variant(spree_image_variant_options(resize_to_fill: [2000, 2000]))), alt: image_alt(image), class: 'w-full h-full' %>
|
47
|
+
<% end %>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
<% end %>
|
51
|
+
</div>
|
52
|
+
<%= render 'spree/products/label', product: product %>
|
53
|
+
<div data-pdp-desktop-gallery-target="imagesSliderPagination" class="swiper-pagination"></div>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
<% else %>
|
58
|
+
<!-- media gallery for mobile -->
|
59
|
+
<% if images.any? %>
|
60
|
+
<div
|
61
|
+
id="media-gallery-<%= product.id %>-mobile"
|
62
|
+
data-controller="lightbox carousel"
|
63
|
+
class="media-gallery swiper-container relative overflow-hidden"
|
64
|
+
data-carousel-options-value='{
|
65
|
+
"slidesPerView": 1,
|
66
|
+
"centeredSlides": true,
|
67
|
+
"spaceBetween": 10,
|
68
|
+
"grabCursor": true
|
69
|
+
}'>
|
70
|
+
<div class="swiper-wrapper">
|
71
|
+
<% images.each do |image| %>
|
72
|
+
<div class="swiper-slide aspect-1" id="swiper-slide-<%= image.id %>">
|
73
|
+
<%= link_to main_app.cdn_image_url(image.variant(spree_image_variant_options(resize_to_fill: [2000, 2000]))), class: "absolute top-2 right-2 p-2 bg-background rounded-full opacity-75 hover:opacity-100", data: { pswp_width: "2000", pswp_height: "2000" } do %>
|
74
|
+
<%= render 'spree/shared/icons/zoom' %>
|
75
|
+
<% end %>
|
76
|
+
<%= render 'spree/products/label', product: product, mobile_pdp: true %>
|
77
|
+
<%= image_tag main_app.cdn_image_url(image.variant(spree_image_variant_options(resize_to_fill: [720, 720]))), alt: image_alt(image), class: 'h-full w-full object-cover object-center', style: 'min-height: 358px' %>
|
78
|
+
</div>
|
79
|
+
<% end %>
|
80
|
+
</div>
|
81
|
+
<% if images.length > 1 %>
|
82
|
+
<div class="swiper-pagination-product-<%= product.id %> mt-3 items-center flex mx-auto align-center justify-center" data-carousel-target="pagination"></div>
|
83
|
+
<% end %>
|
84
|
+
</div>
|
85
|
+
<div id='pinch-to-zoom' class='fixed top-0 left-0 p-4 bg-background z-50 flex justify-center items-center flex-col'>
|
86
|
+
<div class='w-14 h-14'><%= render 'spree/shared/icons/pinch' %></div>
|
87
|
+
<div class='text-sm uppercase pt-4 px-5 text-center !leading-tight'>
|
88
|
+
Pinch to <br>
|
89
|
+
zoom
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
<% end %>
|
93
|
+
<% end %>
|
94
|
+
<% end %>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<% use_variant ||= false %>
|
2
|
+
<% sold_out ||= !product.available? %>
|
3
|
+
<% price_class ||= ''%>
|
4
|
+
<% price_container_class ||= '' %>
|
5
|
+
<% selected_variant ||= nil %>
|
6
|
+
<div class="<%= price_class %>">
|
7
|
+
<div class="flex flex-col gap-3 <%= price_container_class %>">
|
8
|
+
<%
|
9
|
+
if use_variant
|
10
|
+
target = selected_variant
|
11
|
+
sold_out = selected_variant.nil?
|
12
|
+
if sold_out
|
13
|
+
target = @variant_from_options
|
14
|
+
sold_out = @variant_from_options.nil?
|
15
|
+
end
|
16
|
+
else
|
17
|
+
target = product
|
18
|
+
sold_out = !product.available?
|
19
|
+
end
|
20
|
+
|
21
|
+
target ||= product
|
22
|
+
|
23
|
+
price = target.price_in(current_currency)
|
24
|
+
money_price = price.display_amount
|
25
|
+
|
26
|
+
if target.is_a?(Spree::Product) && !use_variant && product.price_varies?(current_currency)
|
27
|
+
price = target.lowest_price(current_currency)
|
28
|
+
money_price = price.display_amount
|
29
|
+
money_price = "#{Spree.t(:from)}: #{money_price}"
|
30
|
+
end
|
31
|
+
%>
|
32
|
+
<div>
|
33
|
+
<% if price.compare_at_amount.present? && price.compare_at_amount > price.amount %>
|
34
|
+
<span class="hidden">
|
35
|
+
<%= Spree.t(:regular_price) %>
|
36
|
+
</span>
|
37
|
+
<p class="inline pr-2 opacity-50 line-through">
|
38
|
+
<%= price.display_compare_at_amount %>
|
39
|
+
</p>
|
40
|
+
<span class="hidden pr-2">
|
41
|
+
<%= Spree.t(:sale_price) %>
|
42
|
+
</span>
|
43
|
+
<p class="inline text-danger">
|
44
|
+
<%= money_price %>
|
45
|
+
</p>
|
46
|
+
<% else %>
|
47
|
+
<span class="hidden">
|
48
|
+
<%= Spree.t(:regular_price) %>
|
49
|
+
</span>
|
50
|
+
|
51
|
+
<% if price&.amount.nil? %>
|
52
|
+
<span class="uppercase"><%= Spree.t(:not_available) %></span>
|
53
|
+
<% else %>
|
54
|
+
<p><%= money_price %></p>
|
55
|
+
<% end %>
|
56
|
+
<% end %>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
</div>
|