AI-генератор сайтов на ChatGPT и Next.js 15: Создаем SEO-оптимизированные страницы с нуля (аналог v0). ai.. ai. ai generator.. ai. ai generator. chatgpt.. ai. ai generator. chatgpt. github.. ai. ai generator. chatgpt. github. next.. ai. ai generator. chatgpt. github. next. Open source.. ai. ai generator. chatgpt. github. next. Open source. ReactJS.. ai. ai generator. chatgpt. github. next. Open source. ReactJS. v0.. ai. ai generator. chatgpt. github. next. Open source. ReactJS. v0. Веб-дизайн.. ai. ai generator. chatgpt. github. next. Open source. ReactJS. v0. Веб-дизайн. Веб-разработка.. ai. ai generator. chatgpt. github. next. Open source. ReactJS. v0. Веб-дизайн. Веб-разработка. искусственный интеллект.. ai. ai generator. chatgpt. github. next. Open source. ReactJS. v0. Веб-дизайн. Веб-разработка. искусственный интеллект. Фриланс.

Этот туториал — первая часть большого путешествия, в котором мы создадим AI-систему для автоматической генерации веб-страниц на React 19 и Next.js 15. Наша цель — не просто скорость, а архитектурная элегантность и идеальная консистентность дизайна.

AI-генератор сайтов
AI-генератор сайтов

План такой:

  • Часть 1 (Вы здесь): Разбираем базовую архитектуру: “жадные” маршруты, компонент-трансформер и типизированные конфиги для стандартных страниц.

  • Часть 2: Усложняем задачу: генерация страниц документации и интерактивных туториалов.

  • Часть 3: Подключаем интеллект: настраиваем AI для автономной генерации контента.

  • Бонус: Практический кейс — разворачиваем, монетизируем и масштабируем реальное приложение.

Это пошаговая инструкция по созданию собственного v0-аналога корпоративного уровня с регистрациями и оплатами. Реальный бизнес на генерации красивых приложений с революционным интерфейсом от А до Я,  в конце четвертой публикации . Чтобы собрать всю систему целиком, подписывайтесь. Дальше будет только интереснее.

Как всегда представляю исходный код готового решения чтобы вы могли сразу же приступить в созданию блогов магазинов лендингов и тп. https://github.com/aifa-agi/aifa

Технологический стек проекта: React 19, Next.js 15, Vercel, Prisma, Stripe, AI SDK, Chat GPT

Технологический стек сочетает стабильность и передовые возможности: React 19 и Next.js 15 с App Router обеспечивают молниеносный рендер и параллельные маршруты, Vercel гарантирует без-доуночные деплои, а Prisma и Neon формируют типобезопасный доступ к данным. Stripe интегрирует мгновенные платежи, AI SDK с ChatGPT добавляет интеллектуальный слой, позволяя AIFA Dev Starter генерировать интерфейсы, контент и прототипы за считанные минуты, уже включая авторизацию и многоязычный AI-чат.

На практике это сводится к простому циклу: вы отправляете промпт в ChatGPT, получаете в ответ конфигурационный файл, загружаете его в приложение и одной командой сборки создаёте готовые, стилизованные страницы. Всё это уже настроено в стартовом шаблоне, включая авторизацию и многоязычный AI-чат.

