diff --git a/src/display/components/collapsible.css b/src/display/components/collapsible.css index 8bc1d8f7618e32d10fb5304057510d2e831e9bc3..b61443e45cf0feea7fbe9bfb98d6449066b8228f 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 b4dd7e419a06dd66c7a881b7ba5e4ff589543a90..3c3e6fcea94f5eb6283a4fe7966431210fe1cbaf 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/display/components/nodeinfo/neighbors.tsx b/src/display/components/nodeinfo/neighbors.tsx new file mode 100644 index 0000000000000000000000000000000000000000..36bf8c37f07d7227eed61b7e31edb163ef08a491 --- /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 92cb5606fedc6734592cd12e07dd6d463b1ca022..d4170924104f38378065a3d5afde299860e970b1 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> ); }