@lightspeed/crane 2.0.0 → 2.0.2
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 +30 -0
- package/dist/cli.mjs +15 -15
- package/package.json +5 -5
- package/template/footers/example-footer/client.ts +1 -0
- package/template/footers/example-footer/server.ts +1 -0
- package/template/headers/example-header/client.ts +1 -0
- package/template/headers/example-header/server.ts +1 -0
- package/template/layouts/catalog/example-catalog/slots/custom-bottom-bar/client.ts +1 -0
- package/template/layouts/catalog/example-catalog/slots/custom-bottom-bar/server.ts +1 -0
- package/template/package.json +1 -1
- package/template/page-templates/example-template/configuration.ts +3 -0
- package/template/preview/shared/api-routes.ts +170 -4
- package/template/preview/shared/preview.ts +20 -2
- package/template/preview/shared/utils.ts +3 -2
- package/template/preview/ssr-server.ts +3 -2
- package/template/preview/vite.config.js +4 -2
- package/template/reference/sections/featured-products/client.ts +1 -0
- package/template/reference/sections/featured-products/server.ts +1 -0
- package/template/reference/sections/intro-slider/client.ts +1 -0
- package/template/reference/sections/intro-slider/server.ts +1 -0
- package/template/reference/sections/tag-lines/client.ts +1 -0
- package/template/reference/sections/tag-lines/composables/highlighted-text-image-list.ts +2 -1
- package/template/reference/sections/tag-lines/server.ts +1 -0
- package/template/reference/sections/trending-categories/client.ts +1 -0
- package/template/reference/sections/trending-categories/server.ts +1 -0
- package/template/reference/shared/utils/styles.ts +1 -0
- package/template/sections/example-section/client.ts +1 -0
- package/template/sections/example-section/server.ts +1 -0
- package/template/sections/example-section/showcases/1.ts +2 -22
- package/template/sections/example-section/showcases/2.ts +2 -22
- package/template/sections/example-section/showcases/3.ts +2 -22
- package/template/sections/example-section/showcases/translations.ts +4 -142
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightspeed/crane",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "bin/crane.js",
|
|
6
6
|
"main": "./dist/app.mjs",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@jest/globals": "^30.0.4",
|
|
42
|
-
"@
|
|
42
|
+
"@lightspeed/eslint-config": "workspace:*",
|
|
43
43
|
"@types/adm-zip": "^0.5.7",
|
|
44
44
|
"@types/axios-concurrency": "^1.0.0",
|
|
45
45
|
"@types/cli-progress": "^3.11.6",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@jridgewell/sourcemap-codec": "^1.5.4",
|
|
67
|
-
"@lightspeed/crane-api": "1.0.
|
|
67
|
+
"@lightspeed/crane-api": "1.0.2",
|
|
68
68
|
"@lightspeed/eslint-config-crane": "1.1.3",
|
|
69
69
|
"@types/prompts": "^2.4.2",
|
|
70
70
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"cli-progress": "^3.12.0",
|
|
78
78
|
"eslint": "^9.33.0",
|
|
79
79
|
"fs-extra": "^11.3.1",
|
|
80
|
-
"glob": "^11.0
|
|
80
|
+
"glob": "^11.1.0",
|
|
81
81
|
"jsonpath-plus": "^10.3.0",
|
|
82
82
|
"kolorist": "^1.8.0",
|
|
83
83
|
"prompts": "^2.4.2",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"axios": "1.11.0"
|
|
102
102
|
},
|
|
103
103
|
"magic-string": "0.30.10",
|
|
104
|
-
"glob": "^11.0
|
|
104
|
+
"glob": "^11.1.0",
|
|
105
105
|
"stylus": "^0.64.0"
|
|
106
106
|
}
|
|
107
107
|
}
|
package/template/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { TemplateCategoriesList } from '@lightspeed/crane-api';
|
|
2
|
+
|
|
1
3
|
export default {
|
|
2
4
|
metadata: {
|
|
3
5
|
name: 'Example Template :: Standard Preset',
|
|
4
6
|
description: 'Standard Preset for the Example template',
|
|
7
|
+
categories: [TemplateCategoriesList.apparel_footwear],
|
|
5
8
|
preview_url: 'https://template_preview.company.site',
|
|
6
9
|
cover_image: {
|
|
7
10
|
set: {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import * as path from 'path';
|
|
2
1
|
import * as fs from 'fs';
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
3
|
+
import * as path from 'path';
|
|
3
4
|
import { URL } from 'url';
|
|
5
|
+
|
|
4
6
|
import { getShowcaseData } from './preview';
|
|
5
7
|
import { fetchTiles, updateTilesSection, updateCustomContent } from './utils';
|
|
6
|
-
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Extract query parameter from URL
|
|
@@ -17,6 +19,29 @@ function getQueryParam(url: string, paramName: string): string | null {
|
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Read request body as JSON
|
|
24
|
+
*/
|
|
25
|
+
function readRequestBody(req: IncomingMessage): Promise<Record<string, unknown>> {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let body = '';
|
|
28
|
+
req.on('data', (chunk) => {
|
|
29
|
+
body += chunk.toString();
|
|
30
|
+
});
|
|
31
|
+
req.on('end', () => {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = body ? JSON.parse(body) : null;
|
|
34
|
+
resolve(parsed);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
reject(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
req.on('error', (error) => {
|
|
40
|
+
reject(error);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
/**
|
|
21
46
|
* Set no-cache headers to prevent browser caching
|
|
22
47
|
*/
|
|
@@ -72,7 +97,7 @@ function getShowcaseIds(sectionName: string, distPath: string): string[] {
|
|
|
72
97
|
* Fetches tiles from remote once and updates them for each section/showcase
|
|
73
98
|
* Accepts section names as parameter from Chrome extension
|
|
74
99
|
*/
|
|
75
|
-
|
|
100
|
+
async function handleGetTile(
|
|
76
101
|
_req: IncomingMessage,
|
|
77
102
|
res: ServerResponse,
|
|
78
103
|
sectionNames: string[],
|
|
@@ -120,6 +145,147 @@ export async function handleGetTile(
|
|
|
120
145
|
}
|
|
121
146
|
}
|
|
122
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Handle PUT /api/v1/tile
|
|
150
|
+
* Updates tiles with content and design from remote
|
|
151
|
+
* Accepts an array of tiles in the request body
|
|
152
|
+
* For each tile, fetches remote data, updates content and design, and sends to original_url
|
|
153
|
+
*/
|
|
154
|
+
async function handleUpdateTile(
|
|
155
|
+
req: IncomingMessage,
|
|
156
|
+
res: ServerResponse,
|
|
157
|
+
authToken?: string,
|
|
158
|
+
originalUrl?: string,
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
const requestBody = await readRequestBody(req);
|
|
161
|
+
try {
|
|
162
|
+
// Read request body containing tiles array
|
|
163
|
+
|
|
164
|
+
if (!requestBody || !Array.isArray(requestBody.tiles)) {
|
|
165
|
+
res.statusCode = 400;
|
|
166
|
+
res.setHeader('Content-Type', 'application/json');
|
|
167
|
+
setNoCacheHeaders(res);
|
|
168
|
+
res.end(JSON.stringify({
|
|
169
|
+
error: 'Invalid request body',
|
|
170
|
+
message: 'Expected { tiles: [...] } in request body',
|
|
171
|
+
}));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const tiles = requestBody.tiles;
|
|
176
|
+
|
|
177
|
+
// Fetch tiles from remote - add published=false query parameter
|
|
178
|
+
const tilesUrl = originalUrl ? `${originalUrl}?published=false` : '';
|
|
179
|
+
const remoteTiles = await fetchTiles(authToken, tilesUrl);
|
|
180
|
+
|
|
181
|
+
if (!remoteTiles || !remoteTiles.tiles) {
|
|
182
|
+
console.error('Can\'t fetch remote tiles or they dont exist from url', tilesUrl);
|
|
183
|
+
res.setHeader('Content-Type', 'application/json');
|
|
184
|
+
setNoCacheHeaders(res);
|
|
185
|
+
res.end(JSON.stringify(requestBody, null, 2));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Iterate over tiles from request body and update with remote data
|
|
190
|
+
const updatedTiles = tiles.map((tile: Record<string, unknown>) => {
|
|
191
|
+
// Find matching tile in remote data by id
|
|
192
|
+
const remoteTile = remoteTiles.tiles.find((rt: Record<string, unknown>) => rt.id === tile.id);
|
|
193
|
+
|
|
194
|
+
if (remoteTile) {
|
|
195
|
+
// Update content and design from remote
|
|
196
|
+
return {
|
|
197
|
+
...tile,
|
|
198
|
+
content: remoteTile.content,
|
|
199
|
+
design: remoteTile.design,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// If no match found, return tile as-is
|
|
204
|
+
return tile;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Prepare updated request body
|
|
208
|
+
const updatedRequestBody = {
|
|
209
|
+
...requestBody,
|
|
210
|
+
tiles: updatedTiles,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Make PUT request to original_url with updated tiles
|
|
214
|
+
if (!originalUrl) {
|
|
215
|
+
console.error('Tile update url was not provided');
|
|
216
|
+
res.statusCode = 400;
|
|
217
|
+
res.setHeader('Content-Type', 'application/json');
|
|
218
|
+
setNoCacheHeaders(res);
|
|
219
|
+
res.end(JSON.stringify(requestBody, null, 2));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const headers: Record<string, string> = {
|
|
224
|
+
'Content-Type': 'application/json',
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (authToken) {
|
|
228
|
+
headers['Authorization'] = authToken;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const response = await fetch(originalUrl, {
|
|
232
|
+
method: 'PUT',
|
|
233
|
+
headers,
|
|
234
|
+
body: JSON.stringify(updatedRequestBody),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
console.error('[API Routes] Failed to update tiles at original_url:', response.status, response.statusText);
|
|
239
|
+
res.statusCode = response.status;
|
|
240
|
+
res.setHeader('Content-Type', 'application/json');
|
|
241
|
+
setNoCacheHeaders(res);
|
|
242
|
+
res.end(JSON.stringify(requestBody, null, 2));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const responseData = await response.json();
|
|
247
|
+
|
|
248
|
+
res.statusCode = 200;
|
|
249
|
+
res.setHeader('Content-Type', 'application/json');
|
|
250
|
+
setNoCacheHeaders(res);
|
|
251
|
+
res.end(JSON.stringify(responseData, null, 2));
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error('[API Routes] ❌ Error updating tiles:', error);
|
|
254
|
+
res.statusCode = 500;
|
|
255
|
+
res.setHeader('Content-Type', 'application/json');
|
|
256
|
+
setNoCacheHeaders(res);
|
|
257
|
+
res.end(JSON.stringify(requestBody, null, 2));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Handle /api/v1/tile (GET and PUT)
|
|
263
|
+
* Routes to appropriate handler based on request method
|
|
264
|
+
*/
|
|
265
|
+
export async function handleTile(
|
|
266
|
+
req: IncomingMessage,
|
|
267
|
+
res: ServerResponse,
|
|
268
|
+
sectionNames: string[],
|
|
269
|
+
authToken?: string,
|
|
270
|
+
originalUrl?: string,
|
|
271
|
+
): Promise<void> {
|
|
272
|
+
const method = req.method?.toUpperCase();
|
|
273
|
+
|
|
274
|
+
if (method === 'GET') {
|
|
275
|
+
await handleGetTile(req, res, sectionNames, authToken, originalUrl);
|
|
276
|
+
} else if (method === 'PUT') {
|
|
277
|
+
await handleUpdateTile(req, res, authToken, originalUrl);
|
|
278
|
+
} else {
|
|
279
|
+
res.statusCode = 405;
|
|
280
|
+
res.setHeader('Content-Type', 'application/json');
|
|
281
|
+
setNoCacheHeaders(res);
|
|
282
|
+
res.end(JSON.stringify({
|
|
283
|
+
error: 'Method not allowed',
|
|
284
|
+
allowedMethods: ['GET', 'PUT'],
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
123
289
|
/**
|
|
124
290
|
* Handle GET /api/v1/sections
|
|
125
291
|
* Returns list of available sections with their showcases
|
|
@@ -405,7 +571,7 @@ export function handleApiRequest(
|
|
|
405
571
|
// Extract section names from query parameter (comma-separated)
|
|
406
572
|
const sectionNamesParam = getQueryParam(url, 'sections');
|
|
407
573
|
const sectionNames = sectionNamesParam ? sectionNamesParam.split(',').map(s => s.trim()) : [];
|
|
408
|
-
|
|
574
|
+
handleTile(req, res, sectionNames, authToken, originalUrl);
|
|
409
575
|
return;
|
|
410
576
|
}
|
|
411
577
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { loadModule, renderServerModule } from './utils';
|
|
3
2
|
import { getExternalContentMock } from './mock';
|
|
3
|
+
import { loadModule, renderServerModule } from './utils';
|
|
4
4
|
|
|
5
5
|
let distFolderPath: string | null = null;
|
|
6
6
|
let currentApp: any = null;
|
|
@@ -431,6 +431,24 @@ export async function renderShowcase(sectionName: string, showcaseId: string): P
|
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
async function getLayout(showcase: any, sectionName: string, distFolder: string) {
|
|
435
|
+
// First, try to get layoutId from showcase
|
|
436
|
+
if (showcase.default?.layoutId) {
|
|
437
|
+
return showcase.default.layoutId;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// If not present in showcase, read from section's layout.mjs
|
|
441
|
+
const basePath = `${distFolder}/sections/${sectionName}`;
|
|
442
|
+
const layoutModule = await loadModule(`${basePath}/js/settings/layout.mjs`) as any;
|
|
443
|
+
|
|
444
|
+
// layout.mjs exports an array of layout configurations
|
|
445
|
+
// Return the first element's layoutId
|
|
446
|
+
if (Array.isArray(layoutModule.default) && layoutModule.default.length > 0) {
|
|
447
|
+
return layoutModule.default[0].layoutId;
|
|
448
|
+
}
|
|
449
|
+
throw new Error('Layout module is not an array or is empty');
|
|
450
|
+
}
|
|
451
|
+
|
|
434
452
|
/**
|
|
435
453
|
* Prepares showcase data (content and design) without rendering.
|
|
436
454
|
* Used by API routes to return tile data.
|
|
@@ -444,7 +462,7 @@ export async function getShowcaseData(sectionName: string, showcaseId: string, d
|
|
|
444
462
|
const backgroundDesign = createBackgroundDesign(showcaseBackground, true); // API render
|
|
445
463
|
const overriddenDesign = designTransformer((design as any).default, (showcase as any).default.design || {});
|
|
446
464
|
overriddenDesign.background = backgroundDesign;
|
|
447
|
-
overriddenDesign.layout = (showcase
|
|
465
|
+
overriddenDesign.layout = await getLayout(showcase, sectionName, distFolder);
|
|
448
466
|
|
|
449
467
|
// Prepare content
|
|
450
468
|
const overriddenContent = getContentToRender(
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { getShowcaseState } from './preview';
|
|
3
|
-
import * as path from 'path';
|
|
4
2
|
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
import { getShowcaseState } from './preview';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Renders a server.js module by directly calling the SSR server.
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* Uses Blockbuster's approach: @swc/core for parsing + importFromString for execution
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as http from 'http';
|
|
8
7
|
import { readFileSync } from 'fs';
|
|
8
|
+
import * as http from 'http';
|
|
9
|
+
|
|
9
10
|
import { parse } from '@swc/core';
|
|
10
|
-
import { importFromString } from 'module-from-string';
|
|
11
11
|
import { parseHTML } from 'linkedom';
|
|
12
|
+
import { importFromString } from 'module-from-string';
|
|
12
13
|
|
|
13
14
|
const PREVIEW_SSR_PORT = process.env.PREVIEW_SSR_PORT ? parseInt(process.env.PREVIEW_SSR_PORT, 10) : 3001;
|
|
14
15
|
const EXTERNAL_IMPORTS_BLOCK_START = '/* EXTERNAL_IMPORTS_START */';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { computed } from 'vue';
|
|
2
1
|
import {
|
|
3
2
|
EditorTypes,
|
|
4
3
|
ImageContent,
|
|
@@ -6,6 +5,8 @@ import {
|
|
|
6
5
|
useDeckElementContent,
|
|
7
6
|
useTextElementDesign,
|
|
8
7
|
} from '@lightspeed/crane-api';
|
|
8
|
+
import { computed } from 'vue';
|
|
9
|
+
|
|
9
10
|
import { Content, Design } from '../type.ts';
|
|
10
11
|
|
|
11
12
|
export type Highlight = {
|
|
@@ -160,30 +160,11 @@ export default {
|
|
|
160
160
|
},
|
|
161
161
|
toggle: {
|
|
162
162
|
type: 'TOGGLE',
|
|
163
|
-
|
|
164
|
-
description: '$label.showcase_1.toggle.description',
|
|
165
|
-
defaults: {
|
|
166
|
-
enabled: true,
|
|
167
|
-
},
|
|
163
|
+
enabled: true,
|
|
168
164
|
},
|
|
169
165
|
selectbox: {
|
|
170
166
|
type: 'SELECTBOX',
|
|
171
|
-
|
|
172
|
-
label: '$label.showcase_1.selectbox.label',
|
|
173
|
-
description: '$label.showcase_1.selectbox.description',
|
|
174
|
-
options: [
|
|
175
|
-
{
|
|
176
|
-
value: 'one',
|
|
177
|
-
label: '$label.showcase_1.selectbox.one.label',
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
value: 'two',
|
|
181
|
-
label: '$label.showcase_1.selectbox.two.label',
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
defaults: {
|
|
185
|
-
value: 'one',
|
|
186
|
-
},
|
|
167
|
+
value: 'one',
|
|
187
168
|
},
|
|
188
169
|
info: {
|
|
189
170
|
type: 'INFO',
|
|
@@ -196,7 +177,6 @@ export default {
|
|
|
196
177
|
},
|
|
197
178
|
button: {
|
|
198
179
|
type: 'BUTTON',
|
|
199
|
-
label: '$label.showcase_1.button.label',
|
|
200
180
|
title: '$label.showcase_1.button.defaults.title',
|
|
201
181
|
buttonType: 'HYPER_LINK',
|
|
202
182
|
link: 'https://www.example.com',
|
|
@@ -139,30 +139,11 @@ export default {
|
|
|
139
139
|
},
|
|
140
140
|
toggle: {
|
|
141
141
|
type: 'TOGGLE',
|
|
142
|
-
|
|
143
|
-
description: '$label.showcase_2.toggle.description',
|
|
144
|
-
defaults: {
|
|
145
|
-
enabled: true,
|
|
146
|
-
},
|
|
142
|
+
enabled: true,
|
|
147
143
|
},
|
|
148
144
|
selectbox: {
|
|
149
145
|
type: 'SELECTBOX',
|
|
150
|
-
|
|
151
|
-
label: '$label.showcase_2.selectbox.label',
|
|
152
|
-
description: '$label.showcase_2.selectbox.description',
|
|
153
|
-
options: [
|
|
154
|
-
{
|
|
155
|
-
value: 'one',
|
|
156
|
-
label: '$label.showcase_2.selectbox.one.label',
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
value: 'two',
|
|
160
|
-
label: '$label.showcase_2.selectbox.two.label',
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
defaults: {
|
|
164
|
-
value: 'one',
|
|
165
|
-
},
|
|
146
|
+
value: 'one',
|
|
166
147
|
},
|
|
167
148
|
info: {
|
|
168
149
|
type: 'INFO',
|
|
@@ -175,7 +156,6 @@ export default {
|
|
|
175
156
|
},
|
|
176
157
|
button: {
|
|
177
158
|
type: 'BUTTON',
|
|
178
|
-
label: '$label.showcase_2.button.label',
|
|
179
159
|
title: '$label.showcase_2.button.defaults.title',
|
|
180
160
|
buttonType: 'HYPER_LINK',
|
|
181
161
|
link: 'https://www.example.com',
|
|
@@ -156,30 +156,11 @@ export default {
|
|
|
156
156
|
},
|
|
157
157
|
toggle: {
|
|
158
158
|
type: 'TOGGLE',
|
|
159
|
-
|
|
160
|
-
description: '$label.showcase_3.toggle.description',
|
|
161
|
-
defaults: {
|
|
162
|
-
enabled: true,
|
|
163
|
-
},
|
|
159
|
+
enabled: true,
|
|
164
160
|
},
|
|
165
161
|
selectbox: {
|
|
166
162
|
type: 'SELECTBOX',
|
|
167
|
-
|
|
168
|
-
label: '$label.showcase_3.selectbox.label',
|
|
169
|
-
description: '$label.showcase_3.selectbox.description',
|
|
170
|
-
options: [
|
|
171
|
-
{
|
|
172
|
-
value: 'one',
|
|
173
|
-
label: '$label.showcase_3.selectbox.one.label',
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
value: 'two',
|
|
177
|
-
label: '$label.showcase_3.selectbox.two.label',
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
defaults: {
|
|
181
|
-
value: 'one',
|
|
182
|
-
},
|
|
163
|
+
value: 'one',
|
|
183
164
|
},
|
|
184
165
|
info: {
|
|
185
166
|
type: 'INFO',
|
|
@@ -192,7 +173,6 @@ export default {
|
|
|
192
173
|
},
|
|
193
174
|
button: {
|
|
194
175
|
type: 'BUTTON',
|
|
195
|
-
label: '$label.showcase_1.button.label',
|
|
196
176
|
title: '$label.showcase_1.button.defaults.title',
|
|
197
177
|
buttonType: 'HYPER_LINK',
|
|
198
178
|
link: 'https://www.example.com',
|