@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.
Files changed (184) hide show
  1. package/README.md +328 -13
  2. package/app/app.config.ts +7 -0
  3. package/app/assets/icons/check-circle.svg +3 -0
  4. package/app/assets/icons/checkmark.svg +3 -0
  5. package/app/assets/icons/chevron.svg +3 -0
  6. package/app/assets/icons/exclamation-circle.svg +3 -0
  7. package/app/assets/icons/star-empty.svg +3 -0
  8. package/app/assets/icons/star-filled.svg +3 -0
  9. package/app/assets/icons/user.svg +1 -0
  10. package/app/components/SwCategoryNavigation.vue +76 -0
  11. package/app/components/SwCategoryNavigationLink.vue +128 -0
  12. package/{components → app/components}/SwContactForm.vue +27 -27
  13. package/app/components/SwFilterChips.vue +144 -0
  14. package/app/components/SwListingProductPrice.vue +89 -0
  15. package/{components → app/components}/SwNewsletterForm.vue +45 -34
  16. package/{components → app/components}/SwPagination.vue +3 -5
  17. package/{components → app/components}/SwProductAddToCart.vue +22 -27
  18. package/app/components/SwProductCard.vue +170 -0
  19. package/app/components/SwProductCardDetails.vue +57 -0
  20. package/app/components/SwProductCardImage.vue +87 -0
  21. package/app/components/SwProductCardSkeleton.vue +33 -0
  22. package/app/components/SwProductListingFilter.vue +64 -0
  23. package/app/components/SwProductListingFilters.vue +308 -0
  24. package/{components → app/components}/SwProductReviews.vue +28 -13
  25. package/app/components/SwProductReviewsForm.vue +292 -0
  26. package/app/components/SwQuantitySelect.vue +106 -0
  27. package/{components → app/components}/SwSlider.vue +4 -4
  28. package/app/components/SwSortDropdown.vue +83 -0
  29. package/app/components/SwStockInfo.vue +44 -0
  30. package/{components → app/components}/SwVariantConfigurator.vue +1 -1
  31. package/app/components/listing-filters/SwFilterPrice.vue +214 -0
  32. package/app/components/listing-filters/SwFilterProperties.vue +113 -0
  33. package/app/components/listing-filters/SwFilterRating.vue +90 -0
  34. package/app/components/listing-filters/SwFilterShippingFree.vue +107 -0
  35. package/{components → app/components}/public/cms/CmsPage.vue +19 -4
  36. package/{components → app/components}/public/cms/block/CmsBlockGalleryBuybox.vue +5 -5
  37. package/{components → app/components}/public/cms/block/CmsBlockImageBubbleRow.vue +5 -5
  38. package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +41 -0
  39. package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +42 -0
  40. package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +37 -0
  41. package/{components → app/components}/public/cms/block/CmsBlockImageSimpleGrid.vue +11 -5
  42. package/{components → app/components}/public/cms/block/CmsBlockImageText.vue +7 -3
  43. package/{components → app/components}/public/cms/block/CmsBlockImageTextBubble.vue +13 -16
  44. package/{components → app/components}/public/cms/block/CmsBlockImageTextCover.vue +7 -9
  45. package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +88 -0
  46. package/app/components/public/cms/block/CmsBlockImageTextRow.vue +53 -0
  47. package/{components → app/components}/public/cms/block/CmsBlockImageThreeColumn.vue +10 -4
  48. package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +37 -0
  49. package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +37 -0
  50. package/{components → app/components}/public/cms/block/CmsBlockProductHeading.vue +1 -1
  51. package/{components → app/components}/public/cms/block/CmsBlockProductThreeColumn.vue +10 -4
  52. package/{components → app/components}/public/cms/block/CmsBlockSidebarFilter.vue +3 -1
  53. package/app/components/public/cms/block/CmsBlockTextOnImage.vue +30 -0
  54. package/{components → app/components}/public/cms/block/CmsBlockTextTeaserSection.vue +4 -4
  55. package/{components → app/components}/public/cms/block/CmsBlockTextTwoColumn.vue +3 -5
  56. package/app/components/public/cms/element/CmsElementBuyBox.vue +145 -0
  57. package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +53 -0
  58. package/{components → app/components}/public/cms/element/CmsElementCrossSelling.vue +3 -3
  59. package/{components → app/components}/public/cms/element/CmsElementImage.vue +52 -13
  60. package/app/components/public/cms/element/CmsElementImageGallery.vue +158 -0
  61. package/{components → app/components}/public/cms/element/CmsElementImageSlider.vue +2 -2
  62. package/{components → app/components}/public/cms/element/CmsElementProductBox.vue +2 -1
  63. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +217 -0
  64. package/{components → app/components}/public/cms/element/CmsElementProductListing.vue +23 -94
  65. package/app/components/public/cms/element/CmsElementProductName.vue +11 -0
  66. package/{components → app/components}/public/cms/element/CmsElementProductSlider.vue +4 -4
  67. package/{components → app/components}/public/cms/element/CmsElementText.vue +8 -2
  68. package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.vue +8 -2
  69. package/app/components/public/cms/element/SwProductListingPagination.vue +70 -0
  70. package/{components → app/components}/public/cms/section/CmsSectionDefault.vue +1 -1
  71. package/app/components/public/cms/section/CmsSectionSidebar.vue +36 -0
  72. package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +28 -0
  73. package/app/components/ui/BaseButton.vue +99 -0
  74. package/app/components/ui/BaseIcon.vue +15 -0
  75. package/app/components/ui/Checkbox.vue +49 -0
  76. package/app/components/ui/CheckmarkIcon.vue +23 -0
  77. package/app/components/ui/ChevronIcon.vue +37 -0
  78. package/app/components/ui/ExclamationIcon.vue +11 -0
  79. package/app/components/ui/IconButton.vue +32 -0
  80. package/app/components/ui/RadioButton.vue +26 -0
  81. package/app/components/ui/StarIcon.vue +18 -0
  82. package/app/components/ui/SwitchButton.vue +100 -0
  83. package/app/components/ui/UserIcon.vue +11 -0
  84. package/app/components/ui/WishlistIcon.vue +20 -0
  85. package/app/composables/useImagePlaceholder.ts +27 -0
  86. package/{helpers → app/helpers}/clientOnly.ts +5 -0
  87. package/app/providers/shopware.test.ts +213 -0
  88. package/app/providers/shopware.ts +107 -0
  89. package/dist/index.d.mts +3 -3
  90. package/dist/index.d.ts +3 -3
  91. package/dist/index.mjs +2 -2
  92. package/index.d.ts +12 -0
  93. package/nuxt.config.ts +80 -6
  94. package/package.json +29 -21
  95. package/uno.config.ts +83 -0
  96. package/components/SwCategoryNavigation.vue +0 -44
  97. package/components/SwCategoryNavigationLink.vue +0 -57
  98. package/components/SwListingProductPrice.vue +0 -89
  99. package/components/SwProductCard.vue +0 -286
  100. package/components/SwProductListingFilter.vue +0 -42
  101. package/components/SwProductListingFilters.vue +0 -292
  102. package/components/listing-filters/SwFilterPrice.vue +0 -160
  103. package/components/listing-filters/SwFilterProperties.vue +0 -123
  104. package/components/listing-filters/SwFilterRating.vue +0 -101
  105. package/components/listing-filters/SwFilterShippingFree.vue +0 -104
  106. package/components/public/cms/block/CmsBlockImageFourColumn.vue +0 -29
  107. package/components/public/cms/block/CmsBlockImageHighlightRow.vue +0 -27
  108. package/components/public/cms/block/CmsBlockImageTextGallery.vue +0 -85
  109. package/components/public/cms/block/CmsBlockImageTextRow.vue +0 -43
  110. package/components/public/cms/block/CmsBlockImageThreeCover.vue +0 -27
  111. package/components/public/cms/block/CmsBlockImageTwoColumn.vue +0 -25
  112. package/components/public/cms/block/CmsBlockTextOnImage.vue +0 -20
  113. package/components/public/cms/element/CmsBlockHtml.md +0 -1
  114. package/components/public/cms/element/CmsElementBuyBox.vue +0 -190
  115. package/components/public/cms/element/CmsElementCategoryNavigation.vue +0 -167
  116. package/components/public/cms/element/CmsElementImageGallery.vue +0 -249
  117. package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +0 -123
  118. package/components/public/cms/element/CmsElementProductName.vue +0 -10
  119. package/components/public/cms/section/CmsSectionSidebar.vue +0 -49
  120. package/components/public/cms/skeleton/ProductCardSkeleton.vue +0 -44
  121. /package/{components → app/components}/SwMedia3D.vue +0 -0
  122. /package/{components → app/components}/SwProductGallery.vue +0 -0
  123. /package/{components → app/components}/SwProductPrice.vue +0 -0
  124. /package/{components → app/components}/SwProductUnits.vue +0 -0
  125. /package/{components → app/components}/SwSharedPrice.vue +0 -0
  126. /package/{components → app/components}/public/cms/CmsGenericBlock.md +0 -0
  127. /package/{components → app/components}/public/cms/CmsGenericBlock.vue +0 -0
  128. /package/{components → app/components}/public/cms/CmsGenericElement.md +0 -0
  129. /package/{components → app/components}/public/cms/CmsGenericElement.vue +0 -0
  130. /package/{components → app/components}/public/cms/CmsNoComponent.vue +0 -0
  131. /package/{components → app/components}/public/cms/CmsPage.md +0 -0
  132. /package/{components → app/components}/public/cms/block/CmsBlockCategoryNavigation.vue +0 -0
  133. /package/{components → app/components}/public/cms/block/CmsBlockCenterText.vue +0 -0
  134. /package/{components → app/components}/public/cms/block/CmsBlockCrossSelling.vue +0 -0
  135. /package/{components → app/components}/public/cms/block/CmsBlockCustomForm.vue +0 -0
  136. /package/{components → app/components}/public/cms/block/CmsBlockDefault.vue +0 -0
  137. /package/{components → app/components}/public/cms/block/CmsBlockForm.vue +0 -0
  138. /package/{components/public/cms/element → app/components/public/cms/block}/CmsBlockHtml.vue +0 -0
  139. /package/{components → app/components}/public/cms/block/CmsBlockImage.vue +0 -0
  140. /package/{components → app/components}/public/cms/block/CmsBlockImageCover.vue +0 -0
  141. /package/{components → app/components}/public/cms/block/CmsBlockImageGallery.vue +0 -0
  142. /package/{components → app/components}/public/cms/block/CmsBlockImageSlider.vue +0 -0
  143. /package/{components → app/components}/public/cms/block/CmsBlockProductDescriptionReviews.vue +0 -0
  144. /package/{components → app/components}/public/cms/block/CmsBlockProductListing.vue +0 -0
  145. /package/{components → app/components}/public/cms/block/CmsBlockProductSlider.vue +0 -0
  146. /package/{components → app/components}/public/cms/block/CmsBlockText.vue +0 -0
  147. /package/{components → app/components}/public/cms/block/CmsBlockTextHero.vue +0 -0
  148. /package/{components → app/components}/public/cms/block/CmsBlockTextTeaser.vue +0 -0
  149. /package/{components → app/components}/public/cms/block/CmsBlockTextThreeColumn.vue +0 -0
  150. /package/{components → app/components}/public/cms/block/CmsBlockVimeoVideo.vue +0 -0
  151. /package/{components → app/components}/public/cms/block/CmsBlockYoutubeVideo.vue +0 -0
  152. /package/{components → app/components}/public/cms/element/CmsElementBuyBox.md +0 -0
  153. /package/{components → app/components}/public/cms/element/CmsElementCategoryNavigation.md +0 -0
  154. /package/{components → app/components}/public/cms/element/CmsElementCrossSelling.md +0 -0
  155. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.md +0 -0
  156. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.vue +0 -0
  157. /package/{components → app/components}/public/cms/element/CmsElementForm.md +0 -0
  158. /package/{components → app/components}/public/cms/element/CmsElementForm.vue +0 -0
  159. /package/{components → app/components}/public/cms/element/CmsElementHtml.vue +0 -0
  160. /package/{components → app/components}/public/cms/element/CmsElementImage.md +0 -0
  161. /package/{components → app/components}/public/cms/element/CmsElementImageGallery.md +0 -0
  162. /package/{components → app/components}/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +0 -0
  163. /package/{components → app/components}/public/cms/element/CmsElementImageSlider.md +0 -0
  164. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.md +0 -0
  165. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.vue +0 -0
  166. /package/{components → app/components}/public/cms/element/CmsElementProductBox.md +0 -0
  167. /package/{components → app/components}/public/cms/element/CmsElementProductDescriptionReviews.md +0 -0
  168. /package/{components → app/components}/public/cms/element/CmsElementProductListing.md +0 -0
  169. /package/{components → app/components}/public/cms/element/CmsElementProductName.md +0 -0
  170. /package/{components → app/components}/public/cms/element/CmsElementProductSlider.md +0 -0
  171. /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.md +0 -0
  172. /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.vue +0 -0
  173. /package/{components → app/components}/public/cms/element/CmsElementText.md +0 -0
  174. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.md +0 -0
  175. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.vue +0 -0
  176. /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.md +0 -0
  177. /package/{components → app/components}/public/cms/section/CmsSectionDefault.md +0 -0
  178. /package/{components → app/components}/public/cms/section/CmsSectionSidebar.md +0 -0
  179. /package/{helpers → app/helpers}/html-to-vue/ast.ts +0 -0
  180. /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.test.ts +0 -0
  181. /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.ts +0 -0
  182. /package/{helpers → app/helpers}/html-to-vue/renderToHtml.ts +0 -0
  183. /package/{helpers → app/helpers}/html-to-vue/renderer.ts +0 -0
  184. /package/{helpers → app/helpers}/media/isSpatial.ts +0 -0
