@blocklet/pages-kit-block-studio 0.6.50 → 0.6.52

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.
@@ -58,6 +58,9 @@ const property_1 = require("@blocklet/pages-kit/utils/property");
58
58
  // @ts-ignore
59
59
  const studio_ui_1 = require("@blocklet/studio-ui");
60
60
  const ui_react_1 = require("@blocklet/ui-react");
61
+ const core_1 = require("@dnd-kit/core");
62
+ const sortable_1 = require("@dnd-kit/sortable");
63
+ const utilities_1 = require("@dnd-kit/utilities");
61
64
  const Add_1 = __importDefault(require("@mui/icons-material/Add"));
62
65
  const Delete_1 = __importDefault(require("@mui/icons-material/Delete"));
63
66
  const DragIndicator_1 = __importDefault(require("@mui/icons-material/DragIndicator"));
@@ -72,9 +75,6 @@ const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
72
75
  const get_1 = __importDefault(require("lodash/get"));
73
76
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
74
77
  const react_1 = __importStar(require("react"));
75
- const react_dnd_1 = require("react-dnd");
76
- const react_dnd_2 = require("react-dnd");
77
- const react_dnd_html5_backend_1 = require("react-dnd-html5-backend");
78
78
  const react_router_dom_1 = require("react-router-dom");
79
79
  const split_pane_react_1 = __importStar(require("split-pane-react"));
80
80
  require("split-pane-react/esm/themes/default.css");
