Convert Dawn Product Page Like Debut Theme with Product Slider

{% if youLike === true %} Hit Subscribe {% endif %}

To veiw the code!
Don't have an account?

Do you Debut theme's product slider? Create a product page just like Debut theme. 

I have been working on Dawn theme product slider and had encounter some issues with it. One thing is the number counter does not make sense. My way around on creating a product slider in Dawn theme is copy the Debut theme. 

Have a Debut product page in your Dawn theme with working radio buttons, zoom, and product slider.

NOTE: You need to log-in before you can see the code. 

 

Follow the instructions below.

1. Go to your Online store > Themes > Actions > Edit code

2. Go to Section folder and open the main-product.liquid

3. To make things simple, we will replace the main-product.liquid

4. Go to section folder and open the main-product.liquid."

5. Delete the code inside the file, paste the code below

 {% 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 }}
{{ 'product-slider.css' | asset_url | stylesheet_tag }}
{{ 'component-rating.css' | asset_url | stylesheet_tag }}
{{ 'component-loading-overlay.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);
newImage.style.display = "block";

document.querySelectorAll('.slide-image')
.forEach(thumb => thumb. classList.remove('active-thumb'));
const sliderComp = document.querySelector("slider-component");
document.querySelector(`[data-thumb-id="${clickedImage}"] > img`).classList.add('active-thumb');
zoom();
}
window.setTimeout(() => {zoom()});
function zoom() {
const mediaSmall = window.matchMedia( '( min-width: 400px )' );
const imageZoom = document.querySelector('#large-image');
const zoomItem = document.querySelector("#large-image > li:nth-child(1)")
imageZoom.addEventListener("mouseout", function() {69
zoomItem.style.transform = 'scale(1)';
});
if (mediaSmall.matches) {
imageZoom.addEventListener("mouseover", function() {
zoomItem.style.transform = 'scale(1.8)';
});
imageZoom.addEventListener("mousemove", function(e) {
const itemWidth = zoomItem.getBoundingClientRect().width;
const itemLeft = zoomItem.getBoundingClientRect().left;
const itemHt = zoomItem.getBoundingClientRect().height;
const itemTop = zoomItem.getBoundingClientRect().top + window.scrollY;
const translateX = Math.round((e.pageX - itemLeft ) / itemWidth * 100);
const translateY = Math.round((e.pageY - itemTop) / itemHt * 100);
zoomItem.style.transformOrigin = `${translateX}% ${translateY}%`;
});
}
}
</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" data-scale="1.6">
{%- for media in product.media -%}
<li class="large-image-item product__media-item grid__item slider__slide
{% if media.media_type != 'image' %} hide-modal {% endif %}"
data-media-id="{{ section.id }}-{{ media.id }}"
data-background="zoom-image">
{% 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 class="slider-wrapper">
<ul class="product-slider-box slider" role="list">
{%- assign variant_images = product.images| where: 'attached_to_variant?', true | map: 'src' -%}
{%- for media in product.media -%}
<li class="product-slider slider__slide" onclick="newLargeImage(this)" data-thumb-id="{{ section.id }}-{{ media.id }}"
{% if section.settings.hide_variants and variant_images contains media.src %}
style="display: none;"
{% endif %} >
{% if media.media_type == 'video' %}
<div class="video-btn" style="display: block" >
<span class="product__media-icon motion-reduce v-btn" aria-hidden="true">
{%- liquid
case media.media_type
when 'video' or 'external_video'
render 'icon-play'
when 'model'
render 'icon-3d-model'
else
render 'icon-zoom'
endcase
-%}
</span>
<img class="slide-image {% if forloop.first %}active-thumb {% endif %}"
src="{{ media.preview_image | img_url: 'large' }}"
alt="{{ thumbnailAlt }}"
{% if section.settings.square_image == true %} style="aspect-ratio: 1;" {% endif %}>
</div>
{% else %}
<img class="slide-image {% if forloop.first %}active-thumb {% endif %}"
src="{{ media.preview_image | img_url: 'large' }}"
alt="{{ thumbnailAlt }}"
{% if section.settings.square_image == true %}style="aspect-ratio: 1;" {% endif %}>
{% endif %}
</li>
{% endfor %}
</ul>
<div class="button-wrapper {% if product.media.size < 3 %}hidden{% endif %}" >
<button type="button" class="slider-button slider-button--prev bigger-slider" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button>
<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 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 }}" role="status" {{ block.shopify_attributes }}>
{%- render 'price', product: product, use_variant: true, show_badges: true, price_class: 'price--large' -%}
</div>
{%- if shop.taxes_included or shop.shipping_policy.body != blank -%}
<div class="product__tax caption rte">
{%- if shop.taxes_included -%}
{{ 'products.product.include_taxes' | t }}
{%- endif -%}
{%- if shop.shipping_policy.body != blank -%}
{{ 'products.product.shipping_policy_html' | t: link: shop.shipping_policy.url }}
{%- endif -%}
</div>
{%- endif -%}
<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 id="Details-{{ block.id }}-{{ section.id }}">
<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" id="ProductAccordion-{{ block.id }}-{{ section.id }}">
{{ 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_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 id="Share-{{ section.id }}" class="share-button" {{ block.shopify_attributes }}>
<button class="share-button__button hidden">
{% render 'icon-share' %}
{{ block.settings.share_label | escape }}
</button>
<details id="Details-{{ block.id }}-{{ section.id }}">
<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="{{ product.selected_variant.url | default: product.url | prepend: shop.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.position }}-{{ forloop.index0 }}"
name="{{ option.name }}"
value="{{ value | escape }}"
form="{{ product_form_id }}"
{% if option.selected_value == value %}checked{% endif %}
>
<label for="{{ section.id }}-{{ option.position }}-{{ 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_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_id }}">
{%- 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 }}" disabled>
<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 %}
>
<span>
{%- if product.selected_or_first_available_variant.available -%}
{{ 'products.product.add_to_cart' | t }}
{%- else -%}
{{ 'products.product.sold_out' | t }}
{%- endif -%}
</span>
<div class="loading-overlay__spinner hidden">
<svg aria-hidden="true" focusable="false" role="presentation" class="spinner" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
<circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
</svg>
</div>
</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-root-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();
}

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 -%}

