Initial commit: Negin Dental Clinic website
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>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user