@@ -105,85 +105,21 @@ function useSessionContext() {
105
105
  const LEFT_DRAWER_WIDTH = 300;
106
106
  const RIGHT_DRAWER_WIDTH = 300;
107
107
  const defaultLocale = 'en';
108
- // Drag and drop types
109
- const ItemTypes = {
110
- ROUTE_ITEM: 'route-item',
111
- };
112
- const DraggableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigate, onDelete, index, moveItem, showDragHandle, routes, }) => {
113
- const ref = react_1.default.useRef(null);
108
+ const SortableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigate, onDelete, showDragHandle, isDragging = false, }) => {
114
109
  const [isHovered, setIsHovered] = react_1.default.useState(false);
115
- const [{ handlerId }, drop] = (0, react_dnd_2.useDrop)({
116
- accept: ItemTypes.ROUTE_ITEM,
117
- collect(monitor) {
118
- return {
119
- handlerId: monitor.getHandlerId(),
120
- };
121
- },
122
- hover(item, monitor) {
123
- if (!ref.current || !showDragHandle) {
124
- return;
125
- }
126
- // Get the real dragIndex from routes array using route as identifier
127
- // This prevents issues when dragging too fast and item.index becomes stale
128
- const dragIndex = routes.findIndex((r) => r === item.route);
129
- const hoverIndex = index;
130
- // Don't replace items with themselves
131
- if (dragIndex === hoverIndex || dragIndex === -1) {
132
- return;
133
- }
134
- // Determine rectangle on screen
135
- const hoverBoundingRect = ref.current?.getBoundingClientRect();
136
- // Get vertical middle
137
- const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
138
- // Determine mouse position
139
- const clientOffset = monitor.getClientOffset();
140
- // Get pixels to the top
141
- const hoverClientY = (clientOffset?.y ?? 0) - hoverBoundingRect.top;
142
- // Only perform the move when the mouse has crossed half of the items height
143
- // When dragging downwards, only move when the cursor is below 50%
144
- // When dragging upwards, only move when the cursor is above 50%
145
- // Dragging downwards
146
- if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
147
- return;
148
- }
149
- // Dragging upwards
150
- if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
151
- return;
152
- }
153
- // Time to actually perform the action
154
- moveItem(dragIndex, hoverIndex);
155
- // Note: we're mutating the monitor item here!
156
- // Generally it's better to avoid mutations,
157
- // but it's good here for the sake of performance
158
- // to avoid expensive index searches.
159
- item.index = hoverIndex;
160
- },
161
- });
162
- const [{ isDragging }, drag, preview] = (0, react_dnd_2.useDrag)({
163
- type: ItemTypes.ROUTE_ITEM,
164
- item: () => {
165
- return { route, index };
166
- },
167
- collect: (monitor) => ({
168
- isDragging: monitor.isDragging(),
169
- }),
170
- canDrag: showDragHandle,
110
+ const { attributes, listeners, setNodeRef, transform, transition } = (0, sortable_1.useSortable)({
111
+ id: route,
112
+ disabled: !showDragHandle,
171
113
  });
172
- const opacity = isDragging ? 0.5 : 1;
173
- // Separate drag handle from the clickable area
174
- const dragHandleRef = react_1.default.useRef(null);
175
- // Only attach drag to the handle when in custom sort mode
176
- react_1.default.useEffect(() => {
177
- if (showDragHandle && dragHandleRef.current) {
178
- drag(dragHandleRef.current);
179
- }
180
- }, [drag, showDragHandle]);
181
- drop(ref);
182
- return ((0, jsx_runtime_1.jsx)(material_1.ListItem, { ref: ref, disablePadding: true, className: isDragging ? 'drag-shaking' : '', sx: {
183
- opacity,
114
+ const style = {
115
+ transform: utilities_1.CSS.Transform.toString(transform),
116
+ transition,
117
+ opacity: isDragging ? 0.5 : 1,
118
+ };
119
+ return ((0, jsx_runtime_1.jsx)(material_1.ListItem, { ref: setNodeRef, style: style, disablePadding: true, className: isDragging ? 'drag-shaking' : '', sx: {
184
120
  transition: isDragging ? 'opacity 0.2s ease' : 'opacity 0.2s ease, transform 0.2s ease',
185
121
  zIndex: isDragging ? 1000 : 'auto',
186
- }, "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: {
122
+ }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: (0, jsx_runtime_1.jsxs)(material_1.ListItemButton, { selected: currentPageId === route, onClick: () => onNavigate(route), sx: {
187
123
  borderRadius: 1,
188
124
  width: '100%',
189
125
  textOverflow: 'ellipsis',
@@ -205,7 +141,7 @@ const DraggableRouteItem = ({ route, staticDataInRoute, currentPageId, onNavigat
205
141
  backgroundColor: isDragging ? 'grey.100' : 'inherit',
206
142
  pl: 1,
207
143
  pr: 1,
208
- }, children: [showDragHandle && ((0, jsx_runtime_1.jsx)(material_1.Box, { ref: dragHandleRef, sx: {
144
+ }, children: [showDragHandle && ((0, jsx_runtime_1.jsx)(material_1.Box, { ...attributes, ...listeners, sx: {
209
145
  display: 'flex',
210
146
  alignItems: 'center',
211
147
  justifyContent: 'center',
@@ -305,6 +241,7 @@ function Layout({ loadState, loadedData }) {
305
241
  draggingSplitPane: false,
306
242
  simulatorType: 'pc',
307
243
  iframeLoaded: false,
244
+ dragOverlay: null,
308
245
  });
309
246
  const { theme, mode, changeMode } = (0, Config_1.useConfig)();
310
247
  // 添加renderComponentTrigger状态,用于触发组件重新渲染
@@ -532,16 +469,35 @@ function Layout({ loadState, loadedData }) {
532
469
  height: '100%',
533
470
  }, children: (0, jsx_runtime_1.jsx)(material_1.Skeleton, { variant: "rectangular", height: "100%", sx: { borderRadius: 1 } }) }));
534
471
  }, []);
535
- // Move item function for drag and drop
536
- const moveItem = (0, react_1.useCallback)((dragIndex, hoverIndex) => {
537
- if (dragIndex === hoverIndex)
472
+ // Configure sensors for dnd-kit
473
+ const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.PointerSensor, {
474
+ activationConstraint: {
475
+ distance: 8, // 8px movement required to start drag
476
+ },
477
+ }), (0, core_1.useSensor)(core_1.KeyboardSensor));
478
+ // Drag event handlers
479
+ const handleDragStart = (event) => {
480
+ const { active } = event;
481
+ state.dragOverlay = active.id;
482
+ };
483
+ const handleDragEnd = (event) => {
484
+ const { active, over } = event;
485
+ state.dragOverlay = null;
486
+ if (!over || active.id === over.id) {
538
487
  return;
539
- const newRoutes = [...routes];
540
- const [draggedItem] = newRoutes.splice(dragIndex, 1);
541
- newRoutes.splice(hoverIndex, 0, draggedItem);
542
- // Save the new order to localStorage (automatically enables custom sort)
543
- setCustomSortOrder(newRoutes);
544
- }, [routes, setCustomSortOrder]);
488
+ }
489
+ const activeRoute = active.id;
490
+ const overRoute = over.id;
491
+ const activeIndex = routes.findIndex((route) => route === activeRoute);
492
+ const overIndex = routes.findIndex((route) => route === overRoute);
493
+ if (activeIndex !== -1 && overIndex !== -1) {
494
+ const newRoutes = [...routes];
495
+ const [draggedItem] = newRoutes.splice(activeIndex, 1);
496
+ newRoutes.splice(overIndex, 0, draggedItem);
497
+ // Save the new order to localStorage (automatically enables custom sort)
498
+ setCustomSortOrder(newRoutes);
499
+ }
500
+ };
545
501
  // 修改 iframe URL 构建逻辑,添加初始状态参数
546
502
  const iframeUrl = (0, react_1.useMemo)(() => {
547
503
  const url = new URL(window.location.href);
@@ -638,30 +594,38 @@ function Layout({ loadState, loadedData }) {
638
594
  },
639
595
  }, 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: () => {
640
596
  state.createBlockOpen = true;
641
- }, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), routes?.length > 0 ? ((0, jsx_runtime_1.jsx)(material_1.List, { sx: {
642
- pr: 1,
643
- overflowY: 'auto',
644
- height: hasCustomSort ? 'calc(100% - 80px)' : 'calc(100% - 60px)',
645
- // Prevent text selection during drag
646
- userSelect: 'none',
647
- }, children: routes
648
- .map((route, index) => {
649
- const routeName = route;
650
- const staticDataInRoute = staticData[route]?.main;
651
- if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
652
- return null;
653
- }
654
- if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
655
- return null;
656
- }
657
- return ((0, jsx_runtime_1.jsx)(DraggableRouteItem, { route: route, staticDataInRoute: staticDataInRoute, currentPageId: currentPage.pageId, onNavigate: (route) => {
658
- if (route !== currentPage.pageId) {
659
- navigate(route);
660
- state.iframeLoaded = false;
661
- }
662
- }, onDelete: handleDeleteBlock, index: index, moveItem: moveItem, showDragHandle: true, routes: routes }, route));
663
- })
664
- .filter(Boolean) })) : ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
597
+ }, children: (0, jsx_runtime_1.jsx)(Add_1.default, { fontSize: "small" }) })] }), routes?.length > 0 ? ((0, jsx_runtime_1.jsxs)(core_1.DndContext, { sensors: sensors, collisionDetection: core_1.closestCorners, onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: [(0, jsx_runtime_1.jsx)(sortable_1.SortableContext, { items: routes, strategy: sortable_1.verticalListSortingStrategy, children: (0, jsx_runtime_1.jsx)(material_1.List, { sx: {
598
+ pr: 1,
599
+ overflowY: 'auto',
600
+ height: hasCustomSort ? 'calc(100% - 80px)' : 'calc(100% - 60px)',
601
+ // Prevent text selection during drag
602
+ userSelect: 'none',
603
+ }, children: routes
604
+ .map((route) => {
605
+ const routeName = route;
606
+ const staticDataInRoute = staticData[route]?.main;
607
+ if (state.searchValue && !routeName?.toLowerCase().includes(state.searchValue?.toLowerCase())) {
608
+ return null;
609
+ }
610
+ if (!state.allComponents?.find(({ blockName }) => `/${blockName}` === routeName)) {
611
+ return null;
612
+ }
613
+ return ((0, jsx_runtime_1.jsx)(SortableRouteItem, { route: route, staticDataInRoute: staticDataInRoute, currentPageId: currentPage.pageId, onNavigate: (route) => {
614
+ if (route !== currentPage.pageId) {
615
+ navigate(route);
616
+ state.iframeLoaded = false;
617
+ }
618
+ }, onDelete: handleDeleteBlock, showDragHandle: true, isDragging: state.dragOverlay === route }, route));
619
+ })
620
+ .filter(Boolean) }) }), (0, jsx_runtime_1.jsx)(core_1.DragOverlay, { children: state.dragOverlay ? ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
621
+ opacity: 0.8,
622
+ backgroundColor: 'background.paper',
623
+ border: '1px solid',
624
+ borderColor: 'primary.main',
625
+ borderRadius: 1,
626
+ boxShadow: 2,
627
+ maxWidth: 280,
628
+ }, children: (0, jsx_runtime_1.jsx)(SortableRouteItem, { route: state.dragOverlay, staticDataInRoute: staticData[state.dragOverlay]?.main, currentPageId: currentPage.pageId, onNavigate: () => { }, onDelete: () => { }, showDragHandle: true, isDragging: true }) })) : null })] })) : ((0, jsx_runtime_1.jsx)(material_1.Box, { sx: {
665
629
  display: 'flex',
666
630
  justifyContent: 'center',
667
631
  alignItems: 'center',
@@ -690,8 +654,11 @@ function Layout({ loadState, loadedData }) {
690
654
  state.allComponents,
691
655
  state.searchValue,
692
656
  state.draggingSplitPane,
657
+ state.dragOverlay,
693
658
  hasCustomSort,
694
- moveItem,
659
+ sensors,
660
+ handleDragStart,
661
+ handleDragEnd,
695
662
  currentPage.pageId,
696
663
  navigate,
697
664
  locale,
@@ -1074,72 +1041,70 @@ function Layout({ loadState, loadedData }) {
1074
1041
  if (isInsideIframe) {
1075
1042
  return middlePanelContent;
1076
1043
  }
1077
- 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: {
1078
- // @ts-ignore
1079
- homeLink: (0, ufo_1.joinURL)(basename),
1080
- addons: (addons) => {
1081
- return [
1082
- (0, jsx_runtime_1.jsx)(material_1.Button, { onClick: async () => {
1083
- if (!session?.user?.did) {
1084
- Toast_1.default.warning(t('themeTranslations.connectWallet'));
1085
- await session.login();
1086
- setTimeout(() => {
1087
- state.createResourceOpen = true;
1088
- }, 1000);
1089
- }
1090
- else {
1044
+ return ((0, jsx_runtime_1.jsxs)(StyledDashboard, { HeaderProps: {
1045
+ // @ts-ignore
1046
+ homeLink: (0, ufo_1.joinURL)(basename),
1047
+ addons: (addons) => {
1048
+ return [
1049
+ (0, jsx_runtime_1.jsx)(material_1.Button, { onClick: async () => {
1050
+ if (!session?.user?.did) {
1051
+ Toast_1.default.warning(t('themeTranslations.connectWallet'));
1052
+ await session.login();
1053
+ setTimeout(() => {
1091
1054
  state.createResourceOpen = true;
1092
- }
1093
- }, children: t('themeTranslations.createResource') }, "logout"),
1094
- ...addons,
1095
- ];
1096
- },
1097
- }, 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: {
1098
- '&.react-split--dragging': {
1099
- '.react-split__pane': {
1100
- '*': {
1101
- userSelect: 'none',
1102
- },
1055
+ }, 1000);
1056
+ }
1057
+ else {
1058
+ state.createResourceOpen = true;
1059
+ }
1060
+ }, children: t('themeTranslations.createResource') }, "logout"),
1061
+ ...addons,
1062
+ ];
1063
+ },
1064
+ }, 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: {
1065
+ '&.react-split--dragging': {
1066
+ '.react-split__pane': {
1067
+ '*': {
1068
+ userSelect: 'none',
1103
1069
  },
1104
1070
  },
1105
- flex: 1,
1106
- }, 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: () => {
1107
- state.createResourceOpen = false;
1108
- } }), (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) => {
1109
- state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
1110
- } }), (0, jsx_runtime_1.jsx)(material_1.TextField, { label: t('themeTranslations.description'), fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
1111
- state.newBlockParams.description = e.target.value;
1112
- } }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", fullWidth: true, onClick: async () => {
1113
- if (!state.newBlockParams.name) {
1114
- Toast_1.default.warning(t('themeTranslations.blockNameRequired'));
1115
- return;
1116
- }
1117
- if (routes.some((route) => {
1118
- const staticDataInRoute = staticData[route]?.main;
1119
- return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
1120
- })) {
1121
- Toast_1.default.warning(t('themeTranslations.blockNameExists'));
1122
- return;
1123
- }
1124
- try {
1125
- await api.post('/api/blocks/create', state.newBlockParams);
1126
- state.init = false;
1127
- setTimeout(() => {
1128
- navigate(`/${state.newBlockParams.name}?no-redirect=true`);
1129
- onCloseCreateBlock();
1130
- }, 1000);
1131
- }
1132
- catch (error) {
1133
- console.error('Failed to create block:', error);
1134
- Toast_1.default.error(t('themeTranslations.failedCreateBlock'));
1135
- }
1136
- }, 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: () => {
1137
- state.previewDialog.open = false;
1138
- } }), (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', {
1139
- componentName: state.deleteConfirmDialog.blockName,
1140
- }) })] }), (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
1141
- ? t('themeTranslations.deleting')
1142
- : t('themeTranslations.deleteConfirm') })] })] })] }) }));
1071
+ },
1072
+ flex: 1,
1073
+ }, 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: () => {
1074
+ state.createResourceOpen = false;
1075
+ } }), (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) => {
1076
+ state.newBlockParams.name = e.target.value.replace(/[^a-zA-Z0-9-]/g, '');
1077
+ } }), (0, jsx_runtime_1.jsx)(material_1.TextField, { label: t('themeTranslations.description'), fullWidth: true, multiline: true, rows: 3, value: state.newBlockParams.description, onChange: (e) => {
1078
+ state.newBlockParams.description = e.target.value;
1079
+ } }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", fullWidth: true, onClick: async () => {
1080
+ if (!state.newBlockParams.name) {
1081
+ Toast_1.default.warning(t('themeTranslations.blockNameRequired'));
1082
+ return;
1083
+ }
1084
+ if (routes.some((route) => {
1085
+ const staticDataInRoute = staticData[route]?.main;
1086
+ return staticDataInRoute?.blockName?.toLowerCase() === state.newBlockParams.name.toLowerCase();
1087
+ })) {
1088
+ Toast_1.default.warning(t('themeTranslations.blockNameExists'));
1089
+ return;
1090
+ }
1091
+ try {
1092
+ await api.post('/api/blocks/create', state.newBlockParams);
1093
+ state.init = false;
1094
+ setTimeout(() => {
1095
+ navigate(`/${state.newBlockParams.name}?no-redirect=true`);
1096
+ onCloseCreateBlock();
1097
+ }, 1000);
1098
+ }
1099
+ catch (error) {
1100
+ console.error('Failed to create block:', error);
1101
+ Toast_1.default.error(t('themeTranslations.failedCreateBlock'));
1102
+ }
1103
+ }, 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: () => {
1104
+ state.previewDialog.open = false;
1105
+ } }), (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', {
1106
+ componentName: state.deleteConfirmDialog.blockName,
1107
+ }) })] }), (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 ? t('themeTranslations.deleting') : t('themeTranslations.deleteConfirm') })] })] })] }));
1143
1108
  }
1144
1109
  // Add SplitPane styling
1145
1110
  const StyledSplitPane = (0, material_1.styled)(split_pane_react_1.default) `