@shopware/cms-base-layer 0.0.0-canary-20250116171244

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +144 -0
  3. package/components/SwCategoryNavigation.vue +44 -0
  4. package/components/SwCategoryNavigationLink.vue +57 -0
  5. package/components/SwContactForm.vue +392 -0
  6. package/components/SwListingProductPrice.vue +88 -0
  7. package/components/SwMedia3D.vue +34 -0
  8. package/components/SwNewsletterForm.vue +347 -0
  9. package/components/SwPagination.vue +106 -0
  10. package/components/SwProductAddToCart.vue +93 -0
  11. package/components/SwProductCard.vue +285 -0
  12. package/components/SwProductGallery.vue +39 -0
  13. package/components/SwProductListingFilter.vue +42 -0
  14. package/components/SwProductListingFilters.vue +292 -0
  15. package/components/SwProductPrice.vue +99 -0
  16. package/components/SwProductReviews.vue +99 -0
  17. package/components/SwProductUnits.vue +54 -0
  18. package/components/SwSharedPrice.vue +19 -0
  19. package/components/SwSlider.vue +328 -0
  20. package/components/SwVariantConfigurator.vue +116 -0
  21. package/components/listing-filters/SwFilterPrice.vue +160 -0
  22. package/components/listing-filters/SwFilterProperties.vue +123 -0
  23. package/components/listing-filters/SwFilterRating.vue +101 -0
  24. package/components/listing-filters/SwFilterShippingFree.vue +104 -0
  25. package/components/public/cms/CmsGenericBlock.md +27 -0
  26. package/components/public/cms/CmsGenericBlock.vue +63 -0
  27. package/components/public/cms/CmsGenericElement.md +31 -0
  28. package/components/public/cms/CmsGenericElement.vue +38 -0
  29. package/components/public/cms/CmsNoComponent.vue +27 -0
  30. package/components/public/cms/CmsPage.md +36 -0
  31. package/components/public/cms/CmsPage.vue +65 -0
  32. package/components/public/cms/block/CmsBlockCategoryNavigation.vue +16 -0
  33. package/components/public/cms/block/CmsBlockCenterText.vue +26 -0
  34. package/components/public/cms/block/CmsBlockCrossSelling.vue +15 -0
  35. package/components/public/cms/block/CmsBlockCustomForm.vue +17 -0
  36. package/components/public/cms/block/CmsBlockDefault.vue +14 -0
  37. package/components/public/cms/block/CmsBlockForm.vue +17 -0
  38. package/components/public/cms/block/CmsBlockGalleryBuybox.vue +25 -0
  39. package/components/public/cms/block/CmsBlockImage.vue +16 -0
  40. package/components/public/cms/block/CmsBlockImageBubbleRow.vue +32 -0
  41. package/components/public/cms/block/CmsBlockImageCover.vue +17 -0
  42. package/components/public/cms/block/CmsBlockImageFourColumn.vue +29 -0
  43. package/components/public/cms/block/CmsBlockImageGallery.vue +18 -0
  44. package/components/public/cms/block/CmsBlockImageHighlightRow.vue +27 -0
  45. package/components/public/cms/block/CmsBlockImageSimpleGrid.vue +24 -0
  46. package/components/public/cms/block/CmsBlockImageSlider.vue +17 -0
  47. package/components/public/cms/block/CmsBlockImageText.vue +19 -0
  48. package/components/public/cms/block/CmsBlockImageTextBubble.vue +51 -0
  49. package/components/public/cms/block/CmsBlockImageTextCover.vue +25 -0
  50. package/components/public/cms/block/CmsBlockImageTextGallery.vue +85 -0
  51. package/components/public/cms/block/CmsBlockImageTextRow.vue +43 -0
  52. package/components/public/cms/block/CmsBlockImageThreeColumn.vue +21 -0
  53. package/components/public/cms/block/CmsBlockImageThreeCover.vue +27 -0
  54. package/components/public/cms/block/CmsBlockImageTwoColumn.vue +25 -0
  55. package/components/public/cms/block/CmsBlockProductDescriptionReviews.vue +15 -0
  56. package/components/public/cms/block/CmsBlockProductHeading.vue +26 -0
  57. package/components/public/cms/block/CmsBlockProductListing.vue +17 -0
  58. package/components/public/cms/block/CmsBlockProductSlider.vue +16 -0
  59. package/components/public/cms/block/CmsBlockProductThreeColumn.vue +22 -0
  60. package/components/public/cms/block/CmsBlockSidebarFilter.vue +17 -0
  61. package/components/public/cms/block/CmsBlockText.vue +15 -0
  62. package/components/public/cms/block/CmsBlockTextHero.vue +15 -0
  63. package/components/public/cms/block/CmsBlockTextOnImage.vue +20 -0
  64. package/components/public/cms/block/CmsBlockTextTeaser.vue +16 -0
  65. package/components/public/cms/block/CmsBlockTextTeaserSection.vue +21 -0
  66. package/components/public/cms/block/CmsBlockTextThreeColumn.vue +22 -0
  67. package/components/public/cms/block/CmsBlockTextTwoColumn.vue +28 -0
  68. package/components/public/cms/block/CmsBlockVimeoVideo.vue +17 -0
  69. package/components/public/cms/block/CmsBlockYoutubeVideo.vue +17 -0
  70. package/components/public/cms/element/CmsElementBuyBox.md +1 -0
  71. package/components/public/cms/element/CmsElementBuyBox.vue +190 -0
  72. package/components/public/cms/element/CmsElementCategoryNavigation.md +1 -0
  73. package/components/public/cms/element/CmsElementCategoryNavigation.vue +167 -0
  74. package/components/public/cms/element/CmsElementCrossSelling.md +1 -0
  75. package/components/public/cms/element/CmsElementCrossSelling.vue +106 -0
  76. package/components/public/cms/element/CmsElementCustomForm.md +1 -0
  77. package/components/public/cms/element/CmsElementCustomForm.vue +27 -0
  78. package/components/public/cms/element/CmsElementForm.md +1 -0
  79. package/components/public/cms/element/CmsElementForm.vue +27 -0
  80. package/components/public/cms/element/CmsElementImage.md +1 -0
  81. package/components/public/cms/element/CmsElementImage.vue +105 -0
  82. package/components/public/cms/element/CmsElementImageGallery.md +1 -0
  83. package/components/public/cms/element/CmsElementImageGallery.vue +249 -0
  84. package/components/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +53 -0
  85. package/components/public/cms/element/CmsElementImageSlider.md +1 -0
  86. package/components/public/cms/element/CmsElementImageSlider.vue +29 -0
  87. package/components/public/cms/element/CmsElementManufacturerLogo.md +1 -0
  88. package/components/public/cms/element/CmsElementManufacturerLogo.vue +11 -0
  89. package/components/public/cms/element/CmsElementProductBox.md +1 -0
  90. package/components/public/cms/element/CmsElementProductBox.vue +14 -0
  91. package/components/public/cms/element/CmsElementProductDescriptionReviews.md +1 -0
  92. package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +109 -0
  93. package/components/public/cms/element/CmsElementProductListing.md +1 -0
  94. package/components/public/cms/element/CmsElementProductListing.vue +245 -0
  95. package/components/public/cms/element/CmsElementProductName.md +1 -0
  96. package/components/public/cms/element/CmsElementProductName.vue +10 -0
  97. package/components/public/cms/element/CmsElementProductSlider.md +1 -0
  98. package/components/public/cms/element/CmsElementProductSlider.vue +80 -0
  99. package/components/public/cms/element/CmsElementSidebarFilter.md +1 -0
  100. package/components/public/cms/element/CmsElementSidebarFilter.vue +12 -0
  101. package/components/public/cms/element/CmsElementText.md +1 -0
  102. package/components/public/cms/element/CmsElementText.vue +186 -0
  103. package/components/public/cms/element/CmsElementVimeoVideo.md +1 -0
  104. package/components/public/cms/element/CmsElementVimeoVideo.vue +63 -0
  105. package/components/public/cms/element/CmsElementYoutubeVideo.md +1 -0
  106. package/components/public/cms/element/CmsElementYoutubeVideo.vue +43 -0
  107. package/components/public/cms/section/CmsSectionDefault.md +3 -0
  108. package/components/public/cms/section/CmsSectionDefault.vue +21 -0
  109. package/components/public/cms/section/CmsSectionSidebar.md +3 -0
  110. package/components/public/cms/section/CmsSectionSidebar.vue +49 -0
  111. package/components/public/cms/skeleton/ProductCardSkeleton.vue +44 -0
  112. package/dist/index.d.mts +5 -0
  113. package/dist/index.d.ts +5 -0
  114. package/dist/index.mjs +31 -0
  115. package/helpers/clientOnly.ts +11 -0
  116. package/helpers/html-to-vue/ast.ts +72 -0
  117. package/helpers/html-to-vue/getOptionsFromNode.test.ts +129 -0
  118. package/helpers/html-to-vue/getOptionsFromNode.ts +52 -0
  119. package/helpers/html-to-vue/renderToHtml.ts +45 -0
  120. package/helpers/html-to-vue/renderer.ts +56 -0
  121. package/helpers/media/isSpatial.ts +8 -0
  122. package/index.cjs +7 -0
  123. package/nuxt.config.ts +21 -0
  124. package/package.json +69 -0
