Untitled

 avatar
unknown
plain_text
a month ago
12 kB
5
Indexable
{% comment %}
  Simple and Clean Bundle Selector - Fixed
{% endcomment %}

<div class="simple-bundle-selector">
  <div class="simple-options-container">
    {% for variant in product.variants %}
      {% if variant.title contains 'Pack' %}
        <div class="simple-option-item" id="option-item-{{ variant.id }}">
          <input 
            type="radio" 
            value="{{ variant.id }}" 
            name="simple_bundle_variant" 
            id="simple_bundle_variant_{{ forloop.index }}"
            class="simple-variant-selector"
            data-variant-id="{{ variant.id }}"
            data-regular-price="{{ variant.price }}"
            data-compare-price="{{ variant.compare_at_price }}"
            {% if forloop.first %}checked{% endif %}
          >
          <label for="simple_bundle_variant_{{ forloop.index }}">
            <div class="simple-option-content">
              <div class="simple-option-header">
                {% case variant.title %}
                  {% when '2 Pack' or '2 pack' %}{% when '4 Pack' or '4 pack' %}<span class="best-seller">Best Seller</span>{% when '6 Pack' or '6 pack' %}<span class="best-value">Best Value</span>
                {% endcase %}
              </div>
              
              <div class="simple-circle">
                {% case variant.title %}
                  {% when '2 Pack' or '2 pack' %}2{% when '4 Pack' or '4 pack' %}4{% when '6 Pack' or '6 pack' %}6
                {% endcase %}
              </div>
              
              <div class="simple-option-price">
                {{ variant.price | money }}
              </div>
              
              {% if variant.compare_at_price > 0 %}
                <div class="simple-option-compare">
                  {{ variant.compare_at_price | money }}
                </div>
              {% endif %}
            </div>
          </label>
        </div>
      {% endif %}
    {% endfor %}
  </div>
</div>

<style>
/* Base styles */
.simple-bundle-selector {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  margin: 20px auto;
  max-width: 600px;
  perspective: 1000px;
}

.simple-options-container {
  display: flex;
  justify-content: center;
  gap: 10px;
}

.simple-option-item {
  position: relative;
  flex: 1;
  min-width: 0;
  flex-basis: 33.333%;
  transition: all 0.3s ease;
}

.simple-option-item input[type="radio"] {
  position: absolute;
  opacity: 0;
}

.simple-option-item label {
  display: block;
  cursor: pointer;
  border: 1px solid #e8e8e8;
  border-radius: 10px;
  padding: 15px 10px;
  background-color: #fff;
  transition: all 0.3s ease;
  height: 100%;
}

/* Selected state and hover effects */
.simple-option-item.selected label,
.simple-option-item input[type="radio"]:checked + label {
  border-color: #de96b8;
  background-color: #fdf6fa;
  transform: translateY(-3px);
  box-shadow: 0 4px 12px rgba(222, 150, 184, 0.15);
}

.simple-option-item label:hover {
  transform: translateY(-2px);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}

.simple-option-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.simple-option-header {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 8px;
  min-height: 18px;
}

.best-seller, .best-value {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 3px;
  font-weight: 500;
  font-size: 10px;
  background-color: #faeaf3;
  color: #d76ea3;
  transition: all 0.3s ease;
}

