feat: categories — pages, nav, home block, admin editor select

This commit is contained in:
Alexey Pavlov
2026-05-31 14:43:28 +03:00
parent 80325b4435
commit 14053131cd
5 changed files with 148 additions and 4 deletions
+30 -3
View File
@@ -8,21 +8,22 @@ import NowBlock from '@/components/NowBlock';
import NotesBlock from '@/components/NotesBlock';
import SeriesGrid from '@/components/SeriesGrid';
import Reveal from '@/components/Reveal';
import { listArticles, listTags, getStats, getLive, listNotes, listSeries } from '@/lib/engine';
import { listArticles, listTags, getStats, getLive, listNotes, listSeries, listCategories } from '@/lib/engine';
import { Sparkles, ArrowRight } from 'lucide-react';
export const dynamic = 'force-dynamic';
export default async function HomePage() {
let articles = [], tags = [], stats = null, live = null, notes = [], series = [];
let articles = [], tags = [], stats = null, live = null, notes = [], series = [], categories = [];
try {
[articles, tags, stats, live, notes, series] = await Promise.all([
[articles, tags, stats, live, notes, series, categories] = await Promise.all([
listArticles({ limit: 13 }),
listTags(),
getStats(),
getLive(),
listNotes({ limit: 6 }),
listSeries(),
listCategories(),
]);
} catch (err) {
console.error('Home load failed:', err.message);
@@ -81,6 +82,32 @@ export default async function HomePage() {
</div>
</Reveal>
{/* Категории */}
{categories.length > 0 && (
<section className="container-wide py-10">
<h2 className="text-xs font-semibold uppercase tracking-widest mute mb-5">Темы</h2>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{categories.map(cat => {
const colorMap = {
emerald: 'bg-emerald-50 dark:bg-emerald-950 border-emerald-200 dark:border-emerald-800 text-emerald-700 dark:text-emerald-300 hover:border-emerald-400 dark:hover:border-emerald-600',
red: 'bg-red-50 dark:bg-red-950 border-red-200 dark:border-red-800 text-red-700 dark:text-red-300 hover:border-red-400',
amber: 'bg-amber-50 dark:bg-amber-950 border-amber-200 dark:border-amber-800 text-amber-700 dark:text-amber-300 hover:border-amber-400',
blue: 'bg-blue-50 dark:bg-blue-950 border-blue-200 dark:border-blue-800 text-blue-700 dark:text-blue-300 hover:border-blue-400',
};
const cls = colorMap[cat.color] || colorMap.emerald;
return (
<Link key={cat.slug} href={`/category/${cat.slug}`}
className={`flex flex-col gap-2 p-4 rounded-xl border transition-all ${cls}`}>
<span className="text-2xl">{cat.icon}</span>
<span className="font-semibold text-sm">{cat.name}</span>
<span className="text-xs opacity-70 line-clamp-2">{cat.description}</span>
</Link>
);
})}
</div>
</section>
)}
{/* Featured */}
{featured && (
<Reveal>