fix: layer panel collapsible tree + element actions (visibility toggle, delete) + RenderEngine skips invisible elements
This commit is contained in:
@@ -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,46 +134,70 @@ const LayerPanel: React.FC<LayerPanelProps> = ({
|
||||
renderIcon={(node) => node.icon}
|
||||
renderActions={(node) => {
|
||||
const layer = layers.find((l) => l.id === node.id);
|
||||
if (!layer) return null;
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: '2px', opacity: 0.6 }}>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onToggleLayer(layer.id); }}
|
||||
title={layer.visible ? 'Sichtbar' : 'Versteckt'}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: layer.visible ? 'var(--text-color, #ccc)' : 'var(--text-muted, #666)' }}
|
||||
>
|
||||
{layer.visible ? '👁' : '🚫'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onToggleLock?.(layer.id); }}
|
||||
title={layer.locked ? 'Gesperrt' : 'Entsperrt'}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: layer.locked ? 'var(--accent, #f59e0b)' : 'var(--text-muted, #666)' }}
|
||||
>
|
||||
{layer.locked ? '🔒' : '🔓'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleAddSubLayer(layer.id); }}
|
||||
title="Teilebene hinzufugen"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: 'var(--text-color, #ccc)' }}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onDuplicateLayer?.(layer.id); }}
|
||||
title="Duplizieren"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: 'var(--text-color, #ccc)' }}
|
||||
>
|
||||
⧉
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onDeleteLayer?.(layer.id); }}
|
||||
title="Loschen"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: '#f44336' }}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
if (layer) {
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: '2px', opacity: 0.6 }}>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onToggleLayer(layer.id); }}
|
||||
title={layer.visible ? 'Sichtbar' : 'Versteckt'}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: layer.visible ? 'var(--text-color, #ccc)' : 'var(--text-muted, #666)' }}
|
||||
>
|
||||
{layer.visible ? '👁' : '🚫'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onToggleLock?.(layer.id); }}
|
||||
title={layer.locked ? 'Gesperrt' : 'Entsperrt'}
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: layer.locked ? 'var(--accent, #f59e0b)' : 'var(--text-muted, #666)' }}
|
||||
>
|
||||
{layer.locked ? '🔒' : '🔓'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleAddSubLayer(layer.id); }}
|
||||
title="Teilebene hinzufugen"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: 'var(--text-color, #ccc)' }}
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onDuplicateLayer?.(layer.id); }}
|
||||
title="Duplizieren"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: 'var(--text-color, #ccc)' }}
|
||||
>
|
||||
⧉
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onDeleteLayer?.(layer.id); }}
|
||||
title="Loschen"
|
||||
style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px', color: '#f44336' }}
|
||||
>
|
||||
✕
|
||||
</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} />}
|
||||
|
||||
Reference in New Issue
Block a user