Next.js (App Router) clone of negindentalclinic.ir, wired to the Meshkee Website API (blog, contact form, favicon), with on-page SEO and a scroll-reveal animation sequence on the homepage. See context.md for full project context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
91 lines
3.7 KiB
JavaScript
91 lines
3.7 KiB
JavaScript
import Image from "next/image";
|
||
import Link from "next/link";
|
||
import PageHero from "@/components/PageHero";
|
||
import { getBlogs, blogTitle, blogExcerpt, blogCover, blogDate, faDate, slugifyFa } from "@/lib/meshkee";
|
||
import styles from "./blog.module.css";
|
||
|
||
export const metadata = {
|
||
title: "مقالات",
|
||
description:
|
||
"مقالات و مطالب آموزشی کلینیک دندانپزشکی نگین درباره سلامت دهان و دندان، مراقبت روزانه از دندانها، ایمپلنت، ارتودنسی و آخرین روشهای درمانی.",
|
||
};
|
||
|
||
export const revalidate = 120;
|
||
|
||
export default async function BlogPage({ searchParams }) {
|
||
const page = Number((await searchParams)?.page) || 1;
|
||
const { items, total, pageSize } = await getBlogs({ page, pageSize: 12 });
|
||
const totalPages = Math.max(1, Math.ceil((total || 0) / (pageSize || 12)));
|
||
|
||
return (
|
||
<>
|
||
<PageHero en="Blog" fa="مقالات" lead="مطالب آموزشی درباره سلامت دهان و دندان." />
|
||
|
||
<section className="section">
|
||
<div className="container">
|
||
{items.length === 0 ? (
|
||
<div className={styles.empty}>
|
||
<h2>بهزودی</h2>
|
||
<p>
|
||
مقالات کلینیک نگین در حال آمادهسازی است. برای دریافت مشاوره و اطلاعات
|
||
بیشتر با ما در تماس باشید.
|
||
</p>
|
||
<Link href="/contact-us" className="btn">
|
||
تماس با ما
|
||
</Link>
|
||
</div>
|
||
) : (
|
||
<>
|
||
<h2 className="visually-hidden">لیست مقالات</h2>
|
||
<div className="grid grid--3">
|
||
{items.map((blog) => {
|
||
const title = blogTitle(blog);
|
||
const cover = blogCover(blog);
|
||
const href = `/blog/${blog.id}/${slugifyFa(title)}`;
|
||
return (
|
||
<article key={blog.id} className={styles.card}>
|
||
<Link href={href} className={styles.cardArt}>
|
||
{cover ? (
|
||
<Image src={cover} alt={title} width={420} height={260} />
|
||
) : (
|
||
<span className={styles.cardArtFallback} aria-hidden="true" />
|
||
)}
|
||
</Link>
|
||
<div className={styles.cardBody}>
|
||
{blogDate(blog) ? (
|
||
<span className={styles.cardDate}>{faDate(blogDate(blog))}</span>
|
||
) : null}
|
||
<h3>
|
||
<Link href={href}>{title}</Link>
|
||
</h3>
|
||
{blogExcerpt(blog) ? <p>{blogExcerpt(blog)}</p> : null}
|
||
<Link href={href} className={styles.cardMore}>
|
||
ادامه مطلب
|
||
</Link>
|
||
</div>
|
||
</article>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{totalPages > 1 ? (
|
||
<nav className={styles.pager} aria-label="صفحهبندی مقالات">
|
||
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
|
||
<Link
|
||
key={p}
|
||
href={p === 1 ? "/blog" : `/blog?page=${p}`}
|
||
className={`${styles.pagerLink} ${p === page ? styles.pagerLinkActive : ""}`}
|
||
>
|
||
{p}
|
||
</Link>
|
||
))}
|
||
</nav>
|
||
) : null}
|
||
</>
|
||
)}
|
||
</div>
|
||
</section>
|
||
</>
|
||
);
|
||
}
|