@blocklet/pages-kit-block-studio 0.5.41 → 0.5.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/middlewares/init-block-studio-router.js +120 -0
- package/lib/cjs/middlewares/init-resource-router.js +54 -5
- package/lib/cjs/plugins/_theme.js +347 -54
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/middlewares/init-block-studio-router.js +120 -0
- package/lib/esm/middlewares/init-resource-router.js +55 -6
- package/lib/esm/plugins/_theme.js +348 -55
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -42,9 +42,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
42
42
|
// NOTICE: This file is very important, please do not change it!
|
|
43
43
|
// import BlockStudio from '@blocklet/pages-kit-block-studio/frontend';
|
|
44
44
|
// export default BlockStudio;
|
|
45
|
+
// add tailwindcss css to the head
|
|
45
46
|
const Session_1 = require("@arcblock/did-connect/lib/Session");
|
|
46
47
|
const Config_1 = require("@arcblock/ux/lib/Config");
|
|
47
|
-
const Empty_1 = __importDefault(require("@arcblock/ux/lib/Empty"));
|
|
48
48
|
const context_1 = require("@arcblock/ux/lib/Locale/context");
|
|
49
49
|
const Theme_1 = require("@arcblock/ux/lib/Theme");
|
|
50
50
|
const Toast_1 = __importStar(require("@arcblock/ux/lib/Toast"));
|
|
@@ -60,16 +60,21 @@ const property_1 = require("@blocklet/pages-kit/utils/property");
|
|
|
60
60
|
const studio_ui_1 = require("@blocklet/studio-ui");
|
|
61
61
|
const ui_react_1 = require("@blocklet/ui-react");
|
|
62
62
|
const Add_1 = __importDefault(require("@mui/icons-material/Add"));
|
|
63
|
+
const Delete_1 = __importDefault(require("@mui/icons-material/Delete"));
|
|
64
|
+
const DragIndicator_1 = __importDefault(require("@mui/icons-material/DragIndicator"));
|
|
63
65
|
const LaptopMac_1 = __importDefault(require("@mui/icons-material/LaptopMac"));
|
|
64
66
|
const PhoneAndroid_1 = __importDefault(require("@mui/icons-material/PhoneAndroid"));
|
|
67
|
+
const Settings_1 = __importDefault(require("@mui/icons-material/Settings"));
|
|
68
|
+
const SortByAlpha_1 = __importDefault(require("@mui/icons-material/SortByAlpha"));
|
|
65
69
|
const material_1 = require("@mui/material");
|
|
66
70
|
const ahooks_1 = require("ahooks");
|
|
67
71
|
const ahooks_2 = require("ahooks");
|
|
68
72
|
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
69
73
|
const get_1 = __importDefault(require("lodash/get"));
|
|
70
74
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
71
|
-
const react_1 = require("react");
|
|
75
|
+
const react_1 = __importStar(require("react"));
|
|
72
76
|
const react_dnd_1 = require("react-dnd");
|
|
77
|
+
const react_dnd_2 = require("react-dnd");
|
|
73
78
|
const react_dnd_html5_backend_1 = require("react-dnd-html5-backend");
|
|
74
79
|
const react_router_dom_1 = require("react-router-dom");
|
|
75
80
|
const split_pane_react_1 = __importStar(require("split-pane-react"));
|
|
@@ -93,6 +98,136 @@ function useSessionContext() {
|
|
|
93
98
|
const LEFT_DRAWER_WIDTH = 300;
|
|
94
99
|
const RIGHT_DRAWER_WIDTH = 300;
|
|
95
100
|
const defaultLocale = 'en';
|
|
101
|
+
// Drag and drop types
|
|
102
|
+
const ItemTypes = {
|
|
103
|
+
ROUTE_ITEM: 'route-item',
|
|
104
|
+
};
|
|
105
|
+
const DraggableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigate, onDelete, index, moveItem, showDragHandle, routes, }) => {
|
|
106
|
+
const ref = react_1.default.useRef(null);
|
|
107
|
+
const [isHovered, setIsHovered] = react_1.default.useState(false);
|
|
108
|
+
const [{ handlerId }, drop] = (0, react_dnd_2.useDrop)({
|
|
109
|
+
accept: ItemTypes.ROUTE_ITEM,
|
|
110
|
+
collect(monitor) {
|
|
111
|
+
return {
|
|
112
|
+
handlerId: monitor.getHandlerId(),
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
hover(item, monitor) {
|
|
116
|
+
if (!ref.current || !showDragHandle) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Get the real dragIndex from routes array using route as identifier
|
|
120
|
+
// This prevents issues when dragging too fast and item.index becomes stale
|
|
121
|
+
const dragIndex = routes.findIndex((r) => r === item.route);
|
|
122
|
+
const hoverIndex = index;
|
|
123
|
+
// Don't replace items with themselves
|
|
124
|
+
if (dragIndex === hoverIndex || dragIndex === -1) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Determine rectangle on screen
|
|
128
|
+
const hoverBoundingRect = ref.current?.getBoundingClientRect();
|
|
129
|
+
// Get vertical middle
|
|
130
|
+
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
|
131
|
+
// Determine mouse position
|
|
132
|
+
const clientOffset = monitor.getClientOffset();
|
|
133
|
+
// Get pixels to the top
|
|
134
|
+
const hoverClientY = (clientOffset?.y ?? 0) - hoverBoundingRect.top;
|
|
135
|
+
// Only perform the move when the mouse has crossed half of the items height
|
|
136
|
+
// When dragging downwards, only move when the cursor is below 50%
|
|
137
|
+
// When dragging upwards, only move when the cursor is above 50%
|
|
138
|
+
// Dragging downwards
|
|
139
|
+
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// Dragging upwards
|
|
143
|
+
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
// Time to actually perform the action
|
|
147
|
+
moveItem(dragIndex, hoverIndex);
|
|
148
|
+
// Note: we're mutating the monitor item here!
|
|
149
|
+
// Generally it's better to avoid mutations,
|
|
150
|
+
// but it's good here for the sake of performance
|
|
151
|
+
// to avoid expensive index searches.
|
|
152
|
+
item.index = hoverIndex;
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
const [{ isDragging }, drag, preview] = (0, react_dnd_2.useDrag)({
|
|
156
|
+
type: ItemTypes.ROUTE_ITEM,
|
|
157
|
+
item: () => {
|
|
158
|
+
return { route, index };
|
|
159
|
+
},
|
|
160
|
+
collect: (monitor) => ({
|
|
161
|
+
isDragging: monitor.isDragging(),
|
|
162
|
+
}),
|
|
163
|
+
canDrag: showDragHandle,
|
|
164
|
+
});
|
|
165
|
+
const opacity = isDragging ? 0.5 : 1;
|
|
166
|
+
// Separate drag handle from the clickable area
|
|
167
|
+
const dragHandleRef = react_1.default.useRef(null);
|
|
168
|
+
// Only attach drag to the handle when in custom sort mode
|
|
169
|
+
react_1.default.useEffect(() => {
|
|
170
|
+
if (showDragHandle && dragHandleRef.current) {
|
|
171
|
+
drag(dragHandleRef.current);
|
|
172
|
+
}
|
|
173
|
+
}, [drag, showDragHandle]);
|
|
174
|
+
drop(ref);
|
|
175
|
+
return ((0, jsx_runtime_1.jsx)(material_1.ListItem, { ref: ref, disablePadding: true, className: isDragging ? 'drag-shaking' : '', sx: {
|
|
176
|
+
opacity,
|
|
177
|
+
transition: isDragging ? 'opacity 0.2s ease' : 'opacity 0.2s ease, transform 0.2s ease',
|
|
178
|
+
zIndex: isDragging ? 1000 : 'auto',
|
|
179
|
+
}, "data-handler-id": handlerId, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: (0, jsx_runtime_1.jsxs)(material_1.ListItemButton, { selected: currentPageId === route, onClick: () => onNavigate(route), sx: {
|
|
180
|
+
borderRadius: 1,
|
|
181
|
+
width: '100%',
|
|
182
|
+
textOverflow: 'ellipsis',
|
|
183
|
+
whiteSpace: 'nowrap',
|
|
184
|
+
overflowX: 'hidden',
|
|
185
|
+
transition: 'all 0.3s ease',
|
|
186
|
+
'&.Mui-selected': {
|
|
187
|
+
backgroundColor: 'primary.main',
|
|
188
|
+
color: 'white',
|
|
189
|
+
'&:hover': {
|
|
190
|
+
backgroundColor: 'primary.main',
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
fontSize: '14px',
|
|
194
|
+
display: 'flex',
|
|
195
|
+
alignItems: 'center',
|
|
196
|
+
gap: 1,
|
|
197
|
+
border: (theme) => (isDragging ? `1px solid ${theme.palette.primary.main}` : '1px solid transparent'),
|
|
198
|
+
backgroundColor: isDragging ? 'grey.100' : 'inherit',
|
|
199
|
+
pl: 1,
|
|
200
|
+
pr: 1,
|
|
201
|
+
}, children: [showDragHandle && ((0, jsx_runtime_1.jsx)(material_1.Box, { ref: dragHandleRef, sx: {
|
|
202
|
+
display: 'flex',
|
|
203
|
+
alignItems: 'center',
|
|
204
|
+
justifyContent: 'center',
|
|
205
|
+
cursor: 'grab',
|
|
206
|
+
borderRadius: 1,
|
|
207
|
+
'&:active': {
|
|
208
|
+
cursor: 'grabbing',
|
|
209
|
+
},
|
|
210
|
+
}, children: (0, jsx_runtime_1.jsx)(DragIndicator_1.default, { sx: {
|
|
211
|
+
fontSize: '14px',
|
|
212
|
+
} }) })), (0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: staticDataInRoute.blockName || route, children: (0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
|
|
213
|
+
flex: 1,
|
|
214
|
+
overflow: 'hidden',
|
|
215
|
+
textOverflow: 'ellipsis',
|
|
216
|
+
whiteSpace: 'nowrap',
|
|
217
|
+
}, children: staticDataInRoute.blockName || route }) }), (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", onClick: (e) => {
|
|
218
|
+
e.stopPropagation();
|
|
219
|
+
onDelete(route, staticDataInRoute.blockName || route);
|
|
220
|
+
}, sx: {
|
|
221
|
+
ml: 1,
|
|
222
|
+
opacity: isHovered ? 0.7 : 0,
|
|
223
|
+
visibility: isHovered ? 'visible' : 'hidden',
|
|
224
|
+
transition: 'opacity 0.2s ease',
|
|
225
|
+
'&:hover': {
|
|
226
|
+
bgcolor: 'error.main',
|
|
227
|
+
color: 'error.contrastText',
|
|
228
|
+
},
|
|
229
|
+
}, children: (0, jsx_runtime_1.jsx)(Delete_1.default, { sx: { fontSize: '16px' } }) })] }) }));
|
|
230
|
+
};
|
|
96
231
|
const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTitle, rightContent, description, loading, onConfirm, onClose, }) => {
|
|
97
232
|
const { t } = (0, context_1.useLocaleContext)();
|
|
98
233
|
const handleConfirm = async () => {
|
|
@@ -146,6 +281,12 @@ function Layout({ loadState, loadedData }) {
|
|
|
146
281
|
loading: false,
|
|
147
282
|
onConfirm: async () => { },
|
|
148
283
|
},
|
|
284
|
+
deleteConfirmDialog: {
|
|
285
|
+
open: false,
|
|
286
|
+
blockName: '',
|
|
287
|
+
route: '',
|
|
288
|
+
loading: false,
|
|
289
|
+
},
|
|
149
290
|
init: false,
|
|
150
291
|
allComponents: [],
|
|
151
292
|
propertiesValue: {},
|
|
@@ -159,6 +300,10 @@ function Layout({ loadState, loadedData }) {
|
|
|
159
300
|
const [hSizes, setHSizes] = (0, ahooks_1.useLocalStorageState)('BlockStudioHorizontalSizes', {
|
|
160
301
|
defaultValue: [LEFT_DRAWER_WIDTH, 'auto', RIGHT_DRAWER_WIDTH],
|
|
161
302
|
});
|
|
303
|
+
// Custom sorting order storage
|
|
304
|
+
const [customSortOrder, setCustomSortOrder] = (0, ahooks_1.useLocalStorageState)('BlockStudioCustomSortOrder', {
|
|
305
|
+
defaultValue: [],
|
|
306
|
+
});
|
|
162
307
|
const { t, locale } = (0, context_1.useLocaleContext)();
|
|
163
308
|
const { session } = useSessionContext();
|
|
164
309
|
const location = (0, react_router_dom_1.useLocation)();
|
|
@@ -182,18 +327,37 @@ function Layout({ loadState, loadedData }) {
|
|
|
182
327
|
iframe.contentWindow.postMessage(safeData, '*');
|
|
183
328
|
}
|
|
184
329
|
}, [mode]);
|
|
185
|
-
const { routes, currentPage } = (0, react_1.useMemo)(() => {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
330
|
+
const { routes, currentPage, hasCustomSort } = (0, react_1.useMemo)(() => {
|
|
331
|
+
const allRoutes = Object.keys(staticData).filter((route) => staticData[route]?.main?.isDeleted !== true);
|
|
332
|
+
let sortedRoutes;
|
|
333
|
+
let hasCustomSort = false;
|
|
334
|
+
if (customSortOrder && customSortOrder.length > 0) {
|
|
335
|
+
// Use custom sort order if available
|
|
336
|
+
hasCustomSort = true;
|
|
337
|
+
const sortOrderMap = new Map(customSortOrder.map((route, index) => [route, index]));
|
|
338
|
+
sortedRoutes = allRoutes.sort((a, b) => {
|
|
339
|
+
const indexA = sortOrderMap.get(a) ?? Number.MAX_SAFE_INTEGER;
|
|
340
|
+
const indexB = sortOrderMap.get(b) ?? Number.MAX_SAFE_INTEGER;
|
|
341
|
+
if (indexA === indexB) {
|
|
342
|
+
return a.localeCompare(b); // Fallback to alphabetical for new items
|
|
343
|
+
}
|
|
344
|
+
return indexA - indexB;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// Use alphabetical sort as default
|
|
349
|
+
hasCustomSort = false;
|
|
350
|
+
sortedRoutes = allRoutes.sort((a, b) => a.localeCompare(b));
|
|
351
|
+
}
|
|
189
352
|
return {
|
|
190
|
-
routes,
|
|
353
|
+
routes: sortedRoutes,
|
|
354
|
+
hasCustomSort,
|
|
191
355
|
currentPage: {
|
|
192
356
|
...staticData[location.pathname]?.main,
|
|
193
357
|
pageId: location.pathname,
|
|
194
358
|
},
|
|
195
359
|
};
|
|
196
|
-
}, [staticData, location.pathname]);
|
|
360
|
+
}, [staticData, location.pathname, customSortOrder]);
|
|
197
361
|
const notSelectedBlock = (0, react_1.useMemo)(() => {
|
|
198
362
|
return !currentPage?.blockName || !currentPage?.code;
|
|
199
363
|
}, [currentPage]);
|
|
@@ -262,6 +426,9 @@ function Layout({ loadState, loadedData }) {
|
|
|
262
426
|
}
|
|
263
427
|
catch (error) {
|
|
264
428
|
console.error('Failed to write metadata:', error);
|
|
429
|
+
Toast_1.default.error(t('themeTranslations.saveMetadataFailed', {
|
|
430
|
+
error: error.message,
|
|
431
|
+
}));
|
|
265
432
|
}
|
|
266
433
|
}
|
|
267
434
|
}, { wait: 500 });
|
|
@@ -352,6 +519,16 @@ function Layout({ loadState, loadedData }) {
|
|
|
352
519
|
const DraggingSplitPlaceholder = (0, react_1.useMemo)(() => {
|
|
353
520
|
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 } }) }));
|
|
354
521
|
}, []);
|
|
522
|
+
// Move item function for drag and drop
|
|
523
|
+
const moveItem = (0, react_1.useCallback)((dragIndex, hoverIndex) => {
|
|
524
|
+
if (dragIndex === hoverIndex)
|
|
525
|
+
return;
|
|
526
|
+
const newRoutes = [...routes];
|
|
527
|
+
const [draggedItem] = newRoutes.splice(dragIndex, 1);
|
|
528
|
+
newRoutes.splice(hoverIndex, 0, draggedItem);
|
|
529
|
+
// Save the new order to localStorage (automatically enables custom sort)
|
|
530
|
+
setCustomSortOrder(newRoutes);
|
|
531
|
+
}, [routes, setCustomSortOrder]);
|
|
355
532
|
// 修改 iframe URL 构建逻辑,添加初始状态参数
|
|
356
533
|
const iframeUrl = (0, react_1.useMemo)(() => {
|
|
357
534
|
const url = new URL(window.location.href);
|
|
@@ -386,16 +563,67 @@ function Layout({ loadState, loadedData }) {
|
|
|
386
563
|
window.addEventListener('message', handleMessage);
|
|
387
564
|
return () => window.removeEventListener('message', handleMessage);
|
|
388
565
|
}, [changeMode, mode]);
|
|
566
|
+
// Add delete block function
|
|
567
|
+
const handleDeleteBlock = async (route, blockName) => {
|
|
568
|
+
state.deleteConfirmDialog = {
|
|
569
|
+
open: true,
|
|
570
|
+
blockName,
|
|
571
|
+
route,
|
|
572
|
+
loading: false,
|
|
573
|
+
};
|
|
574
|
+
};
|
|
575
|
+
const confirmDeleteBlock = async () => {
|
|
576
|
+
state.deleteConfirmDialog.loading = true;
|
|
577
|
+
try {
|
|
578
|
+
// Call delete API
|
|
579
|
+
const response = await api.delete(`/api/blocks/delete`, {
|
|
580
|
+
data: { route: state.deleteConfirmDialog.route },
|
|
581
|
+
});
|
|
582
|
+
if (response.data.success) {
|
|
583
|
+
Toast_1.default.success(t('themeTranslations.deleteSuccess'));
|
|
584
|
+
// Navigate away if currently viewing the deleted component
|
|
585
|
+
if (currentPage.pageId === state.deleteConfirmDialog.route) {
|
|
586
|
+
const remainingComponents = routes.filter((r) => r !== state.deleteConfirmDialog.route);
|
|
587
|
+
navigate('/');
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
throw new Error(response.data.error || t('themeTranslations.deleteFailed'));
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
catch (error) {
|
|
595
|
+
console.error('Failed to delete block:', error);
|
|
596
|
+
Toast_1.default.error(t('themeTranslations.deleteFailed'));
|
|
597
|
+
}
|
|
598
|
+
finally {
|
|
599
|
+
state.deleteConfirmDialog.loading = false;
|
|
600
|
+
state.deleteConfirmDialog.open = false;
|
|
601
|
+
}
|
|
602
|
+
};
|
|
389
603
|
const leftPanelContent = (0, react_1.useMemo)(() => {
|
|
390
604
|
if (state.draggingSplitPane) {
|
|
391
605
|
return DraggingSplitPlaceholder;
|
|
392
606
|
}
|
|
393
|
-
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: {
|
|
607
|
+
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: { pt: 2, pr: 1, pl: 0.5, pb: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.TextField, { placeholder: t('themeTranslations.search'), sx: { minWidth: 60, flex: 1 }, onChange: (e) => {
|
|
394
608
|
state.searchValue = e.target.value;
|
|
395
|
-
} }), (0, jsx_runtime_1.jsx)(material_1.
|
|
609
|
+
} }), hasCustomSort && ((0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: t('themeTranslations.resetToAlphabeticalSort'), children: (0, jsx_runtime_1.jsx)(material_1.IconButton, { size: "small", onClick: () => {
|
|
610
|
+
setCustomSortOrder([]);
|
|
611
|
+
}, sx: {
|
|
612
|
+
transition: 'all 0.2s ease',
|
|
613
|
+
'&:hover': {
|
|
614
|
+
backgroundColor: 'action.hover',
|
|
615
|
+
transform: 'scale(1.1)',
|
|
616
|
+
},
|
|
617
|
+
}, children: (0, jsx_runtime_1.jsx)(SortByAlpha_1.default, { fontSize: "small" }) }) })), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", sx: { minWidth: 40 }, onClick: () => {
|
|
396
618
|
state.createBlockOpen = true;
|
|
397
|
-
}, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), routes?.length > 0 ? ((0, jsx_runtime_1.jsx)(material_1.List, { sx: {
|
|
398
|
-
|
|
619
|
+
}, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), routes?.length > 0 ? ((0, jsx_runtime_1.jsx)(material_1.List, { sx: {
|
|
620
|
+
pr: 1,
|
|
621
|
+
overflowY: 'auto',
|
|
622
|
+
height: hasCustomSort ? 'calc(100% - 80px)' : 'calc(100% - 60px)',
|
|
623
|
+
// Prevent text selection during drag
|
|
624
|
+
userSelect: 'none',
|
|
625
|
+
}, children: routes
|
|
626
|
+
.map((route, index) => {
|
|
399
627
|
const routeName = route;
|
|
400
628
|
const staticDataInRoute = staticData[route]?.main;
|
|
401
629
|
if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
|
|
@@ -404,35 +632,35 @@ function Layout({ loadState, loadedData }) {
|
|
|
404
632
|
if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
|
|
405
633
|
return null;
|
|
406
634
|
}
|
|
407
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
borderRadius: 1,
|
|
414
|
-
mb: 1,
|
|
415
|
-
width: '100%',
|
|
416
|
-
textOverflow: 'ellipsis',
|
|
417
|
-
whiteSpace: 'nowrap',
|
|
418
|
-
overflowX: 'hidden',
|
|
419
|
-
transition: 'all 0.3s ease',
|
|
420
|
-
'&.Mui-selected': {
|
|
421
|
-
backgroundColor: 'primary.main',
|
|
422
|
-
color: 'white',
|
|
423
|
-
'&:hover': {
|
|
424
|
-
backgroundColor: 'primary.main',
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
|
-
fontSize: '14px',
|
|
428
|
-
}, children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, { title: staticDataInRoute.blockName || routeName, children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
429
|
-
width: '100%',
|
|
430
|
-
overflow: 'hidden',
|
|
431
|
-
textOverflow: 'ellipsis',
|
|
432
|
-
}, children: staticDataInRoute.blockName || routeName }) }) }) }, route));
|
|
635
|
+
return ((0, jsx_runtime_1.jsx)(DraggableRouteItem, { route: route, staticDataInRoute: staticDataInRoute, currentPageId: currentPage.pageId, onNavigate: (route) => {
|
|
636
|
+
if (route !== currentPage.pageId) {
|
|
637
|
+
navigate(route);
|
|
638
|
+
state.iframeLoaded = false;
|
|
639
|
+
}
|
|
640
|
+
}, onDelete: handleDeleteBlock, index: index, moveItem: moveItem, showDragHandle: true, routes: routes }, route));
|
|
433
641
|
})
|
|
434
|
-
.filter(Boolean) })) : ((0, jsx_runtime_1.jsx)(material_1.Box, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", children: (0, jsx_runtime_1.
|
|
435
|
-
|
|
642
|
+
.filter(Boolean) })) : ((0, jsx_runtime_1.jsx)(material_1.Box, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", sx: { p: 3 }, children: (0, jsx_runtime_1.jsxs)(material_1.Stack, { alignItems: "center", spacing: 3, sx: { textAlign: 'center' }, children: [(0, jsx_runtime_1.jsx)(material_1.Box, { component: "img", src: "https://api.iconify.design/material-symbols:folder-open-outline.svg", sx: {
|
|
643
|
+
width: 48,
|
|
644
|
+
height: 48,
|
|
645
|
+
opacity: 0.5,
|
|
646
|
+
filter: 'grayscale(100%)',
|
|
647
|
+
}, alt: "No components" }), (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "h6", color: "text.primary", sx: { fontWeight: 600 }, children: t('themeTranslations.noComponentsFound') }), (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", sx: { maxWidth: 200 }, children: t('themeTranslations.createFirstComponent') }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", startIcon: (0, jsx_runtime_1.jsx)(Add_1.default, {}), onClick: () => {
|
|
648
|
+
state.createBlockOpen = true;
|
|
649
|
+
}, sx: { mt: 2 }, children: t('themeTranslations.createComponent') })] }) }))] }));
|
|
650
|
+
}, [
|
|
651
|
+
routes,
|
|
652
|
+
staticData,
|
|
653
|
+
state.allComponents,
|
|
654
|
+
state.searchValue,
|
|
655
|
+
state.draggingSplitPane,
|
|
656
|
+
hasCustomSort,
|
|
657
|
+
moveItem,
|
|
658
|
+
currentPage.pageId,
|
|
659
|
+
navigate,
|
|
660
|
+
locale,
|
|
661
|
+
mode,
|
|
662
|
+
handleDeleteBlock,
|
|
663
|
+
]);
|
|
436
664
|
// 修改 middlePanelContent - iframe 内部监听消息
|
|
437
665
|
const middlePanelContent = (0, react_1.useMemo)(() => {
|
|
438
666
|
// 如果在iframe内部,添加消息接收逻辑
|
|
@@ -447,11 +675,11 @@ function Layout({ loadState, loadedData }) {
|
|
|
447
675
|
const url = new URL(window.location.href);
|
|
448
676
|
const initialComponentId = url.searchParams.get('componentId') || state.metadata.id;
|
|
449
677
|
const initialLocale = url.searchParams.get('locale') || locale || 'en';
|
|
450
|
-
return ((0, jsx_runtime_1.jsx)(material_1.Box, { className: "custom-component-root", sx: { height: '100vh', width: '100vw', overflow: 'auto' }, children: (0, jsx_runtime_1.jsx)(Theme_1.ThemeProvider, { theme: theme, children: (0, jsx_runtime_1.jsx)(
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
678
|
+
return ((0, jsx_runtime_1.jsx)(material_1.Box, { className: "custom-component-root", sx: { height: '100vh', width: '100vw', overflow: 'auto' }, children: (0, jsx_runtime_1.jsx)(Theme_1.ThemeProvider, { theme: theme, children: (0, jsx_runtime_1.jsx)(components_2.CustomComponentRenderer, { locale: initialLocale, componentId: initialComponentId || state.metadata.id, dev: {
|
|
679
|
+
mode: 'draft',
|
|
680
|
+
components: mergedAllBlocks,
|
|
681
|
+
defaultLocale,
|
|
682
|
+
}, properties: mergedPropertiesValues }, `custom-${renderComponentTrigger}`) }) }));
|
|
455
683
|
}
|
|
456
684
|
// 没有匹配到路由,使用欢迎页面
|
|
457
685
|
if (notSelectedBlock) {
|
|
@@ -618,6 +846,7 @@ function Layout({ loadState, loadedData }) {
|
|
|
618
846
|
JSON.stringify(state.metadata || {}),
|
|
619
847
|
JSON.stringify(mergedAllBlocks || []),
|
|
620
848
|
JSON.stringify(mergedPropertiesValues || {}),
|
|
849
|
+
handleDeleteBlock,
|
|
621
850
|
]);
|
|
622
851
|
const rightPanelContent = (0, react_1.useMemo)(() => {
|
|
623
852
|
if (state.draggingSplitPane) {
|
|
@@ -632,7 +861,7 @@ function Layout({ loadState, loadedData }) {
|
|
|
632
861
|
// add disabled backdrop if not selected block
|
|
633
862
|
'& .MuiListItem-root': {
|
|
634
863
|
pointerEvents: notSelectedBlock ? 'none' : 'auto',
|
|
635
|
-
opacity: notSelectedBlock ? 0.
|
|
864
|
+
opacity: notSelectedBlock ? 0.4 : 1,
|
|
636
865
|
userSelect: notSelectedBlock ? 'none' : 'auto',
|
|
637
866
|
filter: notSelectedBlock ? 'blur(5px)' : 'none',
|
|
638
867
|
},
|
|
@@ -645,7 +874,13 @@ function Layout({ loadState, loadedData }) {
|
|
|
645
874
|
display: 'flex',
|
|
646
875
|
justifyContent: 'center',
|
|
647
876
|
alignItems: 'center',
|
|
648
|
-
|
|
877
|
+
p: 3,
|
|
878
|
+
}, children: (0, jsx_runtime_1.jsxs)(material_1.Stack, { alignItems: "center", spacing: 2, sx: {
|
|
879
|
+
textAlign: 'center',
|
|
880
|
+
bgcolor: 'background.default',
|
|
881
|
+
borderRadius: 2,
|
|
882
|
+
p: 3,
|
|
883
|
+
}, children: [(0, jsx_runtime_1.jsx)(Settings_1.default, { sx: { fontSize: 48, color: 'primary.main' } }), (0, jsx_runtime_1.jsxs)(material_1.Stack, { spacing: 1, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "h6", color: "primary.main", sx: { fontWeight: 600 }, children: t('themeTranslations.componentPropertiesTitle') }), (0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", color: "text.secondary", children: t('themeTranslations.selectComponentToConfigureProperties') })] })] }) })), (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) => {
|
|
649
884
|
updater(state.metadata);
|
|
650
885
|
}, 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 () => {
|
|
651
886
|
try {
|
|
@@ -779,6 +1014,7 @@ function Layout({ loadState, loadedData }) {
|
|
|
779
1014
|
getStaticData,
|
|
780
1015
|
state.draggingSplitPane,
|
|
781
1016
|
mode,
|
|
1017
|
+
handleDeleteBlock,
|
|
782
1018
|
]);
|
|
783
1019
|
if (isInsideIframe) {
|
|
784
1020
|
return middlePanelContent;
|
|
@@ -844,7 +1080,11 @@ function Layout({ loadState, loadedData }) {
|
|
|
844
1080
|
}
|
|
845
1081
|
}, 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: () => {
|
|
846
1082
|
state.previewDialog.open = false;
|
|
847
|
-
} })
|
|
1083
|
+
} }), (0, jsx_runtime_1.jsxs)(material_1.Dialog, { open: state.deleteConfirmDialog.open, onClose: () => (state.deleteConfirmDialog.open = false), maxWidth: "sm", fullWidth: true, children: [(0, jsx_runtime_1.jsx)(material_1.DialogTitle, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: t('themeTranslations.deleteComponent') }), (0, jsx_runtime_1.jsxs)(material_1.DialogContent, { children: [(0, jsx_runtime_1.jsx)(material_1.Alert, { severity: "warning", sx: { mb: 2 }, children: t('themeTranslations.deleteWarning') }), (0, jsx_runtime_1.jsx)(material_1.Typography, { children: t('themeTranslations.deleteConfirmMessage', {
|
|
1084
|
+
componentName: state.deleteConfirmDialog.blockName,
|
|
1085
|
+
}) })] }), (0, jsx_runtime_1.jsxs)(material_1.Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2, gap: 1 }, children: [(0, jsx_runtime_1.jsx)(material_1.Button, { variant: "outlined", onClick: () => (state.deleteConfirmDialog.open = false), disabled: state.deleteConfirmDialog.loading, children: t('themeTranslations.cancel') }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", color: "error", onClick: confirmDeleteBlock, disabled: state.deleteConfirmDialog.loading, startIcon: state.deleteConfirmDialog.loading ? (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { size: 20 }) : (0, jsx_runtime_1.jsx)(Delete_1.default, {}), children: state.deleteConfirmDialog.loading
|
|
1086
|
+
? t('themeTranslations.deleting')
|
|
1087
|
+
: t('themeTranslations.deleteConfirm') })] })] })] }) }));
|
|
848
1088
|
}
|
|
849
1089
|
// Add SplitPane styling
|
|
850
1090
|
const StyledSplitPane = (0, material_1.styled)(split_pane_react_1.default) `
|
|
@@ -864,6 +1104,29 @@ const DragHandle = (0, material_1.styled)('div') `
|
|
|
864
1104
|
}
|
|
865
1105
|
`;
|
|
866
1106
|
const StyledDashboard = (0, material_1.styled)(studio_ui_1.Dashboard) `
|
|
1107
|
+
@keyframes dragShake {
|
|
1108
|
+
0%,
|
|
1109
|
+
100% {
|
|
1110
|
+
transform: translateY(0px) rotate(0deg);
|
|
1111
|
+
}
|
|
1112
|
+
25% {
|
|
1113
|
+
transform: translateY(-2px) rotate(-2deg);
|
|
1114
|
+
}
|
|
1115
|
+
50% {
|
|
1116
|
+
transform: translateY(2px) rotate(0deg);
|
|
1117
|
+
}
|
|
1118
|
+
75% {
|
|
1119
|
+
transform: translateY(-2px) rotate(2deg);
|
|
1120
|
+
}
|
|
1121
|
+
100% {
|
|
1122
|
+
transform: translateY(0px) rotate(0deg);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
.drag-shaking {
|
|
1127
|
+
animation: dragShake 0.3s ease-in-out infinite;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
867
1130
|
.dashboard-content {
|
|
868
1131
|
display: flex;
|
|
869
1132
|
flex-direction: row;
|
|
@@ -909,12 +1172,12 @@ function CreateResource({ open, onClose }) {
|
|
|
909
1172
|
return null;
|
|
910
1173
|
}
|
|
911
1174
|
const tenantScope = 'pages-kit-block-studio';
|
|
912
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1175
|
+
return ((0, jsx_runtime_1.jsx)(ui_react_1.BlockletStudio, { mode: "dialog", tenantScope: tenantScope, title: "Pages Kit Blocks", description: "", note: "", introduction: "", logo: "", componentDid: PAGES_KIT_BLOCK_STUDIO_BLOCKLET_DID,
|
|
1176
|
+
// 透传到 get blocklet resource 的参数
|
|
1177
|
+
resourcesParams: {}, dependentComponentsMode: "readonly", open: true, setOpen: () => onClose(), onConnected: () => { }, onUploaded: () => { }, onReleased: () => { },
|
|
1178
|
+
// onOpened={() => onOpened?.()}
|
|
1179
|
+
// 默认选中的资源
|
|
1180
|
+
resources: {} }));
|
|
918
1181
|
}
|
|
919
1182
|
// 添加 themeTranslations 到 translations 对象
|
|
920
1183
|
// 这里我们在运行时扩展 translations 对象,而不是修改源文件
|
|
@@ -965,6 +1228,21 @@ if (!locales_1.translations.en.themeTranslations) {
|
|
|
965
1228
|
step1: 'Browse and select components from the left menu, or create your own',
|
|
966
1229
|
step2: 'Preview your component in the center area with responsive design views',
|
|
967
1230
|
step3: 'Customize properties and configurations in the right panel to bring your ideas to life',
|
|
1231
|
+
// New translations for sorting and improved empty states
|
|
1232
|
+
resetToAlphabeticalSort: 'Reset to Alphabetical Sort',
|
|
1233
|
+
noComponentsFound: 'No Components Found',
|
|
1234
|
+
createFirstComponent: 'Create your first component to get started',
|
|
1235
|
+
createComponent: 'Create Component',
|
|
1236
|
+
componentPropertiesTitle: 'Configure Component',
|
|
1237
|
+
selectComponentToConfigureProperties: 'Select a component from the left panel to configure its properties',
|
|
1238
|
+
saveMetadataFailed: 'Failed to write @metadata.json: {error}',
|
|
1239
|
+
deleteComponent: 'Delete Component',
|
|
1240
|
+
deleteWarning: 'This action cannot be undone. All files in the component directory will be permanently deleted.',
|
|
1241
|
+
deleteConfirmMessage: "Are you sure you want to delete the component '{componentName}'?",
|
|
1242
|
+
deleteConfirm: 'Delete',
|
|
1243
|
+
deleting: 'Deleting...',
|
|
1244
|
+
deleteSuccess: 'Component deleted successfully',
|
|
1245
|
+
deleteFailed: 'Failed to delete component',
|
|
968
1246
|
};
|
|
969
1247
|
}
|
|
970
1248
|
if (!locales_1.translations.zh.themeTranslations) {
|
|
@@ -1014,5 +1292,20 @@ if (!locales_1.translations.zh.themeTranslations) {
|
|
|
1014
1292
|
step1: '从左侧菜单浏览并选择组件,或创建您自己的组件',
|
|
1015
1293
|
step2: '在中央区域预览您的组件,支持响应式设计视图',
|
|
1016
1294
|
step3: '在右侧面板自定义属性和配置,让您的创意变为现实',
|
|
1295
|
+
// New translations for sorting and improved empty states
|
|
1296
|
+
resetToAlphabeticalSort: '重置为字母排序',
|
|
1297
|
+
noComponentsFound: '未找到组件',
|
|
1298
|
+
createFirstComponent: '创建您的第一个组件来开始',
|
|
1299
|
+
createComponent: '创建组件',
|
|
1300
|
+
componentPropertiesTitle: '配置组件',
|
|
1301
|
+
selectComponentToConfigureProperties: '从左侧面板选择一个组件来配置其属性',
|
|
1302
|
+
saveMetadataFailed: '修改 @metadata.json 失败: {error}',
|
|
1303
|
+
deleteComponent: '删除组件',
|
|
1304
|
+
deleteWarning: '此操作无法撤销。组件目录中的所有文件将被永久删除。',
|
|
1305
|
+
deleteConfirmMessage: "确定要删除组件 '{componentName}' 吗?",
|
|
1306
|
+
deleteConfirm: '删除',
|
|
1307
|
+
deleting: '删除中...',
|
|
1308
|
+
deleteSuccess: '组件删除成功',
|
|
1309
|
+
deleteFailed: '删除组件失败',
|
|
1017
1310
|
};
|
|
1018
1311
|
}
|