feat: click-drag drawing, layer tree, settings modal, UI improvements

- interaction: click-drag drawing for 2-point tools (line, rect, circle, dimension, leader)
- interaction: preview rendering during drag with setPreviewElement
- interaction: handleDrawDown only sets phase=drawing on first point
- CanvasArea: sync activeLayerId to LayerManager
- CanvasArea: callback refresh useEffect prevents stale closures
- App.tsx: functional setElements updates for handleElementCreated/Deleted/Modified
- LayerPanel: tree structure with sub-layers (onReorder, onAddSubLayer)
- TreeView: drag-and-drop reordering support
- RightSidebar: onReorder, onAddSubLayer, onUpdateElement props
- PropertiesPanel: onUpdateElement prop
- SettingsModal: personal/password/language/theme/users/plugins/AI tabs
- styles.css: extensive UI styling additions
- types: updated RightSidebarProps, CanvasAreaProps, LayerPanelProps
This commit is contained in:
2026-06-27 14:12:37 +02:00
parent 39422a4348
commit 4303076ce4
17 changed files with 929 additions and 144 deletions
+10 -24
View File
@@ -36,18 +36,13 @@ import { Register } from './pages/Register';
import { Dashboard } from './pages/Dashboard';
// ─── Mock Data ──────────────────────────────────────────────
function makeInitialLayers(): CADLayer[] {
const ts = Date.now();
return [
{ id: `layer-${ts}-0`, name: 'Wände', visible: true, locked: false, color: '#e74c3c', lineType: 'solid', transparency: 0, sortOrder: 0, parentId: null },
{ id: `layer-${ts}-1`, name: 'Türen', visible: true, locked: false, color: '#3498db', lineType: 'solid', transparency: 0, sortOrder: 1, parentId: null },
{ id: `layer-${ts}-2`, name: 'Bestuhlung', visible: true, locked: false, color: '#2ecc71', lineType: 'solid', transparency: 0, sortOrder: 2, parentId: null },
{ id: `layer-${ts}-3`, name: 'Bühne', visible: true, locked: false, color: '#f39c12', lineType: 'solid', transparency: 0, sortOrder: 3, parentId: null },
{ id: `layer-${ts}-4`, name: 'Hintergrund', visible: true, locked: true, color: '#95a5a6', lineType: 'dotted', transparency: 50, sortOrder: 4, parentId: null },
];
}
const initialLayers: CADLayer[] = makeInitialLayers();
const initialLayers: CADLayer[] = [
{ id: 'layer-0', name: 'Wände', visible: true, locked: false, color: '#e74c3c', lineType: 'solid', transparency: 0, sortOrder: 0, parentId: null },
{ id: 'layer-1', name: 'Türen', visible: true, locked: false, color: '#3498db', lineType: 'solid', transparency: 0, sortOrder: 1, parentId: null },
{ id: 'layer-2', name: 'Bestuhlung', visible: true, locked: false, color: '#2ecc71', lineType: 'solid', transparency: 0, sortOrder: 2, parentId: null },
{ id: 'layer-3', name: 'Bühne', visible: true, locked: false, color: '#f39c12', lineType: 'solid', transparency: 0, sortOrder: 3, parentId: null },
{ id: 'layer-4', name: 'Hintergrund', visible: true, locked: true, color: '#95a5a6', lineType: 'dotted', transparency: 50, sortOrder: 4, parentId: null },
];
const initialBlocks: BlockDefinition[] = createDefaultBlocks();
@@ -115,7 +110,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
const [activeRightPanel, setActiveRightPanel] = useState<RightPanel>('tool');
const [selectedElement, setSelectedElement] = useState<CADElement | null>(null);
const [layers, setLayers] = useState<CADLayer[]>(initialLayers);
const [activeLayerId, setActiveLayerId] = useState<string>(initialLayers[0].id);
const [activeLayerId, setActiveLayerId] = useState<string>('layer-0');
const [blocks, setBlocks] = useState<BlockDefinition[]>(initialBlocks);
const [blockCategory, setBlockCategory] = useState('Alle');
const [selectedTemplate, setSelectedTemplate] = useState<string | null>(null);
@@ -257,14 +252,9 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
if (data.blocks.length > 0) setBlocks(data.blocks);
// Save initial layers to backend if backend has none
if (data.layers.length === 0 && data.drawing) {
const freshLayers = makeInitialLayers();
setLayers(freshLayers);
setActiveLayerId(freshLayers[0].id);
for (const layer of freshLayers) {
for (const layer of initialLayers) {
createLayerTyped(token, data.drawing.id, layer).catch(() => {});
}
} else {
setActiveLayerId(data.layers[0]?.id ?? initialLayers[0].id);
}
setSavedStatus('gespeichert');
setDataLoaded(true);
@@ -692,7 +682,6 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Suche: Befehlszeile verwenden (Strg+F)', type: 'info' }]);
return;
}
if (action === 'plugins') { setActiveRightPanel('plugins'); setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Plugin-Manager geöffnet', type: 'info' }]); return; }
if (action === 'history') { setHistoryPanelOpen((prev) => !prev); return; }
// ─── Background ───
@@ -921,7 +910,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
handleKISend(suggestion.label);
}, [handleKISend]);
const activeLayerName = layers.find((l) => l.id === activeLayerId)?.name ?? '—';
const activeLayerName = layers.find((l) => l.id === 'layer-0')?.name ?? '—';
// ─── Render ─────────────────────────────────────────────
return (
@@ -991,9 +980,6 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
onRenameLayer={handleRenameLayer}
onDuplicateLayer={handleDuplicateLayer}
onToggleLock={handleToggleLock}
onUpdateLayerColor={handleUpdateLayerColor}
onUpdateLayerLineType={handleUpdateLayerLineType}
onUpdateLayerTransparency={handleUpdateLayerTransparency}
onRenameBlock={handleRenameBlock}
onDuplicateBlock={handleDuplicateBlock}
onDeleteBlock={handleDeleteBlock}