@shopware/cms-base-layer 1.5.1 → 2.0.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 (183) hide show
  1. package/README.md +330 -12
  2. package/app/app.config.ts +7 -0
  3. package/app/assets/icons/check-circle.svg +3 -0
  4. package/app/assets/icons/checkmark.svg +3 -0
  5. package/app/assets/icons/chevron.svg +3 -0
  6. package/app/assets/icons/exclamation-circle.svg +3 -0
  7. package/app/assets/icons/star-empty.svg +3 -0
  8. package/app/assets/icons/star-filled.svg +3 -0
  9. package/app/assets/icons/user.svg +1 -0
  10. package/app/components/SwCategoryNavigation.vue +76 -0
  11. package/app/components/SwCategoryNavigationLink.vue +128 -0
  12. package/{components → app/components}/SwContactForm.vue +27 -27
  13. package/app/components/SwFilterChips.vue +144 -0
  14. package/app/components/SwListingProductPrice.vue +89 -0
  15. package/{components → app/components}/SwNewsletterForm.vue +45 -34
  16. package/{components → app/components}/SwPagination.vue +3 -5
  17. package/{components → app/components}/SwProductAddToCart.vue +22 -27
  18. package/app/components/SwProductCard.vue +170 -0
  19. package/app/components/SwProductCardDetails.vue +57 -0
  20. package/app/components/SwProductCardImage.vue +87 -0
  21. package/app/components/SwProductCardSkeleton.vue +33 -0
  22. package/app/components/SwProductListingFilter.vue +64 -0
  23. package/app/components/SwProductListingFilters.vue +308 -0
  24. package/{components → app/components}/SwProductReviews.vue +28 -13
  25. package/app/components/SwProductReviewsForm.vue +292 -0
  26. package/app/components/SwQuantitySelect.vue +106 -0
  27. package/{components → app/components}/SwSlider.vue +4 -4
  28. package/app/components/SwSortDropdown.vue +83 -0
  29. package/app/components/SwStockInfo.vue +44 -0
  30. package/{components → app/components}/SwVariantConfigurator.vue +1 -1
  31. package/app/components/listing-filters/SwFilterPrice.vue +214 -0
  32. package/app/components/listing-filters/SwFilterProperties.vue +113 -0
  33. package/app/components/listing-filters/SwFilterRating.vue +90 -0
  34. package/app/components/listing-filters/SwFilterShippingFree.vue +107 -0
  35. package/{components → app/components}/public/cms/CmsPage.vue +19 -4
  36. package/{components → app/components}/public/cms/block/CmsBlockGalleryBuybox.vue +5 -5
  37. package/{components → app/components}/public/cms/block/CmsBlockImageBubbleRow.vue +5 -5
  38. package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +41 -0
  39. package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +42 -0
  40. package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +37 -0
  41. package/{components → app/components}/public/cms/block/CmsBlockImageSimpleGrid.vue +11 -5
  42. package/{components → app/components}/public/cms/block/CmsBlockImageText.vue +7 -3
  43. package/{components → app/components}/public/cms/block/CmsBlockImageTextBubble.vue +13 -16
  44. package/{components → app/components}/public/cms/block/CmsBlockImageTextCover.vue +7 -9
  45. package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +88 -0
  46. package/app/components/public/cms/block/CmsBlockImageTextRow.vue +53 -0
  47. package/{components → app/components}/public/cms/block/CmsBlockImageThreeColumn.vue +10 -4
  48. package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +37 -0
  49. package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +37 -0
  50. package/{components → app/components}/public/cms/block/CmsBlockProductHeading.vue +1 -1
  51. package/{components → app/components}/public/cms/block/CmsBlockProductThreeColumn.vue +10 -4
  52. package/{components → app/components}/public/cms/block/CmsBlockSidebarFilter.vue +3 -1
  53. package/app/components/public/cms/block/CmsBlockTextOnImage.vue +30 -0
  54. package/app/components/public/cms/element/CmsElementBuyBox.vue +145 -0
  55. package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +53 -0
  56. package/{components → app/components}/public/cms/element/CmsElementCrossSelling.vue +3 -3
  57. package/{components → app/components}/public/cms/element/CmsElementImage.vue +52 -13
  58. package/app/components/public/cms/element/CmsElementImageGallery.vue +158 -0
  59. package/{components → app/components}/public/cms/element/CmsElementImageSlider.vue +2 -2
  60. package/{components → app/components}/public/cms/element/CmsElementProductBox.vue +2 -1
  61. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +217 -0
  62. package/{components → app/components}/public/cms/element/CmsElementProductListing.vue +23 -94
  63. package/app/components/public/cms/element/CmsElementProductName.vue +11 -0
  64. package/{components → app/components}/public/cms/element/CmsElementProductSlider.vue +4 -4
  65. package/{components → app/components}/public/cms/element/CmsElementText.vue +8 -2
  66. package/app/components/public/cms/element/SwProductListingPagination.vue +70 -0
  67. package/{components → app/components}/public/cms/section/CmsSectionDefault.vue +1 -1
  68. package/app/components/public/cms/section/CmsSectionSidebar.vue +36 -0
  69. package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +28 -0
  70. package/app/components/ui/BaseButton.vue +99 -0
  71. package/app/components/ui/BaseIcon.vue +15 -0
  72. package/app/components/ui/Checkbox.vue +49 -0
  73. package/app/components/ui/CheckmarkIcon.vue +23 -0
  74. package/app/components/ui/ChevronIcon.vue +37 -0
  75. package/app/components/ui/ExclamationIcon.vue +11 -0
  76. package/app/components/ui/IconButton.vue +32 -0
  77. package/app/components/ui/RadioButton.vue +26 -0
  78. package/app/components/ui/StarIcon.vue +18 -0
  79. package/app/components/ui/SwitchButton.vue +100 -0
  80. package/app/components/ui/UserIcon.vue +11 -0
  81. package/app/components/ui/WishlistIcon.vue +20 -0
  82. package/app/composables/useImagePlaceholder.ts +27 -0
  83. package/{helpers → app/helpers}/clientOnly.ts +5 -0
  84. package/app/providers/shopware.test.ts +213 -0
  85. package/app/providers/shopware.ts +107 -0
  86. package/dist/index.d.mts +3 -3
  87. package/dist/index.d.ts +3 -3
  88. package/dist/index.mjs +2 -2
  89. package/index.d.ts +12 -0
  90. package/nuxt.config.ts +80 -6
  91. package/package.json +29 -21
  92. package/uno.config.ts +83 -0
  93. package/components/SwCategoryNavigation.vue +0 -44
  94. package/components/SwCategoryNavigationLink.vue +0 -57
  95. package/components/SwListingProductPrice.vue +0 -89
  96. package/components/SwProductCard.vue +0 -286
  97. package/components/SwProductListingFilter.vue +0 -42
  98. package/components/SwProductListingFilters.vue +0 -292
  99. package/components/listing-filters/SwFilterPrice.vue +0 -160
  100. package/components/listing-filters/SwFilterProperties.vue +0 -123
  101. package/components/listing-filters/SwFilterRating.vue +0 -101
  102. package/components/listing-filters/SwFilterShippingFree.vue +0 -104
  103. package/components/public/cms/block/CmsBlockImageFourColumn.vue +0 -29
  104. package/components/public/cms/block/CmsBlockImageHighlightRow.vue +0 -27
  105. package/components/public/cms/block/CmsBlockImageTextGallery.vue +0 -85
  106. package/components/public/cms/block/CmsBlockImageTextRow.vue +0 -43
  107. package/components/public/cms/block/CmsBlockImageThreeCover.vue +0 -27
  108. package/components/public/cms/block/CmsBlockImageTwoColumn.vue +0 -25
  109. package/components/public/cms/block/CmsBlockTextOnImage.vue +0 -20
  110. package/components/public/cms/element/CmsElementBuyBox.vue +0 -190
  111. package/components/public/cms/element/CmsElementCategoryNavigation.vue +0 -167
  112. package/components/public/cms/element/CmsElementImageGallery.vue +0 -249
  113. package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +0 -123
  114. package/components/public/cms/element/CmsElementProductName.vue +0 -10
  115. package/components/public/cms/section/CmsSectionSidebar.vue +0 -41
  116. package/components/public/cms/skeleton/ProductCardSkeleton.vue +0 -44
  117. /package/{components → app/components}/SwMedia3D.vue +0 -0
  118. /package/{components → app/components}/SwProductGallery.vue +0 -0
  119. /package/{components → app/components}/SwProductPrice.vue +0 -0
  120. /package/{components → app/components}/SwProductUnits.vue +0 -0
  121. /package/{components → app/components}/SwSharedPrice.vue +0 -0
  122. /package/{components → app/components}/public/cms/CmsGenericBlock.md +0 -0
  123. /package/{components → app/components}/public/cms/CmsGenericBlock.vue +0 -0
  124. /package/{components → app/components}/public/cms/CmsGenericElement.md +0 -0
  125. /package/{components → app/components}/public/cms/CmsGenericElement.vue +0 -0
  126. /package/{components → app/components}/public/cms/CmsNoComponent.vue +0 -0
  127. /package/{components → app/components}/public/cms/CmsPage.md +0 -0
  128. /package/{components → app/components}/public/cms/block/CmsBlockCategoryNavigation.vue +0 -0
  129. /package/{components → app/components}/public/cms/block/CmsBlockCenterText.vue +0 -0
  130. /package/{components → app/components}/public/cms/block/CmsBlockCrossSelling.vue +0 -0
  131. /package/{components → app/components}/public/cms/block/CmsBlockCustomForm.vue +0 -0
  132. /package/{components → app/components}/public/cms/block/CmsBlockDefault.vue +0 -0
  133. /package/{components → app/components}/public/cms/block/CmsBlockForm.vue +0 -0
  134. /package/{components → app/components}/public/cms/block/CmsBlockHtml.vue +0 -0
  135. /package/{components → app/components}/public/cms/block/CmsBlockImage.vue +0 -0
  136. /package/{components → app/components}/public/cms/block/CmsBlockImageCover.vue +0 -0
  137. /package/{components → app/components}/public/cms/block/CmsBlockImageGallery.vue +0 -0
  138. /package/{components → app/components}/public/cms/block/CmsBlockImageSlider.vue +0 -0
  139. /package/{components → app/components}/public/cms/block/CmsBlockProductDescriptionReviews.vue +0 -0
  140. /package/{components → app/components}/public/cms/block/CmsBlockProductListing.vue +0 -0
  141. /package/{components → app/components}/public/cms/block/CmsBlockProductSlider.vue +0 -0
  142. /package/{components → app/components}/public/cms/block/CmsBlockText.vue +0 -0
  143. /package/{components → app/components}/public/cms/block/CmsBlockTextHero.vue +0 -0
  144. /package/{components → app/components}/public/cms/block/CmsBlockTextTeaser.vue +0 -0
  145. /package/{components → app/components}/public/cms/block/CmsBlockTextTeaserSection.vue +0 -0
  146. /package/{components → app/components}/public/cms/block/CmsBlockTextThreeColumn.vue +0 -0
  147. /package/{components → app/components}/public/cms/block/CmsBlockTextTwoColumn.vue +0 -0
  148. /package/{components → app/components}/public/cms/block/CmsBlockVimeoVideo.vue +0 -0
  149. /package/{components → app/components}/public/cms/block/CmsBlockYoutubeVideo.vue +0 -0
  150. /package/{components → app/components}/public/cms/element/CmsElementBuyBox.md +0 -0
  151. /package/{components → app/components}/public/cms/element/CmsElementCategoryNavigation.md +0 -0
  152. /package/{components → app/components}/public/cms/element/CmsElementCrossSelling.md +0 -0
  153. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.md +0 -0
  154. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.vue +0 -0
  155. /package/{components → app/components}/public/cms/element/CmsElementForm.md +0 -0
  156. /package/{components → app/components}/public/cms/element/CmsElementForm.vue +0 -0
  157. /package/{components → app/components}/public/cms/element/CmsElementHtml.vue +0 -0
  158. /package/{components → app/components}/public/cms/element/CmsElementImage.md +0 -0
  159. /package/{components → app/components}/public/cms/element/CmsElementImageGallery.md +0 -0
  160. /package/{components → app/components}/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +0 -0
  161. /package/{components → app/components}/public/cms/element/CmsElementImageSlider.md +0 -0
  162. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.md +0 -0
  163. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.vue +0 -0
  164. /package/{components → app/components}/public/cms/element/CmsElementProductBox.md +0 -0
  165. /package/{components → app/components}/public/cms/element/CmsElementProductDescriptionReviews.md +0 -0
  166. /package/{components → app/components}/public/cms/element/CmsElementProductListing.md +0 -0
  167. /package/{components → app/components}/public/cms/element/CmsElementProductName.md +0 -0
  168. /package/{components → app/components}/public/cms/element/CmsElementProductSlider.md +0 -0
  169. /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.md +0 -0
  170. /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.vue +0 -0
  171. /package/{components → app/components}/public/cms/element/CmsElementText.md +0 -0
  172. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.md +0 -0
  173. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.vue +0 -0
  174. /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.md +0 -0
  175. /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.vue +0 -0
  176. /package/{components → app/components}/public/cms/section/CmsSectionDefault.md +0 -0
  177. /package/{components → app/components}/public/cms/section/CmsSectionSidebar.md +0 -0
  178. /package/{helpers → app/helpers}/html-to-vue/ast.ts +0 -0
  179. /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.test.ts +0 -0
  180. /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.ts +0 -0
  181. /package/{helpers → app/helpers}/html-to-vue/renderToHtml.ts +0 -0
  182. /package/{helpers → app/helpers}/html-to-vue/renderer.ts +0 -0
  183. /package/{helpers → app/helpers}/media/isSpatial.ts +0 -0
