add variant card product

card-product.liquid
 {% comment %} add option h  {% endcomment %}
            

              {% comment %} {%- if has_size_option -%} {% endcomment %}
                <product-form data-section-id="{{ section.id }}" data-product-id="{{ card_product.id }}">
                   {% form 'product', card_product, class: 'js-card-add-to-cart' %}
                    <div class="card-variant-sizes">
                      {%- for option in card_product.options_with_values -%}
                        {% if option.name == 'Size' or option.name == 'Größe' or option.name == 'size'  or  option.name == 'Contents'    or  option.name == 'Inhalt'   %}
                          {%- for value in option.values -%}
                            {%- assign variant_available = false -%}
                            {%- for v in card_product.variants -%}
                              {%- if v.options contains value and v.available -%}
                                {%- assign variant_available = true -%}
                              {%- endif -%}
                            {%- endfor -%}

                            <label class="size-label {% unless variant_available %}soldout{% endunless %}">
                              <input 
                                type="radio"    data-option-index="{{ forloop.parentloop.index }}"
                                name="variant-{{ card_product.id }}" 
                                value="{{ value }}"
                                {% if option.selected_value == value %}checked{% endif %}
                                {% unless variant_available %}disabled{% endunless %}
                              >
                              <span>{{ value }}</span>
                              {%- assign img_url = blank -%}

                              {%- for variant in card_product.variants -%}
                                {%- if variant.options contains value -%}
                                  {%- if variant.image -%}
                                    {%- assign img_url = variant.image | image_url: width: 600 -%}
                                  {%- endif -%}
                                  {%- break -%}
                                {%- endif -%}
                              {%- endfor -%}
                              {%- if img_url == blank and product.featured_image -%}
                                {%- assign img_url = card_product.featured_image | image_url: width: 600 -%}
                              {%- endif -%}

                              <span
                                  data-image="{{ img_url }}"
                                  data-product-url="{{ product.url }}"
                                  data-title="{{ value }}"
                                  class="color-custom color-option {% if is_white %}border-white-css{% endif %}"
                                  style="{{ bg_style }}">
                                  
                              </span>
                            </label>
                            
                          {%- endfor -%}
                        {% endif %}
                      {%- endfor -%}
                    </div>

                    <!-- hidden variant id input (updated by JS) -->
                    <input type="hidden" name="id" value="{{ card_product.selected_or_first_available_variant.id }}">

                    <!-- Add to cart button -->
                    <button type="submit" name="add" class=" add-to-cart-btn">
                      {{ 'shopping-bag-custom.svg' | inline_asset_content }}
                    </button>
                  {% endform %}
                </product-form>
              {% comment %} {%- endif -%} {% endcomment %}

              <script type="application/json" class="product-variants-json">
                {{ card_product.variants | json }}
              </script>
                {% comment %} add option h  {% endcomment %} 
             <div class="card-price" data-price-wrapper>
              {% render 'price', prod
js


<script>
{% comment %} function formatMoney(cents) {
  if (cents === null || cents === undefined) return '';
  return (cents / 100).toLocaleString("en-US", {
    style: "currency",
    currency: {{ cart.currency.iso_code | json }}
  });
} {% endcomment %}

function formatMoney(cents) {
  if (cents === null || cents === undefined) return '';

  return (cents / 100).toLocaleString("de-DE", {
    style: "currency",
    currency: {{ cart.currency.iso_code | json }}
  });
}
function updateCardVariant(inputEl) {
  if (!inputEl) return;

  const form = inputEl.closest("product-form");
  if (!form) return;

  const root = form.parentElement;
  const label = inputEl.closest('.size-label');

  // ACTIVE label (only inside this product card)
  root.querySelectorAll('.size-label.active').forEach(l => l.classList.remove('active'));
  if (label) label.classList.add('active');

  // Find variants JSON (same parentElement in your markup)
  const jsonEl = root.querySelector(".product-variants-json");
  if (!jsonEl) return;

  const variants = JSON.parse(jsonEl.textContent || '[]');
  if (!variants.length) return;

  const selectedValue = (inputEl.value || '').trim();
  if (!selectedValue) return;

  //from your input
  const optIndex = parseInt(inputEl.getAttribute('data-option-index') || '1', 10);

  const matched = variants.find(v => {
    const o1 = (v.option1 || '').trim();
    const o2 = (v.option2 || '').trim();
    const o3 = (v.option3 || '').trim();

    if (optIndex === 1) return o1 === selectedValue;
    if (optIndex === 2) return o2 === selectedValue;
    if (optIndex === 3) return o3 === selectedValue;

    return false;
  });

  if (!matched) return;

  // Update hidden variant id (Add to cart uses this!)
  const idInput = form.querySelector('input[name="id"]');
  if (idInput) idInput.value = matched.id;

  // Update price
  const wrapper = root.querySelector("[data-price-wrapper]");
  if (wrapper) {
    const cmp = matched.compare_at_price;
    const pr = matched.price;

    wrapper.innerHTML = (cmp && cmp > pr)
      ? `<div class="price price--on-sale">
           <div class="price__sale">
             <s class="price-item price-item--regular">${formatMoney(cmp)}</s>
             <span class="price-item price-item--sale">${formatMoney(pr)}</span>
           </div>
         </div>`
      : `<div class="price"><div class="price__regular">
           <span class="price-item price-item--regular">${formatMoney(pr)}</span>
         </div></div>`;
  }
}

// 1) Normal change (works when selecting a different option)
document.addEventListener("change", function(e) {
  if (!e.target.matches('[name^="variant-"]')) return;
  updateCardVariant(e.target);
});

// clicking on an already-checked radio should still update price/id
document.addEventListener("click", function(e) {
  const label = e.target.closest('.card-variant-sizes .size-label');
  if (!label) return;

  const input = label.querySelector('input[type="radio"][name^="variant-"]');
  if (!input) return;

  // If it's already checked, "change" won't fire → update manually
  if (input.checked) {
    updateCardVariant(input);
  } else {
    // Ensure check + then update
    input.checked = true;
    updateCardVariant(input);
  }
});

 Optional: auto-initialize on page load so default (50ml) shows correct price immediately
document.addEventListener("DOMContentLoaded", function() {
  document.querySelectorAll('product-form').forEach(function(pf){
    const input = pf.querySelector('input[type="radio"][name^="variant-"]:checked');
    if (input) updateCardVariant(input);
  });
});
</script>
main.js

  // cusom variant //

  // Custom variant image preview/persist per product card
// - Hover: preview only, revert to current "base" image on mouseleave
// - Click: persist, and update "base" image to the clicked option

function setCardImages($card, url) {
  var $mediaImgs = $card.find('.media--hover-effect img');
  $mediaImgs.each(function () {
    $(this).attr('src', url).attr('srcset', url);
  });
}

function cacheBaseImages($card) {
  var $mediaImgs = $card.find('.media--hover-effect img');

  // Cache base src/srcset once
  $mediaImgs.each(function () {
    var $img = $(this);
    if (!$img.attr('data-base-src')) $img.attr('data-base-src', $img.attr('src') || '');
    if (!$img.attr('data-base-srcset')) $img.attr('data-base-srcset', $img.attr('srcset') || '');
  });
}

function updateBaseImagesTo($card, url) {
  var $mediaImgs = $card.find('.media--hover-effect img');
  $mediaImgs.each(function () {
    var $img = $(this);
    $img.attr('data-base-src', url);
    $img.attr('data-base-srcset', url);
  });
}

function revertToBase($card) {
  var $mediaImgs = $card.find('.media--hover-effect img');
  $mediaImgs.each(function () {
    var $img = $(this);
    var baseSrc = $img.attr('data-base-src');
    var baseSrcset = $img.attr('data-base-srcset');

    if (typeof baseSrc !== 'undefined') $img.attr('src', baseSrc);
    if (typeof baseSrcset !== 'undefined') $img.attr('srcset', baseSrcset);
  });
}

// Hover preview
$(document).on('mouseenter', '.card-variant-sizes .size-label', function () {
  var $label = $(this);
  var $swatch = $label.find('.color-custom.color-option');
  var newImage = $swatch.attr('data-image');
  if (!newImage) return;

  var $card = $label.closest('.card');
  cacheBaseImages($card);

  setCardImages($card, newImage);

  $card.find('.color-custom.color-option').removeClass('selected');
  $swatch.addClass('selected');

}).on('mouseleave', '.card-variant-sizes .size-label', function () {
  var $label = $(this);
  var $card = $label.closest('.card');

  // Always revert to the current base image (which may be updated by click)
  revertToBase($card);

  // Restore "selected" state based on active/checked option (optional)
  var $active = $card.find('.card-variant-sizes .size-label.active .color-custom.color-option');
  $card.find('.color-custom.color-option').removeClass('selected');
  if ($active.length) $active.addClass('selected');
});

// Click persist + update base
$(document).on('click', '.card-variant-sizes .size-label', function () {
  var $label = $(this);
  var $swatch = $label.find('.color-custom.color-option');
  var newImage = $swatch.attr('data-image');
  if (!newImage) return;

  var $card = $label.closest('.card');
  cacheBaseImages($card);

  // Update UI active state (optional)
  $card.find('.card-variant-sizes .size-label').removeClass('active');
  $label.addClass('active');

  // Persist image
  setCardImages($card, newImage);

  // IMPORTANT: update base image to the clicked image
  updateBaseImagesTo($card, newImage);

  $card.find('.color-custom.color-option').removeClass('selected');
  $swatch.addClass('selected');
});

  // cusom variant // 
csss


/*** CARD PRODUCT ***/

.size-label {
    border: none;
    padding: 0;
    font-size: 0.875rem;
    position: relative;
    cursor: pointer;
    color: #151515b3;
    background: #F7F7F7;
    margin-right: 0.5rem;
    height: 1.5rem;
    line-height: 1.5rem;
    text-align: center;
    border-radius: 1.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    letter-spacing: 0.28px !important;
} 

.size-label input {
    display: none;
}
.size-label.soldout {
    opacity: .2;
    cursor: not-allowed;
}
body .predictive-search--search-template {
    background: #fff;
}
.card-price {
    margin-top: 0 !important;
}
.size-label input:checked+span {
   /* color:#151515; */
}

.card__information {
    position: relative;
}
button.add-to-cart-btn {
    border: 0;
    width: 2.1875rem;
    height: 2.1875rem;
    line-height: 2.1875rem;
    text-align: center;
    color: #fff;
    font-size: 2.25rem;
    font-weight: 400;
    font-family: var(--font-body-family);
    cursor: pointer;
    border-radius: 50%;
    padding: 0;
    position: absolute;
    right: 1rem;
    opacity: 0;
    z-index: 9;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent linear-gradient(180deg, #161738, #111472) 0% 0% no-repeat padding-box;
    bottom: 1rem;
}
.card-variant-sizes {
    position: absolute;
    top: 2.2rem;
    background: transparent;
    width: 100%;
    display: flex;
    justify-content: flex-start;
    height: 2.81rem;
    line-height: 2.81rem !important;
    padding-left: 0;
    z-index: 9;
    opacity: 0;
} 
.grid__item:hover  .card-variant-sizes ,.grid__item:hover  button.add-to-cart-btn {
     opacity: 1;
}
.grid__item .has-size:hover .card-information-sub-title {
    opacity: 0;
}
label.size-label.active {
    background: #E6E6E6;
}
label.size-label.active,
.size-label:hover {
    background: #ccc;
    color: #000;
}
.quick-add.no-js-hidden {
    display: none !important;
}

/*** CARD PRODUCT ***/


Leave a Reply

Your email address will not be published. Required fields are marked *