From 8a31671bbcdcdae1163f308944aa05e19be8cadc Mon Sep 17 00:00:00 2001
From: adilallo <39313955+adilallo@users.noreply.github.com>
Date: Thu, 11 Sep 2025 14:06:31 -0600
Subject: [PATCH] Related Article section implemented
---
app/blog/[slug]/page.js | 31 ++-----
app/components/ContentContainer.js | 17 ++--
app/components/ContentThumbnailTemplate.js | 20 ++--
app/components/RelatedArticles.js | 102 +++++++++++++++++++++
content/blog/building-community-trust.md | 22 +++++
5 files changed, 152 insertions(+), 40 deletions(-)
create mode 100644 app/components/RelatedArticles.js
create mode 100644 content/blog/building-community-trust.md
diff --git a/app/blog/[slug]/page.js b/app/blog/[slug]/page.js
index cdcb426..c667d1b 100644
--- a/app/blog/[slug]/page.js
+++ b/app/blog/[slug]/page.js
@@ -1,8 +1,8 @@
import { notFound } from "next/navigation";
import Link from "next/link";
import { getBlogPostBySlug, getAllPosts } from "../../../lib/contentProcessor";
-import ContentThumbnailTemplate from "../../components/ContentThumbnailTemplate";
import ContentBanner from "../../components/ContentBanner";
+import RelatedArticles from "../../components/RelatedArticles";
import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
/**
@@ -70,9 +70,9 @@ export default async function BlogPostPage({ params }) {
notFound();
}
- // Get related posts (for now, just get other posts)
+ // Get related articles (for now, just get other posts)
const allPosts = getAllPosts();
- const relatedPosts = allPosts.filter((p) => p.slug !== post.slug).slice(0, 3); // Show up to 3 related posts
+ const relatedArticles = allPosts; // Pass all posts to RelatedArticles component for filtering
return (
@@ -122,26 +122,11 @@ export default async function BlogPostPage({ params }) {
- {/* Related Posts Section */}
- {relatedPosts.length > 0 && (
-
-
-
- Related Articles
-
-
-
- {relatedPosts.map((relatedPost) => (
-
- ))}
-
-
-
- )}
+ {/* Related Articles Section */}
+
);
}
diff --git a/app/components/ContentContainer.js b/app/components/ContentContainer.js
index b975581..8092062 100644
--- a/app/components/ContentContainer.js
+++ b/app/components/ContentContainer.js
@@ -14,13 +14,16 @@ const ContentContainer = ({ post, width = "200px", size = "responsive" }) => {
if (!slug) return icons[0];
- // Use the same hash logic as background images to ensure matching
- const hash = slug.split("").reduce((a, b) => {
- a = (a << 5) - a + b.charCodeAt(0);
- return a & a;
- }, 0);
-
- return icons[Math.abs(hash) % icons.length];
+ // Use the same cycling logic as background images to ensure matching
+ const slugOrder = [
+ "building-community-trust",
+ "operational-security-mutual-aid",
+ "making-decisions-without-hierarchy",
+ "resolving-active-conflicts",
+ ];
+ const index = slugOrder.indexOf(slug);
+ const finalIndex = index >= 0 ? index % icons.length : 0;
+ return icons[finalIndex];
};
const iconImage = getIconImage(post.slug);
diff --git a/app/components/ContentThumbnailTemplate.js b/app/components/ContentThumbnailTemplate.js
index 3ed84ba..a264f5a 100644
--- a/app/components/ContentThumbnailTemplate.js
+++ b/app/components/ContentThumbnailTemplate.js
@@ -32,16 +32,16 @@ const ContentThumbnailTemplate = ({
if (!slug) return images[0];
- // Use the slug to deterministically select an image
- // More robust hash function using djb2 algorithm
- let hash = 5381;
- for (let i = 0; i < slug.length; i++) {
- hash = (hash << 5) + hash + slug.charCodeAt(i);
- }
-
- // Ensure positive number and get index
- const index = Math.abs(hash) % images.length;
- return images[index];
+ // Simple cycling approach to ensure different styles
+ const slugOrder = [
+ "building-community-trust",
+ "operational-security-mutual-aid",
+ "making-decisions-without-hierarchy",
+ "resolving-active-conflicts",
+ ];
+ const index = slugOrder.indexOf(slug);
+ const finalIndex = index >= 0 ? index % images.length : 0;
+ return images[finalIndex];
};
const backgroundImage = getBackgroundImage(post.slug, variant);
diff --git a/app/components/RelatedArticles.js b/app/components/RelatedArticles.js
new file mode 100644
index 0000000..adb93f8
--- /dev/null
+++ b/app/components/RelatedArticles.js
@@ -0,0 +1,102 @@
+"use client";
+
+import { useState, useEffect } from "react";
+import ContentThumbnailTemplate from "./ContentThumbnailTemplate";
+
+export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
+ // Filter out the current post from related posts
+ const filteredPosts = relatedPosts.filter(
+ (post) => post.slug !== currentPostSlug
+ );
+
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const [progress, setProgress] = useState(0);
+
+ // Auto-advance every 3 seconds
+ useEffect(() => {
+ if (filteredPosts.length <= 1) return;
+
+ const interval = setInterval(() => {
+ setProgress(0);
+ setCurrentIndex((prev) => (prev + 1) % filteredPosts.length);
+ }, 3000);
+
+ return () => clearInterval(interval);
+ }, [filteredPosts.length]);
+
+ // Progress animation
+ useEffect(() => {
+ if (filteredPosts.length <= 1) return;
+
+ const progressInterval = setInterval(() => {
+ setProgress((prev) => {
+ if (prev >= 100) {
+ return 0;
+ }
+ return prev + 1;
+ });
+ }, 30); // 30ms intervals for smooth animation
+
+ return () => clearInterval(progressInterval);
+ }, [currentIndex, filteredPosts.length]);
+
+ if (filteredPosts.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+
+ Related Articles
+
+
+ {/* Horizontal Articles Row - All Visible with Centering */}
+
+
+ {filteredPosts.map((relatedPost, index) => (
+
+
+
+ ))}
+
+
+
+ {/* Three separate progress bars below the carousel */}
+
+ {filteredPosts.map((relatedPost, index) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/content/blog/building-community-trust.md b/content/blog/building-community-trust.md
new file mode 100644
index 0000000..b7b14ff
--- /dev/null
+++ b/content/blog/building-community-trust.md
@@ -0,0 +1,22 @@
+---
+title: "Building Community Trust"
+description: "Strategies for fostering trust, transparency, and accountability in community organizations"
+author: "Author name"
+date: "2025-04-20"
+related:
+ [
+ "resolving-active-conflicts",
+ "operational-security-mutual-aid",
+ "making-decisions-without-hierarchy",
+ ]
+---
+
+Trust is the foundation of any successful community organization. Without it, even the best structures and processes will struggle to function effectively. Building and maintaining trust requires intentional effort, clear communication, and consistent follow-through on commitments.
+
+One key element of building trust is transparency. When community members understand how decisions are made, where resources go, and what challenges the organization faces, they're more likely to feel invested and supportive. This doesn't mean sharing every detail, but it does mean being open about the big picture and the reasoning behind important choices.
+
+Another crucial factor is accountability. When people make mistakes or fail to follow through on commitments, there need to be clear, fair processes for addressing these issues. This might involve mediation, restorative justice practices, or other approaches that focus on learning and repair rather than punishment.
+
+Regular communication also plays a vital role. Whether through newsletters, community meetings, or informal conversations, keeping people informed about what's happening helps prevent misunderstandings and builds a sense of shared purpose. It's especially important to communicate both successes and challenges honestly.
+
+Finally, trust is built through consistent action over time. When community members see that the organization follows through on its promises and treats people fairly, even in difficult situations, trust grows stronger. This consistency creates a foundation that can weather conflicts and challenges when they inevitably arise.