Или используйте полную автоматизацию так же как в v0, но с прицелом под крупные корпоративные интеграции. ( в обновленном https://aifa.dev после третьей публикации)

Вот пример:

aifa.dev

aifa.dev

Кому выгодна AI-система генерации сайтов: студии, корпорации, стартапы, фрилансеры

Дизайн-студии нового формата: от макета к массовому запуску сайтов за минуты

Представьте дизайн-агентство, которое создает не просто красивые макеты, а целые технологические экосистемы. Один раз вложившись в разработку уникальных компонентов и фирменного стиля, дизайнеры получают возможность генерировать профессиональные сайты со скоростью 50+ проектов в час.

Это не фантастика — это новая бизнес-модель, где креатив встречается с автоматизацией. И да, монетизация уже встроена через Stripe — об этом расскажу в следующих частях!

Корпоративные внедрения: единый стиль и масштабируемость для Enterprise-сайтов

Классический кейс — QR-меню для сети ресторанов. Один раз создав профессиональную систему карточек блюд, владелец бизнеса может предложить готовое решение сотням заведений. Рестораны адаптируют только цвета под свой бренд и наполняют контентом голосом — а профессиональный дизайн и UX остаются неизменными.

Масштабируемость, единообразие, скорость внедрения — именно то, что нужно корпоративному сегменту в 2025 году.

Transformer-архитектура компонентов: JSON → React без ручной верстки

В основе технологии AIFA Dev лежат два критически важных компонента:

1. Интеллектуальный промпт-инжиниринг
Специально обученные инструкции для ИИ, способные извлекать из векторных баз данных точные примеры секций и адаптировать их под конкретные задачи.

2. Компонентная архитектура-трансформер
React-компоненты, которые “понимают” конфигурационные файлы и превращают JSON-описания в живые, интерактивные страницы.

Внешние модели (ChatGPT, Claude) отлично справляются с генерацией контента, но компоненты-распаковщики — это сердце системы, которое мы создаем собственными силами.

AI-ready документация: как использовать текст как базу знаний для ChatGPT

Не читайте этот туториал — используйте его как AI-ассистента!

Основная ценность этого объемного материала не в последовательном чтении, а в том, что он становится персональной базой знаний для ваших проектов.

Как это работает:

  1. Скопируйте весь текст в ChatGPT

  2. Задавайте конкретные вопросы: “Как реализовать…?”, “Зачем нужно…?”, “Покажи код для…”

  3. Получайте точные ответы с готовыми компонентами

Это не документация для чтения — это интерактивный справочник для быстрого решения задач. Попробуйте такой подход, и вы поймете, почему современная техническая документация должна быть AI-ready!

1.Введение: цель, выгоды и место метода среди генераторов v0-поколения

Данный туториал не ставит своей задачей создание решения, превосходящего v0 по скорости генерации. Основная цель — обеспечение единообразия и гармоничности дизайна на всех страницах проекта.

Да, создание каждой отдельной страницы может потребовать несколько больше времени по сравнению с универсальными генераторами. Однако совокупные затраты на проект значительно снижаются благодаря следующим преимуществам:

  • Единый стиль всех компонентов — каждая новая страница автоматически вписывается в общую дизайн-систему

  • Гармоничность всего проекта — отсутствие стилистических разрывов между разными разделами сайта

  • Снижение затрат на доработку — минимальная необходимость в последующей стилизации и адаптации

  • Масштабируемость решения — чем больше страниц, тем выше эффективность подхода

Результат: проект получается визуально целостным, профессиональным и требует минимальных усилий на поддержание единообразия интерфейса при масштабировании.

В основном туториале рассматривается создание стандартных страниц с использованием базовых компонентов header и footer.

Однако в исходном коде проекта вы найдете кастомные реализации для специализированных типов страниц:

  • Страницы документации с расширенной навигацией

  • Страницы Tutorial с интерактивными элементами

Работа со сложными компонентами:

Обратите внимание, что некоторые компоненты на главной странице обладают более сложной логикой:

  • Управление состоянием (state management)

  • Анимации и переходы

  • Интерактивные элементы

Интеграция продвинутых решений:

Для интеграции таких сложных компонентов предусмотрена возможность добавления Custom-компонентов вместо стандартных секций. Это позволяет:

  • Сохранить гибкость системы

  • Внедрить уникальную функциональность

  • Поддержать единый стиль даже для нестандартных решений

Практическое задание:

Изучение процесса создания и интеграции Custom-компонентов остается вашим практическим заданием для закрепления полученных знаний.

1.1.Концепция: единообразные страницы бренда, создаваемые ИИ по шаблонам

Современный процесс разработки требует скорости, однородности интерфейса и возможности быстрого реагирования на бизнес-требования. Мы предлагаем архитектуру, в которой стандартные, формализованные описания дизайн-секций (Hero, CTA, FAQ, Features и др.) хранятся в структурированной базе знаний ИИ.
Загружая туда ваши актуальные стандарты UI/UX для каждой секции, вы позволяете искусственному интеллекту выступать не только генератором контента, но и гарантом единого фирменного стиля на всех уровнях создания страниц.

1.2. Пять этапов: от загрузки дизайн-шаблонов до SEO-оптимизированного билда

  1. Загрузка стандартов дизайна:
    В базу знаний ИИ добавляются шаблоны и инструкции для каждой секции — как их визуально и структурно реализовывать в рамках единого стиля вашего бренда.

  2. Обработка текстового запроса:
    Пользователь, менеджер проекта или программист формирует задание в виде текстового промпта — описывает желаемую страницу или её элементы.

  3. AI-интерпретация и структурирование:
    Искусственный интеллект анализирует запрос, генерирует семантический контент, разбивает его на логические секции и подбирает подходящие шаблоны из базы знаний.

  4. Генерация кода страниц:
    На основании выбранных шаблонов и сгенерированного контента система формирует строгие PageConfig’и — декларативные JSON/Type-описания будущих страниц. Они гарантируют соблюдение всех дизайн-стандартов и упрощают downstream-разработку.

  5. Автоматическая сборка и билдинг:
    Готовые конфигурации применяются для статической генерации страниц с использованием рендер-компонентов, в результате чего вы получаете полноценную, SEO-оптимизированную страницу, визуально и технически выдержанную по вашим корпоративным стандартам.

1.3. Экономия ресурсов и рост конверсий: бизнес-преимущества AI-генерации

  • Быстрота вывода новых landing pages и product pages — достаточно промпта, чтобы ИИ сгенерировал страницу на основе актуальных шаблонов.

  • Единый фирменный стиль и качество — извлекается и соблюдается автоматически для каждой новой страницы.

  • Минимизация ручной работы и A/B тестирование — масштабирование вариантов страниц и изменение контента силами AI без участия разработчика в вёрстке.

  • Готовность к многоязычности — все тексты и элементы хранятся централизованно, легко поддаются локализации и адаптации.

  • Инфраструктурная гибкость — легко интегрируется в CI/CD пайплайны, современные хостинги и AI-driven процессы.

1.4. Как продолжить: дорожная карта из трёх статей и бонус-кейса

h4В данном туториале мы пошагово рассмотрим:

  • Архитектура существующих компонентов — детальный разбор структуры PageHtmlTransformer, системы обёрток (Wrapper/FullScreenWrapper), компонентов секций и их взаимодействия для понимания внутренних механизмов работы.

  • Принципы работы системы — изучение логики рендеринга секций, типизации конфигураций, механизмов роутинга и связи между конфигурационными файлами и React-компонентами. Это необходимо для того, чтобы разработчики могли самостоятельно расширять данные представления.

  • Создание инструкций для искусственного интеллекта — формирование структурированного описания существующих доступных типов для метаданных, header section, footer section. Добавление требований к созданию JSX fragment для body section с детальными спецификациями и ограничениями.

  • Генерация конфигурационных файлов — практическое применение полученных знаний для создания config-файлов, которые будут использоваться AI для автоматической генерации страниц с соблюдением всех архитектурных принципов и стандартов дизайна.

2. Структура проекта: папки, файлы и логика маршрутизации Next.js 15

Tree

app/@right/
├── public/
│   ├── (_routing)/
│   │   └── [[...slug]]/
│   │       └── page.tsx                    # 1. Динамический роутинг
│   └── (_service)/
│       ├── (_config)/
│       │   └── public-pages-config.ts   # 6. Конфигурация публичных страниц
│       └── (_libs)/
│           └── utils.ts                      # 7. Утилиты
└── (_service)/
    ├── (_types)
    │   ├── /page-transformer-custom-types/
    │   └── page-wrapper-types.ts                    # 5. Типы и интерфейсы
    └── (_components)/
        └── page-transformer-components/
            ├── page-html-transformer.tsx       # 2. Главный трансформер
├──  custom-sections/
            ├── wrappers/
            │   ├── full-screen-wrapper.tsx      # 3. Полноэкранная обёртка
            │   └── wrapper.tsx                   # 4. Стандартная обёртка
            ├── header-sections-components/
            │   ├── header-section.tsx             # 8. Компонент заголовка
            │   ├── page-header-elements.tsx        # 9. Элементы заголовка
            │   └── announcement.tsx                # 10. Компонент анонса
├── body-sections-components/
            │   └── body-section.tsx                  # 12. Компонент Body
            └── footer-sections-components/
                └── footer-section.tsx               # 11. Компонент футера

Components:

1-@/app/@right/public/(_routing)/[[…slug]]/page.tsx
2-@/app/@right/(_service)/(_components)/page-transformer-components/page-html-transformer.tsx
3-@/app/@right/(_service)/(_components)/page-transformer-components/wrappers/full-screen-wrapper.tsx
4-app/@right/(_service)/(_components)/page-transformer-components/wrappers/wrapper.tsx
5-app/@right/(_service)/(_types)/page-wrapper-types.ts
6-// @/app/@right/public/(_servise)/(_config)/public-pages-config.ts
7-//@app/@right/public/(_servise)/(_libs)/utils.ts
8-@/app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/header-section.tsx
9-@app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/page-header-elements.tsx
10-@app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/announcement.tsx
11-@app/@right/(_service)/(_components)/page-transformer-components/footer-sections-components/footer-section.tsx
12-@app/@right/(_service)/(_components)/page-transformer-components/body-sections-components/body-section.tsx

2.1. Базовый набор компонентов: рендер шаблонных страниц «из коробки»

Назначение

Стандартные компоненты представляют собой базовый набор элементов для создания типизированных страниц в едином стиле. Эта коллекция включает в себя системообразующие элементы архитектуры: динамический роутинг, центральный трансформер, обёртки для разных типов контента, унифицированные секции заголовков и футеров, а также конфигурационные файлы и типизацию.

Ключевые принципы стандартных компонентов:

  • Единообразие интерфейса — все компоненты следуют общим принципам дизайна и поведения

  • AI-совместимость — структура оптимизирована для автоматической генерации контента

  • SEO-оптимизация — встроенная поддержка поисковой оптимизации и правильной HTML-семантики

  • Типизированная архитектура — строгая типизация через TypeScript для предсказуемого поведения

  • Модульность — каждый компонент решает конкретную задачу и может использоваться независимо

Эти компоненты формируют основу системы, которая гарантирует визуальную консистентность и техническое единообразие всех AI-генерируемых страниц.

2.1.1. Компонент [[…slug]]/page.tsx: универсальный catch-all route для динамических URL

2.1.1.1. Почему Next.js использует catch-all routes: гибкость, скорость деплоя

Жадный маршрут (catch-all route) — это тип динамического роута в Next.js, который позволяет обрабатывать неограниченное количество вложенных сегментов URL с помощью одной единственной страницы-компонента. В конструкции […slug] или [[…slug]] (опциональный) массив slug в параметрах будет содержать все части пути, независимо от их количества.

Почему это круто:

  • Произвольное количество уровней вложенности.
    Вам не нужно создавать отдельные папки и файлы в структуре проекта под каждый новый путь. Например, путь /public/category/nike/sneakers/black/12345 обработается ровно тем же компонентом, что и /public/test.

  • Гибкая навигация и быстрый запуск новых страниц.
    Достаточно добавить соответствующий конфиг — и страница мгновенно появляется в приложении, без необходимости заводить новые компоненты или поддерживать сложную файловую структуру.

  • Автоматизация:
    Такое построение идеально сочетается с auto-generated sidebar/menu: создаём нужный пункт в навигации и “умный” роутинг автоматом отрабатывает отображение нужной страницы.

2.1.1.2. Значение динамических URL для AI-ассистентов: бесконечное расширение контента

В современных SaaS/AI-продуктах или headless сайтах зачастую требуется быстро создавать новые страницы “на лету” по запросу юзера или администратора — страница конструируется и конфигурируется не руками, а через генерацию (AI или админ-панель).
Архитектура с жадным роутом:

  • Снимает ограничения структуры и глубины вложенности страниц,

  • Позволяет работать с любым количеством уровней иерархии (например, меню ресторанов с многоуровневой категоризацией; карточки товаров по структуре каталог/категория/производитель/линейка/артикул),

  • Обеспечивает свободу для пользователей и разработчиков — навигация строится только по логике проекта, а не привязана к файловой структуре.

2.1.1.3. Примеры использования:

  • QR-меню для ресторана:
    /public/menu/bar/beer и /public/menu/hot-dishes/italian/pasta → любые глубины подкатегорий.

  • Интернет-магазин:
    /public/shop/clothes/mens/jackets/leather/2023/black/style123

  • Образовательный портал:
    /public/tutorials/python/basics/loops/while-loop/example1

2.1.1.4. Как работает компонент page.tsx

Основные задачи:

  • Приходит массив slug из URL (например, [“category”, “nike”, “sneakers”]).

  • Функция generateStaticParams собирает все маршруты, которые присутствуют в вашем конфиге (pages-config.ts), и передаёт Next.js их для статической генерации.

  • Функция getPageBySlug быстро находит в массиве конфигов нужную страницу ровно по тому slug, который пришёл (обычно с добавлением “public” в начало).

export async function generateStaticParams() {

  const pages: PageConfig[] = getAllPublicPages();

  return pages.map((page: PageConfig) => ({

    slug: page.metadata.slug ? page.metadata.slug.slice(1) : [],

  }));

}
  • Здесь мы формируем все возможные пути для статической генерации: если в конфиге есть [“public”,”cat”,”subcat”,”product”], то будет сгенерирован путь /public/cat/subcat/product.

Далее, когда происходит рендеринг:

export default async function PublicDynamicSlugPage({ params }: Props) {

  const resolvedParams = await params;

  const slugArr = resolvedParams.slug ?? [];

  const pageConfig = getPageBySlug(["public", ...slugArr]);

  if (!pageConfig) {

    return <div>Page not found</div>;

  }

  return <PageHtmlTransformer data={pageConfig} />;

}
  • slugArr может быть любой длины!

  • “public” добавляется для корректного поиска в массиве.

  • Функция поиска работает по полному совпадению slug, что исключает коллизии.

h5 2.1.1.5. Кратко о ключевых функциях:

  • generateStaticParams — сообщает Next.js ВСЕ существующие вложенные пути для генерации.

  • getPageBySlug — ищет нужную страницу в массиве по полному match slug-массива.

  • PageHtmlTransformer — универсальный отрисовщик, которому неважно, какой глубины вложенности страница: он строит компонент на лету из твоего формализованного конфига.

2.1.1.6. Заключение. Почему выбран именно такой подход

  • Гибкость для новых разделов: не надо думать о папках — просто добавь конфиг, и страница появится!

  • Удобство редактирования и масштабирования навигации: весь роутинг и навигация управляются на уровне данных (массивы slugs), а не файлов.

  • Сценарии реального бизнеса: автоматизация генерации меню, товаров, курсов, документации, блогов и всего, что только может прийти в голову.

  • Унификация для AI-ассистентов: такой подход идеально сочетается с автоматической генерацией контента по текстовому описанию (prompt) — любые новые страницы появляются мгновенно и не ограничены глубиной маршрута.

2.1.1.7. Компонент

// @/app/@right/public/(_routing)/[[...slug]]/page.tsx


import { PageHtmlTransformer } from "@/app/@right/(_service)/(_components)/page-transformer-components/page-html-transformer";

import { getPageBySlug } from "@/app/@right/(_service)/(_config)/pages-config";

import { constructMetadata } from "@/lib/construct-metadata";

import type { PageConfig } from "@/app/@right/(_service)/(_types)/page-wrapper-types";

import { getAllPublicPages } from "../../(_servise)/(_libs)/get-all-public-pages";




interface Props {

  params: Promise<{ slug?: string[] }>;

}




export async function generateStaticParams() {

  const pages: PageConfig[] = getAllPublicPages();




  return pages.map((page: PageConfig) => ({

    slug: page.metadata.slug || [],

  }));

}


export async function generateMetadata({ params }: Props) {

  const resolvedParams = await params;

  const slugArr = resolvedParams.slug ?? [];

  const pageConfig = getPageBySlug(["public", ...slugArr]);




  if (!pageConfig) return {};

  return constructMetadata(pageConfig.metadata);

}




export default async function PublicDynamicSlugPage({ params }: Props) {

  const resolvedParams = await params;

  const slugArr = resolvedParams.slug ?? [];

  const publicPageConfig = getPageBySlug(["public", ...slugArr]);




  if (!publicPageConfig) {

    return <div>Page not found</div>;

  }




  return <PageHtmlTransformer data={publicPageConfig} />;

}

2.1.1.7. TL;DR по catch-all: когда и как использовать в AI-проекте

Жадные маршруты и централизованный конфиг страниц делают архитектуру твоего приложения максимально гибкой, расширяемой и дружественной как для разработчиков, так и для AI-оркестрации контента. Новая страница = новая строка в конфиге, никаких новых файлов или папок — навигация и рендер подстраиваются автоматически!

2.1.2. Реальные кейсы catch-all route: магазин, меню ресторана, образовательный портал

2.1.2.1. Архитектурная роль и назначение компонента

PageHtmlTransformer является ядром всей системы рендеринга — это универсальный “дирижёр”, который получает декларативное описание страницы (PageConfig) и превращает его в живые React-компоненты. Его главная задача — обеспечить единообразие визуального представления при максимальной гибкости содержимого.

h6 Ключевые функции:

  • Централизованная логика рендеринга — один компонент управляет всем процессом отображения секций

  • Типизированная обработка — каждый тип секции получает соответствующую обёртку и рендеринг

  • Управление темами и адаптивностью — центральная точка для проброса контекстных данных

  • Унификация стилей — гарантирует единообразие header/footer секций across всех страниц

2.1.2.2. Принципиальное решение: почему header и footer вынесены отдельно

Решение вынести HeaderSection и FooterSection за рамки дефолтной логики BodySection продиктовано фундаментальными требованиями к единообразию дизайна:

h6 Проблема с AI-генераторами контента:

  • Автоматизированные ИИ-генераторы часто создают непоследовательный контент в части оформления заголовков и заключений

  • Каждая секция может иметь уникальное body-содержание, но начало и конец должны следовать строгим стандартам бренда

  • Header и Footer — это “якоря стиля”, которые задают тон всей секции и обеспечивают визуальную связность

Архитектурные преимущества:

  • Гарантированное единообразие — независимо от того, как AI сгенерирует body-контент, header и footer всегда будут выдержаны в корпоративном стиле

  • Централизованный контроль — изменения в стилях заголовков применяются мгновенно ко всем страницам

  • Предсказуемая структура — разработчики и дизайнеры могут рассчитывать на стабильные паттерны

2.1.2.3. Управление темами и контекстом

export function PageHtmlTransformer({ data }: PageHtmlTransformerProps) {

  const { theme } = useTheme();

  // ... rest of logic

}

Зачем пробрасывать тему именно отсюда:

Сценарии, требующие theme-aware логики:

  • Условные изображения: В светлой теме используется одна картинка, в темной — другая

  • Динамические стили: Компоненты с особой логикой цветовых схем

  • Анимации и переходы: Разные эффекты для light/dark режимов

Аналогично с мобильной версией (isMobile):

  • Условный рендеринг: Некоторые компоненты полностью отключаются на мобильных

  • Кардинально разная вёрстка: Когда Tailwind CSS недостаточно гибкий

  • Производительность: Отказ от тяжёлых элементов на слабых устройствах

Пример использования:

// В дочернем компоненте

{theme === 'dark' ? <DarkModeImage /> : <LightModeImage />}

{!isMobile && <DesktopOnlyFeature />}

2.1.2.4. Два типа Wrapper: зачем нужна дифференциация

FullScreenWrapper vs Wrapper — принципиальные различия:

FullScreenWrapper (для hero-section и подобных):

  • Полноэкранная компоновка — занимает всю высоту viewport

  • Поддержка фоновых медиа — video/image backgrounds с наложением контента

  • Z-index управление — сложная слоистая структура для overlay-эффектов

  • Позиционирование — absolute/relative позиционирование для центрирования контента

Wrapper (стандартный):

  • Секционная вёрстка — обычные блоки с padding/margin

  • Container-based — стандартная сетка и отступы

  • Простота и производительность — минимальные CSS-свойства

Почему нельзя объединить в один компонент:

  • Конфликты CSS — fullscreen и container логики несовместимы

  • Производительность — лишние стили влияют на рендеринг

  • Семантическая ясность — разные задачи требуют разных подходов

  • Maintenance — проще поддерживать два специализированных компонента

2.1.2.5. Ограничения renderSectionContent и кастомные случаи

Проблемы со стандартной функцией renderSectionContent:

function renderSectionContent(config: any) {

  return (

    <>

      {config.headerContent && <HeaderSection headerContent={config.headerContent} />}

      {config.bodyContent && <BodySection type={config.type}>{config.bodyContent.content}</BodySection>}

      {config.footerContent && <FooterSection actions={config.footerContent.actions} />}

    </>

  );

}

Ограничения этого подхода:

  • Отсутствие state management — нет возможности использовать useState, useEffect

  • Статичность данных — контент передается как готовые данные, без интерактивности

  • Отсутствие event handling — невозможно обрабатывать пользовательские события

  • Нет lifecycle методов — компоненты не могут реагировать на mount/unmount

Когда нужны кастомные случаи:

  • Интерактивные формы — компоненты с валидацией и отправкой данных

  • Анимированные секции — сложные transitions и animations

  • Real-time данные — компоненты с подпиской на WebSocket или API

  • Условная логика — сложные вычисления на основе пользовательского ввода

Решение через кастомные кейсы:

switch (section.type) {

  case "interactive-form-section": {

    return <CustomInteractiveForm key={config.id} {...config} />;

  }

  case "real-time-dashboard": {

    return <CustomDashboard key={config.id} {...config} theme={theme} />;

  }

  // стандартные случаи...

  default: {

    return (

      <Wrapper key={config.id}>

        {renderSectionContent(config)}

      </Wrapper>

    );

  }

}

 2.1.2.6. Анализ архитектурной роли и рабочего процесса

PageHtmlTransformer выполняет несколько ключевых архитектурных ролей:

  1. Фасад паттерн — предоставляет простой интерфейс для сложной системы рендеринга

  2. Factory паттерн — создает нужные компоненты на основе типа секции

  3. Strategy паттерн — выбирает стратегию рендеринга (Wrapper/FullScreenWrapper) в зависимости от контекста

  4. Template Method паттерн — определяет скелет алгоритма рендеринга с возможностью переопределения отдельных шагов

Рабочий процесс:

  1. Получение конфигурации — принимает PageConfig с массивом секций

  2. Инициализация контекста — получает theme, определяет isMobile

  3. Итерация по секциям — для каждой секции определяет тип и способ рендеринга

  4. Выбор обёртки — FullScreenWrapper для hero-секций, Wrapper для остальных

  5. Рендеринг контента — применяет renderSectionContent или кастомный компонент

  6. Сборка финальной страницы — объединяет все секции в единую структуру

2.1.2.7. Компонент

// @/app/@right/(_service)/(_components)/page-transformer-components/page-html-transformer.tsx

"use client";

import {

  PageConfig,

  Section,

  SectionConfig,

} from "../../(_types)/page-wrapper-types";

import { BodySection } from "./body-sections-components/body-section";

import { FooterSection } from "./footer-sections-components/footer-section";

import { HeaderSection } from "./header-sections-components/header-section";

import { useTheme } from "next-themes";

import { FullScreenWrapper } from "./wrappers/full-screen-wrapper";

import { Wrapper } from "./wrappers/wrapper";


interface PageHtmlTransformerProps {

  data: PageConfig;

}




function renderSectionContent(config: any) {

  return (

    <>

      {config.headerContent && (

        <HeaderSection headerContent={config.headerContent} />

      )}

      {config.bodyContent && (

        <BodySection type={config.type}>

          {config.bodyContent.content}

        </BodySection>

      )}

      {config.footerContent && (

        <FooterSection actions={config.footerContent.actions} />

      )}

    </>

  );

}




export function PageHtmlTransformer({ data }: PageHtmlTransformerProps) {

  const { theme } = useTheme();

  if (!data?.sections?.length) return null;




  return (

    <>

      {data.sections.map((section: Section, idx: number) => {

        switch (section.type) {

          case "hero-section": {

            const config = section as SectionConfig;

            return (

              <FullScreenWrapper

                key={config.id || idx}

                videoUrl={config.videoUrl}

                imageUrl={config.imageUrl}

                className={config.sectionClassName}

              >

                {renderSectionContent(config)}

              </FullScreenWrapper>

            );

          }

          // ...другие case без изменений

          default: {

            const config = section as any;

            return (

              <Wrapper

                key={config.id || idx}

                className={config.sectionClassName}

              >

                {renderSectionContent(config)}

              </Wrapper>

            );

          }

        }

      })}

    </>

  );

}

2.1.2.7.Заключение

PageHtmlTransformer — это сердце системы, которое превращает декларативные описания в живые, интерактивные и стилистически единообразные веб-страницы. Его архитектура балансирует между гибкостью (поддержка кастомных компонентов) и последовательностью (стандартизированные header/footer), что делает его идеальным инструментом для AI-управляемой генерации контента.

2.1.3. FullScreenWrapper vs Wrapper: когда использовать полноэкранную оболочку

2.1.3.1. Основное назначение

FullScreenWrapper предназначен для секций, требующих полноэкранного отображения с поддержкой видео/изображений на фоне. Это базовый контейнер для hero-секций, где контент накладывается поверх медиа-элементов.

2.1.3.2. Слоистая структура

<section className="relative flex min-h-screen flex-col py-10 lg:py-14 bg-background">

  {backgroundElement}  // z-0

  <div className="relative z-10 flex flex-col flex-1">

    {children}         // Header → Body → Footer

  </div>

</section>

Технические особенности:

  • min-h-screen — гарантирует заполнение всего viewport

  • relative позиционирование для z-index управления

  • Background элементы (видео/изображение) с absolute и z-0

  • Контент с relative z-10 всегда поверх фона

2.1.3.3. Кастомизация и расширения

Место для градиентов и анимаций: Добавляйте эффекты через className prop:

<FullScreenWrapper className="bg-gradient-to-br from-blue-900 to-purple-900">

Контроль прозрачности фона: Видео автоматически получает opacity-40 для читаемости текста, но это легко переопределить.

Анимации переходов: transition-all duration-500 уже встроен для плавных изменений фона.

2.1.3.4. Применение для кастомных шаблонов

Если нужны разделители между секциями, бордюры, подсветка или управление размытием — FullScreenWrapper идеальное место для реализации:

// Пример с бордюром и градиентом

<FullScreenWrapper className="border-t-4 border-gradient bg-blur-effect">

2.1.3.5.  Компонент

// @/app/@right/(_service)/(_components)/page-transformer-components/wrappers/full-screen-wrapper.tsx




import React, { HTMLAttributes } from "react";

import { cn } from "@/lib/utils";




interface FullScreenWrapperProps extends HTMLAttributes<HTMLDivElement> {

  videoUrl?: string;

  imageUrl?: string;

  className?: string;

  children: React.ReactNode;

}




export function FullScreenWrapper({

  videoUrl,

  imageUrl,

  className,

  children,

  ...props

}: FullScreenWrapperProps) {

  let backgroundElement: React.ReactNode = null;




  if (videoUrl) {

    backgroundElement = (

      <video

        className="absolute inset-0 size-full object-cover z-0 opacity-40 transition-all duration-500"

        autoPlay

        loop

        muted

        playsInline

        src={videoUrl}

      />

    );

  } else if (imageUrl) {

    backgroundElement = (

      <img

        className="absolute inset-0 size-full object-cover z-0"

        src={imageUrl || "/placeholder.svg"}

        alt="Background"

      />

    );

  }




  return (

    <section

      className={cn(

        "relative flex min-h-screen flex-col py-10 lg:py-14 bg-background",

        className

      )}

      {...props}

    >

      {backgroundElement}

      <div className="relative z-10 flex flex-col flex-1">{children}</div>

    </section>

  );

}

2.1.4. Wrapper: базовая секционная оболочка с container mx-auto

2.1.4.1.  Назначение

Wrapper — базовая обёртка для большинства контентных секций. Обеспечивает стандартные отступы, центрирование контента и контейнеризацию.

2.1.4.2. Структура

<section className="py-10 lg:py-14 bg-background">

  <div className="container mx-auto px-4">

    {children}  // Header → Body → Footer

  </div>

</section>

Ключевые параметры:

  • py-10 lg:py-14 — адаптивные вертикальные отступы

  • container mx-auto px-4 — центрированный контент с горизонтальными отступами

  • bg-background — использует CSS-переменную темы

2.1.4.3. Точки кастомизации

Фоновые эффекты:
Легко добавлять через className:

<Wrapper className="bg-gradient-to-r from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">

Разделители между секциями:

<Wrapper className="border-t border-border/50">

Анимации появления:


<Wrapper className="animate-fade-in transition-all duration-700">

Управление размытием и подсветкой:

<Wrapper className="backdrop-blur-sm shadow-inner">

2.1.4.4. Средне-кастомные переиспользуемые шаблоны

Когда нужен шаблон с уникальной стилизацией, но стандартной структурой — Wrapper ваш выбор:

// Пример для pricing-секций

<Wrapper className="bg-gradient-to-br from-green-50 to-green-100 border-2 border-green-200">

  <HeaderSection />

  <PricingTable />

  <FooterSection />

</Wrapper>

2.1.3.5.  Компонент

// app/@right/(_service)/(_components)/page-transformer-components/wrappers/wrapper.tsx




import React, { HTMLAttributes } from "react";

import { cn } from "@/lib/utils";




interface WrapperProps extends HTMLAttributes<HTMLDivElement> {

  className?: string;

  children: React.ReactNode;

}




export function Wrapper({ className, children, ...props }: WrapperProps) {

  return (

    <section

      className={cn("py-10 lg:py-14 bg-background", className)}

      {...props}

    >

      <div className="container mx-auto px-4">{children}</div>

    </section>

  );

}

Зачем два отдельных wrapper’а?

Технические причины:

  • FullScreenWrapper содержит сложную логику медиа-фонов и z-index управления

  • Wrapper оптимизирован для производительности — минимум CSS-правил

  • Разные подходы к позиционированию: relative vs static

  • Несовместимые CSS-свойства: min-h-screen vs py-*

Практические выгоды:

  • Четкое разделение ответственности

  • Легкость кастомизации под конкретные задачи

  • Предсказуемое поведение для AI-генерации

  • Отсутствие CSS-конфликтов между типами секций

Для AI-систем: Простое правило выбора — immersive контент (hero, showcases) = FullScreenWrapper, информационный контент = Wrapper.

2.1.5. page-wrapper-types.ts: TypeScript-контракт между ИИ и UI

2.1.5.1. Роль типизации: контракт между AI и рендером.

Файл page-wrapper-types.ts — это формальный контракт между AI-генератором и системой рендеринга. Здесь определяется архитектура всех возможных компонентов страницы и правила их взаимодействия.

 2.1.5.2. Категории SectionType и AI-генерация. 

Принцип работы AI: Искусственный интеллект сначала анализирует доступные типы секций из enum SectionType, затем принимает решение о том, какие из них добавить к конкретной странице на основе пользовательского запроса.

Ожидается, что для каждого из 25+ типов секций в базе знаний AI будут загружены исчерпывающие инструкции и примеры, достаточные для автономной генерации контента.

export type SectionType =

  | "hero-section" | "cta-section" | "faq-section"

  | "features-section" | "testimonials-section" | "pricing-section"

  // ... и другие типы

2.1.5.3. SEO-оптимизация и метаданные. 

PageMetadata обеспечивает корректное формирование мета-тегов для поисковых систем:

export interface PageMetadata {

  id: string;           // Уникальный идентификатор

  title: string;        // <title> тег для SEO

  description: string;  // <meta description> для сниппетов

  image?: string;       // Open Graph изображение

  slug?: string[];      // URL-структура страницы

  type: SectionType;    // Тип основной секции

}

Автоматическая генерация мета-тегов происходит в generateMetadata() функции, которая извлекает данные из конфига и передает их в constructMetadata() для формирования корректных HTML-заголовков.

2.1.5.4. HeaderContentConfig: контроль SEO-иерархии. 

Критически важно для SEO:

interface HeaderContentConfig {

  heading: string;

  headingLevel?: 1 | 2;  // H1/H2 для поисковой иерархии

  description?: string;

  showBorder?: boolean;

}

Осторожно с заголовками: Header-секция опциональна, поскольку в некоторых типах секций заголовки H1/H2 могут размещаться внутри bodyContent. Это потенциально опасно для единообразия интерфейса — основной цели данного туториала.

2.1.5.5. BodySection: максимальная свобода дизайна. 

bodyContent?: React.ReactNode;

Архитектурное решение: Тело секции получает полную свободу для реализации любого дизайна, в то время как Header и Footer жестко стандартизированы для поддержания единого стиля.

interface FooterContentConfig {

  actions?: {

    label: string;

    href: string;

    variant?: "default" | "secondary" | "outline" | "ghost" | "link";

  }[];

}

2.1.5.6. FooterContentConfig: минимализм по дизайну. 

Текущая реализация предполагает только опциональные кнопки действий. Никаких дополнительных элементов — максимальная простота и единообразие.

2.1.5.7. Принципы расширения типизации. 

Для добавления новых SectionType:

  1. AI получает новые инструкции в базу знаний

  2. Добавляется тип в enum SectionType

  3. При необходимости расширяется интерфейс конфигурации

Баланс стандартизации: Header и Footer строго типизированы для SEO и единообразия, Body получает максимальную гибкость для творческих решений AI-генераторов

2.1.5.8.  Компонент


2.1.5.9. customComponentsAnyTypeData: поддержка произвольных кастомных компонентов

Поле customComponentsAnyTypeData?: any; в SectionConfig предназначено для передачи данных в секции, реализованные через сложные или уникальные кастомные компоненты, не вписывающиеся в стандартные интерфейсы.
Тип и структура этих данных должны быть подробно и строго описаны внутри самого кастомного компонента. Это решение обеспечивает гибкость для интеграции интерактивных, динамических и продвинутых пользовательских секций без нарушения общего контракта типизации основной архитектуры страниц.

// app/@right/(_service)/(_types)/page-wrapper-types.ts


export interface MetadataConfig {

  title?: string;

  description?: string;

}




export interface PageMetadata {

  id: string;

  title: string;

  description: string;

  image?: string;

  slug?: string[];

  type: SectionType;

}




export type SectionType =

  | "hero-section"

  | "cta-section"

  | "faq-section"

  | "features-section"

  | "testimonials-section"

  | "pricing-section"

  | "contact-section"

  | "blog-posts-section"

  | "product-grid-section"

  | "image-gallery-section"

  | "text-block-section"

  | "video-section"

  | "team-section"

  | "about-us-section"

  | "newsletter-section"

  | "social-proof-section"

  | "comparison-table-section"

  | "map-section"

  | "custom-html-section"

  | "changelog-section"

  | "comparison-two-column-section"

  | "comparison-three-column-section"

  | "feature-showcase-section";




export interface BaseSection {

  id: string;

  type: SectionType;

  className?: string;

}




export interface HeaderContentConfig {

  announcement?: {

    badgeText?: string;

    descriptionText?: string;

    href?: string;

  };

  heading: string;

  headingLevel?: 1 | 2;

  description?: string;

  showBorder?: boolean;

}




export interface FooterContentConfig {

  actions?: {

    label: string;

    href: string;

    variant?:

      | "default"

      | "secondary"

      | "destructive"

      | "outline"

      | "ghost"

      | "link";

  }[];

}

export interface SectionConfig extends BaseSection {

  type: SectionType;

  headerContent: HeaderContentConfig;

  bodyContent?: React.ReactNode;

  footerContent?: FooterContentConfig;

  videoUrl?: string;

  imageUrl?: string;

  sectionClassName?: string;

  contentWrapperClassName?: string;
  customComponentsAnyTypeData?: any;

}




export type Section = SectionConfig;




export interface PageConfig {

  metadata: PageMetadata;

  sections: Section[];

}




export type SlugType = string[];

2.1.6. public-pages-config.ts: реестр публичных страниц и Slug-маршрутов

2.1.6.1. Роль конфига в архитектуре системы

Файл public-pages-config.ts является результатом работы искусственного интеллекта — автоматически генерируемым реестром всех публичных страниц приложения. Этот конфиг создается ИИ в автоматическом режиме на основе системных инструкций и пользовательского запроса, напрямую зависит от доступных компонентов в примерах базы знаний и перечислений в типизации SectionType, которые мы рассматривали выше. Сгенерированная структура служит мостом между AI-анализом требований пользователя и системой рендеринга страниц.

2.1.6.2. Когда использовать файловый конфиг

Оптимальные сценарии для конфиг-файла:

  • Проекты с не более 10-15 страниц

  • Статичный контент, который редко изменяется

  • Прототипирование и MVP — быстрый старт без базы данных

  • Landing pages с фиксированной структурой

Когда переходить на базу данных:
В production-версии на крупном проекте файловый подход имеет смысл только при небольшом количестве страниц. Большинство случаев требуют хранения этой информации в базе данных для динамического управления контентом.

2.1.6.3. Структура конфига

export const PublicPagesConfig = {

  pages: [

    {

      metadata: {

        id: "public",

        title: "Enterprise-Grade AI Next.js starter",

        description: "Free Open-Source starter kit...",

        slug: ["public", "test"],

        type: "hero-section",

      },

      sections: [

        {

          id: "test-block",

          type: "hero-section",

          headerContent: { /* SEO-заголовки */ },

          bodyContent: {},

          footerContent: { /* Кнопки действий */ },

          videoUrl: "/_static/video/ai-loop.mp4",

          contentWrapperClassName: "text-white",

        } as SectionConfig,

      ],

    },

  ] as PageConfig[],

};

2.1.6.4. Принцип категоризации конфигов

Важное архитектурное решение: Размещение конфига в директории public/(_service)/(_config)/ указывает на его принадлежность к публичным страницам.

Масштабирование по категориям:

  • public-pages-config.ts — публичные страницы (landing, about, contact)

  • docs-pages-config.ts — документация с расширенной навигацией

  • admin-pages-config.ts — административные панели

  • blog-pages-config.ts — блоговые записи и статьи

Каждая категория получает:

  • Собственный файл конфигурации

  • Специализированные типы секций

  • Уникальную логику рендеринга

2.1.6.5. Взаимодействие с AI-генерацией

Для AI-систем конфиг служит:

  • Шаблоном структуры — как должны выглядеть PageConfig объекты

  • Примером данных — референсные значения для генерации

  • Валидацией типов — строгая типизация через TypeScript

Рабочий процесс:

  1. AI анализирует существующий конфиг

  2. Генерирует новый PageConfig на основе промпта

  3. Разработчик добавляет конфиг в массив pages

  4. Система автоматически подхватывает новые маршруты

2.1.6.6. Преимущества и ограничения

Преимущества файлового подхода:

  • Версионирование через Git

  • Type safety на этапе компиляции

  • Нулевая латентность — нет запросов к БД

  • Простота деплоя — статическая генерация

Ограничения:

  • Отсутствие динамического управления

  • Необходимость перебилда при изменениях

  • Неподходящ для user-generated content

  • Сложность масштабирования свыше 20-30 страниц

2.1.6.7. Компонент

// @/app/@right/public/(_servise)/(_config)/public-pages-config.ts


import {

  PageConfig,

  SectionConfig,

} from "@/app/@right/(_service)/(_types)/page-wrapper-types";




export const PublicPagesConfig = {

  pages: [

    {

      metadata: {

        id: "public",

        title: "Enterprise-Grade AI Next.js starter",

        description: "Free Open-Source starter kit...",

        slug: ["public", "test"],

        type: "hero-section",

      },

      sections: [

        {

          id: "test-block",

          type: "hero-section",

          headerContent: {

            announcement: {

              badgeText: "Thanks",

              descriptionText: "AI-SDK V5 & Vercel AI",

              href: "https://github.com/aifa-agi/aifa",

            },

            heading: "Enterprise-Grade AI Next.js starter",

            description:

              "Free Open-Source starter kit to build, deploy, and scale intelligent AI applications. Artifacts Feature, features secure multi-provider auth, Stripe payments, vector knowledge bases, deep-research agents, and a unique fractal architecture designed for the future of AI.",

            showBorder: false,

            headingLevel: 1,

          },

          bodyContent: {},

          footerContent: {

            actions: [

              {

                label: "Get Started",

                href: "/https://github.com/aifa-agi/aifa",

                variant: "default",

              },

              { label: "Browse Docs", href: "/docs", variant: "ghost" },

            ],

          },

          videoUrl: "/_static/video/ai-loop.mp4",

          contentWrapperClassName: "text-white",

        } as SectionConfig,

      ],

    },

  ] as PageConfig[],

};

2.1.6.7. Заключение

public-pages-config.ts представляет собой практичное решение для небольших и средних проектов, обеспечивающее баланс между простотой управления и функциональностью. Для крупных проектов этот подход служит отличной отправной точкой перед миграцией на database-driven архитектуру.

2.1.7. utils.ts: вспомогательные функции конфигурации

Утилиты для работы с конфигами страниц. Содержит две ключевые функции: getAllPublicPages() — фильтрует все страницы с префиксом “public” для статической генерации, и getPageBySlug() — находит конкретную страницу по полному совпадению slug-массива с учетом регистра.

// @app/@right/public/(_servise)/(_libs)/utils.ts


import {

  PageConfig,

  SlugType,

} from "@/app/@right/(_service)/(_types)/page-wrapper-types";

import { PublicPagesConfig } from "../(_config)/public-pages-config";




export function getAllPublicPages(): PageConfig[] {

  return PublicPagesConfig.pages.filter(

    (page: PageConfig) => page.metadata.slug?.[0] === "public"

  );

}




export function getPageBySlug(slug: SlugType): PageConfig | undefined {

  return PublicPagesConfig.pages.find(

    (page: PageConfig) =>

      JSON.stringify(

        page.metadata.slug?.map((s: string) => s.toLowerCase())

      ) === JSON.stringify(slug.map((s: string) => s.toLowerCase()))

  );

}

2.1.8.  header-section.tsx: унифицированный заголовок секций

Стандартизированный компонент заголовка для всех типов секций. Обеспечивает единообразие через опциональные элементы: анонс, заголовок H1/H2, описание. Ключевая роль в SEO-оптимизации и визуальной консистентности AI-генерируемых страниц.

// @/app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/header-section.tsx


import React from "react";

import { cn } from "@/lib/utils";

import {

  PageHeaderDescription,

  PageHeaderHeading,

} from "./page-header-elements";




import { Announcement } from "./announcement";

import { HeaderContentConfig } from "../../../(_types)/page-wrapper-types";




export type HeaderSectionProps = {

  headerContent: HeaderContentConfig;

} & React.HTMLAttributes<HTMLDivElement>;




export function HeaderSection({

  headerContent,

  className,

  ...props

}: HeaderSectionProps) {

  if (!headerContent) return null;




  const {

    announcement,

    heading,

    headingLevel = 1,

    description,

    showBorder = false,

  } = headerContent;




  return (

    <section

      className={cn(

        showBorder && "border-t-4 border-b-4 border-primary",

        className

      )}

      {...props}

    >

      <div className="container mx-auto px-4">

        <div className="flex flex-col items-center gap-1 py-8 md:py-10 lg:py-12">

          {announcement && (

            <Announcement

              badgeText={announcement.badgeText}

              descriptionText={announcement.descriptionText}

              href={announcement.href}

            />

          )}

          <PageHeaderHeading level={headingLevel}>{heading}</PageHeaderHeading>

          {description && (

            <PageHeaderDescription>{description}</PageHeaderDescription>

          )}

        </div>

      </div>

    </section>

  );

}

2.1.9.  header-section.tsx: унифицированный заголовок секций

Атомарные компоненты для построения заголовков: PageHeaderHeading с поддержкой H1/H2, PageHeaderDescription для подзаголовков, PageActions для размещения кнопок. Используют createElement для динамической генерации HTML-тегов с правильной SEO-иерархией.

// @app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/page-header-elements.tsx

import { HTMLAttributes, createElement } from "react";

import { cn } from "@/lib/utils";


type HeadingTag = "h1" | "h2";


interface PageHeaderHeadingProps extends HTMLAttributes<HTMLHeadingElement> {

  level?: 1 | 2;

}


function PageHeaderHeading({

  className,

  level = 1,

  ...props

}: PageHeaderHeadingProps) {

  // Выбор тега по уровню

  const Heading: HeadingTag = level === 1 ? "h1" : "h2";

  const h1Classes = "text-2xl sm:text-3xl  md:text-6xl lg:text-7xl";

  const h2Classes = "text-lg sm:text-xl  md:text-3xl lg:text-4xl";




  // Правильное использование createElement

  return createElement(Heading, {

    className: cn(

      "text-center font-bold leading-tight tracking-tighter font-serif",

      level === 1 ? h1Classes : h2Classes,

      className

    ),

    ...props,

  });

}




function PageHeaderDescription({

  className,

  ...props

}: HTMLAttributes<HTMLParagraphElement>) {

  return (

    <p

      className={cn(

        "max-w-2xl text-balance text-center text-base font-light text-muted-foreground sm:text-lg",

        className

      )}

      {...props}

    />

  );

}




function PageActions({ className, ...props }: HTMLAttributes<HTMLDivElement>) {

  return (

    <div

      className={cn(

        "flex w-full items-center justify-center gap-2 pt-2",

        className

      )}

      {...props}

    />

  );

}




// Экспорт компонентов

export { PageActions, PageHeaderDescription, PageHeaderHeading };

2.1.10. announcement.tsx: компонент анонсов

Интерактивный бейдж для анонсов и уведомлений. Поддерживает навигацию, клавиатурное управление и условный рендеринг. Автоматически скрывается при отсутствии контента. Используется для привлечения внимания к важным обновлениям или ссылкам.
// @app/@right/(_service)/(_components)/page-transformer-components/header-sections-components/announcement.tsx

"use client";


import { useRouter } from "next/navigation";

import { Badge } from "@/components/ui/badge";

import { ArrowRight } from "lucide-react";

import { cn } from "@/lib/utils";




interface AnnouncementProps {

  badgeText?: string; // Сделали необязательным

  descriptionText?: string; // Сделали необязательным

  href?: string; // Сделали необязательным

  className?: string;

}




export function Announcement({

  badgeText,

  descriptionText,

  href,

  className,

}: AnnouncementProps) {

  const router = useRouter();




  const handleOnClick = () => {

    if (href) {

      router.push(href);

    }

  };




  // Если нет текста для бейджа, описания или ссылки, возвращаем null

  if (!badgeText && !descriptionText && !href) {

    return null;

  }




  return (

    <div

      className={cn(

        "flex cursor-pointer items-center gap-2 rounded-full border border-primary bg-muted px-3 py-1 text-sm transition-colors hover:bg-muted/80",

        className

      )}

      onClick={handleOnClick}

      role="link"

      tabIndex={0}

      onKeyDown={(e) => {

        if (e.key === "Enter" || e.key === " ") {

          handleOnClick();

        }

      }}

    >

      {badgeText && (

        <Badge variant="secondary" className="text-xs">

          {badgeText}

        </Badge>

      )}

      {descriptionText && (

        <span className="text-muted-foreground">{descriptionText}</span>

      )}

      {href && <ArrowRight className=" h-3 w-3 text-muted-foreground" />}

    </div>

  );

}

2.1.11. footer-section.tsx: унифицированные действия секций

Стандартизированный футер с кнопками действий. Поддерживает множественные кнопки с разными вариантами стилизации. Обеспечивает единообразие CTA-элементов across всех секций. Автоматически скрывается при отсутствии действий.
// @app/@right/(_service)/(_components)/page-transformer-components/footer-sections-components/footer-section.tsx

"use client";




import { useRouter } from "next/navigation";

import type { HTMLAttributes } from "react";

import { cn } from "@/lib/utils";

import { Button } from "@/components/ui/button";

import { PageActions } from "../header-sections-components/page-header-elements";




interface FooterAction {

  label: string;

  href: string;

  variant?:

    | "default"

    | "secondary"

    | "destructive"

    | "outline"

    | "ghost"

    | "link";

}




interface FooterSectionProps extends HTMLAttributes<HTMLDivElement> {

  actions?: FooterAction[];

}




export function FooterSection({

  actions,

  className,

  ...props

}: FooterSectionProps) {

  const router = useRouter();




  if (!actions || actions.length === 0) {

    return null;

  }




  return (

    <section className={cn("py-4 md:py-6 lg:py-8", className)} {...props}>

      <div className="container mx-auto px-4">

        <PageActions>

          {actions.map((action) => (

            <Button

              key={action.href} // href должен быть уникальным!

              size="sm"

              variant={action.variant || "default"}

              onClick={() => router.push(action.href)}

            >

              {action.label}

            </Button>

          ))}

        </PageActions>

      </div>

    </section>

  );

}

2.1.12.  body-section.tsx: контейнер для произвольного контента

2.1.12.1. Назначение и философия

BodySection — это максимально гибкий контейнер для основного содержимого секций. В отличие от строго стандартизированных Header и Footer, этот компонент предоставляет полную свободу для размещения любого React-контента.

2.1.12.2. Принципы генерации контента

Критически важно: Контент для bodyContent должен генерироваться как обычный TSX без элементов .map(), где все элементы представлены в развернутом виде:

// ✅ Правильно - развернутый TSX

bodyContent: (

  <>

    <div className="grid grid-cols-1 md:grid-cols-3 gap-6">

      <div className="feature-card">

        <h3>Feature 1</h3>

        <p>Description 1</p>

      </div>

      <div className="feature-card">

        <h3>Feature 2</h3>

        <p>Description 2</p>

      </div>

      <div className="feature-card">

        <h3>Feature 3</h3>

        <p>Description 3</p>

      </div>

    </div>

  </>

)
```

```

// ❌ Неправильно - использование .map()

bodyContent: (

  <div className="grid">

    {features.map(feature => <FeatureCard key={feature.id} {...feature} />)}

  </div>

)

2.1.12.3.  Когда использовать кастомные компоненты

Если секция требует сложной логики (состояние, эффекты, интерактивность), создавайте самостоятельный компонент и добавляйте его в PageHtmlTransformer как отдельный

case:


switch (section.type) {

  case "interactive-pricing-section": {

    return <CustomPricingCalculator key={config.id} {...config} />;

  }

  // стандартные случаи...

}

2.1.12.3. Техническая реализация

Компонент проверяет наличие children и рендерит их без дополнительной обработки. При отсутствии контента возвращает null, обеспечивая чистую разметку без пустых блоков.

// @/app/@right/(_service)/(_components)/page-transformer-components/body-sections-components/body-section.tsx

export function BodySection({ children, className, ...props }: BodySectionProps) {

  const hasChildren = children !== null && children !== undefined && 

    !(Array.isArray(children) && children.length === 0) &&

    !(typeof children === "string" && children === "");

  if (!hasChildren) return null;

  return (

    <div className={cn(className)} {...props}>

      {children}

    </div>

  );

}

2.1.12.4. Компонент

// @app/@right/(_service)/(_components)/page-transformer-components/body-sections-components/body-section.tsx




import type { HTMLAttributes, ReactNode } from "react";

import { cn } from "@/lib/utils";

import { SectionType } from "../../../(_types)/page-wrapper-types";




interface BodySectionProps extends HTMLAttributes<HTMLDivElement> {

  children?: ReactNode | null;

  type: SectionType;

}




/**

 * BodySection component.

 * Renders children if present,

 * otherwise renders an empty section with a default height (in rem) if provided,

 * or renders nothing.

 */

export function BodySection({

  children,

  className,

  ...props

}: BodySectionProps) {

  const defaultHeightRem = 0;

  const hasChildren =

    children !== null &&

    children !== undefined &&

    // Covers case when children = [] or ""

    !(Array.isArray(children) && children.length === 0) &&

    !(typeof children === "string" && children === "");




  if (!hasChildren && defaultHeightRem) {

    return (

      <div

        className={cn(className)}

        style={{ height: ${defaultHeightRem}rem }}

        {...props}

      >

        {/* Empty section with default height */}

      </div>

    );

  }




  if (!hasChildren) {

    return null;

  }




  // Normal case: render content

  return (

    <div className={cn(className)} {...props}>

      {children}

    </div>

  );

}

2.1.12.5. ЗаключениеBodySection служит мостом между стандартизированной архитектурой системы и творческой свободой AI-генерации, обеспечивая баланс между контролем и гибкостью.

2.2. Custom сложные компонентыCustom компоненты предназначены для реализации сложной интерактивной функциональности, которая выходит за рамки возможностей стандартной архитектуры. Эти компоненты используются в случаях, когда требуется управление состоянием, сложные анимации, real-time взаимодействие или уникальная бизнес-логика.

h4 Когда использовать Custom компоненты:

  • Интерактивные элементы — формы с валидацией, калькуляторы, конфигураторы продуктов

  • Анимированные презентации — сложные transitions, параллакс-эффекты, автоматические слайдеры

  • Real-time функциональность — чаты, уведомления, live-данные

  • Адаптивная логика — компоненты с кардинально разным поведением на desktop/mobile

  • Уникальные UI-паттерны — нестандартные элементы интерфейса, специфичные для проекта

Интеграция с архитектурой:
Custom компоненты добавляются в PageHtmlTransformer как отдельные case в switch-конструкции, получая доступ к контексту темы, устройства и другим системным параметрам. Они сохраняют единый стиль через использование общих CSS-классов и дизайн-токенов, но получают полную свободу в реализации внутренней логики.

Такой подход обеспечивает баланс между стандартизацией большинства контента и творческой свободой в реализации сложных интерактивных элементов.

2.2.1. Директива по обработке кастомных компонентов 

2.2.1.1.  About Wrappers

Запрет на обёртки для кастомных компонентов

Custom-компоненты должны возвращаться напрямую без Wrapper или FullScreenWrapper, так как они сами управляют своей структурой, отступами и слоями.

2.2.1.2. About custom component types

Размещение типов в компоненте

Интерфейсы пропсов кастомного компонента объявляются в верхней части самого компонента. Данные передаются через поле customComponentsAnyTypeData в конфиге секции.

2.2.1.3 Расширенный тип SectionType:

Добавление нового типа секции

Для каждого кастомного компонента добавляется уникальный тип в enum SectionType файла page-wrapper-types.ts для корректной типизации и обработки в switch-конструкции.

// @/app/@right/(_service)/(_types)/page-wrapper-types.ts

// ...

export type SectionType ="hero-section" | “new-custom-section”;

2.2.1.4. Update cases in the ageHtmlTransformer

Обработка кастомного кейса

В PageHtmlTransformer добавляется новый case для обработки кастомного типа секции с прямой передачей данных из customComponentsAnyTypeData в пропсы компонента.

case "new-custom-section":

  return (

    <NewCustomSection

      key={config.id}

      customData={section.customComponentsAnyTypeData.customData}

    />

  );

2.2.1.5. Custom Config

Структура конфигурации

Пример конфигурации страницы с кастомной секцией, где все специфичные данные размещаются в объекте customComponentsAnyTypeData с произвольной структурой под нужды компонента.

export const PublicPagesConfig = {
	pages: [

{

      metadata: {

        id: "CIUD",

        title: "1",

        description: "2",

        slug: ["public", "name"],

        type: "new-custom-section",

      },

      sections: [

        {

          id: "new-custom-section",

          type: "new-custom-section",

          customComponentsAnyTypeData: {

            metaData: {

              metaTitle: "1",

              metaDescription: "2",

            },

            customData: {

              mediaUrl: "/_static/illustrations/3.png",

              title: "4",

              description:

                "5",

            },

          },

        } as SectionConfig,

      ],

    },

             ] as PageConfig[],

2.2.2. Custom component example

2.3.2.1. DoublePresentation

AI-генератор сайтов на ChatGPT и Next.js 15: Создаем SEO-оптимизированные страницы с нуля (аналог v0) - 3

2.3.2.1.1. Обновление основных типов

// @/app/@right/(_service)/(_types)/page-wrapper-types.ts

// Добавляем новый тип секции

export type SectionType =

  | "hero-section"

  | "cta-section"

  | "double-presentation-section" // Новый тип

  // ... остальные типы

2.3.2.1.2. Add new case with current data to : PageHtmlTransformer

case "double-presentation-section":

            return (

              <DoublePresentation

                key={section.id}

                metaData={section.customComponentsAnyTypeData.metaData}

                leftItem={section.customComponentsAnyTypeData.leftItem}

                rightItem={section.customComponentsAnyTypeData.rightItem}

              />

            );

2.3.2.1.3. page-wrapper-types.ts

// app/@right/(_service)/(_types)/page-wrapper-types.ts




export interface MetadataConfig {

  title?: string;

  description?: string;

}




export type CuidString = string;




export interface PageMetadata {

  id: CuidString;

  title: string;

  description: string;

  image?: string;

  slug?: string[];

  type: SectionType;

}




export type SectionType =

  | "hero-section"

  | "cta-section"

  | "faq-section"

  | "features-section"

  | "testimonials-section"

  | "pricing-section"

  | "contact-section"

  | "blog-posts-section"

  | "product-grid-section"

  | "image-gallery-section"

  | "text-block-section"

  | "video-section"

  | "team-section"

  | "about-us-section"

  | "newsletter-section"

  | "social-proof-section"

  | "comparison-table-section"

  | "map-section"

  | "custom-html-section"

  | "changelog-section"

  | "comparison-two-column-section"

  | "comparison-three-column-section"

  | "feature-showcase-section"

  | "double-presentation-section";




export interface BaseSection {

  id: string;

  type: SectionType;

  className?: string;

}




export interface HeaderContentConfig {

  announcement?: {

    badgeText?: string;

    descriptionText?: string;

    href?: string;

  };

  heading: string;

  headingLevel?: 1 | 2;

  description?: string;

  showBorder?: boolean;

}




export interface FooterContentConfig {

  actions?: {

    label: string;

    href: string;

    variant?:

      | "default"

      | "secondary"

      | "destructive"

      | "outline"

      | "ghost"

      | "link";

  }[];

}

export interface SectionConfig extends BaseSection {

  type: SectionType;

  headerContent: HeaderContentConfig;

  bodyContent?: React.ReactNode;

  footerContent?: FooterContentConfig;

  videoUrl?: string;

  imageUrl?: string;

  sectionClassName?: string;

  contentWrapperClassName?: string;

  customComponentsAnyTypeData?: any;

}




export type Section = SectionConfig;




export interface PageConfig {

  metadata: PageMetadata;

  sections: Section[];

}




export type SlugType = string[];

2.3.2.1.4. Config, example:

// @/app/@right/public/(_servise)/(_config)/public-pages-config.ts




import {

  PageConfig,

  SectionConfig,

} from "@/app/@right/(_service)/(_types)/page-wrapper-types";




export const PublicPagesConfig = {

  pages: [

    {

      metadata: {

        id: "public",

        title: "Enterprise-Grade AI Next.js starter",

        description: "Free Open-Source starter kit...",

        slug: ["public", "test"],

        type: "hero-section",

      },

      sections: [

        {

          id: "test-block",

          type: "hero-section",

          headerContent: {

            announcement: {

              badgeText: "Thanks",

              descriptionText: "AI-SDK V5 & Vercel AI",

              href: "https://github.com/aifa-agi/aifa",

            },

            heading: "Enterprise-Grade AI Next.js starter",

            description:

              "Free Open-Source starter kit to build, deploy, and scale intelligent AI applications. Artifacts Feature, features secure multi-provider auth, Stripe payments, vector knowledge bases, deep-research agents, and a unique fractal architecture designed for the future of AI.",

            showBorder: false,

            headingLevel: 1,

          },

          bodyContent: {},

          footerContent: {

            actions: [

              {

                label: "Get Started",

                href: "/https://github.com/aifa-agi/aifa",

                variant: "default",

              },

              { label: "Browse Docs", href: "/docs", variant: "ghost" },

            ],

          },

          videoUrl: "/_static/video/ai-loop.mp4",

          contentWrapperClassName: "text-white",

        } as SectionConfig,

      ],

    },

    {

      metadata: {

        id: "interactive-ai",

        title: "Interactive AI Demo",

        description: "Demo: DoublePresentation custom case",

        slug: ["public", "example"],

        type: "double-presentation-section",

      },




      sections: [

        {

          id: "double-presentation-demo",

          type: "double-presentation-section",

          customComponentsAnyTypeData: {

            metaData: {

              metaTitle: "Interactive AI: Where Conversation Builds the UI",

              metaDescription: "Discover what makes AIFA revolutionary...",

            },

            leftItem: {

              mediaUrl: "/_static/illustrations/ai-chat.png",

              title: "Ai Artifacts Chatbot",

              description:

                "As the AI chatbot speaks, it highlights elements...",

            },

            rightItem: {

              mediaUrl: "/_static/illustrations/ai-web.png",

              title: "Related Pages",

              description:

                "Click any UI element, and the AI provides instant context...",

            },

          },

        } as SectionConfig,

      ],

    },

  ] as PageConfig[],

};

2.3.2.1.5. Component

// @/app/@right/(_service)/(_components)/page-transformer-components/custom-sections/custom-double-prsentation.tsx




"use client";




import React, { useState, useEffect } from "react";

import { motion } from "framer-motion";

import Image from "next/image";

import { cn } from "@/lib/utils";

import { useMediaQuery } from "@/hooks/use-media-query";




interface PresentationMeta {

  metaTitle: string;

  metaDescription: string;

}




interface PresentationItem {

  mediaUrl: string;

  title: string;

  description: string;

}




interface DoublePresentationProps {

  metaData: PresentationMeta;

  leftItem: PresentationItem;

  rightItem: PresentationItem;

}




export default function DoublePresentation({

  metaData,

  leftItem,

  rightItem,

}: DoublePresentationProps) {

  const { isMobile } = useMediaQuery();




  // Desktop animation state

  const [activeContainer, setActiveContainer] = useState<"left" | "right">(

    "left"

  );

  const [sliderKey, setSliderKey] = useState(0);




  // Desktop auto-switching effect

  useEffect(() => {

    // Only run animation cycle on desktop

    if (isMobile) return;




    let sliderTimer: NodeJS.Timeout;

    let transitionTimer: NodeJS.Timeout;




    const startAnimationCycle = () => {

      setSliderKey((prev) => prev + 1);

      sliderTimer = setTimeout(() => {

        setActiveContainer((prev) => (prev === "left" ? "right" : "left"));

        transitionTimer = setTimeout(() => {

          startAnimationCycle();

        }, 500);

      }, 9000);

    };




    startAnimationCycle();




    return () => {

      clearTimeout(sliderTimer);

      clearTimeout(transitionTimer);

    };

  }, [isMobile]);




  // Return null while determining screen size

  if (isMobile === null) {

    return null;

  }




  // Common CSS classes

  const metaBlockClass = "text-center max-w-3xl flex flex-col items-center";

  const descriptionClass =

    "mb-12 max-w-xl text-base text-muted-foreground text-center";

  const desktopTitleClass =

    "mb-6 max-w-3xl font-serif font-bold leading-tight md:text-2xl lg:text-4xl";

  const desktopDescriptionClass =

    "mb-12 max-w-xl text-lg text-muted-foreground md:text-xl text-center";




  // Mobile card renderer

  const renderMobileCard = (item: PresentationItem) => (

    <div className="relative flex flex-col rounded-xl bg-gray-900 text-white shadow-lg mb-6 overflow-hidden">

      <div className="w-full relative" style={{ paddingTop: "56.25%" }}>

        <Image

          src={item.mediaUrl}

          alt={item.title}

          fill

          className="object-cover rounded-t-xl"

          sizes="100vw"

          priority

        />

      </div>

      <div className="flex flex-col p-4">

        <h2 className="text-xl font-bold mb-2">{item.title}</h2>

        <p className="text-gray-300 mb-2 text-base min-h-16">

          {item.description}

        </p>

      </div>

    </div>

  );




  // Desktop card renderer

  const renderDesktopCard = (item: PresentationItem, isActive: boolean) => (

    <motion.div

      layout

      animate={{ flex: isActive ? "7 1 0%" : "3 1 0%" }}

      transition={{ duration: 0.5 }}

      className="relative flex flex-col rounded-lg overflow-hidden bg-transparent text-white p-0 shadow-lg h-[30rem] flex-shrink-0"

    >

      <div className="relative w-full h-60 mb-4 rounded-xl overflow-hidden border-4 border-gray-700">

        <Image

          src={item.mediaUrl}

          alt={item.title}

          fill

          className="object-cover"

          priority

          sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"

        />

      </div>

      <div className="flex flex-col pt-6">

        <h2 className="text-2xl font-bold mb-2 whitespace-nowrap overflow-hidden text-ellipsis">

          {item.title}

        </h2>

        <div className="relative w-full h-px bg-gray-700 mb-4">

          <motion.div

            key={slider-${item.title}-${sliderKey}}

            className={cn(

              "absolute top-0 left-0 h-full",

              isActive ? "bg-primary" : "bg-gray-700"

            )}

            initial={{ width: 0 }}

            animate={{ width: isActive ? "100%" : "0%" }}

            transition={

              isActive ? { duration: 9, ease: "linear" } : { duration: 0 }

            }

          />

        </div>

        <p className="text-gray-300 mb-4 text-sm line-clamp-4 min-h-[4rem]">

          {item.description}

        </p>

      </div>

    </motion.div>

  );




  // Mobile layout

  if (isMobile) {

    return (

      <section className="w-full pt-20">

        <div className="container mx-auto px-4 flex flex-col items-center">

          <div className={metaBlockClass}>

            <h2 className="text-xl font-bold mb-4">{metaData.metaTitle}</h2>

            <p className={descriptionClass}>{metaData.metaDescription}</p>

          </div>




          <div className="w-full flex flex-col">

            {renderMobileCard(leftItem)}

            {renderMobileCard(rightItem)}

          </div>

        </div>

      </section>

    );

  }




  // Desktop layout

  return (

    <section className="w-full pt-28">

      <div className="container mx-auto px-4 flex flex-col items-center gap-12">

        <div className={metaBlockClass}>

          <h2 className={desktopTitleClass}>{metaData.metaTitle}</h2>

          <p className={desktopDescriptionClass}>{metaData.metaDescription}</p>

        </div>




        <div className="flex gap-6 w-full max-w-6xl">

          {renderDesktopCard(leftItem, activeContainer === "left")}

          {renderDesktopCard(rightItem, activeContainer === "right")}

        </div>

      </div>

    </section>

  );

}
AI-генератор сайтов на ChatGPT и Next.js 15: Создаем SEO-оптимизированные страницы с нуля (аналог v0) - 4

Roma Armstromg

AI Architector

Как всегда представляю исходный код готового решения чтобы вы могли сразу же приступить в созданию блогов магазинов лендингов и тп. https://github.com/aifa-agi/aifa

Автор: bolshiyanov

Источник

Rambler's Top100