@shopware/cms-base-layer 1.5.0 → 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.
- package/README.md +328 -13
- package/app/app.config.ts +7 -0
- package/app/assets/icons/check-circle.svg +3 -0
- package/app/assets/icons/checkmark.svg +3 -0
- package/app/assets/icons/chevron.svg +3 -0
- package/app/assets/icons/exclamation-circle.svg +3 -0
- package/app/assets/icons/star-empty.svg +3 -0
- package/app/assets/icons/star-filled.svg +3 -0
- package/app/assets/icons/user.svg +1 -0
- package/app/components/SwCategoryNavigation.vue +76 -0
- package/app/components/SwCategoryNavigationLink.vue +128 -0
- package/{components → app/components}/SwContactForm.vue +27 -27
- package/app/components/SwFilterChips.vue +144 -0
- package/app/components/SwListingProductPrice.vue +89 -0
- package/{components → app/components}/SwNewsletterForm.vue +45 -34
- package/{components → app/components}/SwPagination.vue +3 -5
- package/{components → app/components}/SwProductAddToCart.vue +22 -27
- package/app/components/SwProductCard.vue +170 -0
- package/app/components/SwProductCardDetails.vue +57 -0
- package/app/components/SwProductCardImage.vue +87 -0
- package/app/components/SwProductCardSkeleton.vue +33 -0
- package/app/components/SwProductListingFilter.vue +64 -0
- package/app/components/SwProductListingFilters.vue +308 -0
- package/{components → app/components}/SwProductReviews.vue +28 -13
- package/app/components/SwProductReviewsForm.vue +292 -0
- package/app/components/SwQuantitySelect.vue +106 -0
- package/{components → app/components}/SwSlider.vue +4 -4
- package/app/components/SwSortDropdown.vue +83 -0
- package/app/components/SwStockInfo.vue +44 -0
- package/{components → app/components}/SwVariantConfigurator.vue +1 -1
- package/app/components/listing-filters/SwFilterPrice.vue +214 -0
- package/app/components/listing-filters/SwFilterProperties.vue +113 -0
- package/app/components/listing-filters/SwFilterRating.vue +90 -0
- package/app/components/listing-filters/SwFilterShippingFree.vue +107 -0
- package/{components → app/components}/public/cms/CmsPage.vue +19 -4
- package/{components → app/components}/public/cms/block/CmsBlockGalleryBuybox.vue +5 -5
- package/{components → app/components}/public/cms/block/CmsBlockImageBubbleRow.vue +5 -5
- package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +41 -0
- package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +42 -0
- package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +37 -0
- package/{components → app/components}/public/cms/block/CmsBlockImageSimpleGrid.vue +11 -5
- package/{components → app/components}/public/cms/block/CmsBlockImageText.vue +7 -3
- package/{components → app/components}/public/cms/block/CmsBlockImageTextBubble.vue +13 -16
- package/{components → app/components}/public/cms/block/CmsBlockImageTextCover.vue +7 -9
- package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +88 -0
- package/app/components/public/cms/block/CmsBlockImageTextRow.vue +53 -0
- package/{components → app/components}/public/cms/block/CmsBlockImageThreeColumn.vue +10 -4
- package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +37 -0
- package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +37 -0
- package/{components → app/components}/public/cms/block/CmsBlockProductHeading.vue +1 -1
- package/{components → app/components}/public/cms/block/CmsBlockProductThreeColumn.vue +10 -4
- package/{components → app/components}/public/cms/block/CmsBlockSidebarFilter.vue +3 -1
- package/app/components/public/cms/block/CmsBlockTextOnImage.vue +30 -0
- package/{components → app/components}/public/cms/block/CmsBlockTextTeaserSection.vue +4 -4
- package/{components → app/components}/public/cms/block/CmsBlockTextTwoColumn.vue +3 -5
- package/app/components/public/cms/element/CmsElementBuyBox.vue +145 -0
- package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +53 -0
- package/{components → app/components}/public/cms/element/CmsElementCrossSelling.vue +3 -3
- package/{components → app/components}/public/cms/element/CmsElementImage.vue +52 -13
- package/app/components/public/cms/element/CmsElementImageGallery.vue +158 -0
- package/{components → app/components}/public/cms/element/CmsElementImageSlider.vue +2 -2
- package/{components → app/components}/public/cms/element/CmsElementProductBox.vue +2 -1
- package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +217 -0
- package/{components → app/components}/public/cms/element/CmsElementProductListing.vue +23 -94
- package/app/components/public/cms/element/CmsElementProductName.vue +11 -0
- package/{components → app/components}/public/cms/element/CmsElementProductSlider.vue +4 -4
- package/{components → app/components}/public/cms/element/CmsElementText.vue +8 -2
- package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.vue +8 -2
- package/app/components/public/cms/element/SwProductListingPagination.vue +70 -0
- package/{components → app/components}/public/cms/section/CmsSectionDefault.vue +1 -1
- package/app/components/public/cms/section/CmsSectionSidebar.vue +36 -0
- package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +28 -0
- package/app/components/ui/BaseButton.vue +99 -0
- package/app/components/ui/BaseIcon.vue +15 -0
- package/app/components/ui/Checkbox.vue +49 -0
- package/app/components/ui/CheckmarkIcon.vue +23 -0
- package/app/components/ui/ChevronIcon.vue +37 -0
- package/app/components/ui/ExclamationIcon.vue +11 -0
- package/app/components/ui/IconButton.vue +32 -0
- package/app/components/ui/RadioButton.vue +26 -0
- package/app/components/ui/StarIcon.vue +18 -0
- package/app/components/ui/SwitchButton.vue +100 -0
- package/app/components/ui/UserIcon.vue +11 -0
- package/app/components/ui/WishlistIcon.vue +20 -0
- package/app/composables/useImagePlaceholder.ts +27 -0
- package/{helpers → app/helpers}/clientOnly.ts +5 -0
- package/app/providers/shopware.test.ts +213 -0
- package/app/providers/shopware.ts +107 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +2 -2
- package/index.d.ts +12 -0
- package/nuxt.config.ts +80 -6
- package/package.json +29 -21
- package/uno.config.ts +83 -0
- package/components/SwCategoryNavigation.vue +0 -44
- package/components/SwCategoryNavigationLink.vue +0 -57
- package/components/SwListingProductPrice.vue +0 -89
- package/components/SwProductCard.vue +0 -286
- package/components/SwProductListingFilter.vue +0 -42
- package/components/SwProductListingFilters.vue +0 -292
- package/components/listing-filters/SwFilterPrice.vue +0 -160
- package/components/listing-filters/SwFilterProperties.vue +0 -123
- package/components/listing-filters/SwFilterRating.vue +0 -101
- package/components/listing-filters/SwFilterShippingFree.vue +0 -104
- package/components/public/cms/block/CmsBlockImageFourColumn.vue +0 -29
- package/components/public/cms/block/CmsBlockImageHighlightRow.vue +0 -27
- package/components/public/cms/block/CmsBlockImageTextGallery.vue +0 -85
- package/components/public/cms/block/CmsBlockImageTextRow.vue +0 -43
- package/components/public/cms/block/CmsBlockImageThreeCover.vue +0 -27
- package/components/public/cms/block/CmsBlockImageTwoColumn.vue +0 -25
- package/components/public/cms/block/CmsBlockTextOnImage.vue +0 -20
- package/components/public/cms/element/CmsBlockHtml.md +0 -1
- package/components/public/cms/element/CmsElementBuyBox.vue +0 -190
- package/components/public/cms/element/CmsElementCategoryNavigation.vue +0 -167
- package/components/public/cms/element/CmsElementImageGallery.vue +0 -249
- package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +0 -123
- package/components/public/cms/element/CmsElementProductName.vue +0 -10
- package/components/public/cms/section/CmsSectionSidebar.vue +0 -49
- package/components/public/cms/skeleton/ProductCardSkeleton.vue +0 -44
- /package/{components → app/components}/SwMedia3D.vue +0 -0
- /package/{components → app/components}/SwProductGallery.vue +0 -0
- /package/{components → app/components}/SwProductPrice.vue +0 -0
- /package/{components → app/components}/SwProductUnits.vue +0 -0
- /package/{components → app/components}/SwSharedPrice.vue +0 -0
- /package/{components → app/components}/public/cms/CmsGenericBlock.md +0 -0
- /package/{components → app/components}/public/cms/CmsGenericBlock.vue +0 -0
- /package/{components → app/components}/public/cms/CmsGenericElement.md +0 -0
- /package/{components → app/components}/public/cms/CmsGenericElement.vue +0 -0
- /package/{components → app/components}/public/cms/CmsNoComponent.vue +0 -0
- /package/{components → app/components}/public/cms/CmsPage.md +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCategoryNavigation.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCenterText.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCrossSelling.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCustomForm.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockDefault.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockForm.vue +0 -0
- /package/{components/public/cms/element → app/components/public/cms/block}/CmsBlockHtml.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImage.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageCover.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageGallery.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageSlider.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductDescriptionReviews.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductListing.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductSlider.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockText.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextHero.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextTeaser.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextThreeColumn.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockVimeoVideo.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockYoutubeVideo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementBuyBox.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCategoryNavigation.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCrossSelling.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCustomForm.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCustomForm.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementForm.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementForm.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementHtml.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImage.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageGallery.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageSlider.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductBox.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductDescriptionReviews.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductListing.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductName.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductSlider.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementText.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.md +0 -0
- /package/{components → app/components}/public/cms/section/CmsSectionDefault.md +0 -0
- /package/{components → app/components}/public/cms/section/CmsSectionSidebar.md +0 -0
- /package/{helpers → app/helpers}/html-to-vue/ast.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.test.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/renderToHtml.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/renderer.ts +0 -0
- /package/{helpers → app/helpers}/media/isSpatial.ts +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
|
|
4
|
+
export interface SwBaseButtonProps {
|
|
5
|
+
variant?:
|
|
6
|
+
| "primary"
|
|
7
|
+
| "secondary"
|
|
8
|
+
| "success"
|
|
9
|
+
| "warning"
|
|
10
|
+
| "outline"
|
|
11
|
+
| "ghost";
|
|
12
|
+
size?: "small" | "medium" | "large";
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
type?: "button" | "submit" | "reset";
|
|
16
|
+
block?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
defineOptions({
|
|
20
|
+
inheritAttrs: false,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<SwBaseButtonProps>(), {
|
|
24
|
+
variant: "primary",
|
|
25
|
+
size: "medium",
|
|
26
|
+
disabled: false,
|
|
27
|
+
loading: false,
|
|
28
|
+
type: "button",
|
|
29
|
+
block: false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
click: [event: MouseEvent];
|
|
34
|
+
}>();
|
|
35
|
+
|
|
36
|
+
const buttonClasses = computed(() => {
|
|
37
|
+
const classes = [
|
|
38
|
+
"inline-flex justify-center items-center gap-2 rounded font-bold transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const sizeClasses = {
|
|
42
|
+
small: "px-3 py-2 text-sm",
|
|
43
|
+
medium: "px-4 py-3 text-base",
|
|
44
|
+
large: "px-6 py-4 text-lg",
|
|
45
|
+
};
|
|
46
|
+
classes.push(sizeClasses[props.size]);
|
|
47
|
+
|
|
48
|
+
const variantClasses = {
|
|
49
|
+
primary:
|
|
50
|
+
"bg-brand-primary hover:bg-brand-primary-hover text-brand-on-primary focus:ring-brand-primary",
|
|
51
|
+
secondary:
|
|
52
|
+
"bg-brand-secondary hover:bg-brand-secondary-hover text-brand-on-secondary focus:ring-brand-secondary",
|
|
53
|
+
success:
|
|
54
|
+
"bg-states-success hover:opacity-90 text-white focus:ring-states-success transition-opacity",
|
|
55
|
+
warning:
|
|
56
|
+
"bg-states-warning hover:opacity-90 text-white focus:ring-states-warning transition-opacity",
|
|
57
|
+
outline:
|
|
58
|
+
"border-2 border-brand-primary text-brand-primary hover:bg-brand-primary hover:text-brand-on-primary focus:ring-brand-primary",
|
|
59
|
+
ghost:
|
|
60
|
+
"bg-transparent text-surface-on-surface-variant hover:text-surface-on-surface focus:ring-surface-on-surface",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (props.disabled || props.loading) {
|
|
64
|
+
classes.push(
|
|
65
|
+
"bg-surface-surface-disabled text-surface-on-surface cursor-not-allowed opacity-50",
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
classes.push(variantClasses[props.variant]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (props.block) {
|
|
72
|
+
classes.push("w-full");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return classes.join(" ");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const handleClick = (event: MouseEvent) => {
|
|
79
|
+
if (!props.disabled && !props.loading) {
|
|
80
|
+
emit("click", event);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<button
|
|
87
|
+
:type="type"
|
|
88
|
+
:class="buttonClasses"
|
|
89
|
+
:disabled="disabled || loading"
|
|
90
|
+
@click="handleClick"
|
|
91
|
+
v-bind="$attrs"
|
|
92
|
+
>
|
|
93
|
+
<div v-if="loading" class="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
|
|
94
|
+
|
|
95
|
+
<span :class="{ 'opacity-0': loading }">
|
|
96
|
+
<slot />
|
|
97
|
+
</span>
|
|
98
|
+
</button>
|
|
99
|
+
</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const {
|
|
3
|
+
src,
|
|
4
|
+
size = 24,
|
|
5
|
+
alt = "",
|
|
6
|
+
} = defineProps<{
|
|
7
|
+
src: string;
|
|
8
|
+
size?: number;
|
|
9
|
+
alt?: string;
|
|
10
|
+
}>();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<NuxtImg :src="src" :alt="alt" :width="size" :height="size" />
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const model = defineModel<boolean>({
|
|
3
|
+
required: true,
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
label,
|
|
8
|
+
description,
|
|
9
|
+
disabled = false,
|
|
10
|
+
} = defineProps<{
|
|
11
|
+
label?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}>();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<label class="flex items-start gap-2">
|
|
19
|
+
<input
|
|
20
|
+
class="accent-brand-primary w-4 h-4 focus-within:outline-2 focus-within:outline-brand-primary focus-within:outline focus-within:outline-offset-[2px] focus-within"
|
|
21
|
+
type="checkbox"
|
|
22
|
+
v-model="model"
|
|
23
|
+
:disabled
|
|
24
|
+
/>
|
|
25
|
+
<div v-if="label || description">
|
|
26
|
+
<p
|
|
27
|
+
v-if="label"
|
|
28
|
+
:class="
|
|
29
|
+
disabled
|
|
30
|
+
? 'text-surface-on-surface-disabled'
|
|
31
|
+
: 'text-surface-on-surface'
|
|
32
|
+
"
|
|
33
|
+
>
|
|
34
|
+
{{ label }}
|
|
35
|
+
</p>
|
|
36
|
+
<p
|
|
37
|
+
v-if="description"
|
|
38
|
+
class="text-sm"
|
|
39
|
+
:class="
|
|
40
|
+
disabled
|
|
41
|
+
? 'text-surface-on-surface-disabled'
|
|
42
|
+
: 'text-surface-on-surface-variant'
|
|
43
|
+
"
|
|
44
|
+
>
|
|
45
|
+
{{ description }}
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
48
|
+
</label>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import CheckmarkFilledSvg from "@cms-assets/icons/check-circle.svg";
|
|
3
|
+
import CheckmarkSvg from "@cms-assets/icons/checkmark.svg";
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
filled = false,
|
|
7
|
+
size = 24,
|
|
8
|
+
alt = "",
|
|
9
|
+
} = defineProps<{
|
|
10
|
+
filled?: boolean;
|
|
11
|
+
size?: number;
|
|
12
|
+
alt?: string;
|
|
13
|
+
}>();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<NuxtImg
|
|
18
|
+
:src="filled ? CheckmarkFilledSvg : CheckmarkSvg"
|
|
19
|
+
:alt="alt"
|
|
20
|
+
:width="size"
|
|
21
|
+
:height="size"
|
|
22
|
+
/>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ChevronSvg from "@cms-assets/icons/chevron.svg";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
direction?: "up" | "down" | "left" | "right";
|
|
8
|
+
size?: number;
|
|
9
|
+
alt?: string;
|
|
10
|
+
}>(),
|
|
11
|
+
{
|
|
12
|
+
direction: "down",
|
|
13
|
+
size: 24,
|
|
14
|
+
alt: "",
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const rotationClass = computed(() => {
|
|
19
|
+
const rotations = {
|
|
20
|
+
down: "",
|
|
21
|
+
up: "rotate-180",
|
|
22
|
+
left: "rotate-90",
|
|
23
|
+
right: "-rotate-90",
|
|
24
|
+
};
|
|
25
|
+
return rotations[props.direction];
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<NuxtImg
|
|
31
|
+
:src="ChevronSvg"
|
|
32
|
+
:alt="alt"
|
|
33
|
+
:class="['transition-transform', rotationClass]"
|
|
34
|
+
:width="size"
|
|
35
|
+
:height="size"
|
|
36
|
+
/>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ExclamationCircleSvg from "@cms-assets/icons/exclamation-circle.svg";
|
|
3
|
+
|
|
4
|
+
const { size = 24 } = defineProps<{
|
|
5
|
+
size?: number;
|
|
6
|
+
}>();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<SwBaseIcon :src="ExclamationCircleSvg" :size="size" alt="Error" />
|
|
11
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const { type = "primary" } = defineProps<{
|
|
3
|
+
type?: "primary" | "secondary" | "tertiary" | "outline" | "ghost";
|
|
4
|
+
}>();
|
|
5
|
+
|
|
6
|
+
const styles = {
|
|
7
|
+
primary:
|
|
8
|
+
"bg-brand-primary hover:focus:bg-brand-primary-hover text-brand-on-primary",
|
|
9
|
+
secondary:
|
|
10
|
+
"bg-brand-secondary hover:focus:bg-brand-secondary-hover text-brand-on-secondary",
|
|
11
|
+
tertiary:
|
|
12
|
+
"bg-brand-tertiary hover:focus:bg-brand-tertiary-hover text-brand-on-tertiary",
|
|
13
|
+
outline:
|
|
14
|
+
"text-brand-primary bg-transparent hover:focus:bg-surface-surface-container outline outline-2 outline-offset-[-2px] outline-brand-primary",
|
|
15
|
+
ghost: "bg-transparent hover:focus:bg-surface-surface-container",
|
|
16
|
+
};
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<button
|
|
21
|
+
:class="[
|
|
22
|
+
styles[type],
|
|
23
|
+
{
|
|
24
|
+
'bg-surface-on-surface-disabled text-surface-surface-disabled':
|
|
25
|
+
$attrs.disabled,
|
|
26
|
+
'w-10 h-10': type !== 'ghost',
|
|
27
|
+
},
|
|
28
|
+
]"
|
|
29
|
+
>
|
|
30
|
+
<slot />
|
|
31
|
+
</button>
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const modelValue = defineModel<string | null>();
|
|
3
|
+
|
|
4
|
+
const { selected } = defineProps<{
|
|
5
|
+
selected: boolean;
|
|
6
|
+
}>();
|
|
7
|
+
</script>
|
|
8
|
+
<template>
|
|
9
|
+
<input
|
|
10
|
+
type="radio"
|
|
11
|
+
class="sr-only"
|
|
12
|
+
v-bind="$attrs"
|
|
13
|
+
v-model="modelValue"
|
|
14
|
+
name="shipping-method"
|
|
15
|
+
/>
|
|
16
|
+
<div
|
|
17
|
+
class="w-4 h-4 rounded-full border border-outline-outline border-spacing-1 flex items-center justify-center"
|
|
18
|
+
>
|
|
19
|
+
<div
|
|
20
|
+
:class="{
|
|
21
|
+
'bg-brand-primary': selected,
|
|
22
|
+
}"
|
|
23
|
+
class="w-2.5 h-2.5 rounded-full"
|
|
24
|
+
></div>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import StarEmptySvg from "@cms-assets/icons/star-empty.svg";
|
|
3
|
+
import StarFilledSvg from "@cms-assets/icons/star-filled.svg";
|
|
4
|
+
|
|
5
|
+
const { filled = true, size = 20 } = defineProps<{
|
|
6
|
+
filled?: boolean;
|
|
7
|
+
size?: number;
|
|
8
|
+
}>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<NuxtImg
|
|
13
|
+
:src="filled ? StarFilledSvg : StarEmptySvg"
|
|
14
|
+
alt="Star"
|
|
15
|
+
:width="size"
|
|
16
|
+
:height="size"
|
|
17
|
+
/>
|
|
18
|
+
</template>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
name?: string;
|
|
6
|
+
ariaLabel?: string;
|
|
7
|
+
label?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
const modelValue = defineModel<boolean | null>();
|
|
13
|
+
|
|
14
|
+
const emits = defineEmits<{
|
|
15
|
+
change: [v: boolean | null];
|
|
16
|
+
}>();
|
|
17
|
+
|
|
18
|
+
const value = computed(() => !!modelValue.value);
|
|
19
|
+
|
|
20
|
+
const localChecked = ref<boolean>(value.value);
|
|
21
|
+
watch(value, (v) => {
|
|
22
|
+
localChecked.value = v;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const inputName = props.name ?? "switch-button";
|
|
26
|
+
const inputId = `switch-${inputName}`;
|
|
27
|
+
const inputRef = ref<HTMLInputElement | null>(null);
|
|
28
|
+
|
|
29
|
+
const activateByKeyboard = () => {
|
|
30
|
+
inputRef.value?.click();
|
|
31
|
+
};
|
|
32
|
+
const toggleState = (next?: boolean) => {
|
|
33
|
+
if (props.disabled) return;
|
|
34
|
+
const v = typeof next === "boolean" ? next : !localChecked.value;
|
|
35
|
+
localChecked.value = v;
|
|
36
|
+
modelValue.value = v;
|
|
37
|
+
emits("change", v);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const activateByClick = (ev?: Event) => {
|
|
41
|
+
ev?.stopPropagation();
|
|
42
|
+
toggleState();
|
|
43
|
+
};
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="w-full inline-flex flex-col justify-start items-start gap-2">
|
|
48
|
+
<div class="self-stretch inline-flex justify-start items-center gap-3">
|
|
49
|
+
<!-- left label that toggles the input via for="#inputId" -->
|
|
50
|
+
<label :for="inputId"
|
|
51
|
+
class="flex-1 flex justify-start items-center gap-1 text-surface-on-surface text-base font-normal leading-normal cursor-pointer"
|
|
52
|
+
:class="{ 'cursor-not-allowed': disabled }">
|
|
53
|
+
<span v-if="$slots.default">
|
|
54
|
+
<slot />
|
|
55
|
+
</span>
|
|
56
|
+
<span v-else-if="label">{{ label }}</span>
|
|
57
|
+
</label>
|
|
58
|
+
|
|
59
|
+
<div class="w-10 h-6 relative">
|
|
60
|
+
<label class="inline-block cursor-pointer" :class="{ 'cursor-not-allowed': disabled }">
|
|
61
|
+
<input ref="inputRef" :id="inputId" type="checkbox" :name="inputName" class="sr-only" :checked="localChecked"
|
|
62
|
+
@change="toggleState()"
|
|
63
|
+
:disabled="disabled" :aria-label="ariaLabel || undefined" v-bind="$attrs" />
|
|
64
|
+
<span role="switch" :aria-checked="localChecked" :tabindex="disabled ? -1 : 0"
|
|
65
|
+
class="w-10 h-6 relative rounded-full flex-shrink-0 inline-block switch-track cursor-pointer"
|
|
66
|
+
:class="localChecked ? 'bg-brand-secondary switch-track--on' : 'bg-surface-surface-container-highest'"
|
|
67
|
+
@keydown.space.prevent="activateByKeyboard" @click.prevent="activateByClick">
|
|
68
|
+
<span class="w-4 h-4 rounded-full absolute switch-knob"
|
|
69
|
+
:style="{ left: localChecked ? '19px' : '4px', top: '4px' }"
|
|
70
|
+
:class="localChecked ? 'bg-brand-on-secondary' : 'bg-surface-on-surface-variant'"></span>
|
|
71
|
+
</span>
|
|
72
|
+
</label>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<div v-if="description || $slots.description" class="self-stretch inline-flex justify-start items-center gap-2.5">
|
|
76
|
+
<div class="flex-1 justify-start text-surface-on-surface-variant text-sm font-normal leading-tight">
|
|
77
|
+
<slot name="description">{{ description }}</slot>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<style scoped>
|
|
84
|
+
.switch-track {
|
|
85
|
+
transition: background-color 180ms ease-in-out, box-shadow 180ms ease-in-out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.switch-track--on {
|
|
89
|
+
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.08);
|
|
90
|
+
/* subtle glow when on */
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.switch-knob {
|
|
94
|
+
transition: left 180ms cubic-bezier(.2, .9, .2, 1), top 180ms cubic-bezier(.2, .9, .2, 1), background-color 120ms linear;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.switch-track:focus {
|
|
98
|
+
outline: none;
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
withDefaults(
|
|
3
|
+
defineProps<{
|
|
4
|
+
filled?: boolean;
|
|
5
|
+
}>(),
|
|
6
|
+
{
|
|
7
|
+
filled: false,
|
|
8
|
+
},
|
|
9
|
+
);
|
|
10
|
+
</script>
|
|
11
|
+
<template>
|
|
12
|
+
<div class="relative">
|
|
13
|
+
<!-- use when filled icon is ready -->
|
|
14
|
+
<!-- <Icon size="1rem" name="shopware:heart" v-if="type !== 'filled'" class="w-6 h-5 block hover:cursor-pointer" :class="[
|
|
15
|
+
styles[type]
|
|
16
|
+
]" /> -->
|
|
17
|
+
<div class="i-carbon-favorite w-6 h-5 hover:cursor-pointer" v-if="!filled"></div>
|
|
18
|
+
<div class="i-carbon-favorite-filled w-6 h-5 hover:cursor-pointer" v-else></div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useAppConfig } from "nuxt/app";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable that provides an SVG placeholder image as a data URI
|
|
5
|
+
* Note: CSS variables and currentColor don't work in data URIs since SVGs are rendered in isolation
|
|
6
|
+
*
|
|
7
|
+
* @param color - Hex color for the placeholder (optional - defaults to appConfig.imagePlaceholder.color or #543B95)
|
|
8
|
+
* @returns Base64-encoded SVG data URI
|
|
9
|
+
*/
|
|
10
|
+
export function useImagePlaceholder(color?: string) {
|
|
11
|
+
const appConfig = useAppConfig();
|
|
12
|
+
const placeholderColor =
|
|
13
|
+
color || appConfig.imagePlaceholder?.color || "#543B95";
|
|
14
|
+
|
|
15
|
+
const placeholderSvg = `data:image/svg+xml;base64,${btoa(
|
|
16
|
+
`
|
|
17
|
+
<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
18
|
+
<rect width="96" height="96" rx="8" fill="${placeholderColor}" opacity="0.08"/>
|
|
19
|
+
<g transform="translate(36, 36)">
|
|
20
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 22H21C21.5523 22 22 21.5523 22 21V17L17.7071 12.7071C17.3166 12.3166 16.6834 12.3166 16.2929 12.7071L10.5 18.5C10.2239 18.7761 9.77614 18.7761 9.5 18.5C9.22386 18.2239 9.22386 17.7761 9.5 17.5L11 16L8.70711 13.7071C8.31658 13.3166 7.68342 13.3166 7.29289 13.7071L2 19V21C2 21.5523 2.44772 22 3 22ZM21 24H3C1.34315 24 0 22.6569 0 21V3C0 1.34315 1.34315 0 3 0H21C22.6569 0 24 1.34315 24 3V21C24 22.6569 22.6569 24 21 24ZM6.5 9C7.88071 9 9 7.88071 9 6.5C9 5.11929 7.88071 4 6.5 4C5.11929 4 4 5.11929 4 6.5C4 7.88071 5.11929 9 6.5 9Z" fill="${placeholderColor}" opacity="0.4"/>
|
|
21
|
+
</g>
|
|
22
|
+
</svg>
|
|
23
|
+
`.trim(),
|
|
24
|
+
)}`;
|
|
25
|
+
|
|
26
|
+
return placeholderSvg;
|
|
27
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { defineComponent, onMounted, ref } from "vue";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated This component is deprecated and will be removed in the next major release.
|
|
5
|
+
* Use Nuxt's built-in `<ClientOnly>` component instead.
|
|
6
|
+
* @see https://nuxt.com/docs/api/components/client-only
|
|
7
|
+
*/
|
|
3
8
|
export const ClientOnly = defineComponent({
|
|
4
9
|
setup(_, { slots }) {
|
|
5
10
|
const init = ref(false);
|