@lightspeed/crane 1.4.2 → 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 (116) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/UPGRADE.md +19 -0
  3. package/dist/app.d.mts +1 -1028
  4. package/dist/app.d.ts +1 -1028
  5. package/dist/app.mjs +1 -1
  6. package/dist/cli.mjs +20 -7
  7. package/package.json +3 -2
  8. package/template/footers/example-footer/ExampleFooter.vue +1 -1
  9. package/template/footers/example-footer/client.ts +1 -1
  10. package/template/footers/example-footer/component/LegalLinks.vue +1 -1
  11. package/template/footers/example-footer/component/MadeWith.vue +1 -1
  12. package/template/footers/example-footer/component/ReportAbuse.vue +1 -1
  13. package/template/footers/example-footer/entity/color.ts +2 -2
  14. package/template/footers/example-footer/server.ts +1 -1
  15. package/template/headers/example-header/client.ts +1 -1
  16. package/template/headers/example-header/component/Account.vue +1 -1
  17. package/template/headers/example-header/component/Cart.vue +1 -1
  18. package/template/headers/example-header/component/CategoriesDropdown.vue +1 -1
  19. package/template/headers/example-header/component/Logo.vue +1 -1
  20. package/template/headers/example-header/component/NavigationMenu.vue +1 -1
  21. package/template/headers/example-header/component/SearchForm.vue +1 -1
  22. package/template/headers/example-header/server.ts +1 -1
  23. package/template/index.d.ts +1 -1
  24. package/template/layouts/catalog/example-catalog/Main.vue +1 -1
  25. package/template/layouts/catalog/example-catalog/slots/custom-bottom-bar/client.ts +1 -1
  26. package/template/layouts/catalog/example-catalog/slots/custom-bottom-bar/server.ts +1 -1
  27. package/template/layouts/category/example-category/Main.vue +1 -1
  28. package/template/layouts/category/example-category/settings/content.ts +1 -1
  29. package/template/layouts/category/example-category/settings/design.ts +1 -1
  30. package/template/layouts/product/example-product/Main.vue +1 -1
  31. package/template/layouts/product/example-product/settings/content.ts +1 -1
  32. package/template/layouts/product/example-product/settings/design.ts +1 -1
  33. package/template/package.json +6 -3
  34. package/template/page-templates/example-template/pages/catalog.ts +1 -1
  35. package/template/page-templates/example-template/pages/category.ts +1 -1
  36. package/template/page-templates/example-template/pages/product.ts +1 -1
  37. package/template/preview/sections/preview.html +1 -1
  38. package/template/preview/shared/api-routes.ts +347 -39
  39. package/template/preview/shared/mock.ts +43 -41
  40. package/template/preview/shared/preview.ts +205 -126
  41. package/template/preview/shared/utils.ts +208 -62
  42. package/template/preview/ssr-server.ts +429 -0
  43. package/template/preview/vite.config.js +64 -65
  44. package/template/reference/sections/about-us/AboutUs.vue +1 -1
  45. package/template/reference/sections/about-us/client.ts +1 -1
  46. package/template/reference/sections/about-us/component/Image.vue +1 -1
  47. package/template/reference/sections/about-us/component/Stats.vue +2 -2
  48. package/template/reference/sections/about-us/component/Title.vue +1 -1
  49. package/template/reference/sections/about-us/server.ts +1 -1
  50. package/template/reference/sections/about-us/util/visibility-provider.ts +1 -1
  51. package/template/reference/sections/featured-products/FeaturedProducts.vue +65 -0
  52. package/template/reference/sections/featured-products/assets/arrow.svg +3 -0
  53. package/template/reference/sections/featured-products/assets/custom_section_showcase_1_preview.png +0 -0
  54. package/template/reference/sections/featured-products/client.ts +5 -0
  55. package/template/reference/sections/featured-products/component/ProductItem.vue +71 -0
  56. package/template/reference/sections/featured-products/component/Title.vue +31 -0
  57. package/template/reference/sections/featured-products/entity/color.ts +4 -0
  58. package/template/reference/sections/featured-products/server.ts +5 -0
  59. package/template/reference/sections/featured-products/settings/content.ts +14 -0
  60. package/template/reference/sections/featured-products/settings/design.ts +33 -0
  61. package/template/reference/sections/featured-products/settings/translations.ts +24 -0
  62. package/template/reference/sections/featured-products/showcases/1.ts +28 -0
  63. package/template/reference/sections/featured-products/showcases/translations.ts +16 -0
  64. package/template/reference/sections/featured-products/type.ts +5 -0
  65. package/template/reference/sections/intro-slider/IntroSlider.vue +1 -1
  66. package/template/reference/sections/intro-slider/client.ts +1 -1
  67. package/template/reference/sections/intro-slider/component/Slider.vue +8 -2
  68. package/template/reference/sections/intro-slider/component/Title.vue +1 -1
  69. package/template/reference/sections/intro-slider/entity/color.ts +2 -2
  70. package/template/reference/sections/intro-slider/server.ts +1 -1
  71. package/template/reference/sections/tag-lines/TagLines.vue +1 -1
  72. package/template/reference/sections/tag-lines/client.ts +1 -1
  73. package/template/reference/sections/tag-lines/component/SectionImage.vue +1 -1
  74. package/template/reference/sections/tag-lines/component/Title.vue +1 -1
  75. package/template/reference/sections/tag-lines/composables/highlighted-text-image-list.ts +2 -2
  76. package/template/reference/sections/tag-lines/server.ts +1 -1
  77. package/template/reference/sections/trending-categories/TrendingCategories.vue +70 -0
  78. package/template/reference/sections/trending-categories/assets/arrow.svg +3 -0
  79. package/template/reference/sections/trending-categories/assets/custom_section_showcase_1_preview.png +0 -0
  80. package/template/reference/sections/trending-categories/client.ts +5 -0
  81. package/template/reference/sections/trending-categories/component/CategoryItem.vue +62 -0
  82. package/template/reference/sections/trending-categories/component/Title.vue +32 -0
  83. package/template/reference/sections/trending-categories/entity/color.ts +4 -0
  84. package/template/reference/sections/trending-categories/server.ts +5 -0
  85. package/template/reference/sections/trending-categories/settings/content.ts +14 -0
  86. package/template/reference/sections/trending-categories/settings/design.ts +33 -0
  87. package/template/reference/sections/trending-categories/settings/translations.ts +24 -0
  88. package/template/reference/sections/trending-categories/showcases/1.ts +36 -0
  89. package/template/reference/sections/trending-categories/showcases/translations.ts +22 -0
  90. package/template/reference/sections/trending-categories/type.ts +5 -0
  91. package/template/reference/shared/components/Button.vue +1 -1
  92. package/template/reference/templates/reference-template-apparel/pages/catalog.ts +1 -1
  93. package/template/reference/templates/reference-template-apparel/pages/category.ts +1 -1
  94. package/template/reference/templates/reference-template-apparel/pages/home.ts +10 -0
  95. package/template/reference/templates/reference-template-apparel/pages/product.ts +1 -1
  96. package/template/reference/templates/reference-template-bike/pages/catalog.ts +1 -1
  97. package/template/reference/templates/reference-template-bike/pages/category.ts +1 -1
  98. package/template/reference/templates/reference-template-bike/pages/home.ts +10 -0
  99. package/template/reference/templates/reference-template-bike/pages/product.ts +1 -1
  100. package/template/sections/example-section/ExampleSection.vue +8 -1
  101. package/template/sections/example-section/client.ts +1 -1
  102. package/template/sections/example-section/component/button/Button.vue +1 -1
  103. package/template/sections/example-section/component/image/Image.vue +1 -1
  104. package/template/sections/example-section/component/image/ImagesGrid.vue +1 -1
  105. package/template/sections/example-section/component/selectbox/Selectbox.vue +1 -1
  106. package/template/sections/example-section/component/title/Title.vue +1 -1
  107. package/template/sections/example-section/component/toggle/Toggle.vue +1 -1
  108. package/template/sections/example-section/entity/color.ts +2 -2
  109. package/template/sections/example-section/server.ts +1 -1
  110. package/template/sections/example-section/settings/translations.ts +1 -1
  111. package/template/sections/example-section/showcases/translations.ts +13 -13
  112. package/template/shared/components/LanguageSelector.vue +1 -1
  113. package/template/shared/translation.ts +16 -0
  114. package/template/shared/utils.ts +3 -1
  115. package/template/tsconfig.json +1 -0
  116. package/types.d.ts +6 -457
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <SectionWrapper :style="backgroundStyle">
3
+ <Title v-if="showTitle" />
4
+ <div class="products-wrapper">
5
+ <ProductItem
6
+ v-for="product in productSelectorContent.products"
7
+ :key="product.id"
8
+ :product="product"
9
+ />
10
+ </div>
11
+ </SectionWrapper>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { computed, CSSProperties } from "vue";
16
+ import {
17
+ Color,
18
+ useBackgroundElementDesign,
19
+ useInputboxElementContent,
20
+ useProductSelectorElementContent,
21
+ useTextElementDesign,
22
+ } from "@lightspeed/crane-api";
23
+ import { Content, Design } from "./type";
24
+ import SectionWrapper from "../../shared/components/SectionWrapper.vue";
25
+ import Title from "./component/Title.vue";
26
+ import ProductItem from "./component/ProductItem.vue";
27
+
28
+
29
+ const titleContent = useInputboxElementContent<Content>("section_title");
30
+ const titleDesign = useTextElementDesign<Design>('section_title');
31
+
32
+ const productSelectorContent =
33
+ useProductSelectorElementContent<Content>("featured_products");
34
+
35
+ const showTitle = computed(() => titleDesign.visible && titleContent.hasContent);
36
+
37
+ const backgroundDesign = useBackgroundElementDesign<Design>("background");
38
+ const background = computed(() => ({
39
+ type: backgroundDesign.background?.type,
40
+ solidColor: backgroundDesign.background?.solid?.color as Color,
41
+ fromColor: backgroundDesign.background?.gradient?.fromColor as Color,
42
+ toColor: backgroundDesign.background?.gradient?.toColor as Color,
43
+ }));
44
+
45
+ const backgroundStyle = computed<CSSProperties>(() => {
46
+ if (background.value.type === "gradient") {
47
+ return {
48
+ "background-image": `linear-gradient(to right, ${background.value.fromColor.hex}, ${background.value.toColor.hex})`,
49
+ };
50
+ }
51
+ return { "background-color": background.value.solidColor.hex };
52
+ });
53
+ </script>
54
+
55
+ <style lang="scss" scoped>
56
+ .products-wrapper {
57
+ display: flex;
58
+ flex-wrap: wrap;
59
+ justify-content: center;
60
+ gap: 12px;
61
+ max-width: 1440px;
62
+ margin: 0 auto;
63
+ width: 100%;
64
+ }
65
+ </style>
@@ -0,0 +1,3 @@
1
+ <svg width="22" height="22" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill="currentColor" d="M19.22 1.735c.528.012.97.42 1.037.933l.009.112.09 4.09a.97.97 0 01-1 1 1.08 1.08 0 01-1.037-.934l-.008-.111-.037-1.684-6.809 6.809c-.438.439-.877.47-1.314.095l-.101-.094c-.438-.437-.469-.876-.093-1.314l.094-.101 6.809-6.809-1.684-.037a1.08 1.08 0 01-1.034-.916l-.01-.128a.969.969 0 01.888-.997l.111-.003 4.09.09zM19 14.5a4.5 4.5 0 01-4.288 4.495L14.5 19h-7a4.5 4.5 0 01-4.495-4.288L3 14.5v-7a4.5 4.5 0 014.288-4.495L7.5 3h2.625a1 1 0 01.117 1.993L10.125 5H7.5a2.5 2.5 0 00-2.495 2.336L5 7.5v7a2.5 2.5 0 002.336 2.495L7.5 17h7a2.5 2.5 0 002.495-2.336L17 14.5v-2.625a1 1 0 011.993-.117l.007.117V14.5z" />
3
+ </svg>
@@ -0,0 +1,5 @@
1
+ import { createVueClientApp } from '@lightspeed/crane-api';
2
+ import FeaturedProducts from './FeaturedProducts.vue';
3
+ import { Content, Design } from './type.ts';
4
+
5
+ export default createVueClientApp<Content, Design>(FeaturedProducts);
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <a
3
+ v-if="product"
4
+ :key="product.id"
5
+ :href="product.url"
6
+ class="product"
7
+ >
8
+ <img v-if="product.fullImageUrl" class="product_image" :src="product.fullImageUrl" :alt="product.name" />
9
+ <h4 class="product__title">
10
+ {{ product.name }}
11
+ </h4>
12
+ <span class="product__price">{{ product.formattedPrice }}</span>
13
+ </a>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ interface Props {
18
+ product: ProductListComponentItem
19
+ }
20
+
21
+ const { product } = defineProps<Props>();
22
+
23
+ </script>
24
+
25
+ <style scoped lang="scss">
26
+ .product {
27
+ display: flex;
28
+ flex-direction: column;
29
+ cursor: pointer;
30
+ flex: 0 0 auto;
31
+ min-width: 0;
32
+ overflow: hidden;
33
+ text-decoration: inherit;
34
+ transition: transform 0.2s ease;
35
+
36
+ @media (max-width: 767px) {
37
+ width: calc(50% - 6px);
38
+ }
39
+
40
+ @media (min-width: 768px) {
41
+ width: calc(20% - 9.6px);
42
+ }
43
+
44
+ &:hover {
45
+ transform: translateY(-4px);
46
+ }
47
+ }
48
+
49
+ .product_image {
50
+ width: 100%;
51
+ height: auto;
52
+ aspect-ratio: 3/4;
53
+ object-fit: cover;
54
+ display: block;
55
+ margin-bottom: 4px;
56
+ }
57
+
58
+ .product__title {
59
+ font-size: 1rem;
60
+ font-weight: 300;
61
+ margin: 0;
62
+ line-height: 1.4;
63
+ color: #111;
64
+ }
65
+
66
+ .product__price {
67
+ font-size: 1rem;
68
+ font-weight: 600;
69
+ color: #111;
70
+ }
71
+ </style>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <h1
3
+ :style="titleStyle"
4
+ class="section-title"
5
+ >
6
+ {{ titleContent.value }}
7
+ </h1>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { useInputboxElementContent, useTextElementDesign } from "@lightspeed/crane-api";
12
+ import { Content, Design } from "../type";
13
+ import { computed } from "vue";
14
+
15
+ const titleContent = useInputboxElementContent<Content>("section_title");
16
+ const titleDesign = useTextElementDesign<Design>('section_title');
17
+
18
+ const titleStyle = computed(() => ({
19
+ fontSize: `${titleDesign.size}px`,
20
+ fontFamily: titleDesign.font,
21
+ color: (titleDesign.color as Color).hex,
22
+ 'font-style': titleDesign.italic ? 'italic' : 'normal',
23
+ 'font-weight': titleDesign.bold ? 'bold' : 'normal',
24
+ }));
25
+ </script>
26
+
27
+ <style scoped lang="scss">
28
+ .section-title {
29
+ margin-bottom: 1rem;
30
+ }
31
+ </style>
@@ -0,0 +1,4 @@
1
+ export enum ColorType {
2
+ SOLID = 'solid',
3
+ GRADIENT = 'gradient',
4
+ }
@@ -0,0 +1,5 @@
1
+ import { createVueServerApp } from '@lightspeed/crane-api';
2
+ import FeaturedProducts from './FeaturedProducts.vue';
3
+ import { Content, Design } from './type.ts';
4
+
5
+ export default createVueServerApp<Content, Design>(FeaturedProducts);
@@ -0,0 +1,14 @@
1
+ export default {
2
+ section_title: {
3
+ type: 'INPUTBOX',
4
+ label: '$label.section_title.label',
5
+ placeholder: '$label.section_title.placeholder',
6
+ },
7
+ featured_products: {
8
+ type: 'PRODUCT_SELECTOR',
9
+ label: '$label.featured_products.label',
10
+ defaults: {
11
+ maxProducts: 6,
12
+ },
13
+ },
14
+ } as const;
@@ -0,0 +1,33 @@
1
+ export default {
2
+ section_title: {
3
+ type: 'TEXT',
4
+ label: '$label.section_title.label',
5
+ colors: ['#FFFFFF66', '#0000004D', '#00000099', '#64C7FF66', '#F9947266', '#C794CD66', '#FFD17466'],
6
+ sizes: [18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60],
7
+ defaults: {
8
+ font: 'global.fontFamily.body',
9
+ size: 40,
10
+ bold: true,
11
+ italic: false,
12
+ color: '#313131',
13
+ visible: true,
14
+ },
15
+ },
16
+ background: {
17
+ type: 'BACKGROUND',
18
+ label: '$label.background.label',
19
+ colors: [
20
+ '#FFFFFF66',
21
+ '#0000004D',
22
+ '#00000099',
23
+ '#64C7FF66',
24
+ '#F9947266',
25
+ '#C794CD66',
26
+ '#FFD17466',
27
+ ],
28
+ defaults: {
29
+ style: 'COLOR',
30
+ color: 'global.color.background',
31
+ },
32
+ },
33
+ } as const;
@@ -0,0 +1,24 @@
1
+ export default {
2
+ en: {
3
+ '$label.section_title.label': 'Main title',
4
+ '$label.section_title.placeholder':
5
+ 'This will be the main title for this section',
6
+ '$label.featured_products.label': 'Trending collections',
7
+
8
+ '$label.background.label': 'Background',
9
+ },
10
+
11
+ nl: {
12
+ '$label.section_title.label': 'Hoofdtitel',
13
+ '$label.section_title.placeholder':
14
+ 'Dit wordt de hoofdtitel voor deze sectie',
15
+ '$label.featured_products.label': 'Trending collecties',
16
+ },
17
+
18
+ fr: {
19
+ '$label.section_title.label': 'Titre principal',
20
+ '$label.section_title.placeholder':
21
+ 'Ce sera le titre principal de cette section',
22
+ '$label.featured_products.label': 'Collections tendance',
23
+ },
24
+ } as const;
@@ -0,0 +1,28 @@
1
+ export default {
2
+ showcaseId: '1',
3
+ previewImage: {
4
+ set: {
5
+ ORIGINAL: {
6
+ url: 'custom_section_showcase_1_preview.png',
7
+ },
8
+ },
9
+ },
10
+ blockName: '$label.showcase_1.blockName',
11
+ content: {
12
+ section_title: {
13
+ type: 'INPUTBOX',
14
+ text: '$label.showcase_1.section_title.text',
15
+ },
16
+ featured_products: {
17
+ type: 'PRODUCT_SELECTOR',
18
+ maxProducts: 6,
19
+ },
20
+ },
21
+ design: {
22
+ background: {
23
+ type: 'BACKGROUND',
24
+ style: 'COLOR',
25
+ color: 'global.color.background',
26
+ },
27
+ },
28
+ } as const;
@@ -0,0 +1,16 @@
1
+ export default {
2
+ en: {
3
+ '$label.showcase_1.blockName': 'Reference Section — Featured Products',
4
+ '$label.showcase_1.section_title.text': 'Featured Products',
5
+ },
6
+
7
+ nl: {
8
+ '$label.showcase_1.blockName': 'Referentiesectie — Aanbevolen producten',
9
+ '$label.showcase_1.section_title.text': 'Aanbevolen producten',
10
+ },
11
+
12
+ fr: {
13
+ '$label.showcase_1.blockName': 'Section de référence — Produits phares',
14
+ '$label.showcase_1.section_title.text': 'Produits phares',
15
+ },
16
+ } as const;
@@ -0,0 +1,5 @@
1
+ import ContentSettings from './settings/content.ts';
2
+ import DesignSettings from './settings/design.ts';
3
+
4
+ export type Content = InferContentType<typeof ContentSettings>;
5
+ export type Design = InferDesignType<typeof DesignSettings>;
@@ -27,7 +27,7 @@ import {
27
27
  useButtonElementContent,
28
28
  useButtonElementDesign,
29
29
  ButtonContent,
30
- } from '@lightspeed/crane';
30
+ } from '@lightspeed/crane-api';
31
31
  import { computed } from 'vue';
