--- import ArticleLayout from '@layouts/ArticleLayout.astro'; import { SITE_URL } from '@constants'; import PostCommentForm from '@components/blog/PostCommentForm.astro'; import RelatedPosts from '@components/blog/RelatedPosts.astro'; import ArticleTableOfContents from '@components/blog/ArticleTableOfContents.astro'; import { getPostBySlug, getPosts, getPostImageUrl, getPostVotesStats } from '@lib/pb'; import { marked } from 'marked'; export const prerender = false; const slug = Astro.params.slug; if (!slug) { return Astro.redirect('/blog'); } const post = await getPostBySlug(slug); if (!post) { return Astro.redirect('/blog'); } const { likes = 0, dislikes = 0 } = await getPostVotesStats(post.id).catch(() => ({ likes: 0, dislikes: 0 })); // Конвертируем markdown в HTML const contentHtml = marked(post.content || ''); // Извлекаем заголовки для оглавления const headingRegex = /^(#{2,3})\s+(.+)$/gm; const tocItems: { id: string; text: string; level: number }[] = []; const body = post.content || ''; let match; let headingIndex = 0; while ((match = headingRegex.exec(body)) !== null) { const level = match[1].length; const text = match[2].trim(); tocItems.push({ level, id: `heading-${headingIndex++}`, text }); } // Форматируем дату const formatDate = (date: string) => { return new Date(date).toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' }); }; // Для related posts берем те же категории const { posts: relatedPosts } = await getPosts({ perPage: 4, category: post.category }); const filteredRelated = relatedPosts.filter(p => p.slug !== slug).slice(0, 3); const currentUrl = `${SITE_URL}/blog/${slug}`; const heroImage = getPostImageUrl(post); ---