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 %}
-

+
+ {% color_images_url product.image product.colors.all.0.name product.sku as images %}
+
+ {% for image_url in images %}
+

+ {% 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):
"""