@crm-market/template-shared 1.0.6 → 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.
Files changed (139) hide show
  1. package/assets/scss/_variables.scss +3 -3
  2. package/assets/scss/components/_header.scss +1 -1
  3. package/assets/scss/style.css +4 -4
  4. package/components/AboutUs/StaticContent.vue +32 -0
  5. package/components/Cart/CartEmpty.vue +42 -0
  6. package/components/Cart/CartItem.vue +145 -0
  7. package/components/Cart/CartSummary.vue +57 -0
  8. package/components/Cart/ProductQuantity.vue +23 -13
  9. package/components/Cart/index.vue +68 -150
  10. package/components/Categories/index.vue +88 -291
  11. package/components/Checkout/AddressFields.vue +74 -0
  12. package/components/Checkout/CheckoutForm.vue +75 -0
  13. package/components/Checkout/CityAutocomplete.vue +68 -0
  14. package/components/Checkout/DeliveryMethodCard.vue +66 -0
  15. package/components/Checkout/DeliveryOptions.vue +148 -0
  16. package/components/Checkout/OrderSummary.vue +116 -0
  17. package/components/Checkout/PaymentOptions.vue +76 -0
  18. package/components/Checkout/PickupPoints.vue +46 -0
  19. package/components/Checkout/PromoCode.vue +166 -0
  20. package/components/Checkout/index.vue +235 -173
  21. package/components/Checkout/types.ts +45 -0
  22. package/components/Common/PageBanner.vue +22 -20
  23. package/components/Common/ProductCard.vue +139 -115
  24. package/components/Common/Services.vue +4 -4
  25. package/components/Contact/ContactForm.vue +44 -74
  26. package/components/Contact/ContactInfo.vue +35 -61
  27. package/components/FAQ/index.vue +6 -119
  28. package/components/Layout/Copyright.vue +11 -9
  29. package/components/Layout/Footer.vue +49 -136
  30. package/components/Layout/HeaderBar.vue +174 -0
  31. package/components/Layout/HeaderLogo.vue +27 -0
  32. package/components/Layout/MiddleHeader.vue +1 -228
  33. package/components/Layout/MiddleHeaderThree.vue +1 -203
  34. package/components/Layout/MiddleHeaderTwo.vue +1 -239
  35. package/components/Layout/NavLinks.vue +23 -0
  36. package/components/Layout/Navbar.vue +38 -151
  37. package/components/Layout/NavbarStyleFour.vue +1 -332
  38. package/components/Layout/NavbarStyleThree.vue +1 -188
  39. package/components/Layout/NavbarStyleTwo.vue +1 -108
  40. package/components/Layout/Preloader.vue +5 -12
  41. package/components/Layout/ResponsiveNavbar.vue +32 -418
  42. package/components/Layout/SitewideBanner.vue +285 -0
  43. package/components/Layout/TopHeader.vue +17 -83
  44. package/components/Layout/layoutData.ts +83 -0
  45. package/components/PrivacyPolicy/index.vue +6 -110
  46. package/components/ProductDetails/ProductDetailsTab.vue +31 -321
  47. package/components/ProductDetails/ProductGallery.vue +45 -0
  48. package/components/ProductDetails/ProductQuantity.vue +8 -14
  49. package/components/ProductDetails/RecentlyViewed.vue +53 -289
  50. package/components/ProductDetails/RelatedProducts.vue +64 -0
  51. package/components/ProductDetails/index.vue +90 -230
  52. package/components/Products/index.vue +78 -16
  53. package/components/TermsConditions/index.vue +6 -110
  54. package/components/Wishlist/index.vue +62 -88
  55. package/composables/useCart.ts +133 -81
  56. package/composables/useCategories.ts +67 -31
  57. package/composables/useCategoryImages.ts +45 -0
  58. package/composables/useCheckout.ts +302 -97
  59. package/composables/useContactForm.ts +57 -0
  60. package/composables/useHomeContent.ts +220 -0
  61. package/composables/useI18n.ts +12 -24
  62. package/composables/useJsonLd.ts +162 -0
  63. package/composables/useProducts.ts +244 -83
  64. package/composables/useRecent.ts +30 -0
  65. package/composables/useSanitize.ts +76 -0
  66. package/composables/useSiteConfig.ts +51 -47
  67. package/composables/useStaticPages.ts +48 -0
  68. package/composables/useStoreOrigin.ts +32 -0
  69. package/composables/useTemplateSections.ts +51 -3
  70. package/composables/useThemeVars.ts +113 -0
  71. package/composables/useWishlist.ts +72 -0
  72. package/layouts/default.vue +80 -19
  73. package/locales/en.json +255 -86
  74. package/locales/uk.json +251 -82
  75. package/modules/template-schema.ts +35 -0
  76. package/nuxt.config.ts +8 -11
  77. package/package.json +1 -1
  78. package/pages/about-us.vue +9 -9
  79. package/pages/cart.vue +0 -1
  80. package/pages/categories.vue +0 -1
  81. package/pages/category/[slug].vue +84 -0
  82. package/pages/checkout.vue +0 -1
  83. package/pages/contact.vue +6 -6
  84. package/pages/delivery.vue +12 -0
  85. package/pages/faq.vue +6 -6
  86. package/pages/order-success.vue +113 -0
  87. package/pages/privacy-policy.vue +6 -6
  88. package/pages/product/[slug].vue +82 -0
  89. package/pages/product-details.vue +14 -6
  90. package/pages/products.vue +12 -1
  91. package/pages/returns.vue +12 -0
  92. package/pages/terms-conditions.vue +6 -6
  93. package/pages/wishlist.vue +2 -2
  94. package/utils/image.ts +0 -1
  95. package/utils/seo-urls.ts +70 -0
  96. package/utils/store-origin.ts +36 -0
  97. package/components/AboutUs/AboutUsTuan.vue +0 -25
  98. package/components/AboutUs/Statistics.vue +0 -42
  99. package/components/AboutUs/SubscribeToTheNewsletter.vue +0 -57
  100. package/components/AddAddress/index.vue +0 -68
  101. package/components/BestSellers/Products.vue +0 -1562
  102. package/components/BestSellers/RecentlyViewed.vue +0 -304
  103. package/components/ChangePassword/index.vue +0 -69
  104. package/components/Common/DashboardNavigation.vue +0 -35
  105. package/components/Dashboard/RecentOrder.vue +0 -173
  106. package/components/Dashboard/index.vue +0 -77
  107. package/components/EditAddress/index.vue +0 -117
  108. package/components/EditProfile/index.vue +0 -95
  109. package/components/FeaturedProduct/FeaturedProducts.vue +0 -304
  110. package/components/FeaturedProduct/Products.vue +0 -1562
  111. package/components/ForgotPassword/index.vue +0 -49
  112. package/components/Layout/FooterTwo.vue +0 -159
  113. package/components/Layout/LocationOption.vue +0 -178
  114. package/components/Layout/RTLSwitchBtn.vue +0 -40
  115. package/components/Login/index.vue +0 -89
  116. package/components/MyAccount/index.vue +0 -154
  117. package/components/NewArrivals/Products.vue +0 -1969
  118. package/components/NewArrivals/RecentlyViewed.vue +0 -304
  119. package/components/OrderDetails/index.vue +0 -75
  120. package/components/OrderHistory/index.vue +0 -195
  121. package/components/Products/RecentlyViewed.vue +0 -302
  122. package/components/Register/index.vue +0 -83
  123. package/components/TrendingProducts/FeaturedProducts.vue +0 -304
  124. package/components/TrendingProducts/Products.vue +0 -1564
  125. package/components/Wishlist/ProductQuantity.vue +0 -29
  126. package/layouts/inner.vue +0 -70
  127. package/locales/ar.json +0 -234
  128. package/locales/ru.json +0 -234
  129. package/pages/address.vue +0 -11
  130. package/pages/change-password.vue +0 -11
  131. package/pages/dashboard.vue +0 -11
  132. package/pages/edit-address.vue +0 -11
  133. package/pages/edit-profile.vue +0 -11
  134. package/pages/forgot-password.vue +0 -11
  135. package/pages/login.vue +0 -11
  136. package/pages/my-account.vue +0 -11
  137. package/pages/order-details.vue +0 -11
  138. package/pages/order-history.vue +0 -11
  139. package/pages/register.vue +0 -11
@@ -1,343 +1,53 @@
1
1
  <template>
2
2
  <div>
3
- <v-tabs
4
- v-model="tab"
5
- bg-color="white"
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
- <div class="description-conetnt">
17
- <p class="mb-3">
18
- The Apple MacBook Pro 16.2 is a cutting-edge laptop designed to
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">Brand</td>
48
- <td class="price">Apple</td>
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
- export default {
338
- name: "ProductDetailsTab",
339
- data: () => ({
340
- tab: null,
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="decrement">
4
+ <div @click="change(-1)">
5
5
  <input type="button" class="minusBtn" value="-" />
6
6
  </div>
7
- <input type="text" size="25" v-model="internalValue" class="count" />
8
- <div @click="increment">
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
- import { ref } from "vue";
16
+ const props = defineProps<{ modelValue: number }>();
17
+ const emit = defineEmits<{ (e: 'update:modelValue', value: number): void }>();
17
18
 
18
- const internalValue = ref(0);
19
-
20
- const increment = () => {
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>