@shopware/cms-base-layer 1.5.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +398 -12
  2. package/app/app.config.ts +18 -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 +83 -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/SwFilterDropdown.vue +54 -0
  15. package/app/components/SwListingProductPrice.vue +89 -0
  16. package/{components → app/components}/SwMedia3D.vue +4 -2
  17. package/{components → app/components}/SwNewsletterForm.vue +45 -34
  18. package/{components → app/components}/SwPagination.vue +3 -5
  19. package/{components → app/components}/SwProductAddToCart.vue +22 -27
  20. package/app/components/SwProductCard.vue +169 -0
  21. package/app/components/SwProductCardDetails.vue +74 -0
  22. package/app/components/SwProductCardImage.vue +90 -0
  23. package/app/components/SwProductCardSkeleton.vue +33 -0
  24. package/app/components/SwProductGallery.vue +43 -0
  25. package/app/components/SwProductListingFilter.vue +75 -0
  26. package/app/components/SwProductListingFilters.vue +304 -0
  27. package/app/components/SwProductListingFiltersHorizontal.vue +306 -0
  28. package/{components → app/components}/SwProductPrice.vue +3 -3
  29. package/app/components/SwProductRating.vue +40 -0
  30. package/{components → app/components}/SwProductReviews.vue +25 -23
  31. package/app/components/SwProductReviewsForm.vue +292 -0
  32. package/{components → app/components}/SwProductUnits.vue +10 -15
  33. package/app/components/SwQuantitySelect.vue +103 -0
  34. package/{components → app/components}/SwSlider.vue +154 -55
  35. package/app/components/SwSortDropdown.vue +87 -0
  36. package/app/components/SwStockInfo.vue +44 -0
  37. package/{components → app/components}/SwVariantConfigurator.vue +13 -12
  38. package/app/components/listing-filters/SwFilterPrice.vue +219 -0
  39. package/app/components/listing-filters/SwFilterProperties.vue +120 -0
  40. package/app/components/listing-filters/SwFilterRating.vue +99 -0
  41. package/app/components/listing-filters/SwFilterShippingFree.vue +114 -0
  42. package/app/components/public/cms/CmsBlockSpatialViewer.vue +94 -0
  43. package/app/components/public/cms/CmsGenericBlock.md +42 -0
  44. package/{components → app/components}/public/cms/CmsGenericBlock.vue +15 -1
  45. package/{components → app/components}/public/cms/CmsPage.md +19 -2
  46. package/{components → app/components}/public/cms/CmsPage.vue +30 -5
  47. package/{components → app/components}/public/cms/block/CmsBlockCenterText.vue +1 -1
  48. package/{components → app/components}/public/cms/block/CmsBlockGalleryBuybox.vue +5 -5
  49. package/{components → app/components}/public/cms/block/CmsBlockImageBubbleRow.vue +5 -5
  50. package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +41 -0
  51. package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +42 -0
  52. package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +37 -0
  53. package/{components → app/components}/public/cms/block/CmsBlockImageSimpleGrid.vue +11 -5
  54. package/{components → app/components}/public/cms/block/CmsBlockImageText.vue +7 -3
  55. package/{components → app/components}/public/cms/block/CmsBlockImageTextBubble.vue +13 -16
  56. package/{components → app/components}/public/cms/block/CmsBlockImageTextCover.vue +7 -9
  57. package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +88 -0
  58. package/app/components/public/cms/block/CmsBlockImageTextRow.vue +53 -0
  59. package/{components → app/components}/public/cms/block/CmsBlockImageThreeColumn.vue +10 -4
  60. package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +37 -0
  61. package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +37 -0
  62. package/{components → app/components}/public/cms/block/CmsBlockProductHeading.vue +1 -1
  63. package/{components → app/components}/public/cms/block/CmsBlockProductThreeColumn.vue +10 -4
  64. package/{components → app/components}/public/cms/block/CmsBlockSidebarFilter.vue +3 -1
  65. package/{components → app/components}/public/cms/block/CmsBlockTextOnImage.vue +8 -5
  66. package/app/components/public/cms/element/CmsElementBuyBox.vue +145 -0
  67. package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +53 -0
  68. package/{components → app/components}/public/cms/element/CmsElementCrossSelling.vue +22 -6
  69. package/{components → app/components}/public/cms/element/CmsElementImage.vue +58 -21
  70. package/app/components/public/cms/element/CmsElementImageGallery.vue +225 -0
  71. package/{components → app/components}/public/cms/element/CmsElementImageSlider.vue +2 -2
  72. package/{components → app/components}/public/cms/element/CmsElementProductBox.vue +8 -1
  73. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +217 -0
  74. package/{components → app/components}/public/cms/element/CmsElementProductListing.vue +31 -95
  75. package/app/components/public/cms/element/CmsElementProductName.vue +16 -0
  76. package/app/components/public/cms/element/CmsElementProductSlider.vue +101 -0
  77. package/app/components/public/cms/element/CmsElementSidebarFilter.vue +20 -0
  78. package/{components → app/components}/public/cms/element/CmsElementText.vue +17 -12
  79. package/app/components/public/cms/element/SwProductListingPagination.vue +70 -0
  80. package/{components → app/components}/public/cms/section/CmsSectionDefault.vue +2 -2
  81. package/app/components/public/cms/section/CmsSectionSidebar.vue +39 -0
  82. package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +28 -0
  83. package/app/components/ui/BaseButton.vue +102 -0
  84. package/app/components/ui/BaseIcon.vue +15 -0
  85. package/app/components/ui/Checkbox.vue +49 -0
  86. package/app/components/ui/CheckmarkIcon.vue +23 -0
  87. package/app/components/ui/ChevronIcon.vue +34 -0
  88. package/app/components/ui/ExclamationIcon.vue +11 -0
  89. package/app/components/ui/IconButton.vue +32 -0
  90. package/app/components/ui/RadioButton.vue +26 -0
  91. package/app/components/ui/StarIcon.vue +18 -0
  92. package/app/components/ui/SwitchButton.vue +100 -0
  93. package/app/components/ui/UserIcon.vue +11 -0
  94. package/app/components/ui/WishlistIcon.vue +15 -0
  95. package/app/composables/useImagePlaceholder.ts +27 -0
  96. package/app/composables/useLcpImagePreload.test.ts +229 -0
  97. package/app/composables/useLcpImagePreload.ts +39 -0
  98. package/{helpers → app/helpers}/clientOnly.ts +5 -0
  99. package/app/helpers/cms/findFirstCmsImageUrl.ts +86 -0
  100. package/app/helpers/cms/getImageSizes.test.ts +50 -0
  101. package/app/helpers/cms/getImageSizes.ts +36 -0
  102. package/app/helpers/html-to-vue/ast.ts +106 -0
  103. package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.ts +1 -1
  104. package/{helpers → app/helpers}/html-to-vue/renderToHtml.ts +7 -11
  105. package/app/helpers/html-to-vue/renderer.ts +116 -0
  106. package/app/plugins/unocss-runtime.client.ts +23 -0
  107. package/app/providers/shopware.test.ts +213 -0
  108. package/app/providers/shopware.ts +107 -0
  109. package/dist/index.d.mts +3 -3
  110. package/dist/index.d.ts +3 -3
  111. package/dist/index.mjs +2 -2
  112. package/index.d.ts +36 -0
  113. package/nuxt.config.ts +100 -6
  114. package/package.json +33 -23
  115. package/uno.config.ts +94 -0
  116. package/components/SwCategoryNavigation.vue +0 -44
  117. package/components/SwCategoryNavigationLink.vue +0 -57
  118. package/components/SwListingProductPrice.vue +0 -89
  119. package/components/SwProductCard.vue +0 -286
  120. package/components/SwProductGallery.vue +0 -39
  121. package/components/SwProductListingFilter.vue +0 -42
  122. package/components/SwProductListingFilters.vue +0 -292
  123. package/components/listing-filters/SwFilterPrice.vue +0 -160
  124. package/components/listing-filters/SwFilterProperties.vue +0 -123
  125. package/components/listing-filters/SwFilterRating.vue +0 -101
  126. package/components/listing-filters/SwFilterShippingFree.vue +0 -104
  127. package/components/public/cms/CmsGenericBlock.md +0 -27
  128. package/components/public/cms/block/CmsBlockImageFourColumn.vue +0 -29
  129. package/components/public/cms/block/CmsBlockImageHighlightRow.vue +0 -27
  130. package/components/public/cms/block/CmsBlockImageTextGallery.vue +0 -85
  131. package/components/public/cms/block/CmsBlockImageTextRow.vue +0 -43
  132. package/components/public/cms/block/CmsBlockImageThreeCover.vue +0 -27
  133. package/components/public/cms/block/CmsBlockImageTwoColumn.vue +0 -25
  134. package/components/public/cms/element/CmsElementBuyBox.vue +0 -190
  135. package/components/public/cms/element/CmsElementCategoryNavigation.vue +0 -167
  136. package/components/public/cms/element/CmsElementImageGallery.vue +0 -249
  137. package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +0 -123
  138. package/components/public/cms/element/CmsElementProductName.vue +0 -10
  139. package/components/public/cms/element/CmsElementProductSlider.vue +0 -80
  140. package/components/public/cms/element/CmsElementSidebarFilter.vue +0 -12
  141. package/components/public/cms/section/CmsSectionSidebar.vue +0 -41
  142. package/components/public/cms/skeleton/ProductCardSkeleton.vue +0 -44
  143. package/helpers/html-to-vue/ast.ts +0 -72
  144. package/helpers/html-to-vue/renderer.ts +0 -56
  145. /package/{components → app/components}/SwSharedPrice.vue +0 -0
  146. /package/{components → app/components}/public/cms/CmsGenericElement.md +0 -0
  147. /package/{components → app/components}/public/cms/CmsGenericElement.vue +0 -0
  148. /package/{components → app/components}/public/cms/CmsNoComponent.vue +0 -0
  149. /package/{components → app/components}/public/cms/block/CmsBlockCategoryNavigation.vue +0 -0
  150. /package/{components → app/components}/public/cms/block/CmsBlockCrossSelling.vue +0 -0
  151. /package/{components → app/components}/public/cms/block/CmsBlockCustomForm.vue +0 -0
  152. /package/{components → app/components}/public/cms/block/CmsBlockDefault.vue +0 -0
  153. /package/{components → app/components}/public/cms/block/CmsBlockForm.vue +0 -0
  154. /package/{components → app/components}/public/cms/block/CmsBlockHtml.vue +0 -0
  155. /package/{components → app/components}/public/cms/block/CmsBlockImage.vue +0 -0
  156. /package/{components → app/components}/public/cms/block/CmsBlockImageCover.vue +0 -0
  157. /package/{components → app/components}/public/cms/block/CmsBlockImageGallery.vue +0 -0
  158. /package/{components → app/components}/public/cms/block/CmsBlockImageSlider.vue +0 -0
  159. /package/{components → app/components}/public/cms/block/CmsBlockProductDescriptionReviews.vue +0 -0
  160. /package/{components → app/components}/public/cms/block/CmsBlockProductListing.vue +0 -0
  161. /package/{components → app/components}/public/cms/block/CmsBlockProductSlider.vue +0 -0
  162. /package/{components → app/components}/public/cms/block/CmsBlockText.vue +0 -0
  163. /package/{components → app/components}/public/cms/block/CmsBlockTextHero.vue +0 -0
  164. /package/{components → app/components}/public/cms/block/CmsBlockTextTeaser.vue +0 -0
  165. /package/{components → app/components}/public/cms/block/CmsBlockTextTeaserSection.vue +0 -0
  166. /package/{components → app/components}/public/cms/block/CmsBlockTextThreeColumn.vue +0 -0
  167. /package/{components → app/components}/public/cms/block/CmsBlockTextTwoColumn.vue +0 -0
  168. /package/{components → app/components}/public/cms/block/CmsBlockVimeoVideo.vue +0 -0
  169. /package/{components → app/components}/public/cms/block/CmsBlockYoutubeVideo.vue +0 -0
  170. /package/{components → app/components}/public/cms/element/CmsElementBuyBox.md +0 -0
  171. /package/{components → app/components}/public/cms/element/CmsElementCategoryNavigation.md +0 -0
  172. /package/{components → app/components}/public/cms/element/CmsElementCrossSelling.md +0 -0
  173. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.md +0 -0
  174. /package/{components → app/components}/public/cms/element/CmsElementCustomForm.vue +0 -0
  175. /package/{components → app/components}/public/cms/element/CmsElementForm.md +0 -0
  176. /package/{components → app/components}/public/cms/element/CmsElementForm.vue +0 -0
  177. /package/{components → app/components}/public/cms/element/CmsElementHtml.vue +0 -0
  178. /package/{components → app/components}/public/cms/element/CmsElementImage.md +0 -0
  179. /package/{components → app/components}/public/cms/element/CmsElementImageGallery.md +0 -0
  180. /package/{components → app/components}/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +0 -0
  181. /package/{components → app/components}/public/cms/element/CmsElementImageSlider.md +0 -0
  182. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.md +0 -0
  183. /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.vue +0 -0
  184. /package/{components → app/components}/public/cms/element/CmsElementProductBox.md +0 -0
  185. /package/{components → app/components}/public/cms/element/CmsElementProductDescriptionReviews.md +0 -0
  186. /package/{components → app/components}/public/cms/element/CmsElementProductListing.md +0 -0
  187. /package/{components → app/components}/public/cms/element/CmsElementProductName.md +0 -0
  188. /package/{components → app/components}/public/cms/element/CmsElementProductSlider.md +0 -0
  189. /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.md +0 -0
  190. /package/{components → app/components}/public/cms/element/CmsElementText.md +0 -0
  191. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.md +0 -0
  192. /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.vue +0 -0
  193. /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.md +0 -0
  194. /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.vue +0 -0
  195. /package/{components → app/components}/public/cms/section/CmsSectionDefault.md +0 -0
  196. /package/{components → app/components}/public/cms/section/CmsSectionSidebar.md +0 -0
  197. /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.test.ts +0 -0
  198. /package/{helpers → app/helpers}/media/isSpatial.ts +0 -0
