import { useEffect, useRef, useState } from "react"; import ForceGraph2D, { ForceGraphMethods, LinkObject, NodeObject } from "react-force-graph-2d"; import useNavigateTo from "@/hooks/useNavigateTo"; import { cn } from "@/lib/utils"; import { extractMemoIdFromName } from "@/store/common"; import { Memo, MemoRelation_Type } from "@/types/proto/api/v1/memo_service"; import { LinkType, NodeType } from "./types"; import { convertMemoRelationsToGraphData } from "./utils"; interface Props { memo: Memo; className?: string; parentPage?: string; } const MAIN_NODE_COLOR = "#14b8a6"; const DEFAULT_NODE_COLOR = "#a1a1aa"; const MemoRelationForceGraph = ({ className, memo, parentPage }: Props) => { const navigateTo = useNavigateTo(); const [mode, setMode] = useState<"light" | "dark">("light"); const containerRef = useRef(null); const graphRef = useRef, LinkObject> | undefined>(undefined); const [graphSize, setGraphSize] = useState({ width: 0, height: 0 }); // Simple dark mode detection useEffect(() => { const updateMode = () => { const isDark = document.documentElement.classList.contains("dark"); setMode(isDark ? "dark" : "light"); }; updateMode(); // Watch for changes to the dark class const observer = new MutationObserver(updateMode); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"], }); return () => observer.disconnect(); }, []); useEffect(() => { if (!containerRef.current) return; setGraphSize(containerRef.current.getBoundingClientRect()); }, []); const onNodeClick = (node: NodeObject) => { if (node.memo.name === memo.name) return; navigateTo(`/${memo.name}`, { state: { from: parentPage, }, }); }; return (
(node.id === memo.name ? MAIN_NODE_COLOR : DEFAULT_NODE_COLOR)} nodeRelSize={3} nodeLabel={(node) => extractMemoIdFromName(node.memo.name).slice(0, 6).toLowerCase()} linkColor={() => (mode === "light" ? "#e4e4e7" : "#3f3f46")} graphData={convertMemoRelationsToGraphData(memo.relations.filter((r) => r.type === MemoRelation_Type.REFERENCE))} onNodeClick={onNodeClick} linkDirectionalArrowLength={3} linkDirectionalArrowRelPos={1} linkCurvature={0.25} />
); }; export default MemoRelationForceGraph;