feat: global block library tree + grouping tool — 19 files, 588 tests green
This commit is contained in:
+66
-1
@@ -583,8 +583,37 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
}, []);
|
||||
|
||||
const handleCommandTrigger = useCallback((msg: string) => {
|
||||
// Route group/ungroup actions from keyboard shortcuts
|
||||
if (msg === 'group') {
|
||||
const gm = groupManagerRef.current;
|
||||
const ids = selectedElementIdsRef.current;
|
||||
if (ids.length < 2) {
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppieren: Mindestens 2 Elemente auswählen', type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
const group = gm.createGroup(ids);
|
||||
setGroups(gm.getGroups());
|
||||
collab.setGroup(group);
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe erstellt: ${group.name} (${ids.length} Elemente)`, type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
if (msg === 'ungroup') {
|
||||
const gm = groupManagerRef.current;
|
||||
const allGroups = gm.getGroups();
|
||||
if (allGroups.length === 0) {
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Degruppieren: Keine Gruppe vorhanden', type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
const selIds = selectedElementIdsRef.current;
|
||||
let targetGroup = allGroups.find(g => g.elementIds.some(id => selIds.includes(id)));
|
||||
if (!targetGroup) targetGroup = allGroups[allGroups.length - 1];
|
||||
gm.ungroup(targetGroup.id);
|
||||
setGroups(gm.getGroups());
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe aufgelöst: ${targetGroup.name}`, type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: msg, type: 'info' }]);
|
||||
}, []);
|
||||
}, [collab]);
|
||||
|
||||
// Block management handlers
|
||||
const handleRenameBlock = useCallback((id: string, name: string) => {
|
||||
@@ -892,6 +921,38 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
return;
|
||||
}
|
||||
|
||||
// ─── Group/Ungroup actions ───
|
||||
if (action === 'group') {
|
||||
const gm = groupManagerRef.current;
|
||||
const ids = selectedElementIdsRef.current;
|
||||
if (ids.length < 2) {
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppieren: Mindestens 2 Elemente auswählen', type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
const group = gm.createGroup(ids);
|
||||
const newGroups = gm.getGroups();
|
||||
setGroups(newGroups);
|
||||
collab.setGroup(group);
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe erstellt: ${group.name} (${ids.length} Elemente)`, type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
if (action === 'ungroup') {
|
||||
const gm = groupManagerRef.current;
|
||||
const allGroups = gm.getGroups();
|
||||
if (allGroups.length === 0) {
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Degruppieren: Keine Gruppe vorhanden', type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
// Find the group that contains any selected element
|
||||
const selIds = selectedElementIdsRef.current;
|
||||
let targetGroup = allGroups.find(g => g.elementIds.some(id => selIds.includes(id)));
|
||||
if (!targetGroup) targetGroup = allGroups[allGroups.length - 1];
|
||||
gm.ungroup(targetGroup.id);
|
||||
setGroups(gm.getGroups());
|
||||
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe aufgelöst: ${targetGroup.name}`, type: 'info' }]);
|
||||
return;
|
||||
}
|
||||
|
||||
// ─── Insert actions (set active tool) ───
|
||||
if (action === 'insert-line') { setActiveTool('line'); setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Linie-Werkzeug aktiv', type: 'info' }]); return; }
|
||||
if (action === 'insert-rect') { setActiveTool('rect'); setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Rechteck-Werkzeug aktiv', type: 'info' }]); return; }
|
||||
@@ -1429,6 +1490,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onDeleteBlock={handleDeleteBlock}
|
||||
onSvgImport={handleSvgImport}
|
||||
onSaveGroupAsBlock={handleSaveGroupAsBlock}
|
||||
onGroup={() => handleRibbonAction('group')}
|
||||
onUngroup={() => handleRibbonAction('ungroup')}
|
||||
/>
|
||||
<CanvasArea
|
||||
cursorPos={cursorPos}
|
||||
@@ -1461,6 +1524,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
selectedTemplate={selectedTemplate}
|
||||
bgConfig={bgConfig}
|
||||
remoteCursors={collab.cursors}
|
||||
groups={groups}
|
||||
/>
|
||||
<RightSidebar
|
||||
activePanel={activeRightPanel}
|
||||
@@ -1499,6 +1563,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onReorder={handleReorderLayer}
|
||||
onAddSubLayer={handleAddSubLayer}
|
||||
onUpdateElement={handleUpdateElement}
|
||||
token={token}
|
||||
/>
|
||||
</div>
|
||||
<CommandLine
|
||||
|
||||
Reference in New Issue
Block a user