@@ -0,0 +1,107 @@
1
+ <script
2
+ setup
3
+ lang="ts"
4
+ generic="
5
+ ListingFilter extends {
6
+ id: string;
7
+ code: keyof Schemas['ProductListingResult']['currentFilters'];
8
+ label: string;
9
+ name: string;
10
+ }
11
+ "
12
+ >
13
+ import { useCmsTranslations } from "@shopware/composables";
14
+ import { onClickOutside } from "@vueuse/core";
15
+ import { defu } from "defu";
16
+ import { computed, ref } from "vue";
17
+ import type { Schemas } from "#shopware";
18
+
19
+ const props = defineProps<{
20
+ filter: ListingFilter;
21
+ selectedFilters: Schemas["ProductListingResult"]["currentFilters"];
22
+ description?: string; // Optional description for i18n
23
+ }>();
24
+
25
+ type Translations = {
26
+ listing: {
27
+ freeShipping: string;
28
+ };
29
+ };
30
+ let translations: Translations = {
31
+ listing: {
32
+ freeShipping: "Free shipping",
33
+ },
34
+ };
35
+ translations = defu(useCmsTranslations(), translations) as Translations;
36
+
37
+ const emits =
38
+ defineEmits<
39
+ (e: "select-value", value: { code: string; value: unknown }) => void
40
+ >();
41
+ const currentFilterData = computed(
42
+ () => !!props.selectedFilters[props.filter?.code],
43
+ );
44
+
45
+ const isFilterVisible = ref<boolean>(false);
46
+ const toggle = () => {
47
+ isFilterVisible.value = !isFilterVisible.value;
48
+ };
49
+
50
+ const dropdownElement = ref(null);
51
+ onClickOutside(dropdownElement, () => {
52
+ isFilterVisible.value = false;
53
+ });
54
+
55
+ const handleRadioUpdate = (val: string | null | boolean | undefined) => {
56
+ emits("select-value", { code: props.filter.code, value: !!val });
57
+ };
58
+ </script>
59
+
60
+ <template>
61
+ <div class="self-stretch flex flex-col justify-start items-start gap-4">
62
+ <div class="self-stretch flex flex-col justify-center items-center">
63
+ <div
64
+ class="self-stretch py-3 border-b border-outline-outline-variant inline-flex justify-between items-center gap-1 cursor-pointer"
65
+ @click="toggle"
66
+ role="button"
67
+ tabindex="0"
68
+ :aria-expanded="isFilterVisible"
69
+ :aria-controls="`filter-${props.filter.code}`"
70
+ @keydown.enter="toggle"
71
+ @keydown.space.prevent="toggle"
72
+ >
73
+ <div class="flex-1 flex items-center gap-2.5">
74
+ <div class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left">
75
+ {{ props.filter.label }}
76
+ </div>
77
+ </div>
78
+ <SwIconButton
79
+ type="ghost"
80
+ :aria-label="isFilterVisible ? 'Collapse filter' : 'Expand filter'"
81
+ tabindex="-1"
82
+ >
83
+ <SwChevronIcon :direction="isFilterVisible ? 'up' : 'down'" :size="24" />
84
+ </SwIconButton>
85
+ </div>
86
+ </div>
87
+
88
+ <transition name="filter-collapse">
89
+ <div v-if="isFilterVisible" class="self-stretch">
90
+ <div class="pt-6 space-y-4">
91
+ <div class="self-stretch inline-flex justify-start items-start gap-2 w-full">
92
+ <div class="flex-1 pt-[3px]">
93
+ <SwSwitchButton
94
+ :model-value="currentFilterData"
95
+ @update:model-value="handleRadioUpdate"
96
+ :name="props.filter.code"
97
+ :aria-label="props.filter.label"
98
+ :label="props.filter.label"
99
+ :description="props.description || translations.listing.freeShipping"
100
+ />
101
+ </div>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </transition>
106
+ </div>
107
+ </template>
@@ -2,9 +2,10 @@
2
2
  import {
3
3
  getBackgroundImageUrl,
4
4
  getCmsLayoutConfiguration,
5
+ getProductListingFromCmsPage,
5
6
  } from "@shopware/helpers";
