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,67 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user