@blocklet/pages-kit-block-studio 0.4.127 → 0.4.129
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.
|
@@ -43,6 +43,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
43
43
|
// import BlockStudio from '@blocklet/pages-kit-block-studio/frontend';
|
|
44
44
|
// export default BlockStudio;
|
|
45
45
|
const Session_1 = require("@arcblock/did-connect/lib/Session");
|
|
46
|
+
const Empty_1 = __importDefault(require("@arcblock/ux/lib/Empty"));
|
|
46
47
|
const context_1 = require("@arcblock/ux/lib/Locale/context");
|
|
47
48
|
const Toast_1 = __importStar(require("@arcblock/ux/lib/Toast"));
|
|
48
49
|
const js_sdk_1 = require("@blocklet/js-sdk");
|
|
@@ -58,6 +59,8 @@ const property_1 = require("@blocklet/pages-kit/utils/property");
|
|
|
58
59
|
const studio_ui_1 = require("@blocklet/studio-ui");
|
|
59
60
|
const ui_react_1 = require("@blocklet/ui-react");
|
|
60
61
|
const Add_1 = __importDefault(require("@mui/icons-material/Add"));
|
|
62
|
+
const LaptopMac_1 = __importDefault(require("@mui/icons-material/LaptopMac"));
|
|
63
|
+
const PhoneAndroid_1 = __importDefault(require("@mui/icons-material/PhoneAndroid"));
|
|
61
64
|
const material_1 = require("@mui/material");
|
|
62
65
|
const ahooks_1 = require("ahooks");
|
|
63
66
|
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
@@ -67,6 +70,8 @@ const react_1 = require("react");
|
|
|
67
70
|
const react_dnd_1 = require("react-dnd");
|
|
68
71
|
const react_dnd_html5_backend_1 = require("react-dnd-html5-backend");
|
|
69
72
|
const react_router_dom_1 = require("react-router-dom");
|
|
73
|
+
const split_pane_react_1 = __importStar(require("split-pane-react"));
|
|
74
|
+
require("split-pane-react/esm/themes/default.css");
|
|
70
75
|
const ufo_1 = require("ufo");
|
|
71
76
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
72
77
|
const client_1 = require("vite-plugin-react-pages/client");
|
|
@@ -83,17 +88,18 @@ function useSessionContext() {
|
|
|
83
88
|
const info = (0, react_1.useContext)(SessionContext);
|
|
84
89
|
return info;
|
|
85
90
|
}
|
|
86
|
-
const LEFT_DRAWER_WIDTH =
|
|
91
|
+
const LEFT_DRAWER_WIDTH = 300;
|
|
87
92
|
const RIGHT_DRAWER_WIDTH = 300;
|
|
88
93
|
const defaultLocale = 'en';
|
|
89
|
-
const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTitle, rightContent, description
|
|
94
|
+
const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTitle, rightContent, description, loading, onConfirm, onClose, }) => {
|
|
95
|
+
const { t } = (0, context_1.useLocaleContext)();
|
|
90
96
|
const handleConfirm = async () => {
|
|
91
97
|
try {
|
|
92
98
|
await onConfirm();
|
|
93
99
|
}
|
|
94
100
|
catch (error) {
|
|
95
101
|
console.error('执行操作失败:', error);
|
|
96
|
-
Toast_1.default.error('
|
|
102
|
+
Toast_1.default.error(t('themeTranslations.operationFailed'));
|
|
97
103
|
}
|
|
98
104
|
};
|
|
99
105
|
return ((0, jsx_runtime_1.jsxs)(material_1.Dialog, { open: open, onClose: onClose, maxWidth: "md", fullWidth: true, children: [(0, jsx_runtime_1.jsx)(material_1.DialogTitle, { children: title }), (0, jsx_runtime_1.jsx)(material_1.DialogContent, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', flexDirection: 'row', mb: 2 }, children: [(0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { flex: 1, mr: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "subtitle2", sx: { mb: 1 }, children: leftTitle }), (0, jsx_runtime_1.jsx)(material_1.TextField, { multiline: true, fullWidth: true, rows: 10, InputProps: {
|
|
@@ -110,13 +116,10 @@ const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTit
|
|
|
110
116
|
fontFamily: 'monospace',
|
|
111
117
|
fontSize: '0.875rem',
|
|
112
118
|
},
|
|
113
|
-
} })] })] }), (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", sx: { mt: 2, color: 'text.secondary' }, children: description })] }) }), (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2 }, children: [(0, jsx_runtime_1.jsx)(material_1.Button, { variant: "outlined", onClick: onClose, sx: { mr: 1 }, children:
|
|
119
|
+
} })] })] }), (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", sx: { mt: 2, color: 'text.secondary' }, children: description })] }) }), (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2 }, children: [(0, jsx_runtime_1.jsx)(material_1.Button, { variant: "outlined", onClick: onClose, sx: { mr: 1 }, children: t('themeTranslations.cancel') }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", onClick: handleConfirm, disabled: loading, children: loading ? (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { size: 24 }) : t('themeTranslations.confirmUpdate') })] })] }));
|
|
114
120
|
};
|
|
115
121
|
function Layout({ loadState, loadedData }) {
|
|
116
122
|
const state = (0, ahooks_1.useReactive)({
|
|
117
|
-
injectBlocks: [],
|
|
118
|
-
selectingParam: null,
|
|
119
|
-
componentSelectOpen: false,
|
|
120
123
|
createResourceOpen: false,
|
|
121
124
|
createBlockOpen: false,
|
|
122
125
|
metadata: {
|
|
@@ -144,8 +147,16 @@ function Layout({ loadState, loadedData }) {
|
|
|
144
147
|
init: false,
|
|
145
148
|
allComponents: [],
|
|
146
149
|
propertiesValue: {},
|
|
150
|
+
draggingSplitPane: false,
|
|
151
|
+
simulatorType: 'pc',
|
|
152
|
+
iframeLoaded: false,
|
|
147
153
|
});
|
|
148
|
-
|
|
154
|
+
// 添加renderComponentTrigger状态,用于触发组件重新渲染
|
|
155
|
+
const [renderComponentTrigger, setRenderComponentTrigger] = (0, react_1.useState)(0);
|
|
156
|
+
const [hSizes, setHSizes] = (0, ahooks_1.useLocalStorageState)('BlockStudioHorizontalSizes', {
|
|
157
|
+
defaultValue: [LEFT_DRAWER_WIDTH, 'auto', RIGHT_DRAWER_WIDTH],
|
|
158
|
+
});
|
|
159
|
+
const { t, locale } = (0, context_1.useLocaleContext)();
|
|
149
160
|
const { session } = useSessionContext();
|
|
150
161
|
const location = (0, react_router_dom_1.useLocation)();
|
|
151
162
|
const navigate = (0, react_router_dom_1.useNavigate)();
|
|
@@ -180,14 +191,6 @@ function Layout({ loadState, loadedData }) {
|
|
|
180
191
|
const response = await api.get('/api/blocks/components');
|
|
181
192
|
return response.data || [];
|
|
182
193
|
};
|
|
183
|
-
(0, react_1.useEffect)(() => {
|
|
184
|
-
if (currentPage && state.injectBlocks.length === 0) {
|
|
185
|
-
state.injectBlocks.push({
|
|
186
|
-
...currentPage,
|
|
187
|
-
level: 0,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}, [currentPage]);
|
|
191
194
|
// Add new effect to fetch metadata when page changes
|
|
192
195
|
(0, react_1.useEffect)(() => {
|
|
193
196
|
const fetchMetadata = async () => {
|
|
@@ -273,39 +276,402 @@ function Layout({ loadState, loadedData }) {
|
|
|
273
276
|
description: '',
|
|
274
277
|
};
|
|
275
278
|
};
|
|
276
|
-
let mergedPropertiesValues =
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
(0,
|
|
282
|
-
locale,
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
279
|
+
let mergedPropertiesValues = (0, react_1.useMemo)(() => {
|
|
280
|
+
return Object.fromEntries(Object.values(state.metadata.properties ?? {}).map(({ data }) => {
|
|
281
|
+
return [
|
|
282
|
+
data.id,
|
|
283
|
+
{
|
|
284
|
+
value: (0, cloneDeep_1.default)(state.propertiesValue[data.id]?.value ??
|
|
285
|
+
(0, property_1.parsePropertyValue)(data, data.locales?.[locale]?.defaultValue ?? data.locales?.[defaultLocale]?.defaultValue, {
|
|
286
|
+
locale,
|
|
287
|
+
defaultLocale,
|
|
288
|
+
})),
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
}));
|
|
292
|
+
}, [JSON.stringify(state.metadata.properties), JSON.stringify(state.propertiesValue)]);
|
|
293
|
+
// 添加防抖函数,延迟渲染
|
|
294
|
+
const { run: triggerRerender } = (0, ahooks_1.useDebounceFn)(() => {
|
|
295
|
+
// 发送消息到 iframe
|
|
296
|
+
try {
|
|
297
|
+
const iframe = document.querySelector('#preview-iframe');
|
|
298
|
+
if (iframe && iframe.contentWindow) {
|
|
299
|
+
// 创建精简版数据,只包含必要信息,并避免循环引用
|
|
300
|
+
const safeData = {
|
|
301
|
+
type: 'STATE_UPDATE',
|
|
302
|
+
data: {
|
|
303
|
+
componentId: state.metadata.id,
|
|
304
|
+
// 不传递整个 components 对象,只传递当前组件需要的最小数据集
|
|
305
|
+
currentComponent: {
|
|
306
|
+
id: state.metadata.id,
|
|
307
|
+
// 使用 JSON 序列化和反序列化清除循环引用和函数
|
|
308
|
+
mergedPropertiesValues: (0, cloneDeep_1.default)({
|
|
309
|
+
...mergedPropertiesValues,
|
|
310
|
+
updatedAt: Date.now(),
|
|
311
|
+
} || {}),
|
|
312
|
+
},
|
|
313
|
+
locale: locale,
|
|
314
|
+
defaultLocale: defaultLocale,
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
iframe.contentWindow.postMessage(safeData, '*');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
console.error('Failed to send message to iframe:', error);
|
|
322
|
+
}
|
|
323
|
+
}, { wait: 50 });
|
|
324
|
+
// 当属性变化时触发重新渲染
|
|
325
|
+
(0, react_1.useEffect)(() => {
|
|
326
|
+
triggerRerender();
|
|
327
|
+
}, [JSON.stringify(mergedPropertiesValues), JSON.stringify(mergedAllBlocks), state.metadata.id, locale]);
|
|
328
|
+
const DraggingSplitPlaceholder = (0, react_1.useMemo)(() => {
|
|
329
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Box, { p: 1.5, width: "100%", height: "100%", children: (0, jsx_runtime_1.jsx)(material_1.Skeleton, { variant: "rectangular", height: "100%", sx: { borderRadius: 1 } }) }));
|
|
330
|
+
}, []);
|
|
331
|
+
// 修改 iframe URL 构建逻辑,添加初始状态参数
|
|
332
|
+
const iframeUrl = (0, react_1.useMemo)(() => {
|
|
333
|
+
const url = new URL(window.location.href);
|
|
334
|
+
url.searchParams.set('simulator', '1');
|
|
335
|
+
// 添加初始状态参数
|
|
336
|
+
url.searchParams.set('componentId', state.metadata.id || '');
|
|
337
|
+
url.searchParams.set('locale', locale || defaultLocale || 'en');
|
|
338
|
+
return url.toString();
|
|
339
|
+
}, [window.location.href, state.metadata.id, locale, defaultLocale]);
|
|
340
|
+
// 获取当前URL参数判断是否是在iframe内
|
|
341
|
+
const isInsideIframe = (0, react_1.useMemo)(() => {
|
|
342
|
+
const url = new URL(window.location.href);
|
|
343
|
+
return url.searchParams.get('simulator') === '1';
|
|
344
|
+
}, [window.location.href]);
|
|
345
|
+
// 添加消息事件监听
|
|
346
|
+
(0, react_1.useEffect)(() => {
|
|
347
|
+
const handleMessage = (event) => {
|
|
348
|
+
if (event.data && event.data.type === 'STATE_UPDATE') {
|
|
349
|
+
// 接收并应用父窗口发来的状态更新
|
|
350
|
+
const { componentId, currentComponent, locale } = event.data.data;
|
|
351
|
+
// 安全地更新组件ID
|
|
352
|
+
if (componentId && componentId !== state.metadata.id) {
|
|
353
|
+
state.metadata.id = componentId;
|
|
354
|
+
}
|
|
355
|
+
// 只更新当前组件的属性值,而不是整个组件列表
|
|
356
|
+
if (currentComponent && currentComponent.mergedPropertiesValues) {
|
|
357
|
+
state.propertiesValue = (0, cloneDeep_1.default)(currentComponent.mergedPropertiesValues);
|
|
358
|
+
}
|
|
359
|
+
setRenderComponentTrigger((prev) => prev + 1);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
window.addEventListener('message', handleMessage);
|
|
363
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
364
|
+
}, []);
|
|
365
|
+
const leftPanelContent = (0, react_1.useMemo)(() => {
|
|
366
|
+
if (state.draggingSplitPane) {
|
|
367
|
+
return DraggingSplitPlaceholder;
|
|
291
368
|
}
|
|
292
|
-
|
|
293
|
-
|
|
369
|
+
return ((0, jsx_runtime_1.jsxs)(material_1.Stack, { height: "100%", children: [(0, jsx_runtime_1.jsxs)(material_1.Stack, { gap: 1, direction: "row", alignItems: "center", sx: { py: 2, pr: 1, pl: 0.5, flex: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { placeholder: t('themeTranslations.search'), sx: { minWidth: 60, flex: 1 }, onChange: (e) => {
|
|
370
|
+
state.searchValue = e.target.value;
|
|
371
|
+
} }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", sx: { minWidth: 40 }, onClick: () => {
|
|
372
|
+
state.createBlockOpen = true;
|
|
373
|
+
}, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), routes?.length > 0 ? ((0, jsx_runtime_1.jsx)(material_1.List, { sx: { pr: 1, overflowY: 'auto', height: 'calc(100% - 60px)' }, children: routes
|
|
374
|
+
.map((route) => {
|
|
375
|
+
const routeName = route;
|
|
376
|
+
const staticDataInRoute = staticData[route]?.main;
|
|
377
|
+
if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
return ((0, jsx_runtime_1.jsx)(material_1.ListItem, { disablePadding: true, children: (0, jsx_runtime_1.jsx)(material_1.ListItemButton, { selected: currentPage.pageId === route, onClick: () => {
|
|
384
|
+
navigate(route);
|
|
385
|
+
state.iframeLoaded = false;
|
|
386
|
+
}, sx: {
|
|
387
|
+
borderRadius: 1,
|
|
388
|
+
mb: 1,
|
|
389
|
+
width: '100%',
|
|
390
|
+
textOverflow: 'ellipsis',
|
|
391
|
+
whiteSpace: 'nowrap',
|
|
392
|
+
overflowX: 'hidden',
|
|
393
|
+
transition: 'all 0.3s ease',
|
|
394
|
+
'&.Mui-selected': {
|
|
395
|
+
backgroundColor: 'primary.main',
|
|
396
|
+
color: 'white',
|
|
397
|
+
'&:hover': {
|
|
398
|
+
backgroundColor: 'primary.main',
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
fontSize: '14px',
|
|
402
|
+
}, children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: staticDataInRoute.blockName || routeName, children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
403
|
+
width: '100%',
|
|
404
|
+
overflow: 'hidden',
|
|
405
|
+
textOverflow: 'ellipsis',
|
|
406
|
+
}, children: staticDataInRoute.blockName || routeName }) }) }) }, route));
|
|
407
|
+
})
|
|
408
|
+
.filter(Boolean) })) : ((0, jsx_runtime_1.jsx)(material_1.Box, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", children: (0, jsx_runtime_1.jsx)(Empty_1.default, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", children: t('themeTranslations.noRoutesFound') }) }) }))] }));
|
|
409
|
+
}, [routes, staticData, state.allComponents, state.searchValue, state.draggingSplitPane, locale]);
|
|
410
|
+
// 修改 middlePanelContent - iframe 内部监听消息
|
|
411
|
+
const middlePanelContent = (0, react_1.useMemo)(() => {
|
|
412
|
+
// 如果在iframe内部,添加消息接收逻辑
|
|
413
|
+
if (isInsideIframe) {
|
|
414
|
+
if (loadState.type === '404' || loadState.type === 'loading') {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
if (loadState.type === 'load-error') {
|
|
418
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Box, { width: "100%", height: "100%", display: "flex", justifyContent: "center", alignItems: "center", children: (0, jsx_runtime_1.jsx)(material_1.Alert, { severity: "error", variant: "filled", children: t('themeTranslations.failedLoadCode') }) }));
|
|
419
|
+
}
|
|
420
|
+
// 从 URL 获取初始组件 ID 和语言
|
|
421
|
+
const url = new URL(window.location.href);
|
|
422
|
+
const initialComponentId = url.searchParams.get('componentId') || state.metadata.id;
|
|
423
|
+
const initialLocale = url.searchParams.get('locale') || locale || 'en';
|
|
424
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Box, { className: "custom-component-root", sx: { height: '100%', width: '100%', overflow: 'auto' }, children: (0, jsx_runtime_1.jsx)(material_1.ThemeProvider, { theme: theme_1.pagesTheme, children: (0, jsx_runtime_1.jsx)(react_1.Suspense, { fallback: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, {}), children: (0, jsx_runtime_1.jsx)(components_2.CustomComponentRenderer, { locale: initialLocale, componentId: initialComponentId || state.metadata.id, dev: { mode: 'draft', components: mergedAllBlocks, defaultLocale }, properties: mergedPropertiesValues }, `custom-${renderComponentTrigger}`) }) }) }));
|
|
294
425
|
}
|
|
295
|
-
//
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
426
|
+
// 外部容器,包含设备切换按钮和iframe
|
|
427
|
+
return ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { height: '100%', display: 'flex', flexDirection: 'column' }, children: [(0, jsx_runtime_1.jsx)(material_1.Box, { sx: { p: 1, display: 'flex', justifyContent: 'center', borderBottom: '1px solid #e0e0e0' }, children: (0, jsx_runtime_1.jsxs)(material_1.ToggleButtonGroup, { size: "small", exclusive: true, color: "primary", value: state.simulatorType, onChange: (_, value) => (state.simulatorType = value ?? state.simulatorType), sx: {
|
|
428
|
+
'& > button': {
|
|
429
|
+
p: 0.75,
|
|
430
|
+
minWidth: 50,
|
|
431
|
+
},
|
|
432
|
+
}, children: [(0, jsx_runtime_1.jsx)(material_1.ToggleButton, { value: "pc", children: (0, jsx_runtime_1.jsx)(LaptopMac_1.default, { fontSize: "small" }) }), (0, jsx_runtime_1.jsx)(material_1.ToggleButton, { value: "mobile", children: (0, jsx_runtime_1.jsx)(PhoneAndroid_1.default, { fontSize: "small" }) })] }) }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
433
|
+
height: '100%',
|
|
434
|
+
width: '100%',
|
|
435
|
+
display: 'flex',
|
|
436
|
+
justifyContent: 'center',
|
|
437
|
+
flex: 1,
|
|
438
|
+
overflowY: 'auto',
|
|
439
|
+
position: 'relative', // 为绝对定位的loading提供参考
|
|
440
|
+
p: 1.5,
|
|
441
|
+
alignItems: 'center',
|
|
442
|
+
}, children: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
|
|
443
|
+
position: 'relative',
|
|
444
|
+
height: '100%',
|
|
445
|
+
width: state.simulatorType === 'mobile' ? '375px' : '100%',
|
|
446
|
+
maxWidth: '100%',
|
|
447
|
+
display: 'flex',
|
|
448
|
+
flexDirection: 'column',
|
|
449
|
+
}, children: [state.simulatorType === 'pc' && ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
450
|
+
height: '30px',
|
|
451
|
+
backgroundColor: '#f5f5f5',
|
|
452
|
+
borderTopLeftRadius: '6px',
|
|
453
|
+
borderTopRightRadius: '6px',
|
|
454
|
+
borderTop: '1px solid #e0e0e0',
|
|
455
|
+
borderLeft: '1px solid #e0e0e0',
|
|
456
|
+
borderRight: '1px solid #e0e0e0',
|
|
457
|
+
display: 'flex',
|
|
458
|
+
alignItems: 'center',
|
|
459
|
+
px: 1.5,
|
|
460
|
+
}, children: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', gap: 0.7, alignItems: 'center' }, children: [(0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: 12, height: 12, borderRadius: '50%', backgroundColor: '#ff5f57' } }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: 12, height: 12, borderRadius: '50%', backgroundColor: '#febc2e' } }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: 12, height: 12, borderRadius: '50%', backgroundColor: '#28c840' } })] }) })), state.simulatorType === 'mobile' && ((0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
|
|
461
|
+
height: '30px',
|
|
462
|
+
backgroundColor: '#111',
|
|
463
|
+
borderTopLeftRadius: '20px',
|
|
464
|
+
borderTopRightRadius: '20px',
|
|
465
|
+
display: 'flex',
|
|
466
|
+
justifyContent: 'center',
|
|
467
|
+
alignItems: 'center',
|
|
468
|
+
boxShadow: '0 0 0 12px #111',
|
|
469
|
+
mt: 2,
|
|
470
|
+
}, children: [(0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
471
|
+
width: '60px',
|
|
472
|
+
height: '5px',
|
|
473
|
+
backgroundColor: '#333',
|
|
474
|
+
borderRadius: '3px',
|
|
475
|
+
} }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
476
|
+
width: '40%',
|
|
477
|
+
height: '5px',
|
|
478
|
+
backgroundColor: '#333',
|
|
479
|
+
borderRadius: '3px',
|
|
480
|
+
position: 'absolute',
|
|
481
|
+
bottom: 20,
|
|
482
|
+
left: '50%',
|
|
483
|
+
transform: 'translateX(-50%)',
|
|
484
|
+
} })] })), !state.iframeLoaded && !isInsideIframe && ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
485
|
+
position: 'absolute',
|
|
486
|
+
top: 0,
|
|
487
|
+
left: 0,
|
|
488
|
+
right: 0,
|
|
489
|
+
bottom: 0,
|
|
490
|
+
display: 'flex',
|
|
491
|
+
justifyContent: 'center',
|
|
492
|
+
alignItems: 'center',
|
|
493
|
+
zIndex: 2,
|
|
494
|
+
}, children: (0, jsx_runtime_1.jsx)(material_1.CircularProgress, {}) })), (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: {
|
|
495
|
+
border: 'none',
|
|
496
|
+
height: state.simulatorType === 'mobile' ? 'calc(100% - 60px)' : 'calc(100% - 30px)',
|
|
497
|
+
display: 'flex',
|
|
498
|
+
width: '100%',
|
|
499
|
+
backgroundColor: '#fff',
|
|
500
|
+
...(state.simulatorType === 'mobile'
|
|
501
|
+
? {
|
|
502
|
+
borderRadius: '0 0 20px 20px',
|
|
503
|
+
boxShadow: '0 0 0 12px #111',
|
|
504
|
+
}
|
|
505
|
+
: {
|
|
506
|
+
borderBottomLeftRadius: '6px',
|
|
507
|
+
borderBottomRightRadius: '6px',
|
|
508
|
+
border: '1px solid #e0e0e0',
|
|
509
|
+
}),
|
|
510
|
+
}, children: [state.draggingSplitPane && DraggingSplitPlaceholder, (0, jsx_runtime_1.jsx)(material_1.Box, { id: "preview-iframe", component: "iframe", src: iframeUrl, sx: {
|
|
511
|
+
flex: 1,
|
|
512
|
+
border: 'none',
|
|
513
|
+
display: state.draggingSplitPane ? 'none' : 'flex',
|
|
514
|
+
}, onLoad: () => {
|
|
515
|
+
state.iframeLoaded = true;
|
|
516
|
+
}, title: "Component Preview" })] })] }) })] }, "middle-panel"));
|
|
517
|
+
}, [
|
|
518
|
+
loadedData,
|
|
519
|
+
loadState,
|
|
520
|
+
iframeUrl,
|
|
521
|
+
state.simulatorType,
|
|
522
|
+
state.draggingSplitPane,
|
|
523
|
+
renderComponentTrigger,
|
|
524
|
+
isInsideIframe,
|
|
525
|
+
state.iframeLoaded,
|
|
526
|
+
locale,
|
|
527
|
+
]);
|
|
528
|
+
const rightPanelContent = (0, react_1.useMemo)(() => {
|
|
529
|
+
if (state.draggingSplitPane) {
|
|
530
|
+
return DraggingSplitPlaceholder;
|
|
531
|
+
}
|
|
532
|
+
return ((0, jsx_runtime_1.jsxs)(material_1.List, { sx: { height: '100%', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: '100%' }, children: (0, jsx_runtime_1.jsx)(components_1.BasicInfo, { config: state.metadata }) }) }), (0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { width: '100%' }, children: [(0, jsx_runtime_1.jsx)(components_1.PropertiesConfig, { config: state.metadata, currentLocale: locale, defaultLocale: defaultLocale, allComponents: mergedAllBlocks, onUpdateConfig: (updater) => {
|
|
533
|
+
updater(state.metadata);
|
|
534
|
+
}, useI18nEditor: false }), (0, jsx_runtime_1.jsxs)(material_1.Stack, { direction: "column", spacing: 1, sx: { mt: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", size: "small", color: "primary", onClick: async () => {
|
|
535
|
+
try {
|
|
536
|
+
const { dataPath } = getStaticData() || {};
|
|
537
|
+
if (!dataPath) {
|
|
538
|
+
Toast_1.default.error(t('themeTranslations.componentPathNotFound'));
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
Toast_1.default.info(t('themeTranslations.analyzingInterface'));
|
|
542
|
+
const response = await api.post('/api/blocks/interface-to-properties', {
|
|
543
|
+
componentPath: dataPath,
|
|
544
|
+
});
|
|
545
|
+
if (response.data.success) {
|
|
546
|
+
const { currentProperties, newProperties } = response.data;
|
|
547
|
+
state.previewDialog = {
|
|
548
|
+
open: true,
|
|
549
|
+
title: t('themeTranslations.interfacePropertiesPreview'),
|
|
550
|
+
leftTitle: t('themeTranslations.currentProperties'),
|
|
551
|
+
leftContent: JSON.stringify(currentProperties, null, 2),
|
|
552
|
+
rightTitle: t('themeTranslations.newProperties'),
|
|
553
|
+
rightContent: JSON.stringify(newProperties, null, 2),
|
|
554
|
+
description: t('themeTranslations.confirmUpdateMetadata'),
|
|
555
|
+
loading: false,
|
|
556
|
+
onConfirm: async () => {
|
|
557
|
+
state.previewDialog.loading = true;
|
|
558
|
+
try {
|
|
559
|
+
const updateResponse = await api.post('/api/blocks/interface-to-properties', {
|
|
560
|
+
componentPath: dataPath,
|
|
561
|
+
write: true,
|
|
562
|
+
});
|
|
563
|
+
if (updateResponse.data.success) {
|
|
564
|
+
Toast_1.default.success(t('themeTranslations.metadataSuccess'));
|
|
565
|
+
// 更新当前的metadata状态
|
|
566
|
+
state.metadata = {
|
|
567
|
+
...updateResponse.data.metadata,
|
|
568
|
+
renderer: state.metadata.renderer,
|
|
569
|
+
};
|
|
570
|
+
state.previewDialog.open = false;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
throw new Error(updateResponse.data.error || t('themeTranslations.generationFailed'));
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
finally {
|
|
577
|
+
state.previewDialog.loading = false;
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
Toast_1.default.error(response.data.error || t('themeTranslations.previewFailed'));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
console.error(error);
|
|
588
|
+
Toast_1.default.error(t('themeTranslations.previewFailed'));
|
|
589
|
+
}
|
|
590
|
+
}, children: t('themeTranslations.interfaceToProperties') }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "outlined", size: "small", color: "primary", onClick: async () => {
|
|
591
|
+
try {
|
|
592
|
+
const { dataPath } = getStaticData() || {};
|
|
593
|
+
if (!dataPath) {
|
|
594
|
+
Toast_1.default.error(t('themeTranslations.componentPathNotFound'));
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
Toast_1.default.info(t('themeTranslations.generatingInterface'));
|
|
598
|
+
const response = await api.post('/api/blocks/properties-to-interface', {
|
|
599
|
+
componentPath: dataPath,
|
|
600
|
+
});
|
|
601
|
+
if (response.data.success) {
|
|
602
|
+
const { currentInterface, newInterface } = response.data;
|
|
603
|
+
state.previewDialog = {
|
|
604
|
+
open: true,
|
|
605
|
+
title: t('themeTranslations.propertiesInterfacePreview'),
|
|
606
|
+
leftTitle: t('themeTranslations.currentInterface'),
|
|
607
|
+
leftContent: currentInterface,
|
|
608
|
+
rightTitle: t('themeTranslations.newInterface'),
|
|
609
|
+
rightContent: newInterface,
|
|
610
|
+
description: t('themeTranslations.confirmUpdateInterface'),
|
|
611
|
+
loading: false,
|
|
612
|
+
onConfirm: async () => {
|
|
613
|
+
state.previewDialog.loading = true;
|
|
614
|
+
try {
|
|
615
|
+
const updateResponse = await api.post('/api/blocks/properties-to-interface', {
|
|
616
|
+
componentPath: dataPath,
|
|
617
|
+
write: true,
|
|
618
|
+
});
|
|
619
|
+
if (updateResponse.data.success) {
|
|
620
|
+
Toast_1.default.success(t('themeTranslations.interfaceSuccess'));
|
|
621
|
+
state.previewDialog.open = false;
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
throw new Error(updateResponse.data.error || t('themeTranslations.generationFailed'));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
finally {
|
|
628
|
+
state.previewDialog.loading = false;
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
Toast_1.default.error(response.data.error || t('themeTranslations.previewGenerationFailed'));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
console.error(error);
|
|
639
|
+
Toast_1.default.error(t('themeTranslations.interfacePreviewFailed'));
|
|
640
|
+
}
|
|
641
|
+
}, children: t('themeTranslations.propertiesToInterface') })] })] }) }), state.metadata.id && ((0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: '100%' }, children: (0, jsx_runtime_1.jsx)(components_1.ParametersConfig, { config: state.metadata, allComponents: mergedAllBlocks, defaultLocale: defaultLocale, locale: locale, propertiesValue: mergedPropertiesValues, onChange: ({ key, value, id, path, ...rest }) => {
|
|
642
|
+
const realPath = [...path, 'data'];
|
|
643
|
+
const property = (0, get_1.default)(state.metadata, realPath);
|
|
644
|
+
// ensure property exist
|
|
645
|
+
if (!property) {
|
|
646
|
+
Toast_1.default.warning(`${t('themeTranslations.propertyNotFound')} ${realPath.join('.')}`);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const realValue = (0, property_1.parsePropertyValue)(property, value.value, {
|
|
650
|
+
locale,
|
|
651
|
+
defaultLocale,
|
|
652
|
+
});
|
|
653
|
+
state.propertiesValue[id] = {
|
|
654
|
+
value: realValue,
|
|
655
|
+
};
|
|
656
|
+
} }) }) }))] }));
|
|
657
|
+
}, [
|
|
658
|
+
JSON.stringify(state.metadata || {}),
|
|
659
|
+
locale,
|
|
660
|
+
defaultLocale,
|
|
661
|
+
JSON.stringify(mergedAllBlocks || []),
|
|
662
|
+
JSON.stringify(mergedPropertiesValues || {}),
|
|
663
|
+
getStaticData,
|
|
664
|
+
state.draggingSplitPane,
|
|
665
|
+
]);
|
|
303
666
|
// add auto redirect to first route
|
|
304
667
|
if (loadState.type === '404' &&
|
|
305
668
|
!routes.includes(location.pathname) &&
|
|
306
669
|
!location.search.includes('no-redirect=true')) {
|
|
307
670
|
return (0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: `${firstRoute ?? '/'}`, replace: true });
|
|
308
671
|
}
|
|
672
|
+
if (isInsideIframe) {
|
|
673
|
+
return middlePanelContent;
|
|
674
|
+
}
|
|
309
675
|
return ((0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: react_dnd_html5_backend_1.HTML5Backend, children: (0, jsx_runtime_1.jsxs)(StyledDashboard, { HeaderProps: {
|
|
310
676
|
// @ts-ignore
|
|
311
677
|
homeLink: (0, ufo_1.joinURL)(basename),
|
|
@@ -313,7 +679,7 @@ function Layout({ loadState, loadedData }) {
|
|
|
313
679
|
return [
|
|
314
680
|
(0, jsx_runtime_1.jsx)(material_1.Button, { onClick: async () => {
|
|
315
681
|
if (!session?.user?.did) {
|
|
316
|
-
Toast_1.default.warning('
|
|
682
|
+
Toast_1.default.warning(t('themeTranslations.connectWallet'));
|
|
317
683
|
await session.login();
|
|
318
684
|
setTimeout(() => {
|
|
319
685
|
state.createResourceOpen = true;
|
|
@@ -322,208 +688,35 @@ function Layout({ loadState, loadedData }) {
|
|
|
322
688
|
else {
|
|
323
689
|
state.createResourceOpen = true;
|
|
324
690
|
}
|
|
325
|
-
}, children:
|
|
691
|
+
}, children: t('themeTranslations.createResource') }, "logout"),
|
|
326
692
|
...addons,
|
|
327
693
|
];
|
|
328
694
|
},
|
|
329
|
-
}, MenusDrawerProps: { sx: { [`.${material_1.backdropClasses.root}`]: { top: 64 } } }, children: [(0, jsx_runtime_1.jsxs)(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
position: 'relative',
|
|
337
|
-
height: '100%',
|
|
695
|
+
}, MenusDrawerProps: { sx: { [`.${material_1.backdropClasses.root}`]: { top: 64 } } }, children: [(0, jsx_runtime_1.jsxs)(StyledSplitPane, { split: "vertical", sizes: hSizes, onChange: setHSizes, sashRender: SashRender, onDragStart: () => (state.draggingSplitPane = true), onDragEnd: () => (state.draggingSplitPane = false), sx: {
|
|
696
|
+
'&.react-split--dragging': {
|
|
697
|
+
'.react-split__pane': {
|
|
698
|
+
'*': {
|
|
699
|
+
userSelect: 'none',
|
|
700
|
+
},
|
|
701
|
+
},
|
|
338
702
|
},
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
} }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", sx: { minWidth: 'auto' }, onClick: () => {
|
|
342
|
-
state.createBlockOpen = true;
|
|
343
|
-
}, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), (0, jsx_runtime_1.jsx)(material_1.List, { sx: { pr: 1, overflowY: 'auto' }, children: routes
|
|
344
|
-
.map((route) => {
|
|
345
|
-
const routeName = route;
|
|
346
|
-
const staticDataInRoute = staticData[route]?.main;
|
|
347
|
-
if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
|
|
348
|
-
return null;
|
|
349
|
-
}
|
|
350
|
-
if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
return ((0, jsx_runtime_1.jsx)(material_1.ListItem, { disablePadding: true, children: (0, jsx_runtime_1.jsx)(material_1.ListItemButton, { selected: currentPage.pageId === route, onClick: () => {
|
|
354
|
-
navigate(route);
|
|
355
|
-
}, sx: {
|
|
356
|
-
borderRadius: 1,
|
|
357
|
-
mb: 1,
|
|
358
|
-
width: '100%',
|
|
359
|
-
textOverflow: 'ellipsis',
|
|
360
|
-
whiteSpace: 'nowrap',
|
|
361
|
-
overflowX: 'hidden',
|
|
362
|
-
transition: 'all 0.3s ease',
|
|
363
|
-
'&.Mui-selected': {
|
|
364
|
-
backgroundColor: 'primary.main',
|
|
365
|
-
color: 'white',
|
|
366
|
-
'&:hover': {
|
|
367
|
-
backgroundColor: 'primary.main',
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
fontSize: '14px',
|
|
371
|
-
}, children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: staticDataInRoute.blockName || routeName, children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
372
|
-
width: '100%',
|
|
373
|
-
overflow: 'hidden',
|
|
374
|
-
textOverflow: 'ellipsis',
|
|
375
|
-
}, children: staticDataInRoute.blockName || routeName }) }) }) }, route));
|
|
376
|
-
})
|
|
377
|
-
.filter(Boolean) })] }), (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { flex: 1, overflowX: 'hidden', overflowY: getStaticData()?.isHtml ? 'hidden' : 'auto' }, children: (0, jsx_runtime_1.jsx)(material_1.ThemeProvider, { theme: theme_1.pagesTheme, children: (0, jsx_runtime_1.jsx)(react_1.Suspense, { children: getRenderContent() }) }) }), (0, jsx_runtime_1.jsx)(material_1.Drawer, { variant: "permanent", anchor: "right", sx: {
|
|
378
|
-
width: RIGHT_DRAWER_WIDTH,
|
|
379
|
-
flexShrink: 0,
|
|
380
|
-
zIndex: 1000,
|
|
381
|
-
'& .MuiDrawer-paper': {
|
|
382
|
-
width: RIGHT_DRAWER_WIDTH,
|
|
383
|
-
boxSizing: 'border-box',
|
|
384
|
-
position: 'relative',
|
|
385
|
-
height: '100%',
|
|
386
|
-
},
|
|
387
|
-
}, children: (0, jsx_runtime_1.jsxs)(material_1.List, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: '100%' }, children: (0, jsx_runtime_1.jsx)(components_1.BasicInfo, { config: state.metadata }) }) }), (0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { width: '100%' }, children: [(0, jsx_runtime_1.jsx)(components_1.PropertiesConfig, { config: state.metadata, currentLocale: locale, defaultLocale: defaultLocale, allComponents: mergedAllBlocks, onUpdateConfig: (updater) => {
|
|
388
|
-
updater(state.metadata);
|
|
389
|
-
}, useI18nEditor: false }), (0, jsx_runtime_1.jsxs)(material_1.Stack, { direction: "column", spacing: 1, sx: { mt: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", size: "small", color: "primary", onClick: async () => {
|
|
390
|
-
try {
|
|
391
|
-
const { dataPath } = getStaticData() || {};
|
|
392
|
-
if (!dataPath) {
|
|
393
|
-
Toast_1.default.error('无法找到组件路径');
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
Toast_1.default.info('正在分析组件接口...');
|
|
397
|
-
const response = await api.post('/api/blocks/interface-to-properties', {
|
|
398
|
-
componentPath: dataPath,
|
|
399
|
-
});
|
|
400
|
-
if (response.data.success) {
|
|
401
|
-
const { currentProperties, newProperties } = response.data;
|
|
402
|
-
state.previewDialog = {
|
|
403
|
-
open: true,
|
|
404
|
-
title: 'Interface → Properties 预览',
|
|
405
|
-
leftTitle: '当前 Properties',
|
|
406
|
-
leftContent: JSON.stringify(currentProperties, null, 2),
|
|
407
|
-
rightTitle: '新 Properties',
|
|
408
|
-
rightContent: JSON.stringify(newProperties, null, 2),
|
|
409
|
-
description: '确认后将更新metadata文件。这将保留现有配置值,但可能更改属性结构。',
|
|
410
|
-
loading: false,
|
|
411
|
-
onConfirm: async () => {
|
|
412
|
-
state.previewDialog.loading = true;
|
|
413
|
-
try {
|
|
414
|
-
const updateResponse = await api.post('/api/blocks/interface-to-properties', {
|
|
415
|
-
componentPath: dataPath,
|
|
416
|
-
write: true,
|
|
417
|
-
});
|
|
418
|
-
if (updateResponse.data.success) {
|
|
419
|
-
Toast_1.default.success('Metadata生成成功!');
|
|
420
|
-
// 更新当前的metadata状态
|
|
421
|
-
state.metadata = {
|
|
422
|
-
...updateResponse.data.metadata,
|
|
423
|
-
renderer: state.metadata.renderer,
|
|
424
|
-
};
|
|
425
|
-
state.previewDialog.open = false;
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
throw new Error(updateResponse.data.error || '生成失败');
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
finally {
|
|
432
|
-
state.previewDialog.loading = false;
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
else {
|
|
438
|
-
Toast_1.default.error(response.data.error || '预览失败');
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
catch (error) {
|
|
442
|
-
console.error('生成预览失败:', error);
|
|
443
|
-
Toast_1.default.error('生成预览失败');
|
|
444
|
-
}
|
|
445
|
-
}, children: "Interface \u2192 Properties" }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "outlined", size: "small", color: "primary", onClick: async () => {
|
|
446
|
-
try {
|
|
447
|
-
const { dataPath } = getStaticData() || {};
|
|
448
|
-
if (!dataPath) {
|
|
449
|
-
Toast_1.default.error('无法找到组件路径');
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
Toast_1.default.info('正在生成TypeScript接口预览...');
|
|
453
|
-
const response = await api.post('/api/blocks/properties-to-interface', {
|
|
454
|
-
componentPath: dataPath,
|
|
455
|
-
});
|
|
456
|
-
if (response.data.success) {
|
|
457
|
-
const { currentInterface, newInterface } = response.data;
|
|
458
|
-
state.previewDialog = {
|
|
459
|
-
open: true,
|
|
460
|
-
title: 'Properties → Interface 预览',
|
|
461
|
-
leftTitle: '当前接口',
|
|
462
|
-
leftContent: currentInterface,
|
|
463
|
-
rightTitle: '新接口',
|
|
464
|
-
rightContent: newInterface,
|
|
465
|
-
description: '确认后将更新TypeScript接口。这将覆盖当前的接口定义。',
|
|
466
|
-
loading: false,
|
|
467
|
-
onConfirm: async () => {
|
|
468
|
-
state.previewDialog.loading = true;
|
|
469
|
-
try {
|
|
470
|
-
const updateResponse = await api.post('/api/blocks/properties-to-interface', {
|
|
471
|
-
componentPath: dataPath,
|
|
472
|
-
write: true,
|
|
473
|
-
});
|
|
474
|
-
if (updateResponse.data.success) {
|
|
475
|
-
Toast_1.default.success('TypeScript接口生成成功!');
|
|
476
|
-
state.previewDialog.open = false;
|
|
477
|
-
}
|
|
478
|
-
else {
|
|
479
|
-
throw new Error(updateResponse.data.error || '生成失败');
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
finally {
|
|
483
|
-
state.previewDialog.loading = false;
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
Toast_1.default.error(response.data.error || '预览失败');
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
catch (error) {
|
|
493
|
-
console.error('生成接口预览失败:', error);
|
|
494
|
-
Toast_1.default.error('生成接口预览失败');
|
|
495
|
-
}
|
|
496
|
-
}, children: "Properties \u2192 Interface" })] })] }) }), state.metadata.id && ((0, jsx_runtime_1.jsx)(material_1.ListItem, { children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: { width: '100%' }, children: (0, jsx_runtime_1.jsx)(components_1.ParametersConfig, { config: state.metadata, allComponents: mergedAllBlocks, defaultLocale: defaultLocale, locale: locale, propertiesValue: mergedPropertiesValues, onChange: ({ key, value, id, path, ...rest }) => {
|
|
497
|
-
const realPath = [...path, 'data'];
|
|
498
|
-
const property = (0, get_1.default)(state.metadata, realPath);
|
|
499
|
-
// ensure property exist
|
|
500
|
-
if (!property) {
|
|
501
|
-
Toast_1.default.warning(`无法找到属性,请检查在 @metadata.json 中,是否存在该属性: ${realPath.join('.')}`);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
const realValue = (0, property_1.parsePropertyValue)(property, value.value, {
|
|
505
|
-
locale,
|
|
506
|
-
defaultLocale,
|
|
507
|
-
});
|
|
508
|
-
state.propertiesValue[id] = {
|
|
509
|
-
value: realValue,
|
|
510
|
-
};
|
|
511
|
-
} }) }) }))] }) }), (0, jsx_runtime_1.jsx)(CreateResource, { open: state.createResourceOpen, onClose: () => {
|
|
703
|
+
flex: 1,
|
|
704
|
+
}, children: [(0, jsx_runtime_1.jsx)(split_pane_react_1.Pane, { minSize: 100, maxSize: 400, children: leftPanelContent }), (0, jsx_runtime_1.jsx)(split_pane_react_1.Pane, { minSize: 400, children: middlePanelContent }), (0, jsx_runtime_1.jsx)(split_pane_react_1.Pane, { minSize: 100, maxSize: '30%', children: rightPanelContent })] }), (0, jsx_runtime_1.jsx)(CreateResource, { open: state.createResourceOpen, onClose: () => {
|
|
512
705
|
state.createResourceOpen = false;
|
|
513
|
-
} }), (0, jsx_runtime_1.jsxs)(material_1.Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [(0, jsx_runtime_1.jsx)(material_1.DialogTitle, { children:
|
|
706
|
+
} }), (0, jsx_runtime_1.jsxs)(material_1.Dialog, { open: state.createBlockOpen, onClose: onCloseCreateBlock, children: [(0, jsx_runtime_1.jsx)(material_1.DialogTitle, { children: t('themeTranslations.createNewBlock') }), (0, jsx_runtime_1.jsx)(material_1.DialogContent, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, { spacing: 2, sx: { pt: 1, minWidth: 300 }, children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { autoFocus: true, required: true, label: t('themeTranslations.name'), fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
|
|
514
707
|
state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
|
|
515
|
-
} }), (0, jsx_runtime_1.jsx)(material_1.TextField, { label:
|
|
708
|
+
} }), (0, jsx_runtime_1.jsx)(material_1.TextField, { label: t('themeTranslations.description'), fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
|
|
516
709
|
state.newBlockParams.description = e.target.value;
|
|
517
710
|
} }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", fullWidth: true, onClick: async () => {
|
|
518
711
|
if (!state.newBlockParams.name) {
|
|
519
|
-
Toast_1.default.warning('
|
|
712
|
+
Toast_1.default.warning(t('themeTranslations.blockNameRequired'));
|
|
520
713
|
return;
|
|
521
714
|
}
|
|
522
715
|
if (routes.some((route) => {
|
|
523
716
|
const staticDataInRoute = staticData[route]?.main;
|
|
524
717
|
return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
|
|
525
718
|
})) {
|
|
526
|
-
Toast_1.default.warning('
|
|
719
|
+
Toast_1.default.warning(t('themeTranslations.blockNameExists'));
|
|
527
720
|
return;
|
|
528
721
|
}
|
|
529
722
|
try {
|
|
@@ -536,12 +729,29 @@ function Layout({ loadState, loadedData }) {
|
|
|
536
729
|
}
|
|
537
730
|
catch (error) {
|
|
538
731
|
console.error('Failed to create block:', error);
|
|
539
|
-
Toast_1.default.error('
|
|
732
|
+
Toast_1.default.error(t('themeTranslations.failedCreateBlock'));
|
|
540
733
|
}
|
|
541
|
-
}, children:
|
|
734
|
+
}, children: t('themeTranslations.create') })] }) })] }), (0, jsx_runtime_1.jsx)(ComparisonPreviewDialog, { open: state.previewDialog.open, title: state.previewDialog.title, leftTitle: state.previewDialog.leftTitle, leftContent: state.previewDialog.leftContent, rightTitle: state.previewDialog.rightTitle, rightContent: state.previewDialog.rightContent, description: state.previewDialog.description, loading: state.previewDialog.loading, onConfirm: state.previewDialog.onConfirm, onClose: () => {
|
|
542
735
|
state.previewDialog.open = false;
|
|
543
736
|
} })] }) }));
|
|
544
737
|
}
|
|
738
|
+
// Add SplitPane styling
|
|
739
|
+
const StyledSplitPane = (0, material_1.styled)(split_pane_react_1.default) `
|
|
740
|
+
.react-split__sash {
|
|
741
|
+
z-index: 1000; // resolve the bug of uploader zIndex
|
|
742
|
+
}
|
|
743
|
+
`;
|
|
744
|
+
function SashRender() {
|
|
745
|
+
return (0, jsx_runtime_1.jsx)(DragHandle, {});
|
|
746
|
+
}
|
|
747
|
+
const DragHandle = (0, material_1.styled)('div') `
|
|
748
|
+
height: 100%;
|
|
749
|
+
background-color: #f0f0f0;
|
|
750
|
+
|
|
751
|
+
&:hover {
|
|
752
|
+
background-color: #e3e3e3;
|
|
753
|
+
}
|
|
754
|
+
`;
|
|
545
755
|
const StyledDashboard = (0, material_1.styled)(studio_ui_1.Dashboard) `
|
|
546
756
|
.dashboard-content {
|
|
547
757
|
display: flex;
|
|
@@ -595,3 +805,85 @@ function CreateResource({ open, onClose }) {
|
|
|
595
805
|
// 默认选中的资源
|
|
596
806
|
resources: {} }) }));
|
|
597
807
|
}
|
|
808
|
+
// 添加 themeTranslations 到 translations 对象
|
|
809
|
+
// 这里我们在运行时扩展 translations 对象,而不是修改源文件
|
|
810
|
+
if (!locales_1.translations.en.themeTranslations) {
|
|
811
|
+
locales_1.translations.en.themeTranslations = {
|
|
812
|
+
search: 'Search Blocks...',
|
|
813
|
+
createNewBlock: 'Create New Block',
|
|
814
|
+
name: 'Name',
|
|
815
|
+
description: 'Description',
|
|
816
|
+
create: 'Create',
|
|
817
|
+
blockNameRequired: 'Block name is required',
|
|
818
|
+
blockNameExists: 'Block name already exists, please change it',
|
|
819
|
+
failedCreateBlock: 'Failed to create block',
|
|
820
|
+
createResource: 'Create Resource',
|
|
821
|
+
failedLoadCode: 'Failed to load component code',
|
|
822
|
+
interfaceToProperties: 'Interface → Properties',
|
|
823
|
+
propertiesToInterface: 'Properties → Interface',
|
|
824
|
+
componentPathNotFound: 'Component path not found',
|
|
825
|
+
analyzingInterface: 'Analyzing component interface...',
|
|
826
|
+
interfacePropertiesPreview: 'Interface → Properties Preview',
|
|
827
|
+
currentProperties: 'Current Properties',
|
|
828
|
+
newProperties: 'New Properties',
|
|
829
|
+
confirmUpdateMetadata: 'Confirm to update metadata file. This will preserve existing configuration values, but may change property structure.',
|
|
830
|
+
metadataSuccess: 'Metadata generated successfully!',
|
|
831
|
+
generationFailed: 'Generation failed',
|
|
832
|
+
previewFailed: 'Failed to generate preview',
|
|
833
|
+
generatingInterface: 'Generating TypeScript interface preview...',
|
|
834
|
+
propertiesInterfacePreview: 'Properties → Interface Preview',
|
|
835
|
+
currentInterface: 'Current Interface',
|
|
836
|
+
newInterface: 'New Interface',
|
|
837
|
+
confirmUpdateInterface: 'Confirm to update TypeScript interface. This will overwrite the current interface definition.',
|
|
838
|
+
interfaceSuccess: 'TypeScript interface generated successfully!',
|
|
839
|
+
previewGenerationFailed: 'Preview failed',
|
|
840
|
+
interfacePreviewFailed: 'Failed to generate interface preview',
|
|
841
|
+
propertyNotFound: 'Property not found, please check if it exists in @metadata.json:',
|
|
842
|
+
connectWallet: 'Please connect wallet first',
|
|
843
|
+
cancel: 'Cancel',
|
|
844
|
+
confirmUpdate: 'Confirm Update',
|
|
845
|
+
configUpdateConfirmation: 'Configuration will be updated after confirmation.',
|
|
846
|
+
operationFailed: 'Operation failed',
|
|
847
|
+
noRoutesFound: 'No Components Found',
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
if (!locales_1.translations.zh.themeTranslations) {
|
|
851
|
+
locales_1.translations.zh.themeTranslations = {
|
|
852
|
+
search: '搜索组件...',
|
|
853
|
+
createNewBlock: '创建新组件',
|
|
854
|
+
name: '名称',
|
|
855
|
+
description: '描述',
|
|
856
|
+
create: '创建',
|
|
857
|
+
blockNameRequired: '组件名称必填',
|
|
858
|
+
blockNameExists: '组件名称已存在,请更改',
|
|
859
|
+
failedCreateBlock: '创建组件失败',
|
|
860
|
+
createResource: '创建资源',
|
|
861
|
+
failedLoadCode: '加载组件代码失败',
|
|
862
|
+
interfaceToProperties: '接口 → 属性',
|
|
863
|
+
propertiesToInterface: '属性 → 接口',
|
|
864
|
+
componentPathNotFound: '无法找到组件路径',
|
|
865
|
+
analyzingInterface: '正在分析组件接口...',
|
|
866
|
+
interfacePropertiesPreview: '接口 → 属性预览',
|
|
867
|
+
currentProperties: '当前属性',
|
|
868
|
+
newProperties: '新属性',
|
|
869
|
+
confirmUpdateMetadata: '确认后将更新metadata文件。这将保留现有配置值,但可能更改属性结构。',
|
|
870
|
+
metadataSuccess: 'Metadata生成成功!',
|
|
871
|
+
generationFailed: '生成失败',
|
|
872
|
+
previewFailed: '生成预览失败',
|
|
873
|
+
generatingInterface: '正在生成TypeScript接口预览...',
|
|
874
|
+
propertiesInterfacePreview: '属性 → 接口预览',
|
|
875
|
+
currentInterface: '当前接口',
|
|
876
|
+
newInterface: '新接口',
|
|
877
|
+
confirmUpdateInterface: '确认后将更新TypeScript接口。这将覆盖当前的接口定义。',
|
|
878
|
+
interfaceSuccess: 'TypeScript接口生成成功!',
|
|
879
|
+
previewGenerationFailed: '预览失败',
|
|
880
|
+
interfacePreviewFailed: '生成接口预览失败',
|
|
881
|
+
propertyNotFound: '无法找到属性,请检查在 @metadata.json 中,是否存在该属性:',
|
|
882
|
+
connectWallet: '请先连接钱包',
|
|
883
|
+
cancel: '取消',
|
|
884
|
+
confirmUpdate: '确认更新',
|
|
885
|
+
configUpdateConfirmation: '确认后将更新配置。',
|
|
886
|
+
operationFailed: '执行操作失败',
|
|
887
|
+
noRoutesFound: '未找到组件',
|
|
888
|
+
};
|
|
889
|
+
}
|