@ecomplus/storefront-components 1.0.0-beta.18 → 1.0.0-beta.181

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 (125) hide show
  1. package/CHANGELOG.md +1278 -133
  2. package/README.md +9 -4
  3. package/all.js +3 -1
  4. package/dist/1.storefront-components.min.js +2 -0
  5. package/dist/1.storefront-components.min.js.map +1 -0
  6. package/dist/2.storefront-components.min.js +5 -0
  7. package/dist/2.storefront-components.min.js.map +1 -0
  8. package/dist/3.storefront-components.min.js +5 -0
  9. package/dist/3.storefront-components.min.js.map +1 -0
  10. package/dist/storefront-components.min.js +33 -12
  11. package/dist/storefront-components.min.js.map +1 -1
  12. package/package.json +17 -12
  13. package/src/APagination.vue +2 -0
  14. package/src/AShare.vue +2 -0
  15. package/src/AccountAddresses.vue +3 -0
  16. package/src/AccountForm.vue +3 -0
  17. package/src/AccountPoints.vue +3 -0
  18. package/src/BuyTogether.vue +3 -0
  19. package/src/EarnPointsProgress.vue +3 -0
  20. package/src/ItemCustomizations.vue +2 -0
  21. package/src/KitProductVariations.vue +3 -0
  22. package/src/PointsApplier.vue +2 -0
  23. package/src/ProductQuickview.vue +3 -0
  24. package/src/QuantitySelector.vue +3 -0
  25. package/src/RecommendedItems.vue +3 -0
  26. package/src/ShippingLine.vue +1 -0
  27. package/src/TheCart.vue +3 -0
  28. package/src/html/APagination.html +90 -0
  29. package/src/html/APrices.html +24 -4
  30. package/src/html/AShare.html +31 -0
  31. package/src/html/AccountAddresses.html +90 -0
  32. package/src/html/AccountForm.html +269 -0
  33. package/src/html/AccountPoints.html +39 -0
  34. package/src/html/AddressForm.html +9 -7
  35. package/src/html/BuyTogether.html +60 -0
  36. package/src/html/CartItem.html +86 -38
  37. package/src/html/CartQuickview.html +28 -5
  38. package/src/html/DiscountApplier.html +2 -2
  39. package/src/html/EarnPointsProgress.html +28 -0
  40. package/src/html/InputDate.html +1 -1
  41. package/src/html/InputDocNumber.html +1 -0
  42. package/src/html/InputPhone.html +1 -1
  43. package/src/html/InstantSearch.html +3 -3
  44. package/src/html/ItemCustomizations.html +14 -0
  45. package/src/html/KitProductVariations.html +92 -0
  46. package/src/html/LoginBlock.html +34 -32
  47. package/src/html/LoginModal.html +9 -4
  48. package/src/html/PaymentOption.html +7 -5
  49. package/src/html/PointsApplier.html +26 -0
  50. package/src/html/ProductCard.html +56 -8
  51. package/src/html/ProductGallery.html +21 -3
  52. package/src/html/ProductQuickview.html +64 -0
  53. package/src/html/ProductVariations.html +30 -3
  54. package/src/html/QuantitySelector.html +85 -0
  55. package/src/html/RecommendedItems.html +48 -0
  56. package/src/html/SearchEngine.html +100 -24
  57. package/src/html/ShippingCalculator.html +84 -3
  58. package/src/html/ShippingLine.html +5 -2
  59. package/src/html/TheAccount.html +43 -9
  60. package/src/html/TheCart.html +156 -0
  61. package/src/html/TheProduct.html +416 -138
  62. package/src/js/APagination.js +74 -0
  63. package/src/js/APicture.js +27 -7
  64. package/src/js/APrices.js +80 -41
  65. package/src/js/AShare.js +83 -0
  66. package/src/js/AccountAddresses.js +192 -0
  67. package/src/js/AccountForm.js +312 -0
  68. package/src/js/AccountPoints.js +63 -0
  69. package/src/js/AddressForm.js +80 -35
  70. package/src/js/BuyTogether.js +246 -0
  71. package/src/js/CartItem.js +67 -14
  72. package/src/js/CartQuickview.js +20 -1
  73. package/src/js/DiscountApplier.js +165 -48
  74. package/src/js/EarnPointsProgress.js +77 -0
  75. package/src/js/InputDate.js +8 -8
  76. package/src/js/InputDocNumber.js +20 -0
  77. package/src/js/ItemCustomizations.js +10 -0
  78. package/src/js/KitProductVariations.js +218 -0
  79. package/src/js/LoginBlock.js +46 -5
  80. package/src/js/LoginModal.js +17 -4
  81. package/src/js/PaymentOption.js +28 -1
  82. package/src/js/PointsApplier.js +110 -0
  83. package/src/js/ProductCard.js +97 -11
  84. package/src/js/ProductGallery.js +32 -12
  85. package/src/js/ProductQuickview.js +72 -0
  86. package/src/js/ProductVariations.js +76 -19
  87. package/src/js/QuantitySelector.js +175 -0
  88. package/src/js/RecommendedItems.js +178 -0
  89. package/src/js/SearchEngine.js +185 -55
  90. package/src/js/ShippingCalculator.js +176 -35
  91. package/src/js/ShippingLine.js +35 -5
  92. package/src/js/TheAccount.js +97 -6
  93. package/src/js/TheCart.js +146 -0
  94. package/src/js/TheProduct.js +387 -43
  95. package/src/js/helpers/add-idle-callback.js +7 -0
  96. package/src/js/helpers/check-form-validity.js +3 -0
  97. package/src/js/helpers/favorite-products.js +24 -0
  98. package/src/js/helpers/scroll-to-element.js +10 -0
  99. package/src/js/helpers/sort-apps.js +14 -0
  100. package/src/js/helpers/wait-storefront-info.js +21 -0
  101. package/src/scss/APicture.scss +2 -0
  102. package/src/scss/APrices.scss +13 -1
  103. package/src/scss/AccountAddresses.scss +27 -0
  104. package/src/scss/AccountForm.scss +5 -0
  105. package/src/scss/AccountPoints.scss +17 -0
  106. package/src/scss/BuyTogether.scss +38 -0
  107. package/src/scss/CartItem.scss +17 -1
  108. package/src/scss/EarnPointsProgress.scss +6 -0
  109. package/src/scss/InstantSearch.scss +1 -0
  110. package/src/scss/KitProductVariations.scss +72 -0
  111. package/src/scss/LoginBlock.scss +5 -0
  112. package/src/scss/PaymentOption.scss +10 -1
  113. package/src/scss/ProductCard.scss +66 -28
  114. package/src/scss/ProductGallery.scss +4 -2
  115. package/src/scss/ProductQuickview.scss +36 -0
  116. package/src/scss/ProductVariations.scss +20 -4
  117. package/src/scss/QuantitySelector.scss +39 -0
  118. package/src/scss/RecommendedItems.scss +28 -0
  119. package/src/scss/SearchEngine.scss +9 -5
  120. package/src/scss/ShippingCalculator.scss +42 -1
  121. package/src/scss/ShippingLine.scss +24 -0
  122. package/src/scss/TheAccount.scss +4 -0
  123. package/src/scss/TheCart.scss +54 -0
  124. package/src/scss/TheProduct.scss +146 -1
  125. package/webpack.config.js +20 -6
