index.tsx
1 import "./index.css" 2 3 import React, { useState } from "react" 4 import ReactClient from "react-dom/client" 5 6 function V({ children }: { children: React.ReactNode }) { 7 return <div className="vertical">{children}</div> 8 } 9 10 function Node(props: { children: React.ReactNode, selected?: boolean, collapsable?: boolean }) { 11 const [state, setState] = useState({ collapsed: false }); 12 13 const onClick = () => { 14 setState({ collapsed: !state.collapsed }) 15 } 16 17 18 const selected = props.selected || false 19 const selectedClass = selected ? " selected" : ""; 20 21 const collapsable = props.collapsable === undefined ? true : props.collapsable 22 const collapsed = state.collapsed && collapsable 23 const collapseClass = collapsed ? " collapsed" : ""; 24 25 const dot = collapsed ? (selected ? "⦾" : "◦") : (selected ? "⦿" : "●") 26 27 return ( 28 <div className={"horizontal node" + collapseClass + selectedClass}> 29 <div className="vertical center-items"> 30 <div className="dot" onClick={onClick}>{dot}</div> 31 <div className="vertical-line"></div> 32 </div> 33 <div className="content vertical"> 34 {props.children} 35 </div> 36 </div> 37 ) 38 } 39 40 function Subject({ children }: { children: string }) { 41 return ( 42 <div className="subject"> 43 {children} 44 </div> 45 ) 46 } 47 48 49 function Body({ children }: { children: React.ReactNode }) { 50 return ( 51 <div className="body"> 52 {children} 53 </div> 54 ) 55 } 56 57 type Forest = { 58 id: string, 59 subject: string, 60 children: Array<Forest> 61 } 62 63 function ForestComp(props: { forest: Forest }) { 64 const nodes = props.forest.children.map( 65 (child, index) => <ForestComp key={index} forest={child} /> 66 ) 67 68 return ( 69 <Node collapsable={nodes.length > 0}> 70 <Subject>{props.forest.subject}</Subject> 71 {nodes.length > 0 ? <Body>{nodes}</Body> : null} 72 </Node> 73 ) 74 } 75 76 function Root() { 77 const forest = [ 78 { 79 id: Math.random().toString(16), 80 subject: "Hello", 81 children: [ 82 { 83 id: Math.random().toString(16), 84 subject: "World", 85 children: [ 86 { 87 id: Math.random().toString(16), 88 subject: "Hello", 89 children: [ 90 { 91 id: Math.random().toString(16), 92 subject: "World", 93 children: [] 94 }, 95 { 96 id: Math.random().toString(16), 97 subject: "Yaaaay", 98 children: [] 99 } 100 ] 101 }, 102 { 103 id: Math.random().toString(16), 104 subject: "World", 105 children: [] 106 } 107 ] 108 }, 109 { 110 id: Math.random().toString(16), 111 subject: "Yaaaay", 112 children: [] 113 } 114 ] 115 }, 116 { 117 id: Math.random().toString(16), 118 subject: "World", 119 children: [] 120 } 121 ] 122 123 return ( 124 <V> 125 { 126 forest.map( 127 (child, index) => 128 <ForestComp key={index} forest={child} /> 129 ) 130 } 131 </V> 132 ) 133 } 134 135 ReactClient.createRoot(document.getElementById("root")!).render( 136 <Root /> 137 )