Add the FarrokhWin Next.js site for Meshkee hosting.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user