@@ -35,10 +35,53 @@ import { PatternLibraryElement } from '../../models/listingFlow';
3535import { arePathsEqual } from '../../utils/pathUtils' ;
3636import { getSubElements } from '../../context/EditorContext' ; // Importiere getSubElements
3737
38- const TreeItem = styled ( ListItem ) < { depth : number ; isSelected : boolean } > `
39- padding-left: ${ props => props . depth * 16 + 8 } px;
38+ const LINE_COLOR = 'rgba(0, 0, 0, 0.23)' ; // Farbe für die Verbindungslinien, ähnlich wie Divider
39+
40+ const TreeItem = styled ( ListItem ) < { depth : number ; isSelected : boolean ; isLastChild ?: boolean ; hasChildren ?: boolean } > `
41+ padding-left: ${ props => props . depth * 20 + 8 } px; // Erhöhte Einrückung
4042 background-color: ${ props => props . isSelected ? 'rgba(0, 159, 100, 0.1)' : 'transparent' } ;
4143 border-left: ${ props => props . isSelected ? '3px solid #009F64' : '3px solid transparent' } ;
44+ position: relative; // Für Pseudoelemente
45+
46+ // Vertikale Linie von oben zum aktuellen Element
47+ &::before {
48+ content: '';
49+ position: absolute;
50+ left: ${ props => props . depth * 20 - 10 } px; // Positioniert auf der Höhe des Einzugs-Icons
51+ top: 0;
52+ bottom: 0;
53+ width: 1px;
54+ background-color: ${ LINE_COLOR } ;
55+ // Verstecke die Linie für das erste Element auf jeder Ebene, wenn es keine Geschwister darüber hat
56+ // oder wenn depth === 0 (oberste Ebene)
57+ display: ${ props => props . depth === 0 ? 'none' : 'block' } ;
58+ height: ${ props => props . isLastChild ? 'calc(50% - 0px)' : '100%' } ; // Linie bis zur Mitte, wenn letztes Kind
59+ }
60+
61+ // Horizontale Linie vom vertikalen Strich zum Inhalt (oder zum Aufklapp-Icon)
62+ // Diese Linie wird vor dem Aufklapp-Icon platziert
63+ .MuiIconButton-root:first-of-type::before {
64+ content: '';
65+ position: absolute;
66+ left: -10px; // Von der Mitte des Icons nach links
67+ top: 50%;
68+ width: 10px;
69+ height: 1px;
70+ background-color: ${ LINE_COLOR } ;
71+ display: ${ props => props . depth === 0 ? 'none' : 'block' } ;
72+ }
73+
74+ // Spezielle Anpassung für den Platzhalter-Box, wenn keine Kinder da sind, um die Linie zu zeichnen
75+ .placeholder-for-line::before {
76+ content: '';
77+ position: absolute;
78+ left: -10px;
79+ top: 50%;
80+ width: 10px;
81+ height: 1px;
82+ background-color: ${ LINE_COLOR } ;
83+ display: ${ props => props . depth === 0 ? 'none' : 'block' } ;
84+ }
4285
4386 &:hover {
4487 background-color: ${ props => props . isSelected ? 'rgba(0, 159, 100, 0.15)' : 'rgba(0, 159, 100, 0.05)' } ;
@@ -118,14 +161,16 @@ const TreeNode: React.FC<{
118161 onSelectElement : ( path : number [ ] ) => void ;
119162 onDrillDown : ( path : number [ ] ) => void ;
120163 currentPath : number [ ] ;
164+ isLastChildInLevel : boolean ; // Neue Prop
121165} > = ( {
122166 element,
123167 path,
124168 depth,
125169 selectedPath,
126170 onSelectElement,
127171 onDrillDown,
128- currentPath
172+ currentPath,
173+ isLastChildInLevel
129174} ) => {
130175 const [ expanded , setExpanded ] = useState ( false ) ;
131176 const isSelected = arePathsEqual ( path , selectedPath ) ;
@@ -194,12 +239,15 @@ const TreeNode: React.FC<{
194239 < TreeItem
195240 depth = { depth }
196241 isSelected = { isSelected }
242+ isLastChild = { isLastChildInLevel } // Prop für Styling der Linie
243+ hasChildren = { hasActualChildren } // Prop für Styling der Linie
197244 onClick = { ( ) => onSelectElement ( path ) }
198245 >
199246 < TreeItemContent >
200247 { hasActualChildren ? (
201248 < IconButton
202249 size = "small"
250+ sx = { { position : 'relative' } } // Für ::before Pseudoelement
203251 onClick = { ( e ) => {
204252 e . stopPropagation ( ) ;
205253 setExpanded ( ! expanded ) ;
@@ -208,7 +256,8 @@ const TreeNode: React.FC<{
208256 { expanded ? < ExpandLessIcon fontSize = "small" /> : < ExpandMoreIcon fontSize = "small" /> }
209257 </ IconButton >
210258 ) : (
211- < Box sx = { { width : 28 } } /> // Platzhalter für konsistenten Einzug
259+ // Platzhalter-Box, wenn keine Kinder, aber Linie benötigt wird
260+ < Box className = "placeholder-for-line" sx = { { width : 28 , position : 'relative' } } />
212261 ) }
213262
214263 < ListItemIcon sx = { { minWidth : 36 } } >
@@ -271,14 +320,15 @@ const TreeNode: React.FC<{
271320 < List component = "div" disablePadding >
272321 { children . map ( ( child : PatternLibraryElement , index : number ) => ( // Verwende children
273322 < TreeNode
274- key = { child . element . uuid || index } // Verwende UUID falls vorhanden, sonst Index
323+ key = { child . element . uuid || index }
275324 element = { child }
276325 path = { [ ...path , index ] }
277326 depth = { depth + 1 }
278327 selectedPath = { selectedPath }
279328 onSelectElement = { onSelectElement }
280329 onDrillDown = { onDrillDown }
281330 currentPath = { currentPath }
331+ isLastChildInLevel = { index === children . length - 1 } // Übergebe isLastChild
282332 />
283333 ) ) }
284334 </ List >
@@ -299,14 +349,15 @@ const ElementHierarchyTree: React.FC<ElementHierarchyTreeProps> = ({
299349 < List component = "nav" aria-label = "element hierarchy" dense sx = { { p : 0 } } >
300350 { elements . map ( ( element , index ) => (
301351 < TreeNode
302- key = { index }
352+ key = { element . element . uuid || index }
303353 element = { element }
304354 path = { [ index ] }
305355 depth = { 0 }
306356 selectedPath = { selectedPath }
307357 onSelectElement = { onSelectElement }
308358 onDrillDown = { onDrillDown }
309359 currentPath = { currentPath }
360+ isLastChildInLevel = { index === elements . length - 1 } // Übergebe isLastChild für Top-Level
310361 />
311362 ) ) }
312363 </ List >
0 commit comments