6
7
  import { pascalCase } from "scule";
7
- import { computed, h, resolveComponent } from "vue";
8
+ import { computed, h, resolveComponent, watchEffect } from "vue";
8
9
  import { createCategoryListingContext, useNavigationContext } from "#imports";
9
10
  import type { Schemas } from "#shopware";
10
11
 
@@ -13,10 +14,24 @@ const props = defineProps<{
13
14
  }>();
14
15
 
15
16
  const { routeName } = useNavigationContext();
16
- if (routeName.value === "frontend.navigation.page") {
17
- createCategoryListingContext();
17
+
18
+ // Function to initialize or update listing context
19
+ function updateListingContext(content: Schemas["CmsPage"]) {
20
+ if (routeName.value === "frontend.navigation.page") {
21
+ const initialListing =
22
+ getProductListingFromCmsPage<Schemas["ProductListingResult"]>(content);
23
+
24
+ if (initialListing) {
25
+ createCategoryListingContext(initialListing);
26
+ }
27
+ }
18
28
  }
19
29
 
30
+ // Watch for content changes and update context
31
+ watchEffect(() => {
32
+ updateListingContext(props.content);
33
+ });
34
+
20
35
  const cmsSections = computed<Schemas["CmsSection"][]>(() => {
21
36
  return props.content?.sections || [];
22
37
  });
@@ -48,7 +63,7 @@ const DynamicRender = () => {
48
63
  content: componentObject.section,
49
64
  class: {
50
65
  ...cssClasses,
51
- "max-w-screen-2xl mx-auto": layoutStyles?.sizingMode === "boxed",
66
+ "max-w-screen-2xl w-full mx-auto": layoutStyles?.sizingMode === "boxed",
52
67
  },
53
68
  style: {
54
69
  backgroundColor: layoutStyles?.backgroundColor,
@@ -12,13 +12,13 @@ const leftContent = getSlotContent("left");
12
12
  </script>
13
13
 
14
14
  <template>
15
- <div
16
- class="lg:container mx-auto flex flex-col lg:flex-row gap-10 justify-center"
17
- >
18
- <div class="overflow-hidden basis-4/6">
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
+ <!-- Gallery Section -->
17
+ <div class="w-full lg:w-3/5">
19
18
  <CmsGenericElement :content="leftContent" />
20
19
  </div>
21
- <div class="basis-2/6">
20
+ <!-- Buybox Section -->
21
+ <div class="w-full lg:w-2/5">
22
22
  <CmsGenericElement :content="rightContent" />
23
23
  </div>
24
24
  </div>
@@ -13,20 +13,20 @@ const rightContent = getSlotContent("right");
13
13
  const centerContent = getSlotContent("center");
14
14
  </script>
15
15
  <template>
16
- <div class="cms-block-image-bubble-row grid md:grid-cols-3 gap-10">
17
- <div class="flex items-center justify-center">
16
+ <div class="cms-block-image-bubble-row flex flex-col sm:flex-row justify-start items-start gap-6 w-full">
17
+ <div class="w-full sm:flex-1 flex items-center justify-center">
18
18
  <CmsGenericElement :content="leftContent" class="w-full" />
19
19
  </div>
20
- <div class="flex items-center justify-center">
20
+ <div class="w-full sm:flex-1 flex items-center justify-center">
21
21
  <CmsGenericElement :content="centerContent" class="w-full" />
22
22
  </div>
23
- <div class="flex items-center justify-center">
23
+ <div class="w-full sm:flex-1 flex items-center justify-center">
24
24
  <CmsGenericElement :content="rightContent" class="w-full" />
25
25
  </div>
26
26
  </div>
27
27
  </template>
28
28
  <style scoped>
29
- .cms-block-image-bubble-row .cms-element-image {
29
+ .cms-block-image-bubble-row :deep(.cms-element-image) {
30
30
  @apply object-cover max-w-xs overflow-hidden rounded-full aspect-square;
31
31
  }
32
32
  </style>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockImageFourColumn } from "@shopware/composables";
3
+ import { useCmsBlock } from "#imports";
4
+
5
+ const props = defineProps<{
6
+ content: CmsBlockImageFourColumn;
7
+ }>();
8
+
9
+ const { getSlotContent } = useCmsBlock(props.content);
10
+
11
+ const leftContent = getSlotContent("left");
12
+ const rightContent = getSlotContent("right");
13
+ const centerLeftContent = getSlotContent("center-left");
14
+ const centerRightContent = getSlotContent("center-right");
15
+ </script>
16
+ <template>
17
+ <div class="cms-block-image-four-column flex flex-col sm:flex-row sm:flex-wrap lg:flex-nowrap justify-start items-start gap-6 w-full">
18
+ <div class="w-full sm:w-[calc(50%-12px)] lg:flex-1">
19
+ <CmsGenericElement :content="leftContent" />
20
+ </div>
21
+ <div class="w-full sm:w-[calc(50%-12px)] lg:flex-1">
22
+ <CmsGenericElement :content="centerLeftContent" />
23
+ </div>
24
+ <div class="w-full sm:w-[calc(50%-12px)] lg:flex-1">
25
+ <CmsGenericElement :content="centerRightContent" />
26
+ </div>
27
+ <div class="w-full sm:w-[calc(50%-12px)] lg:flex-1">
28
+ <CmsGenericElement :content="rightContent" />
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <style scoped>
34
+ .cms-block-image-four-column :deep(.cms-element-image) {
35
+ @apply relative h-full w-full;
36
+ }
37
+
38
+ .cms-block-image-four-column :deep(.cms-element-image img) {
39
+ @apply w-full h-full object-cover;
40
+ }
41
+ </style>
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockImageGalleryBig } from "@shopware/composables";
3
+ import { useCmsBlock } from "#imports";
4
+
5
+ const props = defineProps<{
6
+ content: CmsBlockImageGalleryBig;
7
+ }>();
8
+
9
+ const { getSlotContent } = useCmsBlock(props.content);
10
+
11
+ const cmsContent = getSlotContent("imageGallery");
12
+ </script>
13
+
14
+ <template>
15
+ <div class="cms-block-image-gallery-big">
16
+ <CmsGenericElement :content="cmsContent" />
17
+ </div>
18
+ </template>
19
+
20
+ <style scoped>
21
+ .cms-block-image-gallery-big {
22
+ @apply w-full;
23
+ }
24
+
25
+ .cms-block-image-gallery-big :deep(.cms-element-image-gallery) {
26
+ @apply max-w-screen-xl mx-auto;
27
+ }
28
+
29
+ /* Enhanced styling for the big gallery version */
30
+ .cms-block-image-gallery-big :deep(.gallery-slider) {
31
+ @apply max-h-[800px];
32
+ }
33
+
34
+ .cms-block-image-gallery-big :deep(img) {
35
+ @apply object-contain mx-auto;
36
+ }
37
+
38
+ /* Larger navigation controls */
39
+ .cms-block-image-gallery-big :deep(.gallery-slider-controls) {
40
+ @apply scale-125;
41
+ }
42
+ </style>
@@ -0,0 +1,37 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockImageHighlightRow } from "@shopware/composables";
3
+ import { useCmsBlock } from "#imports";
4
+
5
+ const props = defineProps<{
6
+ content: CmsBlockImageHighlightRow;
7
+ }>();
8
+
9
+ const { getSlotContent } = useCmsBlock(props.content);
10
+
11
+ const leftContent = getSlotContent("left");
12
+ const rightContent = getSlotContent("right");
13
+ const centerContent = getSlotContent("center");
14
+ </script>
15
+ <template>
16
+ <div class="cms-block-image-highlight-row flex flex-col sm:flex-row justify-start items-start gap-6 w-full">
17
+ <div class="w-full sm:flex-1">
18
+ <CmsGenericElement :content="leftContent" />
19
+ </div>
20
+ <div class="w-full sm:flex-1">
21
+ <CmsGenericElement :content="centerContent" />
22
+ </div>
23
+ <div class="w-full sm:flex-1">
24
+ <CmsGenericElement :content="rightContent" />
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <style scoped>
30
+ .cms-block-image-highlight-row :deep(.cms-element-image) {
31
+ @apply relative h-full w-full border-[12px] border-surface-surface;
32
+ }
33
+
34
+ .cms-block-image-highlight-row :deep(.cms-element-image img) {
35
+ @apply w-full h-full object-cover;
36
+ }
37
+ </style>
@@ -14,11 +14,17 @@ const rightContent = getSlotContent("right");
14
14
  </script>
15
15
 
16
16
  <template>
17
- <div class="grid md:grid-cols-2 gap-10">
18
- <div class="grid gap-10">
19
- <CmsGenericElement :content="leftTopContent" />
20
- <CmsGenericElement :content="leftBottomContent" />
17
+ <div class="flex flex-col md:flex-row justify-start items-start gap-6 w-full">
18
+ <div class="w-full md:flex-1 flex flex-col justify-start items-start gap-6">
19
+ <div class="w-full">
20
+ <CmsGenericElement :content="leftTopContent" />
21
+ </div>
22
+ <div class="w-full">
23
+ <CmsGenericElement :content="leftBottomContent" />
24
+ </div>
25
+ </div>
26
+ <div class="w-full md:flex-1">
27
+ <CmsGenericElement :content="rightContent" />
21
28
  </div>
22
- <CmsGenericElement :content="rightContent" />
23
29
  </div>
24
30
  </template>
@@ -12,8 +12,12 @@ const leftContent = getSlotContent("left");
12
12
  const rightContent = getSlotContent("right");
13
13
  </script>
14
14
  <template>
15
- <div class="grid md:grid-cols-2 gap-10">
16
- <CmsGenericElement :content="leftContent" />
17
- <CmsGenericElement :content="rightContent" />
15
+ <div class="flex flex-col md:flex-row justify-start items-start gap-6 w-full">
16
+ <div class="w-full md:flex-1 p-4">
17
+ <CmsGenericElement :content="leftContent" />
18
+ </div>
19
+ <div class="w-full md:flex-1 p-4">
20
+ <CmsGenericElement :content="rightContent" />
21
+ </div>
18
22
  </div>
19
23
  </template>
@@ -16,36 +16,33 @@ const rightText = getSlotContent("right-text");
16
16
  const rightImage = getSlotContent("right-image");
17
17
  </script>
18
18
  <template>
19
- <div class="cms-block-image-text-bubble grid grid-cols-3 auto-cols-max">
20
- <div class="cms-element-column p-4">
21
- <div class="flex justify-center">
19
+ <div class="cms-block-image-text-bubble flex flex-col sm:flex-row justify-start items-start gap-6 w-full">
20
+ <div class="w-full sm:flex-1">
21
+ <div class="self-stretch flex justify-center">
22
22
  <CmsGenericElement
23
23
  :content="leftImage"
24
- class="object-center rounded-full"
25
- style="height: calc(100vw / 3 - 64px); width: calc(100vw / 3 - 64px)"
24
+ class="object-center rounded-full w-48 h-48 sm:w-56 sm:h-56 lg:w-64 lg:h-64"
26
25
  />
27
26
  </div>
28
- <CmsGenericElement :content="leftText" />
27
+ <CmsGenericElement :content="leftText" class="self-stretch" />
29
28
  </div>
30
- <div class="cms-element-column p-4">
31
- <div class="flex justify-center">
29
+ <div class="w-full sm:flex-1">
30
+ <div class="self-stretch flex justify-center">
32
31
  <CmsGenericElement
33
32
  :content="centerImage"
34
- class="object-center rounded-full"
35
- style="height: calc(100vw / 3 - 64px); width: calc(100vw / 3 - 64px)"
33
+ class="object-center rounded-full w-48 h-48 sm:w-56 sm:h-56 lg:w-64 lg:h-64"
36
34
  />
37
35
  </div>
38
- <CmsGenericElement :content="centerText" />
36
+ <CmsGenericElement :content="centerText" class="self-stretch" />
39
37
  </div>
40
- <div class="cms-element-column p-4">
41
- <div class="flex justify-center">
38
+ <div class="w-full sm:flex-1">
39
+ <div class="self-stretch flex justify-center">
42
40
  <CmsGenericElement
43
41
  :content="rightImage"
44
- class="object-center rounded-full"
45
- style="height: calc(100vw / 3 - 64px); width: calc(100vw / 3 - 64px)"
42
+ class="object-center rounded-full w-48 h-48 sm:w-56 sm:h-56 lg:w-64 lg:h-64"
46
43
  />
47
44
  </div>
48
- <CmsGenericElement :content="rightText" />
45
+ <CmsGenericElement :content="rightText" class="self-stretch" />
49
46
  </div>
50
47
  </div>
51
48
  </template>
@@ -12,14 +12,12 @@ const leftContent = getSlotContent("left");
12
12
  const rightContent = getSlotContent("right");
13
13
  </script>
14
14
  <template>
15
- <article class="md:grid md:grid-cols-2 gap-10">
16
- <CmsGenericElement
17
- :content="leftContent"
18
- class="cms-block-image-text-cover__image"
19
- />
20
- <CmsGenericElement
21
- :content="rightContent"
22
- class="cms-block-image-text-cover__text"
23
- />
15
+ <article class="flex flex-col md:flex-row justify-start items-start gap-6 w-full pb-6">
16
+ <div class="w-full md:flex-1 px-6 pt-6 md:px-0 md:pt-6 md:pl-6">
17
+ <CmsGenericElement :content="leftContent" />
18
+ </div>
19
+ <div class="w-full md:flex-1 px-6 pt-0 md:pt-6 pb-6 md:px-0 md:pr-6">
20
+ <CmsGenericElement :content="rightContent" />
21
+ </div>
24
22
  </article>
25
23
  </template>
@@ -0,0 +1,88 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ CmsBlockImageTextGallery,
4
+ CmsElementImage,
5
+ CmsElementText,
6
+ } from "@shopware/composables";
7
+ import { useCmsBlock } from "#imports";
8
+
9
+ const props = defineProps<{
10
+ content: CmsBlockImageTextGallery;
11
+ }>();
12
+
13
+ const { getSlotContent } = useCmsBlock(props.content);
14
+
15
+ const leftTextContent = getSlotContent("left-text") as CmsElementText;
16
+ const rightTextContent = getSlotContent("right-text") as CmsElementText;
17
+ const centerTextContent = getSlotContent("center-text") as CmsElementText;
18
+
19
+ const leftImageContent = getSlotContent(
20
+ "left-image",
21
+ ) as unknown as CmsElementImage;
22
+ const rightImageContent = getSlotContent(
23
+ "right-image",
24
+ ) as unknown as CmsElementImage;
25
+ const centerImageContent = getSlotContent(
26
+ "center-image",
27
+ ) as unknown as CmsElementImage;
28
+
29
+ // TODO: useRouter
30
+ function onImageClick(
31
+ slotContent: CmsElementImage & {
32
+ data: {
33
+ url?: string;
34
+ newTab?: boolean;
35
+ };
36
+ },
37
+ ) {
38
+ if (slotContent.data?.url) {
39
+ if (slotContent.data?.newTab) {
40
+ window.open(slotContent.data.url);
41
+ } else {
42
+ window.location.href = slotContent.data.url;
43
+ }
44
+ }
45
+ }
46
+ </script>
47
+ <template>
48
+ <article
49
+ class="cms-block-image-text-gallery flex flex-col sm:flex-row justify-start items-start gap-6 w-full"
50
+ :style="{ backgroundColor: content.backgroundColor || '' }"
51
+ >
52
+ <div class="w-full sm:flex-1">
53
+ <CmsElementImage
54
+ :content="leftImageContent"
55
+ :style="{ cursor: leftImageContent.data?.url && 'pointer' }"
56
+ @click="onImageClick(leftImageContent)"
57
+ />
58
+ <CmsElementText
59
+ :content="leftTextContent"
60
+ class="self-stretch"
61
+ />
62
+ </div>
63
+ <div class="w-full sm:flex-1">
64
+ <CmsElementImage
65
+ :content="centerImageContent"
66
+ :style="{
67
+ cursor: centerImageContent.data?.url && 'pointer',
68
+ }"
69
+ @click="onImageClick(centerImageContent)"
70
+ />
71
+ <CmsElementText
72
+ :content="centerTextContent"
73
+ class="self-stretch"
74
+ />
75
+ </div>
76
+ <div class="w-full sm:flex-1">
77
+ <CmsElementImage
78
+ :content="rightImageContent"
79
+ :style="{ cursor: rightImageContent.data?.url && 'pointer' }"
80
+ @click="onImageClick(rightImageContent)"
81
+ />
82
+ <CmsElementText
83
+ :content="rightTextContent"
84
+ class="self-stretch"
85
+ />
86
+ </div>
87
+ </article>
88
+ </template>
@@ -0,0 +1,53 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockImageTextRow } from "@shopware/composables";
3
+ import { useCmsBlock } from "#imports";
4
+
5
+ const props = defineProps<{
6
+ content: CmsBlockImageTextRow;
7
+ }>();
8
+
9
+ const { getSlotContent } = useCmsBlock(props.content);
10
+
11
+ const leftImageContent = getSlotContent("left-image");
12
+ const leftTextContent = getSlotContent("left-text");
13
+ const centerImageContent = getSlotContent("center-image");
14
+ const centerTextContent = getSlotContent("center-text");
15
+ const rightImageContent = getSlotContent("right-image");
16
+ const rightTextContent = getSlotContent("right-text");
17
+ </script>
18
+ <template>
19
+ <div class="cms-block-image-text-row flex flex-col md:flex-row justify-center items-stretch gap-6 w-full">
20
+ <div class="w-full md:flex-1 flex flex-col">
21
+ <div class="flex-1 mb-4 overflow-hidden rounded-lg min-h-64">
22
+ <CmsGenericElement :content="leftImageContent" />
23
+ </div>
24
+ <CmsGenericElement :content="leftTextContent" class="text-center" />
25
+ </div>
26
+ <div class="w-full md:flex-1 flex flex-col">
27
+ <div class="flex-1 mb-4 overflow-hidden rounded-lg min-h-64">
28
+ <CmsGenericElement :content="centerImageContent" />
29
+ </div>
30
+ <CmsGenericElement :content="centerTextContent" class="text-center" />
31
+ </div>
32
+ <div class="w-full md:flex-1 flex flex-col">
33
+ <div class="flex-1 mb-4 overflow-hidden rounded-lg min-h-64">
34
+ <CmsGenericElement :content="rightImageContent" />
35
+ </div>
36
+ <CmsGenericElement :content="rightTextContent" class="text-center" />
37
+ </div>
38
+ </div>
39
+ </template>
40
+
41
+ <style scoped>
42
+ .cms-block-image-text-row :deep(.cms-element-image) {
43
+ @apply relative h-full w-full;
44
+ }
45
+
46
+ .cms-block-image-text-row :deep(.cms-element-image img) {
47
+ @apply w-full h-full object-cover rounded-lg;
48
+ }
49
+
50
+ .cms-block-image-text-row :deep(.cms-element-text) {
51
+ @apply self-stretch min-h-12;
52
+ }
53
+ </style>
@@ -13,9 +13,15 @@ const rightContent = getSlotContent("right");
13
13
  const centerContent = getSlotContent("center");