32
32
  import { Content, Design } from './type.ts';
33
33
  import Slider from './component/Slider.vue';
@@ -1,4 +1,4 @@
1
- import { createVueClientApp } from '@lightspeed/crane';
1
+ import { createVueClientApp } from '@lightspeed/crane-api';
2
2
  import ExampleSection from './IntroSlider.vue';
3
3
  import { Content, Design } from './type.ts';
4
4
 
@@ -45,7 +45,7 @@ import {
45
45
  useLayoutElementDesign,
46
46
  useImageElementDesign,
47
47
  useTextElementDesign,
48
- } from '@lightspeed/crane';
48
+ } from '@lightspeed/crane-api';
49
49
  import { Content, Design } from '../type.ts';
50
50
 
51
51
  type Slide = {
@@ -117,8 +117,14 @@ const slideSize = computed<number>(() => slideWidth.value + slideGap.value);
117
117
 
118
118
  function initializeItems(): void {
119
119
  windowWidth.value = window.innerWidth;
120
+
121
+ if (!slides.value || slides.value.length === 0) {
122
+ repeatedItems.value = [];
123
+ return;
124
+ }
125
+
120
126
  const minItemsToFillViewport = Math.ceil(windowWidth.value / slideSize.value);
121
- const repeats = Math.ceil(minItemsToFillViewport / (slides.value?.length as number)) + 1;
127
+ const repeats = Math.ceil(minItemsToFillViewport / slides.value.length) + 1;
122
128
 
123
129
  repeatedItems.value = Array(repeats).fill(slides.value).flat();
124
130
  }
@@ -14,7 +14,7 @@ import { computed, CSSProperties } from 'vue';
14
14
  import {
15
15
  useLayoutElementDesign,
16
16
  useTextareaElementContent, useTextareaElementDesign,
17
- } from '@lightspeed/crane';
17
+ } from '@lightspeed/crane-api';
18
18
  import { Content, Design } from '../type.ts';
