diff --git a/.templates/component/{{name.kebabCase}}/index.ts b/.templates/component/{{name.kebabCase}}/index.ts index 5b35acb..9a661a6 100644 --- a/.templates/component/{{name.kebabCase}}/index.ts +++ b/.templates/component/{{name.kebabCase}}/index.ts @@ -1 +1 @@ -export { {{name.pascalCase}} } from './{{name.kebabCase}}.ui' +export { {name.pascalCase} } from './{{name.kebabCase}}' diff --git a/.templates/component/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css b/.templates/component/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css index bedeb67..c3a2af6 100644 --- a/.templates/component/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css +++ b/.templates/component/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css @@ -1,3 +1,2 @@ .root { - } diff --git a/.templates/component/{{name.kebabCase}}/{{name.kebabCase}}.ui.tsx b/.templates/component/{{name.kebabCase}}/{{name.kebabCase}}.tsx similarity index 100% rename from .templates/component/{{name.kebabCase}}/{{name.kebabCase}}.ui.tsx rename to .templates/component/{{name.kebabCase}}/{{name.kebabCase}}.tsx diff --git a/.templates/layout/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css b/.templates/layout/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css index bedeb67..c3a2af6 100644 --- a/.templates/layout/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css +++ b/.templates/layout/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css @@ -1,3 +1,2 @@ .root { - } diff --git a/.templates/screen/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css b/.templates/screen/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css index bedeb67..c3a2af6 100644 --- a/.templates/screen/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css +++ b/.templates/screen/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css @@ -1,3 +1,2 @@ .root { - } diff --git a/.templates/widget/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css b/.templates/widget/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css index bedeb67..c3a2af6 100644 --- a/.templates/widget/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css +++ b/.templates/widget/{{name.kebabCase}}/styles/{{name.kebabCase}}.module.css @@ -1,3 +1,2 @@ .root { - } diff --git a/.vscode/settings.json b/.vscode/settings.json index d551eb1..e87ab80 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,8 +2,7 @@ "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "quickfix.biome": "explicit", - "source.organizeImports.biome": "explicit" + "source.fixAll.biome": "explicit" }, "files.associations": { "*.css": "postcss" diff --git a/AGENTS.md b/AGENTS.md index 8bd0e39..cfcea68 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,83 @@ - -# This is NOT the Next.js you know +# Правила работы с проектом -This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. - +## Стайлгайд + +Проект строго придерживается стайлгайда. Перед любой работой с кодом — прочитай полную документацию: + +https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md + +Все решения по архитектуре, именованию, стилям, компонентам и структуре принимаются на основе этого документа. Отклонения от стайлгайда недопустимы без явного согласования. + +## Язык общения + +- Всегда использовать русский язык: размышления, пояснения, подсказки, инструкции — всё формулировать по-русски. +- Не переключаться на английский без прямого запроса пользователя. + +## Коммиты + +- НЕ добавлять подпись +- Писать сообщения коммитов на русском языке + +### Формат + +``` +<тип>: <краткое описание> + +- Детали в прошедшем времени +- Каждый пункт — отдельное изменение +``` + +### Типы коммитов + +| Тип | Назначение | +|---|---| +| `feat` | Новая функциональность | +| `fix` | Исправление бага | +| `refactor` | Рефакторинг без изменения поведения | +| `style` | Стили, форматирование, отступы | +| `docs` | Документация | +| `chore` | Настройка, зависимости, CI | +| `test` | Тесты | +| `perf` | Оптимизация производительности | + +### Правила + +- Первая строка — не длиннее 72 символов +- Описание — с маленькой буквы (если не имя собственное) +- Пункты — в прошедшем времени +- Scope (область) опционален: `feat(auth): ...`, `fix(ui): ...` + +### Примеры + +``` +feat: автодополнение и режимы запуска + +- Добавлены служебные команды и генерация completion для bash/zsh/fish +- Введён детект режимов запуска (npx/local/direct/global) +- Обновлены help и документация +``` + +``` +fix: некорректная ширина sidebar на мобильных + +- Исправлен медиа-запрос для breakpoint --sm +- Убран фиксированный width в пользу max-width +``` + +``` +chore: настройка Biome и VS Code + +- Добавлены одинарные кавычки в конфигурацию Biome +- Исключена папка .templates из проверок +- Обновлён quickfix.biome на source.fixAll.biome +``` + +## Генерация кода + +- Модули (компоненты, фичи, виджеты, сущности, layouts, screens, сторы) создаются только из шаблонов `.templates/`. +- Ручное создание файловой структуры модулей запрещено. +- Генерация: `npx @gromlab/create <шаблон> <имя> <путь>` + +## Next.js + +This is NOT the Next.js you know. This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. diff --git a/biome.json b/biome.json index f7dce66..7093e34 100644 --- a/biome.json +++ b/biome.json @@ -7,17 +7,33 @@ }, "files": { "ignoreUnknown": true, - "includes": ["**", "!node_modules", "!.next", "!dist", "!build"] + "includes": [ + "**", + "!node_modules", + "!.next", + "!dist", + "!build", + "!.templates" + ] }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "jsxQuoteStyle": "double" + } + }, "linter": { "enabled": true, "rules": { - "recommended": true + "recommended": true, + "suspicious": { + "noUnknownAtRules": "off" + } }, "domains": { "next": "recommended", diff --git a/next.config.ts b/next.config.ts index e9ffa30..5e891cf 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,4 +1,4 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ diff --git a/postcss.config.mjs b/postcss.config.mjs index c36a00a..6786818 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -12,6 +12,6 @@ const config = { }, }, }, -} +}; -export default config +export default config; diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index 1a01ed0..0000000 --- a/src/app/globals.css +++ /dev/null @@ -1,71 +0,0 @@ -/* Цвета */ -:root { - --color-text: #1a1a1a; - --color-text-secondary: #6b7280; - --color-bg: #ffffff; - --color-bg-secondary: #f9fafb; - --color-border: #e5e7eb; - --color-primary: #228be6; - --color-error: #fa5252; - --color-success: #40c057; - --color-warning: #fab005; -} - -/* Отступы */ -:root { - --space-1: 4px; - --space-2: 8px; - --space-3: 12px; - --space-4: 16px; - --space-5: 20px; - --space-6: 24px; - --space-8: 32px; - --space-10: 40px; - --space-12: 48px; - --space-16: 64px; -} - -/* Скругления */ -:root { - --radius-sm: 4px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-full: 9999px; -} - -/* Медиа-запросы (Mobile First) */ -@custom-media --xs (min-width: 36em); -@custom-media --sm (min-width: 48em); -@custom-media --md (min-width: 62em); -@custom-media --lg (min-width: 75em); -@custom-media --xl (min-width: 88em); - -/* Базовые стили */ -html { - height: 100%; -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - min-height: 100%; - display: flex; - flex-direction: column; - color: var(--color-text); - background: var(--color-bg); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 27f1bfe..46c744f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,8 +1,9 @@ -import type { PropsWithChildren } from 'react' -import type { Metadata } from 'next' -import { ColorSchemeScript, MantineProvider } from '@mantine/core' -import '@mantine/core/styles.css' -import './globals.css' +import { ColorSchemeScript } from '@mantine/core'; +import type { Metadata } from 'next'; +import type { PropsWithChildren } from 'react'; +import { MantineProvider } from './providers'; +import '@mantine/core/styles.css'; +import './styles/index.css'; export const metadata: Metadata = { title: { @@ -27,7 +28,7 @@ export const metadata: Metadata = { twitter: { card: 'summary_large_image', }, -} +}; export default function RootLayout({ children }: PropsWithChildren) { return ( @@ -39,5 +40,5 @@ export default function RootLayout({ children }: PropsWithChildren) { {children} - ) + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 0da8585..144ec37 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,11 +1,11 @@ -import type { Metadata } from 'next' -import { HomeScreen } from '@/screens/home' +import type { Metadata } from 'next'; +import { HomeScreen } from '@/screens/home'; export const metadata: Metadata = { title: 'Главная', description: 'Главная страница приложения', -} +}; export default function HomePage() { - return + return ; } diff --git a/src/app/providers/index.ts b/src/app/providers/index.ts new file mode 100644 index 0000000..c248e7a --- /dev/null +++ b/src/app/providers/index.ts @@ -0,0 +1 @@ +export { MantineProvider } from './mantine-provider'; diff --git a/src/app/providers/mantine-provider.tsx b/src/app/providers/mantine-provider.tsx new file mode 100644 index 0000000..bab72f2 --- /dev/null +++ b/src/app/providers/mantine-provider.tsx @@ -0,0 +1,11 @@ +'use client'; + +import { MantineProvider as BaseMantineProvider } from '@mantine/core'; +import type { PropsWithChildren } from 'react'; + +/** + * Провайдер Mantine UI. + */ +export const MantineProvider = ({ children }: PropsWithChildren) => { + return {children}; +}; diff --git a/src/app/styles/index.css b/src/app/styles/index.css new file mode 100644 index 0000000..8671c66 --- /dev/null +++ b/src/app/styles/index.css @@ -0,0 +1,3 @@ +@import "./variables.css"; +@import "./media.css"; +@import "./reset.css"; diff --git a/src/app/styles/media.css b/src/app/styles/media.css new file mode 100644 index 0000000..74c04b0 --- /dev/null +++ b/src/app/styles/media.css @@ -0,0 +1,6 @@ +/* Медиа-запросы (Mobile First) */ +@custom-media --xs (min-width: 36em); +@custom-media --sm (min-width: 48em); +@custom-media --md (min-width: 62em); +@custom-media --lg (min-width: 75em); +@custom-media --xl (min-width: 88em); diff --git a/src/app/styles/reset.css b/src/app/styles/reset.css new file mode 100644 index 0000000..69b15aa --- /dev/null +++ b/src/app/styles/reset.css @@ -0,0 +1,28 @@ +/* Базовые стили */ +html { + height: 100%; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + min-height: 100%; + display: flex; + flex-direction: column; + color: var(--color-text); + background: var(--color-bg); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} diff --git a/src/app/styles/variables.css b/src/app/styles/variables.css new file mode 100644 index 0000000..eae5064 --- /dev/null +++ b/src/app/styles/variables.css @@ -0,0 +1,35 @@ +/* Цвета */ +:root { + --color-text: #1a1a1a; + --color-text-secondary: #6b7280; + --color-bg: #ffffff; + --color-bg-secondary: #f9fafb; + --color-border: #e5e7eb; + --color-primary: #228be6; + --color-error: #fa5252; + --color-success: #40c057; + --color-warning: #fab005; +} + +/* Отступы */ +:root { + --space-1: 4px; + --space-2: 8px; + --space-3: 12px; + --space-4: 16px; + --space-5: 20px; + --space-6: 24px; + --space-8: 32px; + --space-10: 40px; + --space-12: 48px; + --space-16: 64px; +} + +/* Скругления */ +:root { + --radius-1: 4px; + --radius-2: 8px; + --radius-3: 12px; + --radius-4: 16px; + --radius-full: 9999px; +} diff --git a/src/layouts/.gitkeep b/src/layouts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/screens/home/home.screen.tsx b/src/screens/home/home.screen.tsx index 0fee24e..d08b367 100644 --- a/src/screens/home/home.screen.tsx +++ b/src/screens/home/home.screen.tsx @@ -1,6 +1,6 @@ -import type { FC } from 'react' -import { Container, Title, Text, Image, Stack } from '@mantine/core' -import styles from './styles/home.module.css' +import { Container, Image, Stack, Text, Title } from '@mantine/core'; +import type { FC } from 'react'; +import styles from './styles/home.module.css'; /** * Главный экран приложения. @@ -18,11 +18,9 @@ export const HomeScreen: FC = () => { fit="contain" /> Добро пожаловать - - Шаблон приложения на Next.js и TypeScript. - + Шаблон приложения на Next.js и TypeScript. - ) -} + ); +}; diff --git a/src/screens/home/index.ts b/src/screens/home/index.ts index b591e2c..b1d0252 100644 --- a/src/screens/home/index.ts +++ b/src/screens/home/index.ts @@ -1 +1 @@ -export { HomeScreen } from './home.screen' +export { HomeScreen } from './home.screen';