diff --git a/shop/static/shop/css/shop.css b/shop/static/shop/css/shop.css index 9d7e92c..e71a1f6 100644 --- a/shop/static/shop/css/shop.css +++ b/shop/static/shop/css/shop.css @@ -12,6 +12,7 @@ object-fit: contain; /* This will maintain the aspect ratio of the image */ background-color: white; border-radius: 12px; + display: none; /* Hide all images by default */ } .no-image { @@ -480,3 +481,48 @@ v .cart-table { position: relative; 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; +} diff --git a/shop/templates/shop/product_item.html b/shop/templates/shop/product_item.html index 75cef84..4cdb4bb 100644 --- a/shop/templates/shop/product_item.html +++ b/shop/templates/shop/product_item.html @@ -2,10 +2,21 @@
{% if product.image %} - {{ product.title }} +
+ {% color_images_url product.image product.colors.all.0.name product.sku as images %} +
+ {% for image_url in images %} + {{ product.title }} + {% endfor %} +
+ {% if images|length > 1 %} + + + {% endif %} +
{% else %}
No Image Available
{% endif %} @@ -28,17 +39,19 @@
{% for color in product.colors.all %} + {% color_images_url product.image color.name product.sku as color_images %}
+ data-color-images="{{ color_images|join:',' }}" + onclick="selectColor('{{ product.id }}', '{{ color.id }}', '{{ color.name }}', this)"> +
{% endfor %}
{% endif %} @@ -129,14 +142,30 @@ function selectColor(productId, colorId, colorName, element) { // Add selected class to clicked color element.classList.add('selected'); - // Update product image based on selected color - const productImage = document.getElementById(`product-image-${productId}`); + // Update product images based on selected color + const slider = document.getElementById(`slider-${productId}`); + if (slider) { + const colorImages = element.getAttribute('data-color-images').split(','); + const slidesContainer = slider.querySelector('.slides'); - if (productImage) { - const colorImage = element.getAttribute('data-color-image'); - if (colorImage) { - productImage.src = colorImage; - } + // Clear existing slides + slidesContainer.innerHTML = ''; + + // 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); }); } + +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'); +} + diff --git a/shop/templatetags/shop_extras.py b/shop/templatetags/shop_extras.py index dcb40b9..704d9d1 100644 --- a/shop/templatetags/shop_extras.py +++ b/shop/templatetags/shop_extras.py @@ -5,17 +5,16 @@ register = template.Library() from django.conf import settings @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: static/shop/images/products/ - ├── {sku}/ - │ ├── default.jpg (or any supported extension) - │ └── {color_name}/ - │ └── image.jpg (or any supported extension) + ├── {sku}/ + │ ├── default.jpg (or any supported extension) + │ └── {color_name}/ + │ └── image.jpg (or any supported extension) """ - # List of supported image extensions 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 color_path = os.path.join(physical_base_path, color_folder) 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) - if any(f.lower().endswith(ext) for ext in supported_extensions)] + if any(f.lower().endswith(ext) for ext in supported_extensions)] if files: - # Sort files to ensure consistent selection + # Sort files by specific prefix rules files.sort(key=lambda x: ( 1 if '-B_' in x else 2 if '-S_' in x else 0 )) - - # Get the first image - first_file = files[0] - return f'{base_path}{color_folder}/{first_file}' + return [f'{base_path}{color_folder}/{file}' for file in files] # If no color-specific image found, look for default image in product folder if os.path.exists(physical_base_path): - for file 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, file)): # Make sure it's a file, not a directory - return f'{base_path}{file}' + files = [f for f in os.listdir(physical_base_path) + if os.path.isfile(os.path.join(physical_base_path, f)) and + any(f.lower().endswith(ext) for ext in supported_extensions)] + 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 - return default_image + # If nothing found, return list with default image + return [default_image] def generate_color_folder_name(color_name): """