Add pagination to article categories and video pages, and enhance home page with more content and ads
Implement paginated API endpoints for articles and videos, add pagination UI to category and video pages, and inject additional ads and content widgets into the home page. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 517dfa7b-26ac-463d-a6e1-a58c6df97188 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: c201f10b-bbd3-4402-9212-e0b79bfa670f Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/517dfa7b-26ac-463d-a6e1-a58c6df97188/EtK2Sno Replit-Helium-Checkpoint-Created: true
This commit is contained in:
+63
-19
@@ -8,7 +8,7 @@ import { Eye, Play, Images } from "lucide-react";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import Header from "@/components/header";
|
||||
import Footer from "@/components/footer";
|
||||
import AdSense, { ArticleCardAd, MultiplexAd, SidebarAd } from "@/components/adsense";
|
||||
import AdSense, { ArticleCardAd, InArticleAd, MultiplexAd, SidebarAd } from "@/components/adsense";
|
||||
import ArtistPatternBg from "@/components/artist-pattern-bg";
|
||||
import { PhotoGalleryWidget } from "@/components/photo-gallery";
|
||||
import { HoroscopeWidget } from "@/components/horoscope-widget";
|
||||
@@ -516,6 +516,10 @@ export default function Home() {
|
||||
{ id: "recipe", el: <RecipeWidget key="recipe" /> },
|
||||
{ id: "breaking", el: <div key="breaking" className="flex flex-col gap-4"><BreakingNewsWidget /></div> },
|
||||
{ id: "gallery2", el: <PhotoGalleryWidget key="gallery2" reverseOrder={true} /> },
|
||||
{ id: "horoscope2", el: <HoroscopeWidget key="horoscope2" /> },
|
||||
{ id: "news2", el: <div key="news2" className="flex flex-col gap-4"><NewsWidget /></div> },
|
||||
{ id: "recipe2", el: <RecipeWidget key="recipe2" /> },
|
||||
{ id: "breaking2", el: <div key="breaking2" className="flex flex-col gap-4"><BreakingNewsWidget /></div> },
|
||||
], []);
|
||||
|
||||
const gridItems = useMemo(() => {
|
||||
@@ -546,7 +550,7 @@ export default function Home() {
|
||||
}
|
||||
|
||||
const totalRows = items.length / 4;
|
||||
const adRows = [1, 3, 5, 7];
|
||||
const adRows = [1, 3, 5, 7, 9, 11, 13];
|
||||
let adCount = 0;
|
||||
for (const row of adRows) {
|
||||
if (row >= totalRows) continue;
|
||||
@@ -599,6 +603,16 @@ export default function Home() {
|
||||
return articles.filter((a) => !usedIds.has(a.id)).slice(0, 3);
|
||||
}, [articles, widePickedArticles]);
|
||||
|
||||
const extraBottomArticles = useMemo(() => {
|
||||
if (!articles || articles.length < 15) return [];
|
||||
const usedIds = new Set([
|
||||
...articles.slice(0, 9).map((a) => a.id),
|
||||
...widePickedArticles.map((a) => a.id),
|
||||
...bottomArticles.map((a) => a.id),
|
||||
]);
|
||||
return articles.filter((a) => !usedIds.has(a.id)).slice(0, 6);
|
||||
}, [articles, widePickedArticles, bottomArticles]);
|
||||
|
||||
const bottomSection = useMemo(() => {
|
||||
const items: { type: "widget" | "ad" | "article"; el: JSX.Element }[] = [
|
||||
{ type: "widget", el: <NewsWidget key="bottom-news" /> },
|
||||
@@ -611,9 +625,14 @@ export default function Home() {
|
||||
})),
|
||||
{ type: "ad", el: <div key="ad-bottom-1"><ArticleCardAd /></div> },
|
||||
{ type: "widget", el: <PhotoGalleryWidget key="bottom-gallery" /> },
|
||||
{ type: "ad", el: <div key="ad-bottom-2"><ArticleCardAd /></div> },
|
||||
...extraBottomArticles.slice(0, 3).map((a) => ({
|
||||
type: "article" as const,
|
||||
el: <BlogCard key={`bottom-extra-${a.id}`} article={a} focalPoints={focalPoints} />,
|
||||
})),
|
||||
];
|
||||
return items;
|
||||
}, [bottomArticles, focalPoints]);
|
||||
}, [bottomArticles, extraBottomArticles, focalPoints]);
|
||||
|
||||
if (isLoading || !articles) {
|
||||
return (
|
||||
@@ -661,6 +680,8 @@ export default function Home() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InArticleAd />
|
||||
|
||||
{widePickedArticles.length > 0 && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
|
||||
<ArtistPatternBg className="hidden lg:block rounded-lg overflow-hidden bg-card border border-card-border" seed={99}>
|
||||
@@ -683,25 +704,30 @@ export default function Home() {
|
||||
)}
|
||||
|
||||
{gridRows.map((row, ri) => (
|
||||
<div key={`row-${ri}`} className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{row.map((item) =>
|
||||
item.type === "widget"
|
||||
? <div key={item.key}>{item.widget!.el}</div>
|
||||
: item.type === "ad"
|
||||
? <div key={item.key} className="h-full" data-testid={`ad-grid-${item.key}`}><ArticleCardAd /></div>
|
||||
: item.article
|
||||
? <MediumCard key={item.key} article={item.article} focalPoints={focalPoints} />
|
||||
: null
|
||||
)}
|
||||
{ri === gridRows.length - 1 && widePickedArticles.length > 0 && (
|
||||
<div className="sm:col-span-2 lg:col-span-4 grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<WideCardClassic article={widePickedArticles[0]} focalPoints={focalPoints} />
|
||||
{widePickedArticles[1] && <WideCardClassic article={widePickedArticles[1]} focalPoints={focalPoints} />}
|
||||
</div>
|
||||
)}
|
||||
<div key={`row-group-${ri}`}>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{row.map((item) =>
|
||||
item.type === "widget"
|
||||
? <div key={item.key}>{item.widget!.el}</div>
|
||||
: item.type === "ad"
|
||||
? <div key={item.key} className="h-full" data-testid={`ad-grid-${item.key}`}><ArticleCardAd /></div>
|
||||
: item.article
|
||||
? <MediumCard key={item.key} article={item.article} focalPoints={focalPoints} />
|
||||
: null
|
||||
)}
|
||||
{ri === gridRows.length - 1 && widePickedArticles.length > 0 && (
|
||||
<div className="sm:col-span-2 lg:col-span-4 grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<WideCardClassic article={widePickedArticles[0]} focalPoints={focalPoints} />
|
||||
{widePickedArticles[1] && <WideCardClassic article={widePickedArticles[1]} focalPoints={focalPoints} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{ri % 3 === 2 && ri < gridRows.length - 1 && <InArticleAd />}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<InArticleAd />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{bottomSection.map((item, i) => (
|
||||
<div key={`bottom-${i}`}>
|
||||
@@ -710,6 +736,24 @@ export default function Home() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<InArticleAd />
|
||||
|
||||
{extraBottomArticles.length > 3 && (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{extraBottomArticles.slice(3, 6).map((a) => (
|
||||
<BlogCard key={`extra-bottom-${a.id}`} article={a} focalPoints={focalPoints} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<MultiplexAd />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<PhotoGalleryWidget key="extra-gallery" />
|
||||
<NewsWidget key="extra-news" />
|
||||
<RecipeWidget key="extra-recipe" />
|
||||
</div>
|
||||
|
||||
<MultiplexAd />
|
||||
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user