first commit
This commit is contained in:
@@ -0,0 +1,306 @@
|
|||||||
|
<!-- sections/predictive-search.liquid -->
|
||||||
|
<!-- yagor! -->
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
comment
|
||||||
|
Get each resource's result count
|
||||||
|
endcomment
|
||||||
|
assign query_count = predictive_search.resources.queries.size
|
||||||
|
assign product_count = predictive_search.resources.products.size
|
||||||
|
assign collection_count = predictive_search.resources.collections.size
|
||||||
|
assign article_count = predictive_search.resources.articles.size
|
||||||
|
assign page_count = predictive_search.resources.pages.size
|
||||||
|
assign collection_counter = 0
|
||||||
|
assign total_results_counter = 0
|
||||||
|
assign terms = predictive_search.terms
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- if collection_count > 0 -%}
|
||||||
|
{%- liquid
|
||||||
|
assign exclude_collections_strict = settings.exclude_collections_strict | split: ','
|
||||||
|
assign exclude_collections_contain = settings.exclude_collections_contain | split: ','
|
||||||
|
assign collections_markup = ''
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- for collection in predictive_search.resources.collections -%}
|
||||||
|
{%- liquid
|
||||||
|
assign skip_current_collection = false
|
||||||
|
for exclude_collection_strict in exclude_collections_strict
|
||||||
|
assign exclude_collection_strict_stripped = exclude_collection_strict | strip
|
||||||
|
|
||||||
|
if exclude_collection_strict_stripped == collection.handle
|
||||||
|
assign skip_current_collection = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
for exclude_collection_contain in exclude_collections_contain
|
||||||
|
assign exclude_collection_contain_stripped = exclude_collection_contain | strip
|
||||||
|
|
||||||
|
if collection.handle contains exclude_collection_contain_stripped
|
||||||
|
assign skip_current_collection = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if skip_current_collection
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign collection_counter = collection_counter | plus: 1
|
||||||
|
assign collection_counter_animate = collection_counter | plus: product_count | plus: query_count
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- capture collections_markup -%}
|
||||||
|
{{ collections_markup }}
|
||||||
|
|
||||||
|
<div class="other__inline animates" style="animation-delay: {{ collection_counter_animate | times: 90 | plus: 10 }}ms;" id="predictive-search-option-collection-{{ collection_counter }}" role="option" aria-selected="false">
|
||||||
|
<p class="other__inline__title">
|
||||||
|
<a href="{{ collection.url }}">{{ collection.title }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{%- endcapture -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- assign total_results = product_count | plus: query_count | plus: collection_counter | plus: page_count | plus: article_count -%}
|
||||||
|
|
||||||
|
{%- if predictive_search.performed -%}
|
||||||
|
<div class="wrapper">
|
||||||
|
<span class="predictive-search-status visually-hidden" data-predictive-search-live-region-count-value role="status">
|
||||||
|
{%- liquid
|
||||||
|
if total_results == 0
|
||||||
|
echo 'general.search.no_results' | t: terms: terms
|
||||||
|
else
|
||||||
|
echo 'general.search.results_with_count' | t: count: total_results | replace: '**', '' | append: ': '
|
||||||
|
|
||||||
|
if query_count > 0
|
||||||
|
assign count = query_count | plus: collection_counter
|
||||||
|
echo 'general.search.results_suggestions_with_count' | t: count: count | append: ', '
|
||||||
|
endif
|
||||||
|
|
||||||
|
if page_count > 0
|
||||||
|
assign count = page_count | plus: article_count
|
||||||
|
echo 'general.search.results_pages_with_count' | t: count: count | append: ', '
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product_count > 0
|
||||||
|
echo 'general.search.results_products_with_count' | t: count: product_count
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
</span>
|
||||||
|
<div class="search__results__wrapper" id="predictive-search-results" role="listbox" aria-label="{{ 'general.search.search_for' | t: terms: terms }}">
|
||||||
|
{%- if total_results > 0 -%}
|
||||||
|
<div class="search__results__outer">
|
||||||
|
<div class="search__results__other">
|
||||||
|
{%- if query_count > 0 -%}
|
||||||
|
<div class="search__results__other__list">
|
||||||
|
<div class="search__results__heading">
|
||||||
|
<p class="search__results__title">{{ 'general.search.suggestions' | t }}</p>
|
||||||
|
<span class="badge">{{ query_count }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul aria-label="{{ 'general.search.suggestions' | t }}" role="group">
|
||||||
|
{%- for query in predictive_search.resources.queries -%}
|
||||||
|
{%- assign total_results_counter = total_results_counter | plus: 1 -%}
|
||||||
|
<li class="other__inline animates" id="predictive-search-option-query-{{ forloop.index }}" role="option" aria-selected="false" style="animation-delay: {{ total_results_counter | times: 90 | plus: 10 }}ms;">
|
||||||
|
<p class="other__inline__title">
|
||||||
|
<a href="{{ query.url }}">
|
||||||
|
<span>{{ query.styled_text }}</span>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if product_count > 0 -%}
|
||||||
|
<div class="search__results__products">
|
||||||
|
<div class="search__results__products__title">
|
||||||
|
<div id="search_product_results_heading" class="search__results__heading">
|
||||||
|
<p class="search__results__title">{{ 'products.general.products' | t }}</p>
|
||||||
|
<span class="badge">{{ product_count }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul aria-label="{{ 'products.general.products' | t }}" class="search__results__products__list">
|
||||||
|
{%- for product in predictive_search.resources.products -%}
|
||||||
|
{%- liquid
|
||||||
|
assign total_results_counter = total_results_counter | plus: 1
|
||||||
|
assign on_sale = false
|
||||||
|
assign product_price = product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
comment
|
||||||
|
start Yagi app code
|
||||||
|
endcomment
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign product_price = product.metafields.app--168074346497.min_auto_discounted_price.value | default: product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
assign product_price = product.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product_price < product.price and product_compare_at_price == 0 or product_compare_at_price == blank
|
||||||
|
assign product_compare_at_price = product.price
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
end Yagi app code
|
||||||
|
endcomment
|
||||||
|
if product_compare_at_price > product_price
|
||||||
|
assign on_sale = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sold_out = true
|
||||||
|
if product.available
|
||||||
|
assign sold_out = false
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
<div class="product__inline animates" style="animation-delay: {{ total_results_counter | times: 90 | plus: 10 }}ms;" role="option" aria-selected="false">
|
||||||
|
<a href="{{ product.url }}" class="product__inline__link">
|
||||||
|
{%- if product.featured_image != blank -%}
|
||||||
|
<div role="presentation" class="product__inline__image">
|
||||||
|
{% assign alt = product.title | strip_html %}
|
||||||
|
{{ product.featured_image | image_url: width: product.featured_image.width | image_tag: class: 'img-aspect-ratio', alt: alt }}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="product__inline__title">
|
||||||
|
{{ product.title | strip_html }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="product__inline__price">
|
||||||
|
<span class="price{% if on_sale %} on-sale{% endif %}{% if sold_out %} sold-out{% endif %}">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ product_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ product_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{%- if sold_out -%}
|
||||||
|
<br>
|
||||||
|
<em>{{ 'products.product.sold_out' | t }}</em>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{% if on_sale %}
|
||||||
|
<span class="compare-at">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ product_compare_at_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ product_compare_at_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if collection_counter > 0 -%}
|
||||||
|
{%- assign total_results_counter = total_results_counter | plus: collection_counter -%}
|
||||||
|
|
||||||
|
<div class="search__results__other__list">
|
||||||
|
<div id="search_collection_results_heading" class="search__results__heading">
|
||||||
|
<p class="search__results__title">{{ 'collections.sidebar.collections' | t }}</p>
|
||||||
|
<span class="badge">{{ collection_counter }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul aria-label="{{ 'collections.sidebar.collections' | t }}" role="group" class="search__results__collections__list">
|
||||||
|
{{ collections_markup }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if article_count > 0 -%}
|
||||||
|
<div class="search__results__other__list">
|
||||||
|
<div id="search_article_results_heading" class="search__results__heading">
|
||||||
|
<p class="search__results__title">{{ 'blogs.article.articles' | t }}</p>
|
||||||
|
<span class="badge">{{ article_count }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul aria-label="{{ 'blogs.article.articles' | t }}" role="group" class="search__results__articles__list">
|
||||||
|
{%- for article in predictive_search.resources.articles -%}
|
||||||
|
{%- assign total_results_counter = total_results_counter | plus: 1 -%}
|
||||||
|
<li class="other__inline animates" style="animation-delay: {{ total_results_counter | times: 90 | plus: 10 }}ms;" id="predictive-search-option-article-{{ forloop.index }}" role="option" aria-selected="false">
|
||||||
|
<p class="other__inline__title">
|
||||||
|
<a href="{{ article.url }}">{{ article.title }}</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if page_count > 0 -%}
|
||||||
|
<div class="search__results__other__list">
|
||||||
|
<div id="search_page_results_heading" class="search__results__heading">
|
||||||
|
<p class="search__results__title">{{ 'general.page.pages' | t }}</p>
|
||||||
|
<span class="badge">{{ page_count }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul aria-label="{{ 'general.page.pages' | t }}" role="group" class="search__results__articles__list">
|
||||||
|
{%- for page in predictive_search.resources.pages -%}
|
||||||
|
{%- assign total_results_counter = total_results_counter | plus: 1 -%}
|
||||||
|
<li class="other__inline animates" style="animation-delay: {{ total_results_counter | times: 90 | plus: 10 }}ms;" id="predictive-search-option-page-{{ forloop.index }}" role="option" aria-selected="false">
|
||||||
|
<p class="other__inline__title">
|
||||||
|
<a href="{{ page.url }}">{{ page.title }}</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- else -%}
|
||||||
|
<div class="search__results__empty">
|
||||||
|
<div aria-live="polite">
|
||||||
|
<p>
|
||||||
|
{{ 'general.search.no_results_for' | t }}
|
||||||
|
<em>{{ terms }}</em>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div class="search__results__actions">
|
||||||
|
<button
|
||||||
|
class="btn btn--outline search__results__btn !flex items-center flex-nowrap gap-r2 whitespace-normal max-w-full"
|
||||||
|
tabindex="-1"
|
||||||
|
role="option"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
<span class="line-clamp-1 text-ellipsis" data-predictive-search-search-for-text>{{ 'general.search.search_for' | t: terms: terms }}</span>
|
||||||
|
<span class="accent-size-5 [&>svg]:inline-block rtl:-scale-x-100">{%- render 'icon-core-chevron-right' -%}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
<!-- /sections/search.liquid -->
|
||||||
|
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
assign has_filters = false
|
||||||
|
if search.filters != empty and section.settings.show_filters
|
||||||
|
assign has_filters = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign types = search.types | join: ',' | url_encode
|
||||||
|
assign types = 'type=' | append: types
|
||||||
|
|
||||||
|
assign accordion_initial_state = 'accordion-is-open'
|
||||||
|
assign accordion_open_boolean = true
|
||||||
|
if section.settings.collapse_filters
|
||||||
|
# no class means the accordion is closed
|
||||||
|
assign accordion_initial_state = ''
|
||||||
|
# accordion_open_boolean is used to set aria-expanded and
|
||||||
|
# match js logic for 'display: none' on accordion body elements
|
||||||
|
# which are non-adjacent siblings that cannot easily be styled with CSS
|
||||||
|
assign accordion_open_boolean = false
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
<section class="page-search {{ section.settings.width }} section-padding"
|
||||||
|
data-section-type="search-page"
|
||||||
|
data-section-id="{{ section.id }}"
|
||||||
|
style="--PT: {{ section.settings.padding_top }}px; --PB: {{ section.settings.padding_bottom }}px;">
|
||||||
|
<div class="search__page__heading">
|
||||||
|
{% render 'search-bar' %}
|
||||||
|
|
||||||
|
{%- if search.terms.size > 0 -%}
|
||||||
|
<div class="search__page__query note">
|
||||||
|
<p>
|
||||||
|
{%- if search.results_count > 0 -%}
|
||||||
|
{{ 'general.search.results_for' | t }} <span class="strong">{{ search.terms | escape }}</span>
|
||||||
|
{%- else -%}
|
||||||
|
{{ 'general.search.no_results_for' | t }} <span class="strong">{{ search.terms | escape }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if search.performed %}
|
||||||
|
{%- if has_filters -%}
|
||||||
|
{%- assign filter_count = 0 -%}
|
||||||
|
{%- capture filter_clears -%}
|
||||||
|
{%- for filter in search.filters -%}
|
||||||
|
{%- if filter.type == "price_range" -%}
|
||||||
|
{%- if filter.min_value.value != nil or filter.max_value.value != nil -%}
|
||||||
|
{%- assign filter_count = filter_count | plus: 1 -%}
|
||||||
|
<a class="active__filters__remove" href="{{ filter.url_to_remove }}" data-filter-update-url>
|
||||||
|
{%- assign min_value = filter.min_value.value | default: 0 -%}
|
||||||
|
{%- assign max_value = filter.max_value.value | default: filter.range_max -%}
|
||||||
|
{{ min_value | money_without_trailing_zeros }} - {{ max_value | money_without_trailing_zeros }} X
|
||||||
|
</a>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- for filter_value in filter.active_values -%}
|
||||||
|
{%- assign filter_count = filter_count | plus: 1 -%}
|
||||||
|
<a class="active__filters__remove" href="{{ filter_value.url_to_remove }}" data-filter-update-url>
|
||||||
|
{{ filter_value.label }} <span class="filter__x">X</span>
|
||||||
|
</a>
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
<nav class="collection__nav" data-collection-tools>
|
||||||
|
<div class="collection__nav__buttons">
|
||||||
|
{% if filter_count > 0 %}
|
||||||
|
{% capture current_filters_count %}
|
||||||
|
<div class="badge">{{ filter_count }}</div>
|
||||||
|
{% endcapture %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<button class="collection__filters__toggle filters--default-visible drawer--visible" data-filters-toggle="filters">
|
||||||
|
<span class="hide-filters">{{ 'collections.sidebar.hide_filters' | t }}</span>
|
||||||
|
<span class="show-filters">{{ 'collections.sidebar.filter' | t }}</span>
|
||||||
|
<span data-active-filters-count>{{ current_filters_count }}</span>
|
||||||
|
{% render 'icon-core-filter' %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div class="collection__active__filters__wrapper{% unless filter_count > 0 %} is-hidden{% endunless %}">
|
||||||
|
<div class="collection__active__filters" data-active-filters>
|
||||||
|
{%- if filter_count > 1 -%}
|
||||||
|
<a href="{{ routes.search_url }}?{{ types }}&q={{ search.terms | url_encode }}" class="active__filters__clear" data-filter-update-url>{{ 'collections.sidebar.all_tags' | t }}</a>
|
||||||
|
{%- endif -%}
|
||||||
|
{{- filter_clears -}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- if section.settings.show_products_count -%}
|
||||||
|
<div class="collection__count" data-products-count>
|
||||||
|
{%- if search.results_count -%}
|
||||||
|
{{ 'general.search.results_with_count' | t: count: search.results_count | replace_first: '**', '<strong>' | replace_first: '**', '</strong>' | replace_first: '**', '<strong>' | replace_first: '**', '</strong>' }}
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="collection__content">
|
||||||
|
|
||||||
|
{%- if has_filters -%}
|
||||||
|
<div class="collection__filters__wrapper filters--default-visible" data-collection-sidebar data-filters="filters" data-default-hide="false">
|
||||||
|
<div class="collection__filters__outer">
|
||||||
|
<div class="drawer__top">
|
||||||
|
<div class="drawer__top__left">
|
||||||
|
<p class="cart__drawer__title">{{ 'collections.sidebar.filter' | t }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="drawer__button drawer__close"
|
||||||
|
data-first-focus
|
||||||
|
data-filters-toggle="filters"
|
||||||
|
aria-label="{{ 'general.accessibility.close' | t }}">
|
||||||
|
{% render 'icon-core-x' %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="collection__filters__inner">
|
||||||
|
<form data-sidebar-filter-form>
|
||||||
|
<input type="hidden" name="q" value="{{ search.terms }}">
|
||||||
|
|
||||||
|
{%- for filter in search.filters -%}
|
||||||
|
{% render 'filters',
|
||||||
|
filter: filter,
|
||||||
|
forloop: forloop,
|
||||||
|
accordion_open_boolean: accordion_open_boolean,
|
||||||
|
accordion_initial_state: accordion_initial_state %}
|
||||||
|
{%- endfor -%}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="drawer__underlay" data-filters-underlay>
|
||||||
|
<span class="drawer__underlay__fill"></span>
|
||||||
|
<span class="drawer__underlay__blur"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div class="collection__products" data-products-grid>
|
||||||
|
{% paginate search.results by section.settings.pagination_count %}
|
||||||
|
{% for item in search.results %}
|
||||||
|
<div class="search__item__generic">
|
||||||
|
{% if item.image or item.featured_media.preview_image %}
|
||||||
|
|
||||||
|
<div class="search__item__generic__image">
|
||||||
|
<a href="{{ item.url }}" title="{{ item.title | escape }}">
|
||||||
|
{% assign image = item.featured_media.preview_image | default: item.image %}
|
||||||
|
{% assign image_width = 70 | at_most: image.width %}
|
||||||
|
{% assign image_width_2x = image_width | times: 2 | at_most: image.width %}
|
||||||
|
{% assign alt = image.alt %}
|
||||||
|
|
||||||
|
{% capture srcset %}
|
||||||
|
{{ image | image_url: width: image_width_2x }} 2x,
|
||||||
|
{{ image | image_url: width: image_width }}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
{%- render 'image',
|
||||||
|
img_object: image,
|
||||||
|
wh_ratio: image.aspect_ratio,
|
||||||
|
width: image_width,
|
||||||
|
srcset: srcset,
|
||||||
|
alt: alt
|
||||||
|
-%}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="search__item__generic__text">
|
||||||
|
<p class="product__inline__title">
|
||||||
|
{{ item.title | link_to: item.url }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% if item.object_type == 'product' %}
|
||||||
|
<p class="product__inline__price">
|
||||||
|
{%- assign product = item -%}
|
||||||
|
{%- assign on_sale = false -%}
|
||||||
|
{%- assign sold_out = true -%}
|
||||||
|
{%- assign current_variant = product.first_available_variant -%}
|
||||||
|
{% liquid
|
||||||
|
assign product_price = product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
comment
|
||||||
|
start Yagi app code
|
||||||
|
endcomment
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign product_price = product.metafields.app--168074346497.min_auto_discounted_price.value | default: product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
assign product_price = product.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product_price < product.price and product_compare_at_price == 0 or product_compare_at_price == blank
|
||||||
|
assign product_compare_at_price = product.price
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
end Yagi app code
|
||||||
|
endcomment
|
||||||
|
%}
|
||||||
|
|
||||||
|
{%- if product_compare_at_price > product_price -%}
|
||||||
|
{%- assign on_sale = true -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if product.available -%}
|
||||||
|
{%- assign sold_out = false -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<span class="price{% if on_sale %} on-sale{% endif %}">
|
||||||
|
{% if product.price_varies %}{{ 'products.general.from' | t }} {% endif %}
|
||||||
|
{% if settings.currency_code_enable %}
|
||||||
|
{{ product_price | money_with_currency }}
|
||||||
|
{% else %}
|
||||||
|
{{ product_price | money }}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if on_sale %}
|
||||||
|
<span class="compare-at">
|
||||||
|
{% if settings.currency_code_enable %}
|
||||||
|
{{ product_compare_at_price | money_with_currency }}
|
||||||
|
{% else %}
|
||||||
|
{{ product_compare_at_price | money }}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if current_variant.unit_price %}
|
||||||
|
{% capture unit_price_separator %}
|
||||||
|
<span aria-hidden="true">/</span><span class="visually-hidden">{{ 'general.accessibility.unit_price_separator' | t }} </span>
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
{% capture unit_price_base_unit %}
|
||||||
|
{% if current_variant.unit_price_measurement.reference_value != 1 %}
|
||||||
|
{{ current_variant.unit_price_measurement.reference_value }}
|
||||||
|
{% endif %}
|
||||||
|
{{ current_variant.unit_price_measurement.reference_unit }}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<span class="visually-hidden">{{ 'products.product.unit_price_label' | t }}</span>
|
||||||
|
<span class="price-per-unit">{{ current_variant.unit_price | money }}{{ unit_price_separator }}{{ unit_price_base_unit }}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if sold_out %}
|
||||||
|
<br /><em>{{ 'products.product.sold_out' | t }}</em>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
{%- if settings.product_grid_show_rating and product.metafields.reviews.rating.value != blank -%}
|
||||||
|
<div class="rating__wrapper__search">
|
||||||
|
{% render 'product-rating', product: product, show_rating_count: settings.product_grid_show_rating_count %}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% unless forloop.last %}<hr>{% endunless %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if paginate.pages > 1 %}
|
||||||
|
<div class="text-center pt-r11">
|
||||||
|
{% render 'pagination-custom', paginate: paginate %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endpaginate %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{% schema %}
|
||||||
|
{
|
||||||
|
"name": "Search",
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "header",
|
||||||
|
"content": "Search"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "checkbox",
|
||||||
|
"id": "show_filters",
|
||||||
|
"default": true,
|
||||||
|
"label": "Show product filters"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "checkbox",
|
||||||
|
"id": "collapse_filters",
|
||||||
|
"label": "Collapse filter accordions",
|
||||||
|
"info": "Active filters will remain open",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "checkbox",
|
||||||
|
"id": "show_products_count",
|
||||||
|
"label": "Show products count",
|
||||||
|
"info": "Product count will be shown when filters are active",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "range",
|
||||||
|
"id": "pagination_count",
|
||||||
|
"min": 3,
|
||||||
|
"max": 50,
|
||||||
|
"step": 1,
|
||||||
|
"label": "Results per page",
|
||||||
|
"default": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "header",
|
||||||
|
"content": "Section spacing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"id": "width",
|
||||||
|
"label": "Width",
|
||||||
|
"default": "wrapper",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "wrapper--full",
|
||||||
|
"label": "Full width padded"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "wrapper",
|
||||||
|
"label": "Page width"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "wrapper--narrow",
|
||||||
|
"label": "Page width narrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "wrapper--tiny",
|
||||||
|
"label": "Page width extra narrow"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "range",
|
||||||
|
"id": "padding_top",
|
||||||
|
"min": 0,
|
||||||
|
"max": 180,
|
||||||
|
"step": 2,
|
||||||
|
"unit": "px",
|
||||||
|
"label": "Padding top",
|
||||||
|
"default": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "range",
|
||||||
|
"id": "padding_bottom",
|
||||||
|
"min": 0,
|
||||||
|
"max": 180,
|
||||||
|
"step": 2,
|
||||||
|
"unit": "px",
|
||||||
|
"label": "Padding bottom",
|
||||||
|
"default": 36
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{% endschema %}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
<!-- /snippets/product-buttons.liquid -->
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
assign buybutton_setting = false
|
||||||
|
assign gift_card_recipient_feature_active = false
|
||||||
|
assign current_variant = product.selected_or_first_available_variant
|
||||||
|
|
||||||
|
if block.settings.enable_gift_card_recipient and product.gift_card?
|
||||||
|
assign gift_card_recipient_feature_active = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
Quick buy buttons are incompatable with gift card products and subscription products
|
||||||
|
endcomment
|
||||||
|
if block.settings.enable_payment_button and gift_card_recipient_feature_active == false
|
||||||
|
assign buybutton_setting = true
|
||||||
|
endif
|
||||||
|
if product.selling_plan_groups.size > 0
|
||||||
|
assign buybutton_setting = false
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
<div class="product__block__buttons" style="--PB: {{ block.settings.padding_bottom }}px;" {{ block.shopify_attributes }} >
|
||||||
|
<div data-product-form-outer>
|
||||||
|
{% comment %} The [data-product-form] tag distinguishes the product form from upsell instant-add-buttons. {% endcomment %}
|
||||||
|
{%- form 'product', product, id: uniq_id, data-product-form: '', data-product-handle: product.handle -%}
|
||||||
|
{%- unless hidden -%}
|
||||||
|
<div class="product__form__inner" data-form-inner>
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Note: the gift card recipient form is controlled in Checkout and must contain these undocumented line item propeties:
|
||||||
|
* properties[__shopify_send_gift_card_to_recipient] - Hidden - Toggles the feature on/off in checkout, following properties have no effect without it
|
||||||
|
* properties[Recipient email] - The email of the gift card recipient
|
||||||
|
* properties[Recipient name] - The name of the gift card recipient
|
||||||
|
* properties[Message] - Shopify chose a highly generic name for the gift card message, this could easily conflict with an app or custom code
|
||||||
|
{% endcomment %}
|
||||||
|
{%- if gift_card_recipient_feature_active -%}
|
||||||
|
{%- render 'gift-card-recipient-form', product: product, form: form, section: section -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div class="product__submit" data-buttons-wrapper data-add-action-wrapper data-error-boundary>
|
||||||
|
<div data-error-display role='alert' class="add-action-errors"></div>
|
||||||
|
|
||||||
|
{%- assign button_text = 'products.product.add_to_cart' | t -%}
|
||||||
|
{%- if product.metafields.theme.preorder.value == true -%}
|
||||||
|
{% comment %} Add a line item property with 'Sale type: Pre-order' and make the button say 'Pre-order'{% endcomment %}
|
||||||
|
<input type="hidden" data-product-preorder name="properties[{{ 'products.product.sale_type' | t }}]" value="{{ 'products.product.pre_order' | t }}">
|
||||||
|
{%- assign button_text = 'products.product.pre_order' | t -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- render 'sibling-color-as-line-prop' product: product -%}
|
||||||
|
|
||||||
|
{%- if current_variant == null -%}
|
||||||
|
{%- assign button_text = 'products.product.unavailable' | t -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if current_variant.available == false -%}
|
||||||
|
{%- assign button_text = 'products.product.sold_out' | t -%}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
<div class="product__submit__buttons{% if product.has_only_default_variant %} product__submit__buttons--clear{% endif %}">
|
||||||
|
<span class="sr-only" aria-live="polite" x-show="isLoading">
|
||||||
|
{{ 'products.product.adding_to_cart' | t }}
|
||||||
|
</span>
|
||||||
|
<span class="sr-only" aria-live="polite" x-show="isSuccess">
|
||||||
|
{{ 'products.product.added_to_cart' | t }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
name="add"
|
||||||
|
class="btn--outline btn--full btn--primary btn--add-to-cart"
|
||||||
|
data-add-to-cart
|
||||||
|
{% comment %} Explicitly add aria label so that button text isn't read out in screen readers in uppercase {% endcomment %}
|
||||||
|
aria-label="{{ button_text }}"
|
||||||
|
:class="{
|
||||||
|
'has-success': isSuccess,
|
||||||
|
'loading': isLoading
|
||||||
|
}"
|
||||||
|
{% unless current_variant.available %} disabled="disabled" {% endunless %}
|
||||||
|
>
|
||||||
|
<span class="btn-state-ready flex justify-center">
|
||||||
|
<span data-add-to-cart-text>
|
||||||
|
{{ button_text }}
|
||||||
|
</span>
|
||||||
|
{% if current_variant %}
|
||||||
|
{% liquid
|
||||||
|
comment
|
||||||
|
start Yagi app code
|
||||||
|
endcomment
|
||||||
|
assign current_variant_price = current_variant.price
|
||||||
|
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign current_variant_price = current_variant.metafields.app--168074346497.auto_discounted_price.value | default: current_variant.price
|
||||||
|
|
||||||
|
if current_variant.metafields.app--168074346497.discount_type.value != nil and current_variant.metafields.app--168074346497.discount_type.value != "fixed" and product.metafields.app--168074346497.discount_percentage.value > 0.01
|
||||||
|
assign deducted_percentage = 1.0 | minus: product.metafields.app--168074346497.discount_percentage.value
|
||||||
|
|
||||||
|
if current_variant.metafields.app--168074346497.discount_percentage.value > 0.01
|
||||||
|
assign deducted_percentage = 1.0 | minus: current_variant.metafields.app--168074346497.discount_percentage.value
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign current_variant_price = current_variant.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
|
||||||
|
assign current_variant_price = current_variant.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
end Yagi app code
|
||||||
|
endcomment
|
||||||
|
%}
|
||||||
|
<span class="cta__dot opacity-50">•</span>
|
||||||
|
<span
|
||||||
|
data-button-price
|
||||||
|
{% if public_or_tags_matched %}data-yagi-matched{% endif %}
|
||||||
|
data-yagi-price="{{ current_variant_price }}"
|
||||||
|
x-text="$formatCurrency({{- current_variant_price -}} * Math.max(quantity, 1), { form: 'short', currency: '{{ cart.currency.iso_code }}' })"
|
||||||
|
>
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ current_variant_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ current_variant_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="btn-state-loading">
|
||||||
|
<svg height="18" width="18" class="svg-loader">
|
||||||
|
<circle r="7" cx="9" cy="9" />
|
||||||
|
<circle stroke-dasharray="87.96459430051421 87.96459430051421" r="7" cx="9" cy="9" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="btn-state-complete"> </span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{%- if buybutton_setting -%}
|
||||||
|
<div class="product__submit__quick">
|
||||||
|
{{ form | payment_button }}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% comment %} Shop pay split payment terms {% endcomment %}
|
||||||
|
<div class="shop-pay-terms">{{- form | payment_terms -}}</div>
|
||||||
|
{%- endunless -%}
|
||||||
|
|
||||||
|
{% comment %} The input with name="id" indicates the variant to add to cart {% endcomment %}
|
||||||
|
<input type="hidden" name="id" x-model.fill="variantId" value="{{ current_variant.id }}">
|
||||||
|
{%- endform -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,578 @@
|
|||||||
|
<!-- /snippets/product-grid-item-variant.liquid -->
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Inner content for a grid item
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
assign on_sale = false
|
||||||
|
assign product_price = product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
comment
|
||||||
|
start Yagi app code
|
||||||
|
endcomment
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign product_price = product.metafields.app--168074346497.min_auto_discounted_price.value | default: product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
assign product_price = product.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product_price < product.price and product_compare_at_price == 0 or product_compare_at_price == blank
|
||||||
|
assign product_compare_at_price = product.price
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
end Yagi app code
|
||||||
|
endcomment
|
||||||
|
if product_compare_at_price > product_price
|
||||||
|
assign on_sale = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sold_out = true
|
||||||
|
if product.available
|
||||||
|
assign sold_out = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sellout_badge = false
|
||||||
|
if sold_out and settings.badge_sellout
|
||||||
|
assign sellout_badge = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sale_badge = false
|
||||||
|
if on_sale and settings.badge_sale
|
||||||
|
assign sale_badge = true
|
||||||
|
assign sale_badge_content = 'products.product.sale' | t
|
||||||
|
if settings.badge_sale_discount
|
||||||
|
if settings.badge_sale_type == 'dollar'
|
||||||
|
if settings.currency_code_enable
|
||||||
|
assign sale_badge_content = product_compare_at_price | minus: product_price | money_with_currency
|
||||||
|
else
|
||||||
|
assign sale_badge_content = product_compare_at_price | minus: product_price | money_without_trailing_zeros
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
assign difference = product_compare_at_price | minus: product_price
|
||||||
|
assign percent_off = difference | times: 1.0 | divided_by: product_compare_at_price | times: 100
|
||||||
|
assign sale_badge_content = percent_off | floor | append: '%'
|
||||||
|
endif
|
||||||
|
assign save_word = 'products.product.save' | t | append: ' '
|
||||||
|
assign sale_badge_content = sale_badge_content | prepend: save_word
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign custom_badge = false
|
||||||
|
if settings.badge_custom
|
||||||
|
if product.metafields.theme.badge != blank and product.metafields.theme.badge.type == 'single_line_text_field'
|
||||||
|
assign custom_badge = true
|
||||||
|
assign custom_badge_content = product.metafields.theme.badge.value
|
||||||
|
endif
|
||||||
|
for tag in product.tags
|
||||||
|
if tag contains "_badge_"
|
||||||
|
assign tag_content = tag | remove: '_badge_' | replace: '_', ' '
|
||||||
|
if tag_content != ''
|
||||||
|
assign custom_badge = true
|
||||||
|
assign custom_badge_content = tag_content
|
||||||
|
endif
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
if badge_string and badge_string != ''
|
||||||
|
assign custom_badge = true
|
||||||
|
assign custom_badge_content = badge_string
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign tagged = false
|
||||||
|
if sellout_badge or sale_badge or custom_badge
|
||||||
|
assign tagged = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
Disqualify options that have more than 15 variants or are a combined length of > 90 characters
|
||||||
|
endcomment
|
||||||
|
if inline_variant_buttons.values.size > 15
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if inline_variant_buttons
|
||||||
|
assign all_characters = inline_variant_buttons.values | join: ""
|
||||||
|
if all_characters.size >= 90
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Sellign plans can be added along with inline or instand buttons if
|
||||||
|
# the product has exactly 1 selling plan with subscriptions required
|
||||||
|
assign simple_selling_plan = nil
|
||||||
|
|
||||||
|
if inline_variant_buttons or instant_add_button
|
||||||
|
if product.requires_selling_plan and product.selling_plan_groups.size == 1 and product.selling_plan_groups[0].selling_plans.size == 1
|
||||||
|
# one variant, one required subscription, no choices to make
|
||||||
|
assign simple_selling_plan = product.selected_or_first_available_selling_plan_allocation.selling_plan
|
||||||
|
elsif product.selling_plan_groups.size > 0
|
||||||
|
# Abort instant and inline add buttons, subs choices must be made
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
assign instant_add_button = nil
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Catch case where first sibling has inline variants and subsequent do not
|
||||||
|
if product.has_only_default_variant and inline_variant_buttons
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
assign instant_add_button = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Allow configuration of image sizing for different numbers of grid columns
|
||||||
|
# Note: desktop/tablet are set to a default of 3 just in case the grid sizes are not set to prevent accidental gigantic full-width images from being loaded
|
||||||
|
assign columns_desktop = columns_desktop | default: section.settings.grid_large | default: 3
|
||||||
|
assign columns_tablet = columns_tablet | default: section.settings.grid_medium | default: columns_desktop | default: 3
|
||||||
|
assign columns_mobile = columns_mobile | default: section.settings.grid_mobile | default: 1
|
||||||
|
assign section_width = section_width | default: section.settings.width | default: null
|
||||||
|
-%}
|
||||||
|
{%- capture badge -%}
|
||||||
|
{%- if tagged %}
|
||||||
|
{%- if custom_badge -%}
|
||||||
|
<div class="product__badge product__badge--custom product__badge--{{ custom_badge_content | strip_html | handle }}">{{ custom_badge_content }}</div>
|
||||||
|
{%- elsif sellout_badge -%}
|
||||||
|
<div class="product__badge product__badge--sold">{{ 'products.product.sold_out' | t }}</div>
|
||||||
|
{%- elsif sale_badge -%}
|
||||||
|
<div class="product__badge product__badge--sale">{{ sale_badge_content }}</div>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
assign first_image = product.media[0].preview_image
|
||||||
|
assign container_wh_ratio = settings.product_card_wh_ratio
|
||||||
|
assign image_cover = true
|
||||||
|
|
||||||
|
case settings.product_grid_image
|
||||||
|
when 'crop'
|
||||||
|
assign image_wh_ratio = container_wh_ratio
|
||||||
|
when 'uneven'
|
||||||
|
assign container_wh_ratio = first_image.aspect_ratio | default: settings.product_card_wh_ratio
|
||||||
|
when 'scale'
|
||||||
|
assign image_cover = false
|
||||||
|
assign image_wh_ratio = first_image.aspect_ratio | default: settings.product_card_wh_ratio
|
||||||
|
endcase
|
||||||
|
|
||||||
|
# Behavior is inferred based on setting and passed into JS
|
||||||
|
assign image_hover = 'disabled'
|
||||||
|
assign images_limit = settings.cycle_images_limit
|
||||||
|
case images_limit
|
||||||
|
when 1
|
||||||
|
assign image_hover = 'disabled'
|
||||||
|
when 2
|
||||||
|
assign image_hover = 'second_immediately'
|
||||||
|
else
|
||||||
|
assign image_hover = 'cycle_images'
|
||||||
|
endcase
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- capture sizes -%}
|
||||||
|
{%- render 'image-grid-sizes',
|
||||||
|
columns_desktop: columns_desktop,
|
||||||
|
columns_tablet: columns_tablet,
|
||||||
|
columns_mobile: columns_mobile,
|
||||||
|
section_width: section_width
|
||||||
|
%}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
<product-grid-item-variant
|
||||||
|
class="
|
||||||
|
product-grid-item__content{% if on_sale %} on-sale{% endif %}
|
||||||
|
{% if sold_out %} sold-out{% endif %}
|
||||||
|
{% if tagged %} tagged{% endif %}
|
||||||
|
{% comment %} only used to hide badge on hover {% endcomment %}
|
||||||
|
{% if image_hover == 'cycle_images' %} is-slideshow{% endif %}
|
||||||
|
"
|
||||||
|
style="
|
||||||
|
--enter-animation-duration: 225ms;
|
||||||
|
--exit-animation-duration: 400ms;
|
||||||
|
"
|
||||||
|
data-grid-item="{{ product.id }}"
|
||||||
|
data-slideshow-style="{{ image_hover }}"
|
||||||
|
data-grid-item-variant="{{ variant.id }}"
|
||||||
|
{% if visible != true %} hidden {% endif %}
|
||||||
|
aria-label="{{ variant.title }}"
|
||||||
|
>
|
||||||
|
<div class="product-grid-item__container" data-error-boundary>
|
||||||
|
<div data-error-display class="product-grid-item__error-display"> </div>
|
||||||
|
<a href="{{ product.url }}" data-grid-link aria-label="{{ product.title | strip_html | escape }}">
|
||||||
|
<div
|
||||||
|
class="product-grid-item__images aspect-[--wh-ratio]"
|
||||||
|
data-grid-images data-grid-slide
|
||||||
|
style="
|
||||||
|
--wh-ratio: {{ container_wh_ratio }};
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{%- if product.media.size > 0 -%}
|
||||||
|
{% comment %}
|
||||||
|
Manually store and increment this variable since we start skipping images below when we exceed the allowed images which would
|
||||||
|
make using e.g. forloop.index0 not work since the index of the variant image could be greater than the number of images allowed
|
||||||
|
{% endcomment %}
|
||||||
|
{%- assign image_index = 0 -%}
|
||||||
|
|
||||||
|
{%- for media in product.media -%}
|
||||||
|
{%- liquid
|
||||||
|
# If we've already exceeded the number of allowed images, and this is not the variant featured media, skip it
|
||||||
|
if image_index > images_limit
|
||||||
|
if product.selected_variant and product.selected_variant.featured_media.id != media.id
|
||||||
|
continue
|
||||||
|
elsif variant.featured_media.id != media.id
|
||||||
|
continue
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign img_object = media.preview_image
|
||||||
|
assign class = "product-grid-item__image"
|
||||||
|
assign loading = 'lazy'
|
||||||
|
assign fetchpriority = "low"
|
||||||
|
assign visible = false
|
||||||
|
assign active_class = 'is-active'
|
||||||
|
assign is_variant_featured_media = false
|
||||||
|
assign is_selected_variant = false
|
||||||
|
assign preload_image = false
|
||||||
|
assign loading_image = 'lazy'
|
||||||
|
|
||||||
|
if variant.featured_media and media.id == variant.featured_media.id
|
||||||
|
# Variant image is not necessarily first image or default image
|
||||||
|
assign is_variant_featured_media = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product.selected_variant and product.selected_variant.featured_image
|
||||||
|
if product.selected_variant.featured_media.id == media.id
|
||||||
|
assign is_selected_variant = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Show variant image is there is a collection filter applied
|
||||||
|
if is_variant_featured_media and is_selected_variant
|
||||||
|
assign visible = true
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# If no filters are active show the first image first
|
||||||
|
if forloop.first
|
||||||
|
assign visible = true
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if visible
|
||||||
|
assign fetchpriority = "high"
|
||||||
|
if preload
|
||||||
|
assign loading = 'eager'
|
||||||
|
assign preload_image = true
|
||||||
|
endif
|
||||||
|
if eagerload
|
||||||
|
assign loading_image = 'eager'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
%}
|
||||||
|
|
||||||
|
{%- capture srcset -%}
|
||||||
|
{%- render 'image-grid-srcset',
|
||||||
|
image: img_object,
|
||||||
|
columns_desktop: columns_desktop,
|
||||||
|
columns_tablet: columns_tablet,
|
||||||
|
columns_mobile: columns_mobile,
|
||||||
|
section_width: section_width,
|
||||||
|
wh_ratio: image_wh_ratio,
|
||||||
|
crop: 'center'
|
||||||
|
%}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{% comment %} Use a template to prevent hidden images from loading until user begins slideshow{% endcomment %}
|
||||||
|
<product-grid-item-image
|
||||||
|
class="
|
||||||
|
product-grid-item__image-wrapper
|
||||||
|
{% if visible %}{{ active_class }}{% endif %}
|
||||||
|
"
|
||||||
|
data-grid-image="{{ image_index }}"
|
||||||
|
data-grid-image-target="{{ media.id }}"
|
||||||
|
data-variant-id="{{ }}"
|
||||||
|
loading="{{ loading }}"
|
||||||
|
{% if visible %}data-grid-current-image{% endif %}
|
||||||
|
{% if is_selected_variant and visible %}
|
||||||
|
data-slide-for-filter-selected-variant
|
||||||
|
{% endif %}
|
||||||
|
{% if is_variant_featured_media %}
|
||||||
|
data-slide-for-variant-media
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
{% unless visible %}<template>{% endunless %}
|
||||||
|
|
||||||
|
{% render 'image',
|
||||||
|
cover: image_cover,
|
||||||
|
img_object: img_object,
|
||||||
|
class: class,
|
||||||
|
sizes: sizes,
|
||||||
|
srcset: srcset,
|
||||||
|
preload: preload_image,
|
||||||
|
loading: loading_image,
|
||||||
|
fetchpriority: fetchpriority,
|
||||||
|
wh_ratio: image_wh_ratio,
|
||||||
|
placeholder: placeholder
|
||||||
|
%}
|
||||||
|
{% unless visible %}</template>{% endunless %}
|
||||||
|
</product-grid-item-image>
|
||||||
|
{%- assign image_index = image_index | plus: 1 -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{% else %}
|
||||||
|
<div class="product-grid-item__image-wrapper is-active">
|
||||||
|
{% render 'image',
|
||||||
|
cover: image_cover,
|
||||||
|
img_object: null,
|
||||||
|
class: class,
|
||||||
|
placeholder: placeholder,
|
||||||
|
wh_ratio: image_wh_ratio
|
||||||
|
%}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ badge }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% capture quick_action_toolbar_classes %}
|
||||||
|
group/quick-actions-toolbar
|
||||||
|
absolute
|
||||||
|
flex flex-col justify-end items-end overflow-hidden
|
||||||
|
top-[calc(var(--inner)/2)]
|
||||||
|
right-[calc(var(--inner)/2)]
|
||||||
|
bottom-[calc(var(--inner)/2)]
|
||||||
|
left-[calc(var(--inner)/2)]
|
||||||
|
transition duration-[--exit-animation-duration]
|
||||||
|
md:items-normal
|
||||||
|
md:opacity-0
|
||||||
|
md:translate-y-r4
|
||||||
|
md:group-hover/product-grid-item:opacity-100
|
||||||
|
md:group-hover/product-grid-item:translate-y-0
|
||||||
|
md:group-focus-within/product-grid-item:opacity-100
|
||||||
|
md:group-focus-within/product-grid-item:translate-y-0
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Prevent pointer events on the outer <inline-add-product> element since it covers the whole card
|
||||||
|
and we only want the options menu to show when either the button wrapper or options menu itself
|
||||||
|
are still being hovered
|
||||||
|
{% endcomment %}
|
||||||
|
pointer-events-none
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
{% capture quick_action_button_classes %}
|
||||||
|
{{ settings.quick_add_button_color }}
|
||||||
|
group/quick-action-button
|
||||||
|
bg-button
|
||||||
|
flex items-center justify-center
|
||||||
|
type-accent font-bold text-r3
|
||||||
|
transition-opacity duration-[--enter-animation-duration]
|
||||||
|
pointer-events-auto
|
||||||
|
w-r12 aspect-square
|
||||||
|
min-w-[40px]
|
||||||
|
min-h-[40px]
|
||||||
|
md:min-h-[48px]
|
||||||
|
md:px-r8 md:py-r5 md:w-full md:aspect-auto
|
||||||
|
{% if sold_out %}opacity-50 !cursor-not-allowed{% endif %}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
{%- if instant_add_button %}
|
||||||
|
{% comment %} Allow for shorter default text on longer translations {% endcomment %}
|
||||||
|
{% liquid
|
||||||
|
if product.metafields.theme.preorder.value == true
|
||||||
|
assign button_text = 'products.general.instant_add_pre_order' | t
|
||||||
|
else
|
||||||
|
assign button_text = 'products.general.instant_add' | t
|
||||||
|
endif
|
||||||
|
%}
|
||||||
|
{% capture button %}
|
||||||
|
<button
|
||||||
|
data-add-to-cart
|
||||||
|
type="submit"
|
||||||
|
name="add"
|
||||||
|
class="{{ quick_action_button_classes }}"
|
||||||
|
:class="{
|
||||||
|
'has-success': isSuccess,
|
||||||
|
'loading': isLoading
|
||||||
|
}"
|
||||||
|
title="{% if sold_out %}{{ 'products.product.sold_out' | t }}{% else %}{{ button_text }}{% endif %}"
|
||||||
|
:disabled="{{sold_out}} || isDisabled"
|
||||||
|
aria-label="{{ button_text }}"
|
||||||
|
>
|
||||||
|
<span class="btn-state-ready text-button-contrast group-hover/quick-action-button:text-button-contrast/50 whitespace-nowrap">
|
||||||
|
<span class="hidden md:block">
|
||||||
|
{{ button_text }}
|
||||||
|
</span>
|
||||||
|
<span aria-hidden class="block md:hidden">
|
||||||
|
{% render 'icon-set-classic-cart' %}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="btn-state-loading">
|
||||||
|
<svg height="18" width="18" class="svg-loader" style="--border: rgb(var(--rgb-button-contrast) / 50%); --text: rgb(var(--rgb-button-contrast));">
|
||||||
|
<circle r="7" cx="9" cy="9" />
|
||||||
|
<circle stroke-dasharray="87.96459430051421 87.96459430051421" r="7" cx="9" cy="9" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span class="btn-state-complete" style="--primary: rgb(var(--rgb-button-contrast));"> </span>
|
||||||
|
</button>
|
||||||
|
{% endcapture %}
|
||||||
|
<div class="{{quick_action_toolbar_classes}}">
|
||||||
|
{% render 'product-add-button-form', variant: variant, selling_plan: simple_selling_plan, button: button, class: "md:w-full" %}
|
||||||
|
</div>
|
||||||
|
{%- elsif inline_variant_buttons %}
|
||||||
|
<div class="{{quick_action_toolbar_classes}}" x-data="productGridItemQuickAddMenu()">
|
||||||
|
<button
|
||||||
|
class="
|
||||||
|
{{ quick_action_button_classes }}
|
||||||
|
transition-opacity
|
||||||
|
"
|
||||||
|
title="{{ 'products.general.inline_add' | t }}"
|
||||||
|
aria-haspopup="true"
|
||||||
|
:aria-expanded="isOpen"
|
||||||
|
:id="$id('quick-add-menu-button')"
|
||||||
|
:aria-controls="$id('quick-add-menu-slideover')"
|
||||||
|
@click.stop="open()"
|
||||||
|
@mouseover="open()"
|
||||||
|
x-ref="button"
|
||||||
|
:class="
|
||||||
|
isOpen ?
|
||||||
|
'duration-[--enter-animation-duration] delay-0 opacity-0 md:opacity-100' :
|
||||||
|
'duration-[--exit-animation-duration] delay-[--exit-animation-duration] opacity-100'
|
||||||
|
"
|
||||||
|
aria-label="{{ 'products.general.inline_add' | t }}"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="
|
||||||
|
whitespace-nowrap
|
||||||
|
text-button-contrast
|
||||||
|
transition translate-y-0 transform
|
||||||
|
"
|
||||||
|
:class="
|
||||||
|
isOpen ?
|
||||||
|
'duration-[--enter-animation-duration] delay-0 translate-y-full opacity-0' :
|
||||||
|
'duration-[--exit-animation-duration] delay-[calc(var(--exit-animation-duration))] translate-y-0 opacity-100'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="hidden md:block">
|
||||||
|
{{ 'products.general.inline_add' | t }}
|
||||||
|
</span>
|
||||||
|
<span aria-hidden class="block md:hidden">
|
||||||
|
{% render 'icon-set-classic-cart' %}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="absolute top-0 right-0 bottom-0 left-0 overflow-hidden flex flex-col justify-end"
|
||||||
|
role="popover"
|
||||||
|
x-show="isOpen"
|
||||||
|
x-cloak
|
||||||
|
:aria-labelledby="$id('quick-add-menu-button')"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
{{ settings.quick_add_button_color }}
|
||||||
|
top-0 right-0 bottom-0 left-0 top-auto max-h-full overflow-scroll scrollbar-hide
|
||||||
|
pointer-events-auto
|
||||||
|
transition transform
|
||||||
|
absolute
|
||||||
|
origin-bottom
|
||||||
|
bg-button
|
||||||
|
md:opacity-100
|
||||||
|
"
|
||||||
|
x-show="isOpen"
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Animate outer slider up or down
|
||||||
|
{% endcomment %}
|
||||||
|
x-transition:enter="duration-[calc(var(--enter-animation-duration)*2)] delay-[calc(var(--enter-animation-duration)/2)]"
|
||||||
|
x-transition:enter-start="invisible translate-y-full opacity-0 md:opacity-100"
|
||||||
|
x-transition:enter-end="visible translate-y-0 opacity-100 md:opacity-100"
|
||||||
|
x-transition:leave="duration-[calc(var(--exit-animation-duration)*2)] delay-[calc(var(--exit-animation-duration)/4)]"
|
||||||
|
x-transition:leave-start="visible translate-y-0 opacity-100 md:opacity-100"
|
||||||
|
x-transition:leave-end="invisible translate-y-full opacity-0 md:opacity-100"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="transition transform"
|
||||||
|
x-show="isOpen"
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Stagger inner slider up/down animation so it animates _after_ outer slider
|
||||||
|
{% endcomment %}
|
||||||
|
x-transition:enter="duration-[calc(var(--enter-animation-duration)*2)] delay-[calc(var(--enter-animation-duration)/2)]"
|
||||||
|
x-transition:enter-start="translate-y-1/2 opacity-0"
|
||||||
|
x-transition:enter-end="translate-y-0 opacity-full"
|
||||||
|
x-transition:leave="duration-[calc(var(--exit-animation-duration))] delay-0"
|
||||||
|
x-transition:leave-start="translate-y-0 opacity-full"
|
||||||
|
x-transition:leave-end="translate-y-1/2 opacity-0"
|
||||||
|
>
|
||||||
|
{% render 'product-grid-item-quick-add-toolbar',
|
||||||
|
inline_variants: inline_variants,
|
||||||
|
inline_variant_buttons: inline_variant_buttons,
|
||||||
|
simple_selling_plan: simple_selling_plan
|
||||||
|
%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- elsif settings.quickview_enable -%}
|
||||||
|
<div class="{{quick_action_toolbar_classes}}" x-data="productQuickViewButton({{ product.id }}, '{{ product.handle }}')">
|
||||||
|
<div class="quickview md:w-full" data-quickview-holder="{{ product.id }}" data-add-action-wrapper>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="{{ quick_action_button_classes }}"
|
||||||
|
@click.prevent="clickQuickviewButton"
|
||||||
|
:class="{
|
||||||
|
'loading': isLoading
|
||||||
|
}"
|
||||||
|
title="{% if sold_out %}{{ 'products.product.sold_out' | t }}{% else %}{{ 'products.general.quick_view' | t }}{% endif %}"
|
||||||
|
:disabled="{{sold_out}} || isDisabled"
|
||||||
|
aria-label="{{ 'products.general.quick_view' | t }}"
|
||||||
|
>
|
||||||
|
<span class="btn-state-ready text-button-contrast group-hover/quick-action-button:text-button-contrast/50 whitespace-nowrap">
|
||||||
|
<span class="hidden md:block">
|
||||||
|
{{ 'products.general.quick_view' | t }}
|
||||||
|
</span>
|
||||||
|
<span aria-hidden class="block md:hidden">
|
||||||
|
{% render 'icon-set-classic-cart' %}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="btn-state-loading">
|
||||||
|
<svg height="18" width="18" class="svg-loader" style="--border: rgb(var(--rgb-button-contrast) / 50%); --text: rgb(var(--rgb-button-contrast));">
|
||||||
|
<circle r="7" cx="9" cy="9" />
|
||||||
|
<circle stroke-dasharray="87.96459430051421 87.96459430051421" r="7" cx="9" cy="9" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script data-quickview-modal-template type="text/x-template">
|
||||||
|
<div class="drawer drawer--right quickview__modal" data-quickview-modal data-form-holder id="{{ product.id }}" aria-hidden="true">
|
||||||
|
<div class="drawer__content" data-product-quickview-ajax x-section-api='api-product-quickview'></div>
|
||||||
|
|
||||||
|
<span class="drawer__underlay" data-micromodal-close tabindex="-1">
|
||||||
|
<span class="drawer__underlay__fill"></span>
|
||||||
|
<span class="drawer__underlay__blur"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
</product-grid-item-variant>
|
||||||
@@ -0,0 +1,670 @@
|
|||||||
|
<!-- /snippets/product-grid-item-variant.liquid -->
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
A grid item for products used in collection grid view
|
||||||
|
|
||||||
|
* product {object} - The current prodcut
|
||||||
|
|
||||||
|
{% render 'product-grid-item', product: product %}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
|
||||||
|
assign on_sale = false
|
||||||
|
assign product_price = product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
comment
|
||||||
|
start Yagi app
|
||||||
|
endcomment
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign product_price = product.metafields.app--168074346497.min_auto_discounted_price.value | default: product.price
|
||||||
|
assign product_compare_at_price = product.compare_at_price
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
assign product_price = product.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if product_price < product.price and product_compare_at_price == 0 or product_compare_at_price == blank
|
||||||
|
assign product_compare_at_price = product.price
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
comment
|
||||||
|
end Yagi app
|
||||||
|
endcomment
|
||||||
|
|
||||||
|
if product_compare_at_price > product_price
|
||||||
|
assign on_sale = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sold_out = true
|
||||||
|
if product.available
|
||||||
|
assign sold_out = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Siblings are a collection metafield called theme.siblings
|
||||||
|
assign sibs_collection = nil
|
||||||
|
assign has_siblings = false
|
||||||
|
if settings.show_siblings and product.metafields.theme.siblings.value != blank and product.metafields.theme.siblings.type == 'single_line_text_field'
|
||||||
|
assign sibs_collection = collections[product.metafields.theme.siblings.value]
|
||||||
|
# Ensure the collection was set up to contain this product
|
||||||
|
for sib_product in sibs_collection.products
|
||||||
|
if sib_product == product
|
||||||
|
assign has_siblings = true
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign swatch_option = nil
|
||||||
|
assign has_swatches = false
|
||||||
|
assign swatch_limit = settings.card_swatch_limit
|
||||||
|
|
||||||
|
if settings.swatches_enable and settings.swatches_collection_enable
|
||||||
|
# Detect new swatch system
|
||||||
|
for option in product.options_with_values
|
||||||
|
if option.values.first.swatch != null
|
||||||
|
assign has_swatches = true
|
||||||
|
assign swatch_option = option
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if has_swatches == false
|
||||||
|
# Detect old swatch system
|
||||||
|
assign swatch_translation = 'general.swatches.color' | t
|
||||||
|
assign swatch_labels = swatch_translation | append: ',' | split: ','
|
||||||
|
for label in swatch_labels
|
||||||
|
assign sanitized_label = label | lstrip | rstrip
|
||||||
|
if product.options_by_name[sanitized_label].values.size > 0
|
||||||
|
assign has_swatches = true
|
||||||
|
assign swatch_option = product.options_by_name[sanitized_label]
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# A button that will add to cart immediately: product with only one default variant or a product with color swatches and no other variants
|
||||||
|
assign instant_add_button = nil
|
||||||
|
|
||||||
|
if settings.instant_add_enable
|
||||||
|
if product.variants.size == 1
|
||||||
|
assign instant_add_button = true
|
||||||
|
elsif has_swatches and product.options.size == 1
|
||||||
|
assign instant_add_button = true
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# A quick add button that will show short variants like 'size' inside the button.
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
|
||||||
|
# Get the non color option
|
||||||
|
# swatch_option.position -> 1 is off by one, it means product.options[0]
|
||||||
|
# In case of siblings, the inline option buttons always use the first option
|
||||||
|
if settings.instant_add_enable
|
||||||
|
if product.options.size == 1
|
||||||
|
assign inline_variant_buttons = product.options_with_values[0]
|
||||||
|
elsif has_swatches and product.options.size == 2
|
||||||
|
if swatch_option.position == 1
|
||||||
|
assign inline_variant_buttons = product.options_with_values[1]
|
||||||
|
else
|
||||||
|
assign inline_variant_buttons = product.options_with_values[0]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Capture the swatch link markup so we only have filter product.variants by color one time
|
||||||
|
assign swatch_link_markup = ''
|
||||||
|
|
||||||
|
# Pass pre-filtered color variants into content, because the logic needs to know about
|
||||||
|
# swatch option positions and swatches need to use the where filter to get the list
|
||||||
|
assign inline_variants = nil
|
||||||
|
|
||||||
|
# Placeholder to be displayed when no product image
|
||||||
|
assign placeholder = placeholder | default: false
|
||||||
|
-%}
|
||||||
|
|
||||||
|
<product-grid-item
|
||||||
|
aria-label="{{ product.title | strip_html | escape }}"
|
||||||
|
class="product-grid-item group/product-grid-item"
|
||||||
|
data-item-id="{{ product.id }}"
|
||||||
|
{{ attributes }}
|
||||||
|
>
|
||||||
|
{% if has_siblings and sibs_collection.products.size > 0 %}
|
||||||
|
{%- liquid
|
||||||
|
# Initialize an empty array to hold visible siblings (i.e. ones under swatch limit)
|
||||||
|
assign visible_siblings = "" | split: ","
|
||||||
|
|
||||||
|
# Initial visible sibling count is 1 to account for the current product
|
||||||
|
assign visible_sibling_count = 1
|
||||||
|
|
||||||
|
# Loop through siblings collection and add the current product, plus other siblings until we hit the swatch_limit
|
||||||
|
for sibling in sibs_collection.products
|
||||||
|
if sibling.id == product.id or visible_sibling_count < swatch_limit
|
||||||
|
# Create a new array with the current value, then concat it into the main array
|
||||||
|
assign new_array = sibling | sort
|
||||||
|
assign visible_siblings = visible_siblings | concat: new_array
|
||||||
|
|
||||||
|
unless sibling.id == product.id
|
||||||
|
assign visible_sibling_count = visible_sibling_count | plus: 1
|
||||||
|
endunless
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- for sib_product in visible_siblings -%}
|
||||||
|
{% liquid
|
||||||
|
assign visible = false
|
||||||
|
assign first_sibling_variant = sib_product.variants[0]
|
||||||
|
if sib_product.id == product.id
|
||||||
|
assign visible = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
if visible and preload
|
||||||
|
assign preload_variant = true
|
||||||
|
endif
|
||||||
|
if visible and eagerload
|
||||||
|
assign eagerload_variant = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign inline_variant_buttons = nil
|
||||||
|
if settings.instant_add_enable and sib_product.options.size == 1
|
||||||
|
assign inline_variant_buttons = sib_product.options_with_values[0]
|
||||||
|
endif
|
||||||
|
|
||||||
|
if inline_variant_buttons
|
||||||
|
assign inline_variants = sib_product.variants
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{% render 'product-grid-item-variant',
|
||||||
|
product: sib_product,
|
||||||
|
variant: first_sibling_variant,
|
||||||
|
badge_string: badge_string,
|
||||||
|
visible: visible,
|
||||||
|
instant_add_button: instant_add_button,
|
||||||
|
inline_variant_buttons: inline_variant_buttons,
|
||||||
|
inline_variants: inline_variants,
|
||||||
|
section_width: section_width,
|
||||||
|
eagerload: eagerload_variant,
|
||||||
|
preload: preload_variant,
|
||||||
|
placeholder: placeholder,
|
||||||
|
columns_desktop: columns_desktop,
|
||||||
|
columns_tablet: columns_tablet,
|
||||||
|
columns_mobile: columns_mobile
|
||||||
|
%}
|
||||||
|
{% endfor %}
|
||||||
|
{% elsif has_swatches %}
|
||||||
|
{%- liquid
|
||||||
|
|
||||||
|
# Note: this is a hack based on options having a property named option1, option2, or option3 -- which we rely on below to filter the variants array
|
||||||
|
assign swatch_position_key = 'option' | append: swatch_option.position
|
||||||
|
assign selected_swatch_value = swatch_option.selected_value
|
||||||
|
|
||||||
|
# Initialize an empty array to hold visible siblings (i.e. ones under swatch limit)
|
||||||
|
assign visible_swatches = "" | split: ","
|
||||||
|
|
||||||
|
# If there is a selected swatch, start the visible swatch count at 1 to account for it
|
||||||
|
if selected_swatch_value != blank
|
||||||
|
assign visible_swatch_count = 1
|
||||||
|
else
|
||||||
|
assign visible_swatch_count = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Loop through siblings collection and add the current product, plus other swatches until we hit the swatch limit
|
||||||
|
for swatch_value in swatch_option.values
|
||||||
|
if swatch_value == selected_swatch_value or visible_swatch_count < swatch_limit
|
||||||
|
# Create a new array with the current value, then concat it into the main array
|
||||||
|
assign new_array = swatch_value | sort
|
||||||
|
assign visible_swatches = visible_swatches | concat: new_array
|
||||||
|
|
||||||
|
unless swatch_value == selected_swatch_value
|
||||||
|
assign visible_swatch_count = visible_swatch_count | plus: 1
|
||||||
|
endunless
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{%- for swatch_value in visible_swatches -%}
|
||||||
|
{% liquid
|
||||||
|
|
||||||
|
# Limit S|M|L to low-variant products to ensure collection page performance
|
||||||
|
if product.variants.size < 200
|
||||||
|
assign this_color_variants = product.variants | where: swatch_position_key, swatch_value
|
||||||
|
assign in_stock_options = this_color_variants | where: 'available'
|
||||||
|
if inline_variant_buttons
|
||||||
|
assign inline_variants = this_color_variants
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# Fall back to quickview with section-rendering API variant selection if there's too many variants
|
||||||
|
assign inline_variant_buttons = false
|
||||||
|
assign inline_variants = nil
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Use the default variant for the swatch value. If that variant has media attached the image will change.
|
||||||
|
# If not, the variant image will not change when swatch is selected.
|
||||||
|
assign current_variant = swatch_value.variant
|
||||||
|
|
||||||
|
# If there is a variant selected from filters, show that variant first
|
||||||
|
assign visible = false
|
||||||
|
if product.selected_variant.id == current_variant
|
||||||
|
assign visible = true
|
||||||
|
elsif forloop.first
|
||||||
|
assign visible = true
|
||||||
|
endif
|
||||||
|
|
||||||
|
if visible and preload
|
||||||
|
assign preload_variant = true
|
||||||
|
endif
|
||||||
|
if visible and eagerload
|
||||||
|
assign eagerload_variant = true
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{% render 'product-grid-item-variant',
|
||||||
|
product: product,
|
||||||
|
variant: current_variant,
|
||||||
|
badge_string: badge_string,
|
||||||
|
visible: visible,
|
||||||
|
instant_add_button: instant_add_button,
|
||||||
|
inline_variant_buttons: inline_variant_buttons,
|
||||||
|
inline_variants: inline_variants,
|
||||||
|
section_width: section_width,
|
||||||
|
swatch_option: swatch_option,
|
||||||
|
eagerload: eagerload_variant,
|
||||||
|
preload: preload_variant,
|
||||||
|
placeholder: placeholder,
|
||||||
|
columns_desktop: columns_desktop,
|
||||||
|
columns_tablet: columns_tablet,
|
||||||
|
columns_mobile: columns_mobile
|
||||||
|
%}
|
||||||
|
|
||||||
|
{% capture swatch_link_markup %}
|
||||||
|
{{ swatch_link_markup }}
|
||||||
|
<radio-swatch title="{{ swatch_value.name }}" class="swatch__button{% if in_stock_options.size == 0 %} sold-out{% endif %}{% if settings.swatches_squares %} swatch__button--square{% endif %}">
|
||||||
|
<a
|
||||||
|
href="{{ current_variant.url }}"
|
||||||
|
class="swatch__label"
|
||||||
|
{% if swatch_value.swatch != null %}
|
||||||
|
data-swatch
|
||||||
|
style="--swatch: {{ swatch_value.swatch.color }}"
|
||||||
|
{% else %}
|
||||||
|
data-swatch="{{ swatch_value | escape_once }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
data-grid-item-variant="{{ current_variant.id }}"
|
||||||
|
data-swatch-index="{{ forloop.index0 }}"
|
||||||
|
|
||||||
|
{% if visible %}aria-current="true"{%- endif -%}
|
||||||
|
{% if current_variant.featured_media %}
|
||||||
|
data-swatch-image="{{ current_variant.featured_media.preview_image.src }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if current_variant.featured_media %}
|
||||||
|
data-swatch-image-id="{{ current_variant.featured_media.id }}"
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
{% if swatch_value.swatch.image %}
|
||||||
|
{% render 'image', img_object: swatch_value.swatch.image, width: 34, wh_ratio: 1 %}
|
||||||
|
{% endif %}
|
||||||
|
<span class="visually-hidden">{{ swatch_value }}</span>
|
||||||
|
</a>
|
||||||
|
</radio-swatch>
|
||||||
|
{% endcapture %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{%- liquid
|
||||||
|
|
||||||
|
# Limit S|M|L to low-variant products to ensure collection page performance
|
||||||
|
if inline_variant_buttons and product.variants.size < 200
|
||||||
|
assign inline_variants = product.variants
|
||||||
|
else
|
||||||
|
assign inline_variant_buttons = false
|
||||||
|
assign inline_variants = nil
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign selected_variant = product.selected_variant | default: product.variants[0]
|
||||||
|
|
||||||
|
if preload
|
||||||
|
assign preload_variant = true
|
||||||
|
endif
|
||||||
|
if eagerload
|
||||||
|
assign eagerload_variant = true
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
{% render 'product-grid-item-variant',
|
||||||
|
product: product,
|
||||||
|
variant: selected_variant,
|
||||||
|
badge_string: badge_string,
|
||||||
|
visible: true,
|
||||||
|
instant_add_button: instant_add_button,
|
||||||
|
inline_variant_buttons: inline_variant_buttons,
|
||||||
|
inline_variants: inline_variants,
|
||||||
|
section_width: section_width,
|
||||||
|
preload: preload_variant,
|
||||||
|
eagerload: eagerload_variant,
|
||||||
|
placeholder: placeholder,
|
||||||
|
columns_desktop: columns_desktop,
|
||||||
|
columns_tablet: columns_tablet,
|
||||||
|
columns_mobile: columns_mobile
|
||||||
|
%}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="product__grid__info {{ text_align | default: settings.collection_text_alignment | default: 'text-center' }}">
|
||||||
|
<a
|
||||||
|
href="{{ product.url }}" data-grid-link aria-label="{{ product.title | strip_html | escape }}"
|
||||||
|
{% comment %} The link wrapping the product variant image is already focusable, so this does not need to be {% endcomment %}
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<p class="visually-hidden">{{ product.title | strip_html | escape }}</p>
|
||||||
|
|
||||||
|
<div class="product__grid__title__wrapper">
|
||||||
|
<p id="product-{{ product.id }}-title" class="product__grid__title">
|
||||||
|
{{ product.title | strip_html | escape }}
|
||||||
|
</p>
|
||||||
|
{%- if settings.product_grid_show_rating and product.metafields.reviews.rating.value != blank -%}
|
||||||
|
<div class="rating__wrapper__grid">
|
||||||
|
{% render 'product-rating', product: product, show_rating_count: settings.product_grid_show_rating_count %}
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="product__grid__price {% if settings.show_cutline %} product__grid__price--nowrap{% endif %}">
|
||||||
|
{%- if settings.show_cutline -%}
|
||||||
|
<span class="product__grid__cutline">{{ product.metafields.theme.cutline.value }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
<span class="price{% if on_sale %} on-sale{% endif %}">
|
||||||
|
{% if product.price_varies %}{{ 'products.general.from' | t }} {% endif %}
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ product_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ product_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{% if on_sale %}
|
||||||
|
<span class="compare-at">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ product_compare_at_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ product_compare_at_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if product.selected_or_first_available_variant.unit_price %}
|
||||||
|
{% capture unit_price_separator %}
|
||||||
|
<span aria-hidden="true">/</span><span class="visually-hidden">{{ 'general.accessibility.unit_price_separator' | t }} </span>
|
||||||
|
{% endcapture %}
|
||||||
|
{% capture unit_price_base_unit %}
|
||||||
|
{% if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 %}
|
||||||
|
{{ product.selected_or_first_available_variant.unit_price_measurement.reference_value }}
|
||||||
|
{% endif %}
|
||||||
|
{{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
|
||||||
|
{% endcapture %}
|
||||||
|
<p class="product__grid__price__unit">
|
||||||
|
<span class="visually-hidden">{{ 'products.product.unit_price_label' | t }}</span>
|
||||||
|
<span class="price-per-unit">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ product.selected_or_first_available_variant.unit_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ product.selected_or_first_available_variant.unit_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
{{ unit_price_separator }}{{ unit_price_base_unit }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% comment %} {% if sold_out %}
|
||||||
|
<p class="product__grid__price__sold">
|
||||||
|
<em>{{ 'products.product.sold_out' | t }}</em>
|
||||||
|
</p>
|
||||||
|
{% endif %} {% endcomment %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% assign active_variant = product.selected_or_first_available_variant %}
|
||||||
|
|
||||||
|
<div class="product-card__actions mt-2">
|
||||||
|
{%- form 'product', product, class: 'product-card__atc-form', novalidate: 'novalidate', data-type: 'add-to-cart-form', is: 'product-form' -%}
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="id"
|
||||||
|
value="{{ active_variant.id }}"
|
||||||
|
{% if active_variant.available == false %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
name="add"
|
||||||
|
class="product-card__atc"
|
||||||
|
{% if active_variant.available == false %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
{%- if active_variant.available -%}
|
||||||
|
{{ 'products.product.add_to_cart' | t }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ 'products.product.sold_out' | t }}
|
||||||
|
{%- endif -%}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{%- endform -%}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{%- if has_siblings -%}
|
||||||
|
{%- assign sibs_collection = collections[product.metafields.theme.siblings.value] -%}
|
||||||
|
{% if sibs_collection != blank %}
|
||||||
|
{%- assign excess_swatches = sibs_collection.products_count | minus: swatch_limit -%}
|
||||||
|
<div class="product__grid__sibs">
|
||||||
|
<div class="grid__swatch__container">
|
||||||
|
<p class="grid__swatch__placeholder">{{ 'collections.general.swatches_with_count' | t: count: sibs_collection.products_count }}</p>
|
||||||
|
<div class="grid__swatch__hover">
|
||||||
|
<div class="sibs__slider">
|
||||||
|
<div class="sibs__inner">
|
||||||
|
{%- for sib_product in visible_siblings -%}
|
||||||
|
{%- assign title_safe = sib_product.title | strip_html | escape -%}
|
||||||
|
{%- assign color_name = sib_product.metafields.theme.cutline.value | default: title_safe -%}
|
||||||
|
<div class="siblings__link__holder {% if sib_product.available == false %} sold-out{% endif %}">
|
||||||
|
<a
|
||||||
|
href="{{ sib_product.url }}"
|
||||||
|
class="siblings__link"
|
||||||
|
data-sibling-swatch-link
|
||||||
|
data-grid-item-variant="{{ sib_product.variants[0].id }}"
|
||||||
|
data-grid-item-swatch-image="0"
|
||||||
|
title="{{ color_name }}"
|
||||||
|
{% if sib_product.handle == product.handle %}aria-current="true"{%- endif -%}
|
||||||
|
>
|
||||||
|
<div class="siblings__swatch">
|
||||||
|
<div class="sibling__image{% if settings.swatches_squares %} sibling__image--square{% endif %}">
|
||||||
|
{% assign image = sib_product.featured_media.preview_image %}
|
||||||
|
{% assign image_width = 26 %}
|
||||||
|
{% assign image_width_2x = image_width | times: 2 | at_most: image.width %}
|
||||||
|
{% assign alt = image.alt | default: color_name %}
|
||||||
|
|
||||||
|
{% capture srcset %}
|
||||||
|
{{ image | image_url: width: image_width_2x }} 2x,
|
||||||
|
{{ image | image_url: width: image_width }}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
{%- render 'image',
|
||||||
|
img_object: image,
|
||||||
|
wh_ratio: 1.0,
|
||||||
|
srcset: srcset,
|
||||||
|
fetchpriority: 'low',
|
||||||
|
width: image_width,
|
||||||
|
placeholder: placeholder,
|
||||||
|
alt: alt
|
||||||
|
-%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{%- endfor -%}
|
||||||
|
{% if excess_swatches > 0 %} <a class="siblings__more-link" href="{{product.url}}">+{{ excess_swatches }}</a>{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{%- elsif has_swatches and swatch_link_markup != '' -%}
|
||||||
|
{%- assign excess_swatches = swatch_option.values.size | minus: swatch_limit -%}
|
||||||
|
|
||||||
|
<div class="grid__swatch__container">
|
||||||
|
<p class="grid__swatch__placeholder">
|
||||||
|
{{ 'collections.general.swatches_with_count' | t: count: swatch_option.values.size }}
|
||||||
|
</p>
|
||||||
|
<div class="grid__swatch__hover" aria-label="Options">
|
||||||
|
{{ swatch_link_markup }} {% if excess_swatches > 0 %}
|
||||||
|
<a class="grid__swatch__more-link" href="{{product.url}}">+{{ excess_swatches }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
||||||
|
</product-grid-item>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.product-card__actions {
|
||||||
|
position: static !important;
|
||||||
|
margin-top: 1rem;
|
||||||
|
opacity: 1 !important;
|
||||||
|
transform: none !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.product-card__actions {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
.product-card__atc {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__actions .product-card__atc {
|
||||||
|
width: 100% !important;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #000 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0.5rem 1.25rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
min-height: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
|
font-family: var(--FONT-STACK-BODY);
|
||||||
|
font-style: var(--FONT-STYLE-BODY);
|
||||||
|
font-weight: var(--FONT-WEIGHT-BODY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.product-card__actions .product-card__atc {
|
||||||
|
padding: 0.45rem 1rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__actions .product-card__atc:hover,
|
||||||
|
.product-card__actions .product-card__atc:focus {
|
||||||
|
background-color: #111 !important;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__actions .product-card__atc[disabled] {
|
||||||
|
background-color: #555 !important;
|
||||||
|
color: #ccc !important;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card:not(.product-card--list) .product-card__actions .btn {
|
||||||
|
opacity: 1 !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
transform: none !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__main-actions {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === Fix product card squishing on small screens === */
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.collection-products .product-grid,
|
||||||
|
.collection-products .grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-products .product-card {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.collection-products .product-grid,
|
||||||
|
.collection-products .grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card,
|
||||||
|
.product-card__wrapper {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__image-wrapper { flex: 0 0 auto; }
|
||||||
|
.product-card__info { flex: 1 1 auto; display: flex; flex-direction: column; }
|
||||||
|
.product-card__actions { margin-top: auto; }
|
||||||
|
|
||||||
|
.product__grid__title {
|
||||||
|
line-height: 1.3;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: calc(1.3em * 2); /* ensures same vertical space even if short */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2; /* clamp to 2 lines */
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports not (-webkit-line-clamp: 2) {
|
||||||
|
.product__grid__title { max-height: calc(1.3em * 2); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card__type,
|
||||||
|
.f-price { white-space: normal; word-break: break-word; }
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
<!-- /snippets/product-price.liquid -->
|
||||||
|
{%- liquid
|
||||||
|
assign current_variant = product.selected_or_first_available_variant
|
||||||
|
assign price = current_variant.price
|
||||||
|
assign compare_at_price = current_variant.compare_at_price
|
||||||
|
|
||||||
|
comment
|
||||||
|
start Yagi app code
|
||||||
|
endcomment
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
|
||||||
|
if product.metafields.app--168074346497.segment_tags.value.size > 0
|
||||||
|
assign public_or_tags_matched = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
for etag in product.metafields.app--168074346497.segment_tags.value
|
||||||
|
if customer.tags contains etag
|
||||||
|
assign public_or_tags_matched = true
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
if public_or_tags_matched
|
||||||
|
assign price = current_variant.metafields.app--168074346497.auto_discounted_price.value | default: current_variant.price
|
||||||
|
assign compare_at_price = current_variant.compare_at_price
|
||||||
|
|
||||||
|
if shop.metafields.app--168074346497.discount_percentage.value > 0.005
|
||||||
|
assign discount_percentage = shop.metafields.app--168074346497.discount_percentage.value | times: 1.0
|
||||||
|
assign deducted_percentage = 1.0 | minus: discount_percentage
|
||||||
|
assign price = current_variant.price | divided_by: 100.0 | times: deducted_percentage | times: 100.0 | ceil
|
||||||
|
endif
|
||||||
|
|
||||||
|
if price < current_variant.price and compare_at_price == 0 or compare_at_price == blank
|
||||||
|
assign compare_at_price = current_variant.price
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
comment
|
||||||
|
end Yagi app code
|
||||||
|
endcomment
|
||||||
|
|
||||||
|
assign sale_type = settings.badge_sale_type
|
||||||
|
|
||||||
|
if block.settings.price_size
|
||||||
|
assign price_size_class = block.settings.price_size | prepend: 'accent-size-'
|
||||||
|
assign price_small_class = block.settings.price_size | minus: 1 | prepend: 'accent-size-'
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Select current selling plan if it's specified in the URL
|
||||||
|
assign selected_selling_plan = product.selected_selling_plan
|
||||||
|
if product.requires_selling_plan
|
||||||
|
# Fallback to the first available selling plan
|
||||||
|
assign selected_selling_plan = product.selected_or_first_available_selling_plan_allocation.selling_plan | default: product.selling_plan_groups[0].selling_plans[0]
|
||||||
|
endif
|
||||||
|
|
||||||
|
assign sale_text = 'products.product.sale' | t
|
||||||
|
|
||||||
|
# Subscription price
|
||||||
|
if selected_selling_plan
|
||||||
|
assign sale_text = 'products.product.subscription' | t
|
||||||
|
|
||||||
|
# Make sure the variant exists(it isn't 'unavailable') and showing a price makes sense
|
||||||
|
if current_variant
|
||||||
|
assign price_adjustment = selected_selling_plan.price_adjustments[0]
|
||||||
|
|
||||||
|
case price_adjustment.value_type
|
||||||
|
when 'percentage'
|
||||||
|
assign sale_type = 'percentage'
|
||||||
|
assign plan_discount_amount = price | times: price_adjustment.value | divided_by: 100
|
||||||
|
assign compare_at_price = price
|
||||||
|
assign price = compare_at_price | minus: plan_discount_amount
|
||||||
|
when 'fixed_amount'
|
||||||
|
assign sale_type = 'dollar'
|
||||||
|
assign compare_at_price = price
|
||||||
|
assign price = compare_at_price | minus: price_adjustment.value
|
||||||
|
when 'price'
|
||||||
|
assign sale_type = 'dollar'
|
||||||
|
assign compare_at_price = price
|
||||||
|
assign price = price_adjustment.value
|
||||||
|
endcase
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
-%}
|
||||||
|
|
||||||
|
<div class="product__block__price" style="--PB: {{ block.settings.padding_bottom }}px;" {{ block.shopify_attributes }}>
|
||||||
|
<div class="product__price__wrap">
|
||||||
|
<div class="product__price__main" data-price-wrapper>
|
||||||
|
<span class="product__price {{ price_size_class }}">
|
||||||
|
<span data-product-price {% if compare_at_price > price %} class="product__price--sale"{% endif %}>
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if compare_at_price > price or product.selected_selling_plan %}
|
||||||
|
{% case sale_type %}
|
||||||
|
{% when 'strike' %}
|
||||||
|
<span data-compare-price class="product__price--compare {{ price_size_class }}">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ compare_at_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ compare_at_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{% when 'percentage' %}
|
||||||
|
{% assign difference = compare_at_price | minus: price %}
|
||||||
|
{% assign percent_off = difference | times: 100 | divided_by: compare_at_price %}
|
||||||
|
<span class="product__price--off">
|
||||||
|
<span>{{ sale_text }}</span>
|
||||||
|
{% if percent_off > 0 %}
|
||||||
|
<em>•</em>
|
||||||
|
{{ 'products.product.save' | t }}
|
||||||
|
<span>{{ percent_off | floor | append: '%' }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% when 'dollar' %}
|
||||||
|
{% assign amount_off = compare_at_price | minus: price %}
|
||||||
|
<span class="product__price--off">
|
||||||
|
<span>{{ sale_text }}</span>
|
||||||
|
<em>•</em>
|
||||||
|
{{ 'products.product.save' | t }}
|
||||||
|
<span>{{ amount_off | money }}</span>
|
||||||
|
</span>
|
||||||
|
{% endcase %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if current_variant.unit_price != blank %}
|
||||||
|
{% capture show_units %}
|
||||||
|
{%- unless current_variant.unit_price -%}style="display: none;"{%- endunless -%}
|
||||||
|
{% endcapture %}
|
||||||
|
{% capture unit_price_separator %}
|
||||||
|
<span aria-hidden="true">/</span><span class="visually-hidden">{{ 'general.accessibility.unit_price_separator' | t }} </span>
|
||||||
|
{% endcapture %}
|
||||||
|
{% capture unit_price_base_unit %}
|
||||||
|
<span>
|
||||||
|
{% if current_variant.unit_price_measurement %}
|
||||||
|
{% if current_variant.unit_price_measurement.reference_value != 1 %}
|
||||||
|
{{ current_variant.unit_price_measurement.reference_value }}
|
||||||
|
{%- endif -%}
|
||||||
|
{{ current_variant.unit_price_measurement.reference_unit }}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% endcapture %}
|
||||||
|
<div class="product__price--unit {{ price_small_class }}">
|
||||||
|
<span data-product-unit {{ show_units }}>
|
||||||
|
<span class="visually-hidden visually-hidden--inline">{{ 'products.product.unit_price_label' | t }}</span>
|
||||||
|
<span data-product-unit-price id="unit-price-{{ block.id }}">
|
||||||
|
{%- if settings.currency_code_enable -%}
|
||||||
|
{{ current_variant.unit_price | money_with_currency }}
|
||||||
|
{%- else -%}
|
||||||
|
{{ current_variant.unit_price | money }}
|
||||||
|
{%- endif -%}
|
||||||
|
</span>
|
||||||
|
{{ unit_price_separator }}
|
||||||
|
<span data-product-base id="unit-price-base-{{ block.id }}">{{ unit_price_base_unit }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="hide">
|
||||||
|
{{ 'products.product.each' | t }}
|
||||||
|
<span></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user