update shop

timetoconfirm
Raz 8 months ago
parent e9e1f65911
commit b8a708ff44
  1. 46
      shop/static/shop/css/shop.css
  2. 70
      shop/templates/shop/product_item.html
  3. 32
      shop/templatetags/shop_extras.py

@ -12,6 +12,7 @@
object-fit: contain; /* This will maintain the aspect ratio of the image */ object-fit: contain; /* This will maintain the aspect ratio of the image */
background-color: white; background-color: white;
border-radius: 12px; border-radius: 12px;
display: none; /* Hide all images by default */
} }
.no-image { .no-image {
@ -480,3 +481,48 @@ v .cart-table {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.slider-container {
position: relative;
width: 100%;
max-height: 240px; /* Match your original height */
}
.slides {
position: relative;
width: 100%;
height: 100%;
}
.product-image.active {
display: block;
}
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
transform: translateY(-50%);
background: none;
color: black;
border: none;
font-size: 24px;
padding: 8px;
opacity: 0.6;
transition: opacity 0.3s;
z-index: 2;
}
.prev {
left: 5px;
}
.next {
right: 5px;
}
.prev:hover,
.next:hover {
opacity: 1;
}

@ -2,10 +2,21 @@
<div class="small-12 medium-6 large-3 my-block"> <div class="small-12 medium-6 large-3 my-block">
<div class="bubble"> <div class="bubble">
{% if product.image %} {% if product.image %}
<img id="product-image-{{ product.id }}" <div class="slider-container" id="slider-{{ product.id }}">
src="{% color_image_url product.image product.colors.all.0.name product.sku %}" {% color_images_url product.image product.colors.all.0.name product.sku as images %}
<div class="slides">
{% for image_url in images %}
<img src="{{ image_url }}"
alt="{{ product.title }}" alt="{{ product.title }}"
class="product-image"> class="product-image {% if forloop.first %}active{% endif %}"
id="product-image-{{ product.id }}-{{ forloop.counter0 }}">
{% endfor %}
</div>
{% if images|length > 1 %}
<button class="prev" onclick="changeSlide({{ product.id }}, -1)"></button>
<button class="next" onclick="changeSlide({{ product.id }}, 1)"></button>
{% endif %}
</div>
{% else %} {% else %}
<div class="no-image">No Image Available</div> <div class="no-image">No Image Available</div>
{% endif %} {% endif %}
@ -28,6 +39,7 @@
<input type="hidden" name="color" id="color-{{ product.id }}" value="{{ product.colors.all.0.id }}" required> <input type="hidden" name="color" id="color-{{ product.id }}" value="{{ product.colors.all.0.id }}" required>
<div class="color-samples"> <div class="color-samples">
{% for color in product.colors.all %} {% for color in product.colors.all %}
{% color_images_url product.image color.name product.sku as color_images %}
<div class="color-sample {% if forloop.first %}selected{% endif %}" <div class="color-sample {% if forloop.first %}selected{% endif %}"
{% if color.secondary_hex_color %} {% if color.secondary_hex_color %}
style="background-image: linear-gradient(to right, {{ color.colorHex }} 50%, {{ color.secondary_hex_color }} 50%);" style="background-image: linear-gradient(to right, {{ color.colorHex }} 50%, {{ color.secondary_hex_color }} 50%);"
@ -37,8 +49,9 @@
title="{{ color.name }}" title="{{ color.name }}"
data-color-id="{{ color.id }}" data-color-id="{{ color.id }}"
data-color-name="{{ color.name }}" data-color-name="{{ color.name }}"
data-color-image="{% color_image_url product.image color.name product.sku %}" data-color-images="{{ color_images|join:',' }}"
onclick="selectColor('{{ product.id }}', '{{ color.id }}', '{{ color.name }}', this)"></div> onclick="selectColor('{{ product.id }}', '{{ color.id }}', '{{ color.name }}', this)">
</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
@ -129,14 +142,30 @@ function selectColor(productId, colorId, colorName, element) {
// Add selected class to clicked color // Add selected class to clicked color
element.classList.add('selected'); element.classList.add('selected');
// Update product image based on selected color // Update product images based on selected color
const productImage = document.getElementById(`product-image-${productId}`); const slider = document.getElementById(`slider-${productId}`);
if (slider) {
const colorImages = element.getAttribute('data-color-images').split(',');
const slidesContainer = slider.querySelector('.slides');
if (productImage) { // Clear existing slides
const colorImage = element.getAttribute('data-color-image'); slidesContainer.innerHTML = '';
if (colorImage) {
productImage.src = colorImage; // Add new slides
} colorImages.forEach((imageUrl, index) => {
const img = document.createElement('img');
img.src = imageUrl;
img.alt = colorName;
img.className = `product-image ${index === 0 ? 'active' : ''}`;
img.id = `product-image-${productId}-${index}`;
slidesContainer.appendChild(img);
});
// Update navigation buttons visibility
const navButtons = slider.querySelectorAll('.prev, .next');
navButtons.forEach(button => {
button.style.display = colorImages.length > 1 ? 'block' : 'none';
});
} }
} }
@ -212,4 +241,21 @@ function addToCartAjax(productId) {
}, 3000); }, 3000);
}); });
} }
function changeSlide(productId, direction) {
const slides = document.querySelectorAll(`#slider-${productId} .product-image`);
let activeIndex = Array.from(slides).findIndex(slide => slide.classList.contains('active'));
// Remove active class from current slide
slides[activeIndex].classList.remove('active');
// Calculate new index
activeIndex = activeIndex + direction;
if (activeIndex >= slides.length) activeIndex = 0;
if (activeIndex < 0) activeIndex = slides.length - 1;
// Add active class to new slide
slides[activeIndex].classList.add('active');
}
</script> </script>

