--- // src/components/KnowledgeGraph.astro // Interactive visualization of content connections using Cytoscape.js export interface GraphNode { id: string; label: string; category?: string; tags?: string[]; url?: string; // Added URL for linking } export interface GraphEdge { source: string; target: string; strength?: number; } export interface GraphData { nodes: GraphNode[]; edges: GraphEdge[]; } interface Props { graphData: GraphData; height?: string; // e.g., '600px' } const { graphData, height = "60vh" } = Astro.props; // Generate colors based on categories for nodes const uniqueCategories = [...new Set(graphData.nodes.map(node => node.category || 'Uncategorized'))]; const categoryColors = {}; const predefinedColors = { 'Kubernetes': '#326CE5', 'Docker': '#2496ED', 'DevOps': '#FF6F61', 'Homelab': '#06B6D4', 'Networking': '#9333EA', 'Infrastructure': '#10B981', 'Automation': '#F59E0B', 'Security': '#EF4444', 'Monitoring': '#6366F1', 'Storage': '#8B5CF6', 'Obsidian': '#7C3AED', 'Tutorial': '#3B82F6', 'Uncategorized': '#A0AEC0' }; uniqueCategories.forEach((category, index) => { if (predefinedColors[category]) { categoryColors[category] = predefinedColors[category]; } else { const hue = (index * 137.5) % 360; categoryColors[category] = `hsl(${hue}, 70%, 60%)`; } }); // Calculate node sizes const nodeSizes = {}; const minSize = 20; const maxSize = 40; const degreeMap = new Map(); graphData.nodes.forEach(node => degreeMap.set(node.id, 0)); graphData.edges.forEach(edge => { degreeMap.set(edge.source, (degreeMap.get(edge.source) || 0) + 1); degreeMap.set(edge.target, (degreeMap.get(edge.target) || 0) + 1); }); const maxDegree = Math.max(...Array.from(degreeMap.values()), 1); graphData.nodes.forEach(node => { const degree = degreeMap.get(node.id) || 0; const normalizedSize = maxDegree === 0 ? 0.5 : degree / maxDegree; nodeSizes[node.id] = minSize + normalizedSize * (maxSize - minSize); }); ---
Initializing Knowledge Graph...

Node Title

Category: Category Name
Tags:
Connections:
Read Article
{uniqueCategories.map(category => ( ))}
Legend
{uniqueCategories.map(category => (
{category}
))}