@@ -4,13 +4,21 @@ import {
4
4
  getBackgroundImageUrl,
5
5
  getCmsLayoutConfiguration,
6
6
  } from "@shopware/helpers";
7
- import { h } from "vue";
7
+ import { h, provide } from "vue";
8
+ import { useAppConfig } from "#imports";
8
9
  import type { Schemas } from "#shopware";
10
+ import { getImageSizes } from "../../../helpers/cms/getImageSizes";
9
11
 
10
12
  const props = defineProps<{
11
13
  content: Schemas["CmsBlock"];
12
14
  }>();
13
15
 
16
+ const appConfig = useAppConfig();
17
+
18
+ const slotCount = props.content.slots?.length || 1;
19
+ provide("cms-block-slot-count", slotCount);
20
+ provide("cms-image-sizes", getImageSizes(slotCount, appConfig.imageSizes));
21
+
14
22
  const DynamicRender = () => {
15
23
  const {
16
24
  resolvedComponent,
@@ -31,16 +39,22 @@ const DynamicRender = () => {
31
39
  layoutStyles.backgroundImage = getBackgroundImageUrl(
32
40
  layoutStyles.backgroundImage,
33
41
  props.content,
42
+ {
43
+ format: appConfig.backgroundImage?.format,
44
+ quality: appConfig.backgroundImage?.quality,
45
+ },
34
46
  );
35
47
  }
36
48
 
37
49
  const containerStyles = {
38
50
  backgroundColor: layoutStyles.backgroundColor,
39
51
  backgroundImage: layoutStyles.backgroundImage,
52
+ backgroundSize: layoutStyles.backgroundSize,
40
53
  };
41
54
 
42
55
  layoutStyles.backgroundColor = null;
43
56
  layoutStyles.backgroundImage = null;
57
+ layoutStyles.backgroundSize = null;
44
58
  return h(
45
59
  "div",
46
60
  {
@@ -1,6 +1,23 @@
1
- An entrypoint to render the whole CMS object
1
+ An entrypoint to render the whole CMS object.
2
2
 
3
- Example usage:
3
+ Resolves all CMS sections dynamically and applies their layout configuration. When a section has a `backgroundMedia` set, the component automatically optimizes the background image URL using the `getBackgroundImageUrl` helper from `@shopware/helpers`, appending `format` and `quality` parameters from the `backgroundImage` app config.
4
+
5
+ ### Background Image Optimization
6
+
7
+ Background image settings are read from `app.config.ts`:
8
+
9
+ ```ts
10
+ export default defineAppConfig({
11
+ backgroundImage: {
12
+ format: "webp", // output format
13
+ quality: 85, // image quality (0-100)
14
+ },
15
+ });
16
+ ```
17
+
18
+ See the [cms-base-layer README](../../../../../../README.md#%EF%B8%8F-background-image-optimization) for full details.
19
+
20
+ ### Example usage
4
21
 
5
22
  ```vue{29}
6
23
  <script setup lang="ts">
@@ -2,25 +2,48 @@
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 { createCategoryListingContext, useNavigationContext } from "#imports";
8
+ import { computed, h, resolveComponent, watchEffect } from "vue";
9
+ import {
10
+ createCategoryListingContext,
11
+ useAppConfig,
12
+ useNavigationContext,
13
+ } from "#imports";
9
14
  import type { Schemas } from "#shopware";
15
+ import { useLcpImagePreload } from "../../../composables/useLcpImagePreload";
10
16
 
11
17
  const props = defineProps<{
12
18
  content: Schemas["CmsPage"];
13
19
  }>();
14
20
 
15
21
  const { routeName } = useNavigationContext();
16
- if (routeName.value === "frontend.navigation.page") {
17
- createCategoryListingContext();
22
+ const appConfig = useAppConfig();
23
+
24
+ // Function to initialize or update listing context
25
+ function updateListingContext(content: Schemas["CmsPage"]) {
26
+ if (routeName.value === "frontend.navigation.page") {
27
+ const initialListing =
28
+ getProductListingFromCmsPage<Schemas["ProductListingResult"]>(content);
29
+
30
+ if (initialListing) {
31
+ createCategoryListingContext(initialListing);
32
+ }
33
+ }
18
34
  }
19
35
 
36
+ // Watch for content changes and update context
37
+ watchEffect(() => {
38
+ updateListingContext(props.content);
39
+ });
40
+
20
41
  const cmsSections = computed<Schemas["CmsSection"][]>(() => {
21
42
  return props.content?.sections || [];
22
43
  });
23
44
 
45
+ useLcpImagePreload(props.content?.sections || []);
46
+
24
47
  const DynamicRender = () => {
25
48
  const componentsMap = cmsSections.value.map((section) => {
26
49
  return {
@@ -41,6 +64,7 @@ const DynamicRender = () => {
41
64
  layoutStyles.backgroundImage = getBackgroundImageUrl(
42
65
  layoutStyles.backgroundImage,
43
66
  componentObject.section,
67
+ appConfig.backgroundImage,
44
68
  );
45
69
  }
46
70
 
@@ -48,7 +72,8 @@ const DynamicRender = () => {
48
72
  content: componentObject.section,
49
73
  class: {
50
74
  ...cssClasses,
51
- "max-w-screen-2xl mx-auto": layoutStyles?.sizingMode === "boxed",
75
+ "max-w-screen-2xl w-full mx-auto": layoutStyles?.sizingMode === "boxed",
76
+ "w-full": layoutStyles?.sizingMode === "full_width",
52
77
  },
53
78
  style: {
54
79
  backgroundColor: layoutStyles?.backgroundColor,
@@ -21,6 +21,6 @@ const slotCenterContent = getSlotContent("center");
21
21
 
22
22
  <style scoped>
23
23
  .cms-block-center-text .cms-element-image {
24
- @apply aspect-square object-cover;
24
+ @apply self-stretch min-h-12;
25
25
  }
26
26
  </style>
@@ -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-stretch gap-6 w-full">
16
+ <div class="w-full md:flex-1 min-w-0 p-4 flex flex-col">
17
+ <CmsGenericElement :content="leftContent" class="flex-1" />
18
+ </div>
19
+ <div class="w-full md:flex-1 min-w-0 p-4 flex flex-col">
20
+ <CmsGenericElement :content="rightContent" class="flex-1" />
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>