import React, { useEffect, useState, useRef, useCallback } from 'react';
import ForceGraph3D from 'react-force-graph-3d';
import { useNavigate } from 'react-router-dom';
import { fetchGraphData } from '../utils/graphDataManager';
import Loading from '../components/Loading';
import { ArrowLeftIcon, InfoIcon } from '@phosphor-icons/react';
import { Link } from 'react-router-dom';
import Seo from '../components/Seo';
const KnowledgeGraphPage = () => {
const [graphData, setGraphData] = useState({ nodes: [], links: [] });
const [loading, setLoading] = useState(true);
const [hoverNode, setHoverNode] = useState(null);
const fgRef = useRef();
const navigate = useNavigate();
useEffect(() => {
const loadData = async () => {
const data = await fetchGraphData();
setGraphData(data);
setLoading(false);
};
loadData();
}, []);
const handleNodeClick = useCallback(
(node) => {
if (!node) return;
// Aim at node from outside it
const distance = 40;
const distRatio = 1 + distance / Math.hypot(node.x, node.y, node.z);
if (fgRef.current) {
fgRef.current.cameraPosition(
{
x: node.x * distRatio,
y: node.y * distRatio,
z: node.z * distRatio,
}, // new position
node, // lookAt ({ x, y, z })
3000, // ms transition duration
);
}
// Navigate logic
setTimeout(() => {
if (node.group === 'post') {
navigate(`/blog/${node.slug}`);
} else if (node.group === 'app') {
navigate(node.to || `/apps/${node.slug}`);
} else if (node.group === 'project') {
navigate(`/projects/${node.slug}`);
}
}, 1500); // Wait for half the zoom
},
[navigate],
);
if (loading) return