--- import ArticleLayout from '@layouts/ArticleLayout.astro'; import { SITE_URL } from '@constants'; import Comments from '@components/blog/comments/Comments.tsx'; import RelatedPosts from '@components/blog/RelatedPosts.astro'; import ArticleTableOfContents from '@components/blog/ArticleTableOfContents.astro'; import { getPostBySlug, getPosts, getPostImageUrl, getPostVotesStats, getPostViews } 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 })); const views = await getPostViews(post.id).catch(() => 0); // Конвертируем markdown в HTML const contentHtml = marked(post.content || ''); // Извлекаем заголовки для оглавления (поддержка HTML и Markdown) const headingRegex = /]*>([^<]+)<\/?h[2-3]>/gi; 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 = parseInt(match[1]); // Теперь 2 или 3 const text = match[2].trim(); tocItems.push({ level, id: `heading-${headingIndex++}`, text }); } const formatDate = (date: string) => { const d = new Date(date); const day = d.getDate().toString().padStart(2, '0'); const month = (d.getMonth() + 1).toString().padStart(2, '0'); const year = new Date().getFullYear().toString().slice(-2); return `${day}/${month}/${year}`; }; // Для 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); ---