/ frontend / src / index.tsx
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  )