Add interactive carousel to display featured articles
Implement a rotating carousel component for featured articles, allowing users to cycle through up to nine articles in a 3-page, 3-article per page layout, with navigation dots and auto-play functionality. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 517dfa7b-26ac-463d-a6e1-a58c6df97188 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 5611beb8-5cb1-4ae9-98e5-29231d57fcf0 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/517dfa7b-26ac-463d-a6e1-a58c6df97188/0ZGabQy Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
0f4a569bf3
commit
81892e4360
@ -281,11 +281,27 @@ function FeaturedHeroCard({ article, focalPoints }: { article: Article; focalPoi
|
|||||||
}
|
}
|
||||||
|
|
||||||
function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { articles: Article[]; popular?: Article[]; galleryImages?: GalleryImage[]; focalPoints?: Record<string, { x: number; y: number }> }) {
|
function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { articles: Article[]; popular?: Article[]; galleryImages?: GalleryImage[]; focalPoints?: Record<string, { x: number; y: number }> }) {
|
||||||
const hero = articles[0];
|
const pageSize = 3;
|
||||||
const bottom = articles.slice(1, 3);
|
const totalPages = Math.max(1, Math.ceil(Math.min(articles.length, 9) / pageSize));
|
||||||
|
const [page, setPage] = useState(0);
|
||||||
|
const [paused, setPaused] = useState(false);
|
||||||
|
|
||||||
|
const next = useCallback(() => {
|
||||||
|
setPage((p) => (p + 1) % totalPages);
|
||||||
|
}, [totalPages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (paused || totalPages <= 1) return;
|
||||||
|
const timer = setInterval(next, 8000);
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [paused, next, totalPages]);
|
||||||
|
|
||||||
|
const start = page * pageSize;
|
||||||
|
const hero = articles[start];
|
||||||
|
const bottom = articles.slice(start + 1, start + 3);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section data-testid="featured-carousel">
|
<section data-testid="featured-carousel" onMouseEnter={() => setPaused(true)} onMouseLeave={() => setPaused(false)}>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||||
<div className="lg:col-span-2">
|
<div className="lg:col-span-2">
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-1 gap-4">
|
||||||
@ -301,6 +317,13 @@ function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { a
|
|||||||
{popular && popular.length > 0 && <TopStoriesList articles={popular} />}
|
{popular && popular.length > 0 && <TopStoriesList articles={popular} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex justify-center gap-2 mt-3" data-testid="carousel-dots">
|
||||||
|
{Array.from({ length: totalPages }).map((_, i) => (
|
||||||
|
<button key={i} onClick={() => setPage(i)} className={`w-2 h-2 rounded-full transition-all duration-300 ${i === page ? "bg-primary w-5" : "bg-muted-foreground/30 hover:bg-muted-foreground/50"}`} data-testid={`button-carousel-dot-${i}`} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -346,10 +369,10 @@ export default function Home() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const row2 = articles.slice(3, 5);
|
const carouselEnd = Math.min(9, articles.length);
|
||||||
const row3 = articles.slice(5, 7);
|
const row2 = articles.slice(carouselEnd, carouselEnd + 2);
|
||||||
const remaining = articles.slice(7);
|
const row3 = articles.slice(carouselEnd + 2, carouselEnd + 4);
|
||||||
const topStoriesCount = Math.min(12, articles.length);
|
const remaining = articles.slice(carouselEnd + 4);
|
||||||
const rows: Article[][] = [];
|
const rows: Article[][] = [];
|
||||||
for (let i = 0; i < remaining.length; i += 4) {
|
for (let i = 0; i < remaining.length; i += 4) {
|
||||||
rows.push(remaining.slice(i, i + 4));
|
rows.push(remaining.slice(i, i + 4));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user