import Link from 'next/link'; import { requireAdminAuth } from '@/lib/adminAuth'; import { adminListArticles, getStats } from '@/lib/engine'; import { FileText, Eye, TrendingUp, Plus, Image, RefreshCw } from 'lucide-react'; export const dynamic = 'force-dynamic'; export const metadata = { title: 'Дашборд' }; function StatCard({ label, value, icon: Icon, color = 'emerald' }) { const colors = { emerald: 'bg-emerald-50 dark:bg-emerald-950 text-emerald-600 dark:text-emerald-400', blue: 'bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400', amber: 'bg-amber-50 dark:bg-amber-950 text-amber-600 dark:text-amber-400', }; return (
{label}
{value ?? '—'}
); } export default async function AdminDashboard() { await requireAdminAuth(); const [articles, stats] = await Promise.allSettled([ adminListArticles({ limit: 50 }), getStats(), ]); const arts = articles.status === 'fulfilled' ? (Array.isArray(articles.value) ? articles.value : articles.value?.articles || []) : []; const st = stats.status === 'fulfilled' ? stats.value : null; const published = arts.filter(a => a.status === 'published').length; const drafts = arts.filter(a => a.status === 'draft').length; const withoutCover = arts.filter(a => !a.cover_url).length; const recentArts = arts.slice(0, 8); return (

Дашборд

Управление контентом zeropost.ru

Новая статья
{/* Статистика */}
0 ? 'amber' : 'emerald'} />
{/* Быстрые действия */}

Быстрые действия

Написать статью Все статьи {withoutCover > 0 && ( )}
{/* Последние статьи */}

Последние статьи

Все →
{recentArts.map(a => ( {/* Обложка-превью */}
{a.cover_url ? ( ) : (
)}
{a.title}
{a.status === 'published' ? 'Опубликовано' : 'Черновик'} {a.tags?.slice(0, 2).map(t => ( #{t} ))}
{a.published_at ? new Date(a.published_at).toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' }) : '—'}
))}
); } // Кнопка backfill — клиентская function BackfillButton({ count }) { return (
Догенерировать обложки ({count}) ); }