button
diff --git a/parts/7-project-structure.md b/parts/7-project-structure.md
index 5b47db5..32c7df4 100644
--- a/parts/7-project-structure.md
+++ b/parts/7-project-structure.md
@@ -15,28 +15,46 @@ src/
│ ├── config/ # Конфигурации и константы уровня приложения
│ ├── providers/ # Провайдеры и обёртки приложения
│ ├── routing/ # Конфигурация маршрутов
+│ ├── styles/ # Глобальные стили, CSS-переменные, custom media
│ └── index.ts # Публичный API слоя
├── screens/ # Экраны приложения
-│ └── Profile/ # Экран профиля
-│ └── ... # ui/model/index.ts
+│ └── profile/ # Экран профиля
+│ ├── profile.screen.tsx
+│ └── index.ts
├── layouts/ # Общие шаблоны и каркасы страниц
-│ └── MainLayout/ # Основной layout
-│ └── ... # ui/index.ts
+│ └── main-layout/ # Основной layout
+│ ├── main-layout.layout.tsx
+│ └── index.ts
├── widgets/ # Крупные блоки интерфейса
-│ └── Header/ # Виджет шапки
-│ └── ... # ui/index.ts
+│ └── header/ # Виджет шапки
+│ ├── header.widget.tsx
+│ └── index.ts
├── features/ # Пользовательские сценарии
│ └── auth-by-email/ # Авторизация по email
-│ └── ... # ui/model/api/index.ts
+│ ├── ui/
+│ │ └── login-form.ui.tsx
+│ ├── model/
+│ │ └── auth-by-email.store.ts
+│ ├── auth-by-email.feature.tsx
+│ └── index.ts
├── entities/ # Бизнес-сущности
│ └── user/ # Сущность пользователя
-│ └── ... # ui/model/api/lib/index.ts
+│ ├── model/
+│ │ └── user.store.ts
+│ ├── user.entity.tsx
+│ └── index.ts
└── shared/ # Общие ресурсы проекта
- ├── ui/ # Базовые UI-компоненты
+ ├── ui/ # Повторно используемые UI-элементы
+ │ └── icon/
+ │ ├── styles/
+ │ │ └── icon.module.css
+ │ ├── types/
+ │ │ └── icon.interface.ts
+ │ ├── icon.ui.tsx
+ │ └── index.ts
├── lib/ # Утилиты и хелперы
├── services/ # Общие сервисы и клиенты
├── config/ # Общие конфигурации
- ├── styles/ # Глобальные стили и токены
└── assets/ # Ресурсы
├── images/ # Изображения
├── icons/ # Иконки
@@ -56,8 +74,12 @@ src/
## Правила организации
+- В слоях 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`, `lib`, `api`.
+- Внутренние реализации разделяются на `ui/`, `model/`, `styles/`, `helpers/`, `lib/`, `api/`.
- Публичный API модуля объявляется в `index.ts`.
- Внутренние файлы не импортируются напрямую извне.
- Не смешивать ответственность разных слоёв в одном модуле.
diff --git a/parts/8-components.md b/parts/8-0-components.md
similarity index 97%
rename from parts/8-components.md
rename to parts/8-0-components.md
index 26a2277..de04047 100644
--- a/parts/8-components.md
+++ b/parts/8-0-components.md
@@ -1,3 +1,7 @@
+---
+title: Компоненты
+---
+
# Компоненты
Раздел описывает правила создания UI‑компонентов. Эти правила обязательны для всех слоёв FSD: `app`, `screens`, `layouts`, `widgets`, `features`, `entities`, `shared`.
@@ -39,7 +43,7 @@ export interface ContainerProps extends HTMLAttributes
{}
```tsx
import type { FC } from 'react'
-import { cl } from 'clsx'
+import cl from 'clsx'
import type { ContainerProps } from './types/container.interface'
import styles from './styles/container.module.scss'
@@ -72,7 +76,7 @@ export const Container: FC = ({ className, ...htmlAttr }) => {
export { Container } from './container.ui'
```
-## Генерация
+## Шаблоны и генерация кода
Генерация нужна, чтобы быстро создавать компоненты с единым каркасом и не допускать расхождений в структуре. Это даёт одинаковые папки и имена файлов, уменьшает ручные ошибки и ускоряет старт работы.
diff --git a/parts/17-templates-generation.md b/parts/8-1-templates-generation.md
similarity index 70%
rename from parts/17-templates-generation.md
rename to parts/8-1-templates-generation.md
index 123ff96..3bdedfb 100644
--- a/parts/17-templates-generation.md
+++ b/parts/8-1-templates-generation.md
@@ -1,3 +1,7 @@
+---
+title: Шаблоны генерации кода
+---
+
# Шаблоны генерации кода
Подход к использованию шаблонов и генерации кода для стандартизации структуры и ускорения разработки.
@@ -34,15 +38,18 @@ npx @gromlab/create component button
```text
.templates/ # корневая папка всех шаблонов
├── component/ # шаблон компонента
-│ └── {{{name.pascalCase}}}/
-│ ├── index.ts
-│ ├── {{{name.pascalCase}}}.tsx
-│ └── {{{name.pascalCase}}}.module.css
+│ └── {{name.kebabCase}}/
+│ ├── styles/
+│ │ └── {{name.kebabCase}}.module.css
+│ ├── types/
+│ │ └── {{name.kebabCase}}.interface.ts
+│ ├── {{name.kebabCase}}.ui.tsx
+│ └── index.ts
└── store/ # шаблон Zustand стора
- └── {{{name.camelCase}}}Store/
- ├── index.ts
- ├── {{{name.camelCase}}}Store.ts
- └── {{{name.camelCase}}}Store.type.ts
+ └── {{name.kebabCase}}/
+ ├── {{name.kebabCase}}.store.ts
+ ├── {{name.kebabCase}}.type.ts
+ └── index.ts
```
## Синтаксис
@@ -85,18 +92,30 @@ export const {{name.pascalCase}} = () => {
```ts
// .templates/component/index.ts
-export * from './{{name.pascalCase}}'
+export { {{name.pascalCase}} } from './{{name.kebabCase}}.ui'
+```
+
+```ts
+// .templates/component/types/{{name.kebabCase}}.interface.ts
+import type { HTMLAttributes } from 'react'
+
+/**
+ * Параметры {{name.pascalCase}}.
+ */
+export interface {{name.pascalCase}}Props extends HTMLAttributes {}
```
```tsx
-// .templates/component/{{name.pascalCase}}.tsx
-import { FC, HTMLAttributes } from "react";
-import styles from './{{name.kebabCase}}.module.css'
+// .templates/component/{{name.kebabCase}}.ui.tsx
+import type { FC } from 'react'
import cl from 'clsx'
+import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.interface'
+import styles from './styles/{{name.kebabCase}}.module.css'
-interface IOwnProps extends HTMLAttributes {}
-
-export const {{name.pascalCase}}:FC = ({className, ...htmlAttr}) => {
+/**
+ * {{name.pascalCase}}.
+ */
+export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, ...htmlAttr }) => {
return (
{{name.kebabCase}}
@@ -106,8 +125,8 @@ export const {{name.pascalCase}}:FC = ({className, ...htmlAttr}) => {
```
```css
-/* .templates/component/{{name.kebabCase}}.module.css */
+/* .templates/component/styles/{{name.kebabCase}}.module.css */
.root {
-
+
}
```
diff --git a/parts/9-styles.md b/parts/9-styles.md
index e69de29..5ce2a88 100644
--- a/parts/9-styles.md
+++ b/parts/9-styles.md
@@ -0,0 +1,269 @@
+---
+title: Стили
+---
+
+# Стили
+
+Раздел описывает правила написания CSS: PostCSS Modules, вложенность, медиа-запросы, переменные, форматирование.
+
+## Общие правила
+
+- Только **PostCSS** и **CSS Modules** для стилизации.
+- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
+- Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`).
+- Модификаторы — отдельный класс с `_`, применяется через `&._modifier`.
+
+**Хорошо**
+```css
+.submitButton {
+ padding: 8px 16px;
+
+ &._disabled {
+ opacity: 0.5;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: kebab-case и вложенный элемент вместо отдельного класса. */
+.submit-button {
+ padding: 8px 16px;
+
+ &__icon {
+ margin-right: 8px;
+ }
+}
+```
+
+## Вложенность
+
+- Вложенность селекторов запрещена.
+- Исключения:
+ - Псевдоклассы: `&:hover`, `&:active`, `&:focus`, `&:disabled` и т.д.
+ - Псевдоэлементы: `&::before`, `&::after`.
+ - Медиа-запросы: `@media`.
+ - Модификаторы: `&._active`, `&._disabled`.
+- Каждый вложенный блок отделяется пустой строкой от предыдущих свойств.
+
+**Хорошо**
+```css
+.card {
+ padding: 16px;
+ background-color: var(--color-bg);
+
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+
+ &::after {
+ content: '';
+ display: block;
+ }
+
+ &._highlighted {
+ border-color: var(--color-primary);
+ }
+
+ @media (--md) {
+ padding: 24px;
+ }
+}
+
+.cardTitle {
+ font-size: 16px;
+
+ @media (--md) {
+ font-size: 20px;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: вложенность селекторов, нет пустых строк между блоками. */
+.card {
+ padding: 16px;
+ .cardTitle {
+ font-size: 16px;
+ }
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+}
+```
+
+## Медиа-запросы
+
+- Только **Custom Media Queries**: `@media (--md) {}`.
+- Запрещены произвольные breakpoints: `@media (min-width: 768px)`.
+- `@media` пишется только **внутри** селектора.
+- Запрещено писать `@media` на верхнем уровне с селекторами внутри.
+
+**Хорошо**
+```css
+.sidebar {
+ display: none;
+
+ @media (--md) {
+ display: block;
+ }
+}
+
+.sidebarTitle {
+ font-size: 14px;
+
+ @media (--md) {
+ font-size: 18px;
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: @media на верхнем уровне с селекторами внутри. */
+@media (--md) {
+ .sidebar {
+ display: block;
+ }
+
+ .sidebarTitle {
+ font-size: 18px;
+ }
+}
+
+/* Плохо: произвольный breakpoint вместо custom media. */
+.sidebar {
+ @media (min-width: 992px) {
+ display: block;
+ }
+}
+```
+
+## CSS-переменные
+
+- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `app/styles/variables.css` через `:root`.
+- Файл переменных подключается один раз в корневом layout/entry point — после этого переменные доступны глобально через каскад.
+- Не дублировать магические значения в компонентах.
+
+**Хорошо**
+```css
+/* app/styles/variables.css */
+:root {
+ --color-primary: #3b82f6;
+ --color-bg: #ffffff;
+ --color-bg-hover: #f5f5f5;
+ --space-1: 4px;
+ --space-2: 8px;
+ --space-3: 12px;
+ --radius-1: 4px;
+ --radius-2: 8px;
+}
+```
+
+```css
+/* компонент */
+.card {
+ padding: var(--space-3);
+ border-radius: var(--radius-2);
+ background-color: var(--color-bg);
+}
+```
+
+**Плохо**
+```css
+/* Плохо: магические значения вместо переменных. */
+.card {
+ padding: 12px;
+ border-radius: 8px;
+ background-color: #ffffff;
+}
+```
+
+## Custom Media
+
+- Breakpoints определяются через Custom Media Queries в `app/styles/media.css`.
+- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей.
+
+```css
+/* app/styles/media.css */
+@custom-media --sm (min-width: 36em);
+@custom-media --md (min-width: 62em);
+@custom-media --lg (min-width: 82em);
+```
+
+## Импорт стилей
+
+- Стили компонента импортируются только внутри своего компонента.
+- Запрещено импортировать стили одного компонента в другой.
+- Custom media не импортируются в файлы стилей — они подключаются глобально через конфиг PostCSS.
+
+## Форматирование
+
+- Пустая строка между селекторами верхнего уровня.
+- Пустая строка перед каждым вложенным блоком (медиа, псевдокласс, модификатор).
+
+**Хорошо**
+```css
+.userBar {
+ display: none;
+ color: var(--color-text);
+
+ @media (--md) {
+ display: flex;
+ }
+}
+
+.userBarButton {
+ background-color: var(--color-bg);
+
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+
+ &._active {
+ background-color: var(--color-primary);
+ }
+}
+```
+
+**Плохо**
+```css
+/* Плохо: нет пустых строк между селекторами и вложенными блоками. */
+.userBar {
+ display: none;
+ color: var(--color-text);
+ @media (--md) {
+ display: flex;
+ }
+}
+.userBarButton {
+ background-color: var(--color-bg);
+ &:hover {
+ background-color: var(--color-bg-hover);
+ }
+ &._active {
+ background-color: var(--color-primary);
+ }
+}
+```
+
+## Единицы измерения
+
+- `px` — основная единица измерения.
+- Остальные (`em`, `rem`, `%`, `vh`/`vw`) — допускаются по необходимости дизайна.
+
+## Порядок CSS-свойств
+
+В стилях рекомендуется придерживаться логического порядка свойств:
+
+1. Позиционирование (`position`, `top`, `left`, `z-index`).
+2. Блочная модель (`display`, `width`, `height`, `margin`, `padding`).
+3. Оформление (`background`, `border`, `box-shadow`, `border-radius`).
+4. Текст (`font`, `color`, `text-align`, `line-height`).
+5. Прочее (`transition`, `animation`, `opacity`, `cursor`).
+
+## Комментарии
+
+- Желательно не писать комментарии в CSS.
+- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.