Related Articles lg breakpoint implemented

This commit is contained in:
adilallo
2025-09-11 14:27:18 -06:00
parent 8a31671bbc
commit 3820076435
4 changed files with 104 additions and 39 deletions
+11
View File
@@ -3,6 +3,7 @@ import Link from "next/link";
import { getBlogPostBySlug, getAllPosts } from "../../../lib/contentProcessor";
import ContentBanner from "../../components/ContentBanner";
import RelatedArticles from "../../components/RelatedArticles";
import AskOrganizer from "../../components/AskOrganizer";
import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
/**
@@ -127,6 +128,16 @@ export default async function BlogPostPage({ params }) {
relatedPosts={relatedArticles}
currentPostSlug={post.slug}
/>
{/* Ask Organizer Section */}
<AskOrganizer
title="Have questions about this topic?"
subtitle="Get help from experienced organizers"
description="Our community organizers are here to help you implement these strategies in your own community. Reach out for personalized guidance and support."
buttonText="Ask an organizer"
buttonHref="/contact"
variant="centered"
/>
</div>
);
}
+4 -4
View File
@@ -50,9 +50,9 @@ const ContentThumbnailTemplate = ({
return (
<Link
href={`/blog/${post.slug}`}
className={`block group transition-transform duration-300 hover:scale-105 ${className}`}
className={`block transition-transform duration-200 hover:scale-[1.02] ${className}`}
>
<div className="relative w-[260px] h-[390px] overflow-hidden rounded-lg shadow-lg pt-[18px] pl-[18px] pr-[42px] pb-[212px]">
<div className="relative w-[260px] h-[390px] overflow-hidden pt-[18px] pl-[18px] pr-[42px] pb-[212px]">
{/* Background SVG - sized to fit the 260x390 container exactly */}
<div className="absolute inset-0 z-0">
{/* eslint-disable-next-line @next/next/no-img-element */}
@@ -76,9 +76,9 @@ const ContentThumbnailTemplate = ({
return (
<Link
href={`/blog/${post.slug}`}
className={`block group transition-transform duration-300 hover:scale-105 ${className}`}
className={`block transition-transform duration-200 hover:scale-[1.02] ${className}`}
>
<div className="relative w-[320px] h-[225.5px] overflow-hidden rounded-lg shadow-lg pt-[13.75px] pr-[76px] pb-[73.75px] pl-[14px]">
<div className="relative w-[320px] h-[225.5px] overflow-hidden pt-[13.75px] pr-[76px] pb-[73.75px] pl-[14px]">
{/* Background SVG - sized to fit the 320x225.5 container exactly */}
<div className="absolute inset-0 z-0">
{/* eslint-disable-next-line @next/next/no-img-element */}
+80 -35
View File
@@ -11,10 +11,22 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
const [currentIndex, setCurrentIndex] = useState(0);
const [progress, setProgress] = useState(0);
const [isMobile, setIsMobile] = useState(true);
// Auto-advance every 3 seconds
// Check if we're on mobile (below lg breakpoint)
useEffect(() => {
if (filteredPosts.length <= 1) return;
const checkScreenSize = () => {
setIsMobile(window.innerWidth < 1024); // lg breakpoint is 1024px
};
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
return () => window.removeEventListener("resize", checkScreenSize);
}, []);
// Auto-advance every 3 seconds (only on mobile)
useEffect(() => {
if (filteredPosts.length <= 1 || !isMobile) return;
const interval = setInterval(() => {
setProgress(0);
@@ -22,11 +34,11 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
}, 3000);
return () => clearInterval(interval);
}, [filteredPosts.length]);
}, [filteredPosts.length, isMobile]);
// Progress animation
// Progress animation (only on mobile)
useEffect(() => {
if (filteredPosts.length <= 1) return;
if (filteredPosts.length <= 1 || !isMobile) return;
const progressInterval = setInterval(() => {
setProgress((prev) => {
@@ -38,33 +50,64 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
}, 30); // 30ms intervals for smooth animation
return () => clearInterval(progressInterval);
}, [currentIndex, filteredPosts.length]);
}, [currentIndex, filteredPosts.length, isMobile]);
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">
<section className="py-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-064)]">
<div className="flex flex-col gap-[var(--spacing-scale-032)] lg:gap-[51px]">
<h2 className="text-[32px] lg:text-[44px] leading-[110%] font-medium text-[var(--color-content-inverse-primary)] text-center">
Related Articles
</h2>
{/* Horizontal Articles Row - All Visible with Centering */}
{/* Horizontal Articles Row - Carousel on mobile, Scrollable slider on desktop */}
<div className="flex justify-center overflow-hidden">
<div
className="flex gap-0 transition-transform duration-500 ease-in-out"
className={`flex gap-0 transition-transform duration-500 ease-in-out ${
!isMobile
? "overflow-x-auto scrollbar-hide cursor-grab active:cursor-grabbing"
: ""
}`}
style={{
transform: `translateX(calc(50% - 130px - ${
currentIndex * 260
}px))`,
transform: isMobile
? `translateX(calc(50% - 130px - ${currentIndex * 260}px))`
: "none",
scrollBehavior: !isMobile ? "smooth" : "auto",
}}
onMouseDown={
!isMobile
? (e) => {
const slider = e.currentTarget;
const startX = e.pageX - slider.offsetLeft;
const scrollLeft = slider.scrollLeft;
const handleMouseMove = (e) => {
const x = e.pageX - slider.offsetLeft;
const walk = (x - startX) * 2;
slider.scrollLeft = scrollLeft - walk;
};
const handleMouseUp = () => {
document.removeEventListener(
"mousemove",
handleMouseMove
);
document.removeEventListener("mouseup", handleMouseUp);
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
}
: undefined
}
>
{filteredPosts.map((relatedPost, index) => (
<div
key={relatedPost.slug}
className="flex flex-col items-center"
className="flex flex-col items-center flex-shrink-0"
>
<ContentThumbnailTemplate
post={relatedPost}
@@ -75,27 +118,29 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
</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"
>
{/* Progress bars - only show on mobile */}
{isMobile && (
<div className="flex justify-center gap-[var(--measures-spacing-008)] px-[var(--measures-spacing-064)]">
{filteredPosts.map((relatedPost, index) => (
<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>
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>
);
+9
View File
@@ -6,6 +6,15 @@
@source "../.storybook/**/*";
@source "./**/*";
/* Hide scrollbar utility */
.scrollbar-hide {
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
}
.scrollbar-hide::-webkit-scrollbar {
display: none; /* Safari and Chrome */
}
@theme inline {
/* Custom breakpoints */
--breakpoint-xsm: 429px;