astro_advokat/frontend/src/components/single-post/RelatedPosts.astro
2026-03-30 20:21:41 +05:00

152 lines
4.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
import { MONTHS } from "@lib/constants";
const POCKETBASE_URL = import.meta.env.POCKETBASE_URL || "http://localhost:8090";
export interface Props {
currentPostId?: string;
currentPostSlug?: string;
}
const { currentPostId, currentPostSlug } = Astro.props;
interface PostRecord {
id: string;
title: string;
slug: string;
excerpt: string;
image?: string;
tags?: string;
created: string;
}
interface PocketBaseResponse {
items: PostRecord[];
}
// Получаем похожие посты (исключая текущий)
let relatedPosts: PostRecord[] = [];
try {
const filter = currentPostId ? `id!="${currentPostId}"` : "";
const response = await fetch(
`${POCKETBASE_URL}/api/collections/posts/records?filter=${encodeURIComponent(filter)}&perPage=3`
);
const data: PocketBaseResponse = await response.json();
if (data.items) {
relatedPosts = data.items;
}
} catch (error) {
console.error("Error fetching related posts:", error);
}
// Форматируем дату
function formatDate(dateString: string) {
const date = new Date(dateString);
return `${date.getDate()} ${MONTHS[date.getMonth()]} ${date.getFullYear()}`;
}
// Парсим tags
function parseTags(tagsString?: string): string {
if (!tagsString) return "НОВОСТИ";
try {
const tags = typeof tagsString === "string" ? JSON.parse(tagsString) : tagsString;
return Array.isArray(tags) && tags.length > 0 ? tags[0].toUpperCase() : "НОВОСТИ";
} catch {
return "НОВОСТИ";
}
}
---
<section
class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 border-t border-gray-200"
>
{/* Заголовок */}
<div class="flex items-center justify-between mb-8">
<h2 class="text-2xl font-bold text-gray-900">Похожие публикации</h2>
<a
href="/blog"
class="text-blue-600 hover:text-blue-800 font-medium text-sm flex items-center gap-1 transition-colors group"
>
Все статьи
<svg
class="w-4 h-4 transition-transform group-hover:translate-x-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5l7 7-7 7"></path>
</svg>
</a>
</div>
{/* Сетка карточек */}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{relatedPosts && relatedPosts.length > 0 ? (
relatedPosts.map((post) => {
const imageUrl = post.image
? `${POCKETBASE_URL}/api/files/posts/${post.id}/${post.image}`
: "https://images.unsplash.com/photo-1589829085413-56de8ae18c73?q=80&w=800&auto=format&fit=crop";
return (
<article class="group bg-white rounded-2xl overflow-hidden shadow-sm border border-gray-100 hover:shadow-lg transition-all duration-300">
{/* Изображение */}
<a
href={`/blog/${post.slug}`}
class="block relative overflow-hidden aspect-video"
>
<img
src={imageUrl}
alt={post.title}
class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/30 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</a>
{/* Контент */}
<div class="p-6">
<span class="inline-block px-3 py-1 bg-blue-50 text-blue-600 text-xs font-medium rounded-full mb-3">
{parseTags(post.tags)}
</span>
<h3 class="text-lg font-bold text-gray-900 mb-3 line-clamp-2 group-hover:text-blue-600 transition-colors">
<a href={`/blog/${post.slug}`}>{post.title}</a>
</h3>
<p class="text-gray-600 text-sm line-clamp-3 mb-4 leading-relaxed">
{post.excerpt}
</p>
<a
href={`/blog/${post.slug}`}
class="inline-flex items-center gap-2 text-blue-600 font-medium text-sm hover:text-blue-800 transition-colors group/link"
>
Читать далее
<svg
class="w-4 h-4 transition-transform group-hover/link:translate-x-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 8l4 4m0 0l-4 4m4-4H3"
/>
</svg>
</a>
</div>
</article>
);
})
) : (
<p class="col-span-full text-center text-gray-500 py-8">Нет связанных публикаций</p>
)}
</div>
</section>