@@ -1,4 +1,9 @@
1
- <section class="product">
1
+ <section
2
+ class="product"
3
+ :data-product-id="body._id"
4
+ :data-sku="body.sku"
5
+ :data-selected-variation="selectedVariationId"
6
+ >
2
7
  <a-alert
3
8
  :can-show="hasLoadError"
4
9
  variant="danger"
@@ -19,19 +24,33 @@
19
24
  class="row"
20
25
  >
21
26
  <slot name="gallery-col">
22
- <div class="col-12 col-md-6">
23
- <product-gallery
24
- :product="body"
25
- :current.sync="currentGalleyImg"
26
- >
27
- <slot name="first-picture"/>
28
- </product-gallery>
29
- <slot name="gallery-footer"/>
27
+ <div :class="galleryColClassName">
28
+ <component
29
+ :is="isSSR ? 'portal' : 'div'"
30
+ selector="#product-gallery"
31
+ >
32
+ <slot name="stamps"/>
33
+ <product-gallery
34
+ :product="body"
35
+ :can-add-to-cart="canAddToCart && body.available && isInStock"
36
+ :current-slide.sync="currentGalleyImg"
37
+ :is-s-s-r="isSSR"
38
+ >
39
+ <slot name="first-picture"/>
40
+ </product-gallery>
41
+ <slot name="gallery-footer"/>
42
+ </component>
30
43
  </div>
31
44
  </slot>
32
45
 
33
- <div class="col">
34
- <slot name="heading">
46
+ <div
47
+ class="col"
48
+ ref="actions"
49
+ >
50
+ <slot
51
+ v-if="!isSSR"
52
+ name="heading"
53
+ >
35
54
  <component
36
55
  :is="headingTag"
37
56
  class="product__name"
@@ -43,157 +62,378 @@
43
62
  </p>
44
63
  </slot>
45
64
 
46
- <slot name="rating">
65
+ <component
66
+ :is="isSSR ? 'portal' : 'div'"
67
+ selector="#product-actions"
68
+ >
69
+ <slot name="rating">
70
+ <div
71
+ v-once
72
+ class="product__rating"
73
+ :data-sku="body.sku"
74
+ ></div>
75
+ </slot>
76
+
47
77
  <div
48
- v-once
49
- class="product__rating"
50
- :data-sku="body.sku"
51
- ></div>
52
- </slot>
78
+ v-if="!body.available"
79
+ class="product__unavailable"
80
+ >
81
+ <slot name="unavailable">
82
+ {{ i19unavailable }}
83
+ </slot>
84
+ </div>
53
85
 
54
- <slot
55
- name="unavailable"
56
- v-if="!body.available"
57
- >
58
- <p class="product__unavailable">
59
- {{ i19unavailable }}
60
- </p>
61
- </slot>
86
+ <div
87
+ v-else-if="!isInStock"
88
+ class="product__out-of-stock"
89
+ >
90
+ <slot name="out-of-stock">
91
+ {{ i19outOfStock }}
92
+ </slot>
93
+ </div>
62
94
 
63
- <slot
64
- name="out-of-stock"
65
- v-else-if="!isInStock"
66
- >
67
- <p class="product__out-of-stock">
68
- {{ i19outOfStock }}
69
- </p>
70
- </slot>
95
+ <div
96
+ v-else-if="isWithoutPrice"
97
+ class="product__without-price"
98
+ >
99
+ <slot name="without-price">
100
+ <a
101
+ v-if="quoteLink"
102
+ target="_blank"
103
+ rel="noopener"
104
+ :href="quoteLink"
105
+ >
106
+ {{ i19quoteProduct }}
107
+ </a>
108
+ </slot>
109
+ </div>
110
+
111
+ <template v-else>
112
+ <slot name="prices">
113
+ <p class="product__prices">
114
+ <a-prices
115
+ :product="ghostProductForPrices"
116
+ :is-literal="true"
117
+ :is-big="true"
118
+ @fix-price="price => fixedPrice = price"
119
+ />
120
+
121
+ <slot
122
+ name="discount-tag"
123
+ v-bind="{ discount }"
124
+ >
125
+ <span
126
+ v-if="discount > 0"
127
+ class="product__discount"
128
+ >
129
+ {{ i19discountOf }}
130
+ <strong>{{ discount }}%</strong>
131
+ </span>
132
+ </slot>
133
+ </p>
134
+ </slot>
71
135
 
72
- <template v-else>
73
- <slot name="prices">
74
- <p class="product__prices">
75
- <a-prices
76
- :product="{ ...body, ...selectedVariation }"
77
- :is-literal="true"
78
- :is-big="true"
79
- @fix-price="price => fixedPrice = price"
136
+ <slot
137
+ name="variations"
138
+ v-if="hasVariations"
139
+ >
140
+ <product-variations
141
+ :product="body"
142
+ :selected-id.sync="selectedVariationId"
143
+ :max-options-btns="maxVariationOptionsBtns"
144
+ @select-option="handleGridOption"
80
145
  />
146
+ <a-alert :can-show="hasClickedBuy && !selectedVariationId">
147
+ {{ i19selectVariationMsg }}
148
+ </a-alert>
149
+
150
+ <slot name="variations-info"/>
151
+ </slot>
152
+
153
+ <slot
154
+ name="customizations"
155
+ v-if="body.customizations"
156
+ >
157
+ <div
158
+ v-for="custom in body.customizations"
159
+ v-if="custom.custom_value"
160
+ :key="custom._id"
161
+ class="product__customization form-group"
162
+ :class="custom.grid_id ? `product__customization--${custom.grid_id}` : null"
163
+ >
164
+ <label :for="`c-${custom._id}`">
165
+ {{ custom.label }}
166
+ <span
167
+ v-if="custom.add_to_price"
168
+ class="badge badge-secondary"
169
+ >
170
+ {{ formatAdditionalPrice(custom.add_to_price) }}
171
+ </span>
172
+ </label>
173
+
174
+ <input
175
+ type="text"
176
+ class="form-control"
177
+ :id="`c-${custom._id}`"
178
+ @keyup="ev => setCustomizationOption(custom, ev.target.value)"
179
+ >
180
+ </div>
181
+ </slot>
81
182
 
183
+ <div
184
+ v-if="isKit"
185
+ class="product__kit"
186
+ >
82
187
  <slot
83
- name="discount-tag"
84
- v-bind="{ discount }"
188
+ name="kit"
189
+ v-bind="{ kitItems }"
85
190
  >
191
+ <transition enter-active-class="animated fadeInUp">
192
+ <quantity-selector
193
+ v-if="kitItems.length && !isKitWithVariations"
194
+ :items="kitItems"
195
+ :min="body.min_quantity"
196
+ :max="body.quantity"
197
+ :slug="body.slug"
198
+ :kit-product-id="body._id"
199
+ :kit-name="name"
200
+ :kit-price="fixedPrice"
201
+ @buy="d => $emit('buy', d)"
202
+ >
203
+ <template #buy-button-content>
204
+ <slot name="buy-button-content"/>
205
+ </template>
206
+ </quantity-selector>
207
+ <kit-product-variations
208
+ v-if="kitItems.length && isKitWithVariations"
209
+ :items="kitItems"
210
+ :min="body.min_quantity"
211
+ :max="body.quantity"
212
+ :slug="body.slug"
213
+ :kit-product-id="body._id"
214
+ :kit-name="name"
215
+ :kit-price="fixedPrice"
216
+ :max-options-btns="maxVariationOptionsBtns"
217
+ >
218
+ <template #buy-button-content>
219
+ <slot name="buy-button-content"/>
220
+ </template>
221
+ </kit-product-variations>
222
+ </transition>
223
+
86
224
  <span
87
- v-if="discount > 0"
88
- class="product__discount"
225
+ v-if="!kitItems.length"
226
+ class="product__kit-loading spinner-border"
227
+ role="status"
89
228
  >
90
- {{ i19discountOf }}
91
- <strong>{{ discount }}%</strong>
229
+ <span class="sr-only">Loading...</span>
92
230
  </span>
93
231
  </slot>
94
- </p>
95
- </slot>
96
-
97
- <slot
98
- name="variations"
99
- v-if="hasVariations"
100
- >
101
- <product-variations
102
- :product="body"
103
- :selectedId.sync="selectedVariationId"
104
- />
105
- <a-alert :can-show="hasClickedBuy && !selectedVariationId">
106
- {{ i19selectVariation }}
107
- </a-alert>
232
+ </div>
108
233
 
109
- <slot name="variations-info"/>
110
- </slot>
111
-
112
- <div
113
- class="product__buy"
114
- @click="buy"
115
- >
116
- <slot name="buy">
117
- <button
118
- type="button"
119
- class="btn btn-lg btn-primary"
120
- :disabled="hasClickedBuy"
234
+ <template v-else>
235
+ <div
236
+ v-if="!isVariationInStock"
237
+ class="product__out-of-stock"
121
238
  >
122
- <slot name="buy-button-content">
123
- <i class="fas fa-shopping-bag mr-1"></i>
124
- {{ strBuy }}
239
+ <slot name="out-of-stock">
240
+ {{ i19outOfStock }}
125
241
  </slot>
126
- </button>
127
- </slot>
128
- </div>
242
+ </div>
129
243
 
130
- <p
131
- class="product__short-stock"
132
- v-if="isLowQuantity"
133
- >
134
- <i class="fas fa-exclamation-triangle mr-1"></i>
135
- {{ i19only }}
136
- <strong>{{ productQuantity }}</strong>
137
- {{ i19inStock }}
138
- </p>
244
+ <div
245
+ v-else-if="hasBuyButton"
246
+ class="product__buy"
247
+ ref="buy"
248
+ >
249
+ <component
250
+ :is="hasQuantitySelector ? 'quantity-selector' : 'div'"
251
+ :items="hasQuantitySelector ? [{ _id: body._id, quantity: body.min_quantity || 1 }] : null"
252
+ :min="body.min_quantity"
253
+ :max="body.quantity"
254
+ :has-buy-button="false"
255
+ @set-quantity="({ quantity }) => qntToBuy = quantity"
256
+ >
257
+ <span @click="buy">
258
+ <slot
259
+ name="buy"
260
+ v-bind="{ hasClickedBuy, isOnCart }"
261
+ >
262
+ <button
263
+ type="button"
264
+ class="btn btn-lg btn-primary"
265
+ :disabled="hasClickedBuy && !isOnCart"
266
+ >
267
+ <slot name="buy-button-content">
268
+ <i class="i-shopping-bag mr-1"></i>
269
+ {{ strBuy }}
270
+ </slot>
271
+ </button>
272
+ </slot>
273
+ </span>
274
+ </component>
275
+ </div>
139
276
 
140
- <transition enter-active-class="animated fadeInUp">
141
- <slot
142
- name="payment-gateways"
143
- v-bind="{ paymentGateways }"
144
- v-if="paymentGateways.length"
145
- >
146
- <article :key="`payment-${fixedPrice}`">
277
+ <p
278
+ class="product__short-stock"
279
+ v-if="isLowQuantity"
280
+ >
281
+ <i class="i-forward mr-1"></i>
282
+ {{ i19only }}
283
+ <strong>{{ productQuantity }}</strong>
284
+ {{ i19unitsInStock }}
285
+ </p>
286
+ </template>
287
+
288
+ <slot name="sale-timer">
289
+ <div
290
+ v-if="isOnSale"
291
+ class="product__sale-timer mb-3"
292
+ >
293
+ <div>
294
+ {{ i19offer }}
295
+ <br><small>{{ i19endsIn }}</small>
296
+ </div>
147
297
  <div
148
- v-once
149
- class="product__payment card mb-3"
298
+ class="h1 ml-3 mb-0"
299
+ ref="timer"
150
300
  >
151
- <a
152
- id="product-payment-header"
153
- class="card-header"
154
- role="button"
155
- href="#product-payment"
156
- data-toggle="collapse"
157
- aria-expanded="false"
158
- aria-controls="product-payment"
159
- >
160
- <span>{{ i19paymentOptions }}</span>
161
- <i class="fas fa-chevron-down"></i>
162
- </a>
163
-
164
- <div
165
- id="product-payment"
166
- class="collapse"
167
- aria-labelledby="product-payment-header"
301
+ 00:00:00
302
+ </div>
303
+ </div>
304
+ </slot>
305
+
306
+ <slot name="favorite">
307
+ <div>
308
+ <a
309
+ class="btn btn-sm product__favorite"
310
+ @click="toggleFavorite"
311
+ :href="isLogged ? null : accountUrl"
312
+ >
313
+ <i
314
+ class="i-heart mr-1"
315
+ :class="isFavorite ? 'active' : null"
168
316
  >
169
- <div class="card-body">
170
- <payment-option
171
- v-for="(gateway, i) in paymentGateways"
172
- :key="i"
173
- :payment-gateway="gateway"
174
- :price="fixedPrice"
175
- />
317
+ </i>
318
+ <span>
319
+ {{ isFavorite ? i19removeFromFavorites : i19addToFavorites }}
320
+ </span>
321
+ </a>
322
+ </div>
323
+ </slot>
324
+
325
+ <slot name="share">
326
+ <a-share
327
+ v-if="body.slug"
328
+ class="mb-3"
329
+ :url="`/${body.slug}`"
330
+ :title="body.name"
331
+ :description="body.short_description"
332
+ />
333
+ </slot>
334
+
335
+ <transition enter-active-class="animated fadeInUp">
336
+ <slot
337
+ name="payment-gateways"
338
+ v-bind="{ paymentOptions }"
339
+ v-if="!isQuickview && paymentOptions.length"
340
+ >
341
+ <article>
342
+ <div class="product__payment card mb-3">
343
+ <a
344
+ id="product-payment-header"
345
+ class="card-header"
346
+ role="button"
347
+ href="#product-payment"
348
+ data-toggle="collapse"
349
+ aria-expanded="false"
350
+ aria-controls="product-payment"
351
+ >
352
+ <span>{{ i19paymentOptions }}</span>
353
+ <i class="i-chevron-down"></i>
354
+ </a>
355
+
356
+ <div
357
+ id="product-payment"
358
+ class="collapse"
359
+ aria-labelledby="product-payment-header"
360
+ >
361
+ <div class="card-body pb-0">
362
+ <div
363
+ v-for="paymentOption in paymentOptions"
364
+ :key="paymentOption.app_id"
365
+ :id="`product-payment-${paymentOption.app_id}`"
366
+ class="mb-3"
367
+ >
368
+ <slot :name="`payment-${paymentOption.app_id}`">
369
+ <payment-option
370
+ v-for="(gateway, i) in paymentOption.payment_gateways"
371
+ :key="`${paymentOption.app_id}-${i}`"
372
+ :payment-gateway="gateway"
373
+ :installments-option="paymentOption.installments_option"
374
+ :price="fixedPrice"
375
+ />
376
+ </slot>
377
+ </div>
378
+ </div>
176
379
  </div>
177
380
  </div>
178
- </div>
179
- </article>
381
+ </article>
382
+ </slot>
383
+ </transition>
384
+
385
+ <p
386
+ v-if="body.production_time && body.production_time.days"
387
+ class="product__production"
388
+ >
389
+ <i class="i-info-circle mr-1"></i>
390
+ {{ i19productionDeadline }}:
391
+ <strong>
392
+ {{ body.production_time.days }}
393
+ {{ body.production_time.working_days ? i19workingDays : i19days }}
394
+ <template v-if="body.production_time.cumulative">
395
+ {{ i19perUnit }}
396
+ </template>
397
+ </strong>
398
+ </p>
399
+
400
+ <slot
401
+ v-if="!isQuickview && (!isKit || kitItems.length)"
402
+ name="shipping"
403
+ >
404
+ <shipping-calculator
405
+ :shippedItems="isKit ? kitItems : [{
406
+ ...body,
407
+ ...selectedVariation,
408
+ product_id: body._id,
409
+ quantity: qntToBuy || body.min_quantity || 1
410
+ }]"
411
+ >
412
+ <template v-slot:free-from-value="{ amountSubtotal, freeFromValue }">
413
+ <div class="product__free-shipping-from">
414
+ {{ i19freeShippingFrom }}
415
+ <strong>
416
+ {{ Math.ceil(freeFromValue / amountSubtotal) }}
417
+ {{ i19units }}
418
+ </strong>
419
+ </div>
420
+ </template>
421
+ </shipping-calculator>
180
422
  </slot>
181
- </transition>
182
-
183
- <slot name="shipping">
184
- <shipping-calculator
185
- :shippedItems="[{
186
- ...body,
187
- product_id: body._id,
188
- quantity: body.min_quantity || 1
189
- }]"
190
- />
191
- </slot>
192
- </template>
423
+
424
+ <slot name="track-price">
425
+ <div
426
+ v-once
427
+ class="product__track-price"
428
+ :data-sku="body.sku"
429
+ ></div>
430
+ </slot>
431
+ </template>
432
+ </component>
193
433
 
194
434
  <slot
435
+ v-if="!isSSR && body.short_description"
195
436
  name="short-description"
196
- v-if="body.short_description"
197
437
  >
198
438
  <p class="product__info lead">
199
439
  {{ body.short_description }}
@@ -203,7 +443,45 @@
203
443
  </div>
204
444
  </transition>
205
445
 
206
- <template v-if="!body._id">
207
- <slot/>
446
+ <template v-if="!isQuickview && hasStickyBuyButton && body.available && isInStock">
447
+ <transition
448
+ enter-active-class="animated fadeIn"
449
+ leave-active-class="animated fadeOut fast"
450
+ >
451
+ <div
452
+ v-show="isStickyBuyVisible"
453
+ ref="sticky"
454
+ class="product__sticky"
455
+ >
456
+ <div class="product__sticky-container container">
457
+ <div class="product__sticky-info">
458
+ <a-picture
459
+ :can-calc-height="false"
460
+ :src="thumbnail"
461
+ class="product__sticky-picture"
462
+ />
463
+ <h5>{{ name }}</h5>
464
+ </div>
465
+
466
+ <div class="product__sticky-buy">
467
+ <a-prices
468
+ :product="ghostProductForPrices"
469
+ :is-literal="false"
470
+ :can-show-price-options="true"
471
+ />
472
+ <a
473
+ class="btn btn-lg btn-primary"
474
+ href="#"
475
+ @click.prevent="buyOrScroll"
476
+ >
477
+ <i class="i-shopping-bag mr-1"></i>
478
+ {{ strBuy }}
479
+ </a>
480
+ </div>
481
+ </div>
482
+ </div>
483
+ </transition>
208
484
  </template>
485
+
486
+ <slot v-if="!body._id"/>
209
487
  </section>
@@ -0,0 +1,74 @@
1
+ import {
2
+ i19next,
3
+ i19previous
4
+ } from '@ecomplus/i18n'
5
+
6
+ import { i18n } from '@ecomplus/utils'
7
+
8
+ export default {
9
+ name: 'APagination',
10
+
11
+ props: {
12
+ totalItems: {
13
+ type: Number,
14
+ required: true
15
+ },
16
+ page: {
17
+ type: Number,
18
+ default: 1
19
+ },
20
+ pageSize: {
21
+ type: Number,
22
+ default: 24
23
+ }
24
+ },
25
+
26
+ computed: {
27
+ i19next: () => i18n(i19next),
28
+ i19previous: () => i18n(i19previous),
29
+
30
+ totalPages () {
31
+ return Math.ceil(this.totalItems / this.pageSize)
32
+ },
33
+
34
+ pageNums () {
35
+ const pages = []
36
+ if (this.totalPages > 0) {
37
+ let lastPage
38
+ for (let i = -2; i <= 2; i++) {
39
+ lastPage = this.page + i
40
+ if (lastPage >= 1) {
41
+ if (lastPage <= this.totalPages) {
42
+ pages.push(lastPage)
43
+ } else {
44
+ break
45
+ }
46
+ }
47
+ }
48
+ if (pages[0] === 3) {
49
+ pages.unshift(1, 2)
50
+ } else if (pages[0] === 2) {
51
+ pages.unshift(1)
52
+ }
53
+ if (lastPage === this.totalPages - 2) {
54
+ pages.push(lastPage + 1, lastPage + 2)
55
+ } else if (lastPage === this.totalPages - 1) {
56
+ pages.push(lastPage + 1)
57
+ }
58
+ }
59
+ return pages
60
+ },
61
+
62
+ lastPageNum () {
63
+ return this.pageNums[this.pageNums.length - 1]
64
+ }
65
+ },
66
+
67
+ methods: {
68
+ go (page) {
69
+ if (page >= 1 && page <= this.totalPages) {
70
+ this.$emit('update:page', page)
71
+ }
72
+ }
73
+ }
74
+ }