import React from 'react'; import { Link, useParams } from 'react-router-dom'; import { ArrowLeftIcon, ChevronLeftIcon } from 'lucide-react'; import { renderToHTMLString } from '@tiptap/static-renderer'; import { Reveal } from '../components/Reveal'; import { ButtonLink } from '../components/Button'; import { ArticleCard } from '../components/ArticleCard'; import { ArticleMeta } from '../components/ArticleMeta'; import { TableOfContents, extractToc, type TocItem } from '../components/TableOfContents'; import { Newsletter } from '../components/home/Newsletter'; import { useSite } from '../api'; import { applySeo } from '../seo'; import { useEffect } from 'react'; import { ARTICLE_EXTENSIONS } from '../components/admin/ArticleEditor'; import type { Article } from '../data/site'; /** بدنه مقاله را به HTML و فهرست مطالب تبدیل می‌کند — سند TipTap جدید یا پاراگراف‌های قدیمی */ function renderBody(article: Article): { html: string | null; toc: TocItem[]; legacy: string[] } { const body = article.body as unknown; if (Array.isArray(body)) return { html: null, toc: [], legacy: body }; if (body && typeof body === 'object' && (body as { type?: string }).type === 'doc') { try { const html = renderToHTMLString({ extensions: ARTICLE_EXTENSIONS, content: body as never }); // تیترهای H2/H3 شناسه لنگر می‌گیرند تا فهرست مطالب به آن‌ها بپرد const { items, html: htmlWithIds } = extractToc(html); return { html: htmlWithIds, toc: items, legacy: [] }; } catch { return { html: null, toc: [], legacy: [] }; } } return { html: null, toc: [], legacy: [] }; } export function ArticleDetail() { const { slug } = useParams<{slug: string;}>(); const { articles, brand } = useSite(); const article = articles.find((a) => a.slug === slug); // عنوان تب، توضیح متا، OG و JSON-LD از خود مقاله useEffect(() => { if (!article) return; applySeo({ title: `${article.title} | ${brand}`, // توضیحات سئوی اختصاصی در اولویت است؛ در نبود آن، چکیده description: article.meta_description || article.excerpt, path: `/blog/${article.slug}`, image: article.image, type: 'article', jsonLd: { '@context': 'https://schema.org', '@type': 'Article', headline: article.title, description: article.meta_description || article.excerpt, image: article.image ? new URL(article.image, window.location.origin).href : undefined, inLanguage: 'fa', author: { '@type': 'Organization', name: article.author?.trim() || brand }, publisher: { '@type': 'Organization', name: brand }, mainEntityOfPage: new URL(`/blog/${article.slug}`, window.location.origin).href, }, }); }, [article?.id]); if (!article) { return (

این مقاله پیدا نشد

فهرست کامل مقالات وبلاگ را ببینید.

بازگشت به وبلاگ
); } const { html, toc, legacy } = renderBody(article); const related = articles.filter((a) => a.slug !== article.slug && a.status !== 'draft').slice(0, 3); return ( <>
{article.image_alt

{article.excerpt}

{html ? (
) : ( legacy.map((paragraph, i) =>

{paragraph}

) )}
{/* فهرست مطالب — در دسکتاپ کنار متن چسبان می‌ماند */} {toc.length > 0 && ( )}

مقالات مرتبط

{related.map((item, i) => )}
); }