feat: add ProductDetailPage introduce ImageViewer and ImageLightbox components for enhanced image display
- ProductDetailPage is being used in lieu of a modal becaues Lightbox image gallery (modal) being embedded in another modal was causing too much buggy behavior - Added ImageViewer component to manage and display product images with features like lightbox, thumbnails, and image cycling controls. - Replaced ProgressiveImageGallery with ImageViewer in ProductDetailDialog and ProductDetailPage for improved user experience and maintainability. - Implemented useImageLightbox composable to handle lightbox functionality, including keyboard navigation and swipe gestures. - Updated routing to include a dedicated product detail page for better navigation and user flow. These changes significantly enhance the image viewing experience in the product detail context, providing a more dynamic and user-friendly interface.
This commit is contained in:
parent
bff158cb74
commit
3aec5bbdb3
8 changed files with 1100 additions and 384 deletions
|
|
@ -10,7 +10,7 @@
|
|||
<div class="grid gap-6 md:grid-cols-2">
|
||||
<!-- Product Images with Lightbox -->
|
||||
<div class="space-y-4">
|
||||
<ProgressiveImageGallery
|
||||
<ImageViewer
|
||||
:images="productImages"
|
||||
:alt="product.name"
|
||||
container-class="aspect-square rounded-lg overflow-hidden bg-gray-100"
|
||||
|
|
@ -20,9 +20,12 @@
|
|||
:show-thumbnails="productImages.length > 1"
|
||||
:show-lightbox="true"
|
||||
:show-badge="productImages.length > 1"
|
||||
:show-cycle-controls="productImages.length > 1"
|
||||
:is-embedded="true"
|
||||
@error="handleImageError"
|
||||
@image-change="handleImageChange"
|
||||
@lightbox-open="handleLightboxOpen"
|
||||
@lightbox-close="handleLightboxClose"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -145,7 +148,7 @@ import { Button } from '@/components/ui/button'
|
|||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import ProgressiveImageGallery from '@/components/ui/ProgressiveImageGallery.vue'
|
||||
import ImageViewer from '@/components/ui/ImageViewer.vue'
|
||||
import { ShoppingCart, Store, Plus, Minus, X } from 'lucide-vue-next'
|
||||
import { useToast } from '@/core/composables/useToast'
|
||||
import type { Product } from '../types/market'
|
||||
|
|
@ -220,6 +223,16 @@ const handleImageChange = (index: number, src: string) => {
|
|||
console.log('Image changed to index:', index, 'src:', src)
|
||||
}
|
||||
|
||||
const handleLightboxOpen = (index: number) => {
|
||||
// Optional: Handle lightbox open events if needed
|
||||
console.log('Lightbox opened at index:', index)
|
||||
}
|
||||
|
||||
const handleLightboxClose = () => {
|
||||
// Optional: Handle lightbox close events if needed
|
||||
console.log('Lightbox closed')
|
||||
}
|
||||
|
||||
// Reset state when dialog opens/closes
|
||||
watch(() => props.isOpen, (newVal) => {
|
||||
if (newVal) {
|
||||
|
|
|
|||
|
|
@ -27,23 +27,15 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<!-- Product Detail Dialog - Now managed internally -->
|
||||
<ProductDetailDialog
|
||||
v-if="selectedProduct"
|
||||
:product="selectedProduct"
|
||||
:isOpen="showProductDetail"
|
||||
@close="closeProductDetail"
|
||||
@add-to-cart="handleDialogAddToCart"
|
||||
/>
|
||||
</LoadingErrorState>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Package as EmptyIcon } from 'lucide-vue-next'
|
||||
import ProductCard from './ProductCard.vue'
|
||||
import ProductDetailDialog from './ProductDetailDialog.vue'
|
||||
import LoadingErrorState from './LoadingErrorState.vue'
|
||||
import type { Product } from '../types/market'
|
||||
|
||||
|
|
@ -99,29 +91,15 @@ const gridClasses = computed(() => {
|
|||
return classes.join(' ')
|
||||
})
|
||||
|
||||
// Internal state for product detail dialog
|
||||
const showProductDetail = ref(false)
|
||||
const selectedProduct = ref<Product | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
// Handle view details internally
|
||||
// Handle view details by navigating to product page
|
||||
const handleViewDetails = (product: Product) => {
|
||||
selectedProduct.value = product
|
||||
showProductDetail.value = true
|
||||
}
|
||||
|
||||
const closeProductDetail = () => {
|
||||
showProductDetail.value = false
|
||||
selectedProduct.value = null
|
||||
router.push(`/market/product/${product.id}`)
|
||||
}
|
||||
|
||||
// Handle add to cart from product card (quick add, quantity 1)
|
||||
const handleAddToCart = (product: Product) => {
|
||||
emit('add-to-cart', product, 1)
|
||||
}
|
||||
|
||||
// Handle add to cart from dialog (with custom quantity)
|
||||
const handleDialogAddToCart = (product: Product, quantity: number) => {
|
||||
emit('add-to-cart', product, quantity)
|
||||
closeProductDetail()
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue