Have your say in Community Polls: What was/is your greatest motivation to start your own business?

Re: Dawn Slide Component

Solved

Does anyone know about the Dawn slide component availability?

FervEngineering
Excursionist
19 0 12

When reading the link below, it says Dawn will have a slider. Either I can't find it, or it hasn't been shipped in the last version. Does anyone have insight into this?

 

https://ux.shopify.com/next-generation-theme-design-5aae94f6d44c


Edit: I just found a slider example in a section named "featured-blog" which doesn't seem enabled. I don't know if it hasn't been completed yet or if we're supposed to figure out how to implement it on our own.

Accepted Solution (1)

marcoswata
Shopify Partner
123 10 39

This is an accepted solution.

There is a slider component that seems to be used on mobile only, in some sections.

The component CSS and JS can be found at:

/assets/component-slider.css

/assets/slider.js

It uses CSS Flex and you'd have to tweak the CSS to show it on desktop too.

If my answer was helpful then please Like and Accept Solution 🙂
If you need help with design, development or marketing your store, contact me!

View solution in original post

Replies 75 (75)

Anthony_David_
Shopify Partner
417 46 108

New Slider is available in DAWN, check Editor @FervEngineering 

Thanks 

Theme customization | Design | Shopify App Consultant
Have Any Questions? Whatsapp +1 (341) 241-4263
Based in United States
FervEngineering
Excursionist
19 0 12

@Anthony_David_ Are you seeing it in your customizer? I see the code for it when I pull it locally, but it’s not available as a section or block. 

lukezhang
Visitor
1 0 0

I don't see it either. Any pointer will be helpful.

marcoswata
Shopify Partner
123 10 39

This is an accepted solution.

There is a slider component that seems to be used on mobile only, in some sections.

The component CSS and JS can be found at:

/assets/component-slider.css

/assets/slider.js

It uses CSS Flex and you'd have to tweak the CSS to show it on desktop too.

If my answer was helpful then please Like and Accept Solution 🙂
If you need help with design, development or marketing your store, contact me!
FervEngineering
Excursionist
19 0 12

@marcoswata Thanks, I found its usage in featured-collection.liquid and is used as below-looks like they created a custom HTML element for it. I'll accept your answer as the solution.

 

 

 

<slider-component class="slider-mobile-gutter">

 

 

jaymewada213
Visitor
1 0 1

Thanks for the quick solution. Can you also explain how can we enable this product slide on the desktop version also. 
I am struggling to be slider to be displayed on desktop also on the DAWN theme

FervEngineering
Excursionist
19 0 12

It's going to be a little bit involved to get it to work. You'll need to get the products to keep the horizontal grid and unhide the slider buttons like mobile uses. All the classes are already available, but you might want to make an alternate version so it's not confusing when someone's trying to debug and they see class="mobile-xxx" when the viewport is at desktop size.

smj_90
Shopify Partner
57 1 15

I tried everything, by playing with classes and liquid, ALAS! no workaround found!

There is a solution but no accepted! Unless, I don't copy the slider component, and duplicate it and one I call for desktop and other for mobile/tablet version, it doesn't work for desktop!

But duplicating the code is nothing but redundancy.

Does anyone has any solution yet???

If this helped you, please
mark this reply as 'Accepted Solution'
Thanks 🙂
Marb
Tourist
3 0 2

+1 for this, still looking for a solution aswell. Hope this gets updated soon

shadowsfall118
Shopify Partner
125 13 37

I have achieved adding a slider to the product page images by using the slick slider.

Notes:

  • This requires adding code and not editing any of the existing.
  • The click to enlarge still works from the existing code.
  • Works on mobile

There is 4 files to edit:

  1. main-product.liquid
  2. section-main-product.css
  3. header.liquid
  4. footer.liquid  

 

Step 1: For main-product.liquid add the following and comment / remove the "<slider-component class="slider-mobile-gutter">" start and end tags. Add the below code before the <slider-component class="slider-mobile-gutter"> tag we removed or commented out.

<section class="lazy slider" data-sizes="50vw">
{%- for media in product.media -%}
<div>

