Files
alireza-hassaniandClaude Sonnet 5 f16b47966b 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>
2026-09-04 18:28:54 +03:30

68 lines
1.7 KiB
JavaScript

import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import {
getBlogById,
blogTitle,
blogExcerpt,
blogCover,
blogDate,
blogContentHtml,
faDate,
} from "@/lib/meshkee";
import styles from "./blog-detail.module.css";
export const revalidate = 120;
export async function generateMetadata({ params }) {
const { id } = await params;
const blog = await getBlogById(id);
if (!blog) return { title: "مقاله" };
const title = blogTitle(blog);
const description = blogExcerpt(blog) || undefined;
return {
title,
description,
openGraph: {
title,
description,
images: blogCover(blog) ? [blogCover(blog)] : undefined,
},
};
}
export default async function BlogDetailPage({ params }) {
const { id } = await params;
const blog = await getBlogById(id);
if (!blog) notFound();
const title = blogTitle(blog);
const cover = blogCover(blog);
const html = blogContentHtml(blog);
return (
<article className="section">
<div className={`container ${styles.wrap}`}>
<Link href="/blog" className={styles.back}>
← بازگشت به مقالات
</Link>
<h1 className={styles.title}>{title}</h1>
{blogDate(blog) ? <p className={styles.date}>{faDate(blogDate(blog))}</p> : null}
{cover ? (
<div className={styles.cover}>
<Image src={cover} alt={title} width={1200} height={640} priority />
</div>
) : null}
{html ? (
<div className={styles.content} dangerouslySetInnerHTML={{ __html: html }} />
) : (
<p className={styles.content}>{blogExcerpt(blog)}</p>
)}
</div>
</article>
);
}