19
19
 
20
20
  const titleContent = useTextareaElementContent<Content>('section_title');
@@ -1,4 +1,4 @@
1
1
  export enum ColorType {
2
- SOLID = 'solid',
3
- GRADIENT = 'gradient',
2
+ SOLID = 'solid',
3
+ GRADIENT = 'gradient',
4
4
  }
@@ -1,4 +1,4 @@
1
- import { createVueServerApp } from '@lightspeed/crane';
1
+ import { createVueServerApp } from '@lightspeed/crane-api';
2
2
  import ExampleSection from './IntroSlider.vue';
3
3
  import { Content, Design } from './type.ts';
4
4
 
@@ -52,7 +52,7 @@ import {
52
52
  useImageElementContent,
53
53
  useTextElementDesign,
54
54
  useInputboxElementContent,
55
- } from '@lightspeed/crane';
55
+ } from '@lightspeed/crane-api';
56
56
  import { computed } from 'vue';
57
57
  import { Content, Design } from './type.ts';
58
58
  import Tagline from '../../shared/components/Tagline.vue';
@@ -1,4 +1,4 @@
1
- import { createVueClientApp } from '@lightspeed/crane';
1
+ import { createVueClientApp } from '@lightspeed/crane-api';
2
2
  import ExampleSection from './TagLines.vue';