.simple-circle {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: #f6e9f2;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: 600;
  color: #8e5c7b;
  margin-bottom: 12px;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.simple-option-item input[type="radio"]:checked + label .simple-circle {
  transform: scale(1.08);
  box-shadow: 0 0 15px rgba(222, 150, 184, 0.2);
}

.simple-option-price {
  font-size: 16px;
  font-weight: 600;
  color: #333;
  margin-top: 4px;
  transition: all 0.3s ease;
}

.simple-option-item input[type="radio"]:checked + label .simple-option-price {
  color: #000;
  transform: scale(1.05);
}

.simple-option-compare {
  font-size: 14px;
  text-decoration: line-through;
  color: #999;
  margin-top: 2px;
  transition: opacity 0.3s ease;
}

/* Responsive styles */
@media (max-width: 480px) {
  .simple-option-header {
    font-size: 12px;
    margin-bottom: 6px;
  }
  
  .best-seller, .best-value {
    padding: 1px 4px;
    font-size: 9px;
  }
  
  .simple-circle {
    width: 40px;
    height: 40px;
    font-size: 20px;
  }
  
  .simple-option-price {
    font-size: 14px;
  }
  
  .simple-option-compare {
    font-size: 12px;
  }
}

@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.15); }
  100% { transform: scale(1.08); }
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Initialize the bundle selector right away
  initBundleSelector();
  
  // Also initialize after a short delay to ensure everything is loaded
  setTimeout(initBundleSelector, 500);
  
  function initBundleSelector() {
    // Get all option items and radio buttons
    const bundleItems = document.querySelectorAll('.simple-variant-selector');
    const allOptionItems = document.querySelectorAll('.simple-option-item');
    
    // Cart form elements
    const variantIdInputs = document.querySelectorAll('input[name="id"]');
    
    // Find subscription elements
    const subscribeElement = document.querySelector('input[id*="subscribe"], [id*="subscription-option"]');
    const oneTimeElement = document.querySelector('input[id*="one-time"]');
    
    // Get subscription discount percentage
    const discountText = document.querySelector('[class*="save"]');
    let discountPercent = 10; // Default 10%
    
    if (discountText) {
      const match = discountText.textContent.match(/\d+/);
      if (match) {
        discountPercent = parseInt(match[0], 10);
      }
    }
    
    // Function to update displayed prices
    function updatePrices() {
      const isSubscription = subscribeElement && subscribeElement.checked;
      
      bundleItems.forEach(item => {
        const priceElement = item.closest('.simple-option-item').querySelector('.simple-option-price');
        const compareElement = item.closest('.simple-option-item').querySelector('.simple-option-compare');
        const regularPrice = parseFloat(item.getAttribute('data-regular-price'));
        const comparePrice = parseFloat(item.getAttribute('data-compare-price')) || 0;
        
        if (priceElement && !isNaN(regularPrice)) {
          let finalPrice;
          
          if (isSubscription) {
            // Apply discount for subscription
            finalPrice = regularPrice * (1 - discountPercent / 100);
          } else {
            finalPrice = regularPrice;
          }
          
          // Format using Shopify's currency converter
          priceElement.textContent = formatMoney(finalPrice);
          
          // Update compare price if present
          if (compareElement && comparePrice > 0) {
            compareElement.textContent = formatMoney(comparePrice);
          }
        }
      });
    }
    
    // Helper function to format money using Shopify's currency converter
    function formatMoney(cents) {
      if (typeof Shopify !== 'undefined' && Shopify.formatMoney) {
        return Shopify.formatMoney(cents);
      }
      
      // Simple fallback if Shopify formatter isn't available
      return '$' + (cents / 100).toFixed(2);
    }
    
    // Function to update the visual selection state
    function updateSelectionState() {
      // Remove selected class from all items
      allOptionItems.forEach(item => {
        item.classList.remove('selected');
      });
      
      // Find the checked radio button and add selected class to its parent
      const checkedRadio = document.querySelector('.simple-variant-selector:checked');
      if (checkedRadio) {
        checkedRadio.closest('.simple-option-item').classList.add('selected');
      }
    }
    
    // Update all variant inputs on the page
    function updateVariantSelection(variantId) {
      variantIdInputs.forEach(input => {
        input.value = variantId;
      });
      
      // Find main product form
      const mainProductForm = document.querySelector('form[action="/cart/add"]');
      if (mainProductForm) {
        const mainFormVariantInput = mainProductForm.querySelector('input[name="id"]');
        if (mainFormVariantInput) {
          mainFormVariantInput.value = variantId;
          mainFormVariantInput.dispatchEvent(new Event('change', { bubbles: true }));
        }
      }
      
      // Get the subscription app dropdown if it exists and update it
      const subscriptionDropdown = document.querySelector('.rc_widget__option_selector, [id*="purchase-options"]');
      if (subscriptionDropdown) {
        subscriptionDropdown.value = variantId;
        subscriptionDropdown.dispatchEvent(new Event('change', { bubbles: true }));
      }
    }
    
    // Handle bundle selection
    bundleItems.forEach(item => {
      item.addEventListener('change', function() {
        const variantId = this.value;
        
        // Update the form
        updateVariantSelection(variantId);
        
        // Update visual selection state
        updateSelectionState();
        
        // Add pulse animation to the circle
        const circle = this.closest('.simple-option-item').querySelector('.simple-circle');
        circle.style.animation = 'none';
        setTimeout(() => {
          circle.style.animation = 'pulse 0.6s';
        }, 10);
      });
    });
    
    // Listen for subscription option changes
    if (subscribeElement) {
      subscribeElement.addEventListener('change', updatePrices);
    }
    
    if (oneTimeElement) {
      oneTimeElement.addEventListener('change', updatePrices);
    }
    
    // Watch for DOM changes that might affect pricing
    document.addEventListener('click', function() {
      setTimeout(updatePrices, 100);
    });
    
    // Monitor the subscription app elements for changes
    const subscriptionContainer = document.querySelector('.rc_container, .purchase-options-container, [class*="subscription"]');
    if (subscriptionContainer) {
      const subscriptionObserver = new MutationObserver(function(mutations) {
        updatePrices();
      });
      
      subscriptionObserver.observe(subscriptionContainer, {
        childList: true,
        subtree: true,
        characterData: true,
        attributes: true
      });
    }
    
    // Also listen for variant changes from the subscription app
    const subscriptionDropdown = document.querySelector('.rc_widget__option_selector, [id*="purchase-options"]');
    if (subscriptionDropdown) {
      subscriptionDropdown.addEventListener('change', function() {
        // Find corresponding bundle variant
        const selectedVariantId = this.value;
        bundleItems.forEach(item => {
          if (item.value === selectedVariantId) {
            item.checked = true;
            updateSelectionState();
          }
        });
      });
    }
    
    // When a product variant selection changes outside our bundle
    document.addEventListener('variant:changed', function(event) {
      if (event.detail && event.detail.variant) {
        const newVariantId = event.detail.variant.id.toString();
        bundleItems.forEach(item => {
          if (item.value === newVariantId) {
            item.checked = true;
            updateSelectionState();
          }
        });
      }
    });
    
    // Initial setup
    updateSelectionState();
    updatePrices();
  }
});
</script>
Editor is loading...
Leave a Comment