Update the featured articles section to automatically rotate and display the latest articles
Modify the `FeaturedSection` component to include auto-rotation functionality, displaying up to 6 articles in a carousel. Update the `getFeaturedArticles` database query to retrieve the latest 6 articles instead of only those marked as featured. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 413891e8-d784-4bea-b9f5-91a5a68316b4 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: e6e519fc-41a3-463e-88ea-3bde9e02f7f4 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/413891e8-d784-4bea-b9f5-91a5a68316b4/kmpcO4B Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
5f628350f8
commit
db5ec8b74c
@ -8,15 +8,42 @@ import { Skeleton } from "@/components/ui/skeleton";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import Header from "@/components/header";
|
import Header from "@/components/header";
|
||||||
import Footer from "@/components/footer";
|
import Footer from "@/components/footer";
|
||||||
|
import { useState, useEffect, useCallback } from "react";
|
||||||
|
|
||||||
function FeaturedSection({ articles }: { articles: Article[] }) {
|
function FeaturedSection({ articles }: { articles: Article[] }) {
|
||||||
if (articles.length === 0) return null;
|
const pool = articles.slice(0, 6);
|
||||||
|
const totalPages = Math.ceil(pool.length / 3);
|
||||||
|
const [page, setPage] = useState(0);
|
||||||
|
const [paused, setPaused] = useState(false);
|
||||||
|
|
||||||
const hero = articles[0];
|
const next = useCallback(() => {
|
||||||
const side = articles.slice(1, 3);
|
setPage((p) => (p + 1) % totalPages);
|
||||||
|
}, [totalPages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (paused || totalPages <= 1) return;
|
||||||
|
const timer = setInterval(next, 5000);
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [paused, next, totalPages]);
|
||||||
|
|
||||||
|
if (pool.length === 0) return null;
|
||||||
|
|
||||||
|
const start = page * 3;
|
||||||
|
const visible = pool.slice(start, start + 3);
|
||||||
|
while (visible.length < 3 && pool.length >= 3) {
|
||||||
|
visible.push(pool[visible.length % pool.length]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hero = visible[0];
|
||||||
|
const side = visible.slice(1, 3);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="mb-12" data-testid="featured-carousel">
|
<section
|
||||||
|
className="mb-12"
|
||||||
|
data-testid="featured-carousel"
|
||||||
|
onMouseEnter={() => setPaused(true)}
|
||||||
|
onMouseLeave={() => setPaused(false)}
|
||||||
|
>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-5 gap-5">
|
<div className="grid grid-cols-1 lg:grid-cols-5 gap-5">
|
||||||
<Link href={`/article/${hero.slug}`} className="lg:col-span-3">
|
<Link href={`/article/${hero.slug}`} className="lg:col-span-3">
|
||||||
<div
|
<div
|
||||||
@ -75,6 +102,21 @@ function FeaturedSection({ articles }: { articles: Article[] }) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex justify-center gap-2 mt-4" data-testid="carousel-dots">
|
||||||
|
{Array.from({ length: totalPages }).map((_, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => setPage(i)}
|
||||||
|
className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${
|
||||||
|
i === page ? "bg-primary w-6" : "bg-muted-foreground/30 hover:bg-muted-foreground/50"
|
||||||
|
}`}
|
||||||
|
data-testid={`button-carousel-dot-${i}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getFeaturedArticles(): Promise<Article[]> {
|
async getFeaturedArticles(): Promise<Article[]> {
|
||||||
return db.select().from(articles).where(eq(articles.featured, true)).orderBy(desc(articles.publishedAt)).limit(3);
|
return db.select().from(articles).orderBy(desc(articles.publishedAt)).limit(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPopularArticles(limit: number): Promise<Article[]> {
|
async getPopularArticles(limit: number): Promise<Article[]> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user