From f4e78e32272c37ee34585928b6e454b74d53f4b7 Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Wed, 29 Apr 2026 20:52:01 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D1=80=D0=B8=D0=BA=D0=BB=D0=B0=D0=B4=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - обновлён порядок и состав прикладных разделов - добавлены разделы про компоненты, изображения, шрифты и локализацию - уточнены правила модулей, страниц, сегментов и именования - удалены устаревшие пустые разделы и обзор документации --- .vitepress/config.ts | 26 +-- CONTRIBUTING.md | 39 ++-- docs-overview.md | 174 -------------- docs/docs/MAP.md | 18 +- docs/docs/applied/component.md | 199 +++++++++++++++- docs/docs/applied/fonts.md | 128 +++++++++++ docs/docs/applied/hooks.md | 0 docs/docs/applied/images-sprites.md | 0 docs/docs/applied/images.md | 95 ++++++++ docs/docs/applied/localization.md | 81 +++++++ docs/docs/applied/module.md | 214 +++++++++++------- docs/docs/applied/page-level.md | 149 ++++++++++-- docs/docs/applied/project-structure.md | 9 +- docs/docs/applied/styles/styles-usage.md | 11 +- docs/docs/applied/video.md | 0 .../basics/architecture/reference/segments.md | 29 ++- docs/docs/basics/naming.md | 6 + docs/docs/data/index.md | 2 +- 18 files changed, 849 insertions(+), 331 deletions(-) delete mode 100644 docs-overview.md delete mode 100644 docs/docs/applied/hooks.md delete mode 100644 docs/docs/applied/images-sprites.md create mode 100644 docs/docs/applied/images.md delete mode 100644 docs/docs/applied/video.md diff --git a/.vitepress/config.ts b/.vitepress/config.ts index 3c43aaa..788bd51 100644 --- a/.vitepress/config.ts +++ b/.vitepress/config.ts @@ -70,10 +70,10 @@ const sidebar = [ { text: 'Прикладные разделы', items: [ - { text: 'Алиасы импортов', link: '/docs/applied/aliases' }, - { text: 'Biome', link: '/docs/applied/biome' }, - { text: 'PostCSS', link: '/docs/applied/postcss' }, - { text: 'VS Code', link: '/docs/applied/vscode' }, + { text: 'Структура проекта', link: '/docs/applied/project-structure' }, + { text: 'Страницы', link: '/docs/applied/page-level' }, + { text: 'Компонент', link: '/docs/applied/component' }, + { text: 'Модуль', link: '/docs/applied/module' }, { text: 'Стили', collapsed: true, @@ -91,6 +91,9 @@ const sidebar = [ { text: 'Использование', link: '/docs/applied/svg-sprites/svg-sprites-usage' }, ], }, + { text: 'Изображения', link: '/docs/applied/images' }, + { text: 'Шрифты', link: '/docs/applied/fonts' }, + { text: 'Алиасы импортов', link: '/docs/applied/aliases' }, { text: 'Шаблоны генерации', collapsed: true, @@ -101,18 +104,13 @@ const sidebar = [ { text: 'Использование', link: '/docs/applied/templates/templates-usage' }, ], }, - { text: 'Структура проекта', link: '/docs/applied/project-structure' }, - { text: 'Модуль', link: '/docs/applied/module' }, - { text: 'Компонент · в разработке' }, - { text: 'Страницы (App Router)', link: '/docs/applied/page-level' }, + { text: 'Biome', link: '/docs/applied/biome' }, + { text: 'PostCSS', link: '/docs/applied/postcss' }, + { text: 'VS Code', link: '/docs/applied/vscode' }, + { text: 'Локализация', link: '/docs/applied/localization' }, // Неактивные разделы: страницы существуют, но пока пустые. // Оставляем в sidebar без `link`, чтобы видеть план, но без перехода. - { text: 'Изображения · в разработке' }, - { text: 'Видео · в разработке' }, - { text: 'Stores · в разработке' }, - { text: 'Хуки · в разработке' }, - { text: 'Шрифты · в разработке' }, - { text: 'Локализация · в разработке' } + { text: 'Stores · в разработке' } ], }, ]; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c730a9f..faf1688 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,30 +37,35 @@ docs/ │ ├── from-template.md │ ├── manual.md │ └── nextjs.md + ├── data/ # Работа с данными + │ ├── index.md + │ ├── realtime.md + │ └── rest/ └── applied/ # Прикладные разделы: настройка и использование - ├── aliases.md - ├── biome.md - ├── postcss.md - ├── vscode.md + ├── project-structure.md + ├── page-level.md + ├── component.md + ├── module.md ├── styles/ # Стили: настройка + использование │ ├── styles-setup.md │ └── styles-usage.md - ├── svg-sprites/ # SVG-спрайты: настройка + использование + ├── svg-sprites/ # SVG-спрайты: введение + настройка + использование + │ ├── svg-sprites-intro.md │ ├── svg-sprites-setup.md │ └── svg-sprites-usage.md - ├── templates/ # Шаблоны генерации: настройка + использование - │ ├── templates-setup.md - │ └── templates-usage.md - ├── project-structure.md - ├── components.md - ├── page-level.md - ├── images-sprites.md - ├── video.md - ├── data/ - ├── stores.md - ├── hooks.md + ├── images.md ├── fonts.md - └── localization.md + ├── aliases.md + ├── templates/ # Шаблоны генерации: введение + настройка + использование + │ ├── templates-intro.md + │ ├── templates-setup.md + │ ├── templates-create.md + │ └── templates-usage.md + ├── biome.md + ├── postcss.md + ├── vscode.md + ├── localization.md + └── stores.md .vitepress/ └── config.ts # Конфигурация VitePress, сайдбар generate-llms.ts # Скрипт генерации llms.txt и README diff --git a/docs-overview.md b/docs-overview.md deleted file mode 100644 index 7deadb8..0000000 --- a/docs-overview.md +++ /dev/null @@ -1,174 +0,0 @@ -# Обзор страниц документации - -Список всех `.md`-страниц в `docs/docs/` в порядке сайдбара (`.vitepress/config.ts`). -Поля: путь к файлу, заголовок (`h1`), описание (абзац под заголовком). - -## Главная - -### docs/docs/index.md -**Заголовок:** NextJS Style Guide -**Описание:** Стандарты разработки фронтенд-приложений на Next.js и TypeScript. - -## Подсказки - -### docs/docs/workflow.md -**Заголовок:** Подсказки -**Описание:** Короткие ответы на типовые вопросы и решения для спорных ситуаций. - -## Базовые правила - -### docs/docs/basics/tech-stack.md -**Заголовок:** Технологии и библиотеки -**Описание:** Какие библиотеки и инструменты используются в проекте. - -### docs/docs/basics/naming.md -**Заголовок:** Именование -**Описание:** Как называть переменные, файлы и прочие сущности в коде. - -### docs/docs/basics/architecture/index.md -**Заголовок:** SLM Design -**Описание:** Архитектурный подход проекта: что такое SLM и как он устроен. - -### docs/docs/basics/architecture/reference/layers.md -**Заголовок:** Слои SLM -**Описание:** Из каких слоёв состоит SLM-архитектура и как они связаны. - -### docs/docs/basics/architecture/reference/modules.md -**Заголовок:** Модули SLM -**Описание:** Что такое модуль в SLM-архитектуре и как он устроен. - -### docs/docs/basics/architecture/reference/segments.md -**Заголовок:** Сегменты SLM -**Описание:** Что такое сегмент модуля в SLM-архитектуре и какие они бывают. - -### docs/docs/basics/code-style.md -**Заголовок:** Стиль кода -**Описание:** Как оформляется код в проекте. - -### docs/docs/basics/documentation.md -**Заголовок:** Документирование -**Описание:** Что и как документировать в коде. - -### docs/docs/basics/typing.md -**Заголовок:** Типизация -**Описание:** Как типизируется код в проекте. - -## Создание проекта - -### docs/docs/creating-project/from-template.md -**Заголовок:** Создание проекта из шаблона -**Описание:** Создание нового проекта на основе готового шаблона. - -### docs/docs/creating-project/manual.md -**Заголовок:** Создание проекта вручную -**Описание:** Поэтапное создание нового проекта без использования шаблона. - -### docs/docs/creating-project/nextjs.md -**Заголовок:** Чистая установка Next.js -**Описание:** Установка Next.js без лишнего шаблона — голый каркас под дальнейшую сборку. - -## Настройка - -### docs/docs/setup/aliases.md -**Заголовок:** Алиасы импортов -**Описание:** Какие алиасы импортов есть в проекте и как ими пользоваться. - -### docs/docs/setup/biome.md -**Заголовок:** Biome -**Описание:** Установка и настройка линтера-форматтера в новом проекте. - -### docs/docs/setup/postcss.md -**Заголовок:** PostCSS -**Описание:** Установка и настройка CSS-процессора в новом проекте. - -### docs/docs/setup/styles.md -**Заголовок:** Стили -**Описание:** Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили. - -### docs/docs/setup/svg-sprites.md -**Заголовок:** SVG-спрайты -**Описание:** Подключение SVG-спрайтов в новом проекте. - -### docs/docs/setup/templates.md -**Заголовок:** Шаблоны генерации -**Описание:** Подключение шаблонов кодогенерации в новом проекте. - -### docs/docs/setup/vscode.md -**Заголовок:** VS Code -**Описание:** Единые настройки редактора и расширений для команды. - -## Использование - -### docs/docs/usage/project-structure.md -**Заголовок:** Структура проекта -**Описание:** Из чего состоит проект и где что лежит. - -### docs/docs/usage/components.md -**Заголовок:** Компоненты -**Описание:** Как устроен и пишется React-компонент в проекте. - -### docs/docs/usage/page-level.md -**Заголовок:** Файлы роутинга -**Описание:** Что должно лежать в файлах роутинга, а что — в экранах. - -### docs/docs/usage/templates-generation.md -**Заголовок:** Шаблоны и генерация кода -**Описание:** Как устроены шаблоны кодогенерации и как ими пользоваться. - -### docs/docs/usage/styles.md -**Заголовок:** Стили -**Описание:** Как пишутся стили в проекте. - -### docs/docs/usage/images-sprites.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -### docs/docs/usage/svg-sprites.md -**Заголовок:** SVG-спрайты -**Описание:** Как добавлять и использовать SVG-иконки в коде. - -### docs/docs/usage/video.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -### docs/docs/usage/stores.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -### docs/docs/usage/hooks.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -### docs/docs/usage/fonts.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -### docs/docs/usage/localization.md -**Заголовок:** — -**Описание:** _(файл пустой)_ - -## Данные - -### docs/docs/usage/data/index.md -**Заголовок:** Источники данных -**Описание:** Какие источники данных используются в проекте и как с ними работать. - -### docs/docs/usage/data/rest/clients/auto.md -**Заголовок:** Автогенерация REST-клиента -**Описание:** Генерация REST-клиента из OpenAPI-спецификации. - -### docs/docs/usage/data/rest/clients/manual.md -**Заголовок:** Ручное создание REST-клиента -**Описание:** Создание REST-клиента вручную, когда нет OpenAPI-спецификации. - -### docs/docs/usage/data/rest/fetching/server.md -**Заголовок:** Серверные компоненты -**Описание:** Получение REST-данных в серверных компонентах. - -### docs/docs/usage/data/rest/fetching/client.md -**Заголовок:** Клиентские компоненты -**Описание:** Получение REST-данных в клиентских компонентах. - -### docs/docs/usage/data/realtime.md -**Заголовок:** Realtime -**Описание:** Работа с push-данными от сервера: подписки и события. diff --git a/docs/docs/MAP.md b/docs/docs/MAP.md index ae2cbeb..1a6078e 100644 --- a/docs/docs/MAP.md +++ b/docs/docs/MAP.md @@ -36,19 +36,23 @@ ## Прикладные разделы -- [Алиасы импортов](./applied/aliases.md) — Какие алиасы импортов есть в проекте и как ими пользоваться. -- [Biome](./applied/biome.md) — Установка и настройка линтера-форматтера в новом проекте. -- [PostCSS](./applied/postcss.md) — Установка и настройка CSS-процессора в новом проекте. -- [VS Code](./applied/vscode.md) — Единые настройки редактора и расширений для команды. +- [Структура проекта](./applied/project-structure.md) — Из чего состоит проект и где что лежит. +- [Страницы](./applied/page-level.md) — Как работать со страницами и другими файлами роутинга Next.js App Router. +- [Компонент](./applied/component.md) — Как создавать React-компоненты внутри SLM-модулей. +- [Модуль](./applied/module.md) — Как создавать и организовывать SLM-модули в проекте. - [Стили: Настройка](./applied/styles/styles-setup.md) — Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили. - [Стили: Использование](./applied/styles/styles-usage.md) — Как пишутся стили в проекте. - [SVG-спрайты](./applied/svg-sprites/svg-sprites-intro.md) — Что такое SVG-спрайты и какие проблемы они решают. - [SVG-спрайты: Настройка](./applied/svg-sprites/svg-sprites-setup.md) — Подключение SVG-спрайтов в новом проекте. - [SVG-спрайты: Использование](./applied/svg-sprites/svg-sprites-usage.md) — Как добавлять и использовать SVG-иконки в коде. +- [Изображения](./applied/images.md) — Как подключать изображения через Next.js Image в проекте. +- [Шрифты](./applied/fonts.md) — Как подключать шрифты через Next.js Font в проекте. +- [Алиасы импортов](./applied/aliases.md) — Какие алиасы импортов есть в проекте и как ими пользоваться. - [Шаблоны генерации](./applied/templates/templates-intro.md) — Что такое шаблоны кодогенерации и какие проблемы они решают. - [Шаблоны генерации: Настройка](./applied/templates/templates-setup.md) — Первичная установка шаблонов кодогенерации в проект. - [Шаблоны генерации: Создание шаблонов](./applied/templates/templates-create.md) — Структура шаблонов, синтаксис переменных и примеры. - [Шаблоны генерации: Использование](./applied/templates/templates-usage.md) — Генерация файлов из шаблонов через VS Code плагин и CLI. -- [Структура проекта](./applied/project-structure.md) — Из чего состоит проект и где что лежит. -- [Модуль](./applied/module.md) — Как устроен и пишется React-компонент в проекте. -- [Страницы (App Router)](./applied/page-level.md) — Что должно лежать в файлах роутинга, а что — в экранах. +- [Biome](./applied/biome.md) — Установка и настройка линтера-форматтера в новом проекте. +- [PostCSS](./applied/postcss.md) — Установка и настройка CSS-процессора в новом проекте. +- [VS Code](./applied/vscode.md) — Единые настройки редактора и расширений для команды. +- [Локализация](./applied/localization.md) — Как организовать локализацию как infrastructure-модуль. diff --git a/docs/docs/applied/component.md b/docs/docs/applied/component.md index daf3c5e..4e825c3 100644 --- a/docs/docs/applied/component.md +++ b/docs/docs/applied/component.md @@ -1,4 +1,201 @@ --- title: Компонент -description: Как устроен и пишется React-компонент в проекте. +description: Как создавать React-компоненты внутри SLM-модулей. --- + +# Компонент + +Как создавать React-компоненты внутри SLM-модулей. + +## Назначение + +Компонент — минимальная UI-единица проекта. Это один `.tsx` файл без собственной папки, сегментов и публичного API. + +Компонент может использовать стили, типы, хуки и другие ресурсы родительского модуля. Наличие связанных файлов в `styles/` или `types/` не превращает компонент в модуль. + +## Компонент или модуль + +Классификация определяется границей владения: + +- `component` — один `.tsx` файл внутри модуля; +- `module` — папка с `index.ts`, сегментами и собственной публичной границей. + +```text +user/ +├── ui/ +│ └── user-avatar.tsx # компонент +├── styles/ +│ └── user-avatar.module.css # ресурс родительского модуля +├── types/ +│ └── user-avatar.type.ts # ресурс родительского модуля +└── user.tsx # корневой компонент модуля +``` + +`user-avatar.tsx` остаётся компонентом, потому что у него нет собственной папки, `index.ts` и сегментов. + +## Где размещать + +Компонент размещается внутри модуля: + +- В корне модуля, если это главная UI-сущность модуля. +- В `ui/`, если это вспомогательный компонент модуля. + +```text +user/ +├── ui/ +│ └── user-avatar.tsx +├── styles/ +│ ├── user.module.css +│ └── user-avatar.module.css +├── types/ +│ ├── user.type.ts +│ └── user-avatar.type.ts +├── user.tsx +└── index.ts +``` + +`user.tsx` — корневой компонент модуля. `ui/user-avatar.tsx` — вспомогательный компонент этого же модуля. + +## Что запрещено + +- Заворачивать компонент в папку: `ui/header/header.tsx`. +- Создавать для компонента отдельный `index.ts`. +- Создавать собственные сегменты внутри папки компонента: `ui/header/styles/`, `ui/header/types/`, `ui/header/hooks/` и т.п. +- Декларировать внутри `.tsx` сторы, сервисы, API-клиенты, мапперы или утилиты. Для этого есть сегменты родительского модуля. +- Размещать бизнес-правила прямо в компоненте. Компонент может использовать готовые зависимости модуля, но не определяет их. +- Размещать компонент в `parts/` напрямую. `parts/` содержит только модули. + +**Плохо** + +```text +user/ +└── ui/ + └── user-avatar/ + ├── styles/ + │ └── user-avatar.module.css + ├── user-avatar.tsx + └── index.ts +``` + +**Хорошо** + +```text +user/ +├── ui/ +│ └── user-avatar.tsx +├── styles/ +│ └── user-avatar.module.css +└── types/ + └── user-avatar.type.ts +``` + +## Стили и типы + +Компонент использует ресурсы родительского модуля. + +`styles/` и `types/` рядом с корневым компонентом — это сегменты модуля, а не собственные папки `.tsx` файла. + +- CSS Module компонента лежит в `styles/` родительского модуля и называется по компоненту: `user-avatar.module.css`. +- Если у компонента есть CSS Module, его корневой класс всегда называется `.root`. +- Типы компонента лежат в `types/` родительского модуля и называются по компоненту: `user-avatar.type.ts`. +- Локальный `type Props` внутри `.tsx` не используется. Типы пропсов всегда выносятся в `types/` родительского модуля. +- Экспорт типа из `types/` не делает его публичным API. Публичным он становится только при реэкспорте из `index.ts` модуля. + +Причина `.root`: в DevTools проще находить корневой DOM-узел компонента и отличать его от внутренних элементов. + +## Реализация + +- Компоненты объявляются через `const`. +- `React.FC` не используется. +- JSDoc-комментарий обязателен для компонента. +- Пропсы деструктурируются в теле компонента. +- `className` объединяется с `styles.root` через `cl()`. +- Побочные эффекты и состояние выносятся в хуки модуля, если перестают быть тривиальными. +- Компонент возвращает JSX и не содержит orchestration-код страницы или бизнес-домена. + +`user/types/user-avatar.type.ts` + +```ts +import type { ImageProps } from 'next/image' + +/** + * Параметры UserAvatar. + */ +export type UserAvatarParams = {} + +/** Пропсы базового изображения. */ +type RootAttrs = ImageProps + +export type UserAvatarProps = RootAttrs & UserAvatarParams +``` + +`user/ui/user-avatar.tsx` + +```tsx +import cl from 'clsx' +import Image from 'next/image' +import type { UserAvatarProps } from '../types/user-avatar.type' +import styles from '../styles/user-avatar.module.css' + +/** + * Аватар пользователя. + * + * Используется для: + * - отображения пользователя в карточке + * - отображения пользователя в шапке профиля + */ +export const UserAvatar = (props: UserAvatarProps) => { + const { className, ...imageProps } = props + + return +} +``` + +`user/styles/user-avatar.module.css` + +```css +.root { + display: block; + border-radius: 50%; +} +``` + +## Когда нужен модуль + +Решение о выделении модуля остаётся за разработчиком. Поднимать компонент в модуль стоит, если он становится самостоятельной областью: + +- получает свои вложенные компоненты; +- получает свои хуки, стор или сервисы; +- получает внутренние мапперы или утилиты; +- требует собственного публичного API; +- начинает переиспользоваться вне родительского модуля; +- становится отдельной зоной параллельной разработки. + +Пример: страница — это screen-модуль, а самостоятельные секции страницы — вложенные модули в `parts/`. + +```text +screens/home/ +├── parts/ +│ ├── hero-section/ +│ │ ├── styles/ +│ │ │ └── hero-section.module.css +│ │ ├── types/ +│ │ │ └── hero-section.type.ts +│ │ ├── hero-section.tsx +│ │ └── index.ts +│ └── features-section/ +│ ├── styles/ +│ │ └── features-section.module.css +│ ├── types/ +│ │ └── features-section.type.ts +│ ├── features-section.tsx +│ └── index.ts +├── styles/ +│ └── home.module.css +├── types/ +│ └── home.type.ts +├── home.screen.tsx +└── index.ts +``` + +`hero-section` и `features-section` — модули, потому что это самостоятельные части страницы со своей структурой и публичной точкой входа. diff --git a/docs/docs/applied/fonts.md b/docs/docs/applied/fonts.md index e69de29..981276b 100644 --- a/docs/docs/applied/fonts.md +++ b/docs/docs/applied/fonts.md @@ -0,0 +1,128 @@ +--- +title: Шрифты +description: Как подключать шрифты через Next.js Font в проекте. +--- + +# Шрифты + +Как подключать шрифты через Next.js Font в проекте. + +## Назначение + +Шрифты подключаются через `next/font`. Это стандартный способ Next.js: шрифты загружаются без ручных ``, `@font-face` и настройки preconnect. + +Шрифт подключается в точке инициализации приложения, а в CSS используется через переменную. + +## Google Fonts + +```tsx +// src/app/layout.tsx +import type { ReactNode } from 'react' +import { Inter } from 'next/font/google' +import 'shared/styles/global.css' + +const inter = Inter({ + subsets: ['latin', 'cyrillic'], + variable: '--font-main', + display: 'swap', +}) + +type RootLayoutProps = { + children: ReactNode +} + +export default function RootLayout({ children }: RootLayoutProps) { + return ( + + {children} + + ) +} +``` + +```css +/* src/shared/styles/global.css */ +body { + font-family: var(--font-main), system-ui, sans-serif; +} +``` + +## Локальные шрифты + +Каждый локальный шрифт размещается в отдельной папке внутри `src/shared/fonts/`. В этой же папке лежит `.font.ts`, где объявляется `localFont`. + +```text +src/shared/fonts/ +└── roboto/ + ├── roboto.font.ts + ├── Roboto-Regular.woff2 + ├── Roboto-Italic.woff2 + ├── Roboto-Bold.woff2 + └── Roboto-BoldItalic.woff2 +``` + +```ts +// src/shared/fonts/roboto/roboto.font.ts +import localFont from 'next/font/local' + +export const roboto = localFont({ + src: [ + { + path: './Roboto-Regular.woff2', + weight: '400', + style: 'normal', + }, + { + path: './Roboto-Italic.woff2', + weight: '400', + style: 'italic', + }, + { + path: './Roboto-Bold.woff2', + weight: '700', + style: 'normal', + }, + { + path: './Roboto-BoldItalic.woff2', + weight: '700', + style: 'italic', + }, + ], + variable: '--font-main', + display: 'swap', +}) +``` + +`app/` импортирует готовый объект шрифта и только подключает его к документу: + +```tsx +// src/app/layout.tsx +import type { ReactNode } from 'react' +import { roboto } from 'shared/fonts/roboto/roboto.font' +import 'shared/styles/global.css' + +type RootLayoutProps = { + children: ReactNode +} + +export default function RootLayout({ children }: RootLayoutProps) { + return ( + + {children} + + ) +} +``` + +Путь в `localFont` указывается относительно `.font.ts`, поэтому файлы шрифта импортируются коротко: `./Roboto-Regular.woff2`. + +Если шрифтов несколько, у каждого своя папка и свой `.font.ts`. + +## Правила + +- Использовать `next/font/google` или `next/font/local`. +- Не подключать шрифты через ручные `` и `@font-face` без необходимости. +- Подключать шрифты один раз — в корневом layout через готовый объект шрифта. +- Использовать CSS-переменные `variable`, а не жёстко прописывать семейство в каждом компоненте. +- Локальные файлы шрифтов хранить в `src/shared/fonts/{font-name}/` рядом с `{font-name}.font.ts`. +- Не объявлять `localFont` внутри `src/app/layout.tsx`; layout только импортирует готовый шрифт. diff --git a/docs/docs/applied/hooks.md b/docs/docs/applied/hooks.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/docs/applied/images-sprites.md b/docs/docs/applied/images-sprites.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/docs/applied/images.md b/docs/docs/applied/images.md new file mode 100644 index 0000000..c4b8be6 --- /dev/null +++ b/docs/docs/applied/images.md @@ -0,0 +1,95 @@ +--- +title: Изображения +description: Как подключать изображения через Next.js Image в проекте. +--- + +# Изображения + +Как подключать изображения через Next.js Image в проекте. + +## Назначение + +Изображения рендерятся через компонент `Image` из `next/image`. Это сохраняет единый API для размеров, `alt`, lazy-loading и `priority`, даже если оптимизация изображений отключена. + +В проекте оптимизация Next.js Image отключается через `unoptimized`, чтобы сборка и рантайм не зависели от встроенного image optimizer. + +## Настройка + +Отключение оптимизации задаётся глобально в `next.config.ts`: + +```ts +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = { + images: { + unoptimized: true, + }, +} + +export default nextConfig +``` + +После этого `unoptimized` не нужно повторять на каждом `Image`. + +## Использование + +Статические изображения, доступные по URL, размещаются в `public/`: + +```text +public/ +└── images/ + └── user-avatar.png +``` + +```tsx +import Image from 'next/image' + +export const UserAvatar = () => { + return ( + Аватар пользователя + ) +} +``` + +## Правила + +- Использовать `Image` из `next/image`, не обычный ``. +- Для контентных изображений всегда писать осмысленный `alt`. +- Для декоративных изображений использовать `alt=""`. +- Указывать `width` и `height`, если изображение не использует `fill`. +- При `fill` задавать `sizes` и контролировать размеры родителя стилями. +- `priority` ставить только для изображений первого экрана. +- SVG-иконки не оформлять как изображения — для них используется раздел [SVG-спрайты](/docs/applied/svg-sprites/svg-sprites-intro). + +## Пример с `fill` + +```tsx +import Image from 'next/image' +import styles from '../styles/article-card-cover.module.css' + +export const ArticleCardCover = () => { + return ( +
+ Обложка статьи +
+ ) +} +``` + +```css +.root { + position: relative; + aspect-ratio: 16 / 9; + overflow: hidden; +} +``` diff --git a/docs/docs/applied/localization.md b/docs/docs/applied/localization.md index e69de29..c65b7f6 100644 --- a/docs/docs/applied/localization.md +++ b/docs/docs/applied/localization.md @@ -0,0 +1,81 @@ +--- +title: Локализация +description: Как организовать локализацию как infrastructure-модуль. +--- + +# Локализация + +Как организовать локализацию как infrastructure-модуль. + +## Назначение + +Локализация — инфраструктурная подсистема приложения. Она отвечает за текущую локаль, словари, форматирование переводов и API для компонентов. + +Код локализации живёт в `src/infrastructure/i18n/`. Компоненты и модули не читают словари напрямую — они используют публичный API infrastructure-модуля. + +## Структура + +```text +src/infrastructure/i18n/ +├── config/ +│ └── i18n.config.ts +├── dictionaries/ +│ ├── ru.ts +│ └── en.ts +├── hooks/ +│ └── use-translation.hook.ts +├── providers/ +│ └── i18n-provider.tsx +├── types/ +│ └── i18n.type.ts +└── index.ts +``` + +Набор сегментов может отличаться, но публичная точка входа остаётся одна — `infrastructure/i18n`. + +## Подключение + +`app/` только подключает готовый провайдер локализации. Реализация провайдера, словари и конфиг остаются в `infrastructure/i18n/`. + +```tsx +// src/app/layout.tsx +import type { ReactNode } from 'react' +import { I18nProvider } from 'infrastructure/i18n' + +type RootLayoutProps = { + children: ReactNode +} + +export default function RootLayout({ children }: RootLayoutProps) { + return ( + + + {children} + + + ) +} +``` + +## Использование + +Компоненты получают переводы через готовый API модуля локализации: + +```tsx +import { useTranslation } from 'infrastructure/i18n' + +export const ProfileTitle = () => { + const { t } = useTranslation() + + return

{t('profile.title')}

+} +``` + +## Правила + +- Локализация живёт в `infrastructure/i18n/`. +- `app/` только подключает готовый provider и передаёт locale. +- Словари не импортируются напрямую в компоненты, screens или business-модули. +- Ключи переводов не собираются динамически из строк, если это ломает типизацию и поиск. +- Тексты интерфейса не хардкодятся в переиспользуемых компонентах, если они должны переводиться. +- Форматирование дат, чисел и валют должно проходить через API локализации или отдельные утилиты infrastructure-модуля. diff --git a/docs/docs/applied/module.md b/docs/docs/applied/module.md index ea399a7..d063468 100644 --- a/docs/docs/applied/module.md +++ b/docs/docs/applied/module.md @@ -1,110 +1,162 @@ --- title: Модуль -description: Как устроен и пишется React-компонент в проекте. +description: Как создавать и организовывать SLM-модули в проекте. --- # Модуль -Как устроен и пишется React-компонент в проекте. +Как создавать и организовывать SLM-модули в проекте. -## Правила организации +## Назначение -1. Один компонент — один файл. -2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы. -3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры. -4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены. +Модуль — основной строительный блок SLM-архитектуры. Это папка с публичным API (`index.ts`) и опциональными сегментами: компонентами, стилями, типами, хуками, сторами, сервисами и вложенными модулями. -## Базовая структура компонента +Если UI-сущность остаётся одним `.tsx` файлом и использует ресурсы родительского модуля — это [компонент](/docs/applied/component), а не модуль. Связанные файлы в `styles/` и `types/` родителя не создают новую модульную границу. -Минимальный набор файлов: компонент, стили, типы и публичный экспорт. +Архитектурное определение: [Модули SLM](/docs/basics/architecture/reference/modules). Список сегментов: [Сегменты SLM](/docs/basics/architecture/reference/segments). + +## Когда нужен модуль + +Создавайте модуль, если сущности нужны: + +- публичный API; +- хуки, сторы, сервисы, мапперы или утилиты; +- вложенные части; +- переиспользование вне родительского модуля; +- самостоятельная ответственность на слое. + +Если понадобилась папка вокруг компонента — это сигнал, что нужен модуль. + +## Где размещать + +Модуль размещается на самом низком уровне использования. + +- Нужен только одному модулю — размещается в `parts/` родителя. +- Нужен одной странице — размещается в `screens/{name}/parts/`. +- Нужен одному layout — размещается в `layouts/{name}/parts/`. +- Переиспользуется между страницами или layout — поднимается в `widgets/`. +- Представляет бизнес-домен — размещается в `business/`. +- Является UI-китом — размещается в `ui/`. + +`app/` не содержит модулей. Это слой файлового роутинга и инициализации. + +## Структура + +Минимальный UI-модуль: ```text -container/ -├── styles/ -│ └── container.module.css -├── types/ -│ └── container.type.ts -├── container.tsx +user/ +├── user.tsx └── index.ts ``` -## Именования +Модуль расширяется сегментами только при реальной потребности: -- Имя корневого css класса всегда `.root` -- Тип пропсов именуется `{ComponentName}Props`. -- Тип пользовательских параметров именуется `{ComponentName}Params`. +```text +user/ +├── ui/ +│ └── user-avatar.tsx +├── parts/ +│ └── user-posts/ +│ ├── user-posts.tsx +│ └── index.ts +├── styles/ +│ ├── user.module.css +│ └── user-avatar.module.css +├── types/ +│ ├── user.type.ts +│ └── user-avatar.type.ts +├── user.tsx +└── index.ts +``` -## Типизация +Корневой компонент опционален. Business- и infrastructure-модули могут состоять только из хуков, сервисов, типов и публичного API. -Структура типов компонента показана в [примере](#пример). Ниже — обоснования ключевых решений. +## `ui/` и `parts/` -- **`type` вместо `interface`** — гибче для пропсов: поддерживает union, intersection, mapped types. Declaration merging пропсам не нужно. -- **Без `FC`** — неявно добавляет `children`, усложняет дженерики, не даёт преимуществ перед аннотацией параметра. -- **Типы в `types/`, а не в `.tsx`** — предотвращает циклические зависимости (компонент импортирует хук, хук импортирует тип из компонента) и разделяет ответственность: `.tsx` для рендера, `.type.ts` для данных. -- **Без возвращаемого типа** — TypeScript выводит из JSX. Осознанное исключение из [базового правила](/docs/basics/typing). +`ui/` содержит только компоненты: отдельные `.tsx` файлы без собственных сегментов. -## Реализация +`parts/` содержит только модули: каждая запись внутри `parts/` — папка с собственным `index.ts`. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не кладутся. -- Пропсы деструктурируются в теле компонента, не в параметрах. -- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`. -- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`. -- `...htmlAttr` прокидывается на корневой элемент. +```text +user/ +├── ui/ +│ └── user-avatar.tsx # компонент +└── parts/ + └── user-posts/ # модуль + ├── styles/ + │ └── user-posts.module.css + ├── user-posts.tsx + └── index.ts +``` -## Пример +Если компоненту в `ui/` понадобились стили или типы, они добавляются в `styles/` и `types/` родительского модуля. Если компоненту нужны собственные хуки, вложенные части или публичная граница — он переносится в `parts/` как модуль. -`container/types/container.type.ts` +## Публичный API + +`index.ts` — единственная точка входа в модуль. Внешние импорты внутренних файлов запрещены. ```ts -import type { HTMLAttributes } from 'react' - -/** - * Параметры компонента Container. - */ -export type ContainerParams = {} - -/** HTML-атрибуты корневого элемента. */ -type RootAttrs = HTMLAttributes - -export type ContainerProps = RootAttrs & ContainerParams +// user/index.ts +export { User } from './user' +export type { UserProps } from './types/user.type' ``` -`container/styles/container.module.css` - -```css -.root { - max-width: var(--content-width); - margin: 0 auto; - padding: 0 var(--spacing-4); -} -``` - -`container/container.tsx` - -```tsx -import cl from 'clsx' -import type { ContainerProps } from './types/container.type' -import styles from './styles/container.module.css' - -/** - * Контейнер с адаптивной максимальной шириной. - * - * Используется для: - * - обёртки контента страниц с ограничением ширины - * - центрирования блоков в лейауте - */ -export const Container = (props: ContainerProps) => { - const { children, className, ...htmlAttr } = props - - return ( -
- {children} -
- ) -} -``` - -`container/index.ts` - ```ts -export { Container } from './container' +// Плохо: импорт в обход публичного API. +import { UserPosts } from 'screens/user/parts/user-posts/user-posts' + +// Хорошо: импорт через публичный API родительского модуля. +import { User } from 'screens/user' +``` + +Вложенный модуль имеет свой `index.ts`, но наружу родителя экспортируется только при необходимости. + +## Именование + +Базовые правила описаны в разделе [Именование](/docs/basics/naming). + +- Папка модуля — `kebab-case`: `user-posts/`. +- Файл корневого компонента повторяет имя папки: `user-posts/user-posts.tsx`. +- Корневые модули слоёв наследуют роль слоя в имени файла: `screens/profile/profile.screen.tsx`, `layouts/main/main.layout.tsx`. +- Корневой компонент именуется в `PascalCase`: `UserPosts`. +- Если имя без контекста слишком общее, добавляется префикс родителя или роль слоя: `ProfileUserPosts`, `ProfileScreen`, `MainLayout`. + +## Примеры + +### Screen-модуль + +```text +screens/profile/ +├── ui/ +│ └── profile-heading.tsx +├── parts/ +│ └── activity-feed/ +│ ├── styles/ +│ │ └── activity-feed.module.css +│ ├── activity-feed.tsx +│ └── index.ts +├── styles/ +│ ├── profile.module.css +│ └── profile-heading.module.css +├── types/ +│ ├── profile.type.ts +│ └── profile-heading.type.ts +├── profile.screen.tsx +└── index.ts +``` + +### Business-модуль без корневого компонента + +```text +business/auth/ +├── hooks/ +│ └── use-auth.hook.ts +├── services/ +│ └── auth.service.ts +├── stores/ +│ └── auth.store.ts +├── types/ +│ └── auth.type.ts +└── index.ts ``` diff --git a/docs/docs/applied/page-level.md b/docs/docs/applied/page-level.md index f7e1e48..b3079a5 100644 --- a/docs/docs/applied/page-level.md +++ b/docs/docs/applied/page-level.md @@ -1,31 +1,61 @@ --- title: Файлы роутинга -description: "Что должно лежать в файлах роутинга, а что — в экранах." +description: Как работать со страницами и другими файлами роутинга Next.js App Router. --- # Файлы роутинга -Что должно лежать в файлах роутинга, а что — в экранах. +Как работать со страницами и другими файлами роутинга Next.js App Router. -## Организация +## Назначение -- `page.tsx` — тонкий файл: только `metadata` и рендер экрана. Логика, стили и зависимости живут в экране, не в `page.tsx`. -- `error.tsx` и `not-found.tsx` делегируют разметку экранам по тому же принципу. -- `layout.tsx` — точка подключения провайдеров и глобальных стилей. Вёрстка layout-обёрток выносится в слой `layouts/`. -- Стили в файлах роутинга не используются — стилизация только внутри вызываемых компонентов. +`src/app/**` — точка входа приложения и слой файлового роутинга Next.js. -## Реализация +Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen. -- Каждый `page.tsx` экспортирует `metadata` с `title` — он подставляется в шаблон корневого layout (`%s | App`). -- Корневой `layout.tsx` задаёт `metadata` с `title.template`, `description`, `metadataBase` и OpenGraph-настройками. +Границы слоя описаны в [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app). -## Примеры +## Граница ответственности -`src/app/profile/[id]/page.tsx` +| Область | Где живёт | +|---|---| +| Файлы маршрутов (`page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`) | `src/app/**` | +| Параметры маршрута, `metadata`, `redirect()`, `notFound()` | `src/app/**` | +| Серверные запросы для первого рендера | `src/app/**`, через готовые клиенты и сервисы нижних слоёв | +| Прогрев SWR-кеша, начальное состояние, подключение провайдеров | `src/app/**`, только через готовые обёртки из нижних слоёв | +| UI страницы | `screens/` | +| Каркас страницы: header, footer, sidebar | `layouts/` | +| Провайдеры, сторы, хуки, API-клиенты, сервисы | нижние слои (`screens/`, `business/`, `infrastructure/`, `shared/`) | +| CSS Modules и стили компонентов | рядом с компонентами, не в `src/app/**` | + +## Что можно делать в `page.tsx` + +- Экспортировать `metadata` или `generateMetadata`. +- Читать `params` и `searchParams`. +- Нормализовать и валидировать параметры маршрута. +- Делать серверные запросы для первого рендера через готовые клиенты или сервисы. +- Вызывать `redirect()` и `notFound()`. +- Готовить начальные данные для screen. +- Готовить SWR `fallback` и передавать его в готовый провайдер. +- Подключать готовый провайдер стора страницы и передавать начальное состояние. +- Рендерить screen или композицию из готовых обёрток и screen. + +## Что запрещено + +- Писать UI-разметку страницы прямо в файле роутинга. +- Создавать локальные компоненты внутри `src/app/**`. +- Добавлять CSS Modules, стили компонентов, `components/`, `styles/`, `hooks/`, `stores/`, `services/` внутри `src/app/**`. +- Реализовывать провайдеры, сторы, хуки, API-клиенты или сервисы в файлах роутинга. +- Размещать бизнес-логику, мапперы и правила предметной области в файлах роутинга. +- Вызывать `useSWR` и доменные клиентские хуки в файлах роутинга. + +## Страницы + +Страница объявляется через `export default function`. Для серверных запросов используется `async function`. ```tsx import type { Metadata } from 'next' -import { ProfileScreen } from '@/screens/profile' +import { ProfileScreen } from 'screens/profile' export const metadata: Metadata = { title: 'Профиль', @@ -43,12 +73,101 @@ export default async function ProfilePage({ params }: ProfilePageProps) { } ``` -`src/app/error.tsx` +## Данные первого рендера + +Если данные нужны до первого рендера, `page.tsx` получает их на сервере и передаёт в screen. Сам запрос выполняется через готовый клиент или сервис нижнего слоя. + +```tsx +import { notFound } from 'next/navigation' +import { userApi } from 'infrastructure/backend-api' +import { UserScreen } from 'screens/user' + +type UserPageProps = { + params: Promise<{ id: string }> +} + +export default async function UserPage({ params }: UserPageProps) { + const { id } = await params + const user = await userApi.users.get(id) + + if (!user) { + notFound() + } + + return +} +``` + +Если данные нужны нескольким клиентским SWR-хукам, файл роутинга может обернуть дерево в `SWRConfig` и передать `fallback`. Запросы стартуют на сервере, а клиентские хуки получают готовые данные из кеша. + +Ключи `fallback` должны совпадать с ключами внутри готовых SWR-хуков. + +```tsx +import type { ReactNode } from 'react' +import { SWRConfig } from 'swr' +import { backendApi } from 'infrastructure/backend-api' + +type FeedLayoutProps = { + children: ReactNode +} + +export default async function FeedLayout({ children }: FeedLayoutProps) { + const userPromise = backendApi.user.getCurrent() + const postsPromise = backendApi.posts.list() + + return ( + + {children} + + ) +} +``` + +Подробнее о серверных запросах и SWR-кеше: [REST → Серверные компоненты](/docs/data/rest/fetching/server), [REST → Клиентские компоненты](/docs/data/rest/fetching/client). + +## Инициализация состояния + +Файл роутинга может подключить готовый провайдер стора страницы, если состояние зависит от маршрута или данных первого рендера. Реализация стора и провайдера не размещается в `src/app/**`. + +```tsx +import { ProfileScreen, ProfileStoreProvider } from 'screens/profile' + +type ProfilePageProps = { + params: Promise<{ id: string }> +} + +export default async function ProfilePage({ params }: ProfilePageProps) { + const { id } = await params + + return ( + + + + ) +} +``` + +## Layout + +`layout.tsx` подключает готовую инициализацию приложения: глобальные стили, провайдеры и верхнеуровневые обёртки из нижних слоёв. + +Вёрстка layout-каркаса выносится в слой `layouts/`. Реализация провайдеров, стилей и UI не размещается в `app/`. + +## Error и Not Found + +`error.tsx` и `not-found.tsx` делегируют разметку готовым screen или widget. В файле роутинга остаётся только адаптация API Next.js к пропсам нижнего слоя. ```tsx 'use client' -import { ErrorScreen } from '@/screens/error' +import { ErrorScreen } from 'screens/error' type ErrorPageProps = { error: Error & { digest?: string } diff --git a/docs/docs/applied/project-structure.md b/docs/docs/applied/project-structure.md index ce77fe2..5abdd1d 100644 --- a/docs/docs/applied/project-structure.md +++ b/docs/docs/applied/project-structure.md @@ -41,7 +41,7 @@ public/ ```text src/ -├── app/ # Роутинг Next.js, провайдеры, глобальные стили +├── app/ # Роутинг Next.js и точка входа приложения ├── layouts/ # Каркасы страниц (header, footer, sidebar) ├── screens/ # Контент конкретной страницы ├── widgets/ # Составные блоки интерфейса, не привязанные к домену @@ -55,12 +55,13 @@ src/ ### Папка `app/` -Точка входа приложения: инициализация (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты). +Точка входа приложения и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты). +`app/` подключает готовую инициализацию из нижних слоёв, но не реализует провайдеры, стили, UI-компоненты, хуки, сторы или сервисы. + +Подробнее о границах слоя: [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app). ```text src/app/ -├── providers/ # Провайдеры приложения -├── styles/ # Глобальные стили ├── layout.tsx # Корневой layout └── page.tsx # Главная страница ``` diff --git a/docs/docs/applied/styles/styles-usage.md b/docs/docs/applied/styles/styles-usage.md index 2c96a27..d7f1405 100644 --- a/docs/docs/applied/styles/styles-usage.md +++ b/docs/docs/applied/styles/styles-usage.md @@ -12,6 +12,7 @@ description: Как пишутся стили в проекте. - Только **PostCSS** и **CSS Modules** для кастомной стилизации. - Подход **Mobile First** — стили пишутся от мобильных к десктопу. - Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`). +- Корневой класс каждого CSS Module компонента всегда называется `.root` — это упрощает ориентацию в DevTools и отладку DOM. - Модификаторы — отдельный класс с `_`, применяется через `&._modifier`. **Хорошо** @@ -143,13 +144,13 @@ description: Как пишутся стили в проекте. ## CSS-переменные -- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `app/styles/variables.css` через `:root`. -- Файл переменных подключается один раз в корневом layout/entry point — после этого переменные доступны глобально через каскад. +- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `src/shared/styles/variables.css` через `:root`. +- Файл переменных подключается через `src/shared/styles/global.css`, который импортируется один раз в `src/app/layout.tsx`. - Не дублировать магические значения в компонентах. **Хорошо** ```css -/* app/styles/variables.css */ +/* src/shared/styles/variables.css */ :root { --color-primary: #3b82f6; --color-bg: #ffffff; @@ -183,11 +184,11 @@ description: Как пишутся стили в проекте. ## Custom Media -- Breakpoints определяются через Custom Media Queries в `app/styles/media.css`. +- Breakpoints определяются через Custom Media Queries в `src/shared/styles/media.css`. - Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей. ```css -/* app/styles/media.css */ +/* src/shared/styles/media.css */ @custom-media --sm (min-width: 36em); @custom-media --md (min-width: 62em); @custom-media --lg (min-width: 82em); diff --git a/docs/docs/applied/video.md b/docs/docs/applied/video.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/docs/basics/architecture/reference/segments.md b/docs/docs/basics/architecture/reference/segments.md index 22eb7b0..45af86b 100644 --- a/docs/docs/basics/architecture/reference/segments.md +++ b/docs/docs/basics/architecture/reference/segments.md @@ -15,7 +15,7 @@ description: Что такое сегмент модуля в SLM-архитек | Сегмент | Содержимое | |---------|------------| -| `ui/` | Компоненты модуля — только `.tsx` файлы | +| `ui/` | Вспомогательные компоненты модуля — только `.tsx` файлы | | `parts/` | Вложенные модули со своими сегментами | | `hooks/` | React-хуки | | `stores/` | Сторы состояния | @@ -28,16 +28,18 @@ description: Что такое сегмент модуля в SLM-архитек ## Сегмент ui/ -Компоненты, принадлежащие модулю. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков. Использует сегменты родительского модуля. +Вспомогательные компоненты модуля. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков и публичного API. Использует сегменты родительского модуля. + +Корневой компонент модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`. ```text -auth/ +user/ ├── ui/ -│ ├── auth-provider.tsx -│ ├── auth-guard.tsx -│ └── logout-button.tsx +│ ├── user-avatar.tsx +│ └── user-status.tsx ├── types/ ├── hooks/ +├── user.tsx └── index.ts ``` @@ -45,7 +47,7 @@ auth/ ## Сегмент parts/ -Вложенные модули со своими сегментами. Каждый элемент `parts/` — полноценный модуль: папка с компонентом, хуками, стилями, типами и т.д. +Вложенные модули со своими сегментами. `parts/` содержит только модули: каждый элемент `parts/` — папка полноценного модуля с собственным публичным API. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не размещаются. ```text home/ @@ -53,17 +55,20 @@ home/ │ ├── hero-section/ │ │ ├── hero-section.tsx │ │ ├── styles/ -│ │ └── parts/ -│ │ └── top-banner/ -│ │ └── top-banner.tsx +│ │ ├── parts/ +│ │ │ └── top-banner/ +│ │ │ ├── top-banner.tsx +│ │ │ └── index.ts +│ │ └── index.ts │ └── features-section/ │ ├── features-section.tsx -│ └── hooks/ +│ ├── hooks/ +│ └── index.ts ├── home.screen.tsx └── index.ts ``` -Отличие от `ui/`: элемент `parts/` — модуль со своими сегментами. Элемент `ui/` — компонент, один `.tsx` файл. +Отличие от `ui/`: элемент `parts/` — модульная папка со своими сегментами. Элемент `ui/` — вспомогательный компонент, один `.tsx` файл. Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке. diff --git a/docs/docs/basics/naming.md b/docs/docs/basics/naming.md index 71e4a45..096dffb 100644 --- a/docs/docs/basics/naming.md +++ b/docs/docs/basics/naming.md @@ -34,6 +34,12 @@ description: Как называть переменные, файлы и про - `.store.ts` — стор - `.service.ts` — сервис +**Корневые компоненты слоёв** +- `.screen.tsx` — корневой компонент screen-модуля: `screens/profile/profile.screen.tsx`, компонент `ProfileScreen` +- `.layout.tsx` — корневой компонент layout-модуля: `layouts/main/main.layout.tsx`, компонент `MainLayout` + +Обычные и вложенные модули не получают суффикс слоя: `ui/button/button.tsx`, `screens/profile/parts/activity-feed/activity-feed.tsx`. + **Типы и контракты** - `.type.ts` — типы и интерфейсы - `.interface.ts` — интерфейсы diff --git a/docs/docs/data/index.md b/docs/docs/data/index.md index 5bf39e2..cf21259 100644 --- a/docs/docs/data/index.md +++ b/docs/docs/data/index.md @@ -48,4 +48,4 @@ keywords: [данные, api, rest, realtime, клиент, swr, infrastructure, - **Глобальное состояние UI** — Stores, формы, фичефлаги. Это [Stores](/docs/applied/stores). - **Доменная логика** — как данные превращаются в сценарии бизнеса. Это слой `business/` в [Архитектуре](/docs/basics/architecture/). -- **Хуки общего назначения** — переиспользуемые хуки UI, не привязанные к конкретному API. Это [Хуки](/docs/applied/hooks). +- **Хуки общего назначения** — переиспользуемые хуки UI, не привязанные к конкретному API. Отдельный прикладной раздел для них пока не ведётся.