Files
netrunner-landing/components/sections/BlogPreview.tsx
T
2026-04-19 16:05:05 +10:00

145 lines
4.7 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import Link from "next/link";
import {
Card,
CardHeader,
CardTitle,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ArrowRight, Loader2 } from "lucide-react";
import { pb, getPbImage, type PBPost } from "@/lib/pb"; // Импортируем тип отсюда
import { Dictionary } from "@/lib/IDict";
interface BlogPreviewProps {
lang: string;
dict: Dictionary["blog"];
}
export function BlogPreview({ lang, dict }: BlogPreviewProps) {
const [posts, setPosts] = useState<PBPost[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!lang) return;
async function fetchPosts() {
try {
setLoading(true);
// Тянем из нужной языковой коллекции (posts_ru или posts_en)
const result = await pb
.collection(`posts_${lang}`)
.getList<PBPost>(1, 3, {
filter: "published = true",
sort: "-created",
requestKey: null,
});
setPosts(result.items);
} catch (error) {
console.error("Ошибка загрузки логов:", error);
} finally {
setLoading(false);
}
}
fetchPosts();
}, [lang]);
if (loading) {
return (
<div className="flex justify-center py-20 text-primary opacity-50">
<Loader2 className="w-8 h-8 animate-spin" />
</div>
);
}
// Если записей нет, показываем либо ничего, либо сообщение об ошибке из словаря
if (posts.length === 0) return null;
return (
<section id="blog" className="py-24 px-4 container mx-auto max-w-7xl">
<div className="flex flex-col md:flex-row justify-between items-end mb-12 gap-6">
<div>
<Badge
variant="outline"
className="mb-4 text-primary border-primary/30"
>
{dict.badge}
</Badge>
<h2 className="text-4xl font-bold tracking-tighter text-foreground">
{dict.title}
</h2>
</div>
<Button
asChild
variant="ghost"
className="text-muted-foreground hover:text-primary transition-colors"
>
<Link
href={`/${lang}/blog`}
className="flex items-center gap-2 font-bold"
>
{dict.more} <ArrowRight size={16} />
</Link>
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{posts.map((post) => (
<Card
key={post.id}
className="group overflow-hidden border-border/50 bg-card/30 hover:border-primary/50 transition-all duration-300 flex flex-col h-full"
>
{post.image && (
<div className="relative w-full h-48 overflow-hidden border-b border-border/50">
<img
src={getPbImage(post, post.image)}
alt={post.title}
className="object-cover w-full h-full group-hover:scale-105 transition-transform duration-500"
/>
<div className="absolute inset-0 bg-gradient-to-t from-background to-transparent opacity-80" />
</div>
)}
<CardHeader className="flex-none">
<div className="text-xs font-mono text-muted-foreground mb-2">
{new Date(post.created).toLocaleDateString(
lang === "ru" ? "ru-RU" : "en-US",
)}
</div>
<CardTitle className="text-xl group-hover:text-primary transition-colors line-clamp-2 h-14 flex items-start">
{post.title}
</CardTitle>
</CardHeader>
<CardContent className="flex-1">
<p className="text-sm text-muted-foreground line-clamp-3 leading-relaxed">
{post.excerpt}
</p>
</CardContent>
<CardFooter className="pt-0">
<Button
asChild
variant="link"
className="px-0 text-primary font-bold hover:no-underline group/link"
>
<Link
href={`/${lang}/blog/${post.slug}`}
className="flex items-center gap-1"
>
{dict.readMore}
<ArrowRight
size={14}
className="group-hover/link:translate-x-1 transition-transform"
/>
</Link>
</Button>
</CardFooter>
</Card>
))}
</div>
</section>
);
}