@shopware/cms-base-layer 3.0.0 → 3.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 (107) hide show
  1. package/README.md +64 -58
  2. package/app/components/SwCategoryNavigation.vue +1 -0
  3. package/app/components/SwCategoryNavigationLink.vue +16 -8
  4. package/app/components/SwContactForm.vue +1 -0
  5. package/app/components/SwFilterChips.vue +1 -0
  6. package/app/components/SwListingProductPrice.vue +16 -4
  7. package/app/components/SwMedia3D.vue +1 -4
  8. package/app/components/SwNewsletterForm.vue +4 -3
  9. package/app/components/SwProductAddToCart.vue +24 -7
  10. package/app/components/SwProductCard.vue +20 -3
  11. package/app/components/SwProductCardDetails.vue +27 -9
  12. package/app/components/SwProductCardImage.vue +31 -12
  13. package/app/components/SwProductCardSkeleton.vue +37 -14
  14. package/app/components/SwProductGallery.vue +1 -0
  15. package/app/components/SwProductListingFilter.vue +5 -1
  16. package/app/components/SwProductListingFilters.vue +57 -76
  17. package/app/components/SwProductListingFiltersHorizontal.vue +40 -71
  18. package/app/components/SwProductPrice.vue +1 -0
  19. package/app/components/SwProductReviews.vue +14 -6
  20. package/app/components/SwProductReviewsForm.vue +15 -3
  21. package/app/components/SwProductUnits.vue +1 -0
  22. package/app/components/SwQuantitySelect.vue +10 -3
  23. package/app/components/SwSharedPrice.vue +1 -0
  24. package/app/components/SwSlider.vue +1 -0
  25. package/app/components/SwStockInfo.vue +12 -6
  26. package/app/components/SwVariantConfigurator.vue +4 -1
  27. package/app/components/listing-filters/SwFilterPrice.vue +79 -30
  28. package/app/components/listing-filters/SwFilterProperties.vue +40 -25
  29. package/app/components/listing-filters/SwFilterRating.vue +21 -9
  30. package/app/components/listing-filters/SwFilterShippingFree.vue +16 -8
  31. package/app/components/public/cms/CmsBlockSpatialViewer.vue +1 -0
  32. package/app/components/public/cms/CmsGenericBlock.vue +3 -1
  33. package/app/components/public/cms/CmsGenericElement.vue +2 -1
  34. package/app/components/public/cms/CmsNoComponent.vue +2 -1
  35. package/app/components/public/cms/CmsPage.md +1 -1
  36. package/app/components/public/cms/CmsPage.vue +2 -0
  37. package/app/components/public/cms/block/CmsBlockCategoryNavigation.vue +1 -0
  38. package/app/components/public/cms/block/CmsBlockCenterText.vue +3 -1
  39. package/app/components/public/cms/block/CmsBlockCrossSelling.vue +1 -0
  40. package/app/components/public/cms/block/CmsBlockCustomForm.vue +1 -0
  41. package/app/components/public/cms/block/CmsBlockForm.vue +1 -0
  42. package/app/components/public/cms/block/CmsBlockGalleryBuybox.vue +4 -1
  43. package/app/components/public/cms/block/CmsBlockImage.vue +1 -0
  44. package/app/components/public/cms/block/CmsBlockImageBubbleRow.vue +9 -2
  45. package/app/components/public/cms/block/CmsBlockImageCover.vue +1 -0
  46. package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +10 -3
  47. package/app/components/public/cms/block/CmsBlockImageGallery.vue +1 -0
  48. package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +10 -5
  49. package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +11 -3
  50. package/app/components/public/cms/block/CmsBlockImageSimpleGrid.vue +1 -0
  51. package/app/components/public/cms/block/CmsBlockImageSlider.vue +1 -0
  52. package/app/components/public/cms/block/CmsBlockImageText.vue +4 -1
  53. package/app/components/public/cms/block/CmsBlockImageTextBubble.vue +4 -1
  54. package/app/components/public/cms/block/CmsBlockImageTextCover.vue +4 -1
  55. package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +4 -12
  56. package/app/components/public/cms/block/CmsBlockImageTextRow.vue +13 -4
  57. package/app/components/public/cms/block/CmsBlockImageThreeColumn.vue +1 -0
  58. package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +11 -3
  59. package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +11 -4
  60. package/app/components/public/cms/block/CmsBlockProductDescriptionReviews.vue +1 -0
  61. package/app/components/public/cms/block/CmsBlockProductHeading.vue +3 -1
  62. package/app/components/public/cms/block/CmsBlockProductListing.vue +1 -0
  63. package/app/components/public/cms/block/CmsBlockProductThreeColumn.vue +1 -0
  64. package/app/components/public/cms/block/CmsBlockSidebarFilter.vue +1 -0
  65. package/app/components/public/cms/block/CmsBlockText.vue +1 -0
  66. package/app/components/public/cms/block/CmsBlockTextHero.vue +1 -0
  67. package/app/components/public/cms/block/CmsBlockTextOnImage.vue +2 -4
  68. package/app/components/public/cms/block/CmsBlockTextThreeColumn.vue +1 -0
  69. package/app/components/public/cms/block/CmsBlockTextTwoColumn.vue +4 -1
  70. package/app/components/public/cms/block/CmsBlockVimeoVideo.vue +1 -0
  71. package/app/components/public/cms/block/CmsBlockYoutubeVideo.vue +1 -0
  72. package/app/components/public/cms/element/CmsElementBuyBox.vue +90 -72
  73. package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +14 -3
  74. package/app/components/public/cms/element/CmsElementCrossSelling.vue +3 -1
  75. package/app/components/public/cms/element/CmsElementCustomForm.vue +1 -0
  76. package/app/components/public/cms/element/CmsElementForm.vue +1 -0
  77. package/app/components/public/cms/element/CmsElementHtml.vue +0 -1
  78. package/app/components/public/cms/element/CmsElementImage.vue +2 -1
  79. package/app/components/public/cms/element/CmsElementImageGallery.vue +6 -2
  80. package/app/components/public/cms/element/CmsElementManufacturerLogo.vue +1 -0
  81. package/app/components/public/cms/element/CmsElementProductBox.vue +1 -0
  82. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +93 -36
  83. package/app/components/public/cms/element/CmsElementProductListing.vue +16 -5
  84. package/app/components/public/cms/element/CmsElementProductSlider.vue +6 -4
  85. package/app/components/public/cms/element/CmsElementText.vue +2 -0
  86. package/app/components/public/cms/element/CmsElementVimeoVideo.vue +1 -0
  87. package/app/components/public/cms/element/CmsElementYoutubeVideo.vue +1 -0
  88. package/app/components/public/cms/element/SwProductListingPagination.vue +8 -2
  89. package/app/components/public/cms/section/CmsSectionSidebar.vue +13 -8
  90. package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +16 -5
  91. package/app/components/ui/SwitchButton.vue +53 -14
  92. package/app/components/ui/WishlistIcon.vue +8 -2
  93. package/app/composables/useLcpImagePreload.test.ts +1 -0
  94. package/app/composables/useLcpImagePreload.ts +2 -0
  95. package/app/composables/useTypedAppConfig.ts +1 -0
  96. package/app/helpers/cms/getImageSizes.test.ts +1 -0
  97. package/app/helpers/html-to-vue/ast.ts +1 -0
  98. package/app/helpers/html-to-vue/getOptionsFromNode.test.ts +1 -0
  99. package/app/helpers/html-to-vue/renderToHtml.ts +1 -0
  100. package/app/helpers/html-to-vue/renderer.ts +1 -0
  101. package/app/providers/shopware.test.ts +1 -0
  102. package/app/utils/routeQuery.test.ts +65 -0
  103. package/app/utils/routeQuery.ts +26 -0
  104. package/app/utils/useSelectedListingFilters.test.ts +82 -0
  105. package/app/utils/useSelectedListingFilters.ts +105 -0
  106. package/nuxt.config.ts +24 -1
  107. package/package.json +22 -24
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { defu } from "defu";
3
3
  import { computed, useId } from "vue";
