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;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user