@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 = 200;
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 = '确认后将更新配置。', loading, onConfirm, onClose, }) => {
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: "\u53D6\u6D88" }), (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 }) : '确认更新' })] })] }));
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
- const { locale } = (0, context_1.useLocaleContext)();
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 = Object.fromEntries(Object.values(state.metadata.properties ?? {}).map(({ data }) => {
277
- return [
278
- data.id,
279
- {
280
- value: state.propertiesValue[data.id]?.value ??
281
- (0, property_1.parsePropertyValue)(data, data.locales?.[locale]?.defaultValue ?? data.locales?.[defaultLocale]?.defaultValue, {
282
- locale,
283
- defaultLocale,
284
- }),
285
- },
286
- ];
287
- }));
288
- const getRenderContent = (0, react_1.useCallback)(() => {
289
- if (loadState.type === '404') {
290
- return null;
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
- if (['load-error', 'loading'].includes(loadState.type)) {
293
- return ((0, jsx_runtime_1.jsx)(material_1.Box, { width: "100%", height: "100%", display: "flex", justifyContent: "center", alignItems: "center", children: loadState.type === 'load-error' ? ((0, jsx_runtime_1.jsx)(material_1.Alert, { severity: "error", variant: "filled", children: "Failed to load component code" })) : ((0, jsx_runtime_1.jsx)(material_1.CircularProgress, {})) }));
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
- // const pageData = loadedData[loadState.routePath];
296
- // const Component = pageData.main.default;
297
- // return <Component />;
298
- return [
299
- (0, jsx_runtime_1.jsx)(components_2.CustomComponentRenderer, { locale: locale, componentId: state.metadata.id, dev: { mode: 'draft', components: mergedAllBlocks, defaultLocale }, properties: mergedPropertiesValues }, "custom"),
300
- // <Component key="original" />,
301
- ];
302
- }, [loadedData, loadState, locale, state.injectBlocks, state.metadata, mergedAllBlocks, mergedPropertiesValues]);
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: "Create Resource" }, "logout"),
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)(material_1.Drawer, { variant: "permanent", sx: {
330
- width: LEFT_DRAWER_WIDTH,
331
- flexShrink: 0,
332
- zIndex: 1000,
333
- '& .MuiDrawer-paper': {
334
- width: LEFT_DRAWER_WIDTH,
335
- boxSizing: 'border-box',
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
- }, children: [(0, jsx_runtime_1.jsxs)(material_1.Stack, { gap: 1, direction: "row", alignItems: "center", sx: { py: 2, pr: 1, pl: 0.5 }, children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { placeholder: "Search Blocks...", sx: { minWidth: 120 }, onChange: (e) => {
340
- state.searchValue = e.target.value;
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: "Create New Block" }), (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: "Name", fullWidth: true, value: state.newBlockParams.name, onChange: (e) => {
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: "Description", fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
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('Block name is required');
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('Block name already exists, please change it');
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('Failed to create block');
732
+ Toast_1.default.error(t('themeTranslations.failedCreateBlock'));
540
733
  }
541
- }, children: "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: () => {
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
+ }