Related Article section implemented

This commit is contained in:
adilallo
2025-09-11 14:06:31 -06:00
parent ec2db8be22
commit 8a31671bbc
5 changed files with 152 additions and 40 deletions
+10 -7
View File
@@ -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);
+10 -10
View File
@@ -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);
+102
View File
@@ -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 (
<section className="py-[var(--spacing-scale-032)]">
<div className="flex flex-col gap-[var(--spacing-scale-032)]">
<h2 className="text-[32px] leading-[110%] font-medium text-[var(--color-content-inverse-primary)] text-center">
Related Articles
</h2>
{/* Horizontal Articles Row - All Visible with Centering */}
<div className="flex justify-center overflow-hidden">
<div
className="flex gap-0 transition-transform duration-500 ease-in-out"
style={{
transform: `translateX(calc(50% - 130px - ${
currentIndex * 260
}px))`,
}}
>
{filteredPosts.map((relatedPost, index) => (
<div
key={relatedPost.slug}
className="flex flex-col items-center"
>
<ContentThumbnailTemplate
post={relatedPost}
variant="vertical"
/>
</div>
))}
</div>
</div>
{/* Three separate progress bars below the carousel */}
<div className="flex justify-center gap-[var(--measures-spacing-008)] px-[var(--measures-spacing-064)]">
{filteredPosts.map((relatedPost, index) => (
<div
key={relatedPost.slug}
className="max-w-[var(--measures-spacing-056)] w-full h-[var(--measures-spacing-004)] bg-gray-200 rounded-full overflow-hidden"
>
<div
className="h-full bg-gray-600 rounded-full transition-all duration-75 ease-linear"
style={{
width:
index === currentIndex
? `${progress}%`
: index < currentIndex
? "100%"
: "0%",
}}
/>
</div>
))}
</div>
</div>
</section>
);
}