@ -5,9 +5,9 @@ register = template.Library()
from django.conf import settings from django.conf import settings
@register.simple_tag @register.simple_tag
def color_image_url(default_image, color_name, sku): def color_images_url(default_image, color_name, sku):
""" """
Returns color-specific image URL from the color-specific folder structure. Returns color-specific image URLs from the color-specific folder structure.
Structure expected: Structure expected:
static/shop/images/products/ static/shop/images/products/
{sku}/ {sku}/
@ -15,7 +15,6 @@ def color_image_url(default_image, color_name, sku):
{color_name}/ {color_name}/
image.jpg (or any supported extension) image.jpg (or any supported extension)
""" """
# List of supported image extensions # List of supported image extensions
supported_extensions = ['.png.avif', '.jpg', '.jpeg', '.png', '.gif', '.webp', '.avif'] supported_extensions = ['.png.avif', '.jpg', '.jpeg', '.png', '.gif', '.webp', '.avif']
@ -30,31 +29,34 @@ def color_image_url(default_image, color_name, sku):
# Check color-specific folder # Check color-specific folder
color_path = os.path.join(physical_base_path, color_folder) color_path = os.path.join(physical_base_path, color_folder)
if os.path.exists(color_path): if os.path.exists(color_path):
# Get first image from color folder # Get all images from color folder
files = [f for f in os.listdir(color_path) files = [f for f in os.listdir(color_path)
if any(f.lower().endswith(ext) for ext in supported_extensions)] if any(f.lower().endswith(ext) for ext in supported_extensions)]
if files: if files:
# Sort files to ensure consistent selection # Sort files by specific prefix rules
files.sort(key=lambda x: ( files.sort(key=lambda x: (
1 if '-B_' in x else 1 if '-B_' in x else
2 if '-S_' in x else 2 if '-S_' in x else
0 0
)) ))
return [f'{base_path}{color_folder}/{file}' for file in files]
# Get the first image
first_file = files[0]
return f'{base_path}{color_folder}/{first_file}'
# If no color-specific image found, look for default image in product folder # If no color-specific image found, look for default image in product folder
if os.path.exists(physical_base_path): if os.path.exists(physical_base_path):
for file in os.listdir(physical_base_path): files = [f for f in os.listdir(physical_base_path)
if any(file.lower().endswith(ext) for ext in supported_extensions): if os.path.isfile(os.path.join(physical_base_path, f)) and
if os.path.isfile(os.path.join(physical_base_path, file)): # Make sure it's a file, not a directory any(f.lower().endswith(ext) for ext in supported_extensions)]
return f'{base_path}{file}' if files:
files.sort(key=lambda x: (
1 if '-B_' in x else
2 if '-S_' in x else
0
))
return [f'{base_path}{file}' for file in files]
# If nothing found, return the default image from the database # If nothing found, return list with default image
return default_image return [default_image]
def generate_color_folder_name(color_name): def generate_color_folder_name(color_name):
""" """

Loading…
Cancel
Save