3
3
  import { Content, Design } from './type.ts';
4
4
 
@@ -28,7 +28,7 @@
28
28
  import {
29
29
  ImageContent,
30
30
  useLayoutElementDesign,
31
- } from '@lightspeed/crane';
31
+ } from '@lightspeed/crane-api';
32
32
  import { computed } from 'vue';
33
33
  import { Highlight } from '../composables/highlighted-text-image-list.ts';
34
34
 
@@ -9,7 +9,7 @@ import { computed, CSSProperties } from 'vue';
9
9
  import {
10
10
  useInputboxElementContent,
11
11
  useTextElementDesign,
12
- } from '@lightspeed/crane';
12
+ } from '@lightspeed/crane-api';
13
13
  import { Content, Design } from '../type.ts';
14
14
 
15
15
  const titleContent = useInputboxElementContent<Content>('section_title');
@@ -5,14 +5,14 @@ import {
5
5
  TextAreaContent,
6
6
  useDeckElementContent,
7
7
  useTextElementDesign,
8
- } from '@lightspeed/crane';
8
+ } from '@lightspeed/crane-api';
9
9
  import { Content, Design } from '../type.ts';
10
10
 
11
11
  export type Highlight = {
12
12
  text?: TextAreaContent;
13
13
  image?: ImageContent;
14
14
  design: TextDesignData;
15
- }
15
+ };
16
16
 
