@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.
- package/README.md +64 -58
- package/app/components/SwCategoryNavigation.vue +1 -0
- package/app/components/SwCategoryNavigationLink.vue +16 -8
- package/app/components/SwContactForm.vue +1 -0
- package/app/components/SwFilterChips.vue +1 -0
- package/app/components/SwListingProductPrice.vue +16 -4
- package/app/components/SwMedia3D.vue +1 -4
- package/app/components/SwNewsletterForm.vue +4 -3
- package/app/components/SwProductAddToCart.vue +24 -7
- package/app/components/SwProductCard.vue +20 -3
- package/app/components/SwProductCardDetails.vue +27 -9
- package/app/components/SwProductCardImage.vue +31 -12
- package/app/components/SwProductCardSkeleton.vue +37 -14
- package/app/components/SwProductGallery.vue +1 -0
- package/app/components/SwProductListingFilter.vue +5 -1
- package/app/components/SwProductListingFilters.vue +57 -76
- package/app/components/SwProductListingFiltersHorizontal.vue +40 -71
- package/app/components/SwProductPrice.vue +1 -0
- package/app/components/SwProductReviews.vue +14 -6
- package/app/components/SwProductReviewsForm.vue +15 -3
- package/app/components/SwProductUnits.vue +1 -0
- package/app/components/SwQuantitySelect.vue +10 -3
- package/app/components/SwSharedPrice.vue +1 -0
- package/app/components/SwSlider.vue +1 -0
- package/app/components/SwStockInfo.vue +12 -6
- package/app/components/SwVariantConfigurator.vue +4 -1
- package/app/components/listing-filters/SwFilterPrice.vue +79 -30
- package/app/components/listing-filters/SwFilterProperties.vue +40 -25
- package/app/components/listing-filters/SwFilterRating.vue +21 -9
- package/app/components/listing-filters/SwFilterShippingFree.vue +16 -8
- package/app/components/public/cms/CmsBlockSpatialViewer.vue +1 -0
- package/app/components/public/cms/CmsGenericBlock.vue +3 -1
- package/app/components/public/cms/CmsGenericElement.vue +2 -1
- package/app/components/public/cms/CmsNoComponent.vue +2 -1
- package/app/components/public/cms/CmsPage.md +1 -1
- package/app/components/public/cms/CmsPage.vue +2 -0
- package/app/components/public/cms/block/CmsBlockCategoryNavigation.vue +1 -0
- package/app/components/public/cms/block/CmsBlockCenterText.vue +3 -1
- package/app/components/public/cms/block/CmsBlockCrossSelling.vue +1 -0
- package/app/components/public/cms/block/CmsBlockCustomForm.vue +1 -0
- package/app/components/public/cms/block/CmsBlockForm.vue +1 -0
- package/app/components/public/cms/block/CmsBlockGalleryBuybox.vue +4 -1
- package/app/components/public/cms/block/CmsBlockImage.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageBubbleRow.vue +9 -2
- package/app/components/public/cms/block/CmsBlockImageCover.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +10 -3
- package/app/components/public/cms/block/CmsBlockImageGallery.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +10 -5
- package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +11 -3
- package/app/components/public/cms/block/CmsBlockImageSimpleGrid.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageSlider.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageText.vue +4 -1
- package/app/components/public/cms/block/CmsBlockImageTextBubble.vue +4 -1
- package/app/components/public/cms/block/CmsBlockImageTextCover.vue +4 -1
- package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +4 -12
- package/app/components/public/cms/block/CmsBlockImageTextRow.vue +13 -4
- package/app/components/public/cms/block/CmsBlockImageThreeColumn.vue +1 -0
- package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +11 -3
- package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +11 -4
- package/app/components/public/cms/block/CmsBlockProductDescriptionReviews.vue +1 -0
- package/app/components/public/cms/block/CmsBlockProductHeading.vue +3 -1
- package/app/components/public/cms/block/CmsBlockProductListing.vue +1 -0
- package/app/components/public/cms/block/CmsBlockProductThreeColumn.vue +1 -0
- package/app/components/public/cms/block/CmsBlockSidebarFilter.vue +1 -0
- package/app/components/public/cms/block/CmsBlockText.vue +1 -0
- package/app/components/public/cms/block/CmsBlockTextHero.vue +1 -0
- package/app/components/public/cms/block/CmsBlockTextOnImage.vue +2 -4
- package/app/components/public/cms/block/CmsBlockTextThreeColumn.vue +1 -0
- package/app/components/public/cms/block/CmsBlockTextTwoColumn.vue +4 -1
- package/app/components/public/cms/block/CmsBlockVimeoVideo.vue +1 -0
- package/app/components/public/cms/block/CmsBlockYoutubeVideo.vue +1 -0
- package/app/components/public/cms/element/CmsElementBuyBox.vue +90 -72
- package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +14 -3
- package/app/components/public/cms/element/CmsElementCrossSelling.vue +3 -1
- package/app/components/public/cms/element/CmsElementCustomForm.vue +1 -0
- package/app/components/public/cms/element/CmsElementForm.vue +1 -0
- package/app/components/public/cms/element/CmsElementHtml.vue +0 -1
- package/app/components/public/cms/element/CmsElementImage.vue +2 -1
- package/app/components/public/cms/element/CmsElementImageGallery.vue +6 -2
- package/app/components/public/cms/element/CmsElementManufacturerLogo.vue +1 -0
- package/app/components/public/cms/element/CmsElementProductBox.vue +1 -0
- package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +93 -36
- package/app/components/public/cms/element/CmsElementProductListing.vue +16 -5
- package/app/components/public/cms/element/CmsElementProductSlider.vue +6 -4
- package/app/components/public/cms/element/CmsElementText.vue +2 -0
- package/app/components/public/cms/element/CmsElementVimeoVideo.vue +1 -0
- package/app/components/public/cms/element/CmsElementYoutubeVideo.vue +1 -0
- package/app/components/public/cms/element/SwProductListingPagination.vue +8 -2
- package/app/components/public/cms/section/CmsSectionSidebar.vue +13 -8
- package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +16 -5
- package/app/components/ui/SwitchButton.vue +53 -14
- package/app/components/ui/WishlistIcon.vue +8 -2
- package/app/composables/useLcpImagePreload.test.ts +1 -0
- package/app/composables/useLcpImagePreload.ts +2 -0
- package/app/composables/useTypedAppConfig.ts +1 -0
- package/app/helpers/cms/getImageSizes.test.ts +1 -0
- package/app/helpers/html-to-vue/ast.ts +1 -0
- package/app/helpers/html-to-vue/getOptionsFromNode.test.ts +1 -0
- package/app/helpers/html-to-vue/renderToHtml.ts +1 -0
- package/app/helpers/html-to-vue/renderer.ts +1 -0
- package/app/providers/shopware.test.ts +1 -0
- package/app/utils/routeQuery.test.ts +65 -0
- package/app/utils/routeQuery.ts +26 -0
- package/app/utils/useSelectedListingFilters.test.ts +82 -0
- package/app/utils/useSelectedListingFilters.ts +105 -0
- package/nuxt.config.ts +24 -1
- 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
|
|
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
|
|
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">{{
|
|
83
|
+
<label :for="inputId" class="sr-only">{{
|
|
84
|
+
translations.form.quantitySelect.label
|
|
85
|
+
}}</label>
|
|
79
86
|
|
|
80
87
|
<input
|
|
81
88
|
:id="inputId"
|
|
@@ -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
|
|
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"
|
|
37
|
-
deliveryTime?.name }}
|
|
39
|
+
<span v-if="availableStock >= minPurchase && deliveryTime"
|
|
40
|
+
>{{ translations.product.deliveryTime }} {{ deliveryTime?.name }}
|
|
38
41
|
</span>
|
|
39
|
-
<span
|
|
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">
|
|
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
|
|
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
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
169
|
-
|
|
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
|
|
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
|
-
|
|
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="
|
|
177
|
-
|
|
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
|
-
|
|
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="
|
|
184
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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)"
|
|
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)"
|
|
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
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
class="self-stretch
|
|
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
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
</
|
|
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
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
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="[
|
|
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="
|
|
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
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
99
|
+
<div
|
|
100
|
+
v-if="isFilterVisible || displayMode === 'dropdown'"
|
|
101
|
+
class="self-stretch"
|
|
102
|
+
>
|
|
97
103
|
<div class="pt-6 space-y-4">
|
|
98
|
-
<div
|
|
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"
|
|
@@ -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://
|
|
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://
|
|
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://
|
|
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](
|
|
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 { 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
|
-
|
|
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 { 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
|
|
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" />
|