{%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%}
<li class="product__media-item grid__item slider__slide{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}">
{% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
</li>
{%- endunless -%}

</div>
{%- endfor -%}
</section>

 

Step 2: For section-main-product.css add the following to the bottom of the file

.slider {
width: 80%;
margin-left:auto;
margin-right:auto;
}

.slick-slide {
margin: 0px 20px;
}

.slick-slide img {
width: 100%;
}

.slick-prev:before,
.slick-next:before {
color: black;
}


.slick-slide {
transition: all ease-in-out .3s;
opacity: .2;
}

.slick-active {
opacity: .5;
}

.slick-current {
opacity: 1;
}

 

Step 3: For header.liquid add the following just after {%- endif -%} on line 9

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.css"/>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.css"/>

 

Step 4: For footer.liquid add the following to the end of the file

<script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
$(document).on('ready', function() {

$(".lazy").slick({
lazyLoad: 'ondemand', // ondemand progressive anticipated
infinite: true
});
});
</script>
smj_90
Shopify Partner
57 1 15

That's like adding more code to the theme!

Since DAWN is the fastest theme, why to burden it with more code.

There should be a way to use that <slider-component> in desktop mode too!

If this helped you, please
mark this reply as 'Accepted Solution'
Thanks 🙂
shadowsfall118
Shopify Partner
125 13 37

@smj_90 for sure it's adding more but not too much. I didn't notice any impact on performance. I started to look into how to implement the built-in slider component but it would take alot of time I don't have to figure out what CSS @media quires need to be modified or disabled for force showing it on desktop. Not to mention any other code that may be altering how it looks.

For now I think this will have to do as the best free option as I did not come across any other step by step solutions. I came across the barstool dev one but for the life of me couldn't get it to work. 

oliverjames
Excursionist
40 0 11

The slideshow works but the images still stay below it which is annoying..

Kumar2573
Shopify Partner
174 8 23

we added the slick slider in dawn theme with variants swatches.

Demo Url - https://devils-jitu.myshopify.com/products/test-product
password - test

Shopify Certified Developer Profile - https://www.credly.com/badges/1733d05c-2a88-490a-aef5-b01baf3b94ce/public_url
Expert Shopify Plus & shopify Developer & Theme customizer
- If the problem is solved remember to click to Accept Solution
- Press Like ?? if the answer was helpful
- Still, Facing issue, Reach out to me Email :- jitendra3496@gmail.com | Skype :- jitendra2573_1
- Direct Hire me :- Direct Contact me
smj_90
Shopify Partner
57 1 15

@Kumar2573 

Hi there, i checked your code, it's working only for 1st product only. For the rest of the products, it's not working. also the first product pictures keep on changing rest all are static.

i guess you forgot to call 'product unique id' when making that slider, though this approach is amazing!

If this helped you, please
mark this reply as 'Accepted Solution'
Thanks 🙂
j1419
Shopify Partner
49 2 17

@shadowsfall118 Your solution has been the only one that I have seen that works to implement a slider on Dawn's product page. Very detailed instructions worked great. Thanks

LIxiao
Shopify Partner
5 0 0

Can't switch image by selecting attribute

Doug911
Tourist
3 0 1

Thank you! This was super helpful

DB160
Shopify Partner
22 0 10
Hi Doug

Just received your message. Did to manage to sort out the code.

If not go into to edit code for your theme and find the files mentioned at
the end of the post and replace everything with the code give for each file.
You can then go back to the theme customiser and add the featured products
section to your homepage with the updated settings.

Let me know if you need any more help.

Kind Regards

Darren

made4Uo
Shopify Partner
3856 717 1197

Hi,

Fortunately, I manage to customize the Dawn code and added a product slider. I preserve the slider-component code and mostly customize the CSS. Oh I added a javascript code also so when you click the image, the large image container should show the clicked image. Not only that, my product images has different heights, so I added a code so that the slider adjust to the height of the large image. Do not worry. I don't work with any app or any website.  The code is free. Just give me a thumbs up if I solve your problem. 

Grab the code here with instructions https://made4uo.com/blogs/journey-to-awesome-shopify-website/product-slider-for-dawn-theme

 

dawn slider.jpg

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
marcoswata
Shopify Partner
123 10 39

@made4Uo nice work!

I've quickly put together a version of a simple desktop slideshow for the Dawn theme here:

https://dawn-slideshow.myshopify.com/products/example-t-shirt

Password: rohwah

It's not the best way of doing that, but it's an easy one for those who are not used to coding.

Code in github

Basically:

1. sections/main-product.liquid

  • add  the classes slider--desktop slider--tablet  to the <ul> element
  • remove the whole {% if %}..{% endif %} statement from the div.product element

2. assets/component.slider.css (probably easier if you just copy the source code):

  • replicate the existing code for .slider.slider--mobile  to our newly created class .slider.slider--desktop

3.  snippets/product-thumbnail.liquid (optional; for fixed image dimensions):

  • wherever you see img_url: '<number>x', replace it with img_url: '<number>x<number>'. E.g. img_url: '288x
  • for each .product__media.media element, change the padding-top to padding-top:100%; 
If my answer was helpful then please Like and Accept Solution 🙂
If you need help with design, development or marketing your store, contact me!
smj_90
Shopify Partner
57 1 15

@marcoswata exactly what i was looking for! GREAT JOB!!

If this helped you, please
mark this reply as 'Accepted Solution'
Thanks 🙂
RachelFox
Tourist
4 0 7

**EDIT: Found the code files. Thanks!**

 

Hi @marcoswata ! This looks super easy and I really like how it looks. Code you let me which <ul> lines to add the class to? There's a few in there. And which lines of the {%if%} statement to remove. 

 

And do I need to replicate each instance of the slider--mobile to a new slider--desktop in the component-slider.css?

Thank you! 

marcoswata
Shopify Partner
123 10 39

Hi @RachelFox sorry I got a bit lost in the conversation here, what exactly do you need done now? Feel free to send me a message. This conversation was around the first versions of Dawn, now we're on version 7 and things are probably very different.

If my answer was helpful then please Like and Accept Solution 🙂
If you need help with design, development or marketing your store, contact me!
shadowsfall118
Shopify Partner
125 13 37

@made4Uo I followed your guide with a base dawn theme as I like how you implemented the thumbnails but i'm not getting the large main image (only thumbnails). Any thoughts?

StewartM
Shopify Partner
5 0 1

@made4Uo

I also have the same problem, i have even tried deleting and copying the entire css text that is on the website, as this is probably a direct copy from your dev site - i thought it was me. The css file in the video and the one on the site are different, but only because with the cut and paste one you include all the code that has been commented out i think. 

I have gone step by step by with the video and also by just following the steps on the page, it is a fresh "Dawn" install so no other customisations have taken place as yet. 

I think there is a problem with the css style sheet or the script as it doesnt appear to be calling or linking up with the large image in any way, certainly the large image isnt displayed and the slider does not move. 

When you do the first step you are left with giant product images on the product page, which is fine, then you implement the css file and the images shrink to what you would expect the ones along the bottom of the carousel (but with no large image showing). This at least does seem have a slide component that works, but when you change the global.js file to "3" and "4" the slider stops moving and you are left with 4 (or however many images you have on your product page) thumbnail images that just run along the bottom....

I have included a screenshot to show you what i mean, if you could take a look at your code or even try it on a fresh dawn install that would be great as others have shown how to do a slider on the main product images, which is great, but i need a carousel for a design i am working on. 

Thanks 

Screenshot 2021-09-20 at 15.26.16.png

made4Uo
Shopify Partner
3856 717 1197

Hi, 

Thank you for letting me know. The large image is the original image from Dawn, which has the modal, the zoom bottom. I edited the new Dawn theme, which is unedited. 

The bold code is responsible for the big image. The red code is from Dawn. Take note too. In the video, I did not comment out the whole CSS file. Can you post your code?

<section class="page-width">
        <div class="product grid grid--1-col {% if product.media.size > 0 %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
          <div class="grid__item product__media-wrapper">
 
            <div class="slider-container" >
            <a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
            {{ "accessibility.skip_to_product_info" | t }}
            </a>
            <ul class="large-image" id="large-image">
                {%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
                {%- if product.selected_or_first_available_variant.featured_media != null -%}
                {%- assign media = product.selected_or_first_available_variant.featured_media -%}
                {%- for media in product.media -%}
 
                <li class="large-image-item product__media-item grid__item slider__slide
                    {% if media.media_type != 'image' %}
                    product__media-item--full{% endif %}"
                    data-media-id="{{ section.id }}-{{ media.id }}">
                    {% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
                    </li>
                {%- endfor -%}
                {%- endif -%}
                </ul>
 
      <slider-component >
                <ul class="product-slider-box slider" role="list">
                    {%- for media in product.media -%}
                    <li class="product-slider slider__slide">
                        <img class="slide-image"
                        onclick="newLargeImage(this)"
                        data-thumb-id="{{ section.id }}-{{ media.id }}"
                        src="{{ media.preview_image | img_url: 'large', scale: 4 }}"
                        alt="{{ thumbnailAlt }}">
                    </li>
                {% endfor %}
                </ul>
          <div class="slider-buttons no-js-hidden{% if product.media.size < 2 %}
            small-hide{% endif %}">
            <button type="button" class="slider-button slider-button--prev bigger-slider" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
              <div class="slider-counter caption">
              <span class="slider-counter--current">1</span>
              <span aria-hidden="true"> / </span>
              <span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
              <span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
              </div>
            <button type="button" class="slider-button slider-button--next bigger-slider" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
          </div>
          </slider-component>
      </div>
If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
shadowsfall118
Shopify Partner
125 13 37

This is after following step by step

main-product.liquid

{% comment %}theme-check-disable TemplateLength{% endcomment %}
{{ 'section-main-product.css' | asset_url | stylesheet_tag }}
{{ 'component-accordion.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
{{ 'component-rte.css' | asset_url | stylesheet_tag }}
{{ 'component-slider.css' | asset_url | stylesheet_tag }}
{{ 'component-rating.css' | asset_url | stylesheet_tag }}

<link rel="stylesheet" href="{{ 'component-deferred-media.css' | asset_url }}" media="print" onload="this.media='all'">

<script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>

{%- assign first_3d_model = product.media | where: "media_type", "model" | first -%}
{%- if first_3d_model -%}
{{ 'component-product-model.css' | asset_url | stylesheet_tag }}
<link id="ModelViewerStyle" rel="stylesheet" href="https://cdn.shopify.com/shopifycloud/model-viewer-ui/assets/v1.0/model-viewer-ui.css" media="print" onload="this.media='all'">
<link id="ModelViewerOverride" rel="stylesheet" href="{{ 'component-model-viewer-ui.css' | asset_url }}" media="print" onload="this.media='all'">
{%- endif -%}

<section class="page-width">
<div class="product grid grid--1-col {% if product.media.size > 0 %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
<div class="grid__item product__media-wrapper">


<!-- NEW SLIDER -->

<script>
function newLargeImage(x) {
let clickedImage = x.dataset.thumbId;
const newImage = document.querySelector(`[data-media-id="${clickedImage}"]`);
const parentData = newImage.parentElement;
parentData.prepend(newImage);

const resizeObserver = new ResizeObserver(entries =>
x.clientHeight)
resizeObserver.observe(document.body)
const imgHt = x.clientHeight * 4.5;
document.getElementById('large-image').style.paddingBottom = imgHt + 'px';
};
</script>


<div class="slider-container" >
<a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
{{ "accessibility.skip_to_product_info" | t }}
</a>
<ul class="large-image" id="large-image">
{%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
{%- if product.selected_or_first_available_variant.featured_media != null -%}
{%- assign media = product.selected_or_first_available_variant.featured_media -%}
{%- for media in product.media -%}

<li class="large-image-item product__media-item grid__item slider__slide
{% if media.media_type != 'image' %}
product__media-item--full{% endif %}"
data-media-id="{{ section.id }}-{{ media.id }}">
{% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
</li>
{%- endfor -%}
{%- endif -%}
</ul>

<slider-component >
<ul class="product-slider-box slider" role="list">
{%- for media in product.media -%}
<li class="product-slider slider__slide">
<img class="slide-image"
onclick="newLargeImage(this)"
data-thumb-id="{{ section.id }}-{{ media.id }}"
src="{{ media.preview_image | img_url: 'large', scale: 4 }}"
alt="{{ thumbnailAlt }}">
</li>
{% endfor %}
</ul>
<div class="slider-buttons {% if product.media.size < 2 %}
small-hide{% endif %}">
<button type="button" class="slider-button slider-button--prev bigger-slider" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
<div class="slider-counter caption">
<span class="slider-counter--current">1</span>
<span aria-hidden="true"> / </span>
<span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
<span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
</div>
<button type="button" class="slider-button slider-button--next bigger-slider" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
</div>
</slider-component>
</div>

<!-- OLD SLIDER
<slider-component class="slider-mobile-gutter">
<a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
{{ "accessibility.skip_to_product_info" | t }}
</a>
<ul class="product__media-list grid grid--peek list-unstyled slider slider--mobile" role="list">
{%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
{%- if product.selected_or_first_available_variant.featured_media != null -%}
{%- assign media = product.selected_or_first_available_variant.featured_media -%}
<li class="product__media-item grid__item slider__slide{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}">
{% render 'product-thumbnail', media: media, position: 'featured', loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
</li>
{%- endif -%}
{%- for media in product.media -%}
{%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%}
<li class="product__media-item grid__item slider__slide{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}">
{% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
</li>
{%- endunless -%}
{%- endfor -%}
</ul>
<div class="slider-buttons no-js-hidden{% if product.media.size < 2 %} small-hide{% endif %}">
<button type="button" class="slider-button slider-button--prev" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
<div class="slider-counter caption">
<span class="slider-counter--current">1</span>
<span aria-hidden="true"> / </span>
<span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
<span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
</div>
<button type="button" class="slider-button slider-button--next" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
</div>
</slider-component>-->
{%- if first_3d_model -%}
<button
class="button button--full-width product__xr-button"
type="button"
aria-label="{{ 'products.product.xr_button_label' | t }}"
data-shopify-xr
data-shopify-model3d-id="{{ first_3d_model.id }}"
data-shopify-title="{{ product.title | escape }}"
data-shopify-xr-hidden
>
{% render 'icon-3d-model' %}
{{ 'products.product.xr_button' | t }}
</button>
{%- endif -%}
</div>
<div class="product__info-wrapper grid__item">
<div id="ProductInfo-{{ section.id }}" class="product__info-container{% if section.settings.enable_sticky_info %} product__info-container--sticky{% endif %}">
{%- assign product_form_id = 'product-form-' | append: section.id -%}

{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when '@app' -%}
{% render block %}
{%- when 'text' -%}
<p class="product__text{% if block.settings.text_style == 'uppercase' %} caption-with-letter-spacing{% elsif block.settings.text_style == 'subtitle' %} subtitle{% endif %}" {{ block.shopify_attributes }}>
{{- block.settings.text -}}
</p>
{%- when 'title' -%}
<h1 class="product__title" {{ block.shopify_attributes }}>
{{ product.title | escape }}
</h1>
{%- when 'price' -%}
<div class="no-js-hidden" id="price-{{ section.id }}" {{ block.shopify_attributes }}>
{%- render 'price', product: product, use_variant: true, show_badges: true, price_class: 'price--large' -%}
</div>
<div {{ block.shopify_attributes }}>
{%- form 'product', product, id: 'product-form-installment', class: 'installment caption-large' -%}
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
{{ form | payment_terms }}
{%- endform -%}
</div>
{%- when 'description' -%}
{%- if product.description != blank -%}
<div class="product__description rte">
{{ product.description }}
</div>
{%- endif -%}
{%- when 'custom_liquid' -%}
{{ block.settings.custom_liquid }}
{%- when 'collapsible_tab' -%}
<div class="product__accordion accordion" {{ block.shopify_attributes }}>
<details>
<summary>
<div class="summary__title">
{% render 'icon-accordion', icon: block.settings.icon %}
<h2 class="h4 accordion__title">
{{ block.settings.heading | default: block.settings.page.title }}
</h2>
</div>
{% render 'icon-caret' %}
</summary>
<div class="accordion__content rte">
{{ block.settings.content }}
{{ block.settings.page.content }}
</div>
</details>
</div>
{%- when 'quantity_selector' -%}
<div class="product-form__input product-form__quantity" {{ block.shopify_attributes }}>
<label class="form__label" for="Quantity-{{ section.id }}">
{{ 'products.product.quantity.label' | t }}
</label>

<quantity-input class="quantity">
<button class="quantity__button no-js-hidden" name="minus" type="button">
<span class="visually-hidden">{{ 'products.product.quantity.decrease' | t: product: product.title | escape }}</span>
{% render 'icon-minus' %}
</button>
<input class="quantity__input"
type="number"
name="quantity"
id="Quantity-{{ section.id }}"
min="1"
value="1"
form="product-form-{{ section.id }}"
>
<button class="quantity__button no-js-hidden" name="plus" type="button">
<span class="visually-hidden">{{ 'products.product.quantity.increase' | t: product: product.title | escape }}</span>
{% render 'icon-plus' %}
</button>
</quantity-input>
</div>
{%- when 'popup' -%}
<modal-opener class="product-popup-modal__opener no-js-hidden" data-modal="#PopupModal-{{ block.id }}" {{ block.shopify_attributes }}>
<button id="ProductPopup-{{ block.id }}" class="product-popup-modal__button link" type="button" aria-haspopup="dialog">{{ block.settings.text | default: block.settings.page.title }}</button>
</modal-opener>
<a href="{{ block.settings.page.url }}" class="product-popup-modal__button link no-js">{{ block.settings.text }}</a>
{%- when 'share' -%}
<share-button class="share-button" {{ block.shopify_attributes }}>
<button class="share-button__button hidden">
{% render 'icon-share' %}
{{ block.settings.share_label | escape }}
</button>
<details>
<summary class="share-button__button">
{% render 'icon-share' %}
{{ block.settings.share_label | escape }}
</summary>
<div id="Product-share-{{ section.id }}" class="share-button__fallback motion-reduce">
<div class="field">
<span id="ShareMessage-{{ section.id }}" class="share-button__message hidden" role="status">
</span>
<input type="text"
class="field__input"
id="url"
value="{{ shop.url | append: product.url }}"
placeholder="{{ 'general.share.share_url' | t }}"
onclick="this.select();"
readonly
>
<label class="field__label" for="url">{{ 'general.share.share_url' | t }}</label>
</div>
<button class="share-button__close hidden no-js-hidden">
{% render 'icon-close' %}
<span class="visually-hidden">{{ 'general.share.close' | t }}</span>
</button>
<button class="share-button__copy no-js-hidden">
{% render 'icon-clipboard' %}
<span class="visually-hidden">{{ 'general.share.copy_to_clipboard' | t }}</span>
</button>
</div>
</details>
</share-button>
<script src="{{ 'share.js' | asset_url }}" defer="defer"></script>
{%- when 'variant_picker' -%}
{%- unless product.has_only_default_variant -%}
{%- if block.settings.picker_type == 'button' -%}
<variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
{%- for option in product.options_with_values -%}
<fieldset class="js product-form__input">
<legend class="form__label">{{ option.name }}</legend>
{%- for value in option.values -%}
<input type="radio" id="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}"
name="{{ option.name }}"
value="{{ value | escape }}"
form="product-form-{{ section.id }}"
{% if option.selected_value == value %}checked{% endif %}
>
<label for="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}">
{{ value }}
</label>
{%- endfor -%}
</fieldset>
{%- endfor -%}
<script type="application/json">
{{ product.variants | json }}
</script>
</variant-radios>
{%- else -%}
<variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
{%- for option in product.options_with_values -%}
<div class="product-form__input product-form__input--dropdown">
<label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
{{ option.name }}
</label>
<div class="select">
<select id="Option-{{ section.id }}-{{ forloop.index0 }}"
class="select__select"
name="options[{{ option.name | escape }}]"
form="product-form-{{ section.id }}"
>
{%- for value in option.values -%}
<option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}>
{{ value }}
</option>
{%- endfor -%}
</select>
{% render 'icon-caret' %}
</div>
</div>
{%- endfor -%}

<script type="application/json">
{{ product.variants | json }}
</script>
</variant-selects>
{%- endif -%}
{%- endunless -%}

<noscript class="product-form__noscript-wrapper-{{ section.id }}">
<div class="product-form__input{% if product.has_only_default_variant %} hidden{% endif %}">
<label class="form__label" for="Variants-{{ section.id }}">{{ 'products.product.product_variants' | t }}</label>
<div class="select">
<select name="id" id="Variants-{{ section.id }}" class="select__select" form="product-form">
{%- for variant in product.variants -%}
<option
{% if variant == product.selected_or_first_available_variant %}selected="selected"{% endif %}
{% if variant.available == false %}disabled{% endif %}
value="{{ variant.id }}"
>
{{ variant.title }}
{%- if variant.available == false %} - {{ 'products.product.sold_out' | t }}{% endif %}
- {{ variant.price | money | strip_html }}
</option>
{%- endfor -%}
</select>
{% render 'icon-caret' %}
</div>
</div>
</noscript>
{%- when 'buy_buttons' -%}
<div {{ block.shopify_attributes }}>
<product-form class="product-form">
<div class="product-form__error-message-wrapper" role="alert" hidden>
<svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-error" viewBox="0 0 13 13">
<circle cx="6.5" cy="6.50049" r="5.5" stroke="white" stroke-width="2"/>
<circle cx="6.5" cy="6.5" r="5.5" fill="#EB001B" stroke="#EB001B" stroke-width="0.7"/>
<path d="M5.87413 3.52832L5.97439 7.57216H7.02713L7.12739 3.52832H5.87413ZM6.50076 9.66091C6.88091 9.66091 7.18169 9.37267 7.18169 9.00504C7.18169 8.63742 6.88091 8.34917 6.50076 8.34917C6.12061 8.34917 5.81982 8.63742 5.81982 9.00504C5.81982 9.37267 6.12061 9.66091 6.50076 9.66091Z" fill="white"/>
<path d="M5.87413 3.17832H5.51535L5.52424 3.537L5.6245 7.58083L5.63296 7.92216H5.97439H7.02713H7.36856L7.37702 7.58083L7.47728 3.537L7.48617 3.17832H7.12739H5.87413ZM6.50076 10.0109C7.06121 10.0109 7.5317 9.57872 7.5317 9.00504C7.5317 8.43137 7.06121 7.99918 6.50076 7.99918C5.94031 7.99918 5.46982 8.43137 5.46982 9.00504C5.46982 9.57872 5.94031 10.0109 6.50076 10.0109Z" fill="white" stroke="#EB001B" stroke-width="0.7">
</svg>
<span class="product-form__error-message"></span>
</div>

{%- form 'product', product, id: product_form_id, class: 'form', novalidate: 'novalidate', data-type: 'add-to-cart-form' -%}
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
<div class="product-form__buttons">
<button
type="submit"
name="add"
class="product-form__submit button button--full-width {% if block.settings.show_dynamic_checkout and product.selling_plan_groups == empty %}button--secondary{% else %}button--primary{% endif %}"
{% if product.selected_or_first_available_variant.available == false %}disabled{% endif %}
>
{%- if product.selected_or_first_available_variant.available -%}
{{ 'products.product.add_to_cart' | t }}
{%- else -%}
{{ 'products.product.sold_out' | t }}
{%- endif -%}
</button>
{%- if block.settings.show_dynamic_checkout -%}
{{ form | payment_button }}
{%- endif -%}
</div>
{%- endform -%}
</product-form>

{{ 'component-pickup-availability.css' | asset_url | stylesheet_tag }}

{%- assign pick_up_availabilities = product.selected_or_first_available_variant.store_availabilities | where: 'pick_up_enabled', true -%}

<pickup-availability class="product__pickup-availabilities no-js-hidden"
{% if product.selected_or_first_available_variant.available and pick_up_availabilities.size > 0 %} available{% endif %}
data-base-url="{{ shop.url }}{{ routes.root_url }}"
data-variant-id="{{ product.selected_or_first_available_variant.id }}"
data-has-only-default-variant="{{ product.has_only_default_variant }}"
>
<template>
<pickup-availability-preview class="pickup-availability-preview">
{% render 'icon-unavailable' %}
<div class="pickup-availability-info">
<p class="caption-large">{{ 'products.product.pickup_availability.unavailable' | t }}</p>
<button class="pickup-availability-button link link--text underlined-link">{{ 'products.product.pickup_availability.refresh' | t }}</button>
</div>
</pickup-availability-preview>
</template>
</pickup-availability>
</div>

<script src="{{ 'pickup-availability.js' | asset_url }}" defer="defer"></script>
{%- when 'rating' -%}
{%- if product.metafields.reviews.rating.value != blank -%}
{% liquid
assign rating_decimal = 0
assign decimal = product.metafields.reviews.rating.value.rating | modulo: 1
if decimal >= 0.3 and decimal <= 0.7
assign rating_decimal = 0.5
elsif decimal > 0.7
assign rating_decimal = 1
endif
%}
<div class="rating" role="img" aria-label="{{ 'accessibility.star_reviews_info' | t: rating_value: product.metafields.reviews.rating.value, rating_max: product.metafields.reviews.rating.value.scale_max }}">
<span aria-hidden="true" class="rating-star color-icon-{{ settings.accent_icons }}" style="--rating: {{ product.metafields.reviews.rating.value.rating | floor }}; --rating-max: {{ product.metafields.reviews.rating.value.scale_max }}; --rating-decimal: {{ rating_decimal }};"></span>
</div>
<p class="rating-text caption">
<span aria-hidden="true">{{ product.metafields.reviews.rating.value }} / {{ product.metafields.reviews.rating.value.scale_max }}</span>
</p>
<p class="rating-count caption">
<span aria-hidden="true">({{ product.metafields.reviews.rating_count }})</span>
<span class="visually-hidden">{{ product.metafields.reviews.rating_count }} {{ "accessibility.total_reviews" | t }}</span>
</p>
{%- endif -%}
{%- endcase -%}
{%- endfor -%}
</div>
</div>
</div>

<product-modal id="ProductModal-{{ section.id }}" class="product-media-modal media-modal">
<div class="product-media-modal__dialog" role="dialog" aria-label="{{ 'products.modal.label' | t }}" aria-modal="true" tabindex="-1">
<button id="ModalClose-{{ section.id }}" type="button" class="product-media-modal__toggle" aria-label="{{ 'accessibility.close' | t }}">{% render 'icon-close' %}</button>

<div class="product-media-modal__content" role="document" aria-label="{{ 'products.modal.label' | t }}" tabindex="0">
{%- liquid
if product.selected_or_first_available_variant.featured_media != null
assign media = product.selected_or_first_available_variant.featured_media
render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: section.settings.hide_variants
endif
-%}

{%- for media in product.media -%}
{%- liquid
if section.settings.hide_variants and variant_images contains media.src
assign variant_image = true
else
assign variant_image = false
endif

unless media.id == product.selected_or_first_available_variant.featured_media.id
render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: variant_image
endunless
-%}
{%- endfor -%}
</div>
</div>
</product-modal>

{% assign popups = section.blocks | where: "type", "popup" %}
{%- for block in popups -%}
<modal-dialog id="PopupModal-{{ block.id }}" class="product-popup-modal" {{ block.shopify_attributes }}>
<div role="dialog" aria-label="{{ block.settings.text }}" aria-modal="true" class="product-popup-modal__content" tabindex="-1">
<button id="ModalClose-{{ block.id }}" type="button" class="product-popup-modal__toggle" aria-label="{{ 'accessibility.close' | t }}">{% render 'icon-close' %}</button>
<div class="product-popup-modal__content-info">
<h1 class="h2">{{ block.settings.page.title }}</h1>
{{ block.settings.page.content }}
</div>
</div>
</modal-dialog>
{%- endfor -%}
</section>

{% javascript %}
class ProductModal extends ModalDialog {
constructor() {
super();
}

hide() {
super.hide();
window.pauseAllMedia();
}

show(opener) {
super.show(opener);
this.showActiveMedia();
}

showActiveMedia() {
this.querySelectorAll(`[data-media-id]:not([data-media-id="${this.openedBy.getAttribute("data-media-id")}"])`).forEach((element) => {
element.classList.remove('active');
}
)
const activeMedia = this.querySelector(`[data-media-id="${this.openedBy.getAttribute("data-media-id")}"]`);
const activeMediaTemplate = activeMedia.querySelector('template');
const activeMediaContent = activeMediaTemplate ? activeMediaTemplate.content : null;
activeMedia.classList.add('active');
activeMedia.scrollIntoView();

const container = this.querySelector('[role="document"]');
container.scrollLeft = (activeMedia.width - container.clientWidth) / 2;

if (activeMedia.nodeName == 'DEFERRED-MEDIA' && activeMediaContent && activeMediaContent.querySelector('.js-youtube'))
activeMedia.loadContent();
}
}

customElements.define('product-modal', ProductModal);
{% endjavascript %}

<script>
document.addEventListener('DOMContentLoaded', function() {
function isIE() {
const ua = window.navigator.userAgent;
const msie = ua.indexOf('MSIE ');
const trident = ua.indexOf('Trident/');

return (msie > 0 || trident > 0);
}

if (!isIE()) return;
const hiddenInput = document.querySelector('#{{ product_form_id }} input[name="id"]');
const noScriptInputWrapper = document.createElement('div');
const variantSwitcher = document.querySelector('variant-radios[data-section="{{ section.id }}"]') || document.querySelector('variant-selects[data-section="{{ section.id }}"]');
noScriptInputWrapper.innerHTML = document.querySelector('.product-form__noscript-wrapper-{{ section.id }}').textContent;
variantSwitcher.outerHTML = noScriptInputWrapper.outerHTML;

document.querySelector('#Variants-{{ section.id }}').addEventListener('change', function(event) {
hiddenInput.value = event.currentTarget.value;
});
});
</script>

{%- if first_3d_model -%}
<script type="application/json" id="ProductJSON-{{ product.id }}">
{{ product.media | where: 'media_type', 'model' | json }}
</script>

<script src="{{ 'product-model.js' | asset_url }}" defer></script>
{%- endif -%}

<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"url": {{ shop.url | append: product.url | json }},
{%- if product.selected_or_first_available_variant.featured_media -%}
{%- assign media_size = product.selected_or_first_available_variant.featured_media.preview_image.width | append: 'x' -%}
"image": [
{{ product.selected_or_first_available_variant.featured_media | img_url: media_size | prepend: "https:" | json }}
],
{%- endif -%}
"description": {{ product.description | strip_html | json }},
{%- if product.selected_or_first_available_variant.sku != blank -%}
"sku": {{ product.selected_or_first_available_variant.sku | json }},
{%- endif -%}
"brand": {
"@type": "Thing",
"name": {{ product.vendor | json }}
},
"offers": [
{%- for variant in product.variants -%}
{
"@type" : "Offer",
{%- if variant.sku != blank -%}
"sku": {{ variant.sku | json }},
{%- endif -%}
"availability" : "http://schema.org/{% if variant.available %}InStock{% else %}OutOfStock{% endif %}",
"price" : {{ variant.price | divided_by: 100.00 | json }},
"priceCurrency" : {{ cart.currency.iso_code | json }},
"url" : {{ shop.url | append: variant.url | json }}
}{% unless forloop.last %},{% endunless %}
{%- endfor -%}
]
}
</script>

{% schema %}
{
"name": "t:sections.main-product.name",
"tag": "section",
"class": "product-section spaced-section",
"blocks": [
{
"type": "@app"
},
{
"type": "text",
"name": "t:sections.main-product.blocks.text.name",
"settings": [
{
"type": "text",
"id": "text",
"default": "Text block",
"label": "t:sections.main-product.blocks.text.settings.text.label"
},
{
"type": "select",
"id": "text_style",
"options": [
{
"value": "body",
"label": "t:sections.main-product.blocks.text.settings.text_style.options__1.label"
},
{
"value": "subtitle",
"label": "t:sections.main-product.blocks.text.settings.text_style.options__2.label"
},
{
"value": "uppercase",
"label": "t:sections.main-product.blocks.text.settings.text_style.options__3.label"
}
],
"default": "body",
"label": "t:sections.main-product.blocks.text.settings.text_style.label"
}
]
},
{
"type": "title",
"name": "t:sections.main-product.blocks.title.name",
"limit": 1
},
{
"type": "price",
"name": "t:sections.main-product.blocks.price.name",
"limit": 1
},
{
"type": "quantity_selector",
"name": "t:sections.main-product.blocks.quantity_selector.name",
"limit": 1
},
{
"type": "variant_picker",
"name": "t:sections.main-product.blocks.variant_picker.name",
"limit": 1,
"settings": [
{
"type": "select",
"id": "picker_type",
"options": [
{
"value": "dropdown",
"label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.options__1.label"
},
{
"value": "button",
"label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.options__2.label"
}
],
"default": "button",
"label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.label"
}
]
},
{
"type": "buy_buttons",
"name": "t:sections.main-product.blocks.buy_buttons.name",
"limit": 1,
"settings": [
{
"type": "checkbox",
"id": "show_dynamic_checkout",
"default": true,
"label": "t:sections.main-product.blocks.buy_buttons.settings.show_dynamic_checkout.label",
"info": "t:sections.main-product.blocks.buy_buttons.settings.show_dynamic_checkout.info"
}
]
},
{
"type": "description",
"name": "t:sections.main-product.blocks.description.name",
"limit": 1
},
{
"type": "share",
"name": "t:sections.main-product.blocks.share.name",
"limit": 1,
"settings": [
{
"type": "text",
"id": "share_label",
"label": "t:sections.main-product.blocks.share.settings.text.label",
"default": "Share"
},
{
"type": "paragraph",
"content": "t:sections.main-product.blocks.share.settings.featured_image_info.content"
},
{
"type": "paragraph",
"content": "t:sections.main-product.blocks.share.settings.title_info.content"
}
]
},
{
"type": "custom_liquid",
"name": "t:sections.main-product.blocks.custom_liquid.name",
"settings": [
{
"type": "liquid",
"id": "custom_liquid",
"label": "t:sections.main-product.blocks.custom_liquid.settings.custom_liquid.label",
"info": "t:sections.main-product.blocks.custom_liquid.settings.custom_liquid.info"
}
]
},
{
"type": "collapsible_tab",
"name": "t:sections.main-product.blocks.collapsible_tab.name",
"settings": [
{
"type": "text",
"id": "heading",
"default": "Collapsible tab",
"info": "t:sections.main-product.blocks.collapsible_tab.settings.heading.info",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.heading.label"
},
{
"type": "richtext",
"id": "content",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.content.label"
},
{
"type": "page",
"id": "page",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.page.label"
},
{
"type": "select",
"id": "icon",
"options": [
{
"value": "none",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__1.label"
},
{
"value": "box",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__2.label"
},
{
"value": "chat_bubble",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__3.label"
},
{
"value": "check_mark",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__4.label"
},
{
"value": "dryer",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__5.label"
},
{
"value": "eye",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__6.label"
},
{
"value": "heart",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__7.label"
},
{
"value": "iron",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__8.label"
},
{
"value": "leaf",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__9.label"
},
{
"value": "leather",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__10.label"
},
{
"value": "lock",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__11.label"
},
{
"value": "map_pin",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__12.label"
},
{
"value": "pants",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__13.label"
},
{
"value": "plane",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__14.label"
},
{
"value": "price_tag",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__15.label"
},
{
"value": "question_mark",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__16.label"
},
{
"value": "return",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__17.label"
},
{
"value": "ruler",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__18.label"
},
{
"value": "shirt",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__19.label"
},
{
"value": "shoe",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__20.label"
},
{
"value": "silhouette",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__21.label"
},
{
"value": "star",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__22.label"
},
{
"value": "truck",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__23.label"
},
{
"value": "washing",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__24.label"
}
],
"default": "check_mark",
"label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.label"
}
]
},
{
"type": "popup",
"name": "t:sections.main-product.blocks.popup.name",
"settings": [
{
"type": "text",
"id": "text",
"default": "Pop-up link text",
"label": "t:sections.main-product.blocks.popup.settings.link_label.label"
},
{
"id": "page",
"type": "page",
"label": "t:sections.main-product.blocks.popup.settings.page.label"
}
]
},
{
"type": "rating",
"name": "t:sections.main-product.blocks.rating.name",
"limit": 1,
"settings": [
{
"type": "paragraph",
"content": "t:sections.main-product.blocks.rating.settings.paragraph.content"
}
]
}
],
"settings": [
{
"type": "checkbox",
"id": "enable_sticky_info",
"default": true,
"label": "t:sections.main-product.settings.enable_sticky_info.label"
},
{
"type": "header",
"content": "t:sections.main-product.settings.header.content",
"info": "t:sections.main-product.settings.header.info"
},
{
"type": "checkbox",
"id": "hide_variants",
"default": false,
"label": "t:sections.main-product.settings.hide_variants.label"
},
{
"type": "checkbox",
"id": "enable_video_looping",
"default": false,
"label": "t:sections.main-product.settings.enable_video_looping.label"
}
]
}
{% endschema %}

 

component-slider.css

.slider-container {
margin: 0 1rem;
width: 100%;
overflow: auto;
display: flex;
flex-flow: column wrap;
align-items: center;
position: relative;
}

.large-image {
width: 100%;
padding-bottom: 100%;
position: relative;
}

.large-image-item {
position: absolute;
max-width: 100%;
min-width: 50%;
max-height: 100%;
padding: 0;
}

.large-image-item:not(:first-child){
display: none;
}

ul {
padding-inline-start: 0px !important;
}

slider-component {
position: relative;
display: block;
width:100%;
}

.slider__slide {
scroll-snap-align: start;
flex-shrink: 0;
}

.product-slider-box {
flex-wrap: inherit;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
margin-bottom: 1rem;
width: 100%;
display: flex;
}

.product-slider {
height: 100%;
width: 23%;
display: inline-block;
}

.product-slider:not(:first-child){
margin-left: 1rem;
}

.slide-image {
width: 100%;
height: 100%;
object-fit: cover;
}


/*

@media screen and (max-width: 989px) {
.no-js slider-component .slider {
padding-bottom: 3rem;
}
}


@media screen and (max-width: 749px) {
.slider.slider--mobile {
position: relative;
flex-wrap: inherit;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scroll-padding-left: 1rem;
-webkit-overflow-scrolling: touch;
margin-bottom: 1rem;
}

.slider.slider--mobile .slider__slide {
margin-bottom: 0;
padding-bottom: 0;
}
}

@media screen and (max-width: 989px) {
.slider.slider--tablet {
position: relative;
flex-wrap: inherit;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scroll-padding-left: 1rem;
-webkit-overflow-scrolling: touch;
margin-bottom: 1rem;
}

.slider.slider--tablet .slider__slide {
margin-bottom: 0;
padding-bottom: 0;
}
}
*/

/* Scrollbar */

.slider { /* included in ul */
scrollbar-color: rgb(var(--color-foreground)) rgba(var(--color-foreground), 0.04);
-ms-overflow-style: none;
scrollbar-width: none;
}

.slider::-webkit-scrollbar { /* included in ul */
height: 0.4rem;
width: 0.4rem;
display: none;
}

.no-js .slider {
-ms-overflow-style: auto;
scrollbar-width: auto;
}

.no-js .slider::-webkit-scrollbar {
display: initial;
}

.slider::-webkit-scrollbar-thumb {
background-color: rgb(var(--color-foreground));
border-radius: 0.4rem;
border: 0;
}

.slider::-webkit-scrollbar-track {
background: rgba(var(--color-foreground), 0.04);
border-radius: 0.4rem;
}

.slider-counter {
margin: 0 1.2rem;
}

.slider-buttons {
display: flex;
align-items: center;
justify-content: center;
}

/*
@media screen and (min-width: 990px) {
.slider-buttons {
display: none;
}
}

@media screen and (min-width: 750px) {
.slider--mobile + .slider-buttons {
display: none;
}
} */

.slider-button {
color: rgba(var(--color-foreground), 0.75);
background: transparent;
border: none;
cursor: pointer;
width: 44px;
height: 44px;
}

.slider-button:not([disabled]):hover {
color: rgb(var(--color-foreground));
}

.slider-button .icon {
height: 0.6rem;
}

.slider-button[disabled] .icon {
color: rgba(var(--color-foreground), 0.3);
}

.slider-button--next .icon {
margin-right: -0.2rem;
transform: rotate(-90deg) translateX(0.15rem);
}

.slider-button--prev .icon {
margin-left: -0.2rem;
transform: rotate(90deg) translateX(-0.15rem);
}

.slider-button--next:not([disabled]):hover .icon {
transform: rotate(-90deg) translateX(0.15rem) scale(1.07);
}

.slider-button--prev:not([disabled]):hover .icon {
transform: rotate(90deg) translateX(-0.15rem) scale(1.07);
}

 

global.js

function getFocusableElements(container) {
return Array.from(
container.querySelectorAll(
"summary, a[href], button:enabled, [tabindex]:not([tabindex^='-']), [draggable], area, input:not([type=hidden]):enabled, select:enabled, textarea:enabled, object, iframe"
)
);
}

const trapFocusHandlers = {};

function trapFocus(container, elementToFocus = container) {
var elements = getFocusableElements(container);
var first = elements[0];
var last = elements[elements.length - 1];

removeTrapFocus();

trapFocusHandlers.focusin = (event) => {
if (
event.target !== container &&
event.target !== last &&
event.target !== first
)
return;

document.addEventListener('keydown', trapFocusHandlers.keydown);
};

trapFocusHandlers.focusout = function() {
document.removeEventListener('keydown', trapFocusHandlers.keydown);
};

trapFocusHandlers.keydown = function(event) {
if (event.code.toUpperCase() !== 'TAB') return; // If not TAB key
// On the last focusable element and tab forward, focus the first element.
if (event.target === last && !event.shiftKey) {
event.preventDefault();
first.focus();
}

// On the first focusable element and tab backward, focus the last element.
if (
(event.target === container || event.target === first) &&
event.shiftKey
) {
event.preventDefault();
last.focus();
}
};

document.addEventListener('focusout', trapFocusHandlers.focusout);
document.addEventListener('focusin', trapFocusHandlers.focusin);

elementToFocus.focus();
}

// Here run the querySelector to figure out if the browser supports :focus-visible or not and run code based on it.
try {
document.querySelector(":focus-visible");
} catch {
focusVisiblePolyfill();
}

function focusVisiblePolyfill() {
const navKeys = ['ARROWUP', 'ARROWDOWN', 'ARROWLEFT', 'ARROWRIGHT', 'TAB', 'ENTER', 'SPACE', 'ESCAPE', 'HOME', 'END', 'PAGEUP', 'PAGEDOWN']
let currentFocusedElement = null;
let mouseClick = null;

window.addEventListener('keydown', (event) => {
if(navKeys.includes(event.code.toUpperCase())) {
mouseClick = false;
}
});

window.addEventListener('mousedown', (event) => {
mouseClick = true;
});

window.addEventListener('focus', () => {
if (currentFocusedElement) currentFocusedElement.classList.remove('focused');

if (mouseClick) return;

currentFocusedElement = document.activeElement;
currentFocusedElement.classList.add('focused');

}, true);
}

function pauseAllMedia() {
document.querySelectorAll('.js-youtube').forEach((video) => {
video.contentWindow.postMessage('{"event":"command","func":"' + 'pauseVideo' + '","args":""}', '*');
});
document.querySelectorAll('.js-vimeo').forEach((video) => {
video.contentWindow.postMessage('{"method":"pause"}', '*');
});
document.querySelectorAll('video').forEach((video) => video.pause());
document.querySelectorAll('product-model').forEach((model) => {
if (model.modelViewerUI) modelViewerUI.pause();
});
}

function removeTrapFocus(elementToFocus = null) {
document.removeEventListener('focusin', trapFocusHandlers.focusin);
document.removeEventListener('focusout', trapFocusHandlers.focusout);
document.removeEventListener('keydown', trapFocusHandlers.keydown);

if (elementToFocus) elementToFocus.focus();
}

function onKeyUpEscape(event) {
if (event.code.toUpperCase() !== 'ESCAPE') return;

const openDetailsElement = event.target.closest('details[open]');
if (!openDetailsElement) return;

const summaryElement = openDetailsElement.querySelector('summary');
openDetailsElement.removeAttribute('open');
summaryElement.focus();
}

class QuantityInput extends HTMLElement {
constructor() {
super();
this.input = this.querySelector('input');
this.changeEvent = new Event('change', { bubbles: true })

this.querySelectorAll('button').forEach(
(button) => button.addEventListener('click', this.onButtonClick.bind(this))
);
}

onButtonClick(event) {
event.preventDefault();
const previousValue = this.input.value;

event.target.name === 'plus' ? this.input.stepUp() : this.input.stepDown();
if (previousValue !== this.input.value) this.input.dispatchEvent(this.changeEvent);
}
}

customElements.define('quantity-input', QuantityInput);

function debounce(fn, wait) {
let t;
return (...args) => {
clearTimeout(t);
t = setTimeout(() => fn.apply(this, args), wait);
};
}

const serializeForm = form => {
const obj = {};
const formData = new FormData(form);

for (const key of formData.keys()) {
const regex = /(?:^(properties\[))(.*?)(?:\]$)/;

if (regex.test(key)) {
obj.properties = obj.properties || {};
obj.properties[regex.exec(key)[2]] = formData.get(key);
} else {
obj[key] = formData.get(key);
}
}

return JSON.stringify(obj);
};

function fetchConfig(type = 'json') {
return {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': `application/${type}` }
};
}

/*
* Shopify Common JS
*
*/
if ((typeof window.Shopify) == 'undefined') {
window.Shopify = {};
}

Shopify.bind = function(fn, scope) {
return function() {
return fn.apply(scope, arguments);
}
};

Shopify.setSelectorByValue = function(selector, value) {
for (var i = 0, count = selector.options.length; i < count; i++) {
var option = selector.options[i];
if (value == option.value || value == option.innerHTML) {
selector.selectedIndex = i;
return i;
}
}
};

Shopify.addListener = function(target, eventName, callback) {
target.addEventListener ? target.addEventListener(eventName, callback, false) : target.attachEvent('on'+eventName, callback);
};

Shopify.postLink = function(path, options) {
options = options || {};
var method = options['method'] || 'post';
var params = options['parameters'] || {};

var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);

for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
};

Shopify.CountryProvinceSelector = function(country_domid, province_domid, options) {
this.countryEl = document.getElementById(country_domid);
this.provinceEl = document.getElementById(province_domid);
this.provinceContainer = document.getElementById(options['hideElement'] || province_domid);

Shopify.addListener(this.countryEl, 'change', Shopify.bind(this.countryHandler,this));

this.initCountry();
this.initProvince();
};

Shopify.CountryProvinceSelector.prototype = {
initCountry: function() {
var value = this.countryEl.getAttribute('data-default');
Shopify.setSelectorByValue(this.countryEl, value);
this.countryHandler();
},

initProvince: function() {
var value = this.provinceEl.getAttribute('data-default');
if (value && this.provinceEl.options.length > 0) {
Shopify.setSelectorByValue(this.provinceEl, value);
}
},

countryHandler: function(e) {
var opt = this.countryEl.options[this.countryEl.selectedIndex];
var raw = opt.getAttribute('data-provinces');
var provinces = JSON.parse(raw);

this.clearOptions(this.provinceEl);
if (provinces && provinces.length == 0) {
this.provinceContainer.style.display = 'none';
} else {
for (var i = 0; i < provinces.length; i++) {
var opt = document.createElement('option');
opt.value = provinces[i][0];
opt.innerHTML = provinces[i][1];
this.provinceEl.appendChild(opt);
}

this.provinceContainer.style.display = "";
}
},

clearOptions: function(selector) {
while (selector.firstChild) {
selector.removeChild(selector.firstChild);
}
},

setOptions: function(selector, values) {
for (var i = 0, count = values.length; i < values.length; i++) {
var opt = document.createElement('option');
opt.value = values[i];
opt.innerHTML = values[i];
selector.appendChild(opt);
}
}
};

class MenuDrawer extends HTMLElement {
constructor() {
super();

this.mainDetailsToggle = this.querySelector('details');
const summaryElements = this.querySelectorAll('summary');
this.addAccessibilityAttributes(summaryElements);

if (navigator.platform === 'iPhone') document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`);

this.addEventListener('keyup', this.onKeyUp.bind(this));
this.addEventListener('focusout', this.onFocusOut.bind(this));
this.bindEvents();
}

bindEvents() {
this.querySelectorAll('summary').forEach(summary => summary.addEventListener('click', this.onSummaryClick.bind(this)));
this.querySelectorAll('button').forEach(button => button.addEventListener('click', this.onCloseButtonClick.bind(this)));
}

addAccessibilityAttributes(summaryElements) {
summaryElements.forEach(element => {
element.setAttribute('role', 'button');
element.setAttribute('aria-expanded', false);
element.setAttribute('aria-controls', element.nextElementSibling.id);
});
}

onKeyUp(event) {
if(event.code.toUpperCase() !== 'ESCAPE') return;

const openDetailsElement = event.target.closest('details[open]');
if(!openDetailsElement) return;

openDetailsElement === this.mainDetailsToggle ? this.closeMenuDrawer(this.mainDetailsToggle.querySelector('summary')) : this.closeSubmenu(openDetailsElement);
}

onSummaryClick(event) {
const summaryElement = event.currentTarget;
const detailsElement = summaryElement.parentNode;
const isOpen = detailsElement.hasAttribute('open');

if (detailsElement === this.mainDetailsToggle) {
if(isOpen) event.preventDefault();
isOpen ? this.closeMenuDrawer(summaryElement) : this.openMenuDrawer(summaryElement);
} else {
trapFocus(summaryElement.nextElementSibling, detailsElement.querySelector('button'));

setTimeout(() => {
detailsElement.classList.add('menu-opening');
});
}
}

openMenuDrawer(summaryElement) {
setTimeout(() => {
this.mainDetailsToggle.classList.add('menu-opening');
});
summaryElement.setAttribute('aria-expanded', true);
trapFocus(this.mainDetailsToggle, summaryElement);
document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
}

closeMenuDrawer(event, elementToFocus = false) {
if (event !== undefined) {
this.mainDetailsToggle.classList.remove('menu-opening');
this.mainDetailsToggle.querySelectorAll('details').forEach(details => {
details.removeAttribute('open');
details.classList.remove('menu-opening');
});
this.mainDetailsToggle.querySelector('summary').setAttribute('aria-expanded', false);
document.body.classList.remove(`overflow-hidden-${this.dataset.breakpoint}`);
removeTrapFocus(elementToFocus);
this.closeAnimation(this.mainDetailsToggle);
}
}

onFocusOut(event) {
setTimeout(() => {
if (this.mainDetailsToggle.hasAttribute('open') && !this.mainDetailsToggle.contains(document.activeElement)) this.closeMenuDrawer();
});
}

onCloseButtonClick(event) {
const detailsElement = event.currentTarget.closest('details');
this.closeSubmenu(detailsElement);
}

closeSubmenu(detailsElement) {
detailsElement.classList.remove('menu-opening');
removeTrapFocus();
this.closeAnimation(detailsElement);
}

closeAnimation(detailsElement) {
let animationStart;

const handleAnimation = (time) => {
if (animationStart === undefined) {
animationStart = time;
}

const elapsedTime = time - animationStart;

if (elapsedTime < 400) {
window.requestAnimationFrame(handleAnimation);
} else {
detailsElement.removeAttribute('open');
if (detailsElement.closest('details[open]')) {
trapFocus(detailsElement.closest('details[open]'), detailsElement.querySelector('summary'));
}
}
}

window.requestAnimationFrame(handleAnimation);
}
}

customElements.define('menu-drawer', MenuDrawer);

class HeaderDrawer extends MenuDrawer {
constructor() {
super();
}

openMenuDrawer(summaryElement) {
this.header = this.header || document.getElementById('shopify-section-header');
this.borderOffset = this.borderOffset || this.closest('.header-wrapper').classList.contains('header-wrapper--border-bottom') ? 1 : 0;
document.documentElement.style.setProperty('--header-bottom-position', `${parseInt(this.header.getBoundingClientRect().bottom - this.borderOffset)}px`);

setTimeout(() => {
this.mainDetailsToggle.classList.add('menu-opening');
});

summaryElement.setAttribute('aria-expanded', true);
trapFocus(this.mainDetailsToggle, summaryElement);
document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
}
}

customElements.define('header-drawer', HeaderDrawer);

class ModalDialog extends HTMLElement {
constructor() {
super();
this.querySelector('[id^="ModalClose-"]').addEventListener(
'click',
this.hide.bind(this)
);
this.addEventListener('keyup', (event) => {
if (event.code.toUpperCase() === 'ESCAPE') this.hide();
});
if (this.classList.contains('media-modal')) {
this.addEventListener('pointerup', (event) => {
if (event.pointerType === 'mouse' && !event.target.closest('deferred-media, product-model')) this.hide();
});
} else {
this.addEventListener('click', (event) => {
if (event.target.nodeName === 'MODAL-DIALOG') this.hide();
});
}
}

show(opener) {
this.openedBy = opener;
const popup = this.querySelector('.template-popup');
document.body.classList.add('overflow-hidden');
this.setAttribute('open', '');
if (popup) popup.loadContent();
trapFocus(this, this.querySelector('[role="dialog"]'));
}

hide() {
document.body.classList.remove('overflow-hidden');
this.removeAttribute('open');
removeTrapFocus(this.openedBy);
window.pauseAllMedia();
}
}
customElements.define('modal-dialog', ModalDialog);

class ModalOpener extends HTMLElement {
constructor() {
super();

const button = this.querySelector('button');

if (!button) return;
button.addEventListener('click', () => {
const modal = document.querySelector(this.getAttribute('data-modal'));
if (modal) modal.show(button);
});
}
}
customElements.define('modal-opener', ModalOpener);

class DeferredMedia extends HTMLElement {
constructor() {
super();
const poster = this.querySelector('[id^="Deferred-Poster-"]');
if (!poster) return;
poster.addEventListener('click', this.loadContent.bind(this));
}

loadContent() {
window.pauseAllMedia();
if (!this.getAttribute('loaded')) {
const content = document.createElement('div');
content.appendChild(this.querySelector('template').content.firstElementChild.cloneNode(true));

this.setAttribute('loaded', true);
this.appendChild(content.querySelector('video, model-viewer, iframe')).focus();
}
}
}

customElements.define('deferred-media', DeferredMedia);

class SliderComponent extends HTMLElement {
constructor() {
super();
this.slider = this.querySelector('ul');
this.sliderItems = this.querySelectorAll('li');
this.pageCount = this.querySelector('.slider-counter--current');
this.pageTotal = this.querySelector('.slider-counter--total');
this.prevButton = this.querySelector('button[name="previous"]');
this.nextButton = this.querySelector('button[name="next"]');

if (!this.slider || !this.nextButton) return;

const resizeObserver = new ResizeObserver(entries => this.initPages());
resizeObserver.observe(this.slider);

this.slider.addEventListener('scroll', this.update.bind(this));
this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
this.nextButton.addEventListener('click', this.onButtonClick.bind(this));
}

initPages() {
const sliderItemsToShow = Array.from(this.sliderItems).filter(element => element.clientWidth > 0);
this.sliderLastItem = sliderItemsToShow[sliderItemsToShow.length - 1];
if (sliderItemsToShow.length === 0) return;
this.slidesPerPage = Math.floor(this.slider.clientWidth / sliderItemsToShow[0].clientWidth);
this.totalPages = sliderItemsToShow.length - this.slidesPerPage + 3;
this.update();
}

update() {
if (!this.pageCount || !this.pageTotal) return;
this.currentPage = Math.round(this.slider.scrollLeft / this.sliderLastItem.clientWidth) + 4;

if (this.currentPage === 1) {
this.prevButton.setAttribute('disabled', true);
} else {
this.prevButton.removeAttribute('disabled');
}

if (this.currentPage === this.totalPages) {
this.nextButton.setAttribute('disabled', true);
} else {
this.nextButton.removeAttribute('disabled');
}

this.pageCount.textContent = this.currentPage;
this.pageTotal.textContent = this.totalPages;
}

onButtonClick(event) {
event.preventDefault();
const slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + this.sliderLastItem.clientWidth : this.slider.scrollLeft - this.sliderLastItem.clientWidth;
this.slider.scrollTo({
left: slideScrollPosition
});
}
}

customElements.define('slider-component', SliderComponent);

class VariantSelects extends HTMLElement {
constructor() {
super();
this.addEventListener('change', this.onVariantChange);
}

onVariantChange() {
this.updateOptions();
this.updateMasterId();
this.toggleAddButton(true, '', false);
this.updatePickupAvailability();
this.removeErrorMessage();

if (!this.currentVariant) {
this.toggleAddButton(true, '', true);
this.setUnavailable();
} else {
this.updateMedia();
this.updateURL();
this.updateVariantInput();
this.renderProductInfo();
}
}

updateOptions() {
this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
}

updateMasterId() {
this.currentVariant = this.getVariantData().find((variant) => {
return !variant.options.map((option, index) => {
return this.options[index] === option;
}).includes(false);
});
}

updateMedia() {
if (!this.currentVariant) return;
if (!this.currentVariant.featured_media) return;
const newMedia = document.querySelector(
`[data-media-id="${this.dataset.section}-${this.currentVariant.featured_media.id}"]`
);

if (!newMedia) return;
const modalContent = document.querySelector(`#ProductModal-${this.dataset.section} .product-media-modal__content`);
const newMediaModal = modalContent.querySelector( `[data-media-id="${this.currentVariant.featured_media.id}"]`);
const parent = newMedia.parentElement;
if (parent.firstChild == newMedia) return;
modalContent.prepend(newMediaModal);
parent.prepend(newMedia);
this.stickyHeader = this.stickyHeader || document.querySelector('sticky-header');
if(this.stickyHeader) {
this.stickyHeader.dispatchEvent(new Event('preventHeaderReveal'));
}
window.setTimeout(() => { parent.querySelector('li.product__media-item').scrollIntoView({behavior: "smooth"}); });
}

updateURL() {
if (!this.currentVariant || this.dataset.updateUrl === 'false') return;
window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
}

updateVariantInput() {
const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
productForms.forEach((productForm) => {
const input = productForm.querySelector('input[name="id"]');
input.value = this.currentVariant.id;
input.dispatchEvent(new Event('change', { bubbles: true }));
});
}

updatePickupAvailability() {
const pickUpAvailability = document.querySelector('pickup-availability');
if (!pickUpAvailability) return;

if (this.currentVariant && this.currentVariant.available) {
pickUpAvailability.fetchAvailability(this.currentVariant.id);
} else {
pickUpAvailability.removeAttribute('available');
pickUpAvailability.innerHTML = '';
}
}

removeErrorMessage() {
const section = this.closest('section');
if (!section) return;

const productForm = section.querySelector('product-form');
if (productForm) productForm.handleErrorMessage();
}

renderProductInfo() {
fetch(`${this.dataset.url}?variant=${this.currentVariant.id}&section_id=${this.dataset.section}`)
.then((response) => response.text())
.then((responseText) => {
const id = `price-${this.dataset.section}`;
const html = new DOMParser().parseFromString(responseText, 'text/html')
const destination = document.getElementById(id);
const source = html.getElementById(id);

if (source && destination) destination.innerHTML = source.innerHTML;

const price = document.getElementById(`price-${this.dataset.section}`);

if (price) price.classList.remove('visibility-hidden');
this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
});
}

toggleAddButton(disable = true, text, modifyClass = true) {
const productForm = document.getElementById(`product-form-${this.dataset.section}`);
if (!productForm) return;
const addButton = productForm.querySelector('[name="add"]');

if (!addButton) return;

if (disable) {
addButton.setAttribute('disabled', true);
if (text) addButton.textContent = text;
} else {
addButton.removeAttribute('disabled');
addButton.textContent = window.variantStrings.addToCart;
}

if (!modifyClass) return;
}

setUnavailable() {
const button = document.getElementById(`product-form-${this.dataset.section}`);
const addButton = button.querySelector('[name="add"]');
const price = document.getElementById(`price-${this.dataset.section}`);
if (!addButton) return;
addButton.textContent = window.variantStrings.unavailable;
if (price) price.classList.add('visibility-hidden');
}

getVariantData() {
this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
return this.variantData;
}
}

customElements.define('variant-selects', VariantSelects);

class VariantRadios extends VariantSelects {
constructor() {
super();
}

updateOptions() {
const fieldsets = Array.from(this.querySelectorAll('fieldset'));
this.options = fieldsets.map((fieldset) => {
return Array.from(fieldset.querySelectorAll('input')).find((radio) => radio.checked).value;
});
}
}

customElements.define('variant-radios', VariantRadios);

shadowsfall118
Shopify Partner
125 13 37

See attached after following your guide.

Looks like main image block is not being displayed and the JS is throwing an error because it can't grab the image URL of the thumb clicked.

'Uncaught TypeError: Cannot read properties of null (reading 'parentElement')'

StewartM
Shopify Partner
5 0 1

Thank you @shadowsfall118  for also looking into this. 

 

I have attached my files for reference as well @made4Uo - i appreciate your time. 

 

Thanks 


Stewart 

{% comment %}theme-check-disable TemplateLength{% endcomment %}
{{ 'section-main-product.css' | asset_url | stylesheet_tag }}
{{ 'component-accordion.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
{{ 'component-rte.css' | asset_url | stylesheet_tag }}
{{ 'component-slider.css' | asset_url | stylesheet_tag }}
{{ 'component-rating.css' | asset_url | stylesheet_tag }}

<link rel="stylesheet" href="{{ 'component-deferred-media.css' | asset_url }}" media="print" onload="this.media='all'">

<script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>

<script>
function newLargeImage(x) {
let clickedImage = x.dataset.thumbId;
const newImage = document.querySelector(`[data-media-id="${clickedImage}"]`);
const parentData = newImage.parentElement;
parentData.prepend(newImage);

const resizeObserver = new ResizeObserver(entries =>
x.clientHeight)
resizeObserver.observe(document.body)
const imgHt = x.clientHeight * 4.5;
document.getElementById('large-image').style.paddingBottom = imgHt + 'px';
};
</script>


{%- assign first_3d_model = product.media | where: "media_type", "model" | first -%}
{%- if first_3d_model -%}
  {{ 'component-product-model.css' | asset_url | stylesheet_tag }}
  <link id="ModelViewerStyle" rel="stylesheet" href="https://cdn.shopify.com/shopifycloud/model-viewer-ui/assets/v1.0/model-viewer-ui.css" media="print" onload="this.media='all'">
  <link id="ModelViewerOverride" rel="stylesheet" href="{{ 'component-model-viewer-ui.css' | asset_url }}" media="print" onload="this.media='all'">
{%- endif -%}

<section class="page-width">
  <div class="product grid grid--1-col {% if product.media.size > 0 %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
    <div class="grid__item product__media-wrapper">
      
      <div class="slider-container" >
<a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
{{ "accessibility.skip_to_product_info" | t }}
</a>
<ul class="large-image" id="large-image">
{%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
{%- if product.selected_or_first_available_variant.featured_media != null -%}
{%- assign media = product.selected_or_first_available_variant.featured_media -%}
{%- for media in product.media -%}

<li class="large-image-item product__media-item grid__item slider__slide
{% if media.media_type != 'image' %}
product__media-item--full{% endif %}"
data-media-id="{{ section.id }}-{{ media.id }}">
{% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
</li>
{%- endfor -%}
{%- endif -%}
</ul>

<slider-component >
<ul class="product-slider-box slider" role="list">
{%- for media in product.media -%}
<li class="product-slider slider__slide">
<img class="slide-image"
onclick="newLargeImage(this)"
data-thumb-id="{{ section.id }}-{{ media.id }}"
src="{{ media.preview_image | img_url: 'large', scale: 4 }}"
alt="{{ thumbnailAlt }}">
</li>
{% endfor %}
</ul>
<div class="slider-buttons {% if product.media.size < 2 %}
small-hide{% endif %}">
<button type="button" class="slider-button slider-button--prev bigger-slider" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
<div class="slider-counter caption">
<span class="slider-counter--current">1</span>
<span aria-hidden="true"> / </span>
<span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
<span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
</div>
<button type="button" class="slider-button slider-button--next bigger-slider" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
</div>
</slider-component>
</div>
      
      <!-- ORIGINAL SLIDER CODE
      <slider-component class="slider-mobile-gutter">
        <a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
          {{ "accessibility.skip_to_product_info" | t }}
        </a>
        <ul class="product__media-list grid grid--peek list-unstyled slider slider--mobile" role="list">
          {%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
          {%- if product.selected_or_first_available_variant.featured_media != null -%}
            {%- assign media = product.selected_or_first_available_variant.featured_media -%}
            <li class="product__media-item grid__item slider__slide{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}">
              {% render 'product-thumbnail', media: media, position: 'featured', loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
            </li>
          {%- endif -%}
          {%- for media in product.media -%}
            {%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%}
              <li class="product__media-item grid__item slider__slide{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if section.settings.hide_variants and variant_images contains media.src %} product__media-item--variant{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}">
                {% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
              </li>
            {%- endunless -%}
          {%- endfor -%}
        </ul>
        <div class="slider-buttons no-js-hidden{% if product.media.size < 2 %} small-hide{% endif %}">
          <button type="button" class="slider-button slider-button--prev" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
          <div class="slider-counter caption">
            <span class="slider-counter--current">1</span>
            <span aria-hidden="true"> / </span>
            <span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
            <span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
          </div>
          <button type="button" class="slider-button slider-button--next" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
        </div>
      </slider-component> -->


      {%- if first_3d_model -%}
        <button
          class="button button--full-width product__xr-button"
          type="button"
          aria-label="{{ 'products.product.xr_button_label' | t }}"
          data-shopify-xr
          data-shopify-model3d-id="{{ first_3d_model.id }}"
          data-shopify-title="{{ product.title | escape }}"
          data-shopify-xr-hidden
        >
          {% render 'icon-3d-model' %}
          {{ 'products.product.xr_button' | t }}
        </button>
      {%- endif -%}
    </div>
    <div class="product__info-wrapper grid__item">
      <div id="ProductInfo-{{ section.id }}" class="product__info-container{% if section.settings.enable_sticky_info %} product__info-container--sticky{% endif %}">
        {%- assign product_form_id = 'product-form-' | append: section.id -%}

        {%- for block in section.blocks -%}
          {%- case block.type -%}
          {%- when '@app' -%}
            {% render block %}
          {%- when 'text' -%}
            <p class="product__text{% if block.settings.text_style == 'uppercase' %} caption-with-letter-spacing{% elsif block.settings.text_style == 'subtitle' %} subtitle{% endif %}" {{ block.shopify_attributes }}>
              {{- block.settings.text -}}
            </p>
          {%- when 'title' -%}
            <h1 class="product__title" {{ block.shopify_attributes }}>
              {{ product.title | escape }}
            </h1>
          {%- when 'price' -%}
            <div class="no-js-hidden" id="price-{{ section.id }}" {{ block.shopify_attributes }}>
              {%- render 'price', product: product, use_variant: true, show_badges: true, price_class: 'price--large' -%}
            </div>
            <div {{ block.shopify_attributes }}>
              {%- form 'product', product, id: 'product-form-installment', class: 'installment caption-large' -%}
                <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
                {{ form | payment_terms }}
              {%- endform -%}
            </div>
          {%- when 'description' -%}
            {%- if product.description != blank -%}
              <div class="product__description rte">
                {{ product.description }}
              </div>
            {%- endif -%}
          {%- when 'custom_liquid' -%}
            {{ block.settings.custom_liquid }}
          {%- when 'collapsible_tab' -%}
            <div class="product__accordion accordion" {{ block.shopify_attributes }}>
              <details>
                <summary>
                  <div class="summary__title">
                    {% render 'icon-accordion', icon: block.settings.icon %}
                    <h2 class="h4 accordion__title">
                      {{ block.settings.heading | default: block.settings.page.title }}
                    </h2>
                  </div>
                  {% render 'icon-caret' %}
                </summary>
                <div class="accordion__content rte">
                  {{ block.settings.content }}
                  {{ block.settings.page.content }}
                </div>
              </details>
            </div>
          {%- when 'quantity_selector' -%}
            <div class="product-form__input product-form__quantity" {{ block.shopify_attributes }}>
              <label class="form__label" for="Quantity-{{ section.id }}">
                {{ 'products.product.quantity.label' | t }}
              </label>

              <quantity-input class="quantity">
                <button class="quantity__button no-js-hidden" name="minus" type="button">
                  <span class="visually-hidden">{{ 'products.product.quantity.decrease' | t: product: product.title | escape }}</span>
                  {% render 'icon-minus' %}
                </button>
                <input class="quantity__input"
                    type="number"
                    name="quantity"
                    id="Quantity-{{ section.id }}"
                    min="1"
                    value="1"
                    form="product-form-{{ section.id }}"
                  >
                <button class="quantity__button no-js-hidden" name="plus" type="button">
                  <span class="visually-hidden">{{ 'products.product.quantity.increase' | t: product: product.title | escape }}</span>
                  {% render 'icon-plus' %}
                </button>
              </quantity-input>
            </div>
          {%- when 'popup' -%}
              <modal-opener class="product-popup-modal__opener no-js-hidden" data-modal="#PopupModal-{{ block.id }}" {{ block.shopify_attributes }}>
                <button id="ProductPopup-{{ block.id }}" class="product-popup-modal__button link" type="button" aria-haspopup="dialog">{{ block.settings.text | default: block.settings.page.title }}</button>
              </modal-opener>
              <a href="{{ block.settings.page.url }}" class="product-popup-modal__button link no-js">{{ block.settings.text }}</a>
          {%- when 'share' -%}
            <share-button class="share-button" {{ block.shopify_attributes }}>
              <button class="share-button__button hidden">
                {% render 'icon-share' %}
                {{ block.settings.share_label | escape }}
              </button>
              <details>
                <summary class="share-button__button">
                  {% render 'icon-share' %}
                  {{ block.settings.share_label | escape }}
                </summary>
                <div id="Product-share-{{ section.id }}" class="share-button__fallback motion-reduce">
                  <div class="field">
                    <span id="ShareMessage-{{ section.id }}" class="share-button__message hidden" role="status">
                    </span>
                    <input type="text"
                          class="field__input"
                          id="url"
                          value="{{ shop.url | append: product.url }}"
                          placeholder="{{ 'general.share.share_url' | t }}"
                          onclick="this.select();"
                          readonly
                    >
                    <label class="field__label" for="url">{{ 'general.share.share_url' | t }}</label>
                  </div>
                  <button class="share-button__close hidden no-js-hidden">
                    {% render 'icon-close' %}
                    <span class="visually-hidden">{{ 'general.share.close' | t }}</span>
                  </button>
                  <button class="share-button__copy no-js-hidden">
                    {% render 'icon-clipboard' %}
                    <span class="visually-hidden">{{ 'general.share.copy_to_clipboard' | t }}</span>
                  </button>
                </div>
              </details>
            </share-button>
            <script src="{{ 'share.js' | asset_url }}" defer="defer"></script>
          {%- when 'variant_picker' -%}
            {%- unless product.has_only_default_variant -%}
              {%- if block.settings.picker_type == 'button' -%}
                <variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
                  {%- for option in product.options_with_values -%}
                      <fieldset class="js product-form__input">
                        <legend class="form__label">{{ option.name }}</legend>
                        {%- for value in option.values -%}
                          <input type="radio" id="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}"
                                name="{{ option.name }}"
                                value="{{ value | escape }}"
                                form="product-form-{{ section.id }}"
                                {% if option.selected_value == value %}checked{% endif %}
                          >
                          <label for="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}">
                            {{ value }}
                          </label>
                        {%- endfor -%}
                      </fieldset>
                  {%- endfor -%}
                  <script type="application/json">
                    {{ product.variants | json }}
                  </script>
                </variant-radios>
              {%- else -%}
                <variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
                  {%- for option in product.options_with_values -%}
                    <div class="product-form__input product-form__input--dropdown">
                      <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
                        {{ option.name }}
                      </label>
                      <div class="select">
                        <select id="Option-{{ section.id }}-{{ forloop.index0 }}"
                          class="select__select"
                          name="options[{{ option.name | escape }}]"
                          form="product-form-{{ section.id }}"
                        >
                          {%- for value in option.values -%}
                            <option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}>
                              {{ value }}
                            </option>
                          {%- endfor -%}
                        </select>
                        {% render 'icon-caret' %}
                      </div>
                    </div>
                  {%- endfor -%}

                  <script type="application/json">
                    {{ product.variants | json }}
                  </script>
                </variant-selects>
              {%- endif -%}
            {%- endunless -%}

            <noscript class="product-form__noscript-wrapper-{{ section.id }}">
              <div class="product-form__input{% if product.has_only_default_variant %} hidden{% endif %}">
                <label class="form__label" for="Variants-{{ section.id }}">{{ 'products.product.product_variants' | t }}</label>
                <div class="select">
                  <select name="id" id="Variants-{{ section.id }}" class="select__select" form="product-form">
                    {%- for variant in product.variants -%}
                      <option
                        {% if variant == product.selected_or_first_available_variant %}selected="selected"{% endif %}
                        {% if variant.available == false %}disabled{% endif %}
                        value="{{ variant.id }}"
                      >
                        {{ variant.title }}
                        {%- if variant.available == false %} - {{ 'products.product.sold_out' | t }}{% endif %}
                        - {{ variant.price | money | strip_html }}
                      </option>
                    {%- endfor -%}
                  </select>
                  {% render 'icon-caret' %}
                </div>
              </div>
            </noscript>
          {%- when 'buy_buttons' -%}
            <div {{ block.shopify_attributes }}>
              <product-form class="product-form">
                <div class="product-form__error-message-wrapper" role="alert" hidden>
                  <svg aria-hidden="true" focusable="false" role="presentation" class="icon icon-error" viewBox="0 0 13 13">
                    <circle cx="6.5" cy="6.50049" r="5.5" stroke="white" stroke-width="2"/>
                    <circle cx="6.5" cy="6.5" r="5.5" fill="#EB001B" stroke="#EB001B" stroke-width="0.7"/>
                    <path d="M5.87413 3.52832L5.97439 7.57216H7.02713L7.12739 3.52832H5.87413ZM6.50076 9.66091C6.88091 9.66091 7.18169 9.37267 7.18169 9.00504C7.18169 8.63742 6.88091 8.34917 6.50076 8.34917C6.12061 8.34917 5.81982 8.63742 5.81982 9.00504C5.81982 9.37267 6.12061 9.66091 6.50076 9.66091Z" fill="white"/>
                    <path d="M5.87413 3.17832H5.51535L5.52424 3.537L5.6245 7.58083L5.63296 7.92216H5.97439H7.02713H7.36856L7.37702 7.58083L7.47728 3.537L7.48617 3.17832H7.12739H5.87413ZM6.50076 10.0109C7.06121 10.0109 7.5317 9.57872 7.5317 9.00504C7.5317 8.43137 7.06121 7.99918 6.50076 7.99918C5.94031 7.99918 5.46982 8.43137 5.46982 9.00504C5.46982 9.57872 5.94031 10.0109 6.50076 10.0109Z" fill="white" stroke="#EB001B" stroke-width="0.7">
                  </svg>
                  <span class="product-form__error-message"></span>
                </div>

                {%- form 'product', product, id: product_form_id, class: 'form', novalidate: 'novalidate', data-type: 'add-to-cart-form' -%}
                  <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
                  <div class="product-form__buttons">
                    <button
                      type="submit"
                      name="add"
                      class="product-form__submit button button--full-width {% if block.settings.show_dynamic_checkout and product.selling_plan_groups == empty %}button--secondary{% else %}button--primary{% endif %}"
                    {% if product.selected_or_first_available_variant.available == false %}disabled{% endif %}
                    >
                        {%- if product.selected_or_first_available_variant.available -%}
                          {{ 'products.product.add_to_cart' | t }}
                        {%- else -%}
                          {{ 'products.product.sold_out' | t }}
                        {%- endif -%}
                    </button>
                    {%- if block.settings.show_dynamic_checkout -%}
                      {{ form | payment_button }}
                    {%- endif -%}
                  </div>
                {%- endform -%}
              </product-form>

              {{ 'component-pickup-availability.css' | asset_url | stylesheet_tag }}

              {%- assign pick_up_availabilities = product.selected_or_first_available_variant.store_availabilities | where: 'pick_up_enabled', true -%}

              <pickup-availability class="product__pickup-availabilities no-js-hidden"
                {% if product.selected_or_first_available_variant.available and pick_up_availabilities.size > 0 %} available{% endif %}
                data-base-url="{{ shop.url }}{{ routes.root_url }}"
                data-variant-id="{{ product.selected_or_first_available_variant.id }}"
                data-has-only-default-variant="{{ product.has_only_default_variant }}"
              >
                <template>
                  <pickup-availability-preview class="pickup-availability-preview">
                    {% render 'icon-unavailable' %}
                    <div class="pickup-availability-info">
                      <p class="caption-large">{{ 'products.product.pickup_availability.unavailable' | t }}</p>
                      <button class="pickup-availability-button link link--text underlined-link">{{ 'products.product.pickup_availability.refresh' | t }}</button>
                    </div>
                  </pickup-availability-preview>
                </template>
              </pickup-availability>
            </div>

            <script src="{{ 'pickup-availability.js' | asset_url }}" defer="defer"></script>
          {%- when 'rating' -%}
            {%- if product.metafields.reviews.rating.value != blank -%}
              {% liquid
               assign rating_decimal = 0
               assign decimal = product.metafields.reviews.rating.value.rating | modulo: 1
               if decimal >= 0.3 and decimal <= 0.7
                assign rating_decimal = 0.5
              elsif decimal > 0.7
                assign rating_decimal = 1
               endif
              %}
              <div class="rating" role="img" aria-label="{{ 'accessibility.star_reviews_info' | t: rating_value: product.metafields.reviews.rating.value, rating_max: product.metafields.reviews.rating.value.scale_max }}">
                <span aria-hidden="true" class="rating-star color-icon-{{ settings.accent_icons }}" style="--rating: {{ product.metafields.reviews.rating.value.rating | floor }}; --rating-max: {{ product.metafields.reviews.rating.value.scale_max }}; --rating-decimal: {{ rating_decimal }};"></span>
              </div>
              <p class="rating-text caption">
                <span aria-hidden="true">{{ product.metafields.reviews.rating.value }} / {{ product.metafields.reviews.rating.value.scale_max }}</span>
              </p>
              <p class="rating-count caption">
                <span aria-hidden="true">({{ product.metafields.reviews.rating_count }})</span>
                <span class="visually-hidden">{{ product.metafields.reviews.rating_count }} {{ "accessibility.total_reviews" | t }}</span>
              </p>
            {%- endif -%}
          {%- endcase -%}
        {%- endfor -%}
      </div>
    </div>
  </div>

  <product-modal id="ProductModal-{{ section.id }}" class="product-media-modal media-modal">
    <div class="product-media-modal__dialog" role="dialog" aria-label="{{ 'products.modal.label' | t }}" aria-modal="true" tabindex="-1">
      <button id="ModalClose-{{ section.id }}" type="button" class="product-media-modal__toggle" aria-label="{{ 'accessibility.close' | t }}">{% render 'icon-close' %}</button>

      <div class="product-media-modal__content" role="document" aria-label="{{ 'products.modal.label' | t }}" tabindex="0">
        {%- liquid
          if product.selected_or_first_available_variant.featured_media != null
            assign media = product.selected_or_first_available_variant.featured_media
            render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: section.settings.hide_variants
          endif
        -%}

        {%- for media in product.media -%}
          {%- liquid
            if section.settings.hide_variants and variant_images contains media.src
              assign variant_image = true
            else
              assign variant_image = false
            endif

            unless media.id == product.selected_or_first_available_variant.featured_media.id
              render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: variant_image
            endunless
          -%}
        {%- endfor -%}
      </div>
    </div>
  </product-modal>

  {% assign popups = section.blocks | where: "type", "popup" %}
  {%- for block in popups -%}
    <modal-dialog id="PopupModal-{{ block.id }}" class="product-popup-modal" {{ block.shopify_attributes }}>
      <div role="dialog" aria-label="{{ block.settings.text }}" aria-modal="true" class="product-popup-modal__content" tabindex="-1">
        <button id="ModalClose-{{ block.id }}" type="button" class="product-popup-modal__toggle" aria-label="{{ 'accessibility.close' | t }}">{% render 'icon-close' %}</button>
        <div class="product-popup-modal__content-info">
          <h1 class="h2">{{ block.settings.page.title }}</h1>
          {{ block.settings.page.content }}
        </div>
      </div>
    </modal-dialog>
  {%- endfor -%}
</section>

{% javascript %}
  class ProductModal extends ModalDialog {
    constructor() {
      super();
    }

    hide() {
      super.hide();
      window.pauseAllMedia();
    }

    show(opener) {
      super.show(opener);
      this.showActiveMedia();
    }

    showActiveMedia() {
      this.querySelectorAll(`[data-media-id]:not([data-media-id="${this.openedBy.getAttribute("data-media-id")}"])`).forEach((element) => {
          element.classList.remove('active');
        }
      )
      const activeMedia = this.querySelector(`[data-media-id="${this.openedBy.getAttribute("data-media-id")}"]`);
      const activeMediaTemplate = activeMedia.querySelector('template');
      const activeMediaContent = activeMediaTemplate ? activeMediaTemplate.content : null;
      activeMedia.classList.add('active');
      activeMedia.scrollIntoView();

      const container = this.querySelector('[role="document"]');
      container.scrollLeft = (activeMedia.width - container.clientWidth) / 2;

      if (activeMedia.nodeName == 'DEFERRED-MEDIA' && activeMediaContent && activeMediaContent.querySelector('.js-youtube'))
        activeMedia.loadContent();
    }
  }

  customElements.define('product-modal', ProductModal);
{% endjavascript %}

<script>
  document.addEventListener('DOMContentLoaded', function() {
    function isIE() {
      const ua = window.navigator.userAgent;
      const msie = ua.indexOf('MSIE ');
      const trident = ua.indexOf('Trident/');

      return (msie > 0 || trident > 0);
    }

    if (!isIE()) return;
    const hiddenInput = document.querySelector('#{{ product_form_id }} input[name="id"]');
    const noScriptInputWrapper = document.createElement('div');
    const variantSwitcher = document.querySelector('variant-radios[data-section="{{ section.id }}"]') || document.querySelector('variant-selects[data-section="{{ section.id }}"]');
    noScriptInputWrapper.innerHTML = document.querySelector('.product-form__noscript-wrapper-{{ section.id }}').textContent;
    variantSwitcher.outerHTML = noScriptInputWrapper.outerHTML;

    document.querySelector('#Variants-{{ section.id }}').addEventListener('change', function(event) {
      hiddenInput.value = event.currentTarget.value;
    });
  });
</script>

{%- if first_3d_model -%}
  <script type="application/json" id="ProductJSON-{{ product.id }}">
    {{ product.media | where: 'media_type', 'model' | json }}
  </script>

  <script src="{{ 'product-model.js' | asset_url }}" defer></script>
{%- endif -%}

<script type="application/ld+json">
  {
    "@context": "http://schema.org/",
    "@type": "Product",
    "name": {{ product.title | json }},
    "url": {{ shop.url | append: product.url | json }},
    {%- if product.selected_or_first_available_variant.featured_media -%}
      {%- assign media_size = product.selected_or_first_available_variant.featured_media.preview_image.width | append: 'x' -%}
      "image": [
        {{ product.selected_or_first_available_variant.featured_media | img_url: media_size | prepend: "https:" | json }}
      ],
    {%- endif -%}
    "description": {{ product.description | strip_html | json }},
    {%- if product.selected_or_first_available_variant.sku != blank -%}
      "sku": {{ product.selected_or_first_available_variant.sku | json }},
    {%- endif -%}
    "brand": {
      "@type": "Thing",
      "name": {{ product.vendor | json }}
    },
    "offers": [
      {%- for variant in product.variants -%}
        {
          "@type" : "Offer",
          {%- if variant.sku != blank -%}
            "sku": {{ variant.sku | json }},
          {%- endif -%}
          "availability" : "http://schema.org/{% if variant.available %}InStock{% else %}OutOfStock{% endif %}",
          "price" : {{ variant.price | divided_by: 100.00 | json }},
          "priceCurrency" : {{ cart.currency.iso_code | json }},
          "url" : {{ shop.url | append: variant.url | json }}
        }{% unless forloop.last %},{% endunless %}
      {%- endfor -%}
    ]
  }
</script>

{% schema %}
{
  "name": "t:sections.main-product.name",
  "tag": "section",
  "class": "product-section spaced-section",
  "blocks": [
    {
      "type": "@app"
    },
    {
      "type": "text",
      "name": "t:sections.main-product.blocks.text.name",
      "settings": [
        {
          "type": "text",
          "id": "text",
          "default": "Text block",
          "label": "t:sections.main-product.blocks.text.settings.text.label"
        },
        {
          "type": "select",
          "id": "text_style",
          "options": [
            {
              "value": "body",
              "label": "t:sections.main-product.blocks.text.settings.text_style.options__1.label"
            },
            {
              "value": "subtitle",
              "label": "t:sections.main-product.blocks.text.settings.text_style.options__2.label"
            },
            {
              "value": "uppercase",
              "label": "t:sections.main-product.blocks.text.settings.text_style.options__3.label"
            }
          ],
          "default": "body",
          "label": "t:sections.main-product.blocks.text.settings.text_style.label"
        }
      ]
    },
    {
      "type": "title",
      "name": "t:sections.main-product.blocks.title.name",
      "limit": 1
    },
    {
      "type": "price",
      "name": "t:sections.main-product.blocks.price.name",
      "limit": 1
    },
    {
      "type": "quantity_selector",
      "name": "t:sections.main-product.blocks.quantity_selector.name",
      "limit": 1
    },
    {
      "type": "variant_picker",
      "name": "t:sections.main-product.blocks.variant_picker.name",
      "limit": 1,
      "settings": [
        {
          "type": "select",
          "id": "picker_type",
          "options": [
            {
              "value": "dropdown",
              "label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.options__1.label"
            },
            {
              "value": "button",
              "label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.options__2.label"
            }
          ],
          "default": "button",
          "label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.label"
        }
      ]
    },
    {
      "type": "buy_buttons",
      "name": "t:sections.main-product.blocks.buy_buttons.name",
      "limit": 1,
      "settings": [
        {
          "type": "checkbox",
          "id": "show_dynamic_checkout",
          "default": true,
          "label": "t:sections.main-product.blocks.buy_buttons.settings.show_dynamic_checkout.label",
          "info": "t:sections.main-product.blocks.buy_buttons.settings.show_dynamic_checkout.info"
        }
      ]
    },
    {
      "type": "description",
      "name": "t:sections.main-product.blocks.description.name",
      "limit": 1
    },
    {
      "type": "share",
      "name": "t:sections.main-product.blocks.share.name",
      "limit": 1,
      "settings": [
        {
          "type": "text",
          "id": "share_label",
          "label": "t:sections.main-product.blocks.share.settings.text.label",
          "default": "Share"
        },
        {
          "type": "paragraph",
          "content": "t:sections.main-product.blocks.share.settings.featured_image_info.content"
        },
        {
          "type": "paragraph",
          "content": "t:sections.main-product.blocks.share.settings.title_info.content"
        }
      ]
    },
    {
      "type": "custom_liquid",
      "name": "t:sections.main-product.blocks.custom_liquid.name",
      "settings": [
        {
          "type": "liquid",
          "id": "custom_liquid",
          "label": "t:sections.main-product.blocks.custom_liquid.settings.custom_liquid.label",
          "info": "t:sections.main-product.blocks.custom_liquid.settings.custom_liquid.info"
        }
      ]
    },
    {
      "type": "collapsible_tab",
      "name": "t:sections.main-product.blocks.collapsible_tab.name",
      "settings": [
        {
          "type": "text",
          "id": "heading",
          "default": "Collapsible tab",
          "info": "t:sections.main-product.blocks.collapsible_tab.settings.heading.info",
          "label": "t:sections.main-product.blocks.collapsible_tab.settings.heading.label"
        },
        {
          "type": "richtext",
          "id": "content",
          "label": "t:sections.main-product.blocks.collapsible_tab.settings.content.label"
        },
        {
          "type": "page",
          "id": "page",
          "label": "t:sections.main-product.blocks.collapsible_tab.settings.page.label"
        },
        {
          "type": "select",
          "id": "icon",
          "options": [
            {
              "value": "none",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__1.label"
            },
            {
              "value": "box",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__2.label"
            },
            {
              "value": "chat_bubble",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__3.label"
            },
            {
              "value": "check_mark",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__4.label"
            },
            {
              "value": "dryer",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__5.label"
            },
            {
              "value": "eye",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__6.label"
            },
            {
              "value": "heart",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__7.label"
            },
            {
              "value": "iron",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__8.label"
            },
            {
              "value": "leaf",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__9.label"
            },
            {
              "value": "leather",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__10.label"
            },
            {
              "value": "lock",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__11.label"
            },
            {
              "value": "map_pin",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__12.label"
            },
            {
              "value": "pants",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__13.label"
            },
            {
              "value": "plane",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__14.label"
            },
            {
              "value": "price_tag",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__15.label"
            },
            {
              "value": "question_mark",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__16.label"
            },
            {
              "value": "return",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__17.label"
            },
            {
              "value": "ruler",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__18.label"
            },
            {
              "value": "shirt",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__19.label"
            },
            {
              "value": "shoe",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__20.label"
            },
            {
              "value": "silhouette",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__21.label"
            },
            {
              "value": "star",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__22.label"
            },
            {
              "value": "truck",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__23.label"
            },
            {
              "value": "washing",
              "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.options__24.label"
            }
          ],
          "default": "check_mark",
          "label": "t:sections.main-product.blocks.collapsible_tab.settings.icon.label"
        }
      ]
    },
    {
      "type": "popup",
      "name": "t:sections.main-product.blocks.popup.name",
      "settings": [
        {
          "type": "text",
          "id": "text",
          "default": "Pop-up link text",
          "label": "t:sections.main-product.blocks.popup.settings.link_label.label"
        },
        {
          "id": "page",
          "type": "page",
          "label": "t:sections.main-product.blocks.popup.settings.page.label"
        }
      ]
    },
    {
      "type": "rating",
      "name": "t:sections.main-product.blocks.rating.name",
      "limit": 1,
      "settings": [
        {
          "type": "paragraph",
          "content": "t:sections.main-product.blocks.rating.settings.paragraph.content"
        }
      ]
    }
  ],
  "settings": [
    {
      "type": "checkbox",
      "id": "enable_sticky_info",
      "default": true,
      "label": "t:sections.main-product.settings.enable_sticky_info.label"
    },
    {
      "type": "header",
      "content": "t:sections.main-product.settings.header.content",
      "info": "t:sections.main-product.settings.header.info"
    },
    {
      "type": "checkbox",
      "id": "hide_variants",
      "default": false,
      "label": "t:sections.main-product.settings.hide_variants.label"
    },
    {
      "type": "checkbox",
      "id": "enable_video_looping",
      "default": false,
      "label": "t:sections.main-product.settings.enable_video_looping.label"
    }
  ]
}
{% endschema %}

 

 .slider-container {
margin: 0 1rem;
width: 100%;
overflow: auto;
display: flex;
flex-flow: column wrap;
align-items: center;
position: relative;
}

.large-image {
width: 100%;
padding-bottom: 100%;
position: relative;
}

.large-image-item {
position: absolute;
max-width: 100%;
min-width: 50%;
max-height: 100%;
padding: 0;
}

.large-image-item:not(:first-child){
display: none;
}

ul {
padding-inline-start: 0px !important;
}

slider-component {
position: relative;
display: block;
width:100%;
}

.slider__slide {
scroll-snap-align: start;
flex-shrink: 0;
}

.product-slider-box {
flex-wrap: inherit;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
margin-bottom: 1rem;
width: 100%;
display: flex;
}

.product-slider {
height: 100%;
width: 23%;
display: inline-block;
}

.product-slider:not(:first-child){
margin-left: 1rem;
}

.slide-image {
width: 100%;
height: 100%;
object-fit: cover;
}



/* ===ORIGINAL CODE =======

slider-component {
  position: relative;
  display: block;
}

@media screen and (max-width: 989px) {
  .no-js slider-component .slider {
    padding-bottom: 3rem;
  }
}

.slider__slide {
  scroll-snap-align: start;
  flex-shrink: 0;
}

@media screen and (max-width: 749px) {
  .slider.slider--mobile {
    position: relative;
    flex-wrap: inherit;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scroll-padding-left: 1rem;
    -webkit-overflow-scrolling: touch;
    margin-bottom: 1rem;
  }

  .slider.slider--mobile .slider__slide {
    margin-bottom: 0;
    padding-bottom: 0;
  }
}

@media screen and (max-width: 989px) {
  .slider.slider--tablet {
    position: relative;
    flex-wrap: inherit;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scroll-padding-left: 1rem;
    -webkit-overflow-scrolling: touch;
    margin-bottom: 1rem;
  }

  .slider.slider--tablet .slider__slide {
    margin-bottom: 0;
    padding-bottom: 0;
  }
}

/* Scrollbar */

.slider {
  scrollbar-color: rgb(var(--color-foreground)) rgba(var(--color-foreground), 0.04);
  -ms-overflow-style: none;
  scrollbar-width: none;
}

.slider::-webkit-scrollbar {
  height: 0.4rem;
  width: 0.4rem;
  display: none;
}

.no-js .slider {
  -ms-overflow-style: auto;
  scrollbar-width: auto;
}

.no-js .slider::-webkit-scrollbar {
  display: initial;
}

.slider::-webkit-scrollbar-thumb {
  background-color: rgb(var(--color-foreground));
  border-radius: 0.4rem;
  border: 0;
}

.slider::-webkit-scrollbar-track {
  background: rgba(var(--color-foreground), 0.04);
  border-radius: 0.4rem;
}

.slider-counter {
  margin: 0 1.2rem;
}

.slider-buttons {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* =====ORIGINAL CODE=====
@media screen and (min-width: 990px) {
  .slider-buttons {
    display: none;
  }
}

@media screen and (min-width: 750px) {
  .slider--mobile + .slider-buttons {
    display: none;
  }
} */

.slider-button {
  color: rgba(var(--color-foreground), 0.75);
  background: transparent;
  border: none;
  cursor: pointer;
  width: 44px;
  height: 44px;
}

.slider-button:not([disabled]):hover {
  color: rgb(var(--color-foreground));
}

.slider-button .icon {
  height: 0.6rem;
}

.slider-button[disabled] .icon {
  color: rgba(var(--color-foreground), 0.3);
}

.slider-button--next .icon {
  margin-right: -0.2rem;
  transform: rotate(-90deg) translateX(0.15rem);
}

.slider-button--prev .icon {
  margin-left: -0.2rem;
  transform: rotate(90deg) translateX(-0.15rem);
}

.slider-button--next:not([disabled]):hover .icon {
  transform: rotate(-90deg) translateX(0.15rem) scale(1.07);
}

.slider-button--prev:not([disabled]):hover .icon {
  transform: rotate(90deg) translateX(-0.15rem) scale(1.07);
}

 

function getFocusableElements(container) {
  return Array.from(
    container.querySelectorAll(
      "summary, a[href], button:enabled, [tabindex]:not([tabindex^='-']), [draggable], area, input:not([type=hidden]):enabled, select:enabled, textarea:enabled, object, iframe"
    )
  );
}

const trapFocusHandlers = {};

function trapFocus(container, elementToFocus = container) {
  var elements = getFocusableElements(container);
  var first = elements[0];
  var last = elements[elements.length - 1];

  removeTrapFocus();

  trapFocusHandlers.focusin = (event) => {
    if (
      event.target !== container &&
      event.target !== last &&
      event.target !== first
    )
      return;

    document.addEventListener('keydown', trapFocusHandlers.keydown);
  };

  trapFocusHandlers.focusout = function() {
    document.removeEventListener('keydown', trapFocusHandlers.keydown);
  };

  trapFocusHandlers.keydown = function(event) {
    if (event.code.toUpperCase() !== 'TAB') return; // If not TAB key
    // On the last focusable element and tab forward, focus the first element.
    if (event.target === last && !event.shiftKey) {
      event.preventDefault();
      first.focus();
    }

    //  On the first focusable element and tab backward, focus the last element.
    if (
      (event.target === container || event.target === first) &&
      event.shiftKey
    ) {
      event.preventDefault();
      last.focus();
    }
  };

  document.addEventListener('focusout', trapFocusHandlers.focusout);
  document.addEventListener('focusin', trapFocusHandlers.focusin);

  elementToFocus.focus();
}

// Here run the querySelector to figure out if the browser supports :focus-visible or not and run code based on it.
try {
  document.querySelector(":focus-visible");
} catch {
  focusVisiblePolyfill();
}

function focusVisiblePolyfill() {
  const navKeys = ['ARROWUP', 'ARROWDOWN', 'ARROWLEFT', 'ARROWRIGHT', 'TAB', 'ENTER', 'SPACE', 'ESCAPE', 'HOME', 'END', 'PAGEUP', 'PAGEDOWN']
  let currentFocusedElement = null;
  let mouseClick = null;

  window.addEventListener('keydown', (event) => {
    if(navKeys.includes(event.code.toUpperCase())) {
      mouseClick = false;
    }
  });

  window.addEventListener('mousedown', (event) => {
    mouseClick = true;
  });

  window.addEventListener('focus', () => {
    if (currentFocusedElement) currentFocusedElement.classList.remove('focused');

    if (mouseClick) return;

    currentFocusedElement = document.activeElement;
    currentFocusedElement.classList.add('focused');

  }, true);
}

function pauseAllMedia() {
  document.querySelectorAll('.js-youtube').forEach((video) => {
    video.contentWindow.postMessage('{"event":"command","func":"' + 'pauseVideo' + '","args":""}', '*');
  });
  document.querySelectorAll('.js-vimeo').forEach((video) => {
    video.contentWindow.postMessage('{"method":"pause"}', '*');
  });
  document.querySelectorAll('video').forEach((video) => video.pause());
  document.querySelectorAll('product-model').forEach((model) => {
    if (model.modelViewerUI) modelViewerUI.pause();
  });
}

function removeTrapFocus(elementToFocus = null) {
  document.removeEventListener('focusin', trapFocusHandlers.focusin);
  document.removeEventListener('focusout', trapFocusHandlers.focusout);
  document.removeEventListener('keydown', trapFocusHandlers.keydown);

  if (elementToFocus) elementToFocus.focus();
}

function onKeyUpEscape(event) {
  if (event.code.toUpperCase() !== 'ESCAPE') return;

  const openDetailsElement = event.target.closest('details[open]');
  if (!openDetailsElement) return;

  const summaryElement = openDetailsElement.querySelector('summary');
  openDetailsElement.removeAttribute('open');
  summaryElement.focus();
}

class QuantityInput extends HTMLElement {
  constructor() {
    super();
    this.input = this.querySelector('input');
    this.changeEvent = new Event('change', { bubbles: true })

    this.querySelectorAll('button').forEach(
      (button) => button.addEventListener('click', this.onButtonClick.bind(this))
    );
  }

  onButtonClick(event) {
    event.preventDefault();
    const previousValue = this.input.value;

    event.target.name === 'plus' ? this.input.stepUp() : this.input.stepDown();
    if (previousValue !== this.input.value) this.input.dispatchEvent(this.changeEvent);
  }
}

customElements.define('quantity-input', QuantityInput);

function debounce(fn, wait) {
  let t;
  return (...args) => {
    clearTimeout(t);
    t = setTimeout(() => fn.apply(this, args), wait);
  };
}

const serializeForm = form => {
  const obj = {};
  const formData = new FormData(form);

  for (const key of formData.keys()) {
    const regex = /(?:^(properties\[))(.*?)(?:\]$)/;

    if (regex.test(key)) { 
      obj.properties = obj.properties || {};
      obj.properties[regex.exec(key)[2]] = formData.get(key);
    } else {
      obj[key] = formData.get(key);
    }
  }

  return JSON.stringify(obj);
};

function fetchConfig(type = 'json') {
  return {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Accept': `application/${type}` }
  };
}

/*
 * Shopify Common JS
 *
 */
if ((typeof window.Shopify) == 'undefined') {
  window.Shopify = {};
}

Shopify.bind = function(fn, scope) {
  return function() {
    return fn.apply(scope, arguments);
  }
};

Shopify.setSelectorByValue = function(selector, value) {
  for (var i = 0, count = selector.options.length; i < count; i++) {
    var option = selector.options[i];
    if (value == option.value || value == option.innerHTML) {
      selector.selectedIndex = i;
      return i;
    }
  }
};

Shopify.addListener = function(target, eventName, callback) {
  target.addEventListener ? target.addEventListener(eventName, callback, false) : target.attachEvent('on'+eventName, callback);
};

Shopify.postLink = function(path, options) {
  options = options || {};
  var method = options['method'] || 'post';
  var params = options['parameters'] || {};

  var form = document.createElement("form");
  form.setAttribute("method", method);
  form.setAttribute("action", path);

  for(var key in params) {
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("type", "hidden");
    hiddenField.setAttribute("name", key);
    hiddenField.setAttribute("value", params[key]);
    form.appendChild(hiddenField);
  }
  document.body.appendChild(form);
  form.submit();
  document.body.removeChild(form);
};

Shopify.CountryProvinceSelector = function(country_domid, province_domid, options) {
  this.countryEl         = document.getElementById(country_domid);
  this.provinceEl        = document.getElementById(province_domid);
  this.provinceContainer = document.getElementById(options['hideElement'] || province_domid);

  Shopify.addListener(this.countryEl, 'change', Shopify.bind(this.countryHandler,this));

  this.initCountry();
  this.initProvince();
};

Shopify.CountryProvinceSelector.prototype = {
  initCountry: function() {
    var value = this.countryEl.getAttribute('data-default');
    Shopify.setSelectorByValue(this.countryEl, value);
    this.countryHandler();
  },

  initProvince: function() {
    var value = this.provinceEl.getAttribute('data-default');
    if (value && this.provinceEl.options.length > 0) {
      Shopify.setSelectorByValue(this.provinceEl, value);
    }
  },

  countryHandler: function(e) {
    var opt       = this.countryEl.options[this.countryEl.selectedIndex];
    var raw       = opt.getAttribute('data-provinces');
    var provinces = JSON.parse(raw);

    this.clearOptions(this.provinceEl);
    if (provinces && provinces.length == 0) {
      this.provinceContainer.style.display = 'none';
    } else {
      for (var i = 0; i < provinces.length; i++) {
        var opt = document.createElement('option');
        opt.value = provinces[i][0];
        opt.innerHTML = provinces[i][1];
        this.provinceEl.appendChild(opt);
      }

      this.provinceContainer.style.display = "";
    }
  },

  clearOptions: function(selector) {
    while (selector.firstChild) {
      selector.removeChild(selector.firstChild);
    }
  },

  setOptions: function(selector, values) {
    for (var i = 0, count = values.length; i < values.length; i++) {
      var opt = document.createElement('option');
      opt.value = values[i];
      opt.innerHTML = values[i];
      selector.appendChild(opt);
    }
  }
};

class MenuDrawer extends HTMLElement {
  constructor() {
    super();

    this.mainDetailsToggle = this.querySelector('details');
    const summaryElements = this.querySelectorAll('summary');
    this.addAccessibilityAttributes(summaryElements);

    if (navigator.platform === 'iPhone') document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`);

    this.addEventListener('keyup', this.onKeyUp.bind(this));
    this.addEventListener('focusout', this.onFocusOut.bind(this));
    this.bindEvents();
  }

  bindEvents() {
    this.querySelectorAll('summary').forEach(summary => summary.addEventListener('click', this.onSummaryClick.bind(this)));
    this.querySelectorAll('button').forEach(button => button.addEventListener('click', this.onCloseButtonClick.bind(this)));
  }

  addAccessibilityAttributes(summaryElements) {
    summaryElements.forEach(element => {
      element.setAttribute('role', 'button');
      element.setAttribute('aria-expanded', false);
      element.setAttribute('aria-controls', element.nextElementSibling.id);
    });
  }

  onKeyUp(event) {
    if(event.code.toUpperCase() !== 'ESCAPE') return;

    const openDetailsElement = event.target.closest('details[open]');
    if(!openDetailsElement) return;

    openDetailsElement === this.mainDetailsToggle ? this.closeMenuDrawer(this.mainDetailsToggle.querySelector('summary')) : this.closeSubmenu(openDetailsElement);
  }

  onSummaryClick(event) {
    const summaryElement = event.currentTarget;
    const detailsElement = summaryElement.parentNode;
    const isOpen = detailsElement.hasAttribute('open');

    if (detailsElement === this.mainDetailsToggle) {
      if(isOpen) event.preventDefault();
      isOpen ? this.closeMenuDrawer(summaryElement) : this.openMenuDrawer(summaryElement);
    } else {
      trapFocus(summaryElement.nextElementSibling, detailsElement.querySelector('button'));

      setTimeout(() => {
        detailsElement.classList.add('menu-opening');
      });
    }
  }

  openMenuDrawer(summaryElement) {
    setTimeout(() => {
      this.mainDetailsToggle.classList.add('menu-opening');
    });
    summaryElement.setAttribute('aria-expanded', true);
    trapFocus(this.mainDetailsToggle, summaryElement);
    document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
  }

  closeMenuDrawer(event, elementToFocus = false) {
    if (event !== undefined) {
      this.mainDetailsToggle.classList.remove('menu-opening');
      this.mainDetailsToggle.querySelectorAll('details').forEach(details =>  {
        details.removeAttribute('open');
        details.classList.remove('menu-opening');
      });
      this.mainDetailsToggle.querySelector('summary').setAttribute('aria-expanded', false);
      document.body.classList.remove(`overflow-hidden-${this.dataset.breakpoint}`);
      removeTrapFocus(elementToFocus);
      this.closeAnimation(this.mainDetailsToggle);
    }
  }

  onFocusOut(event) {
    setTimeout(() => {
      if (this.mainDetailsToggle.hasAttribute('open') && !this.mainDetailsToggle.contains(document.activeElement)) this.closeMenuDrawer();
    });
  }

  onCloseButtonClick(event) {
    const detailsElement = event.currentTarget.closest('details');
    this.closeSubmenu(detailsElement);
  }

  closeSubmenu(detailsElement) {
    detailsElement.classList.remove('menu-opening');
    removeTrapFocus();
    this.closeAnimation(detailsElement);
  }

  closeAnimation(detailsElement) {
    let animationStart;

    const handleAnimation = (time) => {
      if (animationStart === undefined) {
        animationStart = time;
      }

      const elapsedTime = time - animationStart;

      if (elapsedTime < 400) {
        window.requestAnimationFrame(handleAnimation);
      } else {
        detailsElement.removeAttribute('open');
        if (detailsElement.closest('details[open]')) {
          trapFocus(detailsElement.closest('details[open]'), detailsElement.querySelector('summary'));
        }
      }
    }

    window.requestAnimationFrame(handleAnimation);
  }
}

customElements.define('menu-drawer', MenuDrawer);

class HeaderDrawer extends MenuDrawer {
  constructor() {
    super();
  }

  openMenuDrawer(summaryElement) {
    this.header = this.header || document.getElementById('shopify-section-header');
    this.borderOffset = this.borderOffset || this.closest('.header-wrapper').classList.contains('header-wrapper--border-bottom') ? 1 : 0;
    document.documentElement.style.setProperty('--header-bottom-position', `${parseInt(this.header.getBoundingClientRect().bottom - this.borderOffset)}px`);

    setTimeout(() => {
      this.mainDetailsToggle.classList.add('menu-opening');
    });

    summaryElement.setAttribute('aria-expanded', true);
    trapFocus(this.mainDetailsToggle, summaryElement);
    document.body.classList.add(`overflow-hidden-${this.dataset.breakpoint}`);
  }
}

customElements.define('header-drawer', HeaderDrawer);

class ModalDialog extends HTMLElement {
  constructor() {
    super();
    this.querySelector('[id^="ModalClose-"]').addEventListener(
      'click',
      this.hide.bind(this)
    );
    this.addEventListener('keyup', (event) => {
      if (event.code.toUpperCase() === 'ESCAPE') this.hide();
    });
    if (this.classList.contains('media-modal')) {
      this.addEventListener('pointerup', (event) => {
        if (event.pointerType === 'mouse' && !event.target.closest('deferred-media, product-model')) this.hide();
      });
    } else {
      this.addEventListener('click', (event) => {
        if (event.target.nodeName === 'MODAL-DIALOG') this.hide();
      });
    }
  }

  show(opener) {
    this.openedBy = opener;
    const popup = this.querySelector('.template-popup');
    document.body.classList.add('overflow-hidden');
    this.setAttribute('open', '');
    if (popup) popup.loadContent();
    trapFocus(this, this.querySelector('[role="dialog"]'));
  }

  hide() {
    document.body.classList.remove('overflow-hidden');
    this.removeAttribute('open');
    removeTrapFocus(this.openedBy);
    window.pauseAllMedia();
  }
}
customElements.define('modal-dialog', ModalDialog);

class ModalOpener extends HTMLElement {
  constructor() {
    super();

    const button = this.querySelector('button');

    if (!button) return;
    button.addEventListener('click', () => {
      const modal = document.querySelector(this.getAttribute('data-modal'));
      if (modal) modal.show(button);
    });
  }
}
customElements.define('modal-opener', ModalOpener);

class DeferredMedia extends HTMLElement {
  constructor() {
    super();
    const poster = this.querySelector('[id^="Deferred-Poster-"]');
    if (!poster) return;
    poster.addEventListener('click', this.loadContent.bind(this));
  }

  loadContent() {
    window.pauseAllMedia();
    if (!this.getAttribute('loaded')) {
      const content = document.createElement('div');
      content.appendChild(this.querySelector('template').content.firstElementChild.cloneNode(true));

      this.setAttribute('loaded', true);
      this.appendChild(content.querySelector('video, model-viewer, iframe')).focus();
    }
  }
}

customElements.define('deferred-media', DeferredMedia);

class SliderComponent extends HTMLElement {
  constructor() {
    super();
    this.slider = this.querySelector('ul');
    this.sliderItems = this.querySelectorAll('li');
    this.pageCount = this.querySelector('.slider-counter--current');
    this.pageTotal = this.querySelector('.slider-counter--total');
    this.prevButton = this.querySelector('button[name="previous"]');
    this.nextButton = this.querySelector('button[name="next"]');

    if (!this.slider || !this.nextButton) return;

    const resizeObserver = new ResizeObserver(entries => this.initPages());
    resizeObserver.observe(this.slider);

    this.slider.addEventListener('scroll', this.update.bind(this));
    this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
    this.nextButton.addEventListener('click', this.onButtonClick.bind(this));
  }

  initPages() {
    const sliderItemsToShow = Array.from(this.sliderItems).filter(element => element.clientWidth > 0);
    this.sliderLastItem = sliderItemsToShow[sliderItemsToShow.length - 1];
    if (sliderItemsToShow.length === 0) return;
    this.slidesPerPage = Math.floor(this.slider.clientWidth / sliderItemsToShow[0].clientWidth);
    this.totalPages = sliderItemsToShow.length - this.slidesPerPage + 3;
    this.update();
  }

  update() {
    if (!this.pageCount || !this.pageTotal) return;
    this.currentPage = Math.round(this.slider.scrollLeft / this.sliderLastItem.clientWidth) + 4;

    if (this.currentPage === 1) {
      this.prevButton.setAttribute('disabled', true);
    } else {
      this.prevButton.removeAttribute('disabled');
    }

    if (this.currentPage === this.totalPages) {
      this.nextButton.setAttribute('disabled', true);
    } else {
      this.nextButton.removeAttribute('disabled');
    }

    this.pageCount.textContent = this.currentPage;
    this.pageTotal.textContent = this.totalPages;
  }

  onButtonClick(event) {
    event.preventDefault();
    const slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + this.sliderLastItem.clientWidth : this.slider.scrollLeft - this.sliderLastItem.clientWidth;
    this.slider.scrollTo({
      left: slideScrollPosition
    });
  }
}

customElements.define('slider-component', SliderComponent);

class VariantSelects extends HTMLElement {
  constructor() {
    super();
    this.addEventListener('change', this.onVariantChange);
  }

  onVariantChange() {
    this.updateOptions();
    this.updateMasterId();
    this.toggleAddButton(true, '', false);
    this.updatePickupAvailability();
    this.removeErrorMessage();

    if (!this.currentVariant) {
      this.toggleAddButton(true, '', true);
      this.setUnavailable();
    } else {
      this.updateMedia();
      this.updateURL();
      this.updateVariantInput();
      this.renderProductInfo();
    }
  }

  updateOptions() {
    this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
  }

  updateMasterId() {
    this.currentVariant = this.getVariantData().find((variant) => {
      return !variant.options.map((option, index) => {
        return this.options[index] === option;
      }).includes(false);
    });
  }

  updateMedia() {
    if (!this.currentVariant) return;
    if (!this.currentVariant.featured_media) return;
    const newMedia = document.querySelector(
      `[data-media-id="${this.dataset.section}-${this.currentVariant.featured_media.id}"]`
    );

    if (!newMedia) return;
    const modalContent = document.querySelector(`#ProductModal-${this.dataset.section} .product-media-modal__content`);
    const newMediaModal = modalContent.querySelector( `[data-media-id="${this.currentVariant.featured_media.id}"]`);
    const parent = newMedia.parentElement;
    if (parent.firstChild == newMedia) return;
    modalContent.prepend(newMediaModal);
    parent.prepend(newMedia);
    this.stickyHeader = this.stickyHeader || document.querySelector('sticky-header');
    if(this.stickyHeader) {
      this.stickyHeader.dispatchEvent(new Event('preventHeaderReveal'));
    }
    window.setTimeout(() => { parent.querySelector('li.product__media-item').scrollIntoView({behavior: "smooth"}); });
  }

  updateURL() {
    if (!this.currentVariant || this.dataset.updateUrl === 'false') return;
    window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
  }

  updateVariantInput() {
    const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
    productForms.forEach((productForm) => {
      const input = productForm.querySelector('input[name="id"]');
      input.value = this.currentVariant.id;
      input.dispatchEvent(new Event('change', { bubbles: true }));
    });
  }

  updatePickupAvailability() {
    const pickUpAvailability = document.querySelector('pickup-availability');
    if (!pickUpAvailability) return;

    if (this.currentVariant && this.currentVariant.available) {
      pickUpAvailability.fetchAvailability(this.currentVariant.id);
    } else {
      pickUpAvailability.removeAttribute('available');
      pickUpAvailability.innerHTML = '';
    }
  }

  removeErrorMessage() {
    const section = this.closest('section');
    if (!section) return;

    const productForm = section.querySelector('product-form');
    if (productForm) productForm.handleErrorMessage();
  }

  renderProductInfo() {
    fetch(`${this.dataset.url}?variant=${this.currentVariant.id}&section_id=${this.dataset.section}`)
      .then((response) => response.text())
      .then((responseText) => {
        const id = `price-${this.dataset.section}`;
        const html = new DOMParser().parseFromString(responseText, 'text/html')
        const destination = document.getElementById(id);
        const source = html.getElementById(id);

        if (source && destination) destination.innerHTML = source.innerHTML;

        const price = document.getElementById(`price-${this.dataset.section}`);

        if (price) price.classList.remove('visibility-hidden');
        this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
      });
  }

  toggleAddButton(disable = true, text, modifyClass = true) {
    const productForm = document.getElementById(`product-form-${this.dataset.section}`);
    if (!productForm) return;
    const addButton = productForm.querySelector('[name="add"]');

    if (!addButton) return;

    if (disable) {
      addButton.setAttribute('disabled', true);
      if (text) addButton.textContent = text;
    } else {
      addButton.removeAttribute('disabled');
      addButton.textContent = window.variantStrings.addToCart;
    }

    if (!modifyClass) return;
  }

  setUnavailable() {
    const button = document.getElementById(`product-form-${this.dataset.section}`);
    const addButton = button.querySelector('[name="add"]');
    const price = document.getElementById(`price-${this.dataset.section}`);
    if (!addButton) return;
    addButton.textContent = window.variantStrings.unavailable;
    if (price) price.classList.add('visibility-hidden');
  }

  getVariantData() {
    this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
    return this.variantData;
  }
}

customElements.define('variant-selects', VariantSelects);

class VariantRadios extends VariantSelects {
  constructor() {
    super();
  }

  updateOptions() {
    const fieldsets = Array.from(this.querySelectorAll('fieldset'));
    this.options = fieldsets.map((fieldset) => {
      return Array.from(fieldset.querySelectorAll('input')).find((radio) => radio.checked).value;
    });
  }
}

customElements.define('variant-radios', VariantRadios);

 

 

sapiens_sapiens
Shopify Partner
19 0 2

Hi, I am building my first shop and would like to add a collection slider to the homepage. Could u tell me if this code can be adapted to Dawn 9.0? How can I achieve that?
Thank you in advance

shadowsfall118
Shopify Partner
125 13 37

@sapiens_sapiens this is already built into Dawn 9.0. Go to theme editor and add the Featured Collection Block and make sure to increase the maximum products to show to something like 10 and make sure to click enable carousel on desktop. Is that what you're looking for?

 

Screenshot 2023-06-01 at 12.15.19 PM.pngScreenshot 2023-06-01 at 12.15.15 PM.png

sapiens_sapiens
Shopify Partner
19 0 2

Thx for replying. My goal is to have a collection list slider, while featured collection displays products, not the available collections. How can I achieve that?

shadowsfall118
Shopify Partner
125 13 37

@sapiens_sapiens Try this.

 

  1. Add the "Collection list" block.
  2. Increase Number of columns on desktop to 5.
  3. Change Mobile layout to 2 columns and enable swipe on mobile.
  4. Add the below CSS into the CUSTOM CSS.
  5. Fill in the desired collections.
.collection-list-wrapper > slider-component > .slider-buttons {
  display: flex;
}
.collection-list-wrapper > slider-component > .slider.slider--tablet {
  position: relative;
  flex-wrap: inherit;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scroll-padding-left: 1.5rem;
  -webkit-overflow-scrolling: touch;
  margin-bottom: 1rem;
}

 

Hope that helps!

sapiens_sapiens
Shopify Partner
19 0 2

Great, thanks. My goal is to enable desktop slider too, like in featured collection. Could you tell me how to do it?

shadowsfall118
Shopify Partner
125 13 37

@sapiens_sapiens If you follow my instructions this works on Dawn 9.0 theme. I tested as you can see below:

 

Screenshot 2023-06-02 at 10.33.38 AM.png

Otherwise you may have some CSS overriding it. If you install a fresh dawn theme and test it should work fine.

sapiens_sapiens
Shopify Partner
19 0 2

Thank u

StewartM
Shopify Partner
5 0 1

 

Thanks @shadowsfall118 for also looking into it. 

 

I posted my code on here but it got flagged as potential spam so that was useful - i dont know if you were able to save it before it was removed - so @made4Uo i tried to replace the code you posted with what i had but it is the same outcome. I also tried to do the walkthrough once again just in case i missed something - but still got the same result, no large image, some thumbnails and no slider activity. I have tried it over 10 times now with the same outcome sadly so i have to come to the conclusion there is something wrong 😞 

 

Hopefully this dropbox link might work...

https://www.dropbox.com/sh/3rxwwufxg5sn8rl/AAAlY82qoOXDtsGJHUY7ZFSMa?dl=0 

 

 

Thanks. 

 

 

 

 

made4Uo
Shopify Partner
3856 717 1197

Hi @StewartM  I fix it. Please check my website

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
made4Uo
Shopify Partner
3856 717 1197

I was able reproduce the problem. With my intention on mostly keeping the original Dawn code cause the elements to be hidden. Fixed code available in the website. Let me know if you still have issues

I just deleted the code following code in the large image

{%- assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' -%}
{%- if product.selected_or_first_available_variant.featured_media != null -%}
{%- assign media = product.selected_or_first_available_variant.featured_media -%}

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
made4Uo
Shopify Partner
3856 717 1197

@shadowsfall118  Thanks for posting the file. I was able to find the problem

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
made4Uo
Shopify Partner
3856 717 1197

Thank you for the like. Yes. That is the other way

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
shadowsfall118
Shopify Partner
125 13 37

Thanks @made4Uo for the slider!!!! I can confirm it's working.

Another addition to @made4Uo code is to hide the slider buttons if there is less than 4 images.

global.js inside the INT() function right after this.update(); add the following: 

const thumbCount = this.pageTotal.textContent;
if (thumbCount <= 4) {
document.getElementsByClassName('slider-buttons')[0].style.visibility = 'hidden';
} else {
document.getElementsByClassName('slider-buttons')[0].style.visibility = 'visible';
}
}
made4Uo
Shopify Partner
3856 717 1197

Thank you @shadowsfall118  never think of hiding the slider 😁

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
made4Uo
Shopify Partner
3856 717 1197

Hi @shadowsfall118 . You do not need to add javascript code. Just change the product.media.size < 5 in the slider-buttons so the "small-hide" get activated. See the bold code. I updated my code in the website too. Thank you again

 

<section class="page-width">
        <div class="product grid grid--1-col {% if product.media.size > 0 %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
          <div class="grid__item product__media-wrapper">
 
            <div class="slider-container" >
            <a class="skip-to-content-link button visually-hidden" href="#ProductInfo-{{ section.id }}">
            {{ "accessibility.skip_to_product_info" | t }}
            </a>
            <ul class="large-image" id="large-image">
                {%- for media in product.media -%}
 
                <li class="large-image-item product__media-item grid__item slider__slide
                    {% if media.media_type != 'image' %}
                    product__media-item--full{% endif %}"
                    data-media-id="{{ section.id }}-{{ media.id }}">
                    {% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true %}
                    </li>
                {%- endfor -%}
              
                </ul>
 
      <slider-component >
                <ul class="product-slider-box slider" role="list">
                    {%- for media in product.media -%}
                    <li class="product-slider slider__slide">
                        <img class="slide-image"
                        onclick="newLargeImage(this)"
                        data-thumb-id="{{ section.id }}-{{ media.id }}"
                        src="{{ media.preview_image | img_url: 'large', scale: 4 }}"
                        alt="{{ thumbnailAlt }}">
                    </li>
                {% endfor %}
                </ul>
          <div class="slider-buttons no-js-hidden{% if product.media.size < 2 %}
            small-hide{% endif %}">
            <button type="button" class="slider-button slider-button--prev bigger-slider" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
              <div class="slider-counter caption">
              <span class="slider-counter--current">1</span>
              <span aria-hidden="true"> / </span>
              <span class="visually-hidden">{{ 'accessibility.of' | t }}</span>
              <span class="slider-counter--total">{% if section.settings.hide_variants %}{{ product.media.size | minus: variant_images.size | plus: 1 }}{% else %}{{ product.media.size }}{% endif %}</span>
              </div>
            <button type="button" class="slider-button slider-button--next bigger-slider" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button>
          </div>
          </slider-component>
      </div>
If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
shadowsfall118
Shopify Partner
125 13 37

@made4Uo thanks for pointing this out. Although the "small-hide" css class does not seem to do anything on my vanilla (plain) shop. Maybe replace "small-hide" with "visually-hidden"?

OLD:

<div class="slider-buttons {% if product.media.size < 5 %}
small-hide{% endif %}">

 

NEW:

<div class="slider-buttons {% if product.media.size < 5 %}
visually-hidden{% endif %}">
made4Uo
Shopify Partner
3856 717 1197

@shadowsfall118 . If you go to the asset folder and open the base.css folder you see the visually hidden there (see below). This is not really what we want. I was able to find the small-hide and it only works in small screen. We can use 'hidden' instead. I updated my code in the website again. Code should look like this

<div class="slider-buttons {% if product.media.size < 5 %}hidden{% endif %}">

 

 

.visually-hidden {
position: absolute !important;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0 0 0 0);
word-wrap: normal !important;
}

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free
shadowsfall118
Shopify Partner
125 13 37

@made4Uo I think this line needs to be 4 not 3.

this.totalPages = sliderItemsToShow.length - this.slidesPerPage + 4;

 

I had a product with 5 images and the last was not showing / could not click the right arrow to reveal it.

made4Uo
Shopify Partner
3856 717 1197

You are right! Thank you

If this fixed your issue Likes and Accept as Solution is highly appreciated. Coffee tips fuels my dedication.
Get EXPERIENCED Shopify developers at affordable rates—visit Made4Uo.com for quick quote!
Do not lost your Shopify store! Get FREE trial with ✔️ Rewind Backup: Automatic, reliable, stress-free