feat: add news section with admin editor and public display

- NewsItem type with title, text, date, optional image and link
- Admin page at /admin/news with image upload and auto-date
- Public section between Pricing and FAQ, hidden when empty
- Nav link auto-hides when no news items exist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 23:19:03 +03:00
parent f29dbe0c9f
commit b9800c1cc2
9 changed files with 277 additions and 4 deletions

View File

@@ -0,0 +1,82 @@
import Image from "next/image";
import { Calendar, ExternalLink } from "lucide-react";
import { SectionHeading } from "@/components/ui/SectionHeading";
import { Reveal } from "@/components/ui/Reveal";
import type { SiteContent } from "@/types/content";
interface NewsProps {
data: SiteContent["news"];
}
function formatDate(iso: string): string {
try {
return new Date(iso).toLocaleDateString("ru-RU", {
day: "numeric",
month: "long",
year: "numeric",
});
} catch {
return iso;
}
}
export function News({ data }: NewsProps) {
if (!data.items || data.items.length === 0) return null;
return (
<section id="news" className="section-glow relative section-padding">
<div className="section-divider absolute top-0 left-0 right-0" />
<div className="section-container">
<Reveal>
<SectionHeading centered>{data.title}</SectionHeading>
</Reveal>
<Reveal>
<div className="mx-auto mt-10 max-w-4xl grid gap-4 sm:grid-cols-2">
{data.items.map((item, i) => (
<article
key={i}
className="group rounded-2xl border border-neutral-200 bg-white overflow-hidden transition-all duration-300 hover:shadow-lg dark:border-white/[0.06] dark:bg-[#0a0a0a] dark:hover:border-white/[0.12]"
>
{item.image && (
<div className="relative aspect-[2/1] overflow-hidden">
<Image
src={item.image}
alt={item.title}
fill
sizes="(min-width: 640px) 50vw, 100vw"
className="object-cover transition-transform duration-500 group-hover:scale-105"
/>
</div>
)}
<div className="p-5">
<div className="flex items-center gap-1.5 text-xs text-neutral-400 dark:text-white/30">
<Calendar size={12} />
{formatDate(item.date)}
</div>
<h3 className="mt-2 text-base font-bold text-neutral-900 dark:text-white">
{item.title}
</h3>
<p className="mt-2 text-sm leading-relaxed text-neutral-600 dark:text-neutral-400 line-clamp-4">
{item.text}
</p>
{item.link && (
<a
href={item.link}
target="_blank"
rel="noopener noreferrer"
className="mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-gold-dark hover:text-gold transition-colors dark:text-gold-light"
>
<ExternalLink size={14} />
Подробнее
</a>
)}
</div>
</article>
))}
</div>
</Reveal>
</div>
</section>
);
}