108 lines
4.1 KiB
TypeScript
108 lines
4.1 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
|
|
import SlotImage from "@/components/SlotImage";
|
|
import SlotLink from "@/components/SlotLink";
|
|
import { blogDate, blogHref, blogImage, fetchBlogs, getLocalBlogPosts } from "@/lib/blog";
|
|
import { pageMetadata } from "@/lib/seo";
|
|
import { fetchStaticImageSlots, overlaySlotImages, pickSlot } from "@/lib/static-images";
|
|
|
|
export const revalidate = 60;
|
|
|
|
export async function generateMetadata({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ page?: string }>;
|
|
}): Promise<Metadata> {
|
|
const { page: pageParam } = await searchParams;
|
|
const page = Math.max(1, Number(pageParam) || 1);
|
|
return pageMetadata({
|
|
title: page > 1 ? `وبلاگ — صفحه ${page}` : "وبلاگ",
|
|
description: "آخرین اخبار و مقالات فنی صنایع سیم و کابل کمان.",
|
|
path: page > 1 ? `/blog?page=${page}` : "/blog",
|
|
image: "/images/samples/production-line.avif",
|
|
});
|
|
}
|
|
|
|
export default async function BlogPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ page?: string }>;
|
|
}) {
|
|
const { page: pageParam } = await searchParams;
|
|
const page = Math.max(1, Number(pageParam) || 1);
|
|
const [result, slots] = await Promise.all([fetchBlogs({ page, pageSize: 12 }), fetchStaticImageSlots("blog")]);
|
|
const hero = overlaySlotImages(
|
|
pickSlot(slots, "blog-hero"),
|
|
[{ id: "blog-hero", image: "/images/samples/production-line.avif", title: "وبلاگ" }],
|
|
"blog-hero",
|
|
);
|
|
const usingApi = result.items.length > 0;
|
|
const posts = usingApi ? result.items : page === 1 ? getLocalBlogPosts() : [];
|
|
const pageCount = usingApi
|
|
? Math.max(1, Math.ceil((result.total || result.items.length) / (result.pageSize || 12)))
|
|
: 1;
|
|
|
|
return (
|
|
<>
|
|
<section className="page-hero">
|
|
<SlotImage src={hero.items[0]?.image || "/images/samples/production-line.avif"} alt={hero.items[0]?.title || "وبلاگ کابل کمان"} fill />
|
|
<div className="container">
|
|
<h1>وبلاگ</h1>
|
|
<p className="en">Blog</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="section">
|
|
<div className="container">
|
|
{posts.length === 0 ? (
|
|
<p className="comment-empty">مقالهای برای نمایش وجود ندارد.</p>
|
|
) : (
|
|
<div className="blog-grid">
|
|
{posts.map((post) => (
|
|
<article key={post.id} className="blog-card">
|
|
<div className="blog-card-media">
|
|
<SlotLink href={blogHref(post)} className="blog-card-hit">
|
|
<SlotImage src={blogImage(post)} alt={post.title} fill />
|
|
</SlotLink>
|
|
</div>
|
|
<div className="blog-card-body">
|
|
{blogDate(post) ? <p className="blog-date">{blogDate(post)}</p> : null}
|
|
<h2>
|
|
<SlotLink href={blogHref(post)}>{post.title}</SlotLink>
|
|
</h2>
|
|
{post.abstract ? <p className="blog-excerpt">{post.abstract}</p> : null}
|
|
<SlotLink href={blogHref(post)} className="blog-more">
|
|
ادامه مطلب
|
|
</SlotLink>
|
|
</div>
|
|
</article>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{pageCount > 1 ? (
|
|
<nav className="pagination" aria-label="صفحهبندی وبلاگ">
|
|
{Array.from({ length: pageCount }, (_, index) => {
|
|
const number = index + 1;
|
|
if (pageCount > 12 && Math.abs(number - page) > 3 && number !== 1 && number !== pageCount) {
|
|
return number === 2 || number === pageCount - 1 ? <span key={number}>…</span> : null;
|
|
}
|
|
return (
|
|
<Link
|
|
key={number}
|
|
href={number === 1 ? "/blog" : `/blog?page=${number}`}
|
|
className={number === page ? "active" : undefined}
|
|
>
|
|
{number}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
) : null}
|
|
</div>
|
|
</section>
|
|
</>
|
|
);
|
|
}
|