@shopware/cms-base-layer 2.0.0 → 3.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.
- package/README.md +167 -125
- package/app/app.config.ts +12 -0
- package/app/components/SwCategoryNavigation.vue +25 -18
- package/app/components/SwFilterDropdown.vue +54 -0
- package/app/components/SwListingProductPrice.vue +2 -2
- package/app/components/SwMedia3D.vue +14 -5
- package/app/components/SwProductCard.vue +24 -21
- package/app/components/SwProductCardDetails.vue +29 -12
- package/app/components/SwProductCardImage.vue +30 -29
- package/app/components/SwProductGallery.vue +18 -14
- package/app/components/SwProductListingFilter.vue +20 -9
- package/app/components/SwProductListingFilters.vue +3 -7
- package/app/components/SwProductListingFiltersHorizontal.vue +306 -0
- package/app/components/SwProductPrice.vue +3 -3
- package/app/components/SwProductRating.vue +40 -0
- package/app/components/SwProductReviews.vue +6 -19
- package/app/components/SwProductUnits.vue +10 -15
- package/app/components/SwQuantitySelect.vue +4 -7
- package/app/components/SwSlider.vue +150 -51
- package/app/components/SwSortDropdown.vue +10 -6
- package/app/components/SwVariantConfigurator.vue +13 -13
- package/app/components/listing-filters/SwFilterPrice.vue +45 -40
- package/app/components/listing-filters/SwFilterProperties.vue +40 -33
- package/app/components/listing-filters/SwFilterRating.vue +36 -27
- package/app/components/listing-filters/SwFilterShippingFree.vue +39 -32
- package/app/components/public/cms/CmsBlockSpatialViewer.vue +94 -0
- package/app/components/public/cms/CmsGenericBlock.md +17 -2
- package/app/components/public/cms/CmsGenericBlock.vue +21 -2
- package/app/components/public/cms/CmsGenericElement.vue +7 -2
- package/app/components/public/cms/CmsNoComponent.vue +87 -8
- package/app/components/public/cms/CmsPage.md +19 -2
- package/app/components/public/cms/CmsPage.vue +7 -0
- package/app/components/public/cms/FrontendAccountCustomerGroupRegistrationPage.vue +52 -0
- package/app/components/public/cms/block/CmsBlockCenterText.vue +1 -1
- package/app/components/public/cms/block/CmsBlockImageText.vue +5 -5
- package/app/components/public/cms/block/CmsBlockTextOnImage.vue +5 -12
- package/app/components/public/cms/element/CmsElementBuyBox.vue +3 -3
- package/app/components/public/cms/element/CmsElementCrossSelling.vue +19 -3
- package/app/components/public/cms/element/CmsElementImage.vue +12 -35
- package/app/components/public/cms/element/CmsElementImageGallery.vue +117 -50
- package/app/components/public/cms/element/CmsElementProductBox.vue +7 -1
- package/app/components/public/cms/element/CmsElementProductListing.vue +15 -4
- package/app/components/public/cms/element/CmsElementProductName.vue +6 -1
- package/app/components/public/cms/element/CmsElementProductSlider.vue +56 -35
- package/app/components/public/cms/element/CmsElementSidebarFilter.vue +10 -2
- package/app/components/public/cms/element/CmsElementText.vue +10 -11
- package/app/components/public/cms/element/SwProductListingPagination.vue +2 -2
- package/app/components/public/cms/section/CmsSectionDefault.vue +2 -2
- package/app/components/public/cms/section/CmsSectionSidebar.vue +6 -3
- package/app/components/ui/BaseButton.vue +18 -15
- package/app/components/ui/ChevronIcon.vue +10 -13
- package/app/components/ui/WishlistIcon.vue +3 -8
- package/app/composables/useImagePlaceholder.ts +3 -3
- package/app/composables/useLcpImagePreload.test.ts +229 -0
- package/app/composables/useLcpImagePreload.ts +43 -0
- package/app/composables/useTypedAppConfig.ts +15 -0
- package/app/helpers/cms/findFirstCmsImageUrl.ts +86 -0
- package/app/helpers/cms/getImageSizes.test.ts +50 -0
- package/app/helpers/cms/getImageSizes.ts +36 -0
- package/app/helpers/html-to-vue/ast.ts +53 -19
- package/app/helpers/html-to-vue/getOptionsFromNode.ts +1 -1
- package/app/helpers/html-to-vue/renderToHtml.ts +7 -11
- package/app/helpers/html-to-vue/renderer.ts +86 -26
- package/index.d.ts +37 -5
- package/nuxt.config.ts +25 -0
- package/package.json +21 -21
- package/uno.config.ts +0 -83
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "@shopware/helpers";
|
|
12
12
|
import { getCmsTranslate } from "@shopware/helpers";
|
|
13
13
|
import { defu } from "defu";
|
|
14
|
-
import { computed, ref,
|
|
14
|
+
import { computed, ref, toRef } from "vue";
|
|
15
15
|
import {
|
|
16
16
|
useAddToCart,
|
|
17
17
|
useCartErrorParamsResolver,
|
|
@@ -26,19 +26,17 @@ const { pushSuccess, pushError } = useNotifications();
|
|
|
26
26
|
const { getErrorsCodes } = useCartNotification();
|
|
27
27
|
const { resolveCartError } = useCartErrorParamsResolver();
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
);
|
|
29
|
+
const {
|
|
30
|
+
product: productProp,
|
|
31
|
+
layoutType = "standard",
|
|
32
|
+
displayMode = "standard",
|
|
33
|
+
isProductListing = false,
|
|
34
|
+
} = defineProps<{
|
|
35
|
+
product: Schemas["Product"];
|
|
36
|
+
layoutType?: BoxLayout;
|
|
37
|
+
displayMode?: DisplayMode;
|
|
38
|
+
isProductListing?: boolean;
|
|
39
|
+
}>();
|
|
42
40
|
|
|
43
41
|
type Translations = {
|
|
44
42
|
product: {
|
|
@@ -52,6 +50,8 @@ type Translations = {
|
|
|
52
50
|
badges: {
|
|
53
51
|
topseller: string;
|
|
54
52
|
};
|
|
53
|
+
addToWishlist: string;
|
|
54
|
+
removeFromWishlist: string;
|
|
55
55
|
};
|
|
56
56
|
errors: {
|
|
57
57
|
[key: string]: string;
|
|
@@ -70,6 +70,8 @@ let translations: Translations = {
|
|
|
70
70
|
badges: {
|
|
71
71
|
topseller: "Tip",
|
|
72
72
|
},
|
|
73
|
+
addToWishlist: "Add to wishlist",
|
|
74
|
+
removeFromWishlist: "Remove from wishlist",
|
|
73
75
|
},
|
|
74
76
|
errors: {
|
|
75
77
|
"product-stock-reached":
|
|
@@ -79,7 +81,7 @@ let translations: Translations = {
|
|
|
79
81
|
|
|
80
82
|
translations = defu(useCmsTranslations(), translations) as Translations;
|
|
81
83
|
|
|
82
|
-
const
|
|
84
|
+
const product = toRef(() => productProp);
|
|
83
85
|
|
|
84
86
|
const { addToCart } = useAddToCart(product);
|
|
85
87
|
|
|
@@ -95,12 +97,12 @@ const toggleWishlistProduct = async () => {
|
|
|
95
97
|
if (!isInWishlist.value) {
|
|
96
98
|
await addToWishlist();
|
|
97
99
|
pushSuccess(
|
|
98
|
-
`${
|
|
100
|
+
`${product?.value.translated.name} ${translations.product.addedToWishlist}`,
|
|
99
101
|
);
|
|
100
102
|
} else {
|
|
101
103
|
await removeFromWishlist();
|
|
102
104
|
pushSuccess(
|
|
103
|
-
`${
|
|
105
|
+
`${product?.value.translated.name} ${translations.product.removedFromTheWishlist}`,
|
|
104
106
|
);
|
|
105
107
|
}
|
|
106
108
|
} catch (error) {
|
|
@@ -109,7 +111,7 @@ const toggleWishlistProduct = async () => {
|
|
|
109
111
|
? `${translations.product.reason}: ${error.details.errors?.[0]?.detail}`
|
|
110
112
|
: "";
|
|
111
113
|
return pushError(
|
|
112
|
-
`${
|
|
114
|
+
`${product?.value.translated.name} ${translations.product.cannotAddToWishlist}\n${reason}`,
|
|
113
115
|
{
|
|
114
116
|
timeout: 5000,
|
|
115
117
|
},
|
|
@@ -131,11 +133,11 @@ const addToCartProxy = async () => {
|
|
|
131
133
|
|
|
132
134
|
if (!errors.length)
|
|
133
135
|
pushSuccess(
|
|
134
|
-
`${
|
|
136
|
+
`${product?.value.translated.name} ${translations.product.addedToCart}`,
|
|
135
137
|
);
|
|
136
138
|
};
|
|
137
139
|
|
|
138
|
-
const fromPrice = getProductFromPrice(
|
|
140
|
+
const fromPrice = getProductFromPrice(product.value);
|
|
139
141
|
const productName = computed(() => getProductName({ product: product.value }));
|
|
140
142
|
const productManufacturer = computed(() =>
|
|
141
143
|
getProductManufacturerName(product.value),
|
|
@@ -165,6 +167,7 @@ const productLink = computed(() =>
|
|
|
165
167
|
:fromPrice="fromPrice"
|
|
166
168
|
:addToCartProxy="addToCartProxy"
|
|
167
169
|
:productLink="productLink"
|
|
170
|
+
:layoutType="layoutType"
|
|
168
171
|
/>
|
|
169
172
|
</div>
|
|
170
|
-
</template>
|
|
173
|
+
</template>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { BoxLayout } from "@shopware/composables";
|
|
2
3
|
import type { UrlRouteOutput } from "@shopware/helpers";
|
|
4
|
+
import { computed } from "vue";
|
|
3
5
|
import type { Schemas } from "#shopware";
|
|
4
6
|
|
|
5
7
|
type Translations = {
|
|
@@ -12,7 +14,7 @@ type Translations = {
|
|
|
12
14
|
};
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
defineProps<{
|
|
17
|
+
const props = defineProps<{
|
|
16
18
|
product: Schemas["Product"];
|
|
17
19
|
productName: string | null;
|
|
18
20
|
productManufacturer?: string | null;
|
|
@@ -20,7 +22,10 @@ defineProps<{
|
|
|
20
22
|
fromPrice?: number;
|
|
21
23
|
addToCartProxy: () => Promise<void>;
|
|
22
24
|
productLink: UrlRouteOutput;
|
|
25
|
+
layoutType?: BoxLayout;
|
|
23
26
|
}>();
|
|
27
|
+
|
|
28
|
+
const isMinimalLayout = computed(() => props.layoutType === "minimal");
|
|
24
29
|
</script>
|
|
25
30
|
<template>
|
|
26
31
|
<div class="self-stretch p-2 flex flex-col justify-between items-start gap-4 flex-1">
|
|
@@ -33,25 +38,37 @@ defineProps<{
|
|
|
33
38
|
</div>
|
|
34
39
|
|
|
35
40
|
<RouterLink :to="productLink"
|
|
36
|
-
class="self-stretch text-surface-on-surface text-2xl font-normal font-serif leading-9 overflow-hidden line-clamp-2 break-words"
|
|
41
|
+
class="self-stretch text-surface-on-surface text-2xl font-normal font-serif leading-9 overflow-hidden line-clamp-2 break-words min-h-[4.5rem]"
|
|
37
42
|
data-testid="product-box-product-name-link">
|
|
38
43
|
{{ productName }}
|
|
39
44
|
</RouterLink>
|
|
40
45
|
</div>
|
|
41
46
|
</div>
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
<!-- Star rating for minimal layout -->
|
|
49
|
+
<SwProductRating
|
|
50
|
+
v-if="isMinimalLayout"
|
|
51
|
+
:rating="product?.ratingAverage ?? 0"
|
|
52
|
+
:review-count="product?.productReviews?.length ?? 0"
|
|
53
|
+
class="mt-4"
|
|
54
|
+
/>
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
data-testid="
|
|
48
|
-
|
|
49
|
-
</SwBaseButton>
|
|
56
|
+
<!-- Price for standard layout -->
|
|
57
|
+
<SwListingProductPrice v-else :product="product" data-testid="product-box-product-price" />
|
|
58
|
+
</div>
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
<!-- CTA buttons only for non-minimal layout -->
|
|
61
|
+
<template v-if="!isMinimalLayout">
|
|
62
|
+
<SwBaseButton variant="primary" v-if="!fromPrice" size="medium" :disabled="!product?.available" block
|
|
63
|
+
data-testid="add-to-cart-button" @click="addToCartProxy">
|
|
64
|
+
{{ translations.product.addToCart }}
|
|
54
65
|
</SwBaseButton>
|
|
55
|
-
|
|
66
|
+
|
|
67
|
+
<RouterLink v-else :to="productLink" class="self-stretch">
|
|
68
|
+
<SwBaseButton block>
|
|
69
|
+
{{ translations.product.details }}
|
|
70
|
+
</SwBaseButton>
|
|
71
|
+
</RouterLink>
|
|
72
|
+
</template>
|
|
56
73
|
</div>
|
|
57
74
|
</template>
|
|
@@ -5,9 +5,8 @@ import {
|
|
|
5
5
|
isProductOnSale,
|
|
6
6
|
isProductTopSeller,
|
|
7
7
|
} from "@shopware/helpers";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { useImagePlaceholder } from "#imports";
|
|
8
|
+
import { computed, inject } from "vue";
|
|
9
|
+
import { useUser } from "#imports";
|
|
11
10
|
import type { Schemas } from "#shopware";
|
|
12
11
|
|
|
13
12
|
type Translations = {
|
|
@@ -15,6 +14,8 @@ type Translations = {
|
|
|
15
14
|
badges: {
|
|
16
15
|
topseller: string;
|
|
17
16
|
};
|
|
17
|
+
addToWishlist: string;
|
|
18
|
+
removeFromWishlist: string;
|
|
18
19
|
};
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -27,27 +28,11 @@ const props = defineProps<{
|
|
|
27
28
|
productLink: UrlRouteOutput;
|
|
28
29
|
}>();
|
|
29
30
|
|
|
30
|
-
const containerElement = useTemplateRef<HTMLDivElement>("containerElement");
|
|
31
|
-
const { width, height } = useElementSize(containerElement);
|
|
32
|
-
|
|
33
|
-
const DEFAULT_THUMBNAIL_SIZE = 10;
|
|
34
|
-
function roundUp(num: number) {
|
|
35
|
-
return num ? Math.ceil(num / 100) * 100 : DEFAULT_THUMBNAIL_SIZE;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
31
|
const coverSrcPath = computed(() => {
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Use the larger dimension and apply 2x for high-DPI displays
|
|
44
|
-
// For square containers, width and height should be the same
|
|
45
|
-
const containerSize = Math.max(width.value || 0, height.value || 0);
|
|
46
|
-
const size = roundUp(containerSize * 2);
|
|
47
|
-
return {
|
|
48
|
-
width: size,
|
|
49
|
-
height: size,
|
|
50
|
-
};
|
|
32
|
+
return (
|
|
33
|
+
props.product?.cover?.media?.url ||
|
|
34
|
+
getSmallestThumbnailUrl(props.product?.cover?.media)
|
|
35
|
+
);
|
|
51
36
|
});
|
|
52
37
|
|
|
53
38
|
const coverAlt = computed(() => {
|
|
@@ -57,16 +42,30 @@ const coverAlt = computed(() => {
|
|
|
57
42
|
const isOnSale = computed(() => isProductOnSale(props.product));
|
|
58
43
|
const isTopseller = computed(() => isProductTopSeller(props.product));
|
|
59
44
|
|
|
60
|
-
const
|
|
45
|
+
const { isLoggedIn } = useUser();
|
|
46
|
+
const loginModal = inject<{
|
|
47
|
+
open: (options?: { onSuccess?: () => void | Promise<void> }) => void;
|
|
48
|
+
} | null>("loginModal", null);
|
|
49
|
+
|
|
50
|
+
function handleWishlistClick() {
|
|
51
|
+
if (isLoggedIn.value || !loginModal) {
|
|
52
|
+
props.toggleWishlist();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
loginModal.open({ onSuccess: props.toggleWishlist });
|
|
56
|
+
}
|
|
61
57
|
</script>
|
|
62
58
|
|
|
63
59
|
<template>
|
|
64
|
-
<div
|
|
60
|
+
<div class="self-stretch min-h-[350px] relative flex flex-col justify-start items-start overflow-hidden aspect-square">
|
|
65
61
|
<RouterLink :to="productLink" class="self-stretch h-full relative overflow-hidden">
|
|
66
62
|
<NuxtImg preset="productCard"
|
|
67
63
|
class="w-full h-full absolute top-0 left-0 object-cover"
|
|
68
|
-
:
|
|
69
|
-
|
|
64
|
+
:src="coverSrcPath" :alt="coverAlt"
|
|
65
|
+
width="400" height="400"
|
|
66
|
+
densities="1x"
|
|
67
|
+
loading="lazy"
|
|
68
|
+
data-testid="product-box-img" />
|
|
70
69
|
</RouterLink>
|
|
71
70
|
|
|
72
71
|
<div v-if="isTopseller || isOnSale"
|
|
@@ -77,9 +76,11 @@ const placeholderSvg = useImagePlaceholder();
|
|
|
77
76
|
</div>
|
|
78
77
|
|
|
79
78
|
<client-only>
|
|
80
|
-
<SwIconButton type="secondary"
|
|
79
|
+
<SwIconButton type="secondary"
|
|
80
|
+
:aria-label="isInWishlist ? translations.product.removeFromWishlist : translations.product.addToWishlist"
|
|
81
|
+
:disabled="isLoading"
|
|
81
82
|
class="w-10 h-10 right-4 top-4 absolute bg-brand-secondary rounded-full flex items-center justify-center"
|
|
82
|
-
data-testid="product-box-toggle-wishlist-button" @click="
|
|
83
|
+
data-testid="product-box-toggle-wishlist-button" @click="handleWishlistClick">
|
|
83
84
|
<SwWishlistIcon :filled="isInWishlist" />
|
|
84
85
|
</SwIconButton>
|
|
85
86
|
</client-only>
|
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CmsElementImageGallery,
|
|
4
|
+
SliderElementConfig,
|
|
5
|
+
} from "@shopware/composables";
|
|
3
6
|
import { ref, watch } from "vue";
|
|
4
7
|
import type { Schemas } from "#shopware";
|
|
5
8
|
|
|
6
|
-
const
|
|
9
|
+
const { product, config = {} } = defineProps<{
|
|
7
10
|
product: Schemas["Product"];
|
|
11
|
+
config?: Partial<SliderElementConfig>;
|
|
8
12
|
}>();
|
|
13
|
+
|
|
14
|
+
const defaultConfig: SliderElementConfig = {
|
|
15
|
+
minHeight: { value: "300px", source: "static" },
|
|
16
|
+
navigationArrows: { value: "inside", source: "static" },
|
|
17
|
+
navigationDots: { value: "inside", source: "static" },
|
|
18
|
+
};
|
|
19
|
+
|
|
9
20
|
const content = ref<CmsElementImageGallery>();
|
|
10
21
|
|
|
11
22
|
watch(
|
|
12
|
-
() =>
|
|
13
|
-
(
|
|
14
|
-
const media = value.media;
|
|
23
|
+
[() => product, () => config],
|
|
24
|
+
([currentProduct, currentConfig]) => {
|
|
15
25
|
content.value = {
|
|
16
26
|
config: {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
source: "static",
|
|
20
|
-
},
|
|
21
|
-
navigationArrows: {
|
|
22
|
-
value: "inside",
|
|
23
|
-
source: "static",
|
|
24
|
-
},
|
|
27
|
+
...defaultConfig,
|
|
28
|
+
...currentConfig,
|
|
25
29
|
},
|
|
26
30
|
data: {
|
|
27
|
-
sliderItems: media,
|
|
31
|
+
sliderItems: currentProduct.media,
|
|
28
32
|
},
|
|
29
33
|
} as CmsElementImageGallery;
|
|
30
34
|
},
|
|
@@ -6,7 +6,16 @@ import SwFilterPropertiesVue from "./listing-filters/SwFilterProperties.vue";
|
|
|
6
6
|
import SwFilterRatingVue from "./listing-filters/SwFilterRating.vue";
|
|
7
7
|
import SwFilterShippingFreeVue from "./listing-filters/SwFilterShippingFree.vue";
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const {
|
|
10
|
+
filter,
|
|
11
|
+
selectedManufacturer,
|
|
12
|
+
selectedProperties,
|
|
13
|
+
selectedMinPrice,
|
|
14
|
+
selectedMaxPrice,
|
|
15
|
+
selectedRating,
|
|
16
|
+
selectedShippingFree,
|
|
17
|
+
displayMode = "accordion",
|
|
18
|
+
} = defineProps<{
|
|
10
19
|
filter: ListingFilter;
|
|
11
20
|
selectedManufacturer: Set<string>;
|
|
12
21
|
selectedProperties: Set<string>;
|
|
@@ -14,6 +23,7 @@ const props = defineProps<{
|
|
|
14
23
|
selectedMaxPrice: number | undefined;
|
|
15
24
|
selectedRating: number | undefined;
|
|
16
25
|
selectedShippingFree: boolean | undefined;
|
|
26
|
+
displayMode?: "accordion" | "dropdown";
|
|
17
27
|
}>();
|
|
18
28
|
|
|
19
29
|
const emit = defineEmits<{
|
|
@@ -22,13 +32,13 @@ const emit = defineEmits<{
|
|
|
22
32
|
|
|
23
33
|
const transformedFilters = computed(() => ({
|
|
24
34
|
price: {
|
|
25
|
-
min:
|
|
26
|
-
max:
|
|
35
|
+
min: selectedMinPrice,
|
|
36
|
+
max: selectedMaxPrice,
|
|
27
37
|
},
|
|
28
|
-
rating:
|
|
29
|
-
"shipping-free":
|
|
30
|
-
manufacturer: [...
|
|
31
|
-
properties: [...
|
|
38
|
+
rating: selectedRating,
|
|
39
|
+
"shipping-free": selectedShippingFree,
|
|
40
|
+
manufacturer: [...selectedManufacturer],
|
|
41
|
+
properties: [...selectedProperties],
|
|
32
42
|
}));
|
|
33
43
|
|
|
34
44
|
const filterComponent = computed<Component | undefined>(() => {
|
|
@@ -40,8 +50,8 @@ const filterComponent = computed<Component | undefined>(() => {
|
|
|
40
50
|
};
|
|
41
51
|
|
|
42
52
|
return (
|
|
43
|
-
componentMap[
|
|
44
|
-
("options" in
|
|
53
|
+
componentMap[filter.code] ||
|
|
54
|
+
("options" in filter ? SwFilterPropertiesVue : undefined)
|
|
45
55
|
);
|
|
46
56
|
});
|
|
47
57
|
|
|
@@ -58,6 +68,7 @@ const handleSelectValue = ({
|
|
|
58
68
|
:is="filterComponent"
|
|
59
69
|
:filter="filter"
|
|
60
70
|
:selected-filters="transformedFilters"
|
|
71
|
+
:display-mode="displayMode"
|
|
61
72
|
@select-value="handleSelectValue"
|
|
62
73
|
/>
|
|
63
74
|
</div>
|
|
@@ -7,12 +7,12 @@ import { useCmsTranslations } from "@shopware/composables";
|
|
|
7
7
|
import { defu } from "defu";
|
|
8
8
|
import { computed, reactive } from "vue";
|
|
9
9
|
import type { ComputedRef, UnwrapNestedRefs } from "vue";
|
|
10
|
-
import {
|
|
11
|
-
import { useCategoryListing } from "#imports";
|
|
10
|
+
import type { LocationQueryRaw } from "vue-router";
|
|
11
|
+
import { useCategoryListing, useRoute, useRouter } from "#imports";
|
|
12
12
|
import type { Schemas, operations } from "#shopware";
|
|
13
13
|
|
|
14
14
|
const props = defineProps<{
|
|
15
|
-
content
|
|
15
|
+
content?: CmsElementProductListing | CmsElementSidebarFilter;
|
|
16
16
|
listingType?: string;
|
|
17
17
|
}>();
|
|
18
18
|
|
|
@@ -233,10 +233,6 @@ async function invokeCleanFilters() {
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
const isDefaultSidebarFilter =
|
|
237
|
-
props.content.type === "sidebar-filter" &&
|
|
238
|
-
props.content.config?.boxLayout?.value === "standard";
|
|
239
|
-
|
|
240
236
|
const handleSortChange = (sortKey: string) => {
|
|
241
237
|
currentSortingOrder.value = sortKey;
|
|
242
238
|
};
|