{%- liquid
if product.selected_or_first_available_variant.featured_media
assign seo_media = product.selected_or_first_available_variant.featured_media
else
assign seo_media = product.featured_media
endif
-%}

<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"url": {{ shop.url | append: product.url | json }},
{% if seo_media -%}
{%- assign media_size = seo_media.preview_image.width | append: 'x' -%}
"image": [
{{ seo_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"
},

{
"type": "checkbox",
"id": "square_image",
"default": false,
"label": "Make thumbnail images square"
}
]
}
{% endschema %}

 

6. Next, we need to create a new Asset file. Go to Asset folder, and click "Add a new asset." Make sure it is a CSS file. Name it "product-slider"

7. Open the file and paste the code below, then click SAVE

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

.large-image {
width: 100%;
height: 100%;
position: relative;
overflow:hidden;
}

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

.xoomImage {
position: absolute;
top: 0;
left: 0;
}

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

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

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

.slider-wrapper {
display: flex;
justify-content: center;
}

.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: 85%;
display: flex;
z-index: 1;
}

.product-slider {
height: 100%;
width: 31.5%;
padding: 10px;
display: inline-block;
}

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

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

.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;
}


/*=== buttons === */
.button-wrapper {
height: 100%;
width: 105%;
position: absolute;
display: flex;
justify-content: space-between;
align-items: center;
}

.slider-container::-webkit-scrollbar {
display: none;
}

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

.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: 1.2rem;
}

.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);
}

/* video button when image is a video type */
.video-btn {
width: 100%;
height: 100%;
position: relative;
}

.v-btn {
top: 2% !important;
left: 2% !important;
}

.active-thumb {
border: 3px solid white;
outline: 2px solid black;
}

/* ==== custom codes in editing the product page ==== */
@media screen and (min-width: 750px) {
.custom-width {
padding: 0 10% !important;
}
}

@media screen and (min-width: 990px) {
.product__media-wrapper {
max-width: 50% !important;
width: calc(50% - 1rem / 2);
}

.product__info-wrapper {
padding-left: 5rem !important;
max-width: 50% !important;
width: calc(50% - 1rem / 2);
}
}

/* hide modal */
#large-image > li:nth-child(1) > modal-opener > span {
display: none !important;
}

#large-image > li:nth-child(1) > modal-opener > button {
display: none !important;
}

#large-image > li > modal-opener > div {
padding-top: 0 !important;
}

#large-image > li > modal-opener > div > img {
overflow: hidden;
position: relative !important;
}

 

8. Next, we need to adjust the global.js file under the Asset folder.

9. We will adjust the slider first. Find the slider-component. After the " this.nextButton = this.querySelector('button[name="next"]');", paste the code below. See the image and video for reference.

 this.productSlider = this.querySelector('.product-slider-box');

Code should look like this.:

Product slider

10. Next, we need to find and replace the onButtonClick(event) function with the code below. Please make sure to check the video on this so you don't delete other stuff. 

 onButtonClick(event) {
event.preventDefault();

if (this.productSlider) {
const slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + (this.slider.clientWidth): this.slider.scrollLeft - (this.slider.clientWidth);
this.slider.scrollTo({
left: Math.floor(slideScrollPosition)
});

this.currSlide = Math.round(slideScrollPosition / this.slider.clientWidth);
if (this.currSlide === 0 ) {
this.prevButton.setAttribute('disabled', true);
} else {
this.prevButton.removeAttribute('disabled');
}
if (this.currSlide === this.totalPages / 3 ) {
this.nextButton.setAttribute('disabled', true);
} else {
this.nextButton.removeAttribute('disabled');
}
} else {
const slideScrollPosition = event.currentTarget.name === 'next' ? this.slider.scrollLeft + this.sliderLastItem.clientWidth : this.slider.scrollLeft - this.sliderLastItem.clientWidth;
this.slider.scrollTo({
left: Math.floor(slideScrollPosition)
});
}
}

Code should look like this:

12. Last one. Find the VariantSelects, and add the code under updateMedia(), before  "window.setTimeout(()". See image below, and video for instruction. 

const newId = newMedia.dataset.mediaId;
const newThumb = document.querySelector(`[data-thumb-id="${newId}"]`);
const thumbLocate = newThumb["offsetLeft"];

document.querySelectorAll('.slide-image').forEach(thumb => thumb. classList.remove('active-thumb'));
document.querySelector(`[data-thumb-id="${newId}"] > img`).classList.add('active-thumb');
const sliderBox = document.querySelector(".product-slider-box");
sliderBox.scrollTo({left: thumbLocate});
zoom(); 

 

global.js file

 That is it! I hope it was not too hard. If so, please follow the video. (",)

Update 11/08/21: Fix the issue in Mozilla with scrollbar showing. Just deleted the overflow CSS in slider-container. Added code to hide the buttons whenever the variant images is less than three. 

 

1 comentário

Hi, thank you for this tutorial. I cannot add product in the cart. Required parameter missing or invalid: items. On the YouTube comments, I did the whole steps again twice since you did some changes to the code for the global.js, and I still have the same problem. I tried without variant, and still the same issue. No apps installed yet to interfere. Thank you

Sandrine

Deixe um comentário