@thorprovider/blocks 0.1.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +155 -0
- package/README.md +228 -68
- package/docs/standards/data-contracts.md +13 -2
- package/package.json +26 -10
- package/scripts/fix-esm-extensions.mjs +40 -0
- package/src/blocks/application/login-forms/login-page.test.tsx +190 -0
- package/src/blocks/application/login-forms/login-page.tsx +240 -0
- package/src/blocks/application/password-recovery/forgot-password-page-1.tsx +6 -8
- package/src/blocks/application/signup-forms/signup-page-1.tsx +127 -129
- package/src/blocks/application/verification/verify-1.tsx +2 -2
- package/src/blocks/application/viewport-ownership.test.tsx +41 -0
- package/src/blocks/e-commerce/category-filters/category-listing-filter-fields.tsx +218 -0
- package/src/blocks/e-commerce/category-filters/{category-filter-2.test.tsx → category-listing.test.tsx} +287 -199
- package/src/blocks/e-commerce/category-filters/category-listing.tsx +934 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-contact-step.tsx +149 -0
- package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-country-field.tsx → checkout-country-field.tsx} +10 -8
- package/src/blocks/e-commerce/checkout-forms/checkout-order-summary.tsx +230 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-payment-step.tsx +100 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-progress.tsx +62 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-review-step.tsx +59 -0
- package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-shipping-step.tsx → checkout-shipping-step.tsx} +65 -41
- package/src/blocks/e-commerce/checkout-forms/checkout.test.tsx +478 -0
- package/src/blocks/e-commerce/checkout-forms/checkout.tsx +550 -0
- package/src/blocks/e-commerce/navigation/storefront-navbar-account-menu.test.tsx +56 -0
- package/src/blocks/{marketing/navbars/navbar-4-account-menu.tsx → e-commerce/navigation/storefront-navbar-account-menu.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.test.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.test.tsx} +22 -22
- package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4-mobile-nav.tsx → e-commerce/navigation/storefront-navbar-mobile-nav.tsx} +4 -12
- package/src/blocks/{marketing/navbars/navbar-4-search-bar.tsx → e-commerce/navigation/storefront-navbar-search-bar.tsx} +3 -3
- package/src/blocks/{marketing/navbars/navbar-4.test.tsx → e-commerce/navigation/storefront-navbar.test.tsx} +67 -36
- package/src/blocks/{marketing/navbars/navbar-4.tsx → e-commerce/navigation/storefront-navbar.tsx} +43 -25
- package/src/blocks/e-commerce/product-categories/category-card-grid.test.tsx +122 -0
- package/src/blocks/e-commerce/product-categories/category-card.test.tsx +68 -0
- package/src/blocks/e-commerce/product-categories/category-card.tsx +172 -0
- package/src/blocks/e-commerce/product-categories/category-grid.test.tsx +67 -0
- package/src/blocks/e-commerce/product-categories/category-shared.tsx +109 -0
- package/src/blocks/e-commerce/product-categories/product-category-grid.tsx +170 -0
- package/src/blocks/e-commerce/product-categories/product-category.test.tsx +266 -0
- package/src/blocks/e-commerce/product-categories/product-category.tsx +462 -0
- package/src/blocks/e-commerce/product-list/product-card.test.tsx +263 -0
- package/src/blocks/e-commerce/product-list/product-card.tsx +447 -0
- package/src/blocks/e-commerce/product-list/product-grid.test.tsx +162 -0
- package/src/blocks/e-commerce/product-list/product-grid.tsx +114 -0
- package/src/blocks/e-commerce/product-overview/product-overview-gallery.tsx +71 -0
- package/src/blocks/e-commerce/product-overview/{product-overview-5-lightbox-tab.tsx → product-overview-lightbox-tab.tsx} +35 -23
- package/src/blocks/e-commerce/product-overview/{product-overview-5-reviews-tab.tsx → product-overview-reviews-tab.tsx} +40 -17
- package/src/blocks/e-commerce/product-overview/{product-overview-5-tabs.tsx → product-overview-tabs.tsx} +8 -7
- package/src/blocks/e-commerce/product-overview/product-overview.test.tsx +283 -0
- package/src/blocks/e-commerce/product-overview/product-overview.tsx +1186 -0
- package/src/blocks/e-commerce/reviews/review-rating-2.tsx +5 -6
- package/src/blocks/e-commerce/shopping-carts/shopping-cart.test.tsx +399 -0
- package/src/blocks/e-commerce/shopping-carts/{shopping-cart-4.tsx → shopping-cart.tsx} +119 -85
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.test.tsx +412 -0
- package/src/blocks/e-commerce/storefront-hero/storefront-hero.tsx +1283 -0
- package/src/blocks/marketing/features/feature.test.tsx +153 -0
- package/src/blocks/marketing/features/feature.tsx +195 -0
- package/src/blocks/marketing/footers/footer-section-accessibility.test.tsx +118 -0
- package/src/blocks/marketing/footers/footer-section-actions.test.tsx +131 -0
- package/src/blocks/marketing/footers/footer-section-data.test.tsx +127 -0
- package/src/blocks/marketing/footers/footer-section-native-links.test.tsx +100 -0
- package/src/blocks/marketing/footers/footer-section-public-api.test.tsx +11 -0
- package/src/blocks/marketing/footers/footer-section.test.tsx +46 -0
- package/src/blocks/marketing/footers/footer-section.tsx +532 -0
- package/src/blocks/marketing/navbars/navbar-public-api.test.tsx +57 -0
- package/src/blocks/marketing/navbars/navbar.mega.test.tsx +149 -0
- package/src/blocks/marketing/navbars/navbar.test.tsx +155 -0
- package/src/blocks/marketing/navbars/navbar.tsx +735 -0
- package/src/blocks/marketing/testimonials/testimonial-section.test.tsx +171 -0
- package/src/blocks/marketing/testimonials/testimonial-section.tsx +237 -0
- package/src/index.ts +156 -128
- package/src/lib/contracts-curated.test.ts +47 -29
- package/src/lib/contracts.test.ts +198 -2
- package/src/lib/contracts.ts +410 -16
- package/src/ui/button-group.tsx +1 -1
- package/src/ui/carousel.tsx +1 -1
- package/src/ui/dialog.tsx +1 -1
- package/src/ui/field.tsx +2 -2
- package/src/ui/input-group.tsx +3 -3
- package/src/ui/pagination.tsx +1 -1
- package/src/ui/sidebar.tsx +7 -7
- package/src/ui/toggle-group.tsx +1 -1
- package/tsconfig.build.json +12 -0
- package/tsup.config.ts +11 -7
- package/.turbo/turbo-build.log +0 -24
- package/.turbo/turbo-test.log +0 -47
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/.tsbuildinfo +0 -1
- package/dist/contracts.d.mts +0 -1732
- package/dist/contracts.d.ts +0 -1732
- package/dist/contracts.js +0 -423
- package/dist/contracts.js.map +0 -1
- package/dist/contracts.mjs +0 -365
- package/dist/contracts.mjs.map +0 -1
- package/dist/index.d.mts +0 -3068
- package/dist/index.d.ts +0 -3068
- package/dist/index.js +0 -17834
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -17740
- package/dist/index.mjs.map +0 -1
- package/src/blocks/application/login-forms/login-page-1.tsx +0 -246
- package/src/blocks/application/login-forms/login-page-2.tsx +0 -207
- package/src/blocks/e-commerce/category-filters/category-filter-1.tsx +0 -260
- package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +0 -222
- package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +0 -921
- package/src/blocks/e-commerce/category-filters/category-filter-4-chip-rail.tsx +0 -57
- package/src/blocks/e-commerce/category-filters/category-filter-4-drawer.tsx +0 -124
- package/src/blocks/e-commerce/category-filters/category-filter-4-fields.tsx +0 -170
- package/src/blocks/e-commerce/category-filters/category-filter-4-sidebar.tsx +0 -52
- package/src/blocks/e-commerce/category-filters/category-filter-4-sort-sheet.tsx +0 -57
- package/src/blocks/e-commerce/category-filters/category-filter-4-state.ts +0 -68
- package/src/blocks/e-commerce/category-filters/category-filter-4.tsx +0 -298
- package/src/blocks/e-commerce/checkout-forms/card-formatting.test.ts +0 -47
- package/src/blocks/e-commerce/checkout-forms/card-formatting.ts +0 -9
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-contact-step.tsx +0 -96
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +0 -252
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +0 -188
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-progress.tsx +0 -36
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +0 -216
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +0 -338
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-order-summary.tsx +0 -130
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-payment-card.tsx +0 -175
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2-shipping-card.tsx +0 -190
- package/src/blocks/e-commerce/checkout-forms/checkout-form-2.tsx +0 -312
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-information-step.tsx +0 -91
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-order-summary.tsx +0 -110
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-payment-step.tsx +0 -137
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-progress.tsx +0 -68
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-review-step.tsx +0 -79
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3-shipping-step.tsx +0 -172
- package/src/blocks/e-commerce/checkout-forms/checkout-form-3.tsx +0 -392
- package/src/blocks/e-commerce/product-categories/avatar-group.tsx +0 -86
- package/src/blocks/e-commerce/product-categories/product-category-1.tsx +0 -126
- package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +0 -51
- package/src/blocks/e-commerce/product-categories/product-category-2.tsx +0 -120
- package/src/blocks/e-commerce/product-categories/product-category-4.tsx +0 -129
- package/src/blocks/e-commerce/product-categories/product-category-5.tsx +0 -218
- package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +0 -88
- package/src/blocks/e-commerce/product-list/product-card-1.tsx +0 -192
- package/src/blocks/e-commerce/product-list/product-card-2.tsx +0 -71
- package/src/blocks/e-commerce/product-list/product-card-3-reaction-toggle.tsx +0 -166
- package/src/blocks/e-commerce/product-list/product-card-3.tsx +0 -215
- package/src/blocks/e-commerce/product-list/product-card-5-checkbox-check.tsx +0 -98
- package/src/blocks/e-commerce/product-list/product-card-5-reaction-toggle.tsx +0 -171
- package/src/blocks/e-commerce/product-list/product-card-5.tsx +0 -367
- package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +0 -182
- package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +0 -370
- package/src/blocks/e-commerce/product-overview/product-overview-2.tsx +0 -272
- package/src/blocks/e-commerce/product-overview/product-overview-5-gallery.tsx +0 -59
- package/src/blocks/e-commerce/product-overview/product-overview-5.tsx +0 -274
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-1.tsx +0 -291
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-item-row.tsx +0 -110
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-recommendations.tsx +0 -51
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-2.tsx +0 -295
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3-spinning-counter.tsx +0 -142
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-3.tsx +0 -342
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4-spinning-counter.tsx +0 -146
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +0 -229
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +0 -72
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +0 -263
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-2.tsx +0 -283
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-5.tsx +0 -318
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-6.tsx +0 -205
- package/src/blocks/marketing/features/feature-1.tsx +0 -97
- package/src/blocks/marketing/features/feature-2.tsx +0 -82
- package/src/blocks/marketing/footers/footer-section-1.test.tsx +0 -117
- package/src/blocks/marketing/footers/footer-section-1.tsx +0 -178
- package/src/blocks/marketing/footers/footer-section-3.tsx +0 -192
- package/src/blocks/marketing/footers/footer-section-4.tsx +0 -355
- package/src/blocks/marketing/navbars/navbar-1.tsx +0 -267
- package/src/blocks/marketing/navbars/navbar-2.tsx +0 -351
- package/src/blocks/marketing/navbars/navbar-3.tsx +0 -303
- package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +0 -38
- package/src/blocks/marketing/navbars/navbar-4-like-button.tsx +0 -177
- package/src/blocks/marketing/navbars/navbar-4-product-grid.tsx +0 -219
- package/src/blocks/marketing/testimonials/testimonial-1.tsx +0 -141
- package/src/blocks/marketing/testimonials/testimonial-2.tsx +0 -108
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useEffect } from 'react'
|
|
4
|
-
import { Button } from '../../../ui/button'
|
|
5
|
-
import { cn } from '../../../lib/utils'
|
|
6
|
-
import { Heart, ShoppingBag, Truck, Star, Check } from 'lucide-react'
|
|
7
|
-
import { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '../../../ui/carousel'
|
|
8
|
-
import { ReactionToggle } from '../../shared/reaction-toggle'
|
|
9
|
-
|
|
10
|
-
export interface ProductOverview2ProductImage {
|
|
11
|
-
src: string
|
|
12
|
-
alt: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ProductOverview2ProductColor {
|
|
16
|
-
name: string
|
|
17
|
-
value: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ProductOverview2ProductSize {
|
|
21
|
-
eu: number
|
|
22
|
-
uk: number
|
|
23
|
-
us: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ProductOverview2Product {
|
|
27
|
-
id: string
|
|
28
|
-
brand: string
|
|
29
|
-
name: string
|
|
30
|
-
sku: string
|
|
31
|
-
price: number
|
|
32
|
-
currency: string
|
|
33
|
-
rating: number
|
|
34
|
-
reviews: number
|
|
35
|
-
images: ProductOverview2ProductImage[]
|
|
36
|
-
sizes: ProductOverview2ProductSize[]
|
|
37
|
-
colors: ProductOverview2ProductColor[]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface ProductOverview2Props {
|
|
41
|
-
product: ProductOverview2Product
|
|
42
|
-
sizesLabel?: string
|
|
43
|
-
colorLabel?: string
|
|
44
|
-
reviewsLabel?: string
|
|
45
|
-
addToCartLabel?: string
|
|
46
|
-
removeFromWishlistLabel?: string
|
|
47
|
-
addToWishlistLabel?: string
|
|
48
|
-
sizeGuideLabel?: string
|
|
49
|
-
freeDeliveryLabel?: string
|
|
50
|
-
onAddToCart?: (product: ProductOverview2Product) => void
|
|
51
|
-
onToggleWishlist?: (product: ProductOverview2Product, isWishlisted: boolean) => void
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default function ProductOverview2({
|
|
55
|
-
product,
|
|
56
|
-
sizesLabel = 'Tallas',
|
|
57
|
-
colorLabel = 'Color',
|
|
58
|
-
reviewsLabel = 'Reseñas',
|
|
59
|
-
addToCartLabel = 'Agregar al carrito',
|
|
60
|
-
removeFromWishlistLabel = 'Quitar de favoritos',
|
|
61
|
-
addToWishlistLabel = 'Agregar a favoritos',
|
|
62
|
-
sizeGuideLabel = 'Guía de tallas',
|
|
63
|
-
freeDeliveryLabel = 'Envío gratis en pedidos superiores a $30.00',
|
|
64
|
-
onAddToCart,
|
|
65
|
-
onToggleWishlist,
|
|
66
|
-
}: ProductOverview2Props) {
|
|
67
|
-
const [selectedImage, setSelectedImage] = useState(0)
|
|
68
|
-
const [selectedSize, setSelectedSize] = useState<number | null>(product.sizes[1]?.eu ?? null)
|
|
69
|
-
const [selectedColor, setSelectedColor] = useState(product.colors[0])
|
|
70
|
-
const [isWishlisted, setIsWishlisted] = useState(false)
|
|
71
|
-
const [sizeType, setSizeType] = useState<'eu' | 'uk' | 'us'>('eu')
|
|
72
|
-
const [carouselApi, setCarouselApi] = useState<CarouselApi>()
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (!carouselApi) return
|
|
76
|
-
|
|
77
|
-
// Set carousel to the selected image
|
|
78
|
-
carouselApi.scrollTo(selectedImage)
|
|
79
|
-
|
|
80
|
-
// Update selected image when carousel changes
|
|
81
|
-
const handleSelect = () => {
|
|
82
|
-
const currentIndex = carouselApi.selectedScrollSnap()
|
|
83
|
-
setSelectedImage(currentIndex)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
carouselApi.on('select', handleSelect)
|
|
87
|
-
return () => {
|
|
88
|
-
carouselApi.off('select', handleSelect)
|
|
89
|
-
}
|
|
90
|
-
}, [carouselApi, selectedImage])
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<section className='mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8'>
|
|
94
|
-
<div className='grid grid-cols-1 gap-8 py-4 md:py-6 lg:grid-cols-2 lg:py-12'>
|
|
95
|
-
{/* Product Gallery */}
|
|
96
|
-
<div className='flex flex-col gap-4'>
|
|
97
|
-
{/* Main Image - Carousel */}
|
|
98
|
-
<Carousel setApi={setCarouselApi} className='w-full'>
|
|
99
|
-
<CarouselContent>
|
|
100
|
-
{product.images.map((image, index) => (
|
|
101
|
-
<CarouselItem key={index}>
|
|
102
|
-
<div className='flex h-130 w-full items-center justify-center overflow-hidden rounded-lg bg-muted'>
|
|
103
|
-
<img src={image.src || undefined} alt={image.alt} className='h-full w-full object-cover' />
|
|
104
|
-
</div>
|
|
105
|
-
</CarouselItem>
|
|
106
|
-
))}
|
|
107
|
-
</CarouselContent>
|
|
108
|
-
</Carousel>
|
|
109
|
-
|
|
110
|
-
{/* Thumbnails */}
|
|
111
|
-
<div className='flex flex-wrap gap-4'>
|
|
112
|
-
{product.images.map((image, index) => (
|
|
113
|
-
<button
|
|
114
|
-
type='button'
|
|
115
|
-
key={index}
|
|
116
|
-
onClick={() => setSelectedImage(index)}
|
|
117
|
-
aria-label={`Mostrar imagen ${index + 1} de ${product.name}`}
|
|
118
|
-
className='aspect-square size-16 cursor-pointer'
|
|
119
|
-
>
|
|
120
|
-
<img
|
|
121
|
-
src={image.src || undefined}
|
|
122
|
-
alt={image.alt}
|
|
123
|
-
className={cn(
|
|
124
|
-
'size-full cursor-pointer rounded-md object-cover ring-offset-2 transition-all',
|
|
125
|
-
selectedImage === index ? 'ring-foreground ring-2' : '',
|
|
126
|
-
)}
|
|
127
|
-
/>
|
|
128
|
-
</button>
|
|
129
|
-
))}
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
{/* Product Details */}
|
|
134
|
-
<div className='flex flex-col gap-6'>
|
|
135
|
-
{/* Product Header */}
|
|
136
|
-
<header className='flex flex-col gap-4'>
|
|
137
|
-
<div className='flex items-center'>
|
|
138
|
-
<Button variant='ghost' size='icon' className='bg-primary size-6 scale-75 cursor-pointer rounded-full'>
|
|
139
|
-
<Check className='text-primary-foreground size-4' />
|
|
140
|
-
</Button>
|
|
141
|
-
<span className='ms-2 font-medium'>{product.brand}</span>
|
|
142
|
-
<span className='text-muted-foreground ms-auto'>{product.sku}</span>
|
|
143
|
-
</div>
|
|
144
|
-
<h1 className='text-xl font-bold text-balance xl:text-3xl'>{product.name}</h1>
|
|
145
|
-
|
|
146
|
-
{/* Ratings */}
|
|
147
|
-
<div className='flex items-center gap-2'>
|
|
148
|
-
<div className='flex'>
|
|
149
|
-
{[...Array(5)].map((_, i) => (
|
|
150
|
-
<Star
|
|
151
|
-
key={i}
|
|
152
|
-
className={cn(
|
|
153
|
-
'size-5',
|
|
154
|
-
i < product.rating ? 'fill-foreground text-foreground' : 'text-muted-foreground',
|
|
155
|
-
)}
|
|
156
|
-
/>
|
|
157
|
-
))}
|
|
158
|
-
</div>
|
|
159
|
-
<span className='text-muted-foreground text-sm'>
|
|
160
|
-
{product.reviews} {reviewsLabel}
|
|
161
|
-
</span>
|
|
162
|
-
</div>
|
|
163
|
-
</header>
|
|
164
|
-
|
|
165
|
-
{/* Price */}
|
|
166
|
-
<p className='text-4xl font-bold'>
|
|
167
|
-
{product.currency}
|
|
168
|
-
{product.price.toFixed(2)}
|
|
169
|
-
</p>
|
|
170
|
-
{/* Color Selection */}
|
|
171
|
-
<div>
|
|
172
|
-
<div className='mb-4 flex items-center text-sm'>
|
|
173
|
-
<span className='font-medium'>{colorLabel}:</span>
|
|
174
|
-
<span className='text-muted-foreground ms-1'>{selectedColor.name}</span>
|
|
175
|
-
</div>
|
|
176
|
-
<div className='flex gap-3'>
|
|
177
|
-
{product.colors.map(color => (
|
|
178
|
-
<Button
|
|
179
|
-
key={color.name}
|
|
180
|
-
onClick={() => setSelectedColor(color)}
|
|
181
|
-
className={cn(
|
|
182
|
-
'h-9 px-4 py-2',
|
|
183
|
-
'ring-offset-background size-8 cursor-pointer rounded-sm ring-offset-2 transition-all',
|
|
184
|
-
selectedColor.name === color.name && 'ring-foreground ring-2',
|
|
185
|
-
selectedColor.name !== color.name &&
|
|
186
|
-
['Black', 'White'].includes(color.name) &&
|
|
187
|
-
'outline-muted outline-solid',
|
|
188
|
-
)}
|
|
189
|
-
style={{ backgroundColor: color.value }}
|
|
190
|
-
aria-label={`Seleccionar color ${color.name}`}
|
|
191
|
-
aria-selected={selectedColor.name === color.name}
|
|
192
|
-
/>
|
|
193
|
-
))}
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
{/* Size Selection */}
|
|
198
|
-
<div>
|
|
199
|
-
<div className='mb-4 flex items-center justify-between'>
|
|
200
|
-
<div className='flex items-center'>
|
|
201
|
-
<span className='me-4 text-sm font-medium'>{sizesLabel}</span>
|
|
202
|
-
<div className='border-input flex rounded-sm border p-1'>
|
|
203
|
-
{['eu', 'uk', 'us'].map(type => (
|
|
204
|
-
<Button
|
|
205
|
-
key={type}
|
|
206
|
-
variant='ghost'
|
|
207
|
-
size='sm'
|
|
208
|
-
onClick={() => setSizeType(type as 'eu' | 'uk' | 'us')}
|
|
209
|
-
className={cn(
|
|
210
|
-
'cursor-pointer rounded-sm px-2 text-xs',
|
|
211
|
-
sizeType === type && 'bg-secondary text-secondary-foreground',
|
|
212
|
-
)}
|
|
213
|
-
aria-label={`Seleccionar talla ${type.toUpperCase()}`}
|
|
214
|
-
aria-selected={sizeType === type}
|
|
215
|
-
>
|
|
216
|
-
{type.toUpperCase()}
|
|
217
|
-
</Button>
|
|
218
|
-
))}
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
<Button variant='ghost' className='h-9 px-4 py-2 text-primary cursor-pointer text-sm hover:underline'>
|
|
222
|
-
{sizeGuideLabel}
|
|
223
|
-
</Button>
|
|
224
|
-
</div>
|
|
225
|
-
<div className='grid grid-cols-4 gap-2 xl:grid-cols-5'>
|
|
226
|
-
{product.sizes.map(size => (
|
|
227
|
-
<Button
|
|
228
|
-
key={size.eu}
|
|
229
|
-
variant={selectedSize === size.eu ? 'secondary' : 'outline'}
|
|
230
|
-
onClick={() => setSelectedSize(size.eu)}
|
|
231
|
-
className='h-12 cursor-pointer rounded-full shadow-none'
|
|
232
|
-
>
|
|
233
|
-
{sizeType === 'eu' ? size.eu : sizeType === 'uk' ? size.uk : size.us}
|
|
234
|
-
</Button>
|
|
235
|
-
))}
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
{/* Add to Cart */}
|
|
239
|
-
<div>
|
|
240
|
-
<div className='mb-4 flex gap-4'>
|
|
241
|
-
<Button
|
|
242
|
-
className='h-12 flex-1 cursor-pointer rounded-md'
|
|
243
|
-
size='lg'
|
|
244
|
-
onClick={onAddToCart ? () => onAddToCart(product) : undefined}
|
|
245
|
-
>
|
|
246
|
-
<ShoppingBag />
|
|
247
|
-
{addToCartLabel}
|
|
248
|
-
</Button>
|
|
249
|
-
<Button
|
|
250
|
-
variant='outline'
|
|
251
|
-
size='icon'
|
|
252
|
-
className='border-input size-12 cursor-pointer rounded-md transition-colors'
|
|
253
|
-
onClick={() => {
|
|
254
|
-
const next = !isWishlisted
|
|
255
|
-
setIsWishlisted(next)
|
|
256
|
-
onToggleWishlist?.(product, next)
|
|
257
|
-
}}
|
|
258
|
-
aria-label={isWishlisted ? removeFromWishlistLabel : addToWishlistLabel}
|
|
259
|
-
>
|
|
260
|
-
<ReactionToggle active={isWishlisted} icon={Heart} iconClassName='size-5' activeColorClassName='text-primary' />
|
|
261
|
-
</Button>
|
|
262
|
-
</div>
|
|
263
|
-
<div className='text-muted-foreground flex items-center justify-center gap-2 text-sm'>
|
|
264
|
-
<Truck className='size-4' />
|
|
265
|
-
<span>{freeDeliveryLabel}</span>
|
|
266
|
-
</div>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
</section>
|
|
271
|
-
)
|
|
272
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Camera } from 'lucide-react'
|
|
2
|
-
import { Badge } from '../../../ui/badge'
|
|
3
|
-
import { cn } from '../../../lib/utils'
|
|
4
|
-
|
|
5
|
-
import type { ProductOverview5Product } from './product-overview-5'
|
|
6
|
-
|
|
7
|
-
export interface ProductOverview5GalleryProps {
|
|
8
|
-
product: ProductOverview5Product
|
|
9
|
-
badgeLabel?: string
|
|
10
|
-
selectedImage: number
|
|
11
|
-
onSelectImage: (index: number) => void
|
|
12
|
-
photosLabel?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function ProductOverview5Gallery({
|
|
16
|
-
product,
|
|
17
|
-
badgeLabel,
|
|
18
|
-
selectedImage,
|
|
19
|
-
onSelectImage,
|
|
20
|
-
photosLabel = 'fotos',
|
|
21
|
-
}: ProductOverview5GalleryProps) {
|
|
22
|
-
return (
|
|
23
|
-
<div>
|
|
24
|
-
<div className='bg-muted relative aspect-square overflow-hidden rounded-xl'>
|
|
25
|
-
<img src={product.mainImages[selectedImage] || undefined} alt={product.name} className='size-full object-cover' />
|
|
26
|
-
{badgeLabel && (
|
|
27
|
-
<Badge className='px-2.5 py-0.5 font-semibold absolute top-4 left-4'>
|
|
28
|
-
{badgeLabel}
|
|
29
|
-
</Badge>
|
|
30
|
-
)}
|
|
31
|
-
<div className='absolute right-4 bottom-4 rounded-full bg-black/60 px-3 py-1.5 text-sm text-white backdrop-blur-sm'>
|
|
32
|
-
<Camera className='mr-1 inline size-4' />
|
|
33
|
-
{product.mainImages.length} {photosLabel}
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
{product.mainImages.length > 1 && (
|
|
38
|
-
<div className='mt-4 flex gap-3 overflow-x-auto pb-2'>
|
|
39
|
-
{product.mainImages.map((image, index) => (
|
|
40
|
-
<button
|
|
41
|
-
type='button'
|
|
42
|
-
key={index}
|
|
43
|
-
onClick={() => onSelectImage(index)}
|
|
44
|
-
className={cn(
|
|
45
|
-
'relative aspect-square size-20 flex-shrink-0 cursor-pointer overflow-hidden rounded-lg border-2 transition-all',
|
|
46
|
-
selectedImage === index ? 'border-primary ring-primary/20 shadow-md ring-2' : 'border-muted hover:border-muted-foreground/50',
|
|
47
|
-
)}
|
|
48
|
-
aria-label={`Mostrar imagen ${index + 1} de ${product.name}`}
|
|
49
|
-
>
|
|
50
|
-
<img src={image || undefined} alt={`${product.name} ${index + 1}`} className='size-full object-cover' />
|
|
51
|
-
</button>
|
|
52
|
-
))}
|
|
53
|
-
</div>
|
|
54
|
-
)}
|
|
55
|
-
</div>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default ProductOverview5Gallery
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { Camera, Heart, Info, MessageSquare, Package, Share2, ShoppingCart, Star } from 'lucide-react'
|
|
5
|
-
import { Card, CardContent } from '../../../ui/card'
|
|
6
|
-
import { Button } from '../../../ui/button'
|
|
7
|
-
import { Separator } from '../../../ui/separator'
|
|
8
|
-
import { ReactionToggle } from '../../shared/reaction-toggle'
|
|
9
|
-
import { ProductOverview5Gallery } from './product-overview-5-gallery'
|
|
10
|
-
import { ProductOverview5LightboxTab } from './product-overview-5-lightbox-tab'
|
|
11
|
-
import { ProductOverview5ReviewsTab } from './product-overview-5-reviews-tab'
|
|
12
|
-
import {
|
|
13
|
-
ProductOverview5Tabs,
|
|
14
|
-
ProductOverview5TabsContentFade,
|
|
15
|
-
ProductOverview5TabsIndicator,
|
|
16
|
-
ProductOverview5TabsList,
|
|
17
|
-
ProductOverview5TabsTrigger,
|
|
18
|
-
} from './product-overview-5-tabs'
|
|
19
|
-
|
|
20
|
-
export interface ProductOverview5Review {
|
|
21
|
-
id: number
|
|
22
|
-
author: string
|
|
23
|
-
rating: number
|
|
24
|
-
comment: string
|
|
25
|
-
date: string
|
|
26
|
-
helpful: number
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ProductOverview5Product {
|
|
30
|
-
name: string
|
|
31
|
-
price: number
|
|
32
|
-
originalPrice: null | number
|
|
33
|
-
rating: number
|
|
34
|
-
reviewCount: number
|
|
35
|
-
sku: string
|
|
36
|
-
mainImages: string[]
|
|
37
|
-
galleryImages: string[]
|
|
38
|
-
description: string
|
|
39
|
-
features: string[]
|
|
40
|
-
specifications: Record<string, string>
|
|
41
|
-
userReviews: ProductOverview5Review[]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface ProductOverview5Props {
|
|
45
|
-
product: ProductOverview5Product
|
|
46
|
-
badgeLabel?: string
|
|
47
|
-
availabilityLabel?: string
|
|
48
|
-
currencySymbol?: string
|
|
49
|
-
skuLabel?: string
|
|
50
|
-
overviewLabel?: string
|
|
51
|
-
specsLabel?: string
|
|
52
|
-
featuresLabel?: string
|
|
53
|
-
specificationsLabel?: string
|
|
54
|
-
reviewsLabel?: string
|
|
55
|
-
galleryLabel?: string
|
|
56
|
-
saveLabel?: string
|
|
57
|
-
savedLabel?: string
|
|
58
|
-
shareLabel?: string
|
|
59
|
-
addToCartLabel?: string
|
|
60
|
-
basedOnReviewsLabel?: string
|
|
61
|
-
foundHelpfulLabel?: string
|
|
62
|
-
ofCounterLabel?: string
|
|
63
|
-
photosLabel?: string
|
|
64
|
-
onAddToCart?: (product: ProductOverview5Product) => void
|
|
65
|
-
onToggleWishlist?: (product: ProductOverview5Product, isWishlisted: boolean) => void
|
|
66
|
-
onShare?: (product: ProductOverview5Product) => void
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function renderStars(rating: number) {
|
|
70
|
-
return Array.from({ length: 5 }, (_, i) => (
|
|
71
|
-
<Star key={i} className={`size-4 ${i < Math.floor(rating) ? 'fill-foreground text-foreground' : i < rating ? 'text-foreground' : ''}`} />
|
|
72
|
-
))
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export default function ProductOverview5({
|
|
76
|
-
product,
|
|
77
|
-
badgeLabel = 'Destacado',
|
|
78
|
-
availabilityLabel = 'Disponible',
|
|
79
|
-
currencySymbol = '$',
|
|
80
|
-
skuLabel = 'SKU',
|
|
81
|
-
overviewLabel = 'Resumen',
|
|
82
|
-
specsLabel = 'Especificaciones',
|
|
83
|
-
featuresLabel = 'Características clave',
|
|
84
|
-
specificationsLabel = 'Especificaciones técnicas',
|
|
85
|
-
reviewsLabel = 'Reseñas',
|
|
86
|
-
galleryLabel = 'Galería',
|
|
87
|
-
saveLabel = 'Guardar',
|
|
88
|
-
savedLabel = 'Guardado',
|
|
89
|
-
shareLabel = 'Compartir',
|
|
90
|
-
addToCartLabel = 'Agregar al carrito',
|
|
91
|
-
basedOnReviewsLabel = 'Basado en {count} reseñas',
|
|
92
|
-
foundHelpfulLabel = '{count} personas encontraron esto útil',
|
|
93
|
-
ofCounterLabel = '{current} de {total}',
|
|
94
|
-
photosLabel = 'fotos',
|
|
95
|
-
onAddToCart,
|
|
96
|
-
onToggleWishlist,
|
|
97
|
-
onShare,
|
|
98
|
-
}: ProductOverview5Props) {
|
|
99
|
-
const [selectedImage, setSelectedImage] = useState(0)
|
|
100
|
-
const [isWishlisted, setIsWishlisted] = useState(false)
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
<section className='py-12'>
|
|
104
|
-
<div className='mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8'>
|
|
105
|
-
<div className='grid gap-12 lg:grid-cols-2'>
|
|
106
|
-
<ProductOverview5Gallery
|
|
107
|
-
product={product}
|
|
108
|
-
badgeLabel={badgeLabel}
|
|
109
|
-
selectedImage={selectedImage}
|
|
110
|
-
onSelectImage={setSelectedImage}
|
|
111
|
-
photosLabel={photosLabel}
|
|
112
|
-
/>
|
|
113
|
-
|
|
114
|
-
<div className='flex flex-col gap-8'>
|
|
115
|
-
<div>
|
|
116
|
-
<h1 className='text-3xl leading-tight font-bold text-balance'>{product.name}</h1>
|
|
117
|
-
<div className='mt-4 flex flex-wrap items-center gap-4'>
|
|
118
|
-
<div className='flex items-center gap-2'>
|
|
119
|
-
<div className='flex'>{renderStars(product.rating)}</div>
|
|
120
|
-
<span className='text-sm font-medium'>{product.rating}</span>
|
|
121
|
-
</div>
|
|
122
|
-
<span className='text-muted-foreground text-sm'>
|
|
123
|
-
{product.userReviews.length} {reviewsLabel.toLowerCase()}
|
|
124
|
-
</span>
|
|
125
|
-
<Separator orientation='vertical' className='h-4' />
|
|
126
|
-
<span className='text-muted-foreground text-sm'>
|
|
127
|
-
{skuLabel}: {product.sku}
|
|
128
|
-
</span>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
<div className='flex items-baseline gap-3'>
|
|
133
|
-
<span className='text-4xl font-bold'>
|
|
134
|
-
{currencySymbol}
|
|
135
|
-
{product.price}
|
|
136
|
-
</span>
|
|
137
|
-
{product.originalPrice && (
|
|
138
|
-
<span className='text-muted-foreground text-xl line-through'>
|
|
139
|
-
{currencySymbol}
|
|
140
|
-
{product.originalPrice}
|
|
141
|
-
</span>
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
<div className='inline-flex items-center w-fit gap-2 rounded-full bg-success/10 px-3 py-1.5'>
|
|
146
|
-
<div className='size-2 rounded-full bg-success' />
|
|
147
|
-
<span className='text-sm font-medium text-success'>{availabilityLabel}</span>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<p className='text-muted-foreground leading-relaxed'>{product.description}</p>
|
|
151
|
-
|
|
152
|
-
<div className='flex flex-col gap-4'>
|
|
153
|
-
<Button
|
|
154
|
-
size='lg'
|
|
155
|
-
className='h-12 w-full cursor-pointer gap-2'
|
|
156
|
-
onClick={onAddToCart ? () => onAddToCart(product) : undefined}
|
|
157
|
-
>
|
|
158
|
-
<ShoppingCart />
|
|
159
|
-
{addToCartLabel}
|
|
160
|
-
</Button>
|
|
161
|
-
<div className='flex gap-3'>
|
|
162
|
-
<Button
|
|
163
|
-
variant='outline'
|
|
164
|
-
size='lg'
|
|
165
|
-
className='h-12 flex-1 cursor-pointer gap-2'
|
|
166
|
-
aria-pressed={isWishlisted}
|
|
167
|
-
onClick={() => {
|
|
168
|
-
const next = !isWishlisted
|
|
169
|
-
setIsWishlisted(next)
|
|
170
|
-
onToggleWishlist?.(product, next)
|
|
171
|
-
}}
|
|
172
|
-
>
|
|
173
|
-
<ReactionToggle active={isWishlisted} icon={Heart} activeColorClassName='text-destructive' />
|
|
174
|
-
{isWishlisted ? savedLabel : saveLabel}
|
|
175
|
-
</Button>
|
|
176
|
-
<Button
|
|
177
|
-
variant='outline'
|
|
178
|
-
size='lg'
|
|
179
|
-
className='h-12 flex-1 cursor-pointer gap-2'
|
|
180
|
-
onClick={onShare ? () => onShare(product) : undefined}
|
|
181
|
-
>
|
|
182
|
-
<Share2 />
|
|
183
|
-
{shareLabel}
|
|
184
|
-
</Button>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
|
|
190
|
-
<div className='mt-16'>
|
|
191
|
-
<ProductOverview5Tabs defaultValue='overview' className='w-full'>
|
|
192
|
-
<ProductOverview5TabsList className='bg-muted/50 relative grid !h-12 w-full grid-cols-4 rounded-xl p-1'>
|
|
193
|
-
<ProductOverview5TabsIndicator />
|
|
194
|
-
<ProductOverview5TabsTrigger
|
|
195
|
-
value='overview'
|
|
196
|
-
className='z-10 h-10 gap-2 text-sm font-medium data-active:bg-transparent data-active:shadow-none dark:data-active:bg-transparent'
|
|
197
|
-
>
|
|
198
|
-
<Info className='size-4 shrink-0' />
|
|
199
|
-
<span className='hidden sm:inline'>{overviewLabel}</span>
|
|
200
|
-
</ProductOverview5TabsTrigger>
|
|
201
|
-
<ProductOverview5TabsTrigger
|
|
202
|
-
value='specs'
|
|
203
|
-
className='z-10 h-10 gap-2 text-sm font-medium data-active:bg-transparent data-active:shadow-none dark:data-active:bg-transparent'
|
|
204
|
-
>
|
|
205
|
-
<Package className='size-4 shrink-0' />
|
|
206
|
-
<span className='hidden sm:inline'>{specsLabel}</span>
|
|
207
|
-
</ProductOverview5TabsTrigger>
|
|
208
|
-
<ProductOverview5TabsTrigger
|
|
209
|
-
value='reviews'
|
|
210
|
-
className='z-10 h-10 gap-2 text-sm font-medium data-active:bg-transparent data-active:shadow-none dark:data-active:bg-transparent'
|
|
211
|
-
>
|
|
212
|
-
<MessageSquare className='size-4 shrink-0' />
|
|
213
|
-
<span className='hidden sm:inline'>
|
|
214
|
-
{reviewsLabel} ({product.userReviews.length})
|
|
215
|
-
</span>
|
|
216
|
-
</ProductOverview5TabsTrigger>
|
|
217
|
-
<ProductOverview5TabsTrigger
|
|
218
|
-
value='gallery'
|
|
219
|
-
className='z-10 h-10 gap-2 text-sm font-medium data-active:bg-transparent data-active:shadow-none dark:data-active:bg-transparent'
|
|
220
|
-
>
|
|
221
|
-
<Camera className='size-4 shrink-0' />
|
|
222
|
-
<span className='hidden sm:inline'>{galleryLabel}</span>
|
|
223
|
-
</ProductOverview5TabsTrigger>
|
|
224
|
-
</ProductOverview5TabsList>
|
|
225
|
-
<ProductOverview5TabsContentFade value='overview' className='mt-8'>
|
|
226
|
-
<Card className='border shadow-none'>
|
|
227
|
-
<CardContent className='p-8 py-0'>
|
|
228
|
-
<h3 className='mb-6 text-xl font-semibold text-balance'>{featuresLabel}</h3>
|
|
229
|
-
<div className='grid gap-4 sm:grid-cols-2'>
|
|
230
|
-
{product.features.map(feature => (
|
|
231
|
-
<div key={feature} className='group flex items-center gap-3'>
|
|
232
|
-
<div className='bg-primary/20 size-2 rounded-full transition-colors' />
|
|
233
|
-
<span className='text-sm'>{feature}</span>
|
|
234
|
-
</div>
|
|
235
|
-
))}
|
|
236
|
-
</div>
|
|
237
|
-
</CardContent>
|
|
238
|
-
</Card>
|
|
239
|
-
</ProductOverview5TabsContentFade>
|
|
240
|
-
<ProductOverview5TabsContentFade value='specs' className='mt-8'>
|
|
241
|
-
<Card className='border shadow-none'>
|
|
242
|
-
<CardContent className='p-8 py-0'>
|
|
243
|
-
<h3 className='mb-6 text-xl font-semibold text-balance'>{specificationsLabel}</h3>
|
|
244
|
-
<div className='flex flex-col gap-4'>
|
|
245
|
-
{Object.entries(product.specifications).map(([key, value]) => (
|
|
246
|
-
<div key={key} className='border-muted grid grid-cols-1 gap-2 border-b py-3 last:border-b-0 md:grid-cols-3 md:gap-4'>
|
|
247
|
-
<span className='text-muted-foreground text-sm font-medium'>{key}</span>
|
|
248
|
-
<span className='col-span-1 text-sm md:col-span-2'>{value}</span>
|
|
249
|
-
</div>
|
|
250
|
-
))}
|
|
251
|
-
</div>
|
|
252
|
-
</CardContent>
|
|
253
|
-
</Card>
|
|
254
|
-
</ProductOverview5TabsContentFade>
|
|
255
|
-
<ProductOverview5TabsContentFade value='reviews' className='mt-8'>
|
|
256
|
-
<ProductOverview5ReviewsTab
|
|
257
|
-
product={product}
|
|
258
|
-
basedOnReviewsLabel={basedOnReviewsLabel}
|
|
259
|
-
foundHelpfulLabel={foundHelpfulLabel}
|
|
260
|
-
/>
|
|
261
|
-
</ProductOverview5TabsContentFade>
|
|
262
|
-
<ProductOverview5TabsContentFade value='gallery' className='mt-8'>
|
|
263
|
-
<ProductOverview5LightboxTab
|
|
264
|
-
product={product}
|
|
265
|
-
galleryLabel={galleryLabel}
|
|
266
|
-
ofCounterLabel={ofCounterLabel}
|
|
267
|
-
/>
|
|
268
|
-
</ProductOverview5TabsContentFade>
|
|
269
|
-
</ProductOverview5Tabs>
|
|
270
|
-
</div>
|
|
271
|
-
</div>
|
|
272
|
-
</section>
|
|
273
|
-
)
|
|
274
|
-
}
|