@crm-market/template-shared 1.0.7 → 1.0.8
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/assets/scss/_variables.scss +3 -3
- package/assets/scss/components/_header.scss +1 -1
- package/assets/scss/style.css +4 -4
- package/components/AboutUs/StaticContent.vue +32 -0
- package/components/Cart/CartEmpty.vue +42 -0
- package/components/Cart/CartItem.vue +145 -0
- package/components/Cart/CartSummary.vue +57 -0
- package/components/Cart/ProductQuantity.vue +23 -13
- package/components/Cart/index.vue +68 -150
- package/components/Categories/index.vue +88 -291
- package/components/Checkout/AddressFields.vue +74 -0
- package/components/Checkout/CheckoutForm.vue +75 -0
- package/components/Checkout/CityAutocomplete.vue +68 -0
- package/components/Checkout/DeliveryMethodCard.vue +66 -0
- package/components/Checkout/DeliveryOptions.vue +148 -0
- package/components/Checkout/OrderSummary.vue +116 -0
- package/components/Checkout/PaymentOptions.vue +76 -0
- package/components/Checkout/PickupPoints.vue +46 -0
- package/components/Checkout/PromoCode.vue +166 -0
- package/components/Checkout/index.vue +235 -173
- package/components/Checkout/types.ts +45 -0
- package/components/Common/PageBanner.vue +22 -20
- package/components/Common/ProductCard.vue +139 -115
- package/components/Common/Services.vue +4 -4
- package/components/Contact/ContactForm.vue +44 -74
- package/components/Contact/ContactInfo.vue +35 -61
- package/components/FAQ/index.vue +6 -119
- package/components/Layout/Copyright.vue +11 -9
- package/components/Layout/Footer.vue +49 -136
- package/components/Layout/HeaderBar.vue +174 -0
- package/components/Layout/HeaderLogo.vue +27 -0
- package/components/Layout/MiddleHeader.vue +1 -228
- package/components/Layout/MiddleHeaderThree.vue +1 -203
- package/components/Layout/MiddleHeaderTwo.vue +1 -239
- package/components/Layout/NavLinks.vue +23 -0
- package/components/Layout/Navbar.vue +38 -151
- package/components/Layout/NavbarStyleFour.vue +1 -332
- package/components/Layout/NavbarStyleThree.vue +1 -188
- package/components/Layout/NavbarStyleTwo.vue +1 -108
- package/components/Layout/Preloader.vue +5 -12
- package/components/Layout/ResponsiveNavbar.vue +32 -418
- package/components/Layout/SitewideBanner.vue +285 -0
- package/components/Layout/TopHeader.vue +17 -83
- package/components/Layout/layoutData.ts +83 -0
- package/components/PrivacyPolicy/index.vue +6 -110
- package/components/ProductDetails/ProductDetailsTab.vue +31 -321
- package/components/ProductDetails/ProductGallery.vue +45 -0
- package/components/ProductDetails/ProductQuantity.vue +8 -14
- package/components/ProductDetails/RecentlyViewed.vue +53 -289
- package/components/ProductDetails/RelatedProducts.vue +64 -0
- package/components/ProductDetails/index.vue +90 -230
- package/components/Products/index.vue +78 -16
- package/components/TermsConditions/index.vue +6 -110
- package/components/Wishlist/index.vue +62 -88
- package/composables/useCart.ts +133 -81
- package/composables/useCategories.ts +66 -29
- package/composables/useCategoryImages.ts +45 -0
- package/composables/useCheckout.ts +302 -95
- package/composables/useContactForm.ts +57 -0
- package/composables/useHomeContent.ts +220 -0
- package/composables/useI18n.ts +12 -24
- package/composables/useJsonLd.ts +162 -0
- package/composables/useProducts.ts +244 -81
- package/composables/useRecent.ts +30 -0
- package/composables/useSanitize.ts +76 -0
- package/composables/useSiteConfig.ts +51 -45
- package/composables/useStaticPages.ts +48 -0
- package/composables/useStoreOrigin.ts +32 -0
- package/composables/useTemplateSections.ts +51 -3
- package/composables/useThemeVars.ts +113 -0
- package/composables/useWishlist.ts +72 -0
- package/layouts/default.vue +80 -19
- package/locales/en.json +255 -86
- package/locales/uk.json +251 -82
- package/modules/template-schema.ts +35 -0
- package/nuxt.config.ts +8 -11
- package/package.json +1 -1
- package/pages/about-us.vue +9 -9
- package/pages/cart.vue +0 -1
- package/pages/categories.vue +0 -1
- package/pages/category/[slug].vue +84 -0
- package/pages/checkout.vue +0 -1
- package/pages/contact.vue +6 -6
- package/pages/delivery.vue +12 -0
- package/pages/faq.vue +6 -6
- package/pages/order-success.vue +113 -0
- package/pages/privacy-policy.vue +6 -6
- package/pages/product/[slug].vue +82 -0
- package/pages/product-details.vue +14 -6
- package/pages/products.vue +12 -1
- package/pages/returns.vue +12 -0
- package/pages/terms-conditions.vue +6 -6
- package/pages/wishlist.vue +2 -2
- package/utils/seo-urls.ts +70 -0
- package/utils/store-origin.ts +36 -0
- package/components/AboutUs/AboutUsTuan.vue +0 -25
- package/components/AboutUs/Statistics.vue +0 -42
- package/components/AboutUs/SubscribeToTheNewsletter.vue +0 -57
- package/components/AddAddress/index.vue +0 -68
- package/components/BestSellers/Products.vue +0 -1562
- package/components/BestSellers/RecentlyViewed.vue +0 -304
- package/components/ChangePassword/index.vue +0 -69
- package/components/Common/DashboardNavigation.vue +0 -35
- package/components/Dashboard/RecentOrder.vue +0 -173
- package/components/Dashboard/index.vue +0 -77
- package/components/EditAddress/index.vue +0 -117
- package/components/EditProfile/index.vue +0 -95
- package/components/FeaturedProduct/FeaturedProducts.vue +0 -304
- package/components/FeaturedProduct/Products.vue +0 -1562
- package/components/ForgotPassword/index.vue +0 -49
- package/components/Layout/FooterTwo.vue +0 -159
- package/components/Layout/LocationOption.vue +0 -178
- package/components/Layout/RTLSwitchBtn.vue +0 -40
- package/components/Login/index.vue +0 -89
- package/components/MyAccount/index.vue +0 -154
- package/components/NewArrivals/Products.vue +0 -1969
- package/components/NewArrivals/RecentlyViewed.vue +0 -304
- package/components/OrderDetails/index.vue +0 -75
- package/components/OrderHistory/index.vue +0 -195
- package/components/Products/RecentlyViewed.vue +0 -302
- package/components/Register/index.vue +0 -83
- package/components/TrendingProducts/FeaturedProducts.vue +0 -304
- package/components/TrendingProducts/Products.vue +0 -1564
- package/components/Wishlist/ProductQuantity.vue +0 -29
- package/layouts/inner.vue +0 -70
- package/locales/ar.json +0 -234
- package/locales/ru.json +0 -234
- package/pages/address.vue +0 -11
- package/pages/change-password.vue +0 -11
- package/pages/dashboard.vue +0 -11
- package/pages/edit-address.vue +0 -11
- package/pages/edit-profile.vue +0 -11
- package/pages/forgot-password.vue +0 -11
- package/pages/login.vue +0 -11
- package/pages/my-account.vue +0 -11
- package/pages/order-details.vue +0 -11
- package/pages/order-history.vue +0 -11
- package/pages/register.vue +0 -11
|
@@ -1,343 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<v-tabs
|
|
4
|
-
v-
|
|
5
|
-
|
|
6
|
-
class="product-tabs d-block border-0"
|
|
7
|
-
>
|
|
8
|
-
<v-tab value="description"> Description </v-tab>
|
|
9
|
-
<v-tab value="specification"> Specification </v-tab>
|
|
10
|
-
<v-tab value="reviews"> Reviews </v-tab>
|
|
3
|
+
<v-tabs v-model="tab" bg-color="white" class="product-tabs d-block border-0">
|
|
4
|
+
<v-tab value="description">{{ t('product.description') }}</v-tab>
|
|
5
|
+
<v-tab v-if="specs.length" value="specification">{{ t('product.specification') }}</v-tab>
|
|
11
6
|
</v-tabs>
|
|
12
7
|
|
|
13
8
|
<v-card-text>
|
|
14
9
|
<v-tabs-window v-model="tab">
|
|
15
10
|
<v-tabs-window-item value="description">
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
deliver exceptional performance and advanced features for
|
|
20
|
-
professionals and creative enthusiasts. With its sleek aluminum
|
|
21
|
-
body and precision engineering, this MacBook Pro represents the
|
|
22
|
-
pinnacle of Apple's laptop technology.
|
|
23
|
-
</p>
|
|
24
|
-
<p class="mb-3">
|
|
25
|
-
Stay connected with a variety of ports, including Thunderbolt 3,
|
|
26
|
-
USB-C, and audio jacks. These versatile ports support high-speed
|
|
27
|
-
data transfer and external device connections. Enjoy a rich audio
|
|
28
|
-
experience with high-fidelity speakers that deliver clear and
|
|
29
|
-
immersive sound. Perfect for content creators and multimedia
|
|
30
|
-
enthusiasts.
|
|
31
|
-
</p>
|
|
32
|
-
<p>
|
|
33
|
-
Equipped with the latest processors, ample RAM, and
|
|
34
|
-
high-performance graphics, the MacBook Pro 16.2 ensures smooth
|
|
35
|
-
multitasking, fast rendering, and efficient handling of
|
|
36
|
-
resource-intensive tasks. Seamlessly integrate with the macOS
|
|
37
|
-
ecosystem, benefiting from features like iCloud, Siri, and a vast
|
|
38
|
-
selection of applications available on the App Store.
|
|
39
|
-
</p>
|
|
40
|
-
</div>
|
|
11
|
+
<!-- Опис від продавця: лише очищений білим списком HTML (useSanitize) -->
|
|
12
|
+
<div v-if="safeDescription" class="description-conetnt" v-html="safeDescription"></div>
|
|
13
|
+
<p v-else class="text-muted mb-0">{{ t('product.noDescription') }}</p>
|
|
41
14
|
</v-tabs-window-item>
|
|
42
|
-
<v-tabs-window-item value="specification">
|
|
15
|
+
<v-tabs-window-item v-if="specs.length" value="specification">
|
|
43
16
|
<div class="additional-info table-responsive p-0">
|
|
44
17
|
<table class="table table-bordered">
|
|
45
18
|
<tbody>
|
|
46
|
-
<tr>
|
|
47
|
-
<td class="title text-dark">
|
|
48
|
-
<td class="price">
|
|
49
|
-
</tr>
|
|
50
|
-
<tr>
|
|
51
|
-
<td class="title text-dark">Categories</td>
|
|
52
|
-
<td class="price">Brond New</td>
|
|
53
|
-
</tr>
|
|
54
|
-
<tr>
|
|
55
|
-
<td class="title text-dark">SKU</td>
|
|
56
|
-
<td class="price">01</td>
|
|
57
|
-
</tr>
|
|
58
|
-
<tr>
|
|
59
|
-
<td class="title text-dark">Price</td>
|
|
60
|
-
<td class="price">$399</td>
|
|
19
|
+
<tr v-for="row in specs" :key="row.name">
|
|
20
|
+
<td class="title text-dark">{{ row.name }}</td>
|
|
21
|
+
<td class="price">{{ row.value }}</td>
|
|
61
22
|
</tr>
|
|
62
23
|
</tbody>
|
|
63
24
|
</table>
|
|
64
25
|
</div>
|
|
65
26
|
</v-tabs-window-item>
|
|
66
|
-
<v-tabs-window-item value="reviews">
|
|
67
|
-
<div class="product-reviews">
|
|
68
|
-
<div class="total-rating-wrap">
|
|
69
|
-
<div class="row">
|
|
70
|
-
<div class="col-lg-3 col-md-3">
|
|
71
|
-
<span class="title text-start">Average Rating </span>
|
|
72
|
-
<div class="total-review text-center mb-4 mb-md-0 rounded-0">
|
|
73
|
-
<h1>4.8</h1>
|
|
74
|
-
<ul
|
|
75
|
-
class="d-flex justify-content-center ps-0 list-unstyled"
|
|
76
|
-
>
|
|
77
|
-
<li>
|
|
78
|
-
<i class="ri-star-line"></i>
|
|
79
|
-
</li>
|
|
80
|
-
<li>
|
|
81
|
-
<i class="ri-star-line"></i>
|
|
82
|
-
</li>
|
|
83
|
-
<li>
|
|
84
|
-
<i class="ri-star-line"></i>
|
|
85
|
-
</li>
|
|
86
|
-
<li>
|
|
87
|
-
<i class="ri-star-line"></i>
|
|
88
|
-
</li>
|
|
89
|
-
<li>
|
|
90
|
-
<i class="ri-star-line"></i>
|
|
91
|
-
</li>
|
|
92
|
-
</ul>
|
|
93
|
-
<span>5 Rating</span>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
<div class="col-lg-9 col-md-9">
|
|
98
|
-
<span class="title text-start">Detailed Rating</span>
|
|
99
|
-
<ul class="ps-0 mb-0 list-unstyled total-rating">
|
|
100
|
-
<li class="d-flex align-items-center">
|
|
101
|
-
<div class="d-flex align-items-center">
|
|
102
|
-
<span class="ms-2">5</span>
|
|
103
|
-
</div>
|
|
104
|
-
<div class="w-100 px-2">
|
|
105
|
-
<v-progress-linear
|
|
106
|
-
color="blue-accent-2"
|
|
107
|
-
model-value="100"
|
|
108
|
-
rounded
|
|
109
|
-
></v-progress-linear>
|
|
110
|
-
</div>
|
|
111
|
-
<span class="rating">3%</span>
|
|
112
|
-
</li>
|
|
113
|
-
<li class="d-flex align-items-center">
|
|
114
|
-
<div class="d-flex align-items-center">
|
|
115
|
-
<span class="ms-2">4</span>
|
|
116
|
-
</div>
|
|
117
|
-
<div class="w-100 px-2">
|
|
118
|
-
<v-progress-linear
|
|
119
|
-
color="blue-accent-2"
|
|
120
|
-
model-value="70"
|
|
121
|
-
rounded
|
|
122
|
-
></v-progress-linear>
|
|
123
|
-
</div>
|
|
124
|
-
<span class="rating">2%</span>
|
|
125
|
-
</li>
|
|
126
|
-
<li class="d-flex align-items-center">
|
|
127
|
-
<div class="d-flex align-items-center">
|
|
128
|
-
<span class="ms-2">3</span>
|
|
129
|
-
</div>
|
|
130
|
-
<div class="w-100 px-2">
|
|
131
|
-
<v-progress-linear
|
|
132
|
-
color="blue-accent-2"
|
|
133
|
-
model-value="0"
|
|
134
|
-
rounded
|
|
135
|
-
></v-progress-linear>
|
|
136
|
-
</div>
|
|
137
|
-
<span class="rating">0%</span>
|
|
138
|
-
</li>
|
|
139
|
-
<li class="d-flex align-items-center">
|
|
140
|
-
<div class="d-flex align-items-center">
|
|
141
|
-
<span class="ms-2">2</span>
|
|
142
|
-
</div>
|
|
143
|
-
<div class="w-100 px-2">
|
|
144
|
-
<v-progress-linear
|
|
145
|
-
color="blue-accent-2"
|
|
146
|
-
model-value="0"
|
|
147
|
-
rounded
|
|
148
|
-
></v-progress-linear>
|
|
149
|
-
</div>
|
|
150
|
-
<span class="rating">0%</span>
|
|
151
|
-
</li>
|
|
152
|
-
<li class="d-flex align-items-center">
|
|
153
|
-
<div class="d-flex align-items-center">
|
|
154
|
-
<span class="ms-2">1</span>
|
|
155
|
-
</div>
|
|
156
|
-
<div class="w-100 px-2">
|
|
157
|
-
<v-progress-linear
|
|
158
|
-
color="blue-accent-2"
|
|
159
|
-
model-value="0"
|
|
160
|
-
rounded
|
|
161
|
-
></v-progress-linear>
|
|
162
|
-
</div>
|
|
163
|
-
<span class="rating">0%</span>
|
|
164
|
-
</li>
|
|
165
|
-
</ul>
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
<h3>Client Feedback</h3>
|
|
171
|
-
|
|
172
|
-
<ul class="comment-list ps-0 list-unstyled m-0 pb-5 mb-lg-5">
|
|
173
|
-
<li>
|
|
174
|
-
<div class="d-sm-flex">
|
|
175
|
-
<div class="flex-shrink-0">
|
|
176
|
-
<div class="border-style d-inline-block mb-3 mb-sm-0">
|
|
177
|
-
<img
|
|
178
|
-
class="rounded-circle wh-108"
|
|
179
|
-
src="~/assets/images/user-8.jpg"
|
|
180
|
-
alt="user-1"
|
|
181
|
-
/>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
<div class="flex-grow-1 ms-0 ms-sm-4">
|
|
185
|
-
<h4>Maria Cruz</h4>
|
|
186
|
-
<div class="d-flex align-items-center">
|
|
187
|
-
<div class="d-flex">
|
|
188
|
-
<i class="ri-star-fill"></i>
|
|
189
|
-
<i class="ri-star-fill"></i>
|
|
190
|
-
<i class="ri-star-fill"></i>
|
|
191
|
-
<i class="ri-star-fill"></i>
|
|
192
|
-
<i class="ri-star-fill"></i>
|
|
193
|
-
</div>
|
|
194
|
-
<span>(5.00)</span>
|
|
195
|
-
</div>
|
|
196
|
-
<p>
|
|
197
|
-
Pellentesque urna varius nunc risus. Nisl sagittis et id
|
|
198
|
-
ac faucibus sollicitudin purus. Mattis a ac purus sapien
|
|
199
|
-
mauris mauris sagittis ut in. Molestie integer luctus nam
|
|
200
|
-
duis egestas placerat amet netus. Est ut ligula aliquam
|
|
201
|
-
sed.
|
|
202
|
-
</p>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
</li>
|
|
206
|
-
<li>
|
|
207
|
-
<div class="d-sm-flex">
|
|
208
|
-
<div class="flex-shrink-0">
|
|
209
|
-
<div class="border-style d-inline-block mb-3 mb-sm-0">
|
|
210
|
-
<img
|
|
211
|
-
class="rounded-10 wh-108 rounded-circle"
|
|
212
|
-
src="~/assets/images/user-9.jpg"
|
|
213
|
-
alt="user-2"
|
|
214
|
-
/>
|
|
215
|
-
</div>
|
|
216
|
-
</div>
|
|
217
|
-
<div class="flex-grow-1 ms-0 ms-sm-4">
|
|
218
|
-
<h4>Anthony Hernandez</h4>
|
|
219
|
-
<div class="d-flex align-items-center">
|
|
220
|
-
<div class="d-flex">
|
|
221
|
-
<i class="ri-star-fill"></i>
|
|
222
|
-
<i class="ri-star-fill"></i>
|
|
223
|
-
<i class="ri-star-fill"></i>
|
|
224
|
-
<i class="ri-star-fill"></i>
|
|
225
|
-
<i class="ri-star-fill"></i>
|
|
226
|
-
</div>
|
|
227
|
-
<span>(5.00)</span>
|
|
228
|
-
</div>
|
|
229
|
-
<p>
|
|
230
|
-
Molestie integer luctus nam duis egestas placerat amet
|
|
231
|
-
netus. Est ut ligula aliquam sed. Enim tincidunt
|
|
232
|
-
adipiscing consectetur mauris tincidunt quam. Ipsum
|
|
233
|
-
aliquet aliquet cras nec in eget tristique. Facilisis
|
|
234
|
-
purus viverra interdum viverra.
|
|
235
|
-
</p>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</li>
|
|
239
|
-
<li>
|
|
240
|
-
<div class="d-sm-flex">
|
|
241
|
-
<div class="flex-shrink-0">
|
|
242
|
-
<div class="border-style d-inline-block mb-3 mb-sm-0">
|
|
243
|
-
<img
|
|
244
|
-
class="rounded-10 wh-108 rounded-circle"
|
|
245
|
-
src="~/assets/images/user-10.jpg"
|
|
246
|
-
alt="user-3"
|
|
247
|
-
/>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
<div class="flex-grow-1 ms-0 ms-sm-4">
|
|
251
|
-
<h4>Mildred Benally</h4>
|
|
252
|
-
<div class="d-flex align-items-center">
|
|
253
|
-
<div class="d-flex">
|
|
254
|
-
<i class="ri-star-fill"></i>
|
|
255
|
-
<i class="ri-star-fill"></i>
|
|
256
|
-
<i class="ri-star-fill"></i>
|
|
257
|
-
<i class="ri-star-fill"></i>
|
|
258
|
-
<i class="ri-star-half-fill"></i>
|
|
259
|
-
</div>
|
|
260
|
-
<span>(4.80)</span>
|
|
261
|
-
</div>
|
|
262
|
-
<p>
|
|
263
|
-
Nisl sagittis et id ac faucibus sollicitudin purus. Mattis
|
|
264
|
-
a ac purus sapien mauris mauris sagittis ut in. Molestie
|
|
265
|
-
integer luctus nam duis egestas placerat amet netus. Est
|
|
266
|
-
ut ligula aliquam sed.
|
|
267
|
-
</p>
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
</li>
|
|
271
|
-
</ul>
|
|
272
|
-
|
|
273
|
-
<div class="review-form">
|
|
274
|
-
<h3>Write A Review</h3>
|
|
275
|
-
<div class="d-flex align-items-center rate">
|
|
276
|
-
<i class="ri-star-fill"></i>
|
|
277
|
-
<i class="ri-star-fill"></i>
|
|
278
|
-
<i class="ri-star-fill"></i>
|
|
279
|
-
<i class="ri-star-fill"></i>
|
|
280
|
-
<i class="ri-star-half-fill"></i>
|
|
281
|
-
<span>(3)</span>
|
|
282
|
-
</div>
|
|
283
|
-
<form>
|
|
284
|
-
<div class="row">
|
|
285
|
-
<div class="col-lg-6">
|
|
286
|
-
<div class="form-group mb-4">
|
|
287
|
-
<label class="label">Full Name</label>
|
|
288
|
-
<input
|
|
289
|
-
type="text"
|
|
290
|
-
class="form-control"
|
|
291
|
-
placeholder="Kim Keener"
|
|
292
|
-
/>
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
<div class="col-lg-6">
|
|
296
|
-
<div class="form-group mb-4">
|
|
297
|
-
<label class="label">Email</label>
|
|
298
|
-
<input
|
|
299
|
-
type="email"
|
|
300
|
-
class="form-control"
|
|
301
|
-
placeholder="hello@tuan.com"
|
|
302
|
-
/>
|
|
303
|
-
</div>
|
|
304
|
-
</div>
|
|
305
|
-
<div class="col-lg-12">
|
|
306
|
-
<div class="form-group mb-4">
|
|
307
|
-
<label class="label">Summary</label>
|
|
308
|
-
<textarea
|
|
309
|
-
class="form-control"
|
|
310
|
-
placeholder="Write review summary"
|
|
311
|
-
cols="30"
|
|
312
|
-
rows="10"
|
|
313
|
-
></textarea>
|
|
314
|
-
</div>
|
|
315
|
-
</div>
|
|
316
|
-
<div class="col-lg-12">
|
|
317
|
-
<div class="form-group mb-0">
|
|
318
|
-
<button
|
|
319
|
-
type="submit"
|
|
320
|
-
class="btn btn-warning text-white rounded-pill"
|
|
321
|
-
>
|
|
322
|
-
Submit Now
|
|
323
|
-
</button>
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
327
|
-
</form>
|
|
328
|
-
</div>
|
|
329
|
-
</div>
|
|
330
|
-
</v-tabs-window-item>
|
|
331
27
|
</v-tabs-window>
|
|
332
28
|
</v-card-text>
|
|
333
29
|
</div>
|
|
334
30
|
</template>
|
|
335
31
|
|
|
336
|
-
<script>
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { computed, ref } from 'vue';
|
|
34
|
+
import { sanitizeHtml } from '../../composables/useSanitize';
|
|
35
|
+
import type { Product } from '../../composables/useProducts';
|
|
36
|
+
|
|
37
|
+
const props = defineProps<{ product: Product }>();
|
|
38
|
+
|
|
39
|
+
const { t } = useI18n();
|
|
40
|
+
const tab = ref('description');
|
|
41
|
+
|
|
42
|
+
const safeDescription = computed(() => sanitizeHtml(props.product.description));
|
|
43
|
+
|
|
44
|
+
// Характеристики з attributes (значення можуть бути рядками, числами, масивами)
|
|
45
|
+
const specs = computed(() =>
|
|
46
|
+
Object.entries(props.product.attributes || {})
|
|
47
|
+
.map(([name, value]) => ({
|
|
48
|
+
name,
|
|
49
|
+
value: Array.isArray(value) ? value.join(', ') : typeof value === 'object' && value ? JSON.stringify(value) : String(value ?? ''),
|
|
50
|
+
}))
|
|
51
|
+
.filter((r) => r.value !== ''),
|
|
52
|
+
);
|
|
343
53
|
</script>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<v-card-text>
|
|
4
|
+
<v-tabs-window v-model="tab">
|
|
5
|
+
<v-tabs-window-item v-for="(img, i) in images" :key="img.key" :value="`img${i}`">
|
|
6
|
+
<div class="product-details-img">
|
|
7
|
+
<img :src="img.src" :alt="img.alt" />
|
|
8
|
+
</div>
|
|
9
|
+
</v-tabs-window-item>
|
|
10
|
+
<span v-if="discount" class="discounts">{{ discount }}</span>
|
|
11
|
+
</v-tabs-window>
|
|
12
|
+
<div v-if="!images.length" class="product-details-img d-flex align-items-center justify-content-center bg-light" style="aspect-ratio: 1 / 1">
|
|
13
|
+
<i class="ri-image-line text-muted" style="font-size: 4rem"></i>
|
|
14
|
+
</div>
|
|
15
|
+
</v-card-text>
|
|
16
|
+
|
|
17
|
+
<v-tabs v-if="images.length > 1" v-model="tab" bg-color="white" class="products-tabs justify-content-center">
|
|
18
|
+
<v-tab v-for="(img, i) in images" :key="img.key" :value="`img${i}`">
|
|
19
|
+
<img :src="img.src" :alt="img.alt" />
|
|
20
|
+
</v-tab>
|
|
21
|
+
</v-tabs>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { computed, ref } from 'vue';
|
|
27
|
+
import { resolveMediaUrl, type Product } from '../../composables/useProducts';
|
|
28
|
+
|
|
29
|
+
const props = defineProps<{ product: Product; /** Готовий бейдж: «-20%» або «-50 ₴» */ discount?: string }>();
|
|
30
|
+
|
|
31
|
+
const tab = ref('img0');
|
|
32
|
+
|
|
33
|
+
// Картинки: головна першою, далі за sortOrder
|
|
34
|
+
const images = computed(() => {
|
|
35
|
+
const list = [...(props.product.images || [])]
|
|
36
|
+
.map((img: any) => (typeof img === 'string' ? { url: img } : img))
|
|
37
|
+
.filter((img) => img?.url)
|
|
38
|
+
.sort((a, b) => Number(!!b.isMain) - Number(!!a.isMain) || (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
|
39
|
+
return list.map((img, i) => ({
|
|
40
|
+
key: img.id || `${img.url}-${i}`,
|
|
41
|
+
src: resolveMediaUrl(img.url),
|
|
42
|
+
alt: img.alt || props.product.title || '',
|
|
43
|
+
}));
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="product-quantity">
|
|
3
3
|
<div class="add-to-cart-counter">
|
|
4
|
-
<div @click="
|
|
4
|
+
<div @click="change(-1)">
|
|
5
5
|
<input type="button" class="minusBtn" value="-" />
|
|
6
6
|
</div>
|
|
7
|
-
<input type="text" size="25"
|
|
8
|
-
<div @click="
|
|
7
|
+
<input type="text" size="25" :value="modelValue" readonly class="count" />
|
|
8
|
+
<div @click="change(1)">
|
|
9
9
|
<input type="button" class="plusBtn" value="+" />
|
|
10
10
|
</div>
|
|
11
11
|
</div>
|
|
@@ -13,17 +13,11 @@
|
|
|
13
13
|
</template>
|
|
14
14
|
|
|
15
15
|
<script lang="ts" setup>
|
|
16
|
-
|
|
16
|
+
const props = defineProps<{ modelValue: number }>();
|
|
17
|
+
const emit = defineEmits<{ (e: 'update:modelValue', value: number): void }>();
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
internalValue.value++;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const decrement = () => {
|
|
25
|
-
if (internalValue.value > 0) {
|
|
26
|
-
internalValue.value--;
|
|
27
|
-
}
|
|
19
|
+
// Кількість не може бути меншою за 1
|
|
20
|
+
const change = (delta: number) => {
|
|
21
|
+
emit('update:modelValue', Math.max(1, props.modelValue + delta));
|
|
28
22
|
};
|
|
29
23
|
</script>
|