fix: layer panel collapsible tree + element actions (visibility toggle, delete) + RenderEngine skips invisible elements
This commit is contained in:
@@ -331,6 +331,20 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
}
|
||||
}, [layers, blocks, groups, bgConfig, syncHistory, drawingId, token, collab, activeLayerId]);
|
||||
|
||||
const handleToggleElementVisible = useCallback((id: string) => {
|
||||
setElements((prev) => prev.map((e) => {
|
||||
if (e.id === id) {
|
||||
const newEl = { ...e, properties: { ...e.properties, visible: e.properties?.visible === false ? true : false } };
|
||||
if (token) {
|
||||
setSavedStatus("Speichert…");
|
||||
updateElement(token, newEl.id, newEl).then(() => setSavedStatus("gespeichert")).catch(() => setSavedStatus("Fehler"));
|
||||
}
|
||||
return newEl;
|
||||
}
|
||||
return e;
|
||||
}));
|
||||
}, [token]);
|
||||
|
||||
const handleElementsDeleted = useCallback((ids: string[]) => {
|
||||
setElements((prev) => {
|
||||
const newElements = prev.filter((e) => !ids.includes(e.id));
|
||||
@@ -980,6 +994,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onRenameLayer={handleRenameLayer}
|
||||
onDuplicateLayer={handleDuplicateLayer}
|
||||
onToggleLock={handleToggleLock}
|
||||
onElementsDeleted={handleElementsDeleted}
|
||||
onToggleElementVisible={handleToggleElementVisible}
|
||||
elements={elements}
|
||||
onRenameBlock={handleRenameBlock}
|
||||
onDuplicateBlock={handleDuplicateBlock}
|
||||
|
||||
@@ -151,7 +151,7 @@ export class RenderEngine {
|
||||
const layers = this.layerManager.getLayers();
|
||||
for (const layer of layers) {
|
||||
if (!layer.visible) continue;
|
||||
const els = visibleElements.filter(e => e.layerId === layer.id);
|
||||
const els = visibleElements.filter(e => e.layerId === layer.id && e.properties?.visible !== false);
|
||||
for (const el of els) {
|
||||
this.drawElement(el, layer);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import type { LayerPanelProps } from '../types/ui.types';
|
||||
import type { CADLayer, CADElement } from '../types/cad.types';
|
||||
import type { TreeNode } from '../types/ui.types';
|
||||
@@ -67,6 +67,8 @@ const LayerPanel: React.FC<LayerPanelProps> = ({
|
||||
onToggleLock,
|
||||
onReorder,
|
||||
onAddSubLayer,
|
||||
onElementsDeleted,
|
||||
onToggleElementVisible,
|
||||
}) => {
|
||||
const buildTree = (parentId: string | null): TreeNode[] => {
|
||||
return layers
|
||||
@@ -87,7 +89,7 @@ const LayerPanel: React.FC<LayerPanelProps> = ({
|
||||
id: l.id,
|
||||
name: l.name,
|
||||
icon: layerIcon,
|
||||
expanded: true,
|
||||
expanded: false,
|
||||
active: l.id === activeLayerId,
|
||||
children: [...subLayerNodes, ...elementNodes],
|
||||
count: layerElements.length > 0 ? layerElements.length : undefined,
|
||||
@@ -132,7 +134,7 @@ const LayerPanel: React.FC<LayerPanelProps> = ({
|
||||
renderIcon={(node) => node.icon}
|
||||
renderActions={(node) => {
|
||||
const layer = layers.find((l) => l.id === node.id);
|
||||
if (!layer) return null;
|
||||
if (layer) {
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: '2px', opacity: 0.6 }}>
|
||||
<button
|
||||
@@ -172,6 +174,30 @@ const LayerPanel: React.FC<LayerPanelProps> = ({
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const element = elements.find((el) => el.id === node.id);
|
||||
if (element) {
|
||||
const isVisible = element.properties?.visible !== false;
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: '2px', opacity: 0.6 }}>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onToggleElementVisible?.(element.id); }}
|
||||
title={isVisible ? 'Sichtbar' : 'Versteckt'}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: isVisible ? 'var(--text-color, #ccc)' : 'var(--text-muted, #666)' }}
|
||||
>
|
||||
{isVisible ? '👁' : '🚫'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onElementsDeleted?.([element.id]); }}
|
||||
title="Loschen"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: '#f44336' }}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -17,6 +17,7 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
|
||||
activeLayerId, onSelectLayer, onAddLayer, onToggleLayer,
|
||||
onDeleteLayer, onRenameLayer, onDuplicateLayer, onToggleLock,
|
||||
onReorder, onAddSubLayer,
|
||||
onElementsDeleted, onToggleElementVisible,
|
||||
elements,
|
||||
onRenameBlock, onDuplicateBlock, onDeleteBlock, onSvgImport, onSaveGroupAsBlock,
|
||||
onBlockCategoryChange, onBlockSearch, onDragBlock,
|
||||
@@ -57,7 +58,7 @@ const RightSidebar: React.FC<RightSidebarProps> = ({
|
||||
}} />}
|
||||
</div>
|
||||
<div className={`rightbar-panel${activePanel === 'layer' ? ' active' : ''}`} data-panel-content="layer">
|
||||
{activePanel === 'layer' && <LayerPanel layers={layers} elements={elements} activeLayerId={activeLayerId} onSelectLayer={onSelectLayer ?? (() => {})} onAddLayer={onAddLayer ?? (() => {})} onToggleLayer={onToggleLayer ?? (() => {})} onDeleteLayer={onDeleteLayer} onRenameLayer={onRenameLayer} onDuplicateLayer={onDuplicateLayer} onToggleLock={onToggleLock} onReorder={onReorder} onAddSubLayer={onAddSubLayer} />}
|
||||
{activePanel === 'layer' && <LayerPanel layers={layers} elements={elements} onElementsDeleted={onElementsDeleted} onToggleElementVisible={onToggleElementVisible} activeLayerId={activeLayerId} onSelectLayer={onSelectLayer ?? (() => {})} onAddLayer={onAddLayer ?? (() => {})} onToggleLayer={onToggleLayer ?? (() => {})} onDeleteLayer={onDeleteLayer} onRenameLayer={onRenameLayer} onDuplicateLayer={onDuplicateLayer} onToggleLock={onToggleLock} onReorder={onReorder} onAddSubLayer={onAddSubLayer} />}
|
||||
</div>
|
||||
<div className={`rightbar-panel${activePanel === 'library' ? ' active' : ''}`} data-panel-content="library">
|
||||
{activePanel === 'library' && <BlockLibrary blocks={blocks} category="Alle" onCategoryChange={onBlockCategoryChange ?? (() => {})} onSearch={onBlockSearch ?? (() => {})} onDragBlock={onDragBlock ?? (() => {})} onRenameBlock={onRenameBlock} onDuplicateBlock={onDuplicateBlock} onDeleteBlock={onDeleteBlock} onSvgImport={onSvgImport} onSaveGroupAsBlock={onSaveGroupAsBlock} />}
|
||||
|
||||
@@ -138,6 +138,8 @@ export interface RightSidebarProps {
|
||||
onUpdateLayerLineType?: (id: string, lineType: 'solid' | 'dashed' | 'dotted') => void;
|
||||
onUpdateLayerTransparency?: (id: string, transparency: number) => void;
|
||||
onAddSubLayer?: (parentId: string) => void;
|
||||
onElementsDeleted?: (ids: string[]) => void;
|
||||
onToggleElementVisible?: (id: string) => void;
|
||||
onRenameBlock?: (id: string, name: string) => void;
|
||||
onDuplicateBlock?: (id: string) => void;
|
||||
onDeleteBlock?: (id: string) => void;
|
||||
@@ -176,6 +178,8 @@ export interface LayerPanelProps {
|
||||
onUpdateLayerLineType?: (id: string, lineType: 'solid' | 'dashed' | 'dotted') => void;
|
||||
onUpdateLayerTransparency?: (id: string, transparency: number) => void;
|
||||
onAddSubLayer?: (parentId: string) => void;
|
||||
onElementsDeleted?: (ids: string[]) => void;
|
||||
onToggleElementVisible?: (id: string) => void;
|
||||
}
|
||||
|
||||
export interface BlockLibraryProps {
|
||||
|
||||
Reference in New Issue
Block a user