Сайт, App Router и Mantine
Оглавление · Далее: API
Маршруты и файлы
| URL | Файл в apps/web/src/app | Содержимое |
|---|---|---|
/ | page.tsx | Фотослайдер, последние новости, первые события, информационные блоки |
/news | news/page.tsx | Все новости |
/news/[slug] | news/[slug]/page.tsx | Полный текст новости |
/events | events/page.tsx | Все события |
/events/[slug] | events/[slug]/page.tsx | Полный текст и параметры события |
/api/trpc/* | api/trpc/[trpc]/route.ts | Типизированный API |
/api/webhooks/strapi | api/webhooks/strapi/route.ts | Приём изменения CMS |
/[slug] | [slug]/page.tsx | Информационная страница из CMS |
/api/media/[filename] | api/media/[filename]/route.ts | Ограниченный proxy фотографий |
/api/health | api/health/route.ts | Проверка ответа web |
page.tsx создаёт страницу, layout.tsx — общую оболочку, route.ts — HTTP handler.
Каталог [slug] обозначает динамический сегмент пути. В Next 16 params в этих
страницах ожидается через await; типы PageProps/LayoutProps генерирует Next.
Что выполняется на сервере и в браузере
Страницы и layout — Server Components. Они могут обращаться к серверному caller и готовить HTML без загрузки всей серверной логики в браузер.
providers.tsx, site-shell.tsx, hero-carousel.tsx, information-sections.tsx,
partner-sections.tsx, content-lists.tsx помечены
"use client". Они используют клиентские компоненты Mantine, состояние карусели,
меню и accordion. Серверная страница передаёт им сериализуемые данные.
"use client" задаёт границу клиентского модуля. Это не обещание, что компонент
никогда не участвует в первоначальном серверном рендеринге. Секреты и серверные
библиотеки не следует импортировать внутрь такой границы.
Документация Next.js о Server/Client Components.
Статическая генерация и обновление
Пошаговый учебный разбор — SSG, ISR и 404.
Главная, списки и опубликованные страницы генерируются при next build из Strapi.
Детальные маршруты используют generateStaticParams и force-static: новый slug
генерируется при первом посещении без пересборки. Для сборки нужны доступная CMS,
опубликованный Site, STRAPI_INTERNAL_URL и read-only STRAPI_READ_TOKEN.
Запросы CMS используют force-cache, тег cms и страховочный revalidate: 3600.
Webhook /api/webhooks/strapi проверяет Bearer-секрет и контракт, затем вызывает
revalidateTag("cms", { expire: 0 }) и revalidatePath("/", "layout"). Следующий
запрос обновляет страницу; повторные посещения получают статический HTML из кеша.
Сбрасывается также кеш старых адресов и 404, поэтому работают смена slug,
снятие с публикации и публикация ранее отсутствовавшей страницы. Для небольшого
сайта намеренно сбрасывается весь редакционный кеш. Hatchet в этой цепочке не участвует.
server/cms/queries.ts дополнительно использует React cache для дедупликации
одного render. API остаются динамическими; /api/content-health явно обходит кеш
и проверяет живую CMS. По умолчанию файловый кеш принадлежит одному экземпляру
Next.js; перед масштабированием понадобится общий cache handler.
Настоящее отсутствие опубликованного slug вызывает notFound(). Ошибка сети,
авторизации, pagination или контракта — CmsUnavailableError, а не ложный 404.
Неудачная сборка не выпускает пустой сайт. Error/global-error показывают отказ;
React streaming не гарантирует HTTP 503. Media proxy отдельно возвращает 404/503.
node scripts/check-static-site.mjs собирает сайт на изолированной CMS и проверяет
prerender manifest, cache HIT, обновление через webhook, новый slug, снятие публикации
и динамическую проверку состояния. Внешняя CMS и её секреты для этой проверки не нужны.
Устройство Mantine
- Layout импортирует
@mantine/core/styles.css, затем проектныйindex.css. ColorSchemeScriptиmantineHtmlPropsсинхронизируют цветовую схему.- Клиентский
Providersсоздаёт тему и оборачивает дерево вMantineProvider. - Принудительно выбрана светлая схема.
В теме заданы палитра festival, основной цвет, шрифт, радиус 5 px и defaults
для Button/Container. CSS задаёт конкретную геометрию копируемого оформления.
Это два уровня настройки: компоненты Mantine и композиция страницы.
Официальная инструкция Mantine для Next.js.
Карта компонентов
Файл в src/components | Ответственность |
|---|---|
providers.tsx | Общая тема и provider |
site-shell.tsx | Шапка, desktop/mobile-навигация, Drawer и footer |
content-layout.tsx | PageContainer, PageHeading, ContentSection и ArticleLayout |
content-lists.tsx | Независимые NewsCard/EventCard и списки, использующие эти карточки |
hero-carousel.tsx | Карусель FestivalHero, массив slides приходит через props |
award-strip.tsx | Исторические отметки, массив items приходит через props |
partner-sections.tsx | Группы партнёров, массив groups приходит через props |
information-sections.tsx | ImageTextSection, LinkCardGrid, DirectionsPanel и FaqSection |
festival-home.tsx | Серверная композиция информационных блоков главной |
blocks-content.tsx | Безопасный официальный BlocksRenderer и MediaGallery |
CSS Modules и повторное использование
Стили компонентов находятся в соседних *.module.css: Next.js создаёт уникальные
имена классов. Импортируйте объект styles и передавайте className={styles.root}.
Все размеры и responsive-правила блока держите в его модуле, включая media queries.
В index.css остаются шрифт, общие CSS variables, reset, базовая типографика,
focus-visible и prefers-reduced-motion. Глобальных классов карточек/страниц нет.
Для внутренних элементов Mantine используйте Styles API. Например, FaqSection
передаёт classNames={{ item: styles.faqItem, control: styles.faqControl, panel: styles.faqPanel }}. Не привязывайте проектный CSS к глобальным
.mantine-Accordion-* классам. Тема задаёт цвета/default props, module — геометрию.
Рекомендация Mantine.
Страница собирается из готовых блоков. Например:
<ContentSection title="Последние новости" action={{ href: "/news", label: "Все новости" }}>
<NewsList items={news.slice(0, 3)} featured />
</ContentSection>
Для отдельной карточки используйте NewsCard/EventCard. Для FAQ передавайте записи
{ id, question, content }, для карусели — { title, description, image }.
ArticleLayout объединяет ссылку назад, metadata, необязательную обложку и summary;
текст Blocks передаётся через children, параметры события — через details. Получение данных
и notFound остаются ответственностью серверной страницы.
lib/dates.ts содержит только форматирование. Клиентские карточки импортируют
его и import type для NewsItem/EventItem; типы приходят из @gheilt/contracts, данные — из серверного repository.
CSS Modules не добавляют runtime-зависимость Emotion и работают с серверными
компонентами через стандартную сборку Next.js.
Слайдер не переключается автоматически. Это упрощает чтение и поведение при уменьшении анимации. Новости сортируются по убыванию даты, события — по возрастанию; главная берёт первые три записи из каждого списка. Прошедшие события не фильтруются.
Даты, статус, навигация, логотип, слайды, отметки, страницы и FAQ приходят из CMS. Расписание образца относится к 2025 году, последние исходные новости — к 2026. Архивные даты сохраняются; отсутствующий endsAt не превращается в выдуманное окончание.
Статические ресурсы и дизайн
public/reference содержит шрифт оформления. Логотип/фотографии/партнёры приходят
из CMS и Garage; прежние статические копии удалены. В standalone-образе папку public нужно
копировать явно — соответствующий шаг есть в Dockerfile.
Источники материалов описаны в DESIGN.md.
Редакционные ресурсы загружаются в Strapi/Garage и читаются через /api/media/filename.
Старые файлы reference больше не служат источником контента. Шрифт остаётся локальным.
Приложение не запрашивает исходный сайт/API во время обычного запроса.
Текущая вёрстка переносит оформление образца, но не реализует его регистрацию, личный кабинет или весь внешний функционал. Скриншотная сверка не выполнена; отсутствие ошибок TypeScript не доказывает визуальную идентичность.
Адаптивность и доступность
Основные CSS breakpoints — 1200, 900 и 600 px. Меню меняется на Burger/Drawer,
карточки переходят в одну колонку, изображения получают ограниченную высоту.
Есть skip-link, видимый keyboard focus, подписи кнопок карусели и aria-live.
Для prefers-reduced-motion отключены анимации и плавный скролл.
Проверьте вручную: узкий экран, увеличение текста, Tab/Shift+Tab, открытие и закрытие меню, переключение карусели, переходы к записи и возврат назад. Эти проверки не автоматизированы — UI-тестов в проекте нет.
Запрет индексации
public/robots.txt:User-agent: *иDisallow: /.- Layout metadata:
index: false,follow: false. next.config.ts:X-Robots-Tag: noindex, nofollowдля всех путей.
Robots управляет поведением добросовестных роботов и не закрывает сайт от людей. Он не заменяет аутентификацию и не гарантирует удаление уже известного поисковику URL.
Где смотреть код
Layout, главная, CSS, тема, настройки Next.