From b824833b3332b53ba0d876c766583832c268286b Mon Sep 17 00:00:00 2001
From: Matthias Konitzny <konitzny@ibr.cs.tu-bs.de>
Date: Mon, 18 Jul 2022 13:00:17 +0200
Subject: [PATCH] Partially implemented neighbor menu

---
 src/display/components/collapsible.css        | 13 +++---
 src/display/components/collapsible.tsx        | 13 +++++-
 src/display/components/nodeinfo/neighbors.css |  0
 src/display/components/nodeinfo/neighbors.tsx | 42 +++++++++++++++++++
 .../components/nodeinfo/nodeinfobar.tsx       | 19 ++-------
 5 files changed, 64 insertions(+), 23 deletions(-)
 create mode 100644 src/display/components/nodeinfo/neighbors.css
 create mode 100644 src/display/components/nodeinfo/neighbors.tsx

diff --git a/src/display/components/collapsible.css b/src/display/components/collapsible.css
index 8bc1d8f..b61443e 100644
--- a/src/display/components/collapsible.css
+++ b/src/display/components/collapsible.css
@@ -4,8 +4,12 @@
     border-bottom: 1px solid #dee2e6 !important;
 }
 
+.collapsible-content-padding > ul {
+    margin: 0 0 0 2em;
+}
+
 .collapsible-content-padding {
-    padding: 20px 20px 20px 30px;
+    padding: 10px 0 10px 10px;
 }
 
 .collapsible-rotate-center {
@@ -59,18 +63,17 @@
     content: "\276E";
     margin-left: auto;
     transition: all 0.2s linear;
-    transform: rotate(90deg);
+    transform: rotate(-90deg);
 }
 
 .collapsible-button:not(.collapsed)::after {
-    transform: rotate(-90deg);
+    transform: rotate(90deg);
 }
 
 .collapsible-card {
-    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
     transition: 0.3s;
 }
 
 .collapsible-card:hover {
-    box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
+    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
 }
diff --git a/src/display/components/collapsible.tsx b/src/display/components/collapsible.tsx
index b4dd7e4..3c3e6fc 100644
--- a/src/display/components/collapsible.tsx
+++ b/src/display/components/collapsible.tsx
@@ -5,10 +5,16 @@ interface CollapsibleProps {
     open?: boolean;
     header: string | React.ReactNode;
     children?: React.ReactNode | React.ReactNode[];
+    color?: string;
 }
 
-// Implementation details at nhttps://medium.com/edonec/build-a-react-collapsible-component-from-scratch-using-react-hooks-typescript-73dfd02c9208
-function Collapsible({ open, header, children }: CollapsibleProps) {
+// Implementation details at https://medium.com/edonec/build-a-react-collapsible-component-from-scratch-using-react-hooks-typescript-73dfd02c9208
+function Collapsible({
+    open,
+    header,
+    children,
+    color = "gray",
+}: CollapsibleProps) {
     const [isOpen, setIsOpen] = useState(open);
     const [height, setHeight] = useState<number | undefined>(
         open ? undefined : 0
@@ -36,6 +42,8 @@ function Collapsible({ open, header, children }: CollapsibleProps) {
         else setHeight(0);
     }, [isOpen]);
 
+    const borderBottom = "1px solid " + color;
+
     return (
         <>
             <div className={"collapsible-card"}>
@@ -46,6 +54,7 @@ function Collapsible({ open, header, children }: CollapsibleProps) {
                             isOpen ? "" : "collapsed"
                         }`}
                         onClick={toggleOpen}
+                        style={{ borderBottom }}
                     >
                         {header}
                     </button>
diff --git a/src/display/components/nodeinfo/neighbors.css b/src/display/components/nodeinfo/neighbors.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/display/components/nodeinfo/neighbors.tsx b/src/display/components/nodeinfo/neighbors.tsx
new file mode 100644
index 0000000..36bf8c3
--- /dev/null
+++ b/src/display/components/nodeinfo/neighbors.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import { NodeData } from "../../graph";
+import FancyScrollbar from "../fancyscrollbar";
+import Collapsible from "../collapsible";
+
+interface NeighborsProps {
+    neighbors: NodeData[];
+    nodeClickedCallback?: (node: NodeData) => void;
+}
+
+function Neighbors({ neighbors, nodeClickedCallback }: NeighborsProps) {
+    const classes = [...new Set<string>(neighbors.map((node) => node.type))];
+    const categories = new Map<string, Array<NodeData>>();
+
+    for (const cls of classes) {
+        categories.set(cls, []);
+    }
+
+    for (const neighbor of neighbors) {
+        categories.get(neighbor.type).push(neighbor);
+    }
+
+    return (
+        <div className={"neighbor-container"}>
+            <FancyScrollbar>
+                <Collapsible header={"Verwandte Inhalte"}>
+                    {classes.map((cls) => (
+                        <Collapsible header={cls} key={cls}>
+                            <ul>
+                                {categories.get(cls).map((node) => (
+                                    <li key={node.name}>{node.name}</li>
+                                ))}
+                            </ul>
+                        </Collapsible>
+                    ))}
+                </Collapsible>
+            </FancyScrollbar>
+        </div>
+    );
+}
+
+export default Neighbors;
diff --git a/src/display/components/nodeinfo/nodeinfobar.tsx b/src/display/components/nodeinfo/nodeinfobar.tsx
index 92cb560..d417092 100644
--- a/src/display/components/nodeinfo/nodeinfobar.tsx
+++ b/src/display/components/nodeinfo/nodeinfobar.tsx
@@ -3,6 +3,7 @@ import { NodeData } from "../../graph";
 import TitleArea from "./titlearea";
 import FancyScrollbar from "../fancyscrollbar";
 import MediaArea from "./mediaarea";
+import Neighbors from "./neighbors";
 
 interface InfoBarProps {
     height: number;
@@ -11,22 +12,6 @@ interface InfoBarProps {
 }
 
 function NodeInfoBar({ height, node, nodeClosedCallback }: InfoBarProps) {
-    // const [isOpen, setIsOpen] = useState(open);
-    // const [height, setHeight] = useState<number | undefined>(
-    //     open ? undefined : 0
-    // );
-    //
-    // const toggleOpen = () => {
-    //     setIsOpen((prev) => !prev);
-    // };
-    //
-    // const ref = useRef<HTMLDivElement>(null);
-    //
-    // useEffect(() => {
-    //     if (isOpen) setHeight(targetHeight);
-    //     else setHeight(0);
-    // }, [isOpen]);
-
     return (
         <div id={"infoOverlay"} className={"detail-view"} style={{ height }}>
             <div
@@ -48,6 +33,8 @@ function NodeInfoBar({ height, node, nodeClosedCallback }: InfoBarProps) {
                     />
                 </FancyScrollbar>
             </div>
+
+            <Neighbors neighbors={node.neighbors} />
         </div>
     );
 }
-- 
GitLab