Files
zeropost-web/components/RecentBlock.js
T
Nik (Claude) 334b2f51df feat: журнальная главная, страница Зеро, TG-баннер, stats, auto-publish UI
- Журнальная главная: hero, CategoryRow, PopularBlock, RecentBlock (Сегодня/Вчера/Неделя)
- ArticleCard: 3 размера (hero/regular/compact), цветной badge без дублей тегов
- ArticleCoverSVG: 6 брендовых палитр, аватар Зеро в углу вместо #ZEROPOST
- /about/zero: страница персонажа с галереей 8 поз
- Footer: TG-баннер с аватаром Зеро на каждой странице
- Конец статьи: блок «Понравилась? → Подписаться на канал»
- ChannelEditor: 4 вкладки (Настройки/Расписание/Авто-публикация/Ручная)
- AutoPublishTab: toggle, категории, delay, template, live preview
- ArticlePicker: typeahead с was_sent_to_channel / next_scheduled_at флагами
- /admin/channels/[id]/stats: график роста подписчиков (recharts)
- Dashboard: блок TG-статистики (подписчики, delta 24h/7d, постов)
- Header: упрощён до 2 пунктов desktop + расширенное мобильное меню
- AutogenPanel: корректные time-picker'ы, calcNextRun с учётом last_run_at
2026-06-07 14:04:09 +03:00

62 lines
2.3 KiB
JavaScript

import Link from 'next/link';
import ArticleCard from './ArticleCard';
import { ArrowRight } from 'lucide-react';
/**
* Группировка свежих материалов по дням: «Сегодня», «Вчера», «Эта неделя», «Ранее».
* Не рендерится, если пусто.
*/
function groupByPeriod(articles) {
const now = new Date();
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
const startOfYesterday = startOfToday - 24 * 3600 * 1000;
const startOfWeek = startOfToday - 7 * 24 * 3600 * 1000;
const groups = { today: [], yesterday: [], week: [], earlier: [] };
for (const a of articles) {
const t = new Date(a.published_at).getTime();
if (t >= startOfToday) groups.today.push(a);
else if (t >= startOfYesterday) groups.yesterday.push(a);
else if (t >= startOfWeek) groups.week.push(a);
else groups.earlier.push(a);
}
return groups;
}
const LABELS = {
today: 'Сегодня',
yesterday: 'Вчера',
week: 'На этой неделе',
earlier: 'Ранее',
};
export default function RecentBlock({ articles }) {
if (!articles || articles.length === 0) return null;
const groups = groupByPeriod(articles);
const nonEmpty = Object.entries(groups).filter(([, arr]) => arr.length > 0);
if (nonEmpty.length === 0) return null;
return (
<section className="container-wide pb-12">
<div className="flex items-end justify-between mb-5">
<h2 className="text-xl sm:text-2xl font-bold ink">Свежие материалы</h2>
<Link href="/archive" className="text-sm font-medium inline-flex items-center gap-1 accent hover:opacity-80 transition-opacity">
Архив <ArrowRight className="w-3.5 h-3.5" />
</Link>
</div>
<div className="space-y-8">
{nonEmpty.map(([key, arr]) => (
<div key={key}>
<h3 className="text-xs font-semibold uppercase tracking-widest mute mb-3">
{LABELS[key]} <span className="opacity-50">· {arr.length}</span>
</h3>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
{arr.map(a => <ArticleCard key={a.id} article={a} />)}
</div>
</div>
))}
</div>
</section>
);
}