@lightspeed/crane 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +2 -0
- package/dist/app.d.mts +68 -76
- package/dist/app.d.ts +68 -76
- package/dist/app.mjs +1 -1
- package/dist/cli.mjs +8 -8
- package/package.json +13 -6
- package/template/headers/example-header/ExampleHeader.vue +2 -11
- package/template/headers/example-header/component/CategoriesDropdown.vue +165 -0
- package/template/headers/example-header/component/NavigationMenu.vue +83 -10
- package/template/layouts/catalog/example-catalog/Main.vue +10 -0
- package/template/layouts/category/example-category/Main.vue +11 -0
- package/template/layouts/product/example-product/Main.vue +35 -0
- package/template/page-templates/example-template/pages/catalog.ts +2 -1
- package/template/page-templates/example-template/pages/category.ts +2 -1
- package/template/page-templates/example-template/pages/product.ts +2 -1
- package/types.d.ts +71 -45
|
@@ -28,7 +28,8 @@ import Account from './component/Account.vue';
|
|
|
28
28
|
justify-content: space-between;
|
|
29
29
|
padding: 5px 10px;
|
|
30
30
|
|
|
31
|
-
.custom-
|
|
31
|
+
.custom-header__left,
|
|
32
|
+
.custom-header__right {
|
|
32
33
|
display: flex;
|
|
33
34
|
flex: 0 0 auto;
|
|
34
35
|
gap: 10px;
|
|
@@ -40,16 +41,6 @@ import Account from './component/Account.vue';
|
|
|
40
41
|
order: 3;
|
|
41
42
|
text-align: right;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
.custom-header__left{
|
|
45
|
-
display: flex;
|
|
46
|
-
flex: 0 0 auto;
|
|
47
|
-
gap: 10px;
|
|
48
|
-
align-items: center;
|
|
49
|
-
justify-content: flex-end;
|
|
50
|
-
order: 3;
|
|
51
|
-
text-align: left;
|
|
52
|
-
}
|
|
53
44
|
}
|
|
54
45
|
|
|
55
46
|
.header-content {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<teleport to="body">
|
|
3
|
+
<div
|
|
4
|
+
v-if="categories.length > 0"
|
|
5
|
+
class="categories-dropdown"
|
|
6
|
+
:style="{ left: offsetLeft }"
|
|
7
|
+
@mouseleave="emit('hide')"
|
|
8
|
+
@blur="emit('hide')"
|
|
9
|
+
>
|
|
10
|
+
<ul class="category-list">
|
|
11
|
+
<li
|
|
12
|
+
v-if="categoryId === undefined"
|
|
13
|
+
class="category-item"
|
|
14
|
+
>
|
|
15
|
+
<a
|
|
16
|
+
:href="getCategoryLink('/products')"
|
|
17
|
+
class="category-link"
|
|
18
|
+
>
|
|
19
|
+
<span>View all</span>
|
|
20
|
+
</a>
|
|
21
|
+
</li>
|
|
22
|
+
<li
|
|
23
|
+
v-for="category in categories"
|
|
24
|
+
:key="category.id"
|
|
25
|
+
class="category-item"
|
|
26
|
+
>
|
|
27
|
+
<a
|
|
28
|
+
:href="getCategoryLink(category.urlPath)"
|
|
29
|
+
class="category-link"
|
|
30
|
+
>
|
|
31
|
+
<span>{{ category.name }}</span>
|
|
32
|
+
<span v-if="category.hasChildren" class="arrow">▶</span>
|
|
33
|
+
</a>
|
|
34
|
+
<ul v-if="category.hasChildren" class="subcategory-list">
|
|
35
|
+
<li
|
|
36
|
+
v-for="child in category.children"
|
|
37
|
+
:key="child.id"
|
|
38
|
+
class="subcategory-item"
|
|
39
|
+
>
|
|
40
|
+
<a
|
|
41
|
+
:href="getCategoryLink(child.urlPath)"
|
|
42
|
+
class="subcategory-link"
|
|
43
|
+
>
|
|
44
|
+
{{ child.name }}
|
|
45
|
+
</a>
|
|
46
|
+
</li>
|
|
47
|
+
</ul>
|
|
48
|
+
</li>
|
|
49
|
+
</ul>
|
|
50
|
+
</div>
|
|
51
|
+
</teleport>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
import { computed } from 'vue';
|
|
56
|
+
import { useVueBaseProps } from '@lightspeed/crane';
|
|
57
|
+
import { Design } from '../type.ts';
|
|
58
|
+
|
|
59
|
+
interface Props {
|
|
60
|
+
element?: HTMLElement;
|
|
61
|
+
categoryId?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const props = defineProps<Props>();
|
|
65
|
+
const emit = defineEmits(['hide']);
|
|
66
|
+
|
|
67
|
+
const baseProps = useVueBaseProps<Props, Design>();
|
|
68
|
+
|
|
69
|
+
const isPreviewMode = computed(() => Boolean(baseProps.site?.value?.isPreviewMode));
|
|
70
|
+
const categoryTree = computed(() => baseProps.category?.value?.categoryTree ?? []);
|
|
71
|
+
const categories = computed(() => categoryTree.value
|
|
72
|
+
.filter(filterUniqueCategories)
|
|
73
|
+
.filter((category) => filterByCategoryId(category, props.categoryId))
|
|
74
|
+
.map((category) => ({
|
|
75
|
+
...category,
|
|
76
|
+
hasChildren: category.children?.length > 0,
|
|
77
|
+
}))
|
|
78
|
+
);
|
|
79
|
+
const offsetLeft = computed(() => `${props.element?.offsetLeft ?? 0}px`);
|
|
80
|
+
|
|
81
|
+
function filterUniqueCategories(category: CategoryTree, index: number, categoryTree: CategoryTree[]) {
|
|
82
|
+
return categoryTree.findIndex((c) => c.id === category.id) === index;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function filterByCategoryId(category: CategoryTree, categoryId?: number) {
|
|
86
|
+
if (categoryId !== undefined) {
|
|
87
|
+
return category.id === categoryId;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const getCategoryLink = (urlPath: string) => {
|
|
93
|
+
if (isPreviewMode.value) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return urlPath;
|
|
97
|
+
};
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<style scoped lang="scss">
|
|
101
|
+
.categories-dropdown {
|
|
102
|
+
position: absolute;
|
|
103
|
+
top: 48px;
|
|
104
|
+
left: 12px;
|
|
105
|
+
background-color: #ffffff;
|
|
106
|
+
border: 1px solid #ddd;
|
|
107
|
+
border-radius: 6px;
|
|
108
|
+
min-width: 200px;
|
|
109
|
+
padding: 8px;
|
|
110
|
+
z-index: 1000;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.category-list,
|
|
114
|
+
.subcategory-list {
|
|
115
|
+
list-style-type: none;
|
|
116
|
+
margin: 0;
|
|
117
|
+
padding: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.category-item,
|
|
121
|
+
.subcategory-item {
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
position: relative;
|
|
124
|
+
margin: 0;
|
|
125
|
+
padding: 6px 10px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.category-link,
|
|
129
|
+
.subcategory-link {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
justify-content: space-between;
|
|
133
|
+
color: #080d12;
|
|
134
|
+
text-decoration: none;
|
|
135
|
+
width: 100%;
|
|
136
|
+
transition: color 0.35s ease;
|
|
137
|
+
|
|
138
|
+
&:hover {
|
|
139
|
+
color: #0056b3;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.arrow {
|
|
144
|
+
margin-left: 8px;
|
|
145
|
+
font-size: 10px;
|
|
146
|
+
color: #b7b7b7;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.subcategory-list {
|
|
150
|
+
display: none;
|
|
151
|
+
position: absolute;
|
|
152
|
+
top: 0;
|
|
153
|
+
left: 100%;
|
|
154
|
+
background-color: #ffffff;
|
|
155
|
+
border: 1px solid #ddd;
|
|
156
|
+
border-radius: 6px;
|
|
157
|
+
min-width: 200px;
|
|
158
|
+
padding: 8px;
|
|
159
|
+
z-index: 1001;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.category-item:hover > .subcategory-list {
|
|
163
|
+
display: block;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
@@ -3,42 +3,109 @@
|
|
|
3
3
|
v-if="navigationMenu.hasContent"
|
|
4
4
|
role="navigation"
|
|
5
5
|
>
|
|
6
|
-
<ul>
|
|
6
|
+
<ul class="navigation-menu">
|
|
7
7
|
<li
|
|
8
8
|
v-for="item in navigationMenu.items"
|
|
9
9
|
:key="item.id"
|
|
10
|
+
class="menu-item"
|
|
11
|
+
@mouseenter="onMouseEnter(item, $event)"
|
|
12
|
+
@mouseleave="onMouseLeave(item)"
|
|
13
|
+
@focusin="onMouseEnter(item, $event)"
|
|
14
|
+
@focusout="onMouseLeave(item)"
|
|
10
15
|
>
|
|
11
|
-
<a
|
|
16
|
+
<a
|
|
17
|
+
class="menu-link"
|
|
18
|
+
@click="item.performAction"
|
|
19
|
+
>
|
|
12
20
|
{{ item.title }}
|
|
13
21
|
</a>
|
|
22
|
+
<span
|
|
23
|
+
v-if="item.showStoreCategories && isItemWithCategoriesDropdown(item)"
|
|
24
|
+
class="arrow"
|
|
25
|
+
>
|
|
26
|
+
▶
|
|
27
|
+
</span>
|
|
14
28
|
</li>
|
|
15
29
|
</ul>
|
|
30
|
+
<CategoriesDropdown
|
|
31
|
+
v-if="showCategoriesDropdown"
|
|
32
|
+
:element="activeItem?.element"
|
|
33
|
+
:category-id="categoryId"
|
|
34
|
+
@hide="hideDropdown"
|
|
35
|
+
/>
|
|
16
36
|
</nav>
|
|
17
37
|
</template>
|
|
18
38
|
|
|
19
39
|
<script setup lang="ts">
|
|
40
|
+
import { ref, computed } from 'vue';
|
|
20
41
|
import { useNavigationMenuElementContent } from '@lightspeed/crane';
|
|
42
|
+
import CategoriesDropdown from './CategoriesDropdown.vue';
|
|
43
|
+
|
|
44
|
+
interface ActiveItem {
|
|
45
|
+
actionLink: ActionLink;
|
|
46
|
+
element?: HTMLElement;
|
|
47
|
+
}
|
|
21
48
|
|
|
22
49
|
const navigationMenu = useNavigationMenuElementContent();
|
|
50
|
+
const activeItem = ref<ActiveItem | null>();
|
|
51
|
+
|
|
52
|
+
const showCategoriesDropdown = computed(() => {
|
|
53
|
+
const item = activeItem.value?.actionLink;
|
|
54
|
+
if (isItemWithCategoriesDropdown(item)) {
|
|
55
|
+
return item?.showStoreCategories ?? true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const categoryId = computed(() => {
|
|
61
|
+
const item = activeItem.value?.actionLink;
|
|
62
|
+
if (item?.type === 'GO_TO_CATEGORY') {
|
|
63
|
+
return item.categoryId;
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
function isItemWithCategoriesDropdown(item?: ActionLink) {
|
|
69
|
+
return item?.type === 'GO_TO_STORE' || item?.type === 'GO_TO_CATEGORY';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function onMouseEnter(item: ActionLink, event: MouseEvent | FocusEvent) {
|
|
73
|
+
activeItem.value = {
|
|
74
|
+
actionLink: item,
|
|
75
|
+
element: event.target as HTMLElement,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function onMouseLeave(item: ActionLink | null) {
|
|
80
|
+
if (activeItem.value?.actionLink === item) {
|
|
81
|
+
activeItem.value = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function hideDropdown() {
|
|
86
|
+
activeItem.value = null;
|
|
87
|
+
}
|
|
23
88
|
</script>
|
|
24
89
|
|
|
25
|
-
<style lang="scss"
|
|
26
|
-
|
|
27
|
-
gap: 16px;
|
|
90
|
+
<style scoped lang="scss">
|
|
91
|
+
.navigation-menu {
|
|
28
92
|
display: flex;
|
|
93
|
+
gap: 16px;
|
|
29
94
|
overflow-x: auto;
|
|
30
95
|
white-space: nowrap;
|
|
31
96
|
height: 48px;
|
|
97
|
+
list-style-type: none;
|
|
98
|
+
margin: 0;
|
|
99
|
+
padding: 0;
|
|
32
100
|
}
|
|
33
101
|
|
|
34
|
-
|
|
35
|
-
|
|
102
|
+
.menu-item {
|
|
103
|
+
position: relative;
|
|
36
104
|
display: flex;
|
|
37
105
|
align-items: center;
|
|
38
|
-
min-width: fit-content;
|
|
39
106
|
}
|
|
40
107
|
|
|
41
|
-
|
|
108
|
+
.menu-link {
|
|
42
109
|
cursor: pointer;
|
|
43
110
|
font-size: 16px;
|
|
44
111
|
font-weight: 500;
|
|
@@ -47,7 +114,13 @@ a {
|
|
|
47
114
|
transition: color 0.35s ease;
|
|
48
115
|
|
|
49
116
|
&:hover {
|
|
50
|
-
color: #0056b3
|
|
117
|
+
color: #0056b3;
|
|
51
118
|
}
|
|
52
119
|
}
|
|
120
|
+
|
|
121
|
+
.arrow {
|
|
122
|
+
margin-left: 8px;
|
|
123
|
+
font-size: 8px;
|
|
124
|
+
color: #cacaca;
|
|
125
|
+
}
|
|
53
126
|
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<slot :name="Slot.CATEGORY_TITLE" />
|
|
4
|
+
<slot :name="Slot.PRODUCT_LIST" />
|
|
5
|
+
<slot :name="Slot.BOTTOM_BAR" />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { CategoryLayoutSlot as Slot } from '@lightspeed/crane';
|
|
11
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="{ 'product-details--top-title-navigation': isProductNameAlwaysFirstOnMobile }">
|
|
3
|
+
<slot :name="Slot.TOP_BAR" />
|
|
4
|
+
<div
|
|
5
|
+
:class="availableProductClasses"
|
|
6
|
+
itemtype="http://schema.org/Product"
|
|
7
|
+
:itemscope="showProductDetailsProductPrice"
|
|
8
|
+
>
|
|
9
|
+
<slot :name="Slot.GALLERY" />
|
|
10
|
+
<slot :name="Slot.SIDEBAR" />
|
|
11
|
+
<slot :name="Slot.DESCRIPTION" />
|
|
12
|
+
<div class="clearboth" />
|
|
13
|
+
</div>
|
|
14
|
+
<slot :name="Slot.REVIEW_LIST" />
|
|
15
|
+
<slot :name="Slot.RELATED_PRODUCTS" />
|
|
16
|
+
<slot :name="Slot.BOTTOM_BAR" />
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { HTMLAttributes } from 'vue';
|
|
22
|
+
import { ProductLayoutSlot as Slot } from '@lightspeed/crane';
|
|
23
|
+
|
|
24
|
+
interface Props {
|
|
25
|
+
availableProductClasses?: HTMLAttributes['class'],
|
|
26
|
+
showProductDetailsProductPrice?: boolean,
|
|
27
|
+
isProductNameAlwaysFirstOnMobile?: boolean,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
withDefaults(defineProps<Props>(), {
|
|
31
|
+
isProductNameAlwaysFirstOnMobile: false,
|
|
32
|
+
availableProductClasses: '',
|
|
33
|
+
showProductDetailsProductPrice: true,
|
|
34
|
+
});
|
|
35
|
+
</script>
|
package/types.d.ts
CHANGED
|
@@ -8,13 +8,14 @@ declare module '*.vue' {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
type ActionLinkType
|
|
11
|
-
|
|
11
|
+
= 'SCROLL_TO_TILE'
|
|
12
12
|
| 'HYPER_LINK'
|
|
13
13
|
| 'MAIL_LINK'
|
|
14
14
|
| 'TEL_LINK'
|
|
15
15
|
| 'GO_TO_STORE'
|
|
16
16
|
| 'GO_TO_STORE_LINK'
|
|
17
|
-
| 'GO_TO_PAGE'
|
|
17
|
+
| 'GO_TO_PAGE'
|
|
18
|
+
| 'GO_TO_CATEGORY';
|
|
18
19
|
|
|
19
20
|
interface ButtonContentData {
|
|
20
21
|
readonly title: string;
|
|
@@ -56,7 +57,7 @@ interface ToggleContentData {
|
|
|
56
57
|
interface ActionLink {
|
|
57
58
|
id: string;
|
|
58
59
|
title?: string;
|
|
59
|
-
type?:
|
|
60
|
+
type?: ActionLinkType;
|
|
60
61
|
link?: string;
|
|
61
62
|
email?: string;
|
|
62
63
|
phone?: string;
|
|
@@ -77,24 +78,24 @@ type LogoType = 'TEXT' | 'IMAGE';
|
|
|
77
78
|
interface LogoContentData {
|
|
78
79
|
readonly type: LogoType;
|
|
79
80
|
readonly text: string;
|
|
80
|
-
readonly image: ImageContentData
|
|
81
|
+
readonly image: ImageContentData;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
type GlobalColorsString =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
'global.color.title' |
|
|
86
|
+
'global.color.body' |
|
|
87
|
+
'global.color.button' |
|
|
88
|
+
'global.color.link' |
|
|
89
|
+
'global.color.background';
|
|
89
90
|
|
|
90
91
|
type GlobalFontsString =
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
'global.fontFamily.title' |
|
|
93
|
+
'global.fontFamily.body';
|
|
93
94
|
|
|
94
95
|
type GlobalTextSizeString =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
'global.textSize.title' |
|
|
97
|
+
'global.textSize.subtitle' |
|
|
98
|
+
'global.textSize.body';
|
|
98
99
|
|
|
99
100
|
interface HSLColor {
|
|
100
101
|
h: number;
|
|
@@ -140,9 +141,9 @@ interface TextareaDesignData extends TextDesignData {
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
type CapitalizationType =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
'none'
|
|
145
|
+
| 'all'
|
|
146
|
+
| 'small';
|
|
146
147
|
|
|
147
148
|
interface Frame {
|
|
148
149
|
visible: boolean;
|
|
@@ -163,19 +164,19 @@ interface LogoDesignData {
|
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
type ButtonAppearance =
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
'solid-button'
|
|
168
|
+
| 'outline-button'
|
|
169
|
+
| 'text-link';
|
|
169
170
|
|
|
170
171
|
type ButtonSize =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
'small'
|
|
173
|
+
| 'medium'
|
|
174
|
+
| 'large';
|
|
174
175
|
|
|
175
176
|
type ButtonStyle =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
'round-corner'
|
|
178
|
+
| 'rectangle'
|
|
179
|
+
| 'pill';
|
|
179
180
|
|
|
180
181
|
interface ButtonDesignData {
|
|
181
182
|
appearance: ButtonAppearance | undefined;
|
|
@@ -187,9 +188,9 @@ interface ButtonDesignData {
|
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
type OverlayType =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
'solid'
|
|
192
|
+
| 'gradient'
|
|
193
|
+
| 'none';
|
|
193
194
|
|
|
194
195
|
interface Overlay {
|
|
195
196
|
type: OverlayType | undefined;
|
|
@@ -211,8 +212,8 @@ interface ToggleDesignData {
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
type BackgroundType =
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
'solid'
|
|
216
|
+
| 'gradient';
|
|
216
217
|
|
|
217
218
|
interface Background {
|
|
218
219
|
type: BackgroundType | undefined;
|
|
@@ -295,8 +296,33 @@ interface SiteContent {
|
|
|
295
296
|
readonly legalPages?: LegalPage[];
|
|
296
297
|
}
|
|
297
298
|
|
|
299
|
+
interface CategoryListComponentItem {
|
|
300
|
+
readonly id: number;
|
|
301
|
+
readonly name: string;
|
|
302
|
+
readonly url: string;
|
|
303
|
+
readonly imageUrl?: string;
|
|
304
|
+
readonly thumbnailImageUrl?: string;
|
|
305
|
+
readonly imageBorderInfo?: ImageBorderInfo;
|
|
306
|
+
readonly alt?: string;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
interface CategoryTree {
|
|
310
|
+
readonly id: number;
|
|
311
|
+
readonly name: string;
|
|
312
|
+
readonly nameTranslated: Record<string, string>;
|
|
313
|
+
readonly urlPath: string;
|
|
314
|
+
readonly enabled: boolean;
|
|
315
|
+
readonly children: CategoryTree[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
interface Category {
|
|
319
|
+
readonly categories?: CategoryListComponentItem[];
|
|
320
|
+
readonly categoryTree?: CategoryTree[];
|
|
321
|
+
}
|
|
322
|
+
|
|
298
323
|
interface ExternalContentData {
|
|
299
|
-
|
|
324
|
+
readonly site?: SiteContent;
|
|
325
|
+
readonly category?: Category;
|
|
300
326
|
}
|
|
301
327
|
|
|
302
328
|
interface ButtonContentEditor {
|
|
@@ -344,19 +370,19 @@ interface LogoContentEditor {
|
|
|
344
370
|
}
|
|
345
371
|
|
|
346
372
|
type ContentEditor =
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
373
|
+
TextContentEditor
|
|
374
|
+
| MultilineTextContentEditor
|
|
375
|
+
| ButtonContentEditor
|
|
376
|
+
| ImageContentEditor
|
|
377
|
+
| ToggleContentEditor
|
|
378
|
+
| SelectboxContentEditor
|
|
379
|
+
| MenuContentEditor
|
|
380
|
+
| NavigationMenuContentEditor
|
|
381
|
+
| LogoContentEditor;
|
|
356
382
|
|
|
357
383
|
type InferContentType<T extends Record<string, ContentEditor>> = {
|
|
358
384
|
readonly [P in keyof T]: MapEditorContentTypes[T[P]['type']]
|
|
359
|
-
}
|
|
385
|
+
};
|
|
360
386
|
|
|
361
387
|
type MapEditorDesignTypes = {
|
|
362
388
|
readonly TEXT: string;
|
|
@@ -418,8 +444,8 @@ interface LogoDesignEditor {
|
|
|
418
444
|
}
|
|
419
445
|
|
|
420
446
|
interface DividerDesignEditor {
|
|
421
|
-
|
|
422
|
-
|
|
447
|
+
readonly type: 'DIVIDER';
|
|
448
|
+
readonly label: string | Record<string, string>;
|
|
423
449
|
}
|
|
424
450
|
|
|
425
451
|
type DesignEditor =
|
|
@@ -435,6 +461,6 @@ type DesignEditor =
|
|
|
435
461
|
|
|
436
462
|
type InferDesignType<T extends Record<string, DesignEditor>> = {
|
|
437
463
|
readonly [P in keyof T]: MapEditorDesignTypes[T[P]['type']]
|
|
438
|
-
}
|
|
464
|
+
};
|
|
439
465
|
|
|
440
466
|
type SettingsEditor = DesignEditor | ContentEditor;
|