Compare commits
23 Commits
dadfa83df5
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
| 47658cdbb9 | |||
| 4aeb1dd6b2 | |||
| 436c87a986 | |||
| be3d86f198 | |||
| 073fc6507f | |||
| cba311d78e | |||
| 11f9b702e0 | |||
| f7d3506a91 | |||
| be8e89fccd | |||
| fbac3e1a55 | |||
| 6ccc4a0d06 | |||
| 4ae6ac893d | |||
| 965235e390 | |||
| e608017dce | |||
| 29bcf23dde | |||
| c46b843670 | |||
| 2d1f3b9df9 | |||
| 2bf34e6f79 | |||
| 909ce71931 | |||
| e337ec78fa | |||
| 3993909b98 | |||
| 43f2d92201 | |||
| bc01cb930a |
@@ -73,7 +73,7 @@ jobs:
|
||||
ssh -i ~/.ssh/deploy_key root@188.225.47.78 bash -s <<'SCRIPT'
|
||||
set -e
|
||||
IMAGE="${{ env.REGISTRY_IMAGE }}:latest"
|
||||
CONTAINER="nextjs-style-guide"
|
||||
CONTAINER="frontend-style-guide"
|
||||
|
||||
# Логин в реестр
|
||||
echo '${{ secrets.CR_TOKEN }}' | docker login ${{ env.DOCKER_REGISTRY }} -u '${{ secrets.CR_USER }}' --password-stdin
|
||||
|
||||
31
.vitepress/cache/deps/_metadata.json
vendored
31
.vitepress/cache/deps/_metadata.json
vendored
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"hash": "e66d10e4",
|
||||
"configHash": "bca2cdcc",
|
||||
"lockfileHash": "5778a81f",
|
||||
"browserHash": "5fea5472",
|
||||
"optimized": {
|
||||
"vue": {
|
||||
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
||||
"file": "vue.js",
|
||||
"fileHash": "cabb4131",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vue/devtools-api": {
|
||||
"src": "../../../node_modules/@vue/devtools-api/dist/index.js",
|
||||
"file": "vitepress___@vue_devtools-api.js",
|
||||
"fileHash": "66e76a7b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vueuse/core": {
|
||||
"src": "../../../node_modules/@vueuse/core/index.mjs",
|
||||
"file": "vitepress___@vueuse_core.js",
|
||||
"fileHash": "6d04ab1e",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"chunk-EAEFJUV4": {
|
||||
"file": "chunk-EAEFJUV4.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
12644
.vitepress/cache/deps/chunk-EAEFJUV4.js
vendored
12644
.vitepress/cache/deps/chunk-EAEFJUV4.js
vendored
File diff suppressed because it is too large
Load Diff
7
.vitepress/cache/deps/chunk-EAEFJUV4.js.map
vendored
7
.vitepress/cache/deps/chunk-EAEFJUV4.js.map
vendored
File diff suppressed because one or more lines are too long
3
.vitepress/cache/deps/package.json
vendored
3
.vitepress/cache/deps/package.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
4505
.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
4505
.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
9731
.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
9731
.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
343
.vitepress/cache/deps/vue.js
vendored
343
.vitepress/cache/deps/vue.js
vendored
@@ -1,343 +0,0 @@
|
||||
import {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBaseVNode,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
} from "./chunk-EAEFJUV4.js";
|
||||
export {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createBaseVNode as createElementVNode,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
};
|
||||
//# sourceMappingURL=vue.js.map
|
||||
7
.vitepress/cache/deps/vue.js.map
vendored
7
.vitepress/cache/deps/vue.js.map
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [],
|
||||
"sourcesContent": [],
|
||||
"mappings": "",
|
||||
"names": []
|
||||
}
|
||||
@@ -9,9 +9,9 @@ const ruSidebar = [
|
||||
text: 'Базовые правила',
|
||||
items: [
|
||||
{ text: 'Технологии и библиотеки', link: '/basics/tech-stack' },
|
||||
{ text: 'Именование', link: '/basics/naming' },
|
||||
{ text: 'Архитектура', link: '/basics/architecture' },
|
||||
{ text: 'Стиль кода', link: '/basics/code-style' },
|
||||
{ text: 'Именование', link: '/basics/naming' },
|
||||
{ text: 'Документирование', link: '/basics/documentation' },
|
||||
{ text: 'Типизация', link: '/basics/typing' },
|
||||
],
|
||||
@@ -19,10 +19,9 @@ const ruSidebar = [
|
||||
{
|
||||
text: 'Прикладные разделы',
|
||||
items: [
|
||||
{ text: 'Настройка VS Code', link: '/applied/vscode' },
|
||||
{ text: 'Структура проекта', link: '/applied/project-structure' },
|
||||
{ text: 'Компоненты', link: '/applied/components' },
|
||||
{ text: 'Page-level компоненты', link: '/applied/page-level' },
|
||||
{ text: 'Страницы (App Router)', link: '/applied/page-level' },
|
||||
{ text: 'Шаблоны и генерация кода', link: '/applied/templates-generation' },
|
||||
{ text: 'Стили', link: '/applied/styles' },
|
||||
{ text: 'Изображения', link: '/applied/images-sprites' },
|
||||
@@ -33,6 +32,7 @@ const ruSidebar = [
|
||||
{ text: 'Хуки', link: '/applied/hooks' },
|
||||
{ text: 'Шрифты', link: '/applied/fonts' },
|
||||
{ text: 'Локализация', link: '/applied/localization' },
|
||||
{ text: 'Настройка VS Code', link: '/applied/vscode' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
41
AGENTS.md
41
AGENTS.md
@@ -1,32 +1,13 @@
|
||||
# NextJS Style Guide — правила для агентов
|
||||
# Правила для агентов
|
||||
|
||||
Это проект документации (VitePress). Агент является основным писателем контента в этом проекте — записывает, оформляет и редактирует материал по указаниям пользователя.
|
||||
При работе с документацией следовать правилам из CONTRIBUTING.md.
|
||||
|
||||
## Документация
|
||||
|
||||
### Tip-блоки со ссылками
|
||||
При создании или редактировании документации добавлять tip-блоки (`::: tip`)
|
||||
с ссылками на связанные разделы, где можно найти развёрнутое описание
|
||||
процесса, действия или настройки.
|
||||
|
||||
Формат:
|
||||
```
|
||||
::: tip Заголовок блока
|
||||
Описание — [Название раздела](/путь).
|
||||
:::
|
||||
```
|
||||
|
||||
Заголовок обязателен — он должен кратко описывать о чём блок.
|
||||
Описание должно объяснять что найдёт читатель по ссылке.
|
||||
|
||||
### Структура разделов
|
||||
- **Workflow** — порядок действий ("что делать и в каком порядке")
|
||||
- **Базовые правила** — стандарты и конвенции ("каким должен быть код")
|
||||
- **Прикладные разделы** — конфигурация и устройство конкретной области ("как это настроить и использовать")
|
||||
|
||||
Не дублировать информацию между разделами — использовать ссылки.
|
||||
|
||||
### Единообразие
|
||||
- Заголовок страницы (h1) совпадает с названием в sidebar.
|
||||
- Описание раздела (текст после h1) раскрывает смысл через "Как...".
|
||||
- Не описывать инструменты генерации в каждом разделе — ссылаться на прикладной раздел "Шаблоны и генерация кода".
|
||||
- Язык документации и коммитов — русский.
|
||||
- Исходники документации — в `src/`, только `.md` файлы.
|
||||
- Скрипты и манифесты сборки — в `scripts/`.
|
||||
- Общие правила — в `src/base/`.
|
||||
- Фреймворк-специфичные — в `src/{framework}/`.
|
||||
- Точки входа (`DEVELOP.md`, `REVIEW.md`) — в `src/{framework}/`.
|
||||
- После изменений в `.md`-файлах — запустить `npm run build:ai` для пересборки `dist/ai/`.
|
||||
- При добавлении нового раздела — добавить файл в `src/` и путь в манифест `scripts/{fw}.build.js`.
|
||||
- Frontmatter каждого `.md`-файла содержит поля `title`, `scope`, `keywords`, `when`.
|
||||
|
||||
155
CONTRIBUTING.md
Normal file
155
CONTRIBUTING.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Правила написания документации
|
||||
|
||||
Как писать и редактировать разделы стайлгайда.
|
||||
|
||||
## Типы разделов
|
||||
|
||||
### Базовые правила (`basics/`)
|
||||
|
||||
**Отвечает на вопрос:** «Каким должен быть любой код?»
|
||||
|
||||
Универсальные стандарты, не привязанные к конкретной области.
|
||||
Правило базовое, если оно применимо ко всему коду одинаково.
|
||||
|
||||
**Граница:** если правило касается только одной области — оно прикладное.
|
||||
|
||||
### Прикладные разделы (`applied/`)
|
||||
|
||||
**Отвечает на вопрос:** «Как работать с X?»
|
||||
|
||||
Полное описание конкретной области: структура файлов, правила, именование, типизация, примеры.
|
||||
|
||||
**Граница:** не дублирует базовые правила. Если правило уже описано в базовых — ссылается, но не повторяет.
|
||||
|
||||
### Триггеры (`triggers/`)
|
||||
|
||||
**Отвечает на вопрос:** «Как выполнить задачу X?»
|
||||
|
||||
Конкретная инструкция: какие разделы прочитать, какие шаги выполнить. Триггер ссылается на basics/ и applied/, но не дублирует их. Группируются по роли: `triggers/develop/`, `triggers/review/`, `triggers/architect/`.
|
||||
|
||||
Структура триггера:
|
||||
|
||||
- **Заголовок** — глагол + объект ("Создать компонент", "Добавить иконку")
|
||||
- **Описание** — одно предложение: что делает триггер
|
||||
- **Прочитай перед началом** — ссылки на basics/ и applied/
|
||||
- **Шаги** — нумерованный список действий со ссылками
|
||||
- **Смежные триггеры** — ссылки на связанные задачи
|
||||
- **Проверь себя** — чеклист из 2-5 пунктов для самопроверки
|
||||
|
||||
### Фреймворк-специфичные (`{framework}/`)
|
||||
|
||||
Разделы и триггеры, которые применимы только к конкретному фреймворку. Те же категории — `applied/` и `triggers/`.
|
||||
|
||||
**Граница:** если правило одинаково для всех фреймворков — оно в `base/`.
|
||||
|
||||
## Frontmatter
|
||||
|
||||
Каждый `.md`-файл начинается с YAML frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Название раздела
|
||||
scope: basics | applied | triggers
|
||||
keywords: [ключевое слово 1, ключевое слово 2]
|
||||
when: "Когда агенту читать этот раздел"
|
||||
---
|
||||
```
|
||||
|
||||
| Поле | Описание |
|
||||
|------|----------|
|
||||
| `title` | Название раздела. Совпадает с `h1` в файле |
|
||||
| `scope` | Тип: `basics`, `applied` или `triggers` |
|
||||
| `keywords` | Ключевые слова для поиска агентом |
|
||||
| `when` | Описание ситуации, когда раздел релевантен |
|
||||
|
||||
## Структура прикладного раздела
|
||||
|
||||
Раздел включает только релевантные секции — пустые не создаются.
|
||||
|
||||
```markdown
|
||||
# {Название}
|
||||
|
||||
Краткое описание: о чём раздел.
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
Неочевидная вводная информация (если есть).
|
||||
|
||||
## Структура
|
||||
|
||||
Файловая организация. Обязательно — дерево файлов.
|
||||
|
||||
## Правила
|
||||
|
||||
### Реализация
|
||||
|
||||
Как писать код: синтаксис, паттерны, API.
|
||||
|
||||
### Организация
|
||||
|
||||
Где что лежит: файловые границы, зоны ответственности, экспорт.
|
||||
|
||||
## Именование
|
||||
|
||||
Специфичные для области соглашения (не покрытые в basics/naming).
|
||||
|
||||
## Типизация
|
||||
|
||||
Специфичные для области правила (не покрытые в basics/typing).
|
||||
|
||||
## Документирование
|
||||
|
||||
Специфичные для области правила (не покрытые в basics/documentation).
|
||||
|
||||
## Примеры
|
||||
|
||||
Полноценные примеры кода с путями к файлам.
|
||||
```
|
||||
|
||||
Порядок фиксированный: контекст -> структура -> правила -> специализации базовых -> примеры.
|
||||
|
||||
## Конвенции оформления
|
||||
|
||||
### Заголовки
|
||||
|
||||
- Один `h1` на файл — совпадает с `title` из frontmatter.
|
||||
- Сразу после `h1` — вводный абзац.
|
||||
- Основные секции — `h2`. Подсекции — `h3`. `h4` не используется.
|
||||
|
||||
### Примеры кода
|
||||
|
||||
- Блоки кода с указанием языка: ` ```tsx `, ` ```css `, ` ```bash `, ` ```text `.
|
||||
- Путь к файлу — перед блоком кода или комментарием внутри.
|
||||
- Дерево файлов — ` ```text ` с символами `├──`, `└──`, `│`.
|
||||
|
||||
### Блоки «Хорошо / Плохо»
|
||||
|
||||
```markdown
|
||||
**Хорошо:**
|
||||
|
||||
\`\`\`tsx
|
||||
// правильный код
|
||||
\`\`\`
|
||||
|
||||
**Плохо:**
|
||||
|
||||
\`\`\`tsx
|
||||
// неправильный код
|
||||
\`\`\`
|
||||
```
|
||||
|
||||
### Таблицы
|
||||
|
||||
Формат — стандартный Markdown: `| Ключ | Описание |`.
|
||||
|
||||
### Ссылки между разделами
|
||||
|
||||
Ссылаться можно, дублировать содержимое — нет.
|
||||
|
||||
## Принципы
|
||||
|
||||
1. **Не дублировать.** Одна мысль — одно место. Остальные ссылаются.
|
||||
2. **Базовое vs прикладное.** Применимо ко всему коду — базовое. К одной области — прикладное.
|
||||
3. **Общее vs специфичное.** Одинаково для всех фреймворков — в `base/`. Для одного — в `{framework}/`.
|
||||
4. **Пустые секции не создавать.**
|
||||
5. **Примеры обязательны.** Прикладной раздел без примеров — незавершён.
|
||||
@@ -1,19 +0,0 @@
|
||||
# Ассистент
|
||||
|
||||
## Для ассистента
|
||||
|
||||
- Всегда используй Русский язык для общения и генерации документации/комментариев/коммитов.
|
||||
- Всегда следуй этим правилам при генерации кода и ответах.
|
||||
- Всегда пиши план действий перед генерацией кода.
|
||||
- Всегда спрашивай разрешения у пользователя перед генерацией кода.
|
||||
- Всегда проверяй, что код соответствует линтингу и форматированию.
|
||||
- Всегда сверяйся с чек-листом при генерации кода.
|
||||
- Не предлагай решения, которые противоречат этим правилам этого файла.
|
||||
- Если не уверен — уточни у пользователя, не гадай, не придумывай.
|
||||
|
||||
## Обязательность чек-листов
|
||||
|
||||
- Все чек-листы, приведённые в правилах, обязательны к исполнению.
|
||||
- Ассистент обязан сверяться с чек-листом при выполнении любой задачи, связанной с кодом.
|
||||
- Нельзя сокращать, игнорировать или опускать пункты чек-листа — каждый пункт должен быть выполнен или явно отмечен как невыполнимый с объяснением причины.
|
||||
- В каждом ответе, связанном с генерацией или изменением кода, ассистент обязан ссылаться на соответствующий чек-лист и подтверждать его выполнение.
|
||||
@@ -1,84 +0,0 @@
|
||||
---
|
||||
title: Stores
|
||||
---
|
||||
|
||||
# Stores
|
||||
|
||||
## Сторы (Stores)
|
||||
|
||||
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению сторов. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, удобство поддержки и единый стиль работы с состоянием в проекте.
|
||||
> В проекте для организации состояния используется только библиотека Zustand.
|
||||
|
||||
### Структура
|
||||
- Store размещается в файле `<store-name>.store.ts` в папке `stores/` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- Интерфейс состояния описывается в этом же файле с суффиксом `State` (PascalCase).
|
||||
- Для каждого store создаётся отдельный хук доступа (например, `useTodoStore`).
|
||||
- Для глобальных сторов используйте только `shared/store`.
|
||||
|
||||
### Именование
|
||||
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
|
||||
- Файл store — `<store-name>.store.ts` (kebab-case).
|
||||
- Имя интерфейса состояния — PascalCase с суффиксом `State`.
|
||||
- Имя хука — camelCase с префиксом `use`.
|
||||
|
||||
### Требования
|
||||
- В store допускается только хранение состояния и методы управления им, без бизнес-логики, асинхронных операций и side-effects (см. раздел "Правила организации и использовалья Store").
|
||||
- Для методов, изменяющих состояние через set, если используется функция — тело функции в фигурных скобках, return с новой строки после стрелки.
|
||||
- Не дублируйте логику между сторами.
|
||||
|
||||
### Типизация
|
||||
- Всегда указывайте типы для всех полей состояния и методов.
|
||||
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
|
||||
|
||||
### Документирование
|
||||
- Документируйте только назначение store и смысл полей, строго по [правилам документирования кода](#правило-для-документирования-кода).
|
||||
|
||||
### Экспорт
|
||||
- Экспортируйте хук доступа к store и интерфейс состояния через `index.ts` слоя/компонента.
|
||||
|
||||
### Примеры
|
||||
|
||||
```ts
|
||||
import { create } from 'zustand';
|
||||
import { TodoItem } from './types/todo-item.interface';
|
||||
|
||||
/**
|
||||
* Состояние хранилища задач.
|
||||
*/
|
||||
export interface TodoStoreState {
|
||||
/** Массив задач. */
|
||||
items: TodoItem[];
|
||||
/** Добавить задачу. */
|
||||
addTodo: (item: TodoItem) => void;
|
||||
/** Удалить задачу. */
|
||||
removeTodo: (id: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Хук для доступа к хранилищу задач.
|
||||
*/
|
||||
export const useTodoStore = create<TodoStoreState>((set) => ({
|
||||
items: [],
|
||||
addTodo: (item) => set((state) => {
|
||||
return {
|
||||
items: [...state.items, item],
|
||||
};
|
||||
}),
|
||||
removeTodo: (id) => set((state) => {
|
||||
return {
|
||||
items: state.items.filter((t) => t.id !== id),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
```
|
||||
|
||||
### Чек-лист
|
||||
|
||||
- [ ] Store размещён в `stores/<store-name>.store.ts` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
|
||||
- [ ] Все поля и методы строго типизированы (см. [общие правила типизации](#общие-правила-типизации)).
|
||||
- [ ] В store только состояние и методы управления им, без бизнес-логики и side-effects.
|
||||
- [ ] Для методов, изменяющих состояние через set, используется функция с return с новой строки.
|
||||
- [ ] Документировано только назначение store и смысл полей (см. [правила документирования кода](#правило-для-документирования-кода)).
|
||||
- [ ] Нет неиспользуемого или невалидного кода.
|
||||
- [ ] Экспорт через индексный файл.
|
||||
@@ -1,227 +0,0 @@
|
||||
---
|
||||
title: CSS
|
||||
---
|
||||
|
||||
# CSS
|
||||
|
||||
## Правила оформления и стилизации CSS-кода
|
||||
|
||||
- **Препроцессоры**
|
||||
Используй PostCSS и модули для стилизации.
|
||||
|
||||
- **Архитектура написания стилей**
|
||||
Используй подход **Mobile First**
|
||||
Используй CSS переменные для стилизации.
|
||||
Используй Custom Media Queries для адаптивных стилей.
|
||||
Используй BEM для именования классов.
|
||||
Между каждым CSS-правилом (селектором) должен быть один пустой сброс строки, пример:
|
||||
```css
|
||||
.todo-list {
|
||||
max-width: 600px;
|
||||
padding: var(--space-3);
|
||||
|
||||
@media (--md) {
|
||||
max-width: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
.todo-list__text {
|
||||
font-size: 18px;
|
||||
|
||||
@media (--md) {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
```
|
||||
Запрещено писать правила подряд без пустой строки:
|
||||
```css
|
||||
/* Так делать нельзя! */
|
||||
.todo-list { ... }
|
||||
.todo-list__text { ... }
|
||||
```
|
||||
|
||||
- **Методология именования классов**
|
||||
Использовать методологию **BEM** для именования классов.
|
||||
- Блок: kebab-case, пример `.user-bar { }`
|
||||
- Елемент: kebab-case, соеденный с блоком двойным нижним подчеркиванием, пример `.user-bar__slide { }`
|
||||
- Модификатор: kebab-case, отдельный самостоятельный класс, **не соединяется** с блоком/елементом, имя модификатора всегда начинается с нижнего подчеркивания, пример: `._red { }`
|
||||
|
||||
- **Единицы измерения**
|
||||
Используй `px` как основная единица измирения, так-же допускается использовать остальные единицы измерения если того требует реализуемый дизайн.
|
||||
|
||||
- **Импорт стилей**
|
||||
Стили компонента должны импортироваться только внутри соответствующего компонента.
|
||||
Запрещено импортировать стили одного компонента в другой.
|
||||
Запрещено импортировать `css переменные` в файлы стилей, они доступны глобально.
|
||||
Запрещено импортировать `custom media` в файлы стилей, они доступны глобально.
|
||||
|
||||
- **Переменные**
|
||||
Все значения переменных нужно писать в `/shared/styles` или в Mantine ThemeProvider.
|
||||
Все что не является цветами, брекпоинтами, отступами, скруглением допускаются использоваться в компонентах.
|
||||
Обязательное создавай CSS перменные для:
|
||||
- "Цветов", пример: `--color-danger: red;`.
|
||||
- "Брекпоинты", описываем в (Сustom media) пример: `@custom-media --md (min-width: 62em);`.
|
||||
- "Отспупы (--space)", , пример: `--space-1: 4px;`, `--space-2: 8px;`, `--space-3: 12px;` итд..
|
||||
- "Скругление углов (--radius)", пример: `--radius-1: 4px;`,`--radius-2: 8px;`,`--radius-3: 12px;` итд..
|
||||
|
||||
- **Вложенность селекторов**
|
||||
Запрещено использовать вложенность селекторов.
|
||||
Разрешено использовать вложенность только для:
|
||||
- Псевдо-классов `:hover`, `:active` итд..
|
||||
- Псевдо-елементов `::before`, `::after`
|
||||
- Медиа запросов `@media`
|
||||
- Классы **модификаторы** по методологии BEM
|
||||
Каждый вложенный селектор отделяется 1 пустой строкой.
|
||||
|
||||
- **Медиа запросы**
|
||||
Строго запрещено использовать `@media` без вложения в селектор.
|
||||
Строго запрещено использовать в теле `@media` любые селекторы.
|
||||
Разрешено использовать только Custom Media Queries (например, `@media (--md) {}`).
|
||||
Запрещено использовать любые произвольные значения breakpoints (например, max-width: 768px).
|
||||
**Пример как правильно писать @media**
|
||||
```css
|
||||
.todo-list {
|
||||
max-width: 600px;
|
||||
padding: 24px;
|
||||
|
||||
@media (--md) {
|
||||
max-width: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
.todo-list__text {
|
||||
font-size: 18px;
|
||||
|
||||
@media (--md) {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
**Пример как неправильно писать @media**
|
||||
```css
|
||||
// Медиа запрос не вложен в селектор
|
||||
@media (--md) {
|
||||
.todo-list {
|
||||
max-width: 600px;
|
||||
padding: 24px;
|
||||
}
|
||||
.todo-list__text {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
// Используется стандартный `min-width: 992px` вмето Custom Media Queries
|
||||
@media (min-width: 992px) {
|
||||
// Внутри @media запроса используются селекторы
|
||||
.todo-list {
|
||||
max-width: 600px;
|
||||
padding: 24px;
|
||||
}
|
||||
.todo-list__text {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Глобальные стили и сбросы**
|
||||
Все глобальные стили (например, сбросы) должны располагаться в отдельном файле, например, `src/app/styles/global.css`.
|
||||
|
||||
- **Использование Mantine и PostCSS**
|
||||
Для стандартных визуальных компонентов (кнопки, инпуты, layout, grid, notifications и т.д.) использовать только Mantine и его ThemeProvider.
|
||||
Запрещено использовать в Mantine компонентах его props/styling, вмето этого нужно добавлять кастомные стили PostCSS.
|
||||
Кастомные стили допускаются только в случае, если требуемый дизайн невозможно реализовать средствами Mantine.
|
||||
При написании кастомных стилей стараться использовать переменные и токены Mantine, если это возможно.
|
||||
|
||||
- **Порядок CSS-свойств**
|
||||
В стилях рекомендуется придерживаться логического порядка свойств:
|
||||
1. Позиционирование (position, top, left, z-index и т.д.)
|
||||
2. Блочная модель (display, width, height, margin, padding и т.д.)
|
||||
3. Оформление (background, border, box-shadow и т.д.)
|
||||
4. Текст (font, color, text-align и т.д.)
|
||||
5. Прочее (transition, animation и т.д.)
|
||||
|
||||
- **Комментарии**
|
||||
В стилях запрещено использовать комментарии.
|
||||
|
||||
- **Дублирования**
|
||||
Не дублировать стили между компонентами. Общие стили выносить в shared/styles или использовать переменные.
|
||||
|
||||
- **Примеры кода стилей**
|
||||
Пример как хорошо:
|
||||
```css
|
||||
/* Блок BEM */
|
||||
.user-bar {
|
||||
display: none;
|
||||
color: black;
|
||||
|
||||
/* Медиа запрос custom media и отделяется 1 пустой строкой */
|
||||
@media (--md) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Елемент BEM отделяется 1 пустой строкой*/
|
||||
.user-bar__button-next {
|
||||
background-color: #f0f0f0;
|
||||
|
||||
/* Псевдо-класс отделяется 1 пустой строкой*/
|
||||
&:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
/* Модификатор BEM отделяется 1 пустой строкой*/
|
||||
&._blue {
|
||||
background-color: #2b2bbe;
|
||||
}
|
||||
|
||||
/* Модификатор BEM отделяется 1 пустой строкой*/
|
||||
&._green {
|
||||
background-color: #29c53d;
|
||||
}
|
||||
}
|
||||
```
|
||||
Пример как плохо писать:
|
||||
```css
|
||||
.user-bar {
|
||||
display: none;
|
||||
color: black;
|
||||
&__button {
|
||||
&_next {
|
||||
background-color: #f0f0f0;
|
||||
&:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
&._blue {
|
||||
background-color: #2b2bbe;
|
||||
}
|
||||
&._green {
|
||||
background-color: #29c53d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.user-bar {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Чек лист для проверки стилизации.**
|
||||
- [ ] Используется PostCSS и CSS-модули для стилизации.
|
||||
- [ ] Применён подход Mobile First.
|
||||
- [ ] Именование классов строго по BEM:
|
||||
- [ ] Модификатор — отдельный класс, начинается с нижнего подчёркивания (например, `._red`, `._active`)
|
||||
- [ ] Все CSS-переменные (цвета, брейкпоинты, отступы, скругления) определены только в `/shared/styles` или через Mantine ThemeProvider.
|
||||
- [ ] Для медиа-запросов используются только custom media переменные из `/shared/styles/media.css`.
|
||||
- [ ] Соблюдается правила вложености селекторов.
|
||||
- [ ] Соблюдается правила отступов селекторов.
|
||||
- [ ] Глобальные стили (reset) вынесены в отдельный файл, остальные стили — модульные.
|
||||
- [ ] Для стандартных UI-элементов используются только компоненты Mantine, кастомные стили — только при необходимости.
|
||||
- [ ] В Mantine-компонентах не используются props/styling для стилизации, только PostCSS.
|
||||
- [ ] Кастомные стили используют переменные и токены Mantine, если это возможно.
|
||||
- [ ] В стилях нет комментариев.
|
||||
- [ ] Стили компонента импортируются только внутри соответствующего компонента.
|
||||
- [ ] Нет импорта стилей одного компонента в другой.
|
||||
- [ ] Нет импорта файлов переменных и custom media — они доступны глобально.
|
||||
- [ ] Нет дублирования стилей между компонентами, общие стили вынесены в shared/styles или используются переменные.
|
||||
@@ -1,88 +0,0 @@
|
||||
---
|
||||
title: Компоненты
|
||||
---
|
||||
|
||||
# Компоненты
|
||||
|
||||
## Правила создания и работы с компонентами.
|
||||
|
||||
### 1. Структура компонента
|
||||
Ассистент при создании/рефакторинге компонента должен **строго** придерживаться следующей структуры файлов и папок:
|
||||
|
||||
```
|
||||
component-name/
|
||||
index.ts
|
||||
component-name.tsx
|
||||
styles/
|
||||
component-name.module.css
|
||||
locales/
|
||||
ru.json
|
||||
en.json
|
||||
types/
|
||||
component-name.interface.ts
|
||||
component-name.type.ts
|
||||
component-name.enum.ts
|
||||
schemas/
|
||||
schema-name.schema.ts
|
||||
utils/
|
||||
util-name.util.ts
|
||||
hooks/
|
||||
use-hook-name.hook.ts
|
||||
stores/
|
||||
store-name.store.ts
|
||||
ui/
|
||||
... # вложенные компоненты для component-name
|
||||
```
|
||||
|
||||
Пояснения к структуре компонента:
|
||||
**Обязательные файлы** обязательны для всех компонентов, даже если они пустые.
|
||||
- component-name/: Папка компонента корень для всего компонента.
|
||||
- index.ts: экспортирует главный компонент, интерфейс и всё, что может быть переиспользовано.
|
||||
- component-name.tsx: главный компонент.
|
||||
- styles/component-name.module.css: стили компонента.
|
||||
- locales/ru.json: локализация на русском языке.
|
||||
- locales/en.json: локализация на английском языке.
|
||||
- types/component-name.interface.ts: интерфейс пропсов компонента.
|
||||
**Не обязательные файлы** добавляются только при необходимости
|
||||
- types/component-name.type.ts: типы компонента.
|
||||
- types/component-name.enum.ts: enum компонента.
|
||||
- schemas/schema-name.schema.ts: схемы валидации.
|
||||
- utils/util-name.util.ts: утилиты компонента.
|
||||
- hooks/use-hook-name.hook.ts: хуки компонента.
|
||||
- stores/store-name.store.ts: хранилища состояния компонента.
|
||||
- ui/: Папка для вложенных компонентов.
|
||||
|
||||
### Требования к компоненту
|
||||
- Использовать `memo()` для всех компонентов, которые принимают пропсы.
|
||||
- Использовать `useMemo` для всех вычислений, которые передаются в пропсы других компонентов.
|
||||
- Использовать `useCallback` для всех функций/методов, которые передаются в пропсы других компонентов.
|
||||
|
||||
### Требования к вложенным компонентам
|
||||
- Вложенный компонент — это полноценный компонент, который обязан полностью соблюдать все правила, описанные для компонентов (структура, именование, документация, типизация, стилизация и т.д.).
|
||||
- Все вложенные компоненты размещаются только в папке ui/ основного компонента.
|
||||
|
||||
**Пояснение**
|
||||
Нет необходимости повторять структуру и требования — вложенный компонент подчиняется тем же правилам, что и любой другой компонент, только располагается в папке ui/ родительского компонента.
|
||||
|
||||
### Требования к локализации
|
||||
- Все добавленные локализации обязательно подключать в экземпляр `app/i18n` (чтобы новые namespace были доступны для i18next).
|
||||
|
||||
---
|
||||
|
||||
### Чек-лист для создания нового компонента
|
||||
- [ ] Главный компонент размещён в корне и назван по правилу PascalCase.
|
||||
- [ ] Создан файл стилей в папке `styles/`, имя в kebab-case, используется BEM.
|
||||
- [ ] Все классы применяются через `className={styles['component-name']}`.
|
||||
- [ ] Создана папка `locales/` с файлами `ru.json` и `en.json`.
|
||||
- [ ] Создан файл интерфейса пропсов в папке `types/`, даже если интерфейс пустой.
|
||||
- [ ] Создан файл `index.ts` с экспортом главного компонента и интерфейса.
|
||||
- [ ] Внутренние компоненты (если есть) размещены в папке `ui/`.
|
||||
- [ ] Все важные части кода документированы по TSDoc (см. раздел 16).
|
||||
- [ ] Остальные файлы (schemas, дополнительные типы, enum) добавлены только при необходимости.
|
||||
- [ ] Именование файлов и папок соответствует правилам (см. выше).
|
||||
- [ ] Нет неиспользуемого или невалидного кода.
|
||||
- [ ] Для компонентов с пропсами используется `React.memo`.
|
||||
- [ ] Для вычислений, передаваемых в пропсы, используется `useMemo`.
|
||||
- [ ] Для функций, передаваемых в пропсы, используется `useCallback`.
|
||||
- [ ] Все тексты вынесены в локализационные файлы и используются через i18n.
|
||||
- [ ] Новые namespace подключены в экземпляр i18n.
|
||||
@@ -1,68 +0,0 @@
|
||||
# Хуки (React Hooks)
|
||||
|
||||
> В проекте для создания пользовательских хуков используется только React (функциональные компоненты и хуки).
|
||||
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с хуками в проекте.
|
||||
|
||||
## Рекомендации по использованию сторонних хуков
|
||||
- Если есть возможность, используйте хуки Mantine в компонентах и кастомных хуках для работы с состоянием, темизацией, медиа-запросами и другими возможностями библиотеки.
|
||||
- Не дублируйте функциональность, уже реализованную в Mantine.
|
||||
|
||||
## Структура
|
||||
- Каждый хук размещается в отдельном файле с именем `use-<hook-name>.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- Имя хука — в стиле camelCase с префиксом `use` (например, `useTodoFilter`).
|
||||
- Для сложных возвращаемых структур использовать отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции.
|
||||
|
||||
## Именование
|
||||
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
|
||||
- Файл хука — `use-<hook-name>.hook.ts` (kebab-case).
|
||||
- Имя хука — camelCase с префиксом `use`.
|
||||
|
||||
## Требования
|
||||
- Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы.
|
||||
- Не хранить бизнес-логику, связанную с несколькими слоями — хук должен быть изолирован в рамках своего слоя/feature.
|
||||
- Не дублировать логику между хуками — общие части выносить в shared.
|
||||
- Не использовать side-effects вне useEffect/useLayoutEffect.
|
||||
- Для мемоизации возвращаемых значений и функций использовать useMemo и useCallback.
|
||||
- Не использовать устаревшие или неразрешённые паттерны React.
|
||||
|
||||
## Типизация
|
||||
- Всегда явно указывать типы для всех параметров, возвращаемых значений и состояния внутри хука.
|
||||
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
|
||||
|
||||
## Документирование
|
||||
- Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода).
|
||||
|
||||
## Экспорт
|
||||
- Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента.
|
||||
|
||||
## Примеры
|
||||
|
||||
```ts
|
||||
import { useMemo } from 'react';
|
||||
import { TodoItem } from '../types/todo-item.interface';
|
||||
import { TodoStatus } from '../types/todo-status.enum';
|
||||
|
||||
/**
|
||||
* Хук фильтрации задач по статусу.
|
||||
*/
|
||||
export const useTodoFilter = (items: TodoItem[], filter: TodoStatus): TodoItem[] => {
|
||||
return useMemo(() => {
|
||||
if (filter === TodoStatus.ALL) return items;
|
||||
if (filter === TodoStatus.ACTIVE) return items.filter((t) => !t.completed);
|
||||
return items.filter((t) => t.completed);
|
||||
}, [items, filter]);
|
||||
};
|
||||
```
|
||||
|
||||
## Чек-лист
|
||||
|
||||
- [ ] Хук размещён в файле `use-<hook-name>.hook.ts` в папке `hooks/` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
|
||||
- [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы.
|
||||
- [ ] Вся бизнес-логика изолирована в рамках слоя/feature.
|
||||
- [ ] Нет дублирования логики между хуками.
|
||||
- [ ] Для мемоизации используется useMemo/useCallback.
|
||||
- [ ] Не используются side-effects вне useEffect/useLayoutEffect.
|
||||
- [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)).
|
||||
- [ ] Нет неиспользуемого или невалидного кода.
|
||||
- [ ] Экспорт только именованный через индексный файл.
|
||||
@@ -1,124 +0,0 @@
|
||||
# Хуки API (React Hooks)
|
||||
|
||||
> В проекте для работы с API-хуками используется только React и библиотека SWR для получения данных (GET-запросы).
|
||||
> В этом разделе собраны основные правила и рекомендации по созданию и оформлению хуков для работы с API. Следуйте этим принципам, чтобы обеспечить чистую архитектуру, переиспользуемость и единый стиль работы с API-хуками в проекте.
|
||||
|
||||
## Описание и назначение API-хуков
|
||||
|
||||
API-хуки предназначены для получения данных с сервера (GET-запросы) и используются в компонентах или других хуках.
|
||||
В проекте для этого применяется библиотека SWR, которая обеспечивает кэширование, автоматическое обновление и удобную работу с асинхронными запросами.
|
||||
|
||||
**Fetcher** — это функция, которую использует SWR для выполнения запроса к API. В проекте fetcher обычно экспортируется из файла клиента (например, `backendFetcher` из `shared/api/backend/client.ts`) и инкапсулирует логику обращения к конкретному API-клиенту.
|
||||
|
||||
**API-клиент** — это отдельный модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API.
|
||||
API-клиент включает:
|
||||
- инициализацию экземпляра HTTP-клиента (например, Axios),
|
||||
- настройку базового URL, интерцепторов и общих обработчиков ошибок,
|
||||
- организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.),
|
||||
- экспорт всех функций, типов и fetcher через индексные файлы.
|
||||
|
||||
Каждый API-клиент размещается в папке `src/shared/api/<client-name>/` и имеет собственную структуру согласно архитектуре проекта.
|
||||
|
||||
## Структура
|
||||
- Каждый API-хук размещается в отдельном файле с именем `use-<method-name>.hook-api.ts` в папке `hooks/api/<client-name>/` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- Имя хука — в стиле camelCase с префиксом `use` (например, `useGetUser`).
|
||||
- Для сложных возвращаемых структур используйте отдельные типы или интерфейсы, размещая их в папке `types/` на своём уровне абстракции.
|
||||
|
||||
## Именование
|
||||
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
|
||||
- Файл хука — `use-<method-name>.hook-api.ts` (kebab-case).
|
||||
- Имя хука — camelCase с префиксом `use`.
|
||||
|
||||
## Требования
|
||||
- Хук должен быть строго типизирован: все параметры, возвращаемые значения и внутренние переменные должны иметь явные типы.
|
||||
- Для получения данных используйте только SWR.
|
||||
- Не дублируйте логику между хуками — общие части выносите в shared.
|
||||
- Не используйте side-effects вне useEffect/useLayoutEffect.
|
||||
|
||||
## Типизация
|
||||
- Всегда явно указывайте типы для всех параметров, возвращаемых значений и состояния внутри хука.
|
||||
- Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации).
|
||||
- Не используйте неявное приведение типов и не полагайтесь на автоматический вывод, если это может снизить читаемость или безопасность.
|
||||
|
||||
## Документирование
|
||||
- Документируйте только назначение хука (описание), строго по [правилам документирования кода](#правило-для-документирования-кода).
|
||||
|
||||
## Экспорт
|
||||
- Экспортируйте хук только именованным экспортом через `index.ts` слоя/компонента.
|
||||
|
||||
## Пример API хука
|
||||
|
||||
```ts
|
||||
// use-get-me.hook-api.ts
|
||||
import useSWR from 'swr';
|
||||
import { backendFetcher } from 'shared/api/backend/client';
|
||||
import { UserDto } from 'shared/api/backend/entities/users/get-me.api';
|
||||
|
||||
/**
|
||||
* Хук для получения информации о текущем пользователе.
|
||||
*/
|
||||
export const useGetMe = () => {
|
||||
const { data, error, isLoading } = useSWR<UserDto>('/users/me', backendFetcher);
|
||||
|
||||
return {
|
||||
data,
|
||||
error,
|
||||
isLoading,
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Пример использования хука в компоненте
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useGetMe } from 'shared/hooks/api/backend/use-get-me.hook-api';
|
||||
|
||||
export const UserInfo: React.FC = () => {
|
||||
const { data, error, isLoading } = useGetMe();
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Загрузка...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div>Ошибка загрузки данных</div>;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <div>Нет данных о пользователе</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>Имя: {data.name}</div>
|
||||
<div>Email: {data.email}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Чек-лист для создания API-хука
|
||||
|
||||
- [ ] Для каждого GET-запроса создан отдельный хук.
|
||||
- [ ] Хук размещён в `hooks/api/<client-name>/use-<method-name>.hook-api.ts` на своём уровне абстракции согласно архитектуре проекта.
|
||||
- [ ] Именование файлов и сущностей соответствует [правилам именования файлов и папок](#правила-именования-файлов-и-папок).
|
||||
- [ ] Используется SWR для получения данных.
|
||||
- [ ] Все параметры, возвращаемые значения и внутренние переменные строго типизированы.
|
||||
- [ ] Нет дублирования логики между хуками.
|
||||
- [ ] Не используются side-effects вне useEffect/useLayoutEffect.
|
||||
- [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)).
|
||||
- [ ] Нет неиспользуемого или невалидного кода.
|
||||
- [ ] Экспорт только именованный через индексный файл.
|
||||
|
||||
---
|
||||
|
||||
## Чек-лист для использования API-хука
|
||||
|
||||
- [ ] Импортируется только нужный хук через публичные экспорты (`index.ts`).
|
||||
- [ ] Использование хука строго по назначению (только для получения данных).
|
||||
- [ ] Если требуется получить данные через GET-запрос в компоненте — обязательно используется соответствующий API-хук.
|
||||
**Запрещено вызывать GET-методы API напрямую в компонентах, только через хуки.**
|
||||
- [ ] Обработка состояний загрузки, ошибки и данных реализована корректно.
|
||||
- [ ] Не происходит дублирования логики, связанной с получением данных.
|
||||
- [ ] Нет неиспользуемого или невалидного кода.
|
||||
@@ -1,242 +0,0 @@
|
||||
# API
|
||||
|
||||
> В этом разделе собраны основные правила и рекомендации по созданию, оформлению и использованию API-клиентов и функций для работы с сервером. Следуйте этим принципам, чтобы обеспечить единый стиль, безопасность и удобство поддержки API-слоя в проекте.
|
||||
|
||||
## Описание и назначение API-клиента
|
||||
|
||||
API-клиент — это модуль (папка), отвечающий за взаимодействие с конкретным внешним или внутренним API.
|
||||
В проекте для HTTP-запросов используется только Axios.
|
||||
API-клиент инкапсулирует:
|
||||
- инициализацию экземпляра Axios,
|
||||
- настройку базового URL, интерцепторов, обработчиков ошибок,
|
||||
- организацию всех сущностей и методов для работы с этим API (например, users, auth, orders и т.д.),
|
||||
- экспорт всех функций, типов и fetcher через индексные файлы.
|
||||
|
||||
Каждый API-клиент размещается в папке `src/shared/api/<client-name>/` и имеет собственную структуру согласно архитектуре проекта.
|
||||
|
||||
|
||||
## Использование методов API
|
||||
|
||||
- Все методы API должны использоваться строго внутри блока `try...catch`.
|
||||
- При вызове методов API всегда используйте полный путь, например:
|
||||
`await api.backend.createUser({ email, password });`
|
||||
- Запрещено вызывать методы API вне блока `try...catch` даже в тестах, утилитах и других вспомогательных функциях.
|
||||
|
||||
|
||||
## Структура клиента
|
||||
```text
|
||||
src/shared/api/backend/
|
||||
│
|
||||
├── client.ts
|
||||
├── index.ts
|
||||
└── entities/
|
||||
├── users/
|
||||
│ ├── get-me.api.ts
|
||||
│ ├── create-user.api.ts
|
||||
│ ├── update-user.api.ts
|
||||
│ └── index.ts
|
||||
├── auth/
|
||||
│ ├── login.api.ts
|
||||
│ ├── register.api.ts
|
||||
│ └── index.ts
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
## Описание ключевых элементов
|
||||
|
||||
- **client.ts**
|
||||
Экземпляр Axios с настройками, интерцепторами, экспортом fetcher для SWR.
|
||||
|
||||
- **index.ts**
|
||||
Главная точка экспорта: экспортирует client, fetcher, все сущности и их методы.
|
||||
|
||||
- **entities/**
|
||||
Папка для бизнес-сущностей (например, users, auth, orders и т.д.).
|
||||
|
||||
- **`<entity>/`**
|
||||
Папка для отдельной сущности. Имя — в kebab-case, отражает бизнес-область (например, users, auth).
|
||||
|
||||
- **`<operation>.api.ts`**
|
||||
Файл для каждой операции (CRUD, спец. действия).
|
||||
Внутри:
|
||||
- DTO (интерфейсы запроса/ответа)
|
||||
- Функция, реализующая запрос через client
|
||||
|
||||
- **index.ts (внутри `<entity>`/)**
|
||||
Экспортирует все методы и типы этой сущности.
|
||||
|
||||
- **index.ts (внутри entities/)**
|
||||
Экспортирует все сущности (users, auth и т.д.).
|
||||
|
||||
|
||||
## Именование
|
||||
|
||||
- Соблюдайте [правила именования файлов и папок](#правила-именования-файлов-и-папок):
|
||||
- Файл клиента — `client.ts`.
|
||||
- Файл функции — `<operation>-<entity>.api.ts` (например, `create-user.api.ts`).
|
||||
- DTO — в папке `dto/` (например, `create-user.dto.ts`).
|
||||
- Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент).
|
||||
|
||||
|
||||
## Требования
|
||||
|
||||
- Для каждого действия (CRUD, спец. действия) — отдельная функция и файл.
|
||||
- Все функции используют общий экземпляр Axios из `client.ts`.
|
||||
- Все функции строго типизированы (используются DTO).
|
||||
- DTO объявляется в отдельном файле в папке `dto/` перед функцией, которая его использует.
|
||||
- Для каждого GET метода обязательно должен быть создан API-хук.
|
||||
- Все API-хуки должны создаваться строго по [документации раздела "Хуки для API"](#хуки-для-api-api-hooks).
|
||||
|
||||
|
||||
## Типизация
|
||||
|
||||
- Все функции и DTO строго типизированы.
|
||||
- Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции.
|
||||
- Все DTO размещены в папке `dto/` на своём уровне абстракции.
|
||||
- Придерживайтесь [общих правил типизации проекта](#общие-правила-типизации).
|
||||
|
||||
|
||||
## Документирование
|
||||
|
||||
- Документируйте только назначение функций и DTO.
|
||||
- В описании указывается только смысл функции/типа.
|
||||
|
||||
|
||||
## Экспорт
|
||||
|
||||
- Все функции и типы экспортируются через индексные файлы на каждом уровне (сущность, entities, клиент).
|
||||
|
||||
|
||||
## Примеры
|
||||
|
||||
### Пример клиента API
|
||||
|
||||
```ts
|
||||
// client.ts
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
export { AxiosError, isAxiosError } from 'axios';
|
||||
export type { AxiosResponse } from 'axios';
|
||||
|
||||
/**
|
||||
* Экземпляр HTTP-клиента для работы с backend API.
|
||||
*/
|
||||
export const backendHttpClient: AxiosInstance = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// Интерцептор запроса
|
||||
backendHttpClient.interceptors.request.use(
|
||||
(config) => {
|
||||
// Здесь можно добавить авторизационные заголовки или другую логику
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error)
|
||||
);
|
||||
|
||||
// Интерцептор ответа
|
||||
backendHttpClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
// Здесь можно обработать ошибки (например, показать уведомление)
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Пример DTO
|
||||
|
||||
```ts
|
||||
// dto/create-user.dto.ts
|
||||
/**
|
||||
* DTO для создания пользователя.
|
||||
*/
|
||||
export interface CreateUserDto {
|
||||
/** Email пользователя. */
|
||||
email: string;
|
||||
/** Пароль пользователя. */
|
||||
password: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Пример API-функции
|
||||
|
||||
```ts
|
||||
// create-user.api.ts
|
||||
import { backendHttpClient } from '../client';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
|
||||
/**
|
||||
* Создать пользователя.
|
||||
*/
|
||||
export const createUser = (data: CreateUserDto) => backendHttpClient.post('/users', data);
|
||||
```
|
||||
|
||||
### Пример index.ts (в папке сущности)
|
||||
|
||||
```ts
|
||||
export * from './create-user.api';
|
||||
export * from './get-user.api';
|
||||
```
|
||||
|
||||
### Пример использования API-функции в компоненте
|
||||
|
||||
```tsx
|
||||
import React, { useState } from 'react';
|
||||
import { api } from 'shared/api';
|
||||
|
||||
export const CreateUserForm: React.FC = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
await api.backend.createUser({ email, password });
|
||||
console.log('Пользователь создан!');
|
||||
} catch {
|
||||
console.log('Ошибка создания пользователя');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
placeholder="Email"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
placeholder="Пароль"
|
||||
required
|
||||
/>
|
||||
<button type="submit">Создать пользователя</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Чек-лист для создания клиента
|
||||
- [ ] Новый клиент размещён в `src/shared/api/<client-name>/`.
|
||||
- [ ] В корне клиента есть client.ts (экземпляр Axios) и index.ts (главный экспорт).
|
||||
- [ ] Все бизнес-сущности размещены в entities/, каждая — в отдельной папке.
|
||||
- [ ] Для каждой операции создан отдельный файл `<operation>`.api.ts с DTO и функцией.
|
||||
- [ ] DTO объявлен непосредственно перед функцией.
|
||||
- [ ] В каждой папке сущности есть свой index.ts для экспорта методов и типов.
|
||||
- [ ] В папке entities/ есть общий index.ts для экспорта всех сущностей.
|
||||
- [ ] Все экспорты организованы через индексные файлы.
|
||||
- [ ] Для каждого GET-метода создан отдельный SWR-хук (см. правила API-хуков).
|
||||
- [ ] Нет дублирования кода и неиспользуемых файлов.
|
||||
|
||||
## Чек-лист для использования API
|
||||
- [ ] Импортируется только нужный метод через публичные экспорты (index.ts).
|
||||
- [ ] Все вызовы API обёрнуты в try...catch.
|
||||
- [ ] Используются только строго типизированные методы.
|
||||
- [ ] Не происходит обращения к Axios напрямую — только через client.
|
||||
- [ ] Нет дублирования логики и неиспользуемого кода.
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
title: Общие принципы
|
||||
---
|
||||
|
||||
# Общие принципы
|
||||
|
||||
## Стек технологий и библиотеки
|
||||
- Использовать **TypeScript** для всех файлов логики и компонентов.
|
||||
- Использовать **FSD (Feature-Sliced Design)**: разделять код на features, entities, processes, widgets, shared.
|
||||
- Использовать **React** (функциональные компоненты, хуки).
|
||||
- Использовать **Mantine UI** для UI-компонентов.
|
||||
- Использовать **Axios** в качестве клиента для работы с API.
|
||||
- Использовать **SWR** для data fetching (GET-запросы).
|
||||
- Использовать **Zustand** для глобального состояния.
|
||||
- Использовать **i18n** для локализации.
|
||||
- Использовать **Vitest** для тестирования.
|
||||
- Использовать **PostCSS модули** для стилизации.
|
||||
- Использовать **BEM** для именований классов в стилях
|
||||
- Использовать **Mobile First** подход для написания стилей.
|
||||
- Использовать **Context7** примеров использования библиотек.
|
||||
- Использовать **i18n** (i18next) для локализации всех пользовательских текстов.
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: Архитектура
|
||||
---
|
||||
|
||||
# Архитектура
|
||||
|
||||
## Архитектура проекта
|
||||
В проекте используется FSD (Feature-Sliced Design) архитектура.
|
||||
|
||||
- **FSD-границы**
|
||||
- Не нарушать границы слоёв (например, feature не может импортировать из widgets).
|
||||
- Бизнес-логика должна быть вынесена в хуки или сервисы.
|
||||
- **Импорты**
|
||||
- Внутри слоя — относительные импорты.
|
||||
- Между слоями — абсолютные импорты.
|
||||
- **Требования**
|
||||
- Не смешивать логику разных слоёв.
|
||||
- Не хранить бизнес-логику в UI-компонентах.
|
||||
- **Именование**
|
||||
- Файлы и папки kebab-case.
|
||||
|
||||
---
|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
title: Стиль кода
|
||||
---
|
||||
|
||||
# Стиль кода
|
||||
|
||||
## Отступы
|
||||
|
||||
Используем 2 пробела для отступов во всём проекте. Не используем табы.
|
||||
|
||||
|
||||
## Кавычки
|
||||
|
||||
Используем **одинарные кавычки** для строк в JavaScript/TypeScript, и **двойные кавычки** для атрибутов в JSX/TSX.
|
||||
|
||||
**Пример:**
|
||||
|
||||
```ts
|
||||
// JavaScript/TypeScript
|
||||
const message = 'Привет, мир!';
|
||||
const name = 'ProjectName';
|
||||
```
|
||||
|
||||
```tsx
|
||||
// JSX/TSX
|
||||
<input type="text" placeholder="Введите имя" />
|
||||
<button title="Сохранить">Сохранить</button>
|
||||
```
|
||||
|
||||
## Строгая типизация
|
||||
|
||||
всегда указывать типы для пропсов, возвращаемых значений, параметров функций.
|
||||
|
||||
## Ранние возвраты
|
||||
|
||||
(early return) для повышения читаемости.
|
||||
|
||||
## Мемоизация
|
||||
|
||||
Старайся оптимизировать код если это возможно.
|
||||
|
||||
## Документирование
|
||||
|
||||
Документируем ТОЛЬКО ОПИСАНИЕ (функций, компонентов, типов и их полей).
|
||||
|
||||
## any, unknown
|
||||
|
||||
запрещено использовать без крайней необходимости.
|
||||
|
||||
## Классы в TSX
|
||||
|
||||
Для стилизации компонентов используем CSS-модули и методологию BEM. Классы подключаются через объект стилей, импортированный из соответствующего `.module.css` файла.
|
||||
|
||||
> Объект стилей всегда импортируется с именем `s` (сокращённо от style), а не `styles`.
|
||||
|
||||
**Пример:**
|
||||
|
||||
```tsx
|
||||
import s from './my-component.module.css';
|
||||
|
||||
export const MyComponent = () => (
|
||||
<div className={s['my-component']}>
|
||||
<button className={s['my-component__button']}>Кнопка</button>
|
||||
<span className={s['my-component__text']}>Текст</span>
|
||||
<button className={s['my-component__button'] + ' ' + s._active}>
|
||||
Активная кнопка
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
- Имя класса всегда берётся из объекта `s`.
|
||||
- Для модификаторов используется отдельный класс с нижним подчёркиванием (например, `s._active`).
|
||||
- Не используйте строковые литералы с классами напрямую — только через объект `s`.
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
title: Именование
|
||||
---
|
||||
|
||||
# Именование
|
||||
|
||||
## Именование файлов и папок
|
||||
- Папка компонента: kebab-case, совпадает с названием компонента, пример: `component-name`.
|
||||
- React-компонент: kebab-case, совпадает с названием компонента, пример: `component-name.tsx`.
|
||||
- Стили: kebab-case, шаблон: `<style-name>.module.css`, пример: `style-name.module.css`.
|
||||
- Интерфейсы: kebab-case, шаблон: `<interface-name>.interface.ts`, пример: `interface-name.interface.ts`.
|
||||
- Типы: kebab-case, шаблон: `<type-name>.type.ts`, пример: `type-name.type.ts`.
|
||||
- Enum: kebab-case, шаблон: `<enum-name>.enum.ts`, пример: `enum-name.enum.ts`.
|
||||
- Схемы: kebab-case, шаблон: `<schema-name>.schema.ts`, пример: `schema-name.schema.ts`.
|
||||
- Локализация: kebab-case, пример: `ru.json`, `en.json`.
|
||||
- Утилиты: kebab-case, шаблон: `<util-name>.util.ts`, пример: `util-name.util.ts`
|
||||
- React Hooks: kebab-case, шаблон: `use-<hook-name>.hook.ts`, пример: `use-hook-name.hook.ts`
|
||||
- Хранилища состояния компонента: kebab-case, шаблон: `<store-name>.store.ts`, пример: `store-name.store.ts`
|
||||
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: Документирование
|
||||
---
|
||||
|
||||
# Документирование
|
||||
|
||||
## Правило для документирования кода
|
||||
|
||||
- Документировать разрешено только описание (назначение) функций, компонентов, типов, интерфейсов, enum и их полей.
|
||||
- Строго запрещено документировать параметры, возвращаемые значения, типы пропсов, аргументы, возвращаемые значения функций, компоненты, хуки и т.д.
|
||||
- В интерфейсах, типах и enum разрешено документировать только смысл (описание) каждого поля или значения.
|
||||
- В React-компонентах, функциях, хранилищах, схемах, утилитах разрешено документировать только назначение (описание), без детализации параметров и возвращаемых значений.
|
||||
- Описание должно быть кратким, информативным и реально помогать понять структуру и бизнес-логику.
|
||||
- Не допускается избыточная или дублирующая очевидное документация.
|
||||
- В конце описания всегда ставить точку.
|
||||
|
||||
**Примеры правильного документирования**
|
||||
```tsx
|
||||
/**
|
||||
* Список задач пользователя.
|
||||
*/
|
||||
export const TodoList = memo(() => { ... });
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
*/
|
||||
export interface TodoItem {
|
||||
/** Уникальный идентификатор задачи. */
|
||||
id: string;
|
||||
/** Текст задачи. */
|
||||
text: string;
|
||||
/** Статус выполнения задачи. */
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Перечисление фильтров задач.
|
||||
*/
|
||||
export enum TodoFilter {
|
||||
/** Все задачи. */
|
||||
All = 'all',
|
||||
/** Только активные задачи. */
|
||||
Active = 'active',
|
||||
/** Только выполненные задачи. */
|
||||
Completed = 'completed',
|
||||
}
|
||||
```
|
||||
|
||||
**Примеры неправильного документирования**
|
||||
```ts
|
||||
// ❌ Не нужно:/
|
||||
/**
|
||||
* @param id - идентификатор задачи
|
||||
* @returns объект задачи
|
||||
*/
|
||||
|
||||
// ❌ Не нужно:/
|
||||
/**
|
||||
* @param props - пропсы компонента
|
||||
* @returns JSX.Element
|
||||
*/
|
||||
|
||||
// ❌ Не нужно:/
|
||||
/**
|
||||
* id — идентификатор задачи
|
||||
* text — текст задачи
|
||||
* completed — статус выполнения
|
||||
*/
|
||||
```
|
||||
@@ -1,187 +0,0 @@
|
||||
---
|
||||
title: Типизация
|
||||
---
|
||||
|
||||
# Типизация
|
||||
|
||||
## Общие правила типизации
|
||||
|
||||
> Данный раздел определяет единые требования к типизации для всего проекта. Соблюдение этих правил обеспечивает читаемость, предсказуемость и безопасность кода.
|
||||
|
||||
- Использовать только строгую типизацию TypeScript для всех файлов логики, компонентов, хуков, API, сторов и утилит.
|
||||
- Всегда явно указывать типы для:
|
||||
- Пропсов компонентов
|
||||
- Параметров функций и методов
|
||||
- Возвращаемых значений функций и методов
|
||||
- Всех переменных состояния (в том числе в store)
|
||||
- Всех значимых переменных и констант, если их тип не очевиден из присваивания
|
||||
- Не использовать `any` и `unknown` без крайней необходимости. Если использование неизбежно — обязательно добавить комментарий с обоснованием.
|
||||
- Все интерфейсы, типы и enum всегда размещать в папке `types/` на своём уровне абстракции (например, `features/todo/types/`).
|
||||
- Для DTO всегда использовать отдельную папку `dto/` на уровне сущности или слоя.
|
||||
- Для сложных структур использовать отдельные интерфейсы или типы, размещая их в соответствующих файлах в папке `types/`.
|
||||
- Для DTO, enum, схем и других сущностей — всегда создавать отдельные типы/интерфейсы с осмысленными именами.
|
||||
- Ключи enum всегда писать ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE).
|
||||
- Не использовать неявное приведение типов и не полагаться на автоматический вывод, если это может снизить читаемость или безопасность.
|
||||
- Для массивов и объектов всегда указывать тип элементов/ключей.
|
||||
- Для возвращаемых значений асинхронных функций всегда указывать тип Promise.
|
||||
- Типизацию коллбеков и функций, передаваемых в пропсы, указывать инлайн, не выносить в отдельные типы.
|
||||
- Для типизации внешних библиотек использовать официальные типы или создавать собственные декларации при необходимости.
|
||||
- Не использовать устаревшие или не рекомендуемые паттерны типизации (например, `Function`, `Object`, `{}`).
|
||||
---
|
||||
|
||||
### Примеры
|
||||
|
||||
#### Интерфейс и типы для сущностей (всегда в папке types/)
|
||||
|
||||
```ts
|
||||
// features/todo/types/todo-item.interface.ts
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
*/
|
||||
export interface TodoItem {
|
||||
/** Уникальный идентификатор задачи. */
|
||||
id: string;
|
||||
/** Текст задачи. */
|
||||
text: string;
|
||||
/** Статус выполнения задачи. */
|
||||
completed: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
#### Типизация enum (всегда в папке types/)
|
||||
|
||||
```ts
|
||||
// features/todo/types/todo-status.enum.ts
|
||||
|
||||
/**
|
||||
* Перечисление статусов задачи.
|
||||
*/
|
||||
export enum TodoStatus {
|
||||
/** Активная задача. */
|
||||
ACTIVE = 'active',
|
||||
/** Выполненная задача. */
|
||||
COMPLETED = 'completed',
|
||||
}
|
||||
```
|
||||
|
||||
#### Типизация пропсов компонента
|
||||
|
||||
```ts
|
||||
import { FC, memo } from 'react';
|
||||
import { TodoItem } from './types/todo-item.interface';
|
||||
|
||||
/**
|
||||
* Список задач.
|
||||
*/
|
||||
export interface TodoListProps {
|
||||
/** Массив задач. */
|
||||
items: TodoItem[];
|
||||
}
|
||||
|
||||
export const TodoList: FC<TodoListProps> = memo(({ items }) => (
|
||||
<ul>
|
||||
{items.map((item) => (
|
||||
<li key={item.id}>{item.text}</li>
|
||||
))}
|
||||
</ul>
|
||||
));
|
||||
```
|
||||
|
||||
#### Типизация функций и коллбеков (инлайн)
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Функция фильтрации задач.
|
||||
*/
|
||||
export const getCompletedTodos = (items: TodoItem[]): TodoItem[] => {
|
||||
return items.filter((t) => t.completed);
|
||||
};
|
||||
|
||||
/**
|
||||
* Колбэк для обработки клика (инлайн).
|
||||
*/
|
||||
const handleClick = (id: string): void => {
|
||||
console.log('Clicked:', id);
|
||||
};
|
||||
```
|
||||
|
||||
#### Типизация асинхронных функций
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Получить задачи с сервера.
|
||||
*/
|
||||
export const fetchTodos = async (): Promise<TodoItem[]> => {
|
||||
const response = await fetch('/api/todos');
|
||||
return response.json();
|
||||
};
|
||||
```
|
||||
|
||||
#### Типизация состояния в store (интерфейс в types/)
|
||||
|
||||
```ts
|
||||
// features/todo/types/todo-store.interface.ts
|
||||
|
||||
/**
|
||||
* Состояние хранилища задач.
|
||||
*/
|
||||
export interface TodoStoreState {
|
||||
/** Массив задач. */
|
||||
items: TodoItem[];
|
||||
/** Добавить задачу. */
|
||||
addTodo: (item: TodoItem) => void;
|
||||
/** Удалить задачу. */
|
||||
removeTodo: (id: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
#### Типизация DTO (всегда в папке dto/)
|
||||
|
||||
```ts
|
||||
// features/todo/dto/create-todo.dto.ts
|
||||
|
||||
/**
|
||||
* DTO для создания задачи.
|
||||
*/
|
||||
export interface CreateTodoDto {
|
||||
/** Текст задачи. */
|
||||
text: string;
|
||||
}
|
||||
|
||||
// features/todo/dto/todo-response.dto.ts
|
||||
|
||||
/**
|
||||
* DTO ответа сервера.
|
||||
*/
|
||||
export interface TodoResponseDto {
|
||||
/** Созданная задача. */
|
||||
todo: TodoItem;
|
||||
}
|
||||
```
|
||||
|
||||
#### Типизация внешних библиотек
|
||||
|
||||
```ts
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
export const getData = async (): Promise<AxiosResponse<TodoItem[]>> => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
### Чек-лист проверки типизации
|
||||
|
||||
- [ ] Все пропсы компонентов явно типизированы через интерфейс или тип в папке `types/`.
|
||||
- [ ] Все параметры и возвращаемые значения функций и методов явно типизированы.
|
||||
- [ ] Все переменные состояния (в том числе в store) имеют явные типы.
|
||||
- [ ] Все интерфейсы, типы и enum размещены в папке `types/` на своём уровне абстракции.
|
||||
- [ ] Ключи всех enum написаны ЗАГЛАВНЫМИ_БУКВАМИ (SCREAMING_SNAKE_CASE).
|
||||
- [ ] Все DTO размещены в папке `dto/` на своём уровне абстракции.
|
||||
- [ ] Не используется `any` и `unknown` без крайней необходимости и поясняющего комментария.
|
||||
- [ ] Для сложных структур используются отдельные интерфейсы или типы.
|
||||
- [ ] Для массивов и объектов указан тип элементов/ключей.
|
||||
- [ ] Для асинхронных функций указан тип Promise с конкретным типом результата.
|
||||
- [ ] Типы коллбеков и функций, передаваемых в пропсы, указаны инлайн.
|
||||
- [ ] Не используются устаревшие типы (`Function`, `Object`, `{}`).
|
||||
- [ ] Для внешних библиотек используются официальные типы или собственные декларации.
|
||||
- [ ] Нет неявного приведения типов, все типы читаемы и прозрачны.
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: Локализация
|
||||
---
|
||||
|
||||
# Локализация
|
||||
|
||||
## Правила использования локализации
|
||||
|
||||
- Все пользовательские тексты должны быть вынесены в локализационные файлы.
|
||||
- Для каждого компонента создавать папку `locales/` с файлами `ru.json`, `en.json` и т.д.
|
||||
- Новые namespace обязательно регистрировать в экземпляре i18n (см. `app/i18n.ts`).
|
||||
- В коде использовать только функцию перевода из i18n, не использовать "жёстко" прописанные строки.
|
||||
84
README.md
84
README.md
@@ -1,57 +1,53 @@
|
||||
# NextJS Style Guide
|
||||
# Style Guide
|
||||
|
||||
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure.
|
||||
Репозиторий с правилами и стандартами фронтенд-разработки. Исходники документации собираются в разные форматы под разные фреймворки.
|
||||
|
||||
## Documentation Structure
|
||||
## Структура
|
||||
|
||||
### Processes
|
||||
```text
|
||||
src/ # Исходники — только .md файлы
|
||||
├── base/ # Общие правила (не поставляется отдельно)
|
||||
│ ├── basics/ # Базовые: стиль кода, именование, типизация
|
||||
│ ├── applied/ # Прикладные: компоненты, стили, хуки, API
|
||||
│ └── triggers/ # Триггеры: создание компонента, стилизация и т.д.
|
||||
│
|
||||
└── nextjs/ # Next.js — самостоятельная единица
|
||||
├── applied/ # Next.js-специфичные: page-level, project-structure
|
||||
├── triggers/ # Next.js-специфичные триггеры: create-page, create-layout
|
||||
├── DEVELOP.md # Точка входа для агента-разработчика
|
||||
└── REVIEW.md # Точка входа для агента-ревьювера
|
||||
|
||||
**What to do** in a specific situation — step-by-step instructions.
|
||||
scripts/ # Скрипты и манифесты сборки
|
||||
├── build-ai.js # Скрипт сборки
|
||||
└── nextjs.build.js # Манифест: какие файлы, куда, как называются
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Getting Started | What tools to install before starting development? |
|
||||
| Creating an App | How to create a new project, where to get a template? |
|
||||
| Creating Pages | How to add a page: routing and screen? |
|
||||
| Creating Components | How to generate components using templates? |
|
||||
| Styling | What to use: Mantine, tokens, or PostCSS? |
|
||||
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
|
||||
| State Management | When and how to create a store (Zustand)? |
|
||||
| Localization | How to add translations and work with i18next? |
|
||||
dist/ # Собранные версии (gitignore)
|
||||
├── ai/{framework}/ # Для AI-агентов
|
||||
└── vitepress/{framework}/ # Для людей (планируется)
|
||||
```
|
||||
|
||||
### Basic Rules
|
||||
## Сборка
|
||||
|
||||
**What the code should look like** — standards not tied to a specific technology.
|
||||
```bash
|
||||
npm run build:ai # Собрать все фреймворки
|
||||
```
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Tech Stack | What stack do we use? |
|
||||
| Architecture | How are FSD layers, dependencies, and public API structured? |
|
||||
| Code Style | How to format code: indentation, quotes, imports, early return? |
|
||||
| Naming | How to name files, variables, components, hooks? |
|
||||
| Documentation | How to write JSDoc: what to document and what not? |
|
||||
| Typing | How to type: type vs interface, any/unknown, FC? |
|
||||
## Манифест
|
||||
|
||||
### Applied Sections
|
||||
Каждый фреймворк имеет манифест `scripts/{framework}.build.js`. Ключ — путь в выходной папке, значение — путь исходника в `src/`.
|
||||
|
||||
**How a specific area works** — rules, structure, and code examples for specific technologies and tools.
|
||||
Скрипт только копирует файлы по манифесту. Никакой генерации.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Project Structure | How are folders and files organized by FSD? |
|
||||
| Components | How is a component structured: files, props, clsx, FC? |
|
||||
| Page-level Components | How to define layout, page, loading, error, not-found? |
|
||||
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
|
||||
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
|
||||
| Images | _(not filled)_ |
|
||||
| SVG Sprites | _(not filled)_ |
|
||||
| Video | _(not filled)_ |
|
||||
| API | _(not filled)_ |
|
||||
| Stores | _(not filled)_ |
|
||||
| Hooks | _(not filled)_ |
|
||||
| Fonts | _(not filled)_ |
|
||||
| Localization | _(not filled)_ |
|
||||
## Добавление раздела
|
||||
|
||||
## For Assistants
|
||||
1. Создать `.md` в `src/base/` (общий) или `src/{framework}/` (специфичный).
|
||||
2. Добавить frontmatter: `title`, `scope`, `keywords`, `when`.
|
||||
3. Добавить путь в манифест `scripts/{framework}.build.js`.
|
||||
4. Обновить точку входа (`DEVELOP.md` и/или `REVIEW.md`).
|
||||
5. `npm run build:ai`.
|
||||
|
||||
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md
|
||||
## Добавление фреймворка
|
||||
|
||||
1. Создать `src/{framework}/` с `.md` файлами и точками входа.
|
||||
2. Создать `scripts/{framework}.build.js`.
|
||||
3. `npm run build:ai`.
|
||||
|
||||
60
README_RU.md
60
README_RU.md
@@ -1,60 +0,0 @@
|
||||
# NextJS Style Guide
|
||||
|
||||
Правила и стандарты разработки на NextJS и TypeScript: архитектура, типизация, стили, компоненты, API и инфраструктурные разделы.
|
||||
|
||||
## Для ассистентов
|
||||
|
||||
Полная документация в одном MD файле: https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md
|
||||
|
||||
## Структура документации
|
||||
|
||||
### Workflow
|
||||
|
||||
**Что делать и в каком порядке** — пошаговые инструкции.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Начало работы | Что нужно знать перед началом разработки? |
|
||||
| Создание проекта | Как начать новый проект? |
|
||||
| Генерация кода | Какие модули должны генерироваться из шаблонов? |
|
||||
| Добавление страницы | Как добавить новую страницу в проект? |
|
||||
| Добавление UI-модуля | Как создать компонент, фичу, виджет, сущность или layout? |
|
||||
| Стилизация | Как стилизовать компоненты в проекте? |
|
||||
| Получение данных | Как получать данные с сервера? |
|
||||
| Управление состоянием | Как работать с состоянием? |
|
||||
| Локализация | Как добавлять переводы и подключать локализацию? |
|
||||
|
||||
### Базовые правила
|
||||
|
||||
**Каким должен быть код** — стандарты, не привязанные к конкретной технологии.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Технологии и библиотеки | Какой стек используем? |
|
||||
| Архитектура | Как устроены слои FSD, зависимости, публичный API? |
|
||||
| Стиль кода | Как оформлять код: отступы, кавычки, импорты, early return? |
|
||||
| Именование | Как называть файлы, переменные, компоненты, хуки? |
|
||||
| Документирование | Как писать JSDoc: что документировать, а что нет? |
|
||||
| Типизация | Как типизировать: type vs interface, any/unknown, FC? |
|
||||
|
||||
### Прикладные разделы
|
||||
|
||||
**Как это настроить и использовать** — конфигурация, структура и примеры кода для конкретных областей.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Настройка VS Code | Как настроить редактор для проекта? |
|
||||
| Структура проекта | Как организованы папки и файлы по FSD? |
|
||||
| Компоненты | Как устроен компонент: файлы, пропсы, clsx, FC? |
|
||||
| Page-level компоненты | Как описывать layout, page, loading, error, not-found? |
|
||||
| Шаблоны и генерация кода | Как работают шаблоны, синтаксис и инструменты генерации? |
|
||||
| Стили | Как писать CSS: PostCSS Modules, вложенность, медиа, токены? |
|
||||
| Изображения | _(не заполнен)_ |
|
||||
| SVG-спрайты | _(не заполнен)_ |
|
||||
| Видео | _(не заполнен)_ |
|
||||
| API | _(не заполнен)_ |
|
||||
| Stores | _(не заполнен)_ |
|
||||
| Хуки | _(не заполнен)_ |
|
||||
| Шрифты | _(не заполнен)_ |
|
||||
| Локализация | _(не заполнен)_ |
|
||||
|
||||
107
concat-md.js
107
concat-md.js
@@ -1,107 +0,0 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
// Явный порядок файлов внутри каждого языка
|
||||
const fileOrder = [
|
||||
// index
|
||||
"index.md",
|
||||
// workflow
|
||||
"workflow.md",
|
||||
// basics
|
||||
"basics/tech-stack.md",
|
||||
"basics/architecture.md",
|
||||
"basics/code-style.md",
|
||||
"basics/naming.md",
|
||||
"basics/documentation.md",
|
||||
"basics/typing.md",
|
||||
// applied
|
||||
"applied/vscode.md",
|
||||
"applied/project-structure.md",
|
||||
"applied/components.md",
|
||||
"applied/page-level.md",
|
||||
"applied/templates-generation.md",
|
||||
"applied/styles.md",
|
||||
"applied/images-sprites.md",
|
||||
"applied/svg-sprites.md",
|
||||
"applied/video.md",
|
||||
"applied/api.md",
|
||||
"applied/stores.md",
|
||||
"applied/hooks.md",
|
||||
"applied/fonts.md",
|
||||
"applied/localization.md",
|
||||
];
|
||||
|
||||
// Удалить frontmatter из содержимого md-файла
|
||||
const stripFrontmatter = (content) =>
|
||||
content.replace(/^---[\s\S]*?---\n*/m, "");
|
||||
|
||||
// Сдвинуть уровень заголовков на 1 вниз (h1→h2, h2→h3, ...)
|
||||
// Не трогает заголовки внутри блоков кода
|
||||
const shiftHeadings = (content) => {
|
||||
const lines = content.split("\n");
|
||||
let inCodeBlock = false;
|
||||
|
||||
return lines
|
||||
.map((line) => {
|
||||
if (line.startsWith("```")) inCodeBlock = !inCodeBlock;
|
||||
if (inCodeBlock) return line;
|
||||
if (/^#{1,5}\s/.test(line)) return "#" + line;
|
||||
return line;
|
||||
})
|
||||
.join("\n");
|
||||
};
|
||||
|
||||
// Собрать RULES.md с мета-якорями для каждого файла
|
||||
const buildRules = (lang) => {
|
||||
const srcDir = `./docs/${lang}`;
|
||||
const outDir = `./generated/${lang}`;
|
||||
const outFile = path.join(outDir, "RULES.md");
|
||||
|
||||
if (!fs.existsSync(srcDir)) {
|
||||
console.log(`Пропуск ${lang}: папка ${srcDir} не найдена`);
|
||||
return;
|
||||
}
|
||||
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
|
||||
const parts = [];
|
||||
|
||||
for (const file of fileOrder) {
|
||||
const filePath = path.join(srcDir, file);
|
||||
if (!fs.existsSync(filePath)) continue;
|
||||
|
||||
const raw = fs.readFileSync(filePath, "utf8");
|
||||
const content = stripFrontmatter(raw).trim();
|
||||
if (!content) continue;
|
||||
|
||||
// Мета-якорь: путь VitePress без расширения
|
||||
const route = "/" + file.replace(/\.md$/, "");
|
||||
// index.md остаётся без сдвига (его h1 — главный заголовок документа)
|
||||
const processed = file === "index.md" ? content : shiftHeadings(content);
|
||||
parts.push(`<!-- ${route} -->\n${processed}`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(outFile, parts.join("\n\n"), "utf8");
|
||||
console.log(`RULES.md (${lang}) создан: ${outFile}`);
|
||||
};
|
||||
|
||||
// Собираем RULES.md для обоих языков
|
||||
buildRules("ru");
|
||||
buildRules("en");
|
||||
|
||||
// Генерируем README из index.md
|
||||
const buildReadme = (lang, outFile) => {
|
||||
const indexPath = `./docs/${lang}/index.md`;
|
||||
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
console.log(`Пропуск README (${lang}): ${indexPath} не найден`);
|
||||
return;
|
||||
}
|
||||
|
||||
const content = stripFrontmatter(fs.readFileSync(indexPath, "utf8"));
|
||||
fs.writeFileSync(outFile, content, "utf8");
|
||||
console.log(`${outFile} создан из ${indexPath}`);
|
||||
};
|
||||
|
||||
buildReadme("en", "./README.md");
|
||||
buildReadme("ru", "./README_RU.md");
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: API
|
||||
---
|
||||
|
||||
# API
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Components
|
||||
---
|
||||
|
||||
# Components
|
||||
|
||||
Rules for creating UI components across all FSD layers.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Fonts
|
||||
---
|
||||
|
||||
# Fonts
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Hooks
|
||||
---
|
||||
|
||||
# Hooks
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Images
|
||||
---
|
||||
|
||||
# Images
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Localization
|
||||
---
|
||||
|
||||
# Localization
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Page-level Components
|
||||
---
|
||||
|
||||
# Page-level Components
|
||||
|
||||
Next.js App Router special files used by the framework by convention: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Project Structure
|
||||
---
|
||||
|
||||
# Project Structure
|
||||
|
||||
Base project structure and principles of module organization at folder and file level.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Stores
|
||||
---
|
||||
|
||||
# Stores
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Styles
|
||||
---
|
||||
|
||||
# Styles
|
||||
|
||||
CSS writing rules: PostCSS Modules, nesting, media queries, variables, formatting.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: SVG Sprites
|
||||
---
|
||||
|
||||
# SVG Sprites
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Templates & Code Generation
|
||||
---
|
||||
|
||||
# Templates & Code Generation
|
||||
|
||||
Template tools, syntax, and examples for code generation.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Video
|
||||
---
|
||||
|
||||
# Video
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Architecture
|
||||
---
|
||||
|
||||
# Architecture
|
||||
|
||||
Architecture based on FSD (Feature-Sliced Design) and strict module boundaries.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Code Style
|
||||
---
|
||||
|
||||
# Code Style
|
||||
|
||||
Unified code formatting rules: indentation, line breaks, quotes, import order, and readability.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Documentation
|
||||
---
|
||||
|
||||
# Documentation
|
||||
|
||||
Documentation should help understand the purpose of an entity, not duplicate its types or obvious details.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Naming
|
||||
---
|
||||
|
||||
# Naming
|
||||
|
||||
Naming should be predictable, concise, and reflect the meaning of the entity.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Tech Stack
|
||||
---
|
||||
|
||||
# Tech Stack
|
||||
|
||||
Base technology stack and libraries used in projects.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Typing
|
||||
---
|
||||
|
||||
# Typing
|
||||
|
||||
Typing is required for all public interfaces, functions, and components.
|
||||
@@ -1,57 +0,0 @@
|
||||
# NextJS Style Guide
|
||||
|
||||
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure.
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
### Processes
|
||||
|
||||
**What to do** in a specific situation — step-by-step instructions.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Getting Started | What tools to install before starting development? |
|
||||
| Creating an App | How to create a new project, where to get a template? |
|
||||
| Creating Pages | How to add a page: routing and screen? |
|
||||
| Creating Components | How to generate components using templates? |
|
||||
| Styling | What to use: Mantine, tokens, or PostCSS? |
|
||||
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
|
||||
| State Management | When and how to create a store (Zustand)? |
|
||||
| Localization | How to add translations and work with i18next? |
|
||||
|
||||
### Basic Rules
|
||||
|
||||
**What the code should look like** — standards not tied to a specific technology.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Tech Stack | What stack do we use? |
|
||||
| Architecture | How are FSD layers, dependencies, and public API structured? |
|
||||
| Code Style | How to format code: indentation, quotes, imports, early return? |
|
||||
| Naming | How to name files, variables, components, hooks? |
|
||||
| Documentation | How to write JSDoc: what to document and what not? |
|
||||
| Typing | How to type: type vs interface, any/unknown, FC? |
|
||||
|
||||
### Applied Sections
|
||||
|
||||
**How a specific area works** — rules, structure, and code examples for specific technologies and tools.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Project Structure | How are folders and files organized by FSD? |
|
||||
| Components | How is a component structured: files, props, clsx, FC? |
|
||||
| Page-level Components | How to define layout, page, loading, error, not-found? |
|
||||
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
|
||||
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
|
||||
| Images | _(not filled)_ |
|
||||
| SVG Sprites | _(not filled)_ |
|
||||
| Video | _(not filled)_ |
|
||||
| API | _(not filled)_ |
|
||||
| Stores | _(not filled)_ |
|
||||
| Hooks | _(not filled)_ |
|
||||
| Fonts | _(not filled)_ |
|
||||
| Localization | _(not filled)_ |
|
||||
|
||||
## For Assistants
|
||||
|
||||
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Creating an App
|
||||
---
|
||||
|
||||
# Creating an App
|
||||
|
||||
How to create a new application: choosing a project template and initialization.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Creating Components
|
||||
---
|
||||
|
||||
# Creating Components
|
||||
|
||||
Generating components using templates, working with child components.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Creating Pages
|
||||
---
|
||||
|
||||
# Creating Pages
|
||||
|
||||
Page creation pattern: routing (page.tsx) and screen.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Data Fetching
|
||||
---
|
||||
|
||||
# Data Fetching
|
||||
|
||||
How to fetch data: SWR, API client codegen, sockets.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Getting Started
|
||||
---
|
||||
|
||||
# Getting Started
|
||||
|
||||
Setting up the environment and installing tools before starting development.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Localization
|
||||
---
|
||||
|
||||
# Localization
|
||||
|
||||
How to add translations and work with i18next.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: State Management
|
||||
---
|
||||
|
||||
# State Management
|
||||
|
||||
When and how to create a store (Zustand), what to store locally vs globally.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Styling
|
||||
---
|
||||
|
||||
# Styling
|
||||
|
||||
Styling tools priority and rules for their application.
|
||||
@@ -1,89 +0,0 @@
|
||||
---
|
||||
title: Компоненты
|
||||
---
|
||||
|
||||
# Компоненты
|
||||
|
||||
Раздел описывает правила создания UI‑компонентов. Эти правила обязательны для всех слоёв FSD: `app`, `screens`, `layouts`, `widgets`, `features`, `entities`, `shared`.
|
||||
|
||||
## Базовая структура компонента
|
||||
|
||||
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
|
||||
|
||||
```text
|
||||
container/
|
||||
├── styles/
|
||||
│ └── container.module.css
|
||||
├── types/
|
||||
│ └── container.interface.ts
|
||||
├── container.tsx
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
## Пример базового компонента
|
||||
|
||||
`styles/container.module.css`
|
||||
```scss
|
||||
.root {}
|
||||
```
|
||||
В CSS Modules использование имени класса **.root** — это общепринятое соглашение (best practice)
|
||||
|
||||
`types/container.interface.ts`
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры контейнера.
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
```
|
||||
Интерфес параметров компонента всегда наследует свойства своего тега: div, button, итд..
|
||||
|
||||
`container.tsx`
|
||||
|
||||
```tsx
|
||||
import type { FC } from 'react'
|
||||
import cl from 'clsx'
|
||||
import type { ContainerProps } from './types/container.interface'
|
||||
import styles from './styles/container.module.css'
|
||||
|
||||
/**
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - ограничения ширины контента
|
||||
* - центрирования содержимого
|
||||
* - построения адаптивной сетки страницы
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = ({ className, ...htmlAttr }) => {
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
Container...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- Компонент объявляется через `const` и экспортируется именованно.
|
||||
- Пропсы деструктурируются в сигнатуре; если их больше двух — деструктуризацию переносим в тело компонента.
|
||||
- Из пропсов отдельно извлекаются `className` и `...htmlAttr`, чтобы корректно объединять классы и прокидывать остальные атрибуты.
|
||||
- `cl` — короткое имя функции для конкатенации CSS‑классов.
|
||||
- `FC<>` используется для декларации `children`.
|
||||
|
||||
`index.ts`
|
||||
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
## Шаблоны и генерация кода
|
||||
|
||||
Создание компонентов — **только через шаблоны**. Ручное создание файловой структуры компонента запрещено. Это обеспечивает единообразие каркаса, одинаковые папки и имена файлов, уменьшает ручные ошибки и ускоряет старт работы.
|
||||
|
||||
После генерации через **@gromlab/create** — проверить название компонента/файлов и заполнить описание назначения. Подробный порядок действий и перечень обязательных шаблонов — в разделе «Workflow».
|
||||
|
||||
## Вложенные (дочерние) компоненты
|
||||
|
||||
Если для реализации функционала нужны компоненты, которые используются только внутри текущего компонента, создавайте их как вложенные в папке `ui/`. Такие компоненты не экспортируются наружу и используются только локально.
|
||||
|
||||
Вложенные компоненты подчиняются тем же правилам по структуре, именованию и стилю (включая папку `styles/` для их стилей).
|
||||
@@ -1,182 +0,0 @@
|
||||
---
|
||||
title: Page-level компоненты
|
||||
---
|
||||
|
||||
# Page-level компоненты
|
||||
|
||||
Специальные файлы Next.js App Router, которые фреймворк использует по соглашению: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.
|
||||
|
||||
## Общие правила
|
||||
|
||||
- Экспорт через `export default function` — конвенция Next.js.
|
||||
- Типизация через `PropsWithChildren` или явный интерфейс.
|
||||
- Каждая страница (`page.tsx`) должна содержать `metadata` с `title` и `description`.
|
||||
- Минимум логики — page-level компоненты делегируют работу экранам, виджетам и фичам.
|
||||
- Стили в page-level компонентах не используются — стилизация внутри вызываемых компонентов.
|
||||
|
||||
## layout.tsx
|
||||
|
||||
Корневой layout — точка подключения провайдеров, глобальных стилей и метаданных.
|
||||
|
||||
```tsx
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import type { Metadata } from 'next'
|
||||
import { Providers } from './providers'
|
||||
import './styles/index.css'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: 'App',
|
||||
template: '%s | App',
|
||||
},
|
||||
description: 'Описание приложения',
|
||||
metadataBase: new URL('https://example.com'),
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: 'ru_RU',
|
||||
siteName: 'App',
|
||||
images: [
|
||||
{
|
||||
url: '/og-image.png',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: 'App',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<html lang="ru" suppressHydrationWarning>
|
||||
<body>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Вложенный layout — для секции с общей обёрткой (sidebar, header):
|
||||
|
||||
```tsx
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import { DashboardLayout } from '@/shared/ui/dashboard-layout'
|
||||
|
||||
export default function Layout({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<DashboardLayout>
|
||||
{children}
|
||||
</DashboardLayout>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## page.tsx
|
||||
|
||||
Тонкий файл — только импорт и рендер экрана. Логика, стили и зависимости размещаются в экране, не в `page.tsx`.
|
||||
|
||||
```tsx
|
||||
import type { Metadata } from 'next'
|
||||
import { HomeScreen } from '@/screens/home'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Главная',
|
||||
description: 'Главная страница приложения',
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
return <HomeScreen />
|
||||
}
|
||||
```
|
||||
|
||||
С параметрами маршрута:
|
||||
|
||||
```tsx
|
||||
import type { Metadata } from 'next'
|
||||
import { ProfileScreen } from '@/screens/profile'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Профиль',
|
||||
description: 'Страница профиля пользователя',
|
||||
}
|
||||
|
||||
interface ProfilePageProps {
|
||||
params: Promise<{ id: string }>
|
||||
}
|
||||
|
||||
export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
const { id } = await params
|
||||
|
||||
return <ProfileScreen id={id} />
|
||||
}
|
||||
```
|
||||
|
||||
Каждая страница должна содержать `metadata` с `title` — он подставится в шаблон из корневого layout: `Профиль | App`.
|
||||
|
||||
## loading.tsx
|
||||
|
||||
Состояние загрузки. Показывается пока загружается контент страницы.
|
||||
|
||||
```tsx
|
||||
export default function Loading() {
|
||||
return <div>Загрузка...</div>
|
||||
}
|
||||
```
|
||||
|
||||
## error.tsx
|
||||
|
||||
Обработка ошибок. Обязательно `'use client'` — error boundary работает только на клиенте. Разметку выносим в экран.
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import { ErrorScreen } from '@/screens/error'
|
||||
|
||||
interface ErrorPageProps {
|
||||
error: Error & { digest?: string }
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
const ErrorPage: FC<ErrorPageProps> = ({ error, reset }) => {
|
||||
return <ErrorScreen error={error} reset={reset} />
|
||||
}
|
||||
|
||||
export default ErrorPage
|
||||
```
|
||||
|
||||
## not-found.tsx
|
||||
|
||||
Страница 404. Показывается когда маршрут не найден. Разметку выносим в экран.
|
||||
|
||||
```tsx
|
||||
import type { Metadata } from 'next'
|
||||
import { NotFoundScreen } from '@/screens/not-found'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Страница не найдена',
|
||||
description: 'Запрашиваемая страница не существует',
|
||||
}
|
||||
|
||||
export default function NotFound() {
|
||||
return <NotFoundScreen />
|
||||
}
|
||||
```
|
||||
|
||||
## template.tsx
|
||||
|
||||
Аналог layout, но пересоздаётся при каждой навигации (не сохраняет состояние). Используется редко — для анимаций переходов между страницами.
|
||||
|
||||
```tsx
|
||||
import type { PropsWithChildren } from 'react'
|
||||
|
||||
export default function Template({ children }: PropsWithChildren) {
|
||||
return <div>{children}</div>
|
||||
}
|
||||
```
|
||||
@@ -1,149 +0,0 @@
|
||||
---
|
||||
title: Структура проекта
|
||||
---
|
||||
|
||||
# Структура проекта
|
||||
|
||||
Раздел описывает базовую структуру проекта Next.js (App Router) и принципы организации модулей на уровне папок и файлов.
|
||||
|
||||
## Базовая структура проекта
|
||||
|
||||
```text
|
||||
src/
|
||||
├── app/ # Слой app: роутинг, провайдеры, глобальные стили
|
||||
│ ├── providers/ # Провайдеры и обёртки приложения
|
||||
│ ├── styles/ # Глобальные стили, CSS-переменные, custom media
|
||||
│ ├── layout.tsx # Корневой layout (провайдеры, стили, метаданные)
|
||||
│ ├── page.tsx # Главная страница → HomeScreen
|
||||
│ └── profile/
|
||||
│ ├── page.tsx # → ProfileScreen
|
||||
│ └── [id]/
|
||||
│ └── page.tsx # → ProfileDetailScreen
|
||||
├── screens/ # UI-компоненты страниц
|
||||
│ ├── home/
|
||||
│ │ ├── home.screen.tsx
|
||||
│ │ └── index.ts
|
||||
│ └── profile/
|
||||
│ ├── profile.screen.tsx
|
||||
│ └── index.ts
|
||||
├── layouts/ # Общие шаблоны и каркасы страниц
|
||||
│ └── main-layout/
|
||||
│ ├── main-layout.layout.tsx
|
||||
│ └── index.ts
|
||||
├── widgets/ # Крупные блоки интерфейса
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/ # Пользовательские сценарии
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth-by-email.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/ # Бизнес-сущности
|
||||
│ └── user/
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/ # Общие ресурсы проекта
|
||||
├── ui/ # Повторно используемые UI-элементы
|
||||
│ └── icon/
|
||||
│ ├── styles/
|
||||
│ │ └── icon.module.css
|
||||
│ ├── types/
|
||||
│ │ └── icon.interface.ts
|
||||
│ ├── icon.tsx
|
||||
│ └── index.ts
|
||||
├── lib/ # Утилиты и хелперы
|
||||
├── services/ # Общие сервисы и клиенты
|
||||
├── config/ # Общие конфигурации и константы
|
||||
└── assets/ # Ресурсы
|
||||
├── images/
|
||||
├── icons/
|
||||
├── fonts/
|
||||
└── video/
|
||||
```
|
||||
|
||||
## Слой `app/`
|
||||
|
||||
Папка `app/` совмещает две роли: инициализация приложения (провайдеры, глобальные стили) и файловый роутинг Next.js (route-сегменты, `layout.tsx`, `page.tsx`).
|
||||
|
||||
- `providers/` и `styles/` -- это инфраструктура приложения, они не являются частью роутинга.
|
||||
- Route-сегменты (вложенные папки с `page.tsx`) -- это роутинг Next.js. Они не содержат логики, только импортируют экраны из `screens/`.
|
||||
|
||||
Компоненты, хуки, стили и утилиты не размещаются внутри route-сегментов -- всё это живёт в соответствующих слоях FSD.
|
||||
|
||||
## Правила организации
|
||||
|
||||
- В слоях FSD (`features`, `entities`, `widgets`, `screens` и т.д.) `ui/` используется только для дочерних элементов, которые относятся к модулю и не экспортируются отдельно. Главные компоненты, которые составляют сам слой, держат собственные `*.feature.tsx`, `*.widget.tsx` и т. п., а `ui/` служит для вспомогательных мелких компонентов.
|
||||
- В `shared/ui/` хранятся базовые UI-элементы/компоненты, которыми пользуются сразу несколько модулей; в этом случае они экспортируются наружу и не считаются «дочерними» для слоя.
|
||||
- Если модуль строится вокруг «главного» компонента (`*.feature.tsx`, `*.screen.tsx`, `*.widget.tsx`), помещайте его в корень модуля и экспортируйте через `index.ts`. Проверяйте, что `ui/` не используется просто как «контейнер» слоя.
|
||||
- Каждый слой и модуль хранится в собственной папке.
|
||||
- Внутренние реализации разделяются на `ui/`, `model/`, `styles/`, `helpers/`, `lib/`, `api/`.
|
||||
- Публичный API модуля объявляется в `index.ts`.
|
||||
- Внутренние файлы не импортируются напрямую извне.
|
||||
- Не смешивать ответственность разных слоёв в одном модуле.
|
||||
|
||||
## Пример организации структуры
|
||||
|
||||
**Плохо** -- плоская структура без архитектуры:
|
||||
```text
|
||||
src/
|
||||
├── components/
|
||||
│ ├── Header.tsx
|
||||
│ ├── LoginForm.tsx
|
||||
│ ├── UserCard.tsx
|
||||
│ └── Button.tsx
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts
|
||||
│ └── useUser.ts
|
||||
├── api/
|
||||
│ ├── auth.ts
|
||||
│ └── user.ts
|
||||
├── styles/
|
||||
│ ├── header.module.css
|
||||
│ └── login.module.css
|
||||
├── types/
|
||||
│ └── user.ts
|
||||
└── utils/
|
||||
└── format.ts
|
||||
```
|
||||
|
||||
Нет слоёв, нет границ ответственности -- Header и Button лежат рядом, хотя это разные уровни абстракции. LoginForm знает про API напрямую. При росте проекта `components/` превращается в свалку.
|
||||
|
||||
**Хорошо** -- та же функциональность в FSD:
|
||||
```text
|
||||
src/
|
||||
├── widgets/
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/
|
||||
│ └── user/
|
||||
│ ├── ui/
|
||||
│ │ └── user-card.tsx
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/
|
||||
├── ui/
|
||||
│ └── button/
|
||||
│ ├── button.tsx
|
||||
│ └── index.ts
|
||||
└── lib/
|
||||
└── format.ts
|
||||
```
|
||||
|
||||
Каждый элемент на своём слое, с публичным API и чёткими границами ответственности.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: SVG-спрайты
|
||||
---
|
||||
|
||||
# SVG-спрайты
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: Архитектура
|
||||
---
|
||||
|
||||
# Архитектура
|
||||
|
||||
Архитектура построена на FSD (`Feature‑Sliced Design`) и строгих границах модулей.
|
||||
Цель — разделить ответственность, упростить сопровождение и контроль зависимостей.
|
||||
|
||||
## Принципы
|
||||
|
||||
- Разделять UI, бизнес-логику и инфраструктуру.
|
||||
- Держать зависимости однонаправленными.
|
||||
- Открывать наружу только публичный API модулей.
|
||||
- Не допускать циклических зависимостей.
|
||||
|
||||
## Слои (FSD)
|
||||
|
||||
- **app** — инициализация приложения: провайдеры, глобальные стили. В Next.js эта же папка `app/` дополнительно содержит системные файлы роутинга (`layout.tsx`, `page.tsx`).
|
||||
- **screens** — UI-компоненты страниц. Каждый экран — отдельный компонент, который собирает виджеты и фичи конкретной страницы. Роутинг только использует эти компоненты — он не является частью слоя `screens`. В Next.js файлы `page.tsx` остаются тонкими: импортируют экран и рендерят его.
|
||||
- **layouts** — каркас и шаблоны страниц.
|
||||
- **widgets** — крупные блоки интерфейса, собирающие несколько сценариев.
|
||||
- **features** — отдельные пользовательские действия и сценарии.
|
||||
- **entities** — бизнес-сущности и их модель.
|
||||
- **shared** — переиспользуемая инфраструктура, утилиты и базовые UI‑компоненты.
|
||||
|
||||
## Модули (FSD)
|
||||
|
||||
- Модуль — это отдельная папка в слоях `screens`, `layouts`, `widgets`, `features`, `entities`, которая реализует один сценарий/блок. В корне модуля лежит главный файл (`*.screen.tsx`, `*.layout.tsx`, `*.widget.tsx`, `*.feature.tsx`, `*.entity.tsx`) и публичный API (`index.ts`).
|
||||
- Внутри модуля используются подпапки (по необходимости):
|
||||
- `ui/` — дочерние UI‑компоненты модуля.
|
||||
- `model/` — состояние и бизнес‑логика модуля.
|
||||
- `styles/` — локальные стили модуля.
|
||||
- `helpers/` — локальные хелперы.
|
||||
- `lib/` — утилиты модуля.
|
||||
- `api/` — API‑вызовы модуля.
|
||||
|
||||
## Правила зависимостей
|
||||
|
||||
- Допустимые импорты идут сверху вниз: `app → screens → layouts → widgets → features → entities → shared`.
|
||||
- Импорты между слоями — через публичный API.
|
||||
- Внутри одного слоя — относительные импорты.
|
||||
|
||||
## Публичный API модулей
|
||||
|
||||
- Каждый модуль экспортирует наружу только то, что нужно другим слоям.
|
||||
- Внешние импорты идут только через `index`‑файл модуля.
|
||||
- Внутренние файлы не импортируются напрямую извне.
|
||||
|
||||
## Границы ответственности
|
||||
|
||||
- Бизнес‑логика не размещается в UI‑компонентах.
|
||||
- UI‑компоненты должны быть максимально простыми и предсказуемыми.
|
||||
- Связь между независимыми сценариями поднимается на уровень выше.
|
||||
|
||||
## Типовые ошибки
|
||||
|
||||
- Импорт из более высокого слоя в более низкий.
|
||||
- Смешивание логики нескольких слоёв в одном модуле.
|
||||
- Прямые импорты внутренних файлов, минуя публичный API.
|
||||
@@ -1,64 +0,0 @@
|
||||
---
|
||||
title: Документирование
|
||||
---
|
||||
|
||||
# Документирование
|
||||
|
||||
Документирование должно помогать понять назначение сущности, а не дублировать её типы или очевидные детали.
|
||||
|
||||
## Правила
|
||||
|
||||
- Документировать только назначение функций, компонентов, типов, интерфейсов и enum.
|
||||
- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали.
|
||||
- В интерфейсах, типах и enum описывать только смысл поля или значения.
|
||||
- Описание должно быть кратким, информативным и завершаться точкой.
|
||||
|
||||
## Примеры
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Список задач пользователя.
|
||||
*/
|
||||
export const TodoList = memo(() => { ... });
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
*/
|
||||
export interface TodoItem {
|
||||
/** Уникальный идентификатор задачи. */
|
||||
id: string;
|
||||
/** Текст задачи. */
|
||||
text: string;
|
||||
/** Статус выполнения задачи. */
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Перечисление фильтров задач.
|
||||
*/
|
||||
export enum TodoFilter {
|
||||
/** Все задачи. */
|
||||
All = 'all',
|
||||
/** Только активные задачи. */
|
||||
Active = 'active',
|
||||
/** Только выполненные задачи. */
|
||||
Completed = 'completed',
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```ts
|
||||
// Плохо: дублирование параметров и возвращаемых значений.
|
||||
/**
|
||||
* @param id - идентификатор задачи
|
||||
* @returns объект задачи
|
||||
*/
|
||||
|
||||
// Плохо: описание очевидных деталей.
|
||||
/**
|
||||
* id — идентификатор задачи
|
||||
* text — текст задачи
|
||||
* completed — статус выполнения
|
||||
*/
|
||||
```
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
title: Технологии и библиотеки
|
||||
---
|
||||
|
||||
# Технологии и библиотеки
|
||||
|
||||
Базовый стек технологий и библиотек, на который опираются проекты и примеры в документации.
|
||||
|
||||
## Что используем
|
||||
|
||||
### Стек
|
||||
- **React/TypeScript** — основной стек для UI и приложения.
|
||||
- **Next.js** — для продуктовых сайтов.
|
||||
|
||||
### Архитектура
|
||||
- **FSD (Feature-Sliced Design)** — структура проекта и границы модулей.
|
||||
|
||||
### UI компоненты
|
||||
- **Mantine UI** — базовые UI-компоненты.
|
||||
|
||||
### Fetch (API)
|
||||
- **@gromlab/api-codegen** — генерация API‑клиентов и типов.
|
||||
- **SWR** — получение, кеширование, ревалидация, дедубликация.
|
||||
- **SWR (useSWRSubscription)** - сокеты, реалтайм подписки.
|
||||
|
||||
### Store
|
||||
- **Zustand** — глобальное состояние.
|
||||
|
||||
### Локализация
|
||||
- **i18next (i18n)** — локализация всех пользовательских текстов.
|
||||
|
||||
### Тестирование
|
||||
- **Vitest** — тестирование.
|
||||
|
||||
### Стили
|
||||
- **PostCSS Modules** — изоляция стилей.
|
||||
- **Mobile First** — подход к адаптивной верстке.
|
||||
- **clsx** — конкатенация CSS‑классов.
|
||||
|
||||
### Генерация
|
||||
- **@gromlab/create** — шаблонизатор для создания слоёв и других файлов из шаблонов.
|
||||
@@ -1,60 +0,0 @@
|
||||
# NextJS Style Guide
|
||||
|
||||
Правила и стандарты разработки на NextJS и TypeScript: архитектура, типизация, стили, компоненты, API и инфраструктурные разделы.
|
||||
|
||||
## Для ассистентов
|
||||
|
||||
Полная документация в одном MD файле: https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md
|
||||
|
||||
## Структура документации
|
||||
|
||||
### Workflow
|
||||
|
||||
**Что делать и в каком порядке** — пошаговые инструкции.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Начало работы | Что нужно знать перед началом разработки? |
|
||||
| Создание проекта | Как начать новый проект? |
|
||||
| Генерация кода | Какие модули должны генерироваться из шаблонов? |
|
||||
| Добавление страницы | Как добавить новую страницу в проект? |
|
||||
| Добавление UI-модуля | Как создать компонент, фичу, виджет, сущность или layout? |
|
||||
| Стилизация | Как стилизовать компоненты в проекте? |
|
||||
| Получение данных | Как получать данные с сервера? |
|
||||
| Управление состоянием | Как работать с состоянием? |
|
||||
| Локализация | Как добавлять переводы и подключать локализацию? |
|
||||
|
||||
### Базовые правила
|
||||
|
||||
**Каким должен быть код** — стандарты, не привязанные к конкретной технологии.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Технологии и библиотеки | Какой стек используем? |
|
||||
| Архитектура | Как устроены слои FSD, зависимости, публичный API? |
|
||||
| Стиль кода | Как оформлять код: отступы, кавычки, импорты, early return? |
|
||||
| Именование | Как называть файлы, переменные, компоненты, хуки? |
|
||||
| Документирование | Как писать JSDoc: что документировать, а что нет? |
|
||||
| Типизация | Как типизировать: type vs interface, any/unknown, FC? |
|
||||
|
||||
### Прикладные разделы
|
||||
|
||||
**Как это настроить и использовать** — конфигурация, структура и примеры кода для конкретных областей.
|
||||
|
||||
| Раздел | Отвечает на вопрос |
|
||||
|--------|-------------------|
|
||||
| Настройка VS Code | Как настроить редактор для проекта? |
|
||||
| Структура проекта | Как организованы папки и файлы по FSD? |
|
||||
| Компоненты | Как устроен компонент: файлы, пропсы, clsx, FC? |
|
||||
| Page-level компоненты | Как описывать layout, page, loading, error, not-found? |
|
||||
| Шаблоны и генерация кода | Как работают шаблоны, синтаксис и инструменты генерации? |
|
||||
| Стили | Как писать CSS: PostCSS Modules, вложенность, медиа, токены? |
|
||||
| Изображения | _(не заполнен)_ |
|
||||
| SVG-спрайты | _(не заполнен)_ |
|
||||
| Видео | _(не заполнен)_ |
|
||||
| API | _(не заполнен)_ |
|
||||
| Stores | _(не заполнен)_ |
|
||||
| Хуки | _(не заполнен)_ |
|
||||
| Шрифты | _(не заполнен)_ |
|
||||
| Локализация | _(не заполнен)_ |
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
title: Workflow
|
||||
---
|
||||
|
||||
# Workflow
|
||||
|
||||
Порядок действий при разработке — от создания проекта до реализации фич.
|
||||
|
||||
## Начало работы
|
||||
|
||||
Подготовка окружения перед началом разработки.
|
||||
|
||||
1. Открыть проект в VS Code.
|
||||
2. Установить рекомендуемые расширения (редактор предложит автоматически).
|
||||
3. Ознакомиться со стеком: Next.js (App Router), Mantine, Zustand, FSD.
|
||||
|
||||
## Создание проекта
|
||||
|
||||
Инициализация нового проекта из готового шаблона.
|
||||
|
||||
1. Создать проект из шаблона:
|
||||
```bash
|
||||
npx tiged git@gromlab.ru:templates/nextjs.git my-app
|
||||
cd my-app
|
||||
npm install
|
||||
```
|
||||
2. Проект готов к разработке — стек, структура FSD, конфигурация
|
||||
редактора и шаблоны генерации уже настроены.
|
||||
|
||||
## Генерация кода
|
||||
|
||||
Создание модулей из шаблонов `.templates/` вместо ручного создания файлов.
|
||||
|
||||
1. Определить тип модуля и соответствующий шаблон:
|
||||
|
||||
| Модуль | Слой | Шаблон |
|
||||
|------------|--------------|-------------|
|
||||
| Компонент | `shared/ui/` | `component` |
|
||||
| Фича | `features/` | `feature` |
|
||||
| Виджет | `widgets/` | `widget` |
|
||||
| Сущность | `entities/` | `entity` |
|
||||
| Layout | `layouts/` | `layout` |
|
||||
| Экран | `screens/` | `screen` |
|
||||
| Стор | `model/` | `store` |
|
||||
|
||||
2. Сгенерировать модуль из шаблона.
|
||||
3. Если подходящего шаблона нет — сначала создать шаблон, затем использовать.
|
||||
|
||||
Ручное создание файловой структуры модулей запрещено.
|
||||
|
||||
## Добавление страницы
|
||||
|
||||
Создание нового маршрута: экран + точка входа для роутинга.
|
||||
|
||||
1. Сгенерировать экран из шаблона `screen` в `src/screens/`.
|
||||
2. Заполнить экран логикой и стилями.
|
||||
3. Создать `page.tsx` в нужном маршруте `src/app/`.
|
||||
|
||||
`page.tsx` — тонкая обёртка: только `metadata` и рендер экрана.
|
||||
Логика, стили и хуки размещаются в экране, не в `page.tsx`.
|
||||
|
||||
## Добавление UI-модуля
|
||||
|
||||
Создание компонента, фичи, виджета, сущности или layout.
|
||||
|
||||
1. Сгенерировать модуль из соответствующего шаблона в целевой слой.
|
||||
2. Заполнить модуль логикой и стилями.
|
||||
3. Дочерние компоненты — генерировать из шаблона `component` в папку `ui/`
|
||||
внутри родителя.
|
||||
|
||||
Дочерние компоненты не экспортируются через `index.ts` родителя.
|
||||
|
||||
## Стилизация
|
||||
|
||||
Выбор инструмента стилизации по приоритету.
|
||||
|
||||
1. Использовать Mantine-компоненты и их пропсы.
|
||||
2. Если Mantine не покрывает — использовать CSS-токены
|
||||
(`--color-*`, `--space-*`, `--radius-*`).
|
||||
3. Если нужна кастомная стилизация — PostCSS Modules.
|
||||
|
||||
Инлайн-стили (`style`), магические значения и глобальные стили
|
||||
вне `app/styles/` запрещены.
|
||||
|
||||
## Получение данных
|
||||
|
||||
*Раздел в разработке* — SWR, генерация API-клиентов, сокеты.
|
||||
|
||||
## Управление состоянием
|
||||
|
||||
*Раздел в разработке* — когда создавать стор, что хранить локально и глобально.
|
||||
|
||||
## Локализация
|
||||
|
||||
*Раздел в разработке* — переводы и i18next.
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
title: Генерация кода
|
||||
---
|
||||
|
||||
# Генерация кода
|
||||
|
||||
Как создавать модули в проекте с помощью шаблонов — какие модули покрыты генерацией и когда стоит создавать новые шаблоны.
|
||||
|
||||
## Какие модули генерируются из шаблонов
|
||||
|
||||
| Модуль | Слой | Шаблон |
|
||||
|---|---|---|
|
||||
| Компонент | `shared/ui/` | `component` |
|
||||
| Фича | `features/` | `feature` |
|
||||
| Виджет | `widgets/` | `widget` |
|
||||
| Сущность | `entities/` | `entity` |
|
||||
| Layout | `layouts/` | `layout` |
|
||||
| Экран | `screens/` | `screen` |
|
||||
| Стор | `model/` | `store` |
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
В проекте принято создавать модули из шаблонов `.templates/`. Шаблоны задают единообразную файловую структуру и сокращают рутину — не нужно вручную создавать папки, файлы типов, стилей и экспорты.
|
||||
|
||||
Если для нужного модуля нет подходящего шаблона — стоит сначала создать шаблон, а затем использовать его.
|
||||
|
||||
## Когда создавать новый шаблон
|
||||
|
||||
- Повторяющаяся структура появляется больше одного раза.
|
||||
- Существующий шаблон не покрывает нужный тип модуля.
|
||||
|
||||
Инструменты и синтаксис шаблонов — [Шаблоны и генерация кода](/applied/templates-generation).
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: Создание проекта
|
||||
---
|
||||
|
||||
# Создание проекта
|
||||
|
||||
Как начать новый проект, соответствующий стандартам этого руководства.
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
Новый проект создаётся из готового шаблона. Шаблон содержит настроенный стек, структуру FSD, конфигурацию редактора и шаблоны генерации кода — проект готов к разработке сразу после установки зависимостей.
|
||||
|
||||
### Создание из шаблона
|
||||
|
||||
```bash
|
||||
npx tiged git@gromlab.ru:templates/nextjs.git my-app
|
||||
cd my-app
|
||||
npm install
|
||||
```
|
||||
|
||||
## Что входит в шаблон
|
||||
|
||||
- Next.js + TypeScript (App Router)
|
||||
- Mantine UI + PostCSS Modules
|
||||
- Biome (линтинг и форматирование)
|
||||
- Zustand, SWR
|
||||
- Структура FSD (`screens/`, `widgets/`, `features/`, `entities/`, `shared/`)
|
||||
- Шаблоны генерации (`.templates/`)
|
||||
- Конфигурация VS Code (`.vscode/`)
|
||||
- CSS-токены (цвета, отступы, радиусы, медиа)
|
||||
- Open Graph метаданные
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: Добавление UI-модуля
|
||||
---
|
||||
|
||||
# Добавление UI-модуля
|
||||
|
||||
Как создать компонент, фичу, виджет, сущность или layout в проекте.
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
Все UI-модули создаются только из шаблонов `.templates/`. Ручное создание файловой структуры запрещено. Если подходящего шаблона нет — сначала создать шаблон в `.templates/`, затем использовать его.
|
||||
|
||||
## Порядок действий
|
||||
|
||||
1. [Сгенерировать](/applied/templates-generation) модуль из соответствующего шаблона в целевой слой.
|
||||
2. Заполнить модуль логикой и стилями.
|
||||
|
||||
## Дочерние компоненты
|
||||
|
||||
Если модулю нужны внутренние подкомпоненты — [генерировать](/applied/templates-generation) их из шаблона `component` в папку `ui/` внутри родительского модуля. Дочерние компоненты не экспортируются через `index.ts` родителя.
|
||||
|
||||
Правила написания компонентов — [Компоненты](/applied/components).
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
title: Добавление страницы
|
||||
---
|
||||
|
||||
# Добавление страницы
|
||||
|
||||
Как добавить новую страницу в проект по стандартам этого руководства.
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
Страница в проекте — это два файла: экран в `src/screens/` (вся логика, стили, зависимости) и `page.tsx` в `src/app/` (точка входа для роутинга Next.js). Экран генерируется из шаблона, `page.tsx` создаётся вручную.
|
||||
|
||||
## Порядок действий
|
||||
|
||||
1. [Сгенерировать](/applied/templates-generation) экран из шаблона `screen` в папку `src/screens/`.
|
||||
|
||||
2. Заполнить экран логикой и стилями.
|
||||
|
||||
3. Создать `page.tsx` в нужном маршруте `src/app/`. Файл страницы должен быть тонким — только `metadata` и рендер экрана. Никакой логики, стилей и хуков в `page.tsx` не размещается — всё это живёт в экране.
|
||||
|
||||
## Правила
|
||||
|
||||
- Ручное создание файловой структуры экрана запрещено — только [генерация](/applied/templates-generation) из шаблона.
|
||||
- Логика, стили и зависимости размещаются в экране, не в `page.tsx`.
|
||||
- Каждая страница содержит `metadata` с `title` и `description`.
|
||||
|
||||
Примеры `page.tsx` и `metadata` — [Page-level компоненты](/applied/page-level).
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Получение данных
|
||||
---
|
||||
|
||||
# Получение данных
|
||||
|
||||
Как получать данные с сервера — SWR, генерация API-клиентов, сокеты.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Локализация
|
||||
---
|
||||
|
||||
# Локализация
|
||||
|
||||
Как добавлять переводы и подключать локализацию через i18next.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Управление состоянием
|
||||
---
|
||||
|
||||
# Управление состоянием
|
||||
|
||||
Как работать с состоянием — когда создавать стор, что хранить локально и глобально.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Стилизация
|
||||
---
|
||||
|
||||
# Стилизация
|
||||
|
||||
Как стилизовать компоненты в проекте — приоритет инструментов и правила их применения.
|
||||
|
||||
## Приоритет стилизации
|
||||
|
||||
Основной UI-фреймворк проекта — **Mantine**. При стилизации компонентов придерживаться следующего приоритета:
|
||||
|
||||
1. **Mantine-компоненты и их пропсы** — в первую очередь использовать встроенные возможности Mantine (пропсы, `classNames`, `styles`).
|
||||
2. **Глобальные CSS-токены** (`--color-*`, `--space-*`, `--radius-*`) — для значений, которые не покрываются Mantine.
|
||||
3. **PostCSS Modules** — когда Mantine не покрывает задачу и нужна кастомная стилизация.
|
||||
|
||||
## Что запрещено
|
||||
|
||||
- **Инлайн-стили** — использование атрибута `style` в компонентах строго запрещено.
|
||||
- **Магические значения** — произвольные цвета, отступы и скругления запрещены, использовать токены.
|
||||
- **Глобальные стили** вне `app/styles/` запрещены.
|
||||
|
||||
Правила написания CSS, вложенность, медиа-запросы и токены — [Стили](/applied/styles).
|
||||
@@ -1,137 +0,0 @@
|
||||
<!-- /index -->
|
||||
# NextJS Style Guide
|
||||
|
||||
Rules and standards for NextJS and TypeScript development: architecture, typing, styles, components, API, and infrastructure.
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
### Processes
|
||||
|
||||
**What to do** in a specific situation — step-by-step instructions.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Getting Started | What tools to install before starting development? |
|
||||
| Creating an App | How to create a new project, where to get a template? |
|
||||
| Creating Pages | How to add a page: routing and screen? |
|
||||
| Creating Components | How to generate components using templates? |
|
||||
| Styling | What to use: Mantine, tokens, or PostCSS? |
|
||||
| Data Fetching | How to fetch data: SWR, codegen, sockets? |
|
||||
| State Management | When and how to create a store (Zustand)? |
|
||||
| Localization | How to add translations and work with i18next? |
|
||||
|
||||
### Basic Rules
|
||||
|
||||
**What the code should look like** — standards not tied to a specific technology.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Tech Stack | What stack do we use? |
|
||||
| Architecture | How are FSD layers, dependencies, and public API structured? |
|
||||
| Code Style | How to format code: indentation, quotes, imports, early return? |
|
||||
| Naming | How to name files, variables, components, hooks? |
|
||||
| Documentation | How to write JSDoc: what to document and what not? |
|
||||
| Typing | How to type: type vs interface, any/unknown, FC? |
|
||||
|
||||
### Applied Sections
|
||||
|
||||
**How a specific area works** — rules, structure, and code examples for specific technologies and tools.
|
||||
|
||||
| Section | Answers the question |
|
||||
|---------|---------------------|
|
||||
| Project Structure | How are folders and files organized by FSD? |
|
||||
| Components | How is a component structured: files, props, clsx, FC? |
|
||||
| Page-level Components | How to define layout, page, loading, error, not-found? |
|
||||
| Templates & Code Generation | How do templates work: syntax, variables, modifiers? |
|
||||
| Styles | How to write CSS: PostCSS Modules, nesting, media, tokens? |
|
||||
| Images | _(not filled)_ |
|
||||
| SVG Sprites | _(not filled)_ |
|
||||
| Video | _(not filled)_ |
|
||||
| API | _(not filled)_ |
|
||||
| Stores | _(not filled)_ |
|
||||
| Hooks | _(not filled)_ |
|
||||
| Fonts | _(not filled)_ |
|
||||
| Localization | _(not filled)_ |
|
||||
|
||||
## For Assistants
|
||||
|
||||
Full documentation in a single MD file: https://gromlab.ru/docs/frontend-style-guide/raw/branch/main/generated/en/RULES.md
|
||||
|
||||
<!-- /basics/tech-stack -->
|
||||
## Tech Stack
|
||||
|
||||
Base technology stack and libraries used in projects.
|
||||
|
||||
<!-- /basics/architecture -->
|
||||
## Architecture
|
||||
|
||||
Architecture based on FSD (Feature-Sliced Design) and strict module boundaries.
|
||||
|
||||
<!-- /basics/code-style -->
|
||||
## Code Style
|
||||
|
||||
Unified code formatting rules: indentation, line breaks, quotes, import order, and readability.
|
||||
|
||||
<!-- /basics/naming -->
|
||||
## Naming
|
||||
|
||||
Naming should be predictable, concise, and reflect the meaning of the entity.
|
||||
|
||||
<!-- /basics/documentation -->
|
||||
## Documentation
|
||||
|
||||
Documentation should help understand the purpose of an entity, not duplicate its types or obvious details.
|
||||
|
||||
<!-- /basics/typing -->
|
||||
## Typing
|
||||
|
||||
Typing is required for all public interfaces, functions, and components.
|
||||
|
||||
<!-- /applied/project-structure -->
|
||||
## Project Structure
|
||||
|
||||
Base project structure and principles of module organization at folder and file level.
|
||||
|
||||
<!-- /applied/components -->
|
||||
## Components
|
||||
|
||||
Rules for creating UI components across all FSD layers.
|
||||
|
||||
<!-- /applied/page-level -->
|
||||
## Page-level Components
|
||||
|
||||
Next.js App Router special files used by the framework by convention: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.
|
||||
|
||||
<!-- /applied/templates-generation -->
|
||||
## Templates & Code Generation
|
||||
|
||||
Template tools, syntax, and examples for code generation.
|
||||
|
||||
<!-- /applied/styles -->
|
||||
## Styles
|
||||
|
||||
CSS writing rules: PostCSS Modules, nesting, media queries, variables, formatting.
|
||||
|
||||
<!-- /applied/images-sprites -->
|
||||
## Images
|
||||
|
||||
<!-- /applied/svg-sprites -->
|
||||
## SVG Sprites
|
||||
|
||||
<!-- /applied/video -->
|
||||
## Video
|
||||
|
||||
<!-- /applied/api -->
|
||||
## API
|
||||
|
||||
<!-- /applied/stores -->
|
||||
## Stores
|
||||
|
||||
<!-- /applied/hooks -->
|
||||
## Hooks
|
||||
|
||||
<!-- /applied/fonts -->
|
||||
## Fonts
|
||||
|
||||
<!-- /applied/localization -->
|
||||
## Localization
|
||||
File diff suppressed because it is too large
Load Diff
23
notes
Normal file
23
notes
Normal file
@@ -0,0 +1,23 @@
|
||||
# TODO
|
||||
|
||||
## Триггеры: классификация и расширение
|
||||
|
||||
Текущий список триггеров слабо проработан. Нужно:
|
||||
|
||||
1. Классифицировать триггеры по группам:
|
||||
- Создание — новые модули, компоненты, страницы
|
||||
- Ресурсы — ассеты (иконки, шрифты, изображения, видео)
|
||||
- Данные — API, сторы, серверные данные, формы
|
||||
- Навигация — роутинг, middleware, редиректы
|
||||
- Модификация — рефакторинг, перенос, удаление
|
||||
- Инфраструктура — зависимости, переводы, настройка окружения
|
||||
|
||||
2. Добавить недостающие триггеры. Примеры пробелов:
|
||||
- Создание: утилита/хелпер, тип/интерфейс, контекст
|
||||
- Данные: создать форму, добавить валидацию
|
||||
- Навигация: динамический роут, middleware, редирект
|
||||
- Модификация: рефакторинг компонента, перенос модуля, удаление модуля
|
||||
- Обработка ошибок: error boundary, fallback UI, error.tsx, not-found.tsx, loading.tsx
|
||||
- Авторизация: защита страницы, проверка прав
|
||||
|
||||
3. Обновить секцию "Триггеры" в DEVELOP.md — перейти на новые группы.
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "nextjs-style-guide",
|
||||
"name": "frontend-style-guide",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "nextjs-style-guide",
|
||||
"name": "frontend-style-guide",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.3"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "nextjs-style-guide",
|
||||
"name": "frontend-style-guide",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"docs": "node ./concat-md.js",
|
||||
"build:ai": "node ./scripts/build-ai.js",
|
||||
"dev": "vitepress dev .",
|
||||
"build": "vitepress build .",
|
||||
"serve": "vitepress serve ."
|
||||
|
||||
88
scripts/build-ai.js
Normal file
88
scripts/build-ai.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { pathToFileURL } from "url";
|
||||
|
||||
const SRC_DIR = "./src";
|
||||
const DIST_DIR = "./dist/ai";
|
||||
const SCRIPTS_DIR = "./scripts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Сборка по манифесту
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function buildForFramework(framework) {
|
||||
const manifestPath = path.join(SCRIPTS_DIR, `${framework}.build.js`);
|
||||
|
||||
if (!fs.existsSync(manifestPath)) {
|
||||
console.error(`Манифест не найден: ${manifestPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const manifest = (await import(pathToFileURL(path.resolve(manifestPath)).href)).default;
|
||||
const outDir = path.join(DIST_DIR, framework);
|
||||
|
||||
// Очищаем выходную директорию
|
||||
if (fs.existsSync(outDir)) {
|
||||
fs.rmSync(outDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log(`\nСборка: ${manifest.name} (${framework})`);
|
||||
console.log(`Выход: ${outDir}\n`);
|
||||
|
||||
const errors = [];
|
||||
let count = 0;
|
||||
|
||||
for (const [destRelative, srcRelative] of Object.entries(manifest.files)) {
|
||||
const srcPath = path.join(SRC_DIR, srcRelative);
|
||||
const destPath = path.join(outDir, destRelative);
|
||||
|
||||
if (!fs.existsSync(srcPath)) {
|
||||
errors.push(` [!] Не найден: ${srcRelative}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
console.log(` ${destRelative}`);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.log(`\nОшибки:`);
|
||||
errors.forEach((e) => console.log(e));
|
||||
}
|
||||
|
||||
console.log(`\nГотово: ${outDir} (${count} файлов)`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Определяем что собирать
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let frameworks = fs
|
||||
.readdirSync(SCRIPTS_DIR)
|
||||
.filter((f) => f.endsWith(".build.js"))
|
||||
.map((f) => f.replace(".build.js", ""));
|
||||
|
||||
if (frameworks.length === 0) {
|
||||
console.error("Не найдено ни одного манифеста *.build.js в scripts/");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// --framework=nextjs
|
||||
const fwArg = process.argv.find((a) => a.startsWith("--framework="));
|
||||
if (fwArg) {
|
||||
const fw = fwArg.split("=")[1];
|
||||
if (frameworks.includes(fw)) {
|
||||
frameworks = [fw];
|
||||
} else {
|
||||
console.error(`Фреймворк "${fw}" не найден. Доступные: ${frameworks.join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const fw of frameworks) {
|
||||
await buildForFramework(fw);
|
||||
}
|
||||
|
||||
console.log("\nВсе сборки завершены.");
|
||||
69
scripts/nextjs.build.js
Normal file
69
scripts/nextjs.build.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Манифест сборки стайлгайда для Next.js.
|
||||
*
|
||||
* Ключ — путь файла в dist/ai/nextjs/.
|
||||
* Значение — путь исходника относительно src/.
|
||||
*
|
||||
* Скрипт только копирует. Никакой генерации.
|
||||
*/
|
||||
export default {
|
||||
name: "Next.js",
|
||||
|
||||
files: {
|
||||
// ── Точки входа ─────────────────────────────────────────────
|
||||
"DEVELOP.md": "nextjs/DEVELOP.md",
|
||||
|
||||
// ── Базовые правила ─────────────────────────────────────────
|
||||
"basics/architecture.md": "base/basics/architecture.md",
|
||||
"basics/code-style.md": "base/basics/code-style.md",
|
||||
"basics/documentation.md": "base/basics/documentation.md",
|
||||
"basics/naming.md": "base/basics/naming.md",
|
||||
"basics/tech-stack.md": "base/basics/tech-stack.md",
|
||||
"basics/typing.md": "base/basics/typing.md",
|
||||
|
||||
// ── Прикладные разделы ──────────────────────────────────────
|
||||
"applied/components.md": "base/applied/components.md",
|
||||
"applied/styles.md": "base/applied/styles.md",
|
||||
"applied/templates-generation.md": "base/applied/templates-generation.md",
|
||||
"applied/hooks.md": "base/applied/hooks.md",
|
||||
"applied/stores.md": "base/applied/stores.md",
|
||||
"applied/api.md": "base/applied/api.md",
|
||||
"applied/fonts.md": "base/applied/fonts.md",
|
||||
"applied/localization.md": "base/applied/localization.md",
|
||||
"applied/images-sprites.md": "base/applied/images-sprites.md",
|
||||
"applied/svg-sprites.md": "base/applied/svg-sprites.md",
|
||||
"applied/video.md": "base/applied/video.md",
|
||||
"applied/vscode.md": "base/applied/vscode.md",
|
||||
"applied/page-level.md": "nextjs/applied/page-level.md",
|
||||
"applied/project-structure.md": "nextjs/applied/project-structure.md",
|
||||
|
||||
// ── Триггеры: разработка / создание ─────────────────────────
|
||||
"triggers/develop/create-component.md": "base/triggers/develop/create-component.md",
|
||||
"triggers/develop/create-feature.md": "base/triggers/develop/create-feature.md",
|
||||
"triggers/develop/create-widget.md": "base/triggers/develop/create-widget.md",
|
||||
"triggers/develop/create-entity.md": "base/triggers/develop/create-entity.md",
|
||||
"triggers/develop/create-hook.md": "base/triggers/develop/create-hook.md",
|
||||
"triggers/develop/create-store.md": "base/triggers/develop/create-store.md",
|
||||
"triggers/develop/create-page.md": "nextjs/triggers/develop/create-page.md",
|
||||
"triggers/develop/create-layout.md": "nextjs/triggers/develop/create-layout.md",
|
||||
"triggers/develop/create-project.md": "nextjs/triggers/develop/create-project.md",
|
||||
"triggers/develop/generate-module.md": "base/triggers/develop/generate-module.md",
|
||||
|
||||
// ── Триггеры: разработка / стилизация и ресурсы ─────────────
|
||||
"triggers/develop/style-component.md": "base/triggers/develop/style-component.md",
|
||||
"triggers/develop/add-icon.md": "base/triggers/develop/add-icon.md",
|
||||
"triggers/develop/add-image.md": "base/triggers/develop/add-image.md",
|
||||
"triggers/develop/add-video.md": "base/triggers/develop/add-video.md",
|
||||
"triggers/develop/add-font.md": "base/triggers/develop/add-font.md",
|
||||
|
||||
// ── Триггеры: разработка / данные и состояние ───────────────
|
||||
"triggers/develop/add-api-request.md": "base/triggers/develop/add-api-request.md",
|
||||
"triggers/develop/connect-store.md": "base/triggers/develop/connect-store.md",
|
||||
"triggers/develop/add-server-data.md": "nextjs/triggers/develop/add-server-data.md",
|
||||
|
||||
// ── Триггеры: разработка / инфраструктура ───────────────────
|
||||
"triggers/develop/add-localization.md": "base/triggers/develop/add-localization.md",
|
||||
"triggers/develop/add-dependency.md": "base/triggers/develop/add-dependency.md",
|
||||
"triggers/develop/setup-vscode.md": "base/triggers/develop/setup-vscode.md",
|
||||
},
|
||||
};
|
||||
5
src/base/applied/api.md
Normal file
5
src/base/applied/api.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [api, запрос, fetch, SWR, эндпоинт, REST, клиент]
|
||||
when: "Работа с API: запросы, клиенты, обработка ответов"
|
||||
---
|
||||
118
src/base/applied/components.md
Normal file
118
src/base/applied/components.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: Компоненты
|
||||
scope: applied
|
||||
keywords: [компонент, props, jsx, ui, clsx, cl, React, FC]
|
||||
when: "Создание или редактирование React-компонентов: структура, пропсы, стили"
|
||||
---
|
||||
# Компоненты
|
||||
|
||||
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
|
||||
|
||||
Архитектурные слои и их назначение описаны в разделе [Архитектура](/basics/architecture).
|
||||
|
||||
|
||||
## Правила организации
|
||||
|
||||
1. Один компонент — один файл.
|
||||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
||||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
||||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
||||
|
||||
## Базовая структура компонента
|
||||
|
||||
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
|
||||
|
||||
```text
|
||||
container/
|
||||
├── styles/
|
||||
│ └── container.module.css
|
||||
├── types/
|
||||
│ └── container.type.ts
|
||||
├── container.tsx
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
## Именования
|
||||
|
||||
- Имя корневого css класса всегда `.root`
|
||||
- Тип пропсов именуется `{ComponentName}Props`.
|
||||
- Тип пользовательских параметров именуется `{ComponentName}Params`.
|
||||
|
||||
## Типизация
|
||||
|
||||
Структура типов компонента показана в [примере](#пример). Ниже — обоснования ключевых решений.
|
||||
|
||||
- **`type` вместо `interface`** — гибче для пропсов: поддерживает union, intersection, mapped types. Declaration merging пропсам не нужно.
|
||||
- **Без `FC`** — неявно добавляет `children`, усложняет дженерики, не даёт преимуществ перед аннотацией параметра.
|
||||
- **Типы в `types/`, а не в `.tsx`** — предотвращает циклические зависимости (компонент импортирует хук, хук импортирует тип из компонента) и разделяет ответственность: `.tsx` для рендера, `.type.ts` для данных.
|
||||
- **Без возвращаемого типа** — TypeScript выводит из JSX. Осознанное исключение из [базового правила](/basics/typing).
|
||||
|
||||
## Реализация
|
||||
|
||||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
||||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
||||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
||||
- `...htmlAttr` прокидывается на корневой элемент.
|
||||
|
||||
## Пример
|
||||
|
||||
`container/types/container.type.ts`
|
||||
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры компонента Container.
|
||||
*/
|
||||
export type ContainerParams = {}
|
||||
|
||||
/** HTML-атрибуты корневого элемента. */
|
||||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
||||
|
||||
export type ContainerProps = RootAttrs & ContainerParams
|
||||
```
|
||||
|
||||
`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 (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
`container/index.ts`
|
||||
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
## Дочерние компоненты
|
||||
|
||||
Если модулю нужны внутренние подкомпоненты — генерировать их из шаблона `component` в папку `ui/` внутри родительского модуля. Дочерние компоненты не экспортируются через `index.ts` родителя.
|
||||
5
src/base/applied/fonts.md
Normal file
5
src/base/applied/fonts.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [шрифт, font, next/font, подключение шрифта, woff]
|
||||
when: "Подключение и настройка шрифтов"
|
||||
---
|
||||
5
src/base/applied/hooks.md
Normal file
5
src/base/applied/hooks.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [хук, hook, use, кастомный хук, useState, useEffect]
|
||||
when: "Создание или использование кастомных хуков"
|
||||
---
|
||||
5
src/base/applied/images-sprites.md
Normal file
5
src/base/applied/images-sprites.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [изображение, картинка, image, next/image, public, оптимизация]
|
||||
when: "Работа с изображениями: подключение, оптимизация"
|
||||
---
|
||||
5
src/base/applied/localization.md
Normal file
5
src/base/applied/localization.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [i18n, локализация, перевод, язык, i18next, namespace]
|
||||
when: "Локализация: добавление переводов, работа с i18next"
|
||||
---
|
||||
5
src/base/applied/stores.md
Normal file
5
src/base/applied/stores.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
scope: applied
|
||||
keywords: [стор, store, zustand, состояние, глобальное состояние]
|
||||
when: "Работа с глобальным состоянием: создание стора, подписка"
|
||||
---
|
||||
@@ -1,7 +1,9 @@
|
||||
---
|
||||
title: Стили
|
||||
scope: applied
|
||||
keywords: [css, postcss, модули, css modules, токены, медиа-запросы, вложенность, класс]
|
||||
when: "Стилизация: CSS Modules, PostCSS, переменные, медиа-запросы"
|
||||
---
|
||||
|
||||
# Стили
|
||||
|
||||
Раздел описывает правила написания CSS: PostCSS Modules, вложенность, медиа-запросы, переменные, форматирование.
|
||||
@@ -267,3 +269,17 @@ title: Стили
|
||||
|
||||
- Желательно не писать комментарии в CSS.
|
||||
- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.
|
||||
|
||||
## Приоритет стилизации
|
||||
|
||||
Основной UI-фреймворк проекта — **Mantine**. При стилизации компонентов придерживаться следующего приоритета:
|
||||
|
||||
1. **Mantine-компоненты и их пропсы** — в первую очередь использовать встроенные возможности Mantine (пропсы, `classNames`, `styles`).
|
||||
2. **Глобальные CSS-токены** (`--color-*`, `--space-*`, `--radius-*`) — для значений, которые не покрываются Mantine.
|
||||
3. **PostCSS Modules** — когда Mantine не покрывает задачу и нужна кастомная стилизация.
|
||||
|
||||
## Что запрещено
|
||||
|
||||
- **Инлайн-стили** — использование атрибута `style` в компонентах строго запрещено.
|
||||
- **Магические значения** — произвольные цвета, отступы и скругления запрещены, использовать токены.
|
||||
- **Глобальные стили** вне `app/styles/` запрещены.
|
||||
7
src/base/applied/svg-sprites.md
Normal file
7
src/base/applied/svg-sprites.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: SVG-спрайты
|
||||
scope: applied
|
||||
keywords: [svg, спрайт, иконка, icon, sprite]
|
||||
when: "Работа с SVG-иконками и спрайтами"
|
||||
---
|
||||
# SVG-спрайты
|
||||
@@ -1,7 +1,9 @@
|
||||
---
|
||||
title: Шаблоны и генерация кода
|
||||
scope: applied
|
||||
keywords: [шаблон, генерация, template, scaffold, plop, hygen, .templates]
|
||||
when: "Генерация кода из шаблонов, создание новых шаблонов"
|
||||
---
|
||||
|
||||
<!-- @formatter:off -->
|
||||
::: v-pre
|
||||
|
||||
@@ -20,7 +22,7 @@ title: Шаблоны и генерация кода
|
||||
│ ├── styles/
|
||||
│ │ └── {{name.kebabCase}}.module.css
|
||||
│ ├── types/
|
||||
│ │ └── {{name.kebabCase}}.interface.ts
|
||||
│ │ └── {{name.kebabCase}}.type.ts
|
||||
│ ├── {{name.kebabCase}}.tsx
|
||||
│ └── index.ts
|
||||
└── store/ # шаблон Zustand стора
|
||||
@@ -86,29 +88,35 @@ export { {{name.pascalCase}} } from './{{name.kebabCase}}'
|
||||
```
|
||||
|
||||
```ts
|
||||
// .templates/component/types/{{name.kebabCase}}.interface.ts
|
||||
// .templates/component/types/{{name.kebabCase}}.type.ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры {{name.pascalCase}}.
|
||||
*/
|
||||
export interface {{name.pascalCase}}Props extends HTMLAttributes<HTMLDivElement> {}
|
||||
export type {{name.pascalCase}}Params = {}
|
||||
|
||||
/** HTML-атрибуты корневого элемента. */
|
||||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
||||
|
||||
export type {{name.pascalCase}}Props = RootAttrs & {{name.pascalCase}}Params
|
||||
```
|
||||
|
||||
```tsx
|
||||
// .templates/component/{{name.kebabCase}}.tsx
|
||||
import type { FC } from 'react'
|
||||
import cl from 'clsx'
|
||||
import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.interface'
|
||||
import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.type'
|
||||
import styles from './styles/{{name.kebabCase}}.module.css'
|
||||
|
||||
/**
|
||||
* {{name.pascalCase}}.
|
||||
*/
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, ...htmlAttr }) => {
|
||||
export const {{name.pascalCase}} = (props: {{name.pascalCase}}Props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
{{name.kebabCase}}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -123,7 +131,7 @@ export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, .
|
||||
|
||||
## Генерация через VS Code
|
||||
|
||||
[MyTemplateGenerator](https://open-vsx.org/extension/MyTemplateGenerator/mytemplategenerator) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
|
||||
Template File Generator | gromlab ([Marketplace](https://marketplace.visualstudio.com/items?itemName=gromlab.vscode-templateFileGenerator), [Open VSX](https://open-vsx.org/extension/gromlab/vscode-templateFileGenerator)) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
|
||||
|
||||
1. ПКМ на целевой папке в проводнике VS Code.
|
||||
2. **Generate from template** → выбрать шаблон.
|
||||
@@ -148,3 +156,20 @@ npx @gromlab/create <шаблон> <имя> <путь>
|
||||
|
||||
:::
|
||||
|
||||
## Какие модули генерируются из шаблонов
|
||||
|
||||
| Модуль | Слой | Шаблон |
|
||||
|---|---|---|
|
||||
| Компонент | `shared/ui/` | `component` |
|
||||
| Фича | `features/` | `feature` |
|
||||
| Виджет | `widgets/` | `widget` |
|
||||
| Сущность | `entities/` | `entity` |
|
||||
| Layout | `layouts/` | `layout` |
|
||||
| Экран | `screens/` | `screen` |
|
||||
| Стор | `model/` | `store` |
|
||||
|
||||
## Когда создавать новый шаблон
|
||||
|
||||
- Повторяющаяся структура появляется больше одного раза.
|
||||
- Существующий шаблон не покрывает нужный тип модуля.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user