Files
farrokh-win/src/app/blog/[id]/[slug]/page.tsx
T

108 lines
3.3 KiB
TypeScript

import type { Metadata } from "next";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import CommentBox from "@/components/CommentBox";
import SlotImage from "@/components/SlotImage";
import {
blogDate,
blogHref,
blogImage,
blogTitleSlug,
fetchBlogById,
getLocalBlogPost,
} from "@/lib/blog";
import { fetchComments } from "@/lib/comments";
import { sanitizeHtml } from "@/lib/format";
import { pageMetadata } from "@/lib/seo";
export const revalidate = 60;
type Params = { id: string; slug: string };
export async function generateMetadata({
params,
}: {
params: Promise<Params>;
}): Promise<Metadata> {
const { id } = await params;
const post = (await fetchBlogById(id)) ?? getLocalBlogPost(id);
if (!post) {
return {
title: "مقاله یافت نشد",
description: "این مطلب در وبلاگ پنجره فرخ موجود نیست.",
robots: { index: false },
};
}
return pageMetadata({
title: post.title,
description: post.abstract?.trim() || `${post.title} | مقالات پنجره فرخ`,
path: blogHref(post),
image: blogImage(post),
});
}
export default async function BlogDetailPage({ params }: { params: Promise<Params> }) {
const { id, slug } = await params;
const apiPost = await fetchBlogById(id);
const post = apiPost ?? getLocalBlogPost(id);
if (!post) notFound();
const canonical = blogTitleSlug(post.title);
if (decodeURIComponent(slug) !== canonical) {
redirect(blogHref(post));
}
const comments = apiPost ? await fetchComments("blog", post.id) : [];
const html = sanitizeHtml(post.mainTextHtml);
return (
<>
<section className="page-hero">
<div className="container page-hero-inner">
<div className="page-hero-en">
<span>ARTICLE</span>
<i />
</div>
<div className="page-hero-fa">
<nav className="crumbs">
<Link href="/">خانه</Link>
{" > "}
<Link href="/blog">مقالات</Link>
{" > "}
<span>{post.title}</span>
</nav>
<h1>{post.title}</h1>
{blogDate(post) ? <p className="muted">{blogDate(post)}</p> : null}
</div>
</div>
</section>
<section className="section">
<div className="container detail-article">
{blogImage(post) ? (
<div className="article-cover">
<SlotImage src={blogImage(post)} alt={post.title} />
</div>
) : null}
{post.abstract ? <p className="detail-lead">{post.abstract}</p> : null}
{html ? <div className="rich-text" dangerouslySetInnerHTML={{ __html: html }} /> : null}
<section className="detail-tabs">
<h2>نظرات</h2>
{apiPost ? (
<CommentBox entityType="blog" entityId={post.id} comments={comments} />
) : (
<p className="comment-empty">ثبت نظر برای این مطلب در دسترس نیست.</p>
)}
</section>
<Link href="/blog" className="text-link">
بازگشت به مقالات
</Link>
</div>
</section>
</>
);
}