Last active
July 28, 2024 23:35
-
-
Save josephbona/b300b9e81e3bc53e27493555ae6795c1 to your computer and use it in GitHub Desktop.
Dawn Product Gallery
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% comment %}theme-check-disable TemplateLength{% endcomment %} | |
{{ 'section-main-product.css' | asset_url | stylesheet_tag }} | |
{{ 'component-accordion.css' | asset_url | stylesheet_tag }} | |
{{ 'component-badge.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 }} | |
<link rel="stylesheet" href="{{ 'component-cart-notification.css' | asset_url }}" media="print" onload="this.media='all'"> | |
<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 src="{{ 'product-gallery.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"> | |
<product-gallery class="product-gallery"> | |
{%- if product.media.size > 1 -%} | |
<ul class="product-gallery__nav"> | |
{%- for media in product.media -%} | |
<li class="product-gallery__nav-item {% if media.id == product.selected_or_first_available_variant.featured_media.id %}product-gallery__nav-item--active{% endif %}" data-media-id="{{ media.id }}"> | |
{% render 'product-thumbnail', media: media, position: forloop.index, loop: section.settings.enable_video_looping, modal_id: section.id %} | |
</li> | |
{%- endfor -%} | |
</ul> | |
{%- endif -%} | |
<div class="product-gallery__images"> | |
{%- for media in product.media -%} | |
<div class="product-gallery__image {% if media.id == product.selected_or_first_available_variant.featured_media.id or product.media.size == 1 %}product-gallery__image--active{% endif %}" data-media-id="{{ media.id }}"> | |
{% render 'product-thumbnail', media: media %} | |
</div> | |
{%- endfor -%} | |
<button type="button" class="slider-button slider-button--prev" name="previous" aria-label="{{ 'accessibility.previous_slide' | t }}">{% render 'icon-caret' %}</button> | |
<button type="button" class="slider-button slider-button--next" name="next" aria-label="{{ 'accessibility.next_slide' | t }}">{% render 'icon-caret' %}</button> | |
</div> | |
</product-gallery> | |
</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 '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.link_label | default: block.settings.page.title }}</button> | |
</modal-opener> | |
<a href="{{ block.settings.page.url }}" class="product-popup-modal__button link no-js">{{ block.settings.link_label }}</a> | |
{%- when 'share' -%} | |
<share-button class="share-button" {{ block.shopify_attributes }}> | |
<button class="share-button__button button button--tertiary hidden"> | |
{% render 'icon-share' %} | |
{{ 'general.share.share' | t }} | |
</button> | |
<details> | |
<summary class="share-button__button button button--tertiary"> | |
{% render 'icon-share' %} | |
{{ 'general.share.share' | t }} | |
</summary> | |
<div class="share-button__fallback"> | |
<div class="field"> | |
<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="button button--tertiary"> | |
{% render 'icon-clipboard' %} | |
{{ 'general.share.copy_to_clipboard' | t }} | |
</button> | |
<span id="ShareMessage-{{ section.id }}" class="share-button__message hidden" role="status" aria-hidden="true"> | |
{{ 'general.share.success_message' | t }} | |
</span> | |
</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> | |
<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"> | |
{%- 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> | |
</div> | |
<div class="product__accordion accordion"> | |
<details> | |
<summary> | |
<div class="summary__title"> | |
{% render 'icon-accordion', icon: 'ruler' %} | |
<h2 class="h4 accordion__title"> | |
Size Guide | |
</h2> | |
</div> | |
{% render 'icon-caret' %} | |
</summary> | |
<div class="accordion__content rte"> | |
<div id="size-guide"></div> | |
</div> | |
</details> | |
</div> | |
<div class="product__accordion accordion"> | |
<details> | |
<summary> | |
<div class="summary__title"> | |
{% render 'icon-accordion', icon: 'price_tag' %} | |
<h2 class="h4 accordion__title"> | |
Materials & Care | |
</h2> | |
</div> | |
{% render 'icon-caret' %} | |
</summary> | |
<div class="accordion__content"> | |
{{ product.metafields.custom_fields.materials }} | |
</div> | |
</details> | |
</div> | |
{%- endcase -%} | |
{%- endfor -%} | |
</div> | |
</div> | |
</div> | |
{%- render 'cart-notification' -%} | |
{% 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.link_label }}" 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")}"]`); | |
activeMedia.classList.add('active'); | |
activeMedia.scrollIntoView(); | |
if (activeMedia.nodeName == 'DEFERRED-MEDIA' && activeMedia.querySelector('template')?.content?.querySelector('.js-youtube')) | |
activeMedia.loadContent(); | |
} | |
} | |
customElements.define('product-modal', ProductModal); | |
{% endjavascript %} | |
{%- 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 -%} | |
{% 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": "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": "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": "link_label", | |
"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" | |
} | |
] | |
} | |
], | |
"settings": [ | |
{ | |
"type": "header", | |
"content": "t:sections.main-product.settings.header.content", | |
"info": "t:sections.main-product.settings.header.info" | |
}, | |
{ | |
"type": "checkbox", | |
"id": "enable_sticky_info", | |
"default": true, | |
"label": "t:sections.main-product.settings.enable_sticky_info.label" | |
}, | |
{ | |
"type": "checkbox", | |
"id": "enable_video_looping", | |
"default": false, | |
"label": "t:sections.main-product.settings.enable_video_looping.label" | |
} | |
] | |
} | |
{% endschema %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ProductGallery extends HTMLElement { | |
constructor() { | |
super(); | |
this.init() | |
const resizeObserver = new ResizeObserver(entries => this.update()); | |
resizeObserver.observe(this); | |
this.navItems.forEach(item => item.addEventListener('click', this.onNavItemClick.bind(this))) | |
this.prevButton.addEventListener('click', this.onButtonClick.bind(this)); | |
this.nextButton.addEventListener('click', this.onButtonClick.bind(this)); | |
window.addEventListener('message', this.onVariantChange.bind(this)) | |
} | |
init() { | |
this.imagesContainer = this.querySelector('.product-gallery__images'); | |
this.navItems = this.querySelectorAll('.product-gallery__nav-item'); | |
this.images = this.querySelectorAll('.product-gallery__image'); | |
this.prevButton = this.querySelector('button[name="previous"]'); | |
this.nextButton = this.querySelector('button[name="next"]'); | |
if (this.findCurrentIndex() === -1) { | |
this.setCurrentImage(this.images[0]) | |
} | |
} | |
onVariantChange(event) { | |
if (!event.data || event.data.type !== 'variant_changed') return | |
const currentImage = Array.from(this.images).find(item => item.dataset.mediaId == event.data.variant.featured_media.id) | |
if (currentImage) { | |
this.setCurrentImage(currentImage) | |
} | |
} | |
onNavItemClick(event) { | |
const mediaId = event.target.closest('li').dataset.mediaId | |
this.images.forEach(item => item.classList.remove('product-gallery__image--active')) | |
this.setCurrentImage(Array.from(this.images).find(item => item.dataset.mediaId === mediaId)) | |
} | |
update() { | |
this.style.height = `${this.imagesContainer.offsetHeight}px` | |
this.prevButton.removeAttribute('disabled') | |
this.nextButton.removeAttribute('disabled') | |
if (this.findCurrentIndex() === 0) this.prevButton.setAttribute('disabled', true) | |
if (this.findCurrentIndex() === this.images.length - 1) this.nextButton.setAttribute('disabled', true) | |
} | |
setCurrentImage(elem) { | |
this.images.forEach(item => item.classList.remove('product-gallery__image--active')) | |
elem.classList.add('product-gallery__image--active') | |
this.update() | |
} | |
findCurrentIndex() { | |
return Array.from(this.images).findIndex(item => item.classList.contains('product-gallery__image--active')) | |
} | |
onButtonClick(event) { | |
event.preventDefault(); | |
let index = this.findCurrentIndex() | |
if (event.currentTarget.name === 'next') { | |
index++ | |
} else { | |
index-- | |
} | |
this.setCurrentImage(this.images[index]) | |
} | |
} | |
customElements.define('product-gallery', ProductGallery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.product-gallery { | |
display: flex; | |
} | |
.product-gallery .slider-button { | |
position: absolute; | |
top: 50%; | |
transform: translateY(-50%); | |
} | |
.product-gallery .slider-button:not([disabled]):hover { | |
border-color: rgba(var(--color-foreground), 0.3); | |
} | |
.product-gallery .slider-button:disabled { | |
display: none; | |
} | |
.product-gallery .slider-button--prev { | |
left: 0; | |
border-left-width: 0; | |
} | |
.product-gallery .slider-button--next { | |
right: 0; | |
border-right-width: 0; | |
} | |
.product-gallery__nav { | |
width: 140px; | |
list-style: none; | |
margin: 0 .5rem 0 0; | |
padding: 0; | |
height: 100%; | |
overflow-y: auto; | |
display: none; | |
} | |
.product-gallery__nav::-webkit-scrollbar { | |
display: none; | |
} | |
.product-gallery__nav-item { | |
display: block; | |
cursor: pointer; | |
} | |
.product-gallery__nav-item + .product-gallery__nav-item { | |
margin-top: .5rem; | |
} | |
.product-gallery__nav-item img { | |
width: 100%; | |
display: block; | |
} | |
.product-gallery__images { | |
flex-grow: 1; | |
height: fit-content; | |
position: relative; | |
} | |
.product-gallery__image { | |
display: none; | |
} | |
.product-gallery__image--active { | |
display: block; | |
} | |
@media screen and (min-width: 750px) { | |
.product-gallery__nav { | |
display: block; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment