@ecomplus/widget-martan 1.1.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +11 -0
  3. package/cms.config.js +264 -0
  4. package/dist/public/widget-martan.1.min.js +2 -0
  5. package/dist/public/widget-martan.1.min.js.map +1 -0
  6. package/dist/public/widget-martan.2.min.js +2 -0
  7. package/dist/public/widget-martan.2.min.js.map +1 -0
  8. package/dist/public/widget-martan.3.min.js +2 -0
  9. package/dist/public/widget-martan.3.min.js.map +1 -0
  10. package/dist/public/widget-martan.4.min.js +2 -0
  11. package/dist/public/widget-martan.4.min.js.map +1 -0
  12. package/dist/public/widget-martan.5.min.js +2 -0
  13. package/dist/public/widget-martan.5.min.js.map +1 -0
  14. package/dist/public/widget-martan.var.min.js +71 -0
  15. package/dist/public/widget-martan.var.min.js.map +1 -0
  16. package/dist/widget-martan.1.min.js +2 -0
  17. package/dist/widget-martan.1.min.js.map +1 -0
  18. package/dist/widget-martan.2.min.js +2 -0
  19. package/dist/widget-martan.2.min.js.map +1 -0
  20. package/dist/widget-martan.3.min.js +2 -0
  21. package/dist/widget-martan.3.min.js.map +1 -0
  22. package/dist/widget-martan.4.min.js +2 -0
  23. package/dist/widget-martan.4.min.js.map +1 -0
  24. package/dist/widget-martan.5.min.js +2 -0
  25. package/dist/widget-martan.5.min.js.map +1 -0
  26. package/dist/widget-martan.min.js +71 -0
  27. package/dist/widget-martan.min.js.map +1 -0
  28. package/package.json +36 -0
  29. package/src/append/body.ejs +79 -0
  30. package/src/append/head.ejs +5 -0
  31. package/src/append/product-block.ejs +5 -0
  32. package/src/append/product-card-slots.ejs +3 -0
  33. package/src/append/product-slots.ejs +25 -0
  34. package/src/append/stamps.ejs +3 -0
  35. package/src/index.js +22 -0
  36. package/src/utils/get-width.js +11 -0
  37. package/src/utils/textToNumber.js +31 -0
  38. package/src/utils/time-ago.js +35 -0
  39. package/src/widgets/reviews/AuthorAndRating.vue +30 -0
  40. package/src/widgets/reviews/AverageScore.vue +160 -0
  41. package/src/widgets/reviews/AverageTotal.vue +35 -0
  42. package/src/widgets/reviews/CardReview.vue +87 -0
  43. package/src/widgets/reviews/GridView.vue +113 -0
  44. package/src/widgets/reviews/HeaderExpanded.vue +84 -0
  45. package/src/widgets/reviews/HeaderMinimal.vue +110 -0
  46. package/src/widgets/reviews/ListView.vue +47 -0
  47. package/src/widgets/reviews/Quickview.vue +398 -0
  48. package/src/widgets/reviews/ReviewBody.vue +39 -0
  49. package/src/widgets/reviews/ReviewReply.vue +57 -0
  50. package/src/widgets/reviews/Reviews.vue +496 -0
  51. package/src/widgets/reviews/Score.vue +186 -0
  52. package/src/widgets/reviews/Sort.vue +76 -0
  53. package/src/widgets/reviews/ThumbsPictures.vue +135 -0
  54. package/src/widgets/reviews/Total.vue +79 -0
  55. package/src/widgets/reviews/VerifiedPurchase.vue +111 -0
  56. package/src/widgets/reviews/VideoPlayer.vue +136 -0
  57. package/src/widgets/reviews/index.js +52 -0
  58. package/src/widgets/reviews/isRecommended.vue +44 -0
  59. package/src/widgets/snippets/Rating.vue +71 -0
  60. package/src/widgets/snippets/Snippets.vue +311 -0
  61. package/src/widgets/snippets/index.js +45 -0
  62. package/webpack.config.js +1 -0