4
+
4
5
  import { useCmsTranslations } from "#imports";
5
6
 
6
7
  type Translations = {
@@ -63,7 +64,9 @@ const sizeClasses = {
63
64
  };
64
65
  </script>
65
66
  <template>
66
- <div class="rounded outline outline-1 outline-offset-[-1px] outline-outline-outline inline-flex">
67
+ <div
68
+ class="rounded outline outline-1 outline-offset-[-1px] outline-outline-outline inline-flex"
69
+ >
67
70
  <button
68
71
  type="button"
69
72
  :class="sizeClasses[size]"
@@ -73,9 +76,13 @@ const sizeClasses = {
73
76
  >
74
77
  -
75
78
  </button>
76
- <div class="bg-white border-l border-r border-outline-outline inline-flex flex-col justify-center items-center">
79
+ <div
80
+ class="bg-white border-l border-r border-outline-outline inline-flex flex-col justify-center items-center"
81
+ >
77
82
  <!-- visually hidden label for screen readers -->
78
- <label :for="inputId" class="sr-only">{{ translations.form.quantitySelect.label }}</label>
83
+ <label :for="inputId" class="sr-only">{{
84
+ translations.form.quantitySelect.label
85
+ }}</label>
79
86
 
80
87
  <input
81
88
  :id="inputId"
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from "vue";
3
+
3
4
  import { usePrice } from "#imports";
4
5
 
5
6
  const { getFormattedPrice } = usePrice();
@@ -11,6 +11,7 @@ import {
11
11
  watch,
12
12
  } from "vue";
13
13
  import type { CSSProperties, VNode, VNodeArrayChildren } from "vue";
14
+
14
15
  import { useCmsElementConfig, useHead, useId } from "#imports";
15
16
  import type { Schemas } from "#shopware";
16
17
 
@@ -31,14 +31,20 @@ translations = defu(useCmsTranslations(), translations) as Translations;
31
31
  </script>
32
32
  <template>
33
33
  <div class="inline-flex justify-start items-center gap-2">
34
- <div class="w-2 h-2 bg-states-success rounded-full" v-if="availableStock > 0"></div>
34
+ <div
35
+ class="w-2 h-2 bg-states-success rounded-full"
36
+ v-if="availableStock > 0"
37
+ ></div>
35
38
  <div class="w-2 h-2 bg-states-error rounded-full" v-else></div>
36
- <span v-if="availableStock >= minPurchase && deliveryTime">{{ translations.product.deliveryTime }} {{
37
- deliveryTime?.name }}
39
+ <span v-if="availableStock >= minPurchase && deliveryTime"
40
+ >{{ translations.product.deliveryTime }} {{ deliveryTime?.name }}
38
41
  </span>
39
- <span v-else-if="availableStock < minPurchase && deliveryTime && restockTime">
42
+ <span
43
+ v-else-if="availableStock < minPurchase && deliveryTime && restockTime"
44
+ >
40
45
  {{ translations.product.deliveryTime }} {{ restockTime }}
41
- {{ translations.product.days }} {{ deliveryTime?.name }}</span>
46
+ {{ translations.product.days }} {{ deliveryTime?.name }}</span
47
+ >
42
48
  <span v-else>{{ translations.product.noAvailable }}</span>
43
49
  </div>
44
- </template>
50
+ </template>
@@ -4,6 +4,7 @@ import { buildUrlPrefix, getProductRoute } from "@shopware/helpers";
4
4
  import { defu } from "defu";
5
5
  import { computed, ref, unref } from "vue";
6
6
  import type { ComputedRef } from "vue";
7
+
7
8
  import { useProductConfigurator, useRouter, useUrlResolver } from "#imports";
8
9
  import type { Schemas } from "#shopware";
9
10
 
@@ -84,7 +85,9 @@ const onHandleChange = async () => {
84
85
  :key="optionGroup.id"
85
86
  class="mt-6"
86
87
  >
87
- <div class="text-sm text-gray-900 font-medium">{{ optionGroup.name }}</div>
88
+ <div class="text-sm text-gray-900 font-medium">
89
+ {{ optionGroup.name }}
90
+ </div>
88
91
  <fieldset class="mt-4 flex-1">
89
92
  <legend class="sr-only">
90
93
  {{ translations.product.chooseA }} {{ optionGroup.name }}
@@ -1,15 +1,20 @@
1
- <script setup lang="ts" generic="
1
+ <script
2
+ setup
3
+ lang="ts"
4
+ generic="
2
5
  ListingFilter extends {
3
6
  code: string;
4
7
  min?: number;
5
8
  max?: number;
6
9
  label: string;
7
10
  }
8
- ">
11
+ "
12
+ >
9
13
  import { useCmsTranslations } from "@shopware/composables";
10
14
  import { onClickOutside, useDebounceFn, useEventListener } from "@vueuse/core";
11
15
  import { defu } from "defu";
12
16
  import { onMounted, reactive, ref, watch } from "vue";
17
+
13
18
  import type { Schemas } from "#shopware";
14
19
 
15
20
  const emits =
@@ -149,15 +154,17 @@ const startDrag = (type: "min" | "max", event: MouseEvent | TouchEvent) => {
149
154
  @keydown.space.prevent="toggle"
150
155
  >
151
156
  <div class="flex-1 flex items-center gap-2.5">
152
- <div class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left">
157
+ <div
158
+ class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left"
159
+ >
153
160
  {{ filter.label }}
154
161
  </div>
155
162
  </div>
156
- <span
157
- class="flex items-center justify-center"
158
- aria-hidden="true"
159
- >
160
- <SwChevronIcon :direction="isFilterVisible ? 'up' : 'down'" :size="24" />
163
+ <span class="flex items-center justify-center" aria-hidden="true">
164
+ <SwChevronIcon
165
+ :direction="isFilterVisible ? 'up' : 'down'"
166
+ :size="24"
167
+ />
161
168
  </span>
162
169
  </div>
163
170
  </div>
@@ -165,52 +172,94 @@ const startDrag = (type: "min" | "max", event: MouseEvent | TouchEvent) => {
165
172
 
166
173
  <!-- Filter content -->
167
174
  <transition name="filter-collapse">
168
- <div v-if="isFilterVisible || displayMode === 'dropdown'" :id="filter.code"
169
- class="self-stretch flex flex-col justify-start items-start gap-2.5">
175
+ <div
176
+ v-if="isFilterVisible || displayMode === 'dropdown'"
177
+ :id="filter.code"
178
+ class="self-stretch flex flex-col justify-start items-start gap-2.5"
179
+ >
170
180
  <div class="self-stretch flex flex-col justify-start items-start gap-1">
171
- <div class="self-stretch inline-flex justify-between items-center gap-2">
181
+ <div
182
+ class="self-stretch inline-flex justify-between items-center gap-2"
183
+ >
172
184
  <div
173
- class="w-16 h-10 px-2 py-1 rounded-lg outline outline-1 outline-offset-[-1px] outline-outline-outline-variant inline-flex flex-col justify-center items-start gap-2.5">
174
- <input type="number" :placeholder="translations.listing.min" v-model.number="prices.min"
185
+ class="w-16 h-10 px-2 py-1 rounded-lg outline outline-1 outline-offset-[-1px] outline-outline-outline-variant inline-flex flex-col justify-center items-start gap-2.5"
186
+ >
187
+ <input
188
+ type="number"
189
+ :placeholder="translations.listing.min"
190
+ v-model.number="prices.min"
175
191
  class="w-full bg-transparent border-none outline-none text-surface-on-surface text-sm font-normal leading-tight"
176
- @change="emits('select-value', { code: filter.code, value: { min: prices.min, max: prices.max } })"
177
- :min="filter.min" :max="prices.max" />
192
+ @change="
193
+ emits('select-value', {
194
+ code: filter.code,
195
+ value: { min: prices.min, max: prices.max },
196
+ })
197
+ "
198
+ :min="filter.min"
199
+ :max="prices.max"
200
+ />
178
201
  </div>
179
202
  <div
180
- class="w-16 h-10 px-2 py-1 rounded-lg outline outline-1 outline-offset-[-1px] outline-outline-outline-variant inline-flex flex-col justify-center items-start gap-2.5">
181
- <input type="number" :placeholder="translations.listing.max" v-model.number="prices.max"
203
+ class="w-16 h-10 px-2 py-1 rounded-lg outline outline-1 outline-offset-[-1px] outline-outline-outline-variant inline-flex flex-col justify-center items-start gap-2.5"
204
+ >
205
+ <input
206
+ type="number"
207
+ :placeholder="translations.listing.max"
208
+ v-model.number="prices.max"
182
209
  class="w-full bg-transparent border-none outline-none text-surface-on-surface text-sm font-normal leading-tight"
183
- @change="emits('select-value', { code: filter.code, value: { min: prices.min, max: prices.max } })"
184
- :min="prices.min" :max="filter.max" />
210
+ @change="
211
+ emits('select-value', {
212
+ code: filter.code,
213
+ value: { min: prices.min, max: prices.max },
214
+ })
215
+ "
216
+ :min="prices.min"
217
+ :max="filter.max"
218
+ />
185
219
  </div>
186
220
  </div>
187
221
  <!-- Custom slider UI -->
188
- <div class="relative w-64 h-10 mt-2 mx-auto flex items-center select-none">
222
+ <div
223
+ class="relative w-64 h-10 mt-2 mx-auto flex items-center select-none"
224
+ >
189
225
  <!-- Track -->
190
226
  <div
191
- class="absolute left-0 top-1/2 -translate-y-1/2 w-full h-2 bg-surface-surface-container-highest rounded-full">
192
- </div>
227
+ class="absolute left-0 top-1/2 -translate-y-1/2 w-full h-2 bg-surface-surface-container-highest rounded-full"
228
+ ></div>
193
229
  <!-- Active range -->
194
- <div class="absolute top-1/2 -translate-y-1/2 h-2 bg-surface-surface-primary rounded-full" :style="{
195
- left: ((prices.min - (filter.min ?? 0)) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100 + '%',
196
- width: ((prices.max - prices.min) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100 + '%',
197
- }"></div>
230
+ <div
231
+ class="absolute top-1/2 -translate-y-1/2 h-2 bg-surface-surface-primary rounded-full"
232
+ :style="{
233
+ left:
234
+ ((prices.min - (filter.min ?? 0)) /
235
+ ((filter.max ?? 100) - (filter.min ?? 0))) *
236
+ 100 +
237
+ '%',
238
+ width:
239
+ ((prices.max - prices.min) /
240
+ ((filter.max ?? 100) - (filter.min ?? 0))) *
241
+ 100 +
242
+ '%',
243
+ }"
244
+ ></div>
198
245
  <!-- Min thumb -->
199
246
  <div
200
247
  class="absolute top-1/2 -translate-y-1/2 w-5 h-5 bg-brand-primary rounded-full shadow-[2px_2px_10px_0px_rgba(0,0,0,0.15)] cursor-pointer touch-none"
201
248
  :style="{
202
- left: `calc(${((prices.min - (filter.min ?? 0)) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100}% - 10px)`
249
+ left: `calc(${((prices.min - (filter.min ?? 0)) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100}% - 10px)`,
203
250
  }"
204
251
  @mousedown.prevent="startDrag('min', $event)"
205
- @touchstart.prevent="startDrag('min', $event)"></div>
252
+ @touchstart.prevent="startDrag('min', $event)"
253
+ ></div>
206
254
  <!-- Max thumb -->
207
255
  <div
208
256
  class="absolute top-1/2 -translate-y-1/2 w-5 h-5 bg-brand-primary rounded-full shadow-[2px_2px_10px_0px_rgba(0,0,0,0.15)] cursor-pointer touch-none"
209
257
  :style="{
210
- left: `calc(${((prices.max - (filter.min ?? 0)) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100}% - 10px)`
258
+ left: `calc(${((prices.max - (filter.min ?? 0)) / ((filter.max ?? 100) - (filter.min ?? 0))) * 100}% - 10px)`,
211
259
  }"
212
260
  @mousedown.prevent="startDrag('max', $event)"
213
- @touchstart.prevent="startDrag('max', $event)"></div>
261
+ @touchstart.prevent="startDrag('max', $event)"
262
+ ></div>
214
263
  </div>
215
264
  </div>
216
265
  </div>
@@ -13,6 +13,7 @@
13
13
  >
14
14
  import { getTranslatedProperty } from "@shopware/helpers";
15
15
  import { computed, ref } from "vue";
16
+
16
17
  import type { Schemas } from "#shopware";
17
18
 
18
19
  const {
@@ -75,15 +76,17 @@ const selectValue = (id: string) => {
75
76
  @keydown.space.prevent="toggle"
76
77
  >
77
78
  <div class="flex-1 flex items-center gap-2.5">
78
- <div class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left">
79
+ <div
80
+ class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left"
81
+ >
79
82
  {{ filter.label }}
80
83
  </div>
81
84
  </div>
82
- <span
83
- class="flex items-center justify-center"
84
- aria-hidden="true"
85
- >
86
- <SwChevronIcon :direction="isFilterVisible ? 'up' : 'down'" :size="24" />
85
+ <span class="flex items-center justify-center" aria-hidden="true">
86
+ <SwChevronIcon
87
+ :direction="isFilterVisible ? 'up' : 'down'"
88
+ :size="24"
89
+ />
87
90
  </span>
88
91
  </div>
89
92
  </div>
@@ -91,28 +94,40 @@ const selectValue = (id: string) => {
91
94
 
92
95
  <!-- Filter content -->
93
96
  <transition name="filter-collapse">
94
- <div v-if="isFilterVisible || displayMode === 'dropdown'" :id="filter.code" class="self-stretch flex flex-col justify-start items-start gap-4">
95
- <fieldset class="self-stretch flex flex-col justify-start items-start gap-4">
96
- <legend class="sr-only">{{ filter.name }}</legend>
97
- <label
98
- v-for="option in filter.options || filter.entities"
99
- :key="`${option.id}-${isChecked(option.id)}`"
100
- class="self-stretch inline-flex justify-start items-start gap-2 cursor-pointer"
97
+ <div
98
+ v-if="isFilterVisible || displayMode === 'dropdown'"
99
+ :id="filter.code"
100
+ class="self-stretch flex flex-col justify-start items-start gap-4"
101
+ >
102
+ <fieldset
103
+ class="self-stretch flex flex-col justify-start items-start gap-4"
101
104
  >
102
- <div class="w-4 self-stretch pt-[3px] flex justify-start items-start gap-2.5">
103
- <SwCheckbox
104
- :model-value="isChecked(option.id)"
105
- @update:model-value="() => selectValue(option.id)"
106
- />
107
- </div>
108
- <div class="flex-1 inline-flex flex-col justify-start items-start gap-0.5">
109
- <div class="inline-flex justify-start items-center gap-1">
110
- <div class="flex-1 text-surface-on-surface text-base font-normal leading-normal">
111
- {{ getTranslatedProperty(option, 'name') }}
105
+ <legend class="sr-only">{{ filter.name }}</legend>
106
+ <label
107
+ v-for="option in filter.options || filter.entities"
108
+ :key="`${option.id}-${isChecked(option.id)}`"
109
+ class="self-stretch inline-flex justify-start items-start gap-2 cursor-pointer"
110
+ >
111
+ <div
112
+ class="w-4 self-stretch pt-[3px] flex justify-start items-start gap-2.5"
113
+ >
114
+ <SwCheckbox
115
+ :model-value="isChecked(option.id)"
116
+ @update:model-value="() => selectValue(option.id)"
117
+ />
118
+ </div>
119
+ <div
120
+ class="flex-1 inline-flex flex-col justify-start items-start gap-0.5"
121
+ >
122
+ <div class="inline-flex justify-start items-center gap-1">
123
+ <div
124
+ class="flex-1 text-surface-on-surface text-base font-normal leading-normal"
125
+ >
126
+ {{ getTranslatedProperty(option, "name") }}
127
+ </div>
112
128
  </div>
113
129
  </div>
114
- </div>
115
- </label>
130
+ </label>
116
131
  </fieldset>
117
132
  </div>
118
133
  </transition>
@@ -9,6 +9,7 @@
9
9
  "
10
10
  >
11
11
  import { computed, ref } from "vue";
12
+
12
13
  import type { Schemas } from "#shopware";
13
14
 
14
15
  const emits =
@@ -65,15 +66,17 @@ const toggle = () => {
65
66
  @keydown.space.prevent="toggle"
66
67
  >
67
68
  <div class="flex-1 flex items-center gap-2.5">
68
- <div class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left">
69
+ <div
70
+ class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left"
71
+ >
69
72
  {{ filter.label }}
70
73
  </div>
71
74
  </div>
72
- <span
73
- class="flex items-center justify-center"
74
- aria-hidden="true"
75
- >
76
- <SwChevronIcon :direction="isFilterVisible ? 'up' : 'down'" :size="24" />
75
+ <span class="flex items-center justify-center" aria-hidden="true">
76
+ <SwChevronIcon
77
+ :direction="isFilterVisible ? 'up' : 'down'"
78
+ :size="24"
79
+ />
77
80
  </span>
78
81
  </div>
79
82
  </div>
@@ -81,14 +84,23 @@ const toggle = () => {
81
84
 
82
85
  <!-- Filter content -->
83
86
  <transition name="filter-collapse">
84
- <div v-if="isFilterVisible || displayMode === 'dropdown'" class="self-stretch flex flex-col justify-start items-start gap-4">
87
+ <div
88
+ v-if="isFilterVisible || displayMode === 'dropdown'"
89
+ class="self-stretch flex flex-col justify-start items-start gap-4"
90
+ >
85
91
  <div class="flex flex-row items-center gap-2 mt-2">
86
92
  <div
87
93
  v-for="i in 5"
88
94
  :key="i"
89
- :class="['h-6 w-6 cursor-pointer', displayedScore >= i ? 'i-carbon-star-filled' : 'i-carbon-star']"
95
+ :class="[
96
+ 'h-6 w-6 cursor-pointer',
97
+ displayedScore >= i ? 'i-carbon-star-filled' : 'i-carbon-star',
98
+ ]"
90
99
  @mouseleave="isHoverActive = false"
91
- @click="hoverRating(i); onChangeRating()"
100
+ @click="
101
+ hoverRating(i);
102
+ onChangeRating();
103
+ "
92
104
  @mouseover="hoverRating(i)"
93
105
  :aria-label="`${i} star${i !== 1 ? 's' : ''}`"
94
106
  />
@@ -14,6 +14,7 @@ import { useCmsTranslations } from "@shopware/composables";
14
14
  import { onClickOutside } from "@vueuse/core";
15
15
  import { defu } from "defu";
16
16
  import { computed, ref } from "vue";
17
+
17
18
  import type { Schemas } from "#shopware";
18
19
 
19
20
  const {
@@ -77,15 +78,17 @@ const handleRadioUpdate = (val: string | null | boolean | undefined) => {
77
78
  @keydown.space.prevent="toggle"
78
79
  >
79
80
  <div class="flex-1 flex items-center gap-2.5">
80
- <div class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left">
81
+ <div
82
+ class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left"
83
+ >
81
84
  {{ filter.label }}
82
85
  </div>
83
86
  </div>
84
- <span
85
- class="flex items-center justify-center"
86
- aria-hidden="true"
87
- >
88
- <SwChevronIcon :direction="isFilterVisible ? 'up' : 'down'" :size="24" />
87
+ <span class="flex items-center justify-center" aria-hidden="true">
88
+ <SwChevronIcon
89
+ :direction="isFilterVisible ? 'up' : 'down'"
90
+ :size="24"
91
+ />
89
92
  </span>
90
93
  </div>
91
94
  </div>
@@ -93,9 +96,14 @@ const handleRadioUpdate = (val: string | null | boolean | undefined) => {
93
96
 
94
97
  <!-- Filter content -->
95
98
  <transition name="filter-collapse">
96
- <div v-if="isFilterVisible || displayMode === 'dropdown'" class="self-stretch">
99
+ <div
100
+ v-if="isFilterVisible || displayMode === 'dropdown'"
101
+ class="self-stretch"
102
+ >
97
103
  <div class="pt-6 space-y-4">
98
- <div class="self-stretch inline-flex justify-start items-start gap-2 w-full">
104
+ <div
105
+ class="self-stretch inline-flex justify-start items-start gap-2 w-full"
106
+ >
99
107
  <div class="flex-1 pt-[3px]">
100
108
  <SwSwitchButton
101
109
  :model-value="currentFilterData"
@@ -1,5 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, defineAsyncComponent } from "vue";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
  import type { Schemas } from "#shopware";
5
6
 
@@ -5,7 +5,9 @@ import {
5
5
  getCmsLayoutConfiguration,
6
6
  } from "@shopware/helpers";
7
7
  import { h, provide, resolveComponent } from "vue";
8
+
8
9
  import type { Schemas } from "#shopware";
10
+
9
11
  import { useTypedAppConfig } from "../../../composables/useTypedAppConfig";
10
12
  import { getImageSizes } from "../../../helpers/cms/getImageSizes";
11
13
 
@@ -69,7 +71,7 @@ const DynamicRender = () => {
69
71
  }
70
72
  if (import.meta.dev) {
71
73
  console.warn(
72
- `[CMS] Block type "${componentName}" is not implemented.\n → Create a component named "${componentNameToResolve}.vue" to render it.\n 📖 Docs: https://frontends.shopware.com/getting-started/cms/create-blocks`,
74
+ `[CMS] Block type "${componentName}" is not implemented.\n → Create a component named "${componentNameToResolve}.vue" to render it.\n 📖 Docs: https://developer.shopware.com/frontends/guides/cms/create-blocks`,
73
75
  );
74
76
  return h(resolveComponent("CmsNoComponent"), { content: props.content });
75
77
  }
@@ -2,6 +2,7 @@
2
2
  import { resolveCmsComponent } from "@shopware/composables";
3
3
  import { getCmsLayoutConfiguration } from "@shopware/helpers";
4
4
  import { h, resolveComponent } from "vue";
5
+
5
6
  import type { Schemas } from "#shopware";
6
7
 
7
8
  const props = defineProps<{
@@ -30,7 +31,7 @@ const DynamicRender = () => {
30
31
  }
31
32
  if (import.meta.dev) {
32
33
  console.warn(
33
- `[CMS] Element type "${componentName}" is not implemented.\n → Create a component named "${componentNameToResolve}.vue" to render it.\n 📖 Docs: https://frontends.shopware.com/getting-started/cms/create-elements`,
34
+ `[CMS] Element type "${componentName}" is not implemented.\n → Create a component named "${componentNameToResolve}.vue" to render it.\n 📖 Docs: https://developer.shopware.com/frontends/guides/cms/create-elements`,
34
35
  );
35
36
  return h(resolveComponent("CmsNoComponent"), { content: props.content });
36
37
  }
@@ -2,6 +2,7 @@
2
2
  import { refAutoReset } from "@vueuse/core";
3
3
  import { pascalCase } from "scule";
4
4
  import { computed } from "vue";
5
+
5
6
  import type { Schemas } from "#shopware";
6
7
 
7
8
  const props = defineProps<{
@@ -27,7 +28,7 @@ const docsUrl = computed(() => {
27
28
  component: expectedComponentName.value,
28
29
  type: elementType.value.toLowerCase(),
29
30
  });
30
- return `https://frontends.shopware.com/getting-started/cms/missing-component?${params}`;
31
+ return `https://developer.shopware.com/frontends/guides/cms/missing-component?${params}`;
31
32
  });
32
33
 
33
34
  const aiPrompt = computed(() => {
@@ -15,7 +15,7 @@ export default defineAppConfig({
15
15
  });
16
16
  ```
17
17
 
18
- See the [cms-base-layer README](../../../../../../README.md#%EF%B8%8F-background-image-optimization) for full details.
18
+ See the [cms-base-layer README](https://github.com/shopware/frontends/tree/main/packages/cms-base-layer#%EF%B8%8F-background-image-optimization) for full details.
19
19
 
20
20
  ### Example usage
21
21
 
@@ -6,8 +6,10 @@ import {
6
6
  } from "@shopware/helpers";
7
7
  import { pascalCase } from "scule";
8
8
  import { computed, h, resolveComponent, watchEffect } from "vue";
9
+
9
10
  import { createCategoryListingContext, useNavigationContext } from "#imports";
10
11
  import type { Schemas } from "#shopware";
12
+
11
13
  import { useLcpImagePreload } from "../../../composables/useLcpImagePreload";
12
14
  import { useTypedAppConfig } from "../../../composables/useTypedAppConfig";
13
15
 
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCategoryNavigation } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCenterText } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -21,6 +22,7 @@ const slotCenterContent = getSlotContent("center");
21
22
 
22
23
  <style scoped>
23
24
  .cms-block-center-text .cms-element-image {
24
- @apply self-stretch min-h-12;
25
+ align-self: stretch;
26
+ min-height: 3rem;
25
27
  }
26
28
  </style>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCrossSelling } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockForm } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockForm } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockGalleryBuybox } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{
@@ -12,7 +13,9 @@ const leftContent = getSlotContent("left");
12
13
  </script>
13
14
 
14
15
  <template>
15
- <div class="w-full flex flex-col lg:flex-row justify-center items-stretch gap-4 lg:gap-10 lg:px-0 overflow-hidden">
16
+ <div
17
+ class="w-full flex flex-col lg:flex-row justify-center items-stretch gap-4 lg:gap-10 lg:px-0 overflow-hidden"
18
+ >
16
19
  <!-- Gallery Section -->
17
20
  <div class="w-full lg:w-3/5">
18
21
  <CmsGenericElement :content="leftContent" />
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImage } from "@shopware/composables";
3
+
3
4
  import { useCmsBlock } from "#imports";
4
5
 
5
6
  const props = defineProps<{