17
17
  export function useHighlightedTextElementList() {
18
18
  const design = computed<TextDesignData[]>(() => [
@@ -1,4 +1,4 @@
1
- import { createVueServerApp } from '@lightspeed/crane';
1
+ import { createVueServerApp } from '@lightspeed/crane-api';
2
2
  import ExampleSection from './TagLines.vue';
3
3
  import { Content, Design } from './type.ts';
4
4
 
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <SectionWrapper :style="backgroundStyle">
3
+ <Title v-if="showTitle" />
4
+ <div
5
+ v-if="categorySelectorContent.hasContent"
6
+ class="categories-wrapper"
7
+ >
8
+ <CategoryItem v-for="category in categorySelectorContent.categories" :key="category.id" :category="category" />
9
+ </div>
10
+ </SectionWrapper>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { computed, CSSProperties } from "vue";
15
+ import {
16
+ Color,
17
+ useBackgroundElementDesign,
18
+ useCategorySelectorElementContent,
19
+ useInputboxElementContent,
20
+ useTextElementDesign
21
+ } from "@lightspeed/crane-api";
22
+
23
+ import { Content, Design } from "./type";
24
+ import SectionWrapper from "../../shared/components/SectionWrapper.vue";
25
+ import Title from "./component/Title.vue";
26
+ import CategoryItem from "./component/CategoryItem.vue";
27
+
28
+
29
+ const titleContent = useInputboxElementContent<Content>("section_title");
30
+ const titleDesign = useTextElementDesign<Design>('section_title');
31
+
32
+
33
+ const categorySelectorContent = useCategorySelectorElementContent<Content>(
34
+ "trending_categories",
35
+ );
36
+
37
+ const showTitle = computed(() => titleDesign.visible && titleContent.hasContent);
38
+
39
+ const backgroundDesign = useBackgroundElementDesign<Design>("background");
40
+ const background = computed(() => ({
41
+ type: backgroundDesign.background?.type,
42
+ solidColor: backgroundDesign.background?.solid?.color as Color,
43
+ fromColor: backgroundDesign.background?.gradient?.fromColor as Color,
44
+ toColor: backgroundDesign.background?.gradient?.toColor as Color,
45
+ }));
46
+
47
+ const backgroundStyle = computed<CSSProperties>(() => {
48
+ if (background.value.type === "gradient") {
49
+ return {
50
+ "background-image": `linear-gradient(to right, ${background.value.fromColor.hex}, ${background.value.toColor.hex})`,
51
+ };
52
+ }
53
+ return { "background-color": background.value.solidColor.hex };
54
+ });
55
+ </script>
56
+
57
+ <style lang="scss" scoped>
58
+ .categories-wrapper {
59
+ display: flex;
60
+ flex-wrap: wrap;
61
+ justify-content: center;
62
+ width: 100%;
63
+ margin: 0 auto;
64
+ gap: 12px;
65
+
66
+ @media (min-width: 768px) {
67
+ max-width: 1440px;
68
+ }
69
+ }
70
+ </style>
@@ -0,0 +1,3 @@
1
+ <svg width="22" height="22" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill="currentColor" d="M19.22 1.735c.528.012.97.42 1.037.933l.009.112.09 4.09a.97.97 0 01-1 1 1.08 1.08 0 01-1.037-.934l-.008-.111-.037-1.684-6.809 6.809c-.438.439-.877.47-1.314.095l-.101-.094c-.438-.437-.469-.876-.093-1.314l.094-.101 6.809-6.809-1.684-.037a1.08 1.08 0 01-1.034-.916l-.01-.128a.969.969 0 01.888-.997l.111-.003 4.09.09zM19 14.5a4.5 4.5 0 01-4.288 4.495L14.5 19h-7a4.5 4.5 0 01-4.495-4.288L3 14.5v-7a4.5 4.5 0 014.288-4.495L7.5 3h2.625a1 1 0 01.117 1.993L10.125 5H7.5a2.5 2.5 0 00-2.495 2.336L5 7.5v7a2.5 2.5 0 002.336 2.495L7.5 17h7a2.5 2.5 0 002.495-2.336L17 14.5v-2.625a1 1 0 011.993-.117l.007.117V14.5z" />
3
+ </svg>
@@ -0,0 +1,5 @@
1
+ import { createVueClientApp } from '@lightspeed/crane-api';
2
+ import TrendingCategories from './TrendingCategories.vue';
3
+ import { Content, Design } from './type.ts';
4
+
5
+ export default createVueClientApp<Content, Design>(TrendingCategories);
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <a
3
+ v-if="category"
4
+ :key="category.id"
5
+ :href="category.url"
6
+ class="category"
7
+ >
8
+ <img v-if="category.imageUrl" class="category_image" :src="category.imageUrl" :alt="category.name" />
9
+ <h4 class="category__title">{{ category.name }}</h4>
10
+ </a>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ interface Props {
15
+ category: CategoryListComponentItem
16
+ }
17
+
18
+ const { category } = defineProps<Props>()
19
+ </script>
20
+
21
+ <style scoped lang="scss">
22
+ .category {
23
+ display: flex;
24
+ flex-direction: column;
25
+ cursor: pointer;
26
+ flex: 0 0 auto;
27
+ min-width: 0;
28
+ overflow: hidden;
29
+
30
+ @media (max-width: 767px) {
31
+ width: calc(50% - 6px);
32
+ }
33
+
34
+ @media (min-width: 768px) {
35
+ width: calc(20% - 9.6px);
36
+ }
37
+ }
38
+
39
+ .category_image {
40
+ width: 100%;
41
+ height: auto;
42
+ aspect-ratio: 3/4;
43
+ object-fit: cover;
44
+ display: block;
45
+ margin-bottom: 4px;
46
+ transition: transform 0.3s ease;
47
+
48
+ .category:hover & {
49
+ transform: scale(1.05);
50
+ }
51
+ }
52
+
53
+ .category__title {
54
+ font-size: 1rem;
55
+ font-weight: 300;
56
+ margin: 0;
57
+ padding: 24px 6px 0 6px;
58
+ line-height: 1.4;
59
+ color: #111;
60
+ text-align: center;
61
+ }
62
+ </style>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <h1
3
+ :style="titleStyle"
4
+ class="section-title"
5
+ >
6
+ {{ titleContent.value }}
7
+ </h1>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { useInputboxElementContent, useTextElementDesign } from "@lightspeed/crane-api";
12
+ import { Content, Design } from "../type";
13
+ import { computed } from "vue";
14
+
15
+ const titleContent = useInputboxElementContent<Content>("section_title");
16
+ const titleDesign = useTextElementDesign<Design>('section_title');
17
+
18
+ const titleStyle = computed(() => ({
19
+ fontSize: `${titleDesign.size}px`,
20
+ fontFamily: titleDesign.font,
21
+ color: (titleDesign.color as Color).hex,
22
+ 'font-style': titleDesign.italic ? 'italic' : 'normal',
23
+ 'font-weight': titleDesign.bold ? 'bold' : 'normal',
24
+ }));
25
+ </script>
26
+
27
+ <style scoped lang="scss">
28
+ .section-title {
29
+ margin-bottom: 1rem;
30
+ text-align: center;
31
+ }
32
+ </style>
@@ -0,0 +1,4 @@
1
+ export enum ColorType {
2
+ SOLID = 'solid',
3
+ GRADIENT = 'gradient',
4
+ }
@@ -0,0 +1,5 @@
1
+ import { createVueServerApp } from '@lightspeed/crane-api';
2
+ import TrendingCategories from './TrendingCategories.vue';
3
+ import { Content, Design } from './type.ts';
4
+
5
+ export default createVueServerApp<Content, Design>(TrendingCategories);
@@ -0,0 +1,14 @@
1
+ export default {
2
+ section_title: {
3
+ type: 'INPUTBOX',
4
+ label: '$label.section_title.label',
5
+ placeholder: '$label.section_title.placeholder',
6
+ },
7
+ trending_categories: {
8
+ type: 'CATEGORY_SELECTOR',
9
+ label: '$label.trending_categories.label',
10
+ defaults: {
11
+ maxCategories: 4,
12
+ },
13
+ },
14
+ } as const;