From d4f75d324e9ba5a4396b70f36fbf04b49b6a954c Mon Sep 17 00:00:00 2001 From: Daniel LaForce Date: Sat, 26 Apr 2025 19:19:21 -0600 Subject: [PATCH] feat(MiniGraph): Add cose layout & fullscreen functionality, fix content error --- src/components/MiniGraph.astro | 1115 +++++++++++++++++++++++++------- src/pages/posts/[slug].astro | 6 +- 2 files changed, 891 insertions(+), 230 deletions(-) diff --git a/src/components/MiniGraph.astro b/src/components/MiniGraph.astro index c872e1c..8a2daed 100644 --- a/src/components/MiniGraph.astro +++ b/src/components/MiniGraph.astro @@ -8,8 +8,8 @@ interface Props { title: string; // Current post title tags?: string[]; // Current post tags category?: string; // Current post category - relatedPosts?: any[]; // Related posts data - allPosts?: any[]; // All posts for second level relationships + allPosts?: any[]; // All posts for related content in fullscreen mode + content?: string; // Current post content for fullscreen view } // Extract props with defaults @@ -18,142 +18,152 @@ const { title, tags = [], category = "Uncategorized", - relatedPosts = [], - allPosts = [] + allPosts = [], + content = "" // Default to empty string if content is not passed } = Astro.props; // Generate unique ID for the graph container const graphId = `graph-${Math.random().toString(36).substring(2, 8)}`; -// Get all unique tags from related posts (Level 1 tags) -const relatedPostsTags = relatedPosts - .flatMap(post => post.data.tags || []) - .filter(tag => !tags.includes(tag)); // Exclude current post tags to avoid duplicates - -// Get Level 2 posts: posts related to Level 1 tags (excluding current post and Level 1 posts) -const level2PostIds = new Set(); -const level2Posts = []; - -// For each Level 1 tag, find related posts -tags.forEach(tag => { - allPosts.forEach(post => { - // Skip if post is current post or already in related posts - if (post.slug === slug || relatedPosts.some(rp => rp.slug === post.slug)) { - return; - } - - // If post has the tag and isn't already added - if (post.data.tags?.includes(tag) && !level2PostIds.has(post.slug)) { - level2PostIds.add(post.slug); - level2Posts.push(post); - } - }); -}); - -// Get Level 2 tags from Level 2 posts -const level2Tags = new Set(); -level2Posts.forEach(post => { - (post.data.tags || []).forEach(tag => { - // Only add if not already in Level 0 or Level 1 tags - if (!tags.includes(tag) && !relatedPostsTags.includes(tag)) { - level2Tags.add(tag); - } - }); -}); - -// Prepare nodes data with different levels +// Prepare graph data for current post and its tags const nodes = [ - // Level 0: Current post node + // Current post node { id: slug, label: title, type: "post", - level: 0 + category: category, + tags: tags, + content: content, // Use the content prop + url: `/posts/${slug}` }, - // Level 1: Tag nodes + // Tag nodes ...tags.map(tag => ({ id: `tag-${tag}`, label: tag, type: "tag", - level: 1 - })), - // Level 1: Related post nodes - ...relatedPosts.map(post => ({ - id: post.slug, - label: post.data.title, - type: "post", - level: 1 - })), - // Level 2: Related tags nodes - ...relatedPostsTags.map(tag => ({ - id: `tag-${tag}`, - label: tag, - type: "tag", - level: 2 - })), - // Level 2: Posts related to tags - ...level2Posts.map(post => ({ - id: post.slug, - label: post.data.title, - type: "post", - level: 2 - })), - // Level 2: Tags from Level 2 posts - ...[...level2Tags].map(tag => ({ - id: `tag-${tag}`, - label: tag.toString(), - type: "tag", - level: 2 + url: `/tag/${tag}` })) ]; -// Create edges connecting nodes -const edges = [ - // Level 0 to Level 1: Current post to its tags - ...tags.map(tag => ({ - source: slug, - target: `tag-${tag}`, - type: "post-tag" - })), - // Level 0 to Level 1: Current post to related posts - ...relatedPosts.map(post => ({ - source: slug, - target: post.slug, - type: "post-related" - })), - // Level 1 to Level 2: Related posts to their tags - ...relatedPosts.flatMap(post => - (post.data.tags || []).map(tag => ({ - source: post.slug, - target: `tag-${tag}`, - type: "post-tag" - })) - ), - // Level 1 to Level 2: Tags to related posts - ...level2Posts.flatMap(post => - tags.filter(tag => post.data.tags?.includes(tag)).map(tag => ({ - source: `tag-${tag}`, - target: post.slug, - type: "tag-post" - })) - ) -]; +// Create edges connecting post to tags +const edges = tags.map(tag => ({ + source: slug, + target: `tag-${tag}`, + type: "post-tag" +})); // Prepare graph data object const graphData = { nodes, edges }; + +// Generate predefined colors for categories (copied from KnowledgeGraph.astro) +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' +}; + +// Generate colors based on node types +const nodeTypeColors = { + 'post': '#3B82F6', // Blue for posts + 'tag': '#10B981' // Green for tags +}; --- - +

Post Connections

+ + + + + +
+
+

Post Title

+ +
+ + + +
+
+ + + + + + + +

Select a post node to view its content

+
+
+ + +
- + - -