Showing the hero matters for discoverability — visitors see who Зеро is
and the TG channel link even before the first note is published.
When there are no notes, hero spans the full width (no empty grid).
ZeroBlock переработан:
- full-width секция с amber-градиентом и border-y
- hero: квадратный аватар Зеро (kofeиная поза) 32-48px + заголовок + tagline
+ CTA-кнопки 'Все заметки' / '@zeropostru'
- notes карточки: квадратная обложка-поза (image_url из БД) с object-cover,
под ней цитата с line-clamp-6 + 'в Telegram' ссылка если опубликовано
- на главной (compact): 5/7 split — hero слева, 3 карточки справа
- на /zero: hero сверху во всю ширину, сетка из всех карточек ниже
- graceful empty state когда заметок ещё нет
/zero страница упрощена: вся структура внутри ZeroBlock (убран дублирующий
hero с био-bullets — текст консолидирован в один tagline).
New /admin/categories page:
- list with icon, name, slug, color preview, article/topic counters
- new/edit form (slug locked after creation since it's FK in articles/topics)
- 12 color palette, sort_order, archive toggle (soft delete)
- hard delete only when archived AND no articles/topics attached
AdminNav: new pin 'Категории' (FolderPlus) in 'Контент' group, before Статьи.
Dynamic categories — hardcoded CAT_LABELS removed from:
- components/admin/AutogenPanel.js — now accepts categories prop, builds
lookup map from DB, supports all 12 palette colors
- app/page.js — CATEGORY_ORDER hardcode removed; renders categories in
sort_order from DB, skips empty ones
Plumbing: app/admin/api/categories/[...path]/route.js — catch-all proxy
Top horizontal nav was getting cramped at 8 items. Sidebar:
- 240px fixed left, full-height
- 3 groups: Контент (Статьи / Черновики / Заметки / Зеро),
Публикации (Каналы / Автогенерация), Система (Настройки)
- Сайт + Выход pinned at bottom
- Mobile: hides off-screen with hamburger toggle + backdrop overlay
Layout: main now pl-60 on md+ (slides under sidebar), no padding on mobile
since sidebar overlays. Content keeps max-w-6xl + mx-auto, so visual layout
on individual pages doesn't change.
Admin (/admin/zero):
- new AdminZero with list, status filters, generate button (bucket + allow_dup)
- per-note actions: approve, edit inline, regenerate (bucket pick), skip,
'publish now' (approve + scheduled_at=now → runner picks up within 1m)
- config panel: toggle on/off, generate/approve/publish hour MSK, site URL base
- new pin 'Зеро' (☕) in AdminNav
Site (zeropost.ru):
- ZeroBlock — feed of last 3-6 Zero notes, rendered on home next to Серии
- /zero — full Zero notes list page with character bio block (avatar + bullets)
Autogen integration:
- ZeroAutogenCard on /admin/autogen — amber card with on/off, hour pickers,
'generate now' and last-3 preview, link to full section
Plumbing:
- lib/engine.js: listZeroNotes(), getZeroCharacter()
- app/admin/api/zero/[...path]/route.js: catch-all proxy with cookie auth
TOC:
- renderMarkdownWithToc: парсит h2/h3, генерит транслит-якоря для кириллицы, возвращает {html, toc}
- TableOfContents компонент: sticky на десктопе, раскрывающийся блок на мобиле
- IntersectionObserver-free подсветка активной секции через scroll listener
- Двухколоночный layout статьи на lg+: 240px TOC + контент
SVG-обложки:
- ArticleCoverSVG: процедурно сгенерированная композиция (curve/circle/arc/rect) по seed = id статьи
- 6 палитр на выбор (emerald/teal/yellow/blue/purple/orange), seed детерминированный
- Используется в ArticleCard как fallback когда cover_url пусто
- На странице статьи тоже SVG если обложки нет
- Тег статьи отображается лейблом в углу
Архив:
- /archive: все статьи сгруппированы по месяцам, компактный список
- В Header добавлен пункт Архив (desktop+mobile)
- В Footer ссылки на Архив, Заметки, О проекте
- В sitemap.xml включён /archive
- SeriesGrid: карточки серий с иконками (Sparkles/Plug/Zap/Layers) и цветовыми темами
- /series/[slug]: страница серии с интро и сеткой статей в порядке из article_ids
- Stats: count-up анимация (easeOutQuart 1.2s) при появлении в viewport через IntersectionObserver
- sitemap.xml: добавлены /notes и все серии
- NowBlock: live indicator (последняя статья / идёт генерация) + bar-чарт за 7 дней
- NotesBlock: карточки заметок редактора с pin
- /notes: отдельная страница со всеми заметками
- ArticleMeta: раскрывающийся блок «Как сделана эта статья» на странице статьи
- В шапку добавлена ссылка «Заметки» (desktop и mobile)
- HeroImage: на мобилке картинка позиционируется фоном за текстом, opacity 0.45
- Сильный mask-gradient к левому-нижнему углу, чтобы заголовок читался
- Софт-вуаль поверх фона (background var(--bg) с убывающей прозрачностью)
- Секция hero: min-h-[88vh] на мобиле, текст по центру по вертикали
- В тёмной теме мобильная opacity ещё ниже (0.32)
- Десктоп без изменений
- HeroImage компонент: WebP с 3 размерами (800/1280/1920) + <picture> srcset
- На десктопе: справа, fade с левого края, lёгкий parallax при скролле
- На мобиле: сверху, фейд к контенту, без parallax
- В тёмной теме картинка приглушается opacity 0.55 + filter
- max-width текстового блока скорректирован чтобы не наезжать на иллюстрацию
Мобилка:
- Header: hide-on-scroll, мобильный burger-menu, тонкая адаптация
- Hero: текст и кнопки оптимизированы под узкие экраны (full-width buttons)
- ArticleCard featured: на мобилке в столбик, картинка сверху
- Stats: компактная сетка 2x2 с уменьшенным шрифтом
- Глобально: scroll-behavior smooth, safe-area-inset, tap targets 40px+
- prefers-reduced-motion respected
Страница статьи:
- ReadingProgress: прогресс-бар сверху при скролле
- ScrollToTop: круглая кнопка наверху после 800px скролла
- ShareButton: Web Share API на мобилках, копирование URL на десктопе
- Related articles: подбираем по пересечению тегов (max 3)
- Мобильная типографика: prose-base sm:prose-lg, leading-relaxed
SEO/инфра:
- /api/search: простой поиск по title/excerpt/tags с подсветкой и скорингом
- SearchBox: оверлей с / хоткеем, дебаунс 250ms, мобиле-friendly
- /rss.xml: полноценный RSS-фид
- sitemap.xml: динамический через next sitemap()
- robots.txt: динамический
- viewport metadata + theme-color для светлой/тёмной темы
- alternates rel=alternate type=application/rss+xml
- Header: убрана кнопка "Кабинет" → только статьи / о проекте / переключатель темы
- Hero: вторая кнопка теперь ведёт на /about ("Как это работает"), убрано рекламное упоминание сервиса
- Страница статьи: убран CTA-блок "Открыть ZeroPost" в конце, оставлена только короткая заметка
- Footer: убрана ссылка на app.zeropost.ru
- About: переписан текст — это блог-эксперимент, не лендинг продукта
- ArticleCard: реальные обложки с fallback на детерминированный градиент по id статьи
- HeroBackground: 3 анимированных blob'а + dot-grid + плавный fade к контенту
- Stats компонент: 4 карточки — статьи / минуты чтения / токены / просмотры
- Reveal компонент: IntersectionObserver-based fade-in при скролле, respect prefers-reduced-motion
- next.config: rewrites /uploads/* → engine, чтобы картинки работали с относительными путями
- На странице статьи — обложка над контентом
- CSS-переменные --bg, --surface, --ink, --mute, --accent для обеих тем
- darkMode: 'class' в Tailwind config
- ThemeToggle компонент с Sun/Moon, сохраняет выбор в localStorage
- Inline-скрипт в layout.js защищает от FOUC (FlashOfUnstyledContent)
- Авто-определение по prefers-color-scheme как fallback
- not-found.js: красивая 404 страница вместо дефолтной Next
- Обновлены все компоненты и страницы — Header, Footer, ArticleCard, page.js, blog, tag, about