@@ -0,0 +1,249 @@
1
+ <script setup lang="ts">
2
+ import type { CmsElementImageGallery } from "@shopware/composables";
3
+ import { computed, onMounted, ref, useTemplateRef } from "vue";
4
+ import { useCmsElementConfig } from "#imports";
5
+ import { isSpatial } from "../../../../helpers/media/isSpatial";
6
+
7
+ const props = withDefaults(
8
+ defineProps<{
9
+ content: CmsElementImageGallery;
10
+ slidesToShow?: number;
11
+ slidesToScroll?: number;
12
+ }>(),
13
+ {
14
+ slidesToShow: 5,
15
+ slidesToScroll: 4,
16
+ },
17
+ );
18
+
19
+ const { getConfigValue } = useCmsElementConfig(props.content);
20
+
21
+ const speed = ref<number>(300);
22
+ const currentIndex = ref(0);
23
+ const currentThumb = ref(0);
24
+ const imageSlider = useTemplateRef("imageSlider");
25
+ const imageThumbsTrack = useTemplateRef("imageThumbsTrack");
26
+ const isLoading = ref(true);
27
+ const imageThumbsTrackStyle = ref({});
28
+ const imageThumbs = useTemplateRef("imageThumbs");
29
+ const imageThumbsStyle = ref({});
30
+ const mediaGallery = computed(() => props.content.data?.sliderItems ?? []);
31
+ const galleryPosition = computed<string>(
32
+ () => getConfigValue("galleryPosition") ?? "left",
33
+ );
34
+ const scrollPx = ref(0);
35
+
36
+ onMounted(() => {
37
+ initThumbs();
38
+ });
39
+
40
+ function initThumbs() {
41
+ if (imageThumbsTrack.value) {
42
+ setTimeout(() => {
43
+ if (galleryPosition.value === "left") {
44
+ const clientHeight = imageThumbsTrack.value?.clientHeight ?? 0;
45
+ scrollPx.value = clientHeight / mediaGallery.value.length;
46
+ imageThumbsStyle.value = {
47
+ height: `${scrollPx.value * +props.slidesToShow}px`,
48
+ };
49
+ } else {
50
+ const clientWidth = imageThumbs.value?.clientWidth ?? 0;
51
+ scrollPx.value = clientWidth / props.slidesToShow;
52
+ imageThumbsTrackStyle.value = {
53
+ width: `${scrollPx.value * mediaGallery.value.length}px`,
54
+ };
55
+ }
56
+ isLoading.value = false;
57
+ }, 100);
58
+ }
59
+ }
60
+
61
+ function changeCover(i: number) {
62
+ if (i === currentIndex.value) return;
63
+ imageSlider.value?.goToSlide(i);
64
+ }
65
+
66
+ function handleChangeSlide(e: number) {
67
+ currentIndex.value = e;
68
+ if (currentIndex.value > currentThumb.value + props.slidesToShow - 1) {
69
+ move("next", currentIndex.value);
70
+ return;
71
+ }
72
+ if (currentIndex.value < currentThumb.value) {
73
+ move("previous", currentIndex.value);
74
+ return;
75
+ }
76
+ }
77
+
78
+ function move(type: "next" | "previous", specificIndex?: number | string) {
79
+ let step: number;
80
+ const index =
81
+ typeof specificIndex !== "number"
82
+ ? Number.parseInt(specificIndex as string)
83
+ : specificIndex;
84
+ if (index >= 0) {
85
+ if (type === "next") {
86
+ step =
87
+ index + props.slidesToScroll < mediaGallery.value.length
88
+ ? index
89
+ : mediaGallery.value.length - props.slidesToShow;
90
+ } else {
91
+ step =
92
+ index - props.slidesToScroll > 0 ? index - props.slidesToScroll : 0;
93
+ }
94
+ } else {
95
+ if (type === "next") {
96
+ step =
97
+ currentThumb.value + props.slidesToShow - 1 + props.slidesToScroll <
98
+ mediaGallery.value.length
99
+ ? currentThumb.value + props.slidesToScroll
100
+ : mediaGallery.value.length - props.slidesToShow;
101
+ } else {
102
+ step =
103
+ currentThumb.value - props.slidesToScroll > 0
104
+ ? currentThumb.value - props.slidesToScroll
105
+ : 0;
106
+ }
107
+ }
108
+ currentThumb.value = step;
109
+ let xAxis = 0;
110
+ let yAxis = 0;
111
+ if (galleryPosition.value === "left") {
112
+ yAxis = scrollPx.value * currentThumb.value;
113
+ } else {
114
+ xAxis = scrollPx.value * currentThumb.value;
115
+ }
116
+ imageThumbsTrackStyle.value = {
117
+ ...imageThumbsTrackStyle.value,
118
+ transform: `translate3d(-${xAxis}px, -${yAxis}px, 0px)`,
119
+ transition: `transform ${speed.value}ms ease 0s`,
120
+ };
121
+ }
122
+
123
+ function previous() {
124
+ if (currentThumb.value <= 0) {
125
+ return;
126
+ }
127
+ move("previous");
128
+ }
129
+
130
+ function next() {
131
+ if (currentThumb.value + props.slidesToShow >= mediaGallery.value.length) {
132
+ return;
133
+ }
134
+ move("next");
135
+ }
136
+ </script>
137
+
138
+ <template>
139
+ <div
140
+ :class="{
141
+ 'opacity-0': isLoading,
142
+ 'flex gap-10': true,
143
+ 'flex-col-reverse': galleryPosition === 'underneath',
144
+ }"
145
+ >
146
+ <div
147
+ :class="{
148
+ 'hidden lg:flex basis-20 relative flex-col items-center':
149
+ galleryPosition === 'left',
150
+ 'flex relative w-full': galleryPosition === 'underneath',
151
+ }"
152
+ >
153
+ <button
154
+ v-if="mediaGallery.length > slidesToShow"
155
+ class="disabled:opacity-10 p-1"
156
+ aria-label="Previous image"
157
+ @click="previous"
158
+ >
159
+ <div
160
+ class="h-7 w-7"
161
+ :class="{
162
+ 'i-carbon-chevron-up': galleryPosition === 'left',
163
+ 'i-carbon-chevron-left': galleryPosition !== 'left',
164
+ }"
165
+ />
166
+ </button>
167
+ <span class="sr-only">Previous image</span>
168
+ <div
169
+ ref="imageThumbs"
170
+ class="overflow-hidden -my-2.5"
171
+ :style="imageThumbsStyle"
172
+ >
173
+ <div
174
+ ref="imageThumbsTrack"
175
+ :class="{
176
+ flex: true,
177
+ 'flex-col': galleryPosition === 'left',
178
+ }"
179
+ :style="imageThumbsTrackStyle"
180
+ >
181
+ <div
182
+ v-for="(image, i) in mediaGallery"
183
+ :key="image.media.url"
184
+ :class="{
185
+ 'py-2.5': galleryPosition === 'left',
186
+ 'flex-1 px-2.5': galleryPosition === 'underneath',
187
+ }"
188
+ >
189
+ <div
190
+ class="w-20 h-20 overflow-hidden cursor-pointer p-1 border-secondary-200 rounded transition duration-150 ease-in-out"
191
+ :class="{
192
+ border: i !== currentIndex,
193
+ 'border-indigo-500 border-3': i === currentIndex,
194
+ }"
195
+ @click="() => changeCover(i)"
196
+ >
197
+ <div v-if="isSpatial(image.media)" class="h-full relative">
198
+ <CmsElementImageGallery3dPlaceholder
199
+ class="w-full h-full object-center"
200
+ />
201
+ <span
202
+ class="absolute bottom-0 text-sm bg-gray rounded px-1 text-white"
203
+ >
204
+ 3D</span
205
+ >
206
+ </div>
207
+ <img
208
+ v-else
209
+ loading="lazy"
210
+ :src="image.media.url"
211
+ class="w-full h-full object-center object-cover"
212
+ alt="Product image"
213
+ />
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ <button
219
+ v-if="mediaGallery.length > slidesToShow"
220
+ class="disabled:opacity-10 p-1"
221
+ aria-label="Next image"
222
+ @click="next"
223
+ >
224
+ <span class="sr-only">Next image</span>
225
+ <div
226
+ class="h-7 w-7"
227
+ :class="{
228
+ 'i-carbon-chevron-down': galleryPosition === 'left',
229
+ 'i-carbon-chevron-right': galleryPosition !== 'left',
230
+ }"
231
+ />
232
+ </button>
233
+ </div>
234
+ <div class="flex-1 overflow-hidden">
235
+ <SwSlider
236
+ ref="imageSlider"
237
+ :config="props.content.config"
238
+ @change-slide="handleChangeSlide"
239
+ >
240
+ <CmsElementImage
241
+ v-for="image of mediaGallery"
242
+ :key="image.media.url"
243
+ :image-gallery="true"
244
+ :content="{ data: image, config: props.content.config } as any"
245
+ />
246
+ </SwSlider>
247
+ </div>
248
+ </div>
249
+ </template>
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <svg
3
+ xmlns="http://www.w3.org/2000/svg"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ width="552"
6
+ height="383"
7
+ viewBox="0 0 552 383"
8
+ >
9
+ <defs>
10
+ <g
11
+ id="icons-default-placeholder"
12
+ fill="none"
13
+ fill-rule="evenodd"
14
+ opacity=".65"
15
+ >
16
+ <rect
17
+ width="333.061"
18
+ height="499.591"
19
+ x="84.659"
20
+ y="-82.663"
21
+ fill="#E9EBF2"
22
+ fill-rule="nonzero"
23
+ transform="rotate(-89.862 251.19 167.132)"
24
+ ></rect>
25
+ <g transform="translate(51 49)">
26
+ <rect
27
+ width="333.06"
28
+ height="499.59"
29
+ x="83.983"
30
+ y="-83.234"
31
+ fill="#DADDE5"
32
+ fill-rule="nonzero"
33
+ transform="rotate(-90 250.513 166.561)"
34
+ ></rect>
35
+ <polygon
36
+ fill="#E9EBF2"
37
+ points="137.18 333.1 500.31 333.1 500.31 302.36 322.15 110.42"
38
+ ></polygon>
39
+ <circle cx="113.04" cy="65.68" r="35.9" fill="#F5F7FC"></circle>
40
+ <polygon
41
+ fill="#F5F7FC"
42
+ points="219.88 157.3 73.85 333.1 383.05 333.1"
43
+ ></polygon>
44
+ </g>
45
+ </g>
46
+ </defs>
47
+ <use
48
+ xlink:href="#icons-default-placeholder"
49
+ fill="#758CA3"
50
+ fill-rule="evenodd"
51
+ ></use>
52
+ </svg>
53
+ </template>
@@ -0,0 +1 @@
1
+ Display a slider of images
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ CmsElementImage,
4
+ CmsElementImageSlider,
5
+ } from "@shopware/composables";
6
+ import { computed } from "vue";
7
+
8
+ const props = defineProps<{
9
+ content: CmsElementImageSlider;
10
+ }>();
11
+ const items = computed(() => props.content.data.sliderItems);
12
+ </script>
13
+ <template>
14
+ <!-- need some with here for small views that the slider can calculate the correct items with -->
15
+ <div class="cms-element-image-slider w-[92vw] sm:w-[94vw] md:w-auto">
16
+ <SwSlider :config="props.content.config">
17
+ <CmsElementImage
18
+ v-for="image of items"
19
+ :key="image.media.url"
20
+ :content="
21
+ {
22
+ data: image,
23
+ config: props.content.config,
24
+ } as unknown as CmsElementImage
25
+ "
26
+ />
27
+ </SwSlider>
28
+ </div>
29
+ </template>
@@ -0,0 +1 @@
1
+ Display a logo of manufacturer of a product
@@ -0,0 +1,11 @@
1
+ <script setup lang="ts">
2
+ import type { CmsElementManufacturerLogo } from "@shopware/composables";
3
+ import CmsElementImage from "./CmsElementImage.vue";
4
+
5
+ defineProps<{
6
+ content: CmsElementManufacturerLogo;
7
+ }>();
8
+ </script>
9
+ <template>
10
+ <CmsElementImage :content="content" />
11
+ </template>
@@ -0,0 +1 @@
1
+ Display a box for provided product
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import type { CmsElementProductBox } from "@shopware/composables";
3
+ import { computed } from "vue";
4
+
5
+ const props = defineProps<{
6
+ content: CmsElementProductBox;
7
+ }>();
8
+
9
+ const product = computed(() => props.content.data?.product || {});
10
+ </script>
11
+
12
+ <template>
13
+ <SwProductCard :product="product" />
14
+ </template>
@@ -0,0 +1 @@
1
+ Display a description and reviews for provided product
@@ -0,0 +1,109 @@
1
+ <script setup lang="ts">
2
+ import type { CmsElementProductDescriptionReviews } from "@shopware/composables";
3
+ import { useCmsTranslations } from "@shopware/composables";
4
+ import { getProductName, getTranslatedProperty } from "@shopware/helpers";
5
+ import { defu } from "defu";
6
+ import { computed, ref } from "vue";
7
+ import xss from "xss";
8
+ import { useProduct } from "#imports";
9
+
10
+ const props = defineProps<{
11
+ content: CmsElementProductDescriptionReviews;
12
+ }>();
13
+
14
+ type Translations = {
15
+ products: {
16
+ description: string;
17
+ reviews: string;
18
+ };
19
+ };
20
+
21
+ let translations: Translations = {
22
+ products: {
23
+ description: "Description",
24
+ reviews: "Reviews",
25
+ },
26
+ };
27
+ translations = defu(useCmsTranslations(), translations) as Translations;
28
+
29
+ const currentTab = ref<number>(1);
30
+ const { product } = useProduct(props.content.data?.product);
31
+
32
+ const description = computed(() =>
33
+ xss(getTranslatedProperty(product.value, "description")),
34
+ );
35
+
36
+ const toggleTabs = (tabNumber: number) => {
37
+ currentTab.value = tabNumber;
38
+ };
39
+
40
+ const reviews = computed(() => props.content.data.reviews.elements);
41
+ </script>
42
+
43
+ <template>
44
+ <div
45
+ v-if="product"
46
+ class="cms-block-product-description-reviews flex flex-wrap"
47
+ >
48
+ <div class="w-full">
49
+ <ul
50
+ class="flex flex-wrap text-sm font-medium list-none text-center text-secondary-500 border-b border-secondary-200 dark:border-secondary-500 dark:text-secondary-400"
51
+ >
52
+ <li class="mr-2 text-center">
53
+ <a
54
+ class="font-bold uppercase px-5 py-3 block leading-normal cursor-pointer"
55
+ :class="[
56
+ currentTab !== 1
57
+ ? 'text-secondary-500 bg-white'
58
+ : 'text-white bg-secondary-500',
59
+ ]"
60
+ @click="() => toggleTabs(1)"
61
+ >
62
+ <i class="fas fa-space-shuttle text-base mr-1" />
63
+ {{ translations.products.description }}
64
+ </a>
65
+ </li>
66
+ <li class="mr-2 text-center">
67
+ <a
68
+ class="font-bold uppercase px-5 py-3 block leading-normal cursor-pointer"
69
+ :class="[
70
+ currentTab !== 2
71
+ ? 'text-secondary-500 bg-white'
72
+ : 'text-white bg-secondary-500',
73
+ ]"
74
+ @click="() => toggleTabs(2)"
75
+ >
76
+ <i class="fas fa-cog text-base mr-1" />
77
+ {{ translations.products.reviews }}
78
+ </a>
79
+ </li>
80
+ </ul>
81
+ <div class="relative flex flex-col min-w-0 break-words w-full mb-6">
82
+ <div class="px-4 py-5 flex-auto">
83
+ <div class="tab-content tab-space">
84
+ <div
85
+ :class="[
86
+ 'cms-block-product-description-reviews__description',
87
+ currentTab !== 1 ? 'hidden' : 'block',
88
+ ]"
89
+ >
90
+ <p class="text-xl font-bold mt-3">
91
+ {{ getProductName({ product }) }}
92
+ </p>
93
+ <!-- eslint-disable-next-line vue/no-v-html -->
94
+ <div class="mt-2" v-html="description"></div>
95
+ </div>
96
+ <div
97
+ :class="[
98
+ 'cms-block-product-description-reviews__reviews',
99
+ currentTab !== 2 ? 'hidden' : 'block',
100
+ ]"
101
+ >
102
+ <SwProductReviews :product="product" :reviews="reviews" />
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </template>
@@ -0,0 +1 @@
1
+ Display the list of products for currently active listing page