@@ -0,0 +1,84 @@
1
+ <template>
2
+ <div class="mt-header--expanded">
3
+ <average-total :average="reviews.averageTotal" />
4
+ <score
5
+ :reviews="reviews"
6
+ :starColor="starColor"
7
+ @updateOrderByAverage="updateOrderBy"
8
+ />
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ export default {
14
+ props: {
15
+ starColor: {
16
+ type: String,
17
+ default: '#212529'
18
+ },
19
+
20
+ reviews: {
21
+ type: Object,
22
+ default: {
23
+ list: [],
24
+ orderRating: null,
25
+ total: 0,
26
+ average: {
27
+ one: 0,
28
+ two: 0,
29
+ three: 0,
30
+ four: 0,
31
+ five: 0,
32
+ },
33
+ averageTotal: 0,
34
+ }
35
+ },
36
+ },
37
+
38
+ name: 'header-expanded',
39
+
40
+ components: {
41
+ AverageTotal: () => import("./AverageTotal.vue"),
42
+ AverageScore: () => import("./AverageScore.vue"),
43
+ Score: () => import("./Score.vue"),
44
+ },
45
+
46
+ methods: {
47
+ updateOrderBy: ({ rating }) => this.$emit('updateOrderByAverage', { rating })
48
+ }
49
+ };
50
+ </script>
51
+
52
+ <style lang="scss">
53
+ .mt-header--expanded {
54
+ display: flex;
55
+ align-items: center;
56
+ border-bottom: 1px solid #e3e3e3;
57
+ padding-bottom: 25px;
58
+
59
+ .mt-rating__average {
60
+ display: flex;
61
+ align-items: center;
62
+ }
63
+
64
+ .mt-rating__average__wrapper {
65
+ display: flex;
66
+ flex-direction: column;
67
+ justify-content: center;
68
+ height: 100%;
69
+ padding-top: 5px;
70
+ }
71
+
72
+ .mt-rating__average_total {
73
+ font-size: 48px;
74
+ margin: 0 18px 0 0;
75
+ padding: 0;
76
+ }
77
+ }
78
+
79
+ @media (max-width: 580px) {
80
+ .mt-rating__options {
81
+ max-width: 97%;
82
+ }
83
+ }
84
+ </style>
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="mt-header--minimal">
3
+ <div class="rating">
4
+ <div style="display: flex; align-items: center; gap: 10px">
5
+ <rating :color="starColor" :rating="reviews.averageTotal" />
6
+
7
+ <span class="average" v-if="reviews.averageTotal > 0">
8
+ {{ reviews.averageTotal }}
9
+ <span class="baseado" style="font-size: 10px; opacity: 0.8"
10
+ >({{
11
+ reviews.total > 1
12
+ ? i19basedOn$1Reviews.replace("$1", reviews.total)
13
+ : i19basedOn$1Review.replace("$1", reviews.total)
14
+ }})</span
15
+ ></span
16
+ >
17
+ <span class="average" v-else>
18
+ {{ reviews.averageTotal }}
19
+ <span class="baseado" style="font-size: 10px; opacity: 0.8"
20
+ >({{ i19noReview }})</span
21
+ ></span
22
+ >
23
+ </div>
24
+
25
+ <Sort @onSort="onSort" />
26
+ </div>
27
+ </div>
28
+ </template>
29
+
30
+ <script>
31
+ import Rating from "../snippets/Rating.vue";
32
+ import Sort from "./Sort.vue";
33
+
34
+ export default {
35
+ props: {
36
+ starColor: {
37
+ type: String,
38
+ default: "#212529",
39
+ },
40
+
41
+ reviews: {
42
+ type: Object,
43
+ default: {
44
+ list: [],
45
+ orderRating: null,
46
+ total: 0,
47
+ average: {
48
+ one: 0,
49
+ two: 0,
50
+ three: 0,
51
+ four: 0,
52
+ five: 0,
53
+ },
54
+ averageTotal: 0,
55
+ },
56
+ },
57
+ },
58
+
59
+ name: "header-minimal",
60
+
61
+ components: {
62
+ Rating,
63
+ Sort,
64
+ },
65
+
66
+ computed: {
67
+ i19basedOn$1Reviews: () => "Baseado em $1 avaliações",
68
+ i19basedOn$1Review: () => "Baseado em $1 avaliação",
69
+ i19noReview: () => "Nenhuma avaliação",
70
+ },
71
+
72
+ methods: {
73
+ updateOrderBy: ({ rating }) =>
74
+ this.$emit("updateOrderByAverage", { rating }),
75
+
76
+ onSort(value) {
77
+ this.$emit("onSort", value);
78
+ },
79
+ },
80
+ };
81
+ </script>
82
+
83
+ <style lang="scss">
84
+ .mt-header--minimal {
85
+ .rating {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 15px;
89
+ border-bottom: 1px solid #eee;
90
+ justify-content: space-between;
91
+ margin-bottom: 10px;
92
+ padding-bottom: 10px;
93
+ }
94
+
95
+ .average {
96
+ font-size: 26px;
97
+ color: #6c757d;
98
+ }
99
+
100
+ .mt-rating__average__sort {
101
+ width: 100%;
102
+ }
103
+
104
+ .baseado {
105
+ @media (max-width: 580px) {
106
+ display: none;
107
+ }
108
+ }
109
+ }
110
+ </style>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <div class="mt-reviews__list">
3
+ <card-review
4
+ v-for="review in reviews.list"
5
+ :key="review.id"
6
+ :review="review"
7
+ :starColor="starColor"
8
+ @openQuickview="openQuickview"
9
+ />
10
+ </div>
11
+ </template>
12
+
13
+ <script>
14
+ import CardReview from "./CardReview.vue";
15
+ import Quickview from "./Quickview.vue";
16
+
17
+ export default {
18
+ name: 'ListView',
19
+
20
+ components: {
21
+ CardReview,
22
+ Quickview,
23
+ },
24
+
25
+ props: {
26
+ starColor: {
27
+ type: String,
28
+ default: "#212529",
29
+ },
30
+
31
+ reviews: {
32
+ type: Object,
33
+ default: {
34
+ list: [],
35
+ orderRating: null,
36
+ total: 0,
37
+ },
38
+ },
39
+ },
40
+
41
+ methods: {
42
+ openQuickview: function ({ review, slide }) {
43
+ this.$emit('openQuickview', { review, slide })
44
+ },
45
+ },
46
+ };
47
+ </script>
@@ -0,0 +1,398 @@
1
+ <template>
2
+ <div
3
+ class="modal fade"
4
+ id="martan-quickview"
5
+ tabindex="-1"
6
+ role="dialog"
7
+ aria-labelledby="quickviewModal"
8
+ aria-hidden="true"
9
+ >
10
+ <div class="modal-dialog modal-dialog-centered modal-xl" role="document">
11
+ <div class="modal-content">
12
+ <div class="modal-header" v-show="false">
13
+ <h5 class="modal-title" id="quickviewModal">{{ i19quickview }}</h5>
14
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
15
+ <span aria-hidden="true">&times;</span>
16
+ </button>
17
+ </div>
18
+
19
+ <div class="modal-body mt-quickview">
20
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
21
+ <span aria-hidden="true">&times;</span>
22
+ </button>
23
+
24
+ <div
25
+ class="glide mt-quickview__galery"
26
+ v-if="pictures.length || video"
27
+ ref="galery"
28
+ >
29
+ <div
30
+ class="mt-quickview__controls"
31
+ data-glide-el="controls"
32
+ :style="`--button--hover-color:${starColor || '#eeeeee'}`"
33
+ >
34
+ <button
35
+ :title="i19previous"
36
+ :aria-label="i19previous"
37
+ class="left"
38
+ data-glide-dir="<"
39
+ v-on:click="back"
40
+ v-if="glide && glide.index > 0"
41
+ >
42
+ <i class="i-chevron-left"></i>
43
+ </button>
44
+ </div>
45
+
46
+ <div class="glide__track" data-glide-el="track">
47
+ <ul class="glide__slides">
48
+ <li v-for="picture in pictures" :key="picture.id" class="glide__slide">
49
+ <img
50
+ :alt="`Foto da avaliação do produto feita por ${author}`"
51
+ :src="picture.big"
52
+ />
53
+ </li>
54
+
55
+ <li v-if="video" class="lazy-image video-wrapper" :key="video">
56
+ <VideoPlayer :video="video" />
57
+ </li>
58
+ </ul>
59
+ </div>
60
+
61
+ <div
62
+ class="mt-quickview__controls"
63
+ data-glide-el="controls"
64
+ :style="`--button--hover-color:${starColor || '#eeeeee'}`"
65
+ >
66
+ <button
67
+ :title="i19next"
68
+ :aria-label="i19next"
69
+ data-glide-dir=">"
70
+ v-on:click="next"
71
+ >
72
+ <i class="i-chevron-right"></i>
73
+ </button>
74
+ </div>
75
+ </div>
76
+
77
+ <div class="mt-review">
78
+ <div class="mt-rating__group">
79
+ <AuthorAndRating
80
+ :author="author"
81
+ :isAnonymous="review.is_anonymous"
82
+ :rating="rating"
83
+ :starColor="starColor"
84
+ v-if="review"
85
+ />
86
+
87
+ <isRecommended :recommended="recommended" v-if="review" />
88
+
89
+ <VerifiedPurchase :showVerified="true" v-if="isVerified" />
90
+ </div>
91
+
92
+ <ThumbsPictures v-if="review" :review="review" @onClick="goToSlide" />
93
+
94
+ <ReviewBody :body="body" :createdAt="review.created_at" v-if="review" />
95
+
96
+ <ReviewReply :reply="reply" />
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </template>
103
+
104
+ <script>
105
+ import Glide from "@glidejs/glide";
106
+ import { i19next, i19previous } from "@ecomplus/i18n";
107
+ import { i18n, formatDate } from "@ecomplus/utils";
108
+ import $ from "../../../../storefront-twbs/src";
109
+ import { timeAgo } from "./../../utils/time-ago";
110
+
111
+ import ThumbsPictures from "./ThumbsPictures.vue";
112
+ import VerifiedPurchase from "./VerifiedPurchase.vue";
113
+ import AuthorAndRating from "./AuthorAndRating.vue";
114
+ import IsRecommended from "./isRecommended.vue";
115
+ import ReviewBody from "./ReviewBody.vue";
116
+ import ReviewReply from "./ReviewReply.vue";
117
+ import VideoPlayer from "./VideoPlayer.vue";
118
+ import Rating from "../snippets/Rating.vue";
119
+
120
+ export default {
121
+ name: "Quickview",
122
+
123
+ components: {
124
+ ThumbsPictures,
125
+ Rating,
126
+ VerifiedPurchase,
127
+ AuthorAndRating,
128
+ IsRecommended,
129
+ ReviewBody,
130
+ ReviewReply,
131
+ VideoPlayer,
132
+ },
133
+
134
+ props: {
135
+ review: Object,
136
+ isOpen: {
137
+ type: Boolean,
138
+ default: false,
139
+ },
140
+ starColor: String,
141
+ },
142
+
143
+ data() {
144
+ return {
145
+ glide: null,
146
+ };
147
+ },
148
+
149
+ computed: {
150
+ i19quickview: () => "Quickview",
151
+ i19next: () => i18n(i19next),
152
+ i19previous: () => i18n(i19previous),
153
+
154
+ reviewId: function () {
155
+ if (this.review && this.review.id) {
156
+ return this.review.id;
157
+ }
158
+
159
+ return null;
160
+ },
161
+
162
+ pictures: function () {
163
+ if (this.review && this.review.pictures) {
164
+ return this.review.pictures;
165
+ }
166
+ return [];
167
+ },
168
+
169
+ video: function () {
170
+ if (this.review && this.review.video_url) {
171
+ return this.review.video_url;
172
+ }
173
+ return null;
174
+ },
175
+
176
+ title: function () {
177
+ if (this.review && this.review.title) {
178
+ return this.review.title;
179
+ }
180
+ return null;
181
+ },
182
+
183
+ author: function () {
184
+ if (this.review && this.review.display_name) {
185
+ return this.review.display_name;
186
+ }
187
+ return null;
188
+ },
189
+
190
+ rating: function () {
191
+ if (this.review && this.review.rating) {
192
+ return this.review.rating;
193
+ }
194
+ return null;
195
+ },
196
+
197
+ recommended: function () {
198
+ if (this.review && this.review.is_recommended) {
199
+ return this.review.is_recommended;
200
+ }
201
+ return null;
202
+ },
203
+
204
+ isVerified: function () {
205
+ if (this.review && this.review.verified_purchase) {
206
+ return this.review.verified_purchase;
207
+ }
208
+ return null;
209
+ },
210
+
211
+ reply: function () {
212
+ if (this.review && this.review.reply) {
213
+ return this.review.reply;
214
+ }
215
+ return null;
216
+ },
217
+
218
+ created: function () {
219
+ if (this.review && this.review.created_at) {
220
+ return this.review.created_at;
221
+ }
222
+ return null;
223
+ },
224
+
225
+ body: function () {
226
+ if (this.review && this.review.body) {
227
+ return this.review.body;
228
+ }
229
+ return null;
230
+ },
231
+ },
232
+
233
+ watch: {
234
+ isOpen: function (isOpened) {
235
+ if (isOpened) {
236
+ $("#martan-quickview").modal("show");
237
+ }
238
+ },
239
+ },
240
+
241
+ mounted() {
242
+ $("#martan-quickview").on("hidden.bs.modal", this.close);
243
+ $("#martan-quickview").on("shown.bs.modal", this.mount);
244
+
245
+ this.glide = new Glide(".mt-quickview__galery", {
246
+ keyboard: false,
247
+ rewind: true,
248
+ type: "carousel",
249
+ dragThreshold: false,
250
+ startAt: 0,
251
+ perView: 1,
252
+ perViewLg: 1,
253
+ perViewSm: 1,
254
+ });
255
+ },
256
+
257
+ beforeDestroy() {
258
+ if (this.glide) {
259
+ this.glide.destroy();
260
+ }
261
+ },
262
+
263
+ methods: {
264
+ mount: function () {
265
+ if (
266
+ (this.review && this.review.pictures) ||
267
+ (this.review && this.review.video_url)
268
+ ) {
269
+ setTimeout(() => {
270
+ try {
271
+ this.glide.mount();
272
+ this.glide.update({ perView: 1 });
273
+ } catch (error) {}
274
+ }, 5);
275
+ }
276
+ },
277
+
278
+ close: function () {
279
+ this.$emit("onClose", true);
280
+ try {
281
+ this.glide.destroy();
282
+ } catch (error) {}
283
+ },
284
+
285
+ next: function () {
286
+ try {
287
+ this.glide.go(">");
288
+ this.glide.update({ perView: 1 });
289
+ } catch (error) {}
290
+ },
291
+
292
+ back: function () {
293
+ try {
294
+ this.glide.go("<");
295
+ this.glide.update({ perView: 1 });
296
+ } catch (error) {}
297
+ },
298
+
299
+ goToSlide: function ({ slide }) {
300
+ try {
301
+ if (this.glide) this.glide.go(`=${slide}`).update({ perView: 1 });
302
+ } catch (error) {}
303
+ },
304
+
305
+ formatDate,
306
+ timeAgo,
307
+ },
308
+ };
309
+ </script>
310
+
311
+ <style lang="scss">
312
+ .mt-quickview {
313
+ padding: 0;
314
+
315
+ @media (min-width: 992px) {
316
+ display: flex;
317
+ }
318
+
319
+ @media (min-width: 1200px) {
320
+ display: flex;
321
+ }
322
+
323
+ .close {
324
+ position: absolute;
325
+ z-index: 1;
326
+ padding: 8px 1rem;
327
+ }
328
+
329
+ &__galery {
330
+ max-width: 500px;
331
+ min-height: 500px;
332
+ width: 100%;
333
+ display: flex;
334
+ align-items: center;
335
+
336
+ img {
337
+ max-width: 500px;
338
+ max-height: 500px;
339
+ height: 100%;
340
+ object-fit: contain;
341
+ width: 100%;
342
+ }
343
+
344
+ .glide__slides {
345
+ align-items: center;
346
+ }
347
+ }
348
+
349
+ &__info {
350
+ display: flex;
351
+ align-items: center;
352
+ gap: 10px;
353
+ padding-bottom: 10px;
354
+ }
355
+
356
+ &__review {
357
+ padding: 1rem;
358
+
359
+ @media (min-width: 992px) {
360
+ max-height: 500px;
361
+ overflow: auto;
362
+ }
363
+
364
+ @media (min-width: 1200px) {
365
+ max-height: 500px;
366
+ overflow: auto;
367
+ }
368
+ }
369
+
370
+ &__controls {
371
+ padding: 5px;
372
+
373
+ button {
374
+ width: 30px;
375
+ height: 30px;
376
+ border: none;
377
+ border-radius: 50%;
378
+ transition: all ease-in-out 0.5s;
379
+ display: flex;
380
+ align-items: center;
381
+ justify-content: center;
382
+
383
+ &:hover {
384
+ background-color: var(--button--hover-color);
385
+ }
386
+ }
387
+ }
388
+
389
+ .mt-review {
390
+ padding: 10px 20px;
391
+ }
392
+
393
+ .video-wrapper {
394
+ display: flex;
395
+ align-items: center;
396
+ }
397
+ }
398
+ </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <div class="body-wrapper">
3
+ <div class="mt-review__body">{{ body }}</div>
4
+ <span class="mt-review__date" :title="formatDate(createdAt)">
5
+ {{ i19published }}
6
+ {{ timeAgo(createdAt) }}
7
+ </span>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ import { formatDate } from "@ecomplus/utils";
13
+ import { timeAgo } from "../../utils/time-ago";
14
+
15
+ export default {
16
+
17
+ name: "ReviewBody",
18
+
19
+ props: {
20
+ body: {
21
+ type: String,
22
+ required: true
23
+ },
24
+ createdAt: {
25
+ type: String,
26
+ required: true
27
+ },
28
+ },
29
+
30
+ computed: {
31
+ i19published: () => 'Publicado'
32
+ },
33
+
34
+ methods: {
35
+ formatDate,
36
+ timeAgo
37
+ }
38
+ };
39
+ </script>