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>
68 lines
1.7 KiB
JavaScript
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>
|
|
);
|
|
}
|