14
14
  </script>
15
15
  <template>
16
- <div class="grid md:grid-cols-3 gap-10">
17
- <CmsGenericElement :content="leftContent" />
18
- <CmsGenericElement :content="centerContent" />
19
- <CmsGenericElement :content="rightContent" />
16
+ <div class="flex flex-col sm:flex-row justify-start items-start gap-6 w-full">
17
+ <div class="w-full sm:flex-1">
18
+ <CmsGenericElement :content="leftContent" />
19
+ </div>
20
+ <div class="w-full sm:flex-1">
21
+ <CmsGenericElement :content="centerContent" />
22
+ </div>
23
+ <div class="w-full sm:flex-1">
24
+ <CmsGenericElement :content="rightContent" />
25
+ </div>
20
26
  </div>
21
27
  </template>
@@ -0,0 +1,37 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockImageThreeCover } from "@shopware/composables";
3
+ import { useCmsBlock } from "#imports";
4
+
5
+ const props = defineProps<{
6
+ content: CmsBlockImageThreeCover;
7
+ }>();
8
+
9
+ const { getSlotContent } = useCmsBlock(props.content);
10
+
11
+ const leftContent = getSlotContent("left");
12
+ const rightContent = getSlotContent("right");
13
+ const centerContent = getSlotContent("center");
14
+ </script>
15
+ <template>
16
+ <div class="cms-block-image-three-cover flex flex-col sm:flex-row justify-start items-start gap-6 w-full">
17
+ <div class="w-full sm:flex-1">
18
+ <CmsGenericElement :content="leftContent" />
19
+ </div>
20
+ <div class="w-full sm:flex-1">
21
+ <CmsGenericElement :content="centerContent" />
22
+ </div>
23
+ <div class="w-full sm:flex-1">
24
+ <CmsGenericElement :content="rightContent" />
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <style scoped>
30
+ .cms-block-image-three-cover :deep(.cms-element-image) {
31
+ @apply aspect-square relative h-full w-full;
32
+ }
33
+
34
+ .cms-block-image-three-cover :deep(.cms-element-image img) {
35
+ @apply w-full h-full object-cover;
36
+ }
37
+ </style>