@@ -1,160 +0,0 @@
1
- <script
2
- setup
3
- lang="ts"
4
- generic="
5
- ListingFilter extends {
6
- code: string;
7
- min?: number;
8
- max?: number;
9
- label: string;
10
- }
11
- "
12
- >
13
- import { useCmsTranslations } from "@shopware/composables";
14
- import { onClickOutside, useDebounceFn } from "@vueuse/core";
15
- import { defu } from "defu";
16
- import { onMounted, reactive, ref, watch } from "vue";
17
- import type { Schemas } from "#shopware";
18
-
19
- const emits =
20
- defineEmits<
21
- (e: "select-value", value: { code: string; value: unknown }) => void
22
- >();
23
-
24
- const props = defineProps<{
25
- filter: ListingFilter;
26
- selectedFilters: Schemas["ProductListingResult"]["currentFilters"];
27
- }>();
28
-
29
- type Translations = {
30
- listing: {
31
- min: string;
32
- max: string;
33
- };
34
- };
35
- let translations: Translations = {
36
- listing: {
37
- min: "Min",
38
- max: "Max",
39
- },
40
- };
41
- translations = defu(useCmsTranslations(), translations) as Translations;
42
-
43
- const prices = reactive<{ min: number; max: number }>({
44
- min: 0,
45
- max: 0,
46
- });
47
-
48
- onMounted(() => {
49
- prices.min = Math.floor(
50
- props.selectedFilters.price.min ?? props.filter?.min ?? 0,
51
- );
52
- prices.max = Math.floor(
53
- props.selectedFilters.price.max ?? props.filter?.max ?? 0,
54
- );
55
- });
56
-
57
- const isFilterVisible = ref<boolean>(false);
58
- const toggle = () => {
59
- isFilterVisible.value = !isFilterVisible.value;
60
- };
61
-
62
- const dropdownElement = ref(null);
63
- onClickOutside(dropdownElement, () => {
64
- isFilterVisible.value = false;
65
- });
66
-
67
- function onMinPriceChange(newPrice: number, oldPrice: number) {
68
- if (newPrice === oldPrice || oldPrice === 0) return;
69
- emits("select-value", {
70
- code: "min-price",
71
- value: newPrice,
72
- });
73
- }
74
- const debounceMinPriceUpdate = useDebounceFn(onMinPriceChange, 500);
75
- watch(() => prices.min, debounceMinPriceUpdate);
76
-
77
- function onMaxPriceChange(newPrice: number, oldPrice: number) {
78
- if (newPrice === oldPrice || oldPrice === 0) return;
79
- emits("select-value", {
80
- code: "max-price",
81
- value: newPrice,
82
- });
83
- }
84
- const debounceMaxPriceUpdate = useDebounceFn(onMaxPriceChange, 500);
85
- watch(() => prices.max, debounceMaxPriceUpdate);
86
- </script>
87
-
88
- <template>
89
- <div class="border-b border-gray-200 py-6 px-5">
90
- <h3 class="-my-3 flow-root">
91
- <button
92
- type="button"
93
- class="flex w-full items-center justify-between bg-white py-2 text-base text-gray-400 hover:text-gray-500"
94
- @click="toggle"
95
- >
96
- <span class="font-medium text-gray-900 text-left">{{
97
- props.filter.label
98
- }}</span>
99
- <span class="ml-6 flex items-center">
100
- <i
101
- :class="[
102
- !isFilterVisible
103
- ? 'i-carbon-chevron-down'
104
- : 'i-carbon-chevron-up',
105
- ]"
106
- />
107
- </span>
108
- </button>
109
- </h3>
110
-
111
- <transition name="fade" mode="out-in">
112
- <div v-show="isFilterVisible" class="space-y-6 mt-5">
113
- <div class="mt-2 flex">
114
- <div class="w-1/2 flex rounded-md mr-4">
115
- <span
116
- class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm"
117
- >
118
- {{ translations.listing.min }}
119
- </span>
120
- <input
121
- id="min-price"
122
- v-model="prices.min"
123
- step="1"
124
- type="number"
125
- name="min-price"
126
- class="pl-2 focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border border-gray-300"
127
- :placeholder="prices.min?.toString()"
128
- />
129
- </div>
130
- <div class="w-1/2 flex rounded-md">
131
- <span
132
- class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm"
133
- >
134
- {{ translations.listing.max }}
135
- </span>
136
- <input
137
- id="max-price"
138
- v-model="prices.max"
139
- type="number"
140
- name="max-price"
141
- class="pl-2 focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border border-gray-300"
142
- :placeholder="prices.max?.toString()"
143
- />
144
- </div>
145
- </div>
146
- </div>
147
- </transition>
148
- </div>
149
- </template>
150
- <style scoped>
151
- .fade-enter-active,
152
- .fade-leave-active {
153
- transition: all 0.2s ease;
154
- }
155
-
156
- .fade-enter-from,
157
- .fade-leave-to {
158
- opacity: 0;
159
- }
160
- </style>
@@ -1,123 +0,0 @@
1
- <script
2
- setup
3
- lang="ts"
4
- generic="
5
- ListingFilter extends {
6
- code: string;
7
- label: string;
8
- name: string;
9
- options: Array<Schemas['PropertyGroupOption']>;
10
- entities: Array<Schemas['ProductManufacturer']>;
11
- }
12
- "
13
- >
14
- import { getTranslatedProperty } from "@shopware/helpers";
15
- import { inject, ref } from "vue";
16
- import type { Schemas } from "#shopware";
17
-
18
- const props = defineProps<{
19
- filter: ListingFilter;
20
- }>();
21
-
22
- const emits =
23
- defineEmits<
24
- (e: "select-value", value: { code: string; value: unknown }) => void
25
- >();
26
- const selectedOptionIds = inject<string[]>("selectedOptionIds");
27
- const isFilterVisible = ref<boolean>(false);
28
- const toggle = () => {
29
- isFilterVisible.value = !isFilterVisible.value;
30
- };
31
- </script>
32
-
33
- <template>
34
- <div class="border-b border-gray-200 py-6 px-5">
35
- <h2 class="-my-3 flow-root">
36
- <button
37
- type="button"
38
- class="flex w-full items-center justify-between bg-white py-2 text-base text-gray-400 hover:text-gray-500"
39
- @click="toggle"
40
- >
41
- <span class="font-medium text-gray-900 text-left">{{
42
- props.filter.label
43
- }}</span>
44
- <span class="ml-6 flex items-center">
45
- <i
46
- :class="[
47
- !isFilterVisible
48
- ? 'i-carbon-chevron-down'
49
- : 'i-carbon-chevron-up',
50
- ]"
51
- />
52
- </span>
53
- </button>
54
- </h2>
55
- <transition name="fade" mode="out-in">
56
- <div v-show="isFilterVisible" :id="props.filter.code" class="pt-6">
57
- <fieldset class="space-y-4">
58
- <legend class="sr-only">{{ props.filter.name }}</legend>
59
- <div
60
- v-for="option in props.filter.options || props.filter.entities"
61
- :key="`${option.id}-${selectedOptionIds?.includes(option.id)}`"
62
- class="flex items-center"
63
- >
64
- <input
65
- :id="`filter-mobile-${props.filter.code}-${option.id}`"
66
- :checked="selectedOptionIds?.includes(option.id)"
67
- :name="props.filter.name"
68
- :value="option.name"
69
- :aria-label="`${option.name} filter`"
70
- type="checkbox"
71
- class="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500"
72
- @change="
73
- emits('select-value', {
74
- code: props.filter.code,
75
- value: option.id,
76
- })
77
- "
78
- />
79
-
80
- <div v-if="option.media?.url">
81
- <img
82
- loading="lazy"
83
- class="ml-2 h-4 w-4"
84
- :src="option.media.url"
85
- :alt="option.media.translated.alt || ''"
86
- :class="{
87
- 'border-blue border-2': selectedOptionIds?.includes(
88
- option.id,
89
- ),
90
- }"
91
- />
92
- </div>
93
- <div
94
- v-else-if="option.colorHexCode"
95
- class="ml-2 h-4 w-4"
96
- :style="`background-color: ${option.colorHexCode}`"
97
- :class="{
98
- 'border-blue border-2': selectedOptionIds?.includes(option.id),
99
- }"
100
- />
101
- <label
102
- :for="`filter-mobile-${props.filter.code}-${option.id}`"
103
- class="ml-3 text-gray-600"
104
- >
105
- {{ getTranslatedProperty(option, "name") }}
106
- </label>
107
- </div>
108
- </fieldset>
109
- </div>
110
- </transition>
111
- </div>
112
- </template>
113
- <style scoped>
114
- .fade-enter-active,
115
- .fade-leave-active {
116
- transition: all 0.2s ease;
117
- }
118
-
119
- .fade-enter-from,
120
- .fade-leave-to {
121
- opacity: 0;
122
- }
123
- </style>
@@ -1,101 +0,0 @@
1
- <script
2
- setup
3
- lang="ts"
4
- generic="
5
- ListingFilter extends {
6
- code: string;
7
- label: string;
8
- }
9
- "
10
- >
11
- import { computed, ref } from "vue";
12
- import type { Schemas } from "#shopware";
13
-
14
- const emits =
15
- defineEmits<
16
- (e: "select-value", value: { code: string; value: unknown }) => void
17
- >();
18
-
19
- const props = defineProps<{
20
- filter: ListingFilter;
21
- selectedFilters: Schemas["ProductListingResult"]["currentFilters"];
22
- }>();
23
- const isHoverActive = ref(false);
24
- const hoveredIndex = ref(0);
25
- const displayedScore = computed(() =>
26
- isHoverActive.value ? hoveredIndex.value : props.selectedFilters?.rating || 0,
27
- );
28
-
29
- const hoverRating = (key: number) => {
30
- hoveredIndex.value = key;
31
- isHoverActive.value = true;
32
- };
33
- const onChangeRating = () => {
34
- const newValue =
35
- props.selectedFilters?.rating !== hoveredIndex.value
36
- ? hoveredIndex.value
37
- : undefined;
38
- emits("select-value", { code: props.filter?.code, value: newValue });
39
- };
40
-
41
- const isFilterVisible = ref<boolean>(false);
42
- const toggle = () => {
43
- isFilterVisible.value = !isFilterVisible.value;
44
- };
45
- </script>
46
-
47
- <template>
48
- <div class="border-b border-gray-200 py-6 px-5">
49
- <h3 class="-my-3 flow-root">
50
- <button
51
- type="button"
52
- class="flex w-full items-center justify-between bg-white py-2 text-base text-gray-400 hover:text-gray-500"
53
- @click="toggle"
54
- >
55
- <span class="font-medium text-gray-900 text-left">{{
56
- props.filter.label
57
- }}</span>
58
- <span class="ml-6 flex items-center">
59
- <i
60
- :class="[
61
- !isFilterVisible
62
- ? 'i-carbon-chevron-down'
63
- : 'i-carbon-chevron-up',
64
- ]"
65
- />
66
- </span>
67
- </button>
68
- </h3>
69
- <transition name="fade" mode="out-in">
70
- <div v-show="isFilterVisible">
71
- <div class="space-y-6 mt-4">
72
- <div class="flex">
73
- <div
74
- v-for="i in 5"
75
- :key="i"
76
- class="h-6 w-6 c-yellow-500"
77
- :class="{
78
- 'i-carbon-star-filled': displayedScore >= i,
79
- 'i-carbon-star': displayedScore < i,
80
- }"
81
- @mouseleave="isHoverActive = false"
82
- @click="onChangeRating()"
83
- @mouseover="hoverRating(i)"
84
- />
85
- </div>
86
- </div>
87
- </div>
88
- </transition>
89
- </div>
90
- </template>
91
- <style scoped>
92
- .fade-enter-active,
93
- .fade-leave-active {
94
- transition: all 0.2s ease;
95
- }
96
-
97
- .fade-enter-from,
98
- .fade-leave-to {
99
- opacity: 0;
100
- }
101
- </style>
@@ -1,104 +0,0 @@
1
- <script
2
- setup
3
- lang="ts"
4
- generic="
5
- ListingFilter extends {
6
- id: string;
7
- code: keyof Schemas['ProductListingResult']['currentFilters'];
8
- label: string;
9
- name: string;
10
- }
11
- "
12
- >
13
- import { onClickOutside } from "@vueuse/core";
14
- import { computed, ref } from "vue";
15
- import type { Schemas } from "#shopware";
16
-
17
- const props = defineProps<{
18
- filter: ListingFilter;
19
- selectedFilters: Schemas["ProductListingResult"]["currentFilters"];
20
- }>();
21
-
22
- const emits =
23
- defineEmits<
24
- (e: "select-value", value: { code: string; value: unknown }) => void
25
- >();
26
- const currentFilterData = computed(
27
- () => !!props.selectedFilters[props.filter?.code],
28
- );
29
- const onChangeOption = (): void => {
30
- emits("select-value", {
31
- code: props.filter?.code,
32
- value: !currentFilterData.value,
33
- });
34
- };
35
-
36
- const isFilterVisible = ref<boolean>(false);
37
- const toggle = () => {
38
- isFilterVisible.value = !isFilterVisible.value;
39
- };
40
-
41
- const dropdownElement = ref(null);
42
- onClickOutside(dropdownElement, () => {
43
- isFilterVisible.value = false;
44
- });
45
- </script>
46
-
47
- <template>
48
- <div class="border-b border-gray-200 py-6 px-5">
49
- <h3 class="-my-3 flow-root">
50
- <button
51
- type="button"
52
- class="flex w-full items-center justify-between bg-white py-2 text-base text-gray-400 hover:text-gray-500"
53
- @click="toggle"
54
- >
55
- <span class="font-medium text-gray-900 text-left">{{
56
- props.filter.label
57
- }}</span>
58
- <span class="ml-6 flex items-center">
59
- <i
60
- :class="[
61
- !isFilterVisible
62
- ? 'i-carbon-chevron-down'
63
- : 'i-carbon-chevron-up',
64
- ]"
65
- />
66
- </span>
67
- </button>
68
- </h3>
69
- <transition name="fade" mode="out-in">
70
- <div v-show="isFilterVisible" id="filter-section-0" class="pt-6">
71
- <div class="space-y-4">
72
- <div class="flex items-center" @click="onChangeOption()">
73
- <input
74
- :id="`filter-mobile-${props.filter.id || props.filter.code}`"
75
- :checked="currentFilterData"
76
- :name="props.filter.name"
77
- :value="props.filter.name"
78
- type="checkbox"
79
- class="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500"
80
- />
81
-
82
- <label
83
- :for="`filter-mobile-${props.filter.id || props.filter.code}`"
84
- class="ml-3 text-gray-600"
85
- >
86
- {{ props.filter.label }}
87
- </label>
88
- </div>
89
- </div>
90
- </div>
91
- </transition>
92
- </div>
93
- </template>
94
- <style scoped>
95
- .fade-enter-active,
96
- .fade-leave-active {
97
- transition: all 0.2s ease;
98
- }
99
-
100
- .fade-enter-from,
101
- .fade-leave-to {
102
- opacity: 0;
103
- }
104
- </style>
@@ -1,29 +0,0 @@
1
- <script setup lang="ts">
2
- import type { CmsBlockImageFourColumn } from "@shopware/composables";
3
- import { useCmsBlock } from "#imports";
4
-
5
- const props = defineProps<{
6
- content: CmsBlockImageFourColumn;
7
- }>();
8
-
9
- const { getSlotContent } = useCmsBlock(props.content);
10
-
11
- const leftContent = getSlotContent("left");
12
- const rightContent = getSlotContent("right");
13
- const centerLeftContent = getSlotContent("center-left");
14
- const centerRightContent = getSlotContent("center-right");
15
- </script>
16
- <template>
17
- <div class="cms-block-image-four-column grid md:grid-cols-4 gap-10">
18
- <CmsGenericElement :content="leftContent" />
19
- <CmsGenericElement :content="centerLeftContent" />
20
- <CmsGenericElement :content="centerRightContent" />
21
- <CmsGenericElement :content="rightContent" />
22
- </div>
23
- </template>
24
-
25
- <style scoped>
26
- .cms-block-image-four-column .cms-element-image {
27
- @apply object-cover;
28
- }
29
- </style>
@@ -1,27 +0,0 @@
1
- <script setup lang="ts">
2
- import type { CmsBlockImageHighlightRow } from "@shopware/composables";
3
- import { useCmsBlock } from "#imports";
4
-
5
- const props = defineProps<{
6
- content: CmsBlockImageHighlightRow;
7
- }>();
8
-
9
- const { getSlotContent } = useCmsBlock(props.content);
10
-
11
- const leftContent = getSlotContent("left");
12
- const rightContent = getSlotContent("right");
13
- const centerContent = getSlotContent("center");
14
- </script>
15
- <template>
16
- <div class="cms-block-image-highlight-row grid md:grid-cols-3 gap-10">
17
- <CmsGenericElement :content="leftContent" />
18
- <CmsGenericElement :content="centerContent" />
19
- <CmsGenericElement :content="rightContent" />
20
- </div>
21
- </template>
22
-
23
- <style scoped>
24
- .cms-block-image-highlight-row .cms-element-image {
25
- @apply border-[12px] border-white;
26
- }
27
- </style>
@@ -1,85 +0,0 @@
1
- <script setup lang="ts">
2
- import type {
3
- CmsBlockImageTextGallery,
4
- CmsElementImage,
5
- CmsElementText,
6
- } from "@shopware/composables";
7
- import { useCmsBlock } from "#imports";
8
- import type { Schemas } from "#shopware";
9
-
10
- const props = defineProps<{
11
- content: CmsBlockImageTextGallery;
12
- }>();
13
-
14
- const { getSlotContent } = useCmsBlock(props.content);
15
-
16
- const leftTextContent = getSlotContent("left-text") as CmsElementText;
17
- const rightTextContent = getSlotContent("right-text") as CmsElementText;
18
- const centerTextContent = getSlotContent("center-text") as CmsElementText;
19
-
20
- const leftImageContent = getSlotContent("left-image") as CmsElementImage;
21
- const rightImageContent = getSlotContent("right-image") as CmsElementImage;
22
- const centerImageContent = getSlotContent("center-image") as CmsElementImage;
23
-
24
- // TODO: useRouter
25
- function onImageClick(
26
- slotContent: Schemas["CmsSlot"] & {
27
- data: {
28
- url?: string;
29
- newTab?: boolean;
30
- };
31
- },
32
- ) {
33
- if (slotContent.data?.url) {
34
- if (slotContent.data?.newTab) {
35
- window.open(slotContent.data.url);
36
- } else {
37
- window.location.href = slotContent.data.url;
38
- }
39
- }
40
- }
41
- </script>
42
- <template>
43
- <article
44
- class="cms-block-image-text-gallery"
45
- :style="{ backgroundColor: content.backgroundColor || '' }"
46
- >
47
- <div class="cms-block-image-text-gallery__container">
48
- <div class="cms-block-image-text-gallery__container__column">
49
- <CmsElementImage
50
- :content="leftImageContent"
51
- :style="{ cursor: leftImageContent.data?.url && 'pointer' }"
52
- @click="onImageClick(leftImageContent)"
53
- />
54
- <CmsElementText
55
- :content="leftTextContent"
56
- class="cms-block-imag)e-text-gallery__container__column--text"
57
- />
58
- </div>
59
- <div class="cms-block-image-text-gallery__container__column">
60
- <CmsElementImage
61
- :content="centerImageContent"
62
- :style="{
63
- cursor: centerImageContent.data?.url && 'pointer',
64
- }"
65
- @click="onImageClick(centerImageContent)"
66
- />
67
- <CmsElementText
68
- :content="centerTextContent"
69
- class="cms-block-image-text-gallery__container__column--text"
70
- />
71
- </div>
72
- <div class="cms-block-image-text-gallery__container__column">
73
- <CmsElementImage
74
- :content="rightImageContent"
75
- :style="{ cursor: rightImageContent.data?.url && 'pointer' }"
76
- @click="onImageClick(rightImageContent)"
77
- />
78
- <CmsElementText
79
- :content="rightTextContent"
80
- class="cms-block-image-text-gallery__container__column--text"
81
- />
82
- </div>
83
- </div>
84
- </article>
85
- </template>
@@ -1,43 +0,0 @@
1
- <script setup lang="ts">
2
- import type { CmsBlockImageTextRow } from "@shopware/composables";
3
- import { useCmsBlock } from "#imports";
4
-
5
- const props = defineProps<{
6
- content: CmsBlockImageTextRow;
7
- }>();
8
-
9
- const { getSlotContent } = useCmsBlock(props.content);
10
-
11
- const leftImageContent = getSlotContent("left-image");
12
- const leftTextContent = getSlotContent("left-text");
13
- const centerImageContent = getSlotContent("center-image");
14
- const centerTextContent = getSlotContent("center-text");
15
- const rightImageContent = getSlotContent("right-image");
16
- const rightTextContent = getSlotContent("right-text");
17
- </script>
18
- <template>
19
- <div class="cms-block-image-text-row grid md:grid-cols-3 gap-10">
20
- <div class="cms-block-image-text-row__column">
21
- <CmsGenericElement :content="leftImageContent" />
22
- <CmsGenericElement :content="leftTextContent" />
23
- </div>
24
- <div class="cms-block-image-text-row__column">
25
- <CmsGenericElement :content="centerImageContent" />
26
- <CmsGenericElement :content="centerTextContent" />
27
- </div>
28
- <div class="cms-block-image-text-row__column">
29
- <CmsGenericElement :content="rightImageContent" />
30
- <CmsGenericElement :content="rightTextContent" />
31
- </div>
32
- </div>
33
- </template>
34
-
35
- <style scoped>
36
- .cms-block-image-text-row .cms-element-image {
37
- @apply object-cover;
38
- }
39
-
40
- .cms-block-image-text-row .cms-block-image-text-row__column div:first-child {
41
- @apply mb-5;
42
- }
43
- </style>