145 lines
4.7 KiB
TypeScript
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>
|
|
);
|
|
}
|