@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.
- package/CHANGELOG.md +132 -0
- package/README.md +11 -0
- package/cms.config.js +264 -0
- package/dist/public/widget-martan.1.min.js +2 -0
- package/dist/public/widget-martan.1.min.js.map +1 -0
- package/dist/public/widget-martan.2.min.js +2 -0
- package/dist/public/widget-martan.2.min.js.map +1 -0
- package/dist/public/widget-martan.3.min.js +2 -0
- package/dist/public/widget-martan.3.min.js.map +1 -0
- package/dist/public/widget-martan.4.min.js +2 -0
- package/dist/public/widget-martan.4.min.js.map +1 -0
- package/dist/public/widget-martan.5.min.js +2 -0
- package/dist/public/widget-martan.5.min.js.map +1 -0
- package/dist/public/widget-martan.var.min.js +71 -0
- package/dist/public/widget-martan.var.min.js.map +1 -0
- package/dist/widget-martan.1.min.js +2 -0
- package/dist/widget-martan.1.min.js.map +1 -0
- package/dist/widget-martan.2.min.js +2 -0
- package/dist/widget-martan.2.min.js.map +1 -0
- package/dist/widget-martan.3.min.js +2 -0
- package/dist/widget-martan.3.min.js.map +1 -0
- package/dist/widget-martan.4.min.js +2 -0
- package/dist/widget-martan.4.min.js.map +1 -0
- package/dist/widget-martan.5.min.js +2 -0
- package/dist/widget-martan.5.min.js.map +1 -0
- package/dist/widget-martan.min.js +71 -0
- package/dist/widget-martan.min.js.map +1 -0
- package/package.json +36 -0
- package/src/append/body.ejs +79 -0
- package/src/append/head.ejs +5 -0
- package/src/append/product-block.ejs +5 -0
- package/src/append/product-card-slots.ejs +3 -0
- package/src/append/product-slots.ejs +25 -0
- package/src/append/stamps.ejs +3 -0
- package/src/index.js +22 -0
- package/src/utils/get-width.js +11 -0
- package/src/utils/textToNumber.js +31 -0
- package/src/utils/time-ago.js +35 -0
- package/src/widgets/reviews/AuthorAndRating.vue +30 -0
- package/src/widgets/reviews/AverageScore.vue +160 -0
- package/src/widgets/reviews/AverageTotal.vue +35 -0
- package/src/widgets/reviews/CardReview.vue +87 -0
- package/src/widgets/reviews/GridView.vue +113 -0
- package/src/widgets/reviews/HeaderExpanded.vue +84 -0
- package/src/widgets/reviews/HeaderMinimal.vue +110 -0
- package/src/widgets/reviews/ListView.vue +47 -0
- package/src/widgets/reviews/Quickview.vue +398 -0
- package/src/widgets/reviews/ReviewBody.vue +39 -0
- package/src/widgets/reviews/ReviewReply.vue +57 -0
- package/src/widgets/reviews/Reviews.vue +496 -0
- package/src/widgets/reviews/Score.vue +186 -0
- package/src/widgets/reviews/Sort.vue +76 -0
- package/src/widgets/reviews/ThumbsPictures.vue +135 -0
- package/src/widgets/reviews/Total.vue +79 -0
- package/src/widgets/reviews/VerifiedPurchase.vue +111 -0
- package/src/widgets/reviews/VideoPlayer.vue +136 -0
- package/src/widgets/reviews/index.js +52 -0
- package/src/widgets/reviews/isRecommended.vue +44 -0
- package/src/widgets/snippets/Rating.vue +71 -0
- package/src/widgets/snippets/Snippets.vue +311 -0
- package/src/widgets/snippets/index.js +45 -0
- package/webpack.config.js +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ecomplus/widget-martan",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Storefront plugin for martan product reviews, product q&a",
|
|
5
|
+
"main": "dist/widget-martan.min.js",
|
|
6
|
+
"module": "src/index.js",
|
|
7
|
+
"browser": "dist/widget-martan.min.js",
|
|
8
|
+
"jsdelivr": "dist/public/widget-martan.var.min.js",
|
|
9
|
+
"unpkg": "dist/public/widget-martan.var.min.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "cross-env NODE_ENV=production webpack",
|
|
12
|
+
"serve": "webpack-dev-server"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/ecomplus/storefront.git",
|
|
17
|
+
"directory": "@ecomplus/widget-martan"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"ecomplus",
|
|
21
|
+
"storefront",
|
|
22
|
+
"widget",
|
|
23
|
+
"martan",
|
|
24
|
+
"reviews"
|
|
25
|
+
],
|
|
26
|
+
"author": "Talisson Trindade <tt@martan.app>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/ecomplus/storefront/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/ecomplus/storefront/tree/master/@ecomplus/widget-martan#readme",
|
|
32
|
+
"webpackOutput": {
|
|
33
|
+
"library": "widgetMartan",
|
|
34
|
+
"filename": "widget-martan.min.js"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
document.addEventListener("DOMContentLoaded", function (event) {
|
|
3
|
+
const scriptUrl =
|
|
4
|
+
"<%- options.widgets_src || 'https://unpkg.com/@martan-app/widgets-js@1.1.23/dist/martan.umd.js' %>"
|
|
5
|
+
|
|
6
|
+
const startWidget = () => {
|
|
7
|
+
const color =
|
|
8
|
+
"<%- options.widget_rating && options.widget_rating.star_color || '#000' %>"
|
|
9
|
+
const fontSize =
|
|
10
|
+
"<%- options.widget_rating && options.widget_rating.font_size || 14 %>"
|
|
11
|
+
|
|
12
|
+
const storeId = "<%- options.store_id %>"
|
|
13
|
+
const widgetKey = "<%- options.widget_key %>"
|
|
14
|
+
const webId = "<%- options.web_id %>"
|
|
15
|
+
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
try {
|
|
18
|
+
const martan = new window.Martan({
|
|
19
|
+
storeId: parseInt(storeId, 10),
|
|
20
|
+
widgetKey,
|
|
21
|
+
webId
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const init = () =>
|
|
25
|
+
martan
|
|
26
|
+
.average({
|
|
27
|
+
fontSize,
|
|
28
|
+
color,
|
|
29
|
+
classes: ['.product-card__rating']
|
|
30
|
+
})
|
|
31
|
+
.start()
|
|
32
|
+
|
|
33
|
+
const $searchEngine = document.getElementById("search-engine")
|
|
34
|
+
if (!$searchEngine) {
|
|
35
|
+
init()
|
|
36
|
+
} else {
|
|
37
|
+
const displayOnSearchPage =
|
|
38
|
+
"<%- options.widget_rating && options.widget_rating.search_page %>"
|
|
39
|
+
|
|
40
|
+
if (displayOnSearchPage === "true") {
|
|
41
|
+
const callback = () => {
|
|
42
|
+
searchEngineObserver.disconnect()
|
|
43
|
+
const $retailRow = $searchEngine.querySelectorAll(
|
|
44
|
+
".search-engine__retail > .row"
|
|
45
|
+
)[0]
|
|
46
|
+
|
|
47
|
+
const rowObserver = new MutationObserver(() => {
|
|
48
|
+
setTimeout(() => init(), 100)
|
|
49
|
+
rowObserver.disconnect()
|
|
50
|
+
})
|
|
51
|
+
rowObserver.observe($retailRow, {
|
|
52
|
+
childList: true,
|
|
53
|
+
subtree: true,
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
const searchEngineObserver = new MutationObserver(callback)
|
|
57
|
+
searchEngineObserver.observe($searchEngine, {
|
|
58
|
+
attributes: true,
|
|
59
|
+
childList: true,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {}
|
|
64
|
+
}, 50)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const isEnabled =
|
|
68
|
+
"<%- options.widget_rating && options.widget_rating.is_enabled %>"
|
|
69
|
+
|
|
70
|
+
if (isEnabled === "true") {
|
|
71
|
+
const script = document.createElement("script")
|
|
72
|
+
script.setAttribute("src", scriptUrl)
|
|
73
|
+
script.setAttribute("id", "martan-scripts")
|
|
74
|
+
script.async = true
|
|
75
|
+
document.body.appendChild(script)
|
|
76
|
+
script.onload = startWidget
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
</script>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<section id="reviews">
|
|
2
|
+
<div class="container" id="<%- options.martanReviewsTarget || 'reviews_widget' %>" data-product="<%- _.state.sku %>" style="margin-bottom: 1rem; display: <%- options && options.widget_rating && options.widget_rating.is_enabled
|
|
3
|
+
? 'initial' : 'none' %>;">
|
|
4
|
+
</div>
|
|
5
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<div data-slot="rating" class="d-none">
|
|
2
|
+
<div
|
|
3
|
+
id="martan-rating__action"
|
|
4
|
+
style="margin-bottom: 1rem; display: <%- options && options.widget_rating && options.widget_rating.is_enabled ? 'initial' : 'none' %>;"
|
|
5
|
+
>
|
|
6
|
+
<a
|
|
7
|
+
class="martan-widget-rating"
|
|
8
|
+
title="Pergunte e veja opiniões de quem já comprou"
|
|
9
|
+
href="#reviews"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
data-martan-style="completed"
|
|
13
|
+
data-martan-product-id="<%- _.state.sku %>"
|
|
14
|
+
class="mt-review-average d-inline-block"
|
|
15
|
+
></div>
|
|
16
|
+
</a>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div
|
|
20
|
+
class="d-none"
|
|
21
|
+
id="snippet_widget"
|
|
22
|
+
data-sku="<%- _.state.sku %>"
|
|
23
|
+
style="margin-bottom: 1rem; height: 60px"
|
|
24
|
+
></div>
|
|
25
|
+
</div>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Reviews from './widgets/reviews'
|
|
2
|
+
import Snippets from './widgets/snippets'
|
|
3
|
+
|
|
4
|
+
export const MARTAN_API = 'https://widgets.martan.app/v1'
|
|
5
|
+
|
|
6
|
+
export default (options) => {
|
|
7
|
+
if (options && options.store_id && options.web_id) {
|
|
8
|
+
if (options.widget_snippet && options.widget_snippet.is_enabled) {
|
|
9
|
+
Snippets(options)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (options.widget_review && options.widget_review.is_enabled) {
|
|
13
|
+
Reviews(options)
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
console.error(
|
|
17
|
+
new Error(
|
|
18
|
+
"Can't setup Martan widget without `martanStoreId` and `martanWidgetKey`"
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { numberToText } from './textToNumber'
|
|
2
|
+
|
|
3
|
+
// calcula a % usando a média de avaliacoes / total de avaliacoes do produto
|
|
4
|
+
export function getWidth(reviews, rating) {
|
|
5
|
+
if (reviews.total === 0) return '0%'
|
|
6
|
+
|
|
7
|
+
return `${(
|
|
8
|
+
(100 * reviews.average[numberToText(rating)]) /
|
|
9
|
+
reviews.total
|
|
10
|
+
).toFixed()}%`
|
|
11
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const textToNumber = (number) => {
|
|
2
|
+
switch (number) {
|
|
3
|
+
case 'one':
|
|
4
|
+
return 1
|
|
5
|
+
case 'two':
|
|
6
|
+
return 2
|
|
7
|
+
case 'three':
|
|
8
|
+
return 3
|
|
9
|
+
case 'four':
|
|
10
|
+
return 4
|
|
11
|
+
case 'five':
|
|
12
|
+
return 5
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const numberToText = (text) => {
|
|
17
|
+
switch (text) {
|
|
18
|
+
case 1:
|
|
19
|
+
return 'one'
|
|
20
|
+
case 2:
|
|
21
|
+
return 'two'
|
|
22
|
+
case 3:
|
|
23
|
+
return 'three'
|
|
24
|
+
case 4:
|
|
25
|
+
return 'four'
|
|
26
|
+
case 5:
|
|
27
|
+
return 'five'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { textToNumber, numberToText }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Retorna uma hora em formato humanizade
|
|
2
|
+
export function timeAgo (date) {
|
|
3
|
+
const segundos = Math.floor((new Date() - new Date(date)) / 1000)
|
|
4
|
+
|
|
5
|
+
const intervalos = {
|
|
6
|
+
ano: 31536000,
|
|
7
|
+
mês: 2592000,
|
|
8
|
+
semana: 604800,
|
|
9
|
+
dia: 86400,
|
|
10
|
+
hora: 3600,
|
|
11
|
+
minuto: 60,
|
|
12
|
+
segundo: 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let contador
|
|
16
|
+
|
|
17
|
+
if (segundos === 0) {
|
|
18
|
+
return 'Agora'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const intervalo in intervalos) {
|
|
22
|
+
contador = Math.floor(segundos / intervalos[intervalo])
|
|
23
|
+
|
|
24
|
+
if (contador > 0) {
|
|
25
|
+
if (contador === 1) {
|
|
26
|
+
return `${contador} ${intervalo} atrás`
|
|
27
|
+
} else {
|
|
28
|
+
if (intervalo === 'mês') {
|
|
29
|
+
return `${contador} meses atrás`
|
|
30
|
+
}
|
|
31
|
+
return `${contador} ${intervalo}s atrás`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="display: flex;align-items: baseline; justify-content: space-between">
|
|
3
|
+
<div style="display: flex; height: 20px; align-items: center; gap: 5px">
|
|
4
|
+
<div class="mt-review__author" style="padding-right: 2px">
|
|
5
|
+
<span>{{ isAnonymous ? "Anônimo" : author }}</span>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<rating :rating="rating" :color="starColor" />
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import Rating from "../snippets/Rating.vue";
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: "AuthorAndRating",
|
|
18
|
+
|
|
19
|
+
props: {
|
|
20
|
+
isAnonymous: Boolean,
|
|
21
|
+
author: String,
|
|
22
|
+
rating: Number,
|
|
23
|
+
starColor: String,
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
components: {
|
|
27
|
+
Rating,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ul class="mt-rating__options" ref="options">
|
|
3
|
+
<li class="mt-rating__list" v-for="index in maxReviews" :key="index"
|
|
4
|
+
v-on:click="(e) => (reviews.total === 0 ? null : setRating(e, index))">
|
|
5
|
+
<div class="mt-rating-star">
|
|
6
|
+
<span>{{ index }}</span>
|
|
7
|
+
|
|
8
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-star" width="14" height="14"
|
|
9
|
+
viewBox="0 0 24 24" stroke-width="2" stroke="#e3e6e6" fill="none" stroke-linecap="round"
|
|
10
|
+
stroke-linejoin="round">
|
|
11
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
12
|
+
<path
|
|
13
|
+
d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
|
|
14
|
+
</svg>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="mt-rating-meter">
|
|
18
|
+
<div class="mt-rating-bar" v-bind:style="{
|
|
19
|
+
width: reviews.getWidth(index),
|
|
20
|
+
'background-color': config.star_color || 'red',
|
|
21
|
+
}" />
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="mt-rating-total">
|
|
25
|
+
<span>{{ reviews.average[numberToText(index)] }}</span>
|
|
26
|
+
<span>({{ reviews.getWidth(index) }})</span>
|
|
27
|
+
|
|
28
|
+
<span class="mt-rating-remove"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-x"
|
|
29
|
+
width="15" height="15" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
|
30
|
+
stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
32
|
+
<path d="M18 6l-12 12"></path>
|
|
33
|
+
<path d="M6 6l12 12"></path>
|
|
34
|
+
</svg></span>
|
|
35
|
+
</div>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<script>
|
|
42
|
+
export default {
|
|
43
|
+
name: 'AverageScore',
|
|
44
|
+
|
|
45
|
+
props: {
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
data() {
|
|
49
|
+
return {
|
|
50
|
+
maxReviews: 5
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
methods: {
|
|
55
|
+
async setRating(e, rating) {
|
|
56
|
+
const removeClass = () =>
|
|
57
|
+
new Promise((resolve) => {
|
|
58
|
+
const res = Array.from(options.value.children).map((option) => {
|
|
59
|
+
option.style.removeProperty("opacity")
|
|
60
|
+
option.children[0].childNodes[1].style.stroke = "rgb(227, 230, 230)"
|
|
61
|
+
return option.classList.remove("is-active")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
resolve(res)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
await removeClass().then(() => {
|
|
68
|
+
if (rating !== reviews.orderRating) {
|
|
69
|
+
const el = Array.from(options.value.children)[rating - 1]
|
|
70
|
+
el.classList.add("is-active")
|
|
71
|
+
el.style.opacity = 1
|
|
72
|
+
el.children[0].childNodes[1].style.stroke = config.star_color
|
|
73
|
+
Array.from(options.value.children).forEach((option, index) => {
|
|
74
|
+
if (index !== rating - 1) {
|
|
75
|
+
option.style.opacity = ".5"
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
if (rating === reviews.orderRating) {
|
|
82
|
+
reviews.orderRating = null
|
|
83
|
+
} else {
|
|
84
|
+
reviews.offset = 0
|
|
85
|
+
reviews.orderRating = rating
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<style>
|
|
93
|
+
.mt-rating-remove {
|
|
94
|
+
visibility: hidden;
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.mt-rating__list.is-active .mt-rating-remove {
|
|
101
|
+
visibility: visible;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.mt-rating__options li:hover {
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.mt-rating__list {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
height: 23px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.mt-rating__list.is-active .mt-rating-total,
|
|
115
|
+
.mt-rating__list:hover .mt-rating-total {
|
|
116
|
+
visibility: visible;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.mt-rating__list:hover {
|
|
120
|
+
opacity: 0.9;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.mt-rating-meter {
|
|
124
|
+
overflow: hidden;
|
|
125
|
+
box-shadow: inset 0 0 0 1px #e3e6e6;
|
|
126
|
+
background-color: #e3e6e6;
|
|
127
|
+
height: 10px;
|
|
128
|
+
width: 100%;
|
|
129
|
+
border-radius: 50px;
|
|
130
|
+
display: flex;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.mt-rating__options {
|
|
134
|
+
margin: 0;
|
|
135
|
+
list-style: none;
|
|
136
|
+
padding: 0;
|
|
137
|
+
max-width: 800px;
|
|
138
|
+
width: 100%;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.mt-rating-star {
|
|
142
|
+
display: flex;
|
|
143
|
+
width: 30px;
|
|
144
|
+
justify-content: space-around;
|
|
145
|
+
font-size: 12px;
|
|
146
|
+
color: #757373;
|
|
147
|
+
align-items: center;
|
|
148
|
+
margin-left: 5px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.mt-rating-total {
|
|
152
|
+
visibility: hidden;
|
|
153
|
+
width: 50px;
|
|
154
|
+
font-size: 12px;
|
|
155
|
+
color: #757373;
|
|
156
|
+
margin-left: 2px;
|
|
157
|
+
display: flex;
|
|
158
|
+
gap: 3px;
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export default {
|
|
3
|
+
name: 'AverageTotal',
|
|
4
|
+
|
|
5
|
+
props: {
|
|
6
|
+
average: {
|
|
7
|
+
type: Number,
|
|
8
|
+
default: 0
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="mt-rating__resume" :title="'Nota média ' + average">
|
|
16
|
+
<div class="mt-rating__average">
|
|
17
|
+
<div class="mt-rating__average__wrapper">
|
|
18
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-star-filled" width="24" height="24"
|
|
19
|
+
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round"
|
|
20
|
+
stroke-linejoin="round">
|
|
21
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
22
|
+
<path
|
|
23
|
+
d="M8.243 7.34l-6.38 .925l-.113 .023a1 1 0 0 0 -.44 1.684l4.622 4.499l-1.09 6.355l-.013 .11a1 1 0 0 0 1.464 .944l5.706 -3l5.693 3l.1 .046a1 1 0 0 0 1.352 -1.1l-1.091 -6.355l4.624 -4.5l.078 -.085a1 1 0 0 0 -.633 -1.62l-6.38 -.926l-2.852 -5.78a1 1 0 0 0 -1.794 0l-2.853 5.78z"
|
|
24
|
+
stroke-width="0" fill="currentColor" />
|
|
25
|
+
</svg>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div style="margin-left: 10px">
|
|
29
|
+
<p class="mt-rating__average--total">
|
|
30
|
+
{{ average }}
|
|
31
|
+
</p>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mt-review">
|
|
3
|
+
<div class="mt-rating__group">
|
|
4
|
+
<author-and-rating
|
|
5
|
+
v-if="review"
|
|
6
|
+
:author="review.display_name"
|
|
7
|
+
:isAnonymous="review.is_anonymous"
|
|
8
|
+
:rating="review.rating"
|
|
9
|
+
:starColor="starColor"
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
<is-recommended v-if="review" :recommended="review.is_recommended" />
|
|
13
|
+
|
|
14
|
+
<verified-purchase v-if="isVerified" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<thumbs-pictures
|
|
18
|
+
:review="review"
|
|
19
|
+
@onClick="(e) => $emit('openQuickview', e)"
|
|
20
|
+
/>
|
|
21
|
+
|
|
22
|
+
<review-body
|
|
23
|
+
v-if="review"
|
|
24
|
+
:body="review.body"
|
|
25
|
+
:createdAt="review.created_at"
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
<review-reply :reply="review.reply" />
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
import Rating from "../snippets/Rating.vue";
|
|
34
|
+
import ThumbsPictures from "./ThumbsPictures.vue";
|
|
35
|
+
import VerifiedPurchase from "./VerifiedPurchase.vue";
|
|
36
|
+
import AuthorAndRating from "./AuthorAndRating.vue";
|
|
37
|
+
import IsRecommended from "./isRecommended.vue";
|
|
38
|
+
import ReviewBody from "./ReviewBody.vue";
|
|
39
|
+
import ReviewReply from "./ReviewReply.vue";
|
|
40
|
+
|
|
41
|
+
export default {
|
|
42
|
+
name: "CardReview",
|
|
43
|
+
|
|
44
|
+
props: {
|
|
45
|
+
review: {
|
|
46
|
+
type: Object,
|
|
47
|
+
default () {
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
starColor: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "#212529",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
components: {
|
|
59
|
+
ThumbsPictures,
|
|
60
|
+
Rating,
|
|
61
|
+
VerifiedPurchase,
|
|
62
|
+
AuthorAndRating,
|
|
63
|
+
IsRecommended,
|
|
64
|
+
ReviewBody,
|
|
65
|
+
ReviewReply,
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
computed: {
|
|
69
|
+
isVerified: function () {
|
|
70
|
+
return this.review && this.review.verified_purchase;
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<style>
|
|
77
|
+
.mt-reply__wrapper {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (max-width: 580px) {
|
|
83
|
+
.body-wrapper {
|
|
84
|
+
padding: 0px;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mt-gridview">
|
|
3
|
+
<div class="mt-gridview__card" v-for="review in reviews.list" :key="review.id" @click="(e) => openQuickview(review)">
|
|
4
|
+
<div class="mt-gridview__thumb" v-if="getPictureURL(review)">
|
|
5
|
+
<img :src="getPictureURL(review)" :alt="review.title" @click="() => openQuickview(review)" />
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div class="mt-gridview__detail">
|
|
9
|
+
<span class="mt-gridview__author">{{ review.display_name.substr(0, 16) }}</span>
|
|
10
|
+
<rating :rating="review.rating" :color="starColor" />
|
|
11
|
+
<verified-purchase v-if="review.verified_purchase" />
|
|
12
|
+
<span class="mt-gridview__body">{{ review.body.substr(0, 250) }}</span>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import Rating from '../snippets/Rating.vue';
|
|
20
|
+
import CardReview from "./CardReview.vue";
|
|
21
|
+
import VerifiedPurchase from './VerifiedPurchase.vue';
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
name: "GridView",
|
|
25
|
+
|
|
26
|
+
components: {
|
|
27
|
+
CardReview,
|
|
28
|
+
Rating,
|
|
29
|
+
VerifiedPurchase,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
props: {
|
|
33
|
+
starColor: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: "#212529",
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
reviews: {
|
|
39
|
+
type: Object,
|
|
40
|
+
default: {
|
|
41
|
+
list: [],
|
|
42
|
+
orderRating: null,
|
|
43
|
+
total: 0,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
methods: {
|
|
49
|
+
openQuickview: function (review) {
|
|
50
|
+
this.$emit('openQuickview', { review })
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
getPictureURL(review) {
|
|
54
|
+
if (review && review.pictures && review.pictures.length && review.pictures[0].normal) {
|
|
55
|
+
return review.pictures[0].normal
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return false
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<style lang="scss">
|
|
65
|
+
.mt-gridview {
|
|
66
|
+
transition: all 0.7s ease;
|
|
67
|
+
column-count: 2;
|
|
68
|
+
column-gap: 10px;
|
|
69
|
+
margin-right: auto;
|
|
70
|
+
margin-left: auto;
|
|
71
|
+
|
|
72
|
+
@media only screen and (min-width: 600px) {
|
|
73
|
+
column-count: 3;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media only screen and (min-width: 768px) {
|
|
77
|
+
column-count: 4;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@media only screen and (min-width: 992px) {
|
|
81
|
+
column-count: 5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&__card {
|
|
85
|
+
width: 100%;
|
|
86
|
+
border: 1px #d5d9d9 solid;
|
|
87
|
+
border-radius: 6px;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
margin: 0;
|
|
90
|
+
display: grid;
|
|
91
|
+
grid-template-rows: 1fr auto;
|
|
92
|
+
margin-bottom: 10px;
|
|
93
|
+
break-inside: avoid;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&__detail {
|
|
97
|
+
padding: 10px;
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
gap: 8px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&__thumb {
|
|
104
|
+
img {
|
|
105
|
+
max-width: 250px;
|
|
106
|
+
width: 100%;
|
|
107
|
+
object-fit: contain;
|
|
108
|
+
border-top-right-radius: 5px;
|
|
109
|
+
border-top-left-radius: 5px;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
</style>
|