This commit is contained in:
2026-01-29 16:00:19 +03:00
parent 2b108e8f96
commit 7e2dea74ef
56 changed files with 539 additions and 1149 deletions

31
.vitepress/cache/deps/_metadata.json vendored Normal file
View File

@@ -0,0 +1,31 @@
{
"hash": "89603b55",
"configHash": "8cb3bfba",
"lockfileHash": "5778a81f",
"browserHash": "39b85539",
"optimized": {
"vue": {
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "a740251a",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "35102a70",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "c5cd7aa4",
"needsInterop": false
}
},
"chunks": {
"chunk-EAEFJUV4": {
"file": "chunk-EAEFJUV4.js"
}
}
}

View File

@@ -12641,4 +12641,4 @@ vue/dist/vue.runtime.esm-bundler.js:
* @license MIT * @license MIT
**) **)
*/ */
//# sourceMappingURL=chunk-HVR2FF6M.js.map //# sourceMappingURL=chunk-EAEFJUV4.js.map

File diff suppressed because one or more lines are too long

View File

@@ -35,7 +35,7 @@ import {
unref, unref,
watch, watch,
watchEffect watchEffect
} from "./chunk-HVR2FF6M.js"; } from "./chunk-EAEFJUV4.js";
// node_modules/@vueuse/shared/index.mjs // node_modules/@vueuse/shared/index.mjs
function computedEager(fn, options) { function computedEager(fn, options) {
@@ -9431,83 +9431,135 @@ function useWindowSize(options = {}) {
} }
return { width, height }; return { width, height };
} }
export { export {
DefaultMagicKeysAliasMap,
StorageSerializers,
TransitionPresets,
assert,
computedAsync as asyncComputed,
refAutoReset as autoResetRef,
breakpointsAntDesign,
breakpointsBootstrapV5,
breakpointsElement,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsQuasar,
breakpointsSematic,
breakpointsTailwind,
breakpointsVuetify,
breakpointsVuetifyV2,
breakpointsVuetifyV3,
bypassFilter,
camelize,
clamp,
cloneFnJSON,
computedAsync,
computedEager, computedEager,
computedInject,
computedWithControl, computedWithControl,
tryOnScopeDispose, containsProp,
computedWithControl as controlledComputed,
controlledRef,
createEventHook, createEventHook,
createFetch,
createFilterWrapper,
createGlobalState, createGlobalState,
injectLocal,
provideLocal,
createInjectionState, createInjectionState,
reactify as createReactiveFn,
createRef, createRef,
createReusableTemplate,
createSharedComposable, createSharedComposable,
createSingletonPromise,
createTemplatePromise,
createUnrefFn,
customStorageEventName,
debounceFilter,
refDebounced as debouncedRef,
watchDebounced as debouncedWatch,
defaultDocument,
defaultLocation,
defaultNavigator,
defaultWindow,
computedEager as eagerComputed,
executeTransition,
extendRef, extendRef,
formatDate,
formatTimeAgo,
get, get,
getLifeCycleTarget,
getSSRHandler,
hasOwn,
hyphenate,
identity,
watchIgnorable as ignorableWatch,
increaseWithUnit,
injectLocal,
invoke,
isClient,
isDef,
isDefined, isDefined,
isIOS,
isObject,
isWorker,
makeDestructurable, makeDestructurable,
mapGamepadToXbox360Controller,
noop,
normalizeDate,
notNullish,
now,
objectEntries,
objectOmit,
objectPick,
onClickOutside,
onElementRemoval,
onKeyDown,
onKeyPressed,
onKeyStroke,
onKeyUp,
onLongPress,
onStartTyping,
pausableFilter,
watchPausable as pausableWatch,
promiseTimeout,
provideLocal,
provideSSRWidth,
pxValue,
rand,
reactify, reactify,
reactifyObject, reactifyObject,
toReactive,
reactiveComputed, reactiveComputed,
reactiveOmit, reactiveOmit,
isClient,
isWorker,
isDef,
notNullish,
assert,
isObject,
now,
timestamp,
clamp,
noop,
rand,
hasOwn,
isIOS,
createFilterWrapper,
bypassFilter,
debounceFilter,
throttleFilter,
pausableFilter,
hyphenate,
camelize,
promiseTimeout,
identity,
createSingletonPromise,
invoke,
containsProp,
increaseWithUnit,
pxValue,
objectPick,
objectOmit,
objectEntries,
getLifeCycleTarget,
toArray,
toRef2 as toRef,
resolveRef,
reactivePick, reactivePick,
refAutoReset, refAutoReset,
useDebounceFn,
refDebounced, refDebounced,
refDefault, refDefault,
useThrottleFn,
refThrottled, refThrottled,
refWithControl, refWithControl,
controlledRef, resolveRef,
resolveUnref,
set, set,
watchWithFilter, setSSRHandler,
watchPausable,
syncRef, syncRef,
syncRefs, syncRefs,
templateRef,
throttleFilter,
refThrottled as throttledRef,
watchThrottled as throttledWatch,
timestamp,
toArray,
toReactive,
toRef2 as toRef,
toRefs2 as toRefs, toRefs2 as toRefs,
toValue2 as toValue, toValue2 as toValue,
resolveUnref,
tryOnBeforeMount, tryOnBeforeMount,
tryOnBeforeUnmount, tryOnBeforeUnmount,
tryOnMounted, tryOnMounted,
tryOnScopeDispose,
tryOnUnmounted, tryOnUnmounted,
unrefElement,
until, until,
useActiveElement,
useAnimate,
useArrayDifference, useArrayDifference,
useArrayEvery, useArrayEvery,
useArrayFilter, useArrayFilter,
@@ -9520,97 +9572,29 @@ export {
useArrayReduce, useArrayReduce,
useArraySome, useArraySome,
useArrayUnique, useArrayUnique,
useCounter,
formatDate,
normalizeDate,
useDateFormat,
useIntervalFn,
useInterval,
useLastChanged,
useTimeoutFn,
useTimeout,
useToNumber,
useToString,
useToggle,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchThrottled,
watchTriggerable,
whenever,
computedAsync,
computedInject,
createReusableTemplate,
createTemplatePromise,
createUnrefFn,
defaultWindow,
defaultDocument,
defaultNavigator,
defaultLocation,
unrefElement,
useEventListener,
onClickOutside,
useMounted,
useSupported,
useMutationObserver,
onElementRemoval,
onKeyStroke,
onKeyDown,
onKeyPressed,
onKeyUp,
onLongPress,
onStartTyping,
templateRef,
useActiveElement,
useRafFn,
useAnimate,
useAsyncQueue, useAsyncQueue,
useAsyncState, useAsyncState,
useBase64, useBase64,
useBattery, useBattery,
useBluetooth, useBluetooth,
useSSRWidth,
provideSSRWidth,
useMediaQuery,
breakpointsTailwind,
breakpointsBootstrapV5,
breakpointsVuetifyV2,
breakpointsVuetifyV3,
breakpointsVuetify,
breakpointsAntDesign,
breakpointsQuasar,
breakpointsSematic,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsElement,
useBreakpoints, useBreakpoints,
useBroadcastChannel, useBroadcastChannel,
useBrowserLocation, useBrowserLocation,
useCached, useCached,
usePermission,
useClipboard, useClipboard,
useClipboardItems, useClipboardItems,
cloneFnJSON,
useCloned, useCloned,
getSSRHandler,
setSSRHandler,
usePreferredDark,
StorageSerializers,
customStorageEventName,
useStorage,
useColorMode, useColorMode,
useConfirmDialog, useConfirmDialog,
useCountdown, useCountdown,
useCounter,
useCssVar, useCssVar,
useCurrentElement, useCurrentElement,
useCycleList, useCycleList,
useDark, useDark,
useManualRefHistory, useDateFormat,
useRefHistory, refDebounced as useDebounce,
useDebounceFn,
useDebouncedRefHistory, useDebouncedRefHistory,
useDeviceMotion, useDeviceMotion,
useDeviceOrientation, useDeviceOrientation,
@@ -9620,18 +9604,16 @@ export {
useDocumentVisibility, useDocumentVisibility,
useDraggable, useDraggable,
useDropZone, useDropZone,
useResizeObserver,
useElementBounding, useElementBounding,
useElementByPoint, useElementByPoint,
useElementHover, useElementHover,
useElementSize, useElementSize,
useIntersectionObserver,
useElementVisibility, useElementVisibility,
useEventBus, useEventBus,
useEventListener,
useEventSource, useEventSource,
useEyeDropper, useEyeDropper,
useFavicon, useFavicon,
createFetch,
useFetch, useFetch,
useFileDialog, useFileDialog,
useFileSystemAccess, useFileSystemAccess,
@@ -9639,23 +9621,28 @@ export {
useFocusWithin, useFocusWithin,
useFps, useFps,
useFullscreen, useFullscreen,
mapGamepadToXbox360Controller,
useGamepad, useGamepad,
useGeolocation, useGeolocation,
useIdle, useIdle,
useImage, useImage,
useScroll,
useInfiniteScroll, useInfiniteScroll,
useIntersectionObserver,
useInterval,
useIntervalFn,
useKeyModifier, useKeyModifier,
useLastChanged,
useLocalStorage, useLocalStorage,
DefaultMagicKeysAliasMap,
useMagicKeys, useMagicKeys,
useManualRefHistory,
useMediaControls, useMediaControls,
useMediaQuery,
useMemoize, useMemoize,
useMemory, useMemory,
useMounted,
useMouse, useMouse,
useMouseInElement, useMouseInElement,
useMousePressed, useMousePressed,
useMutationObserver,
useNavigatorLanguage, useNavigatorLanguage,
useNetwork, useNetwork,
useNow, useNow,
@@ -9663,21 +9650,28 @@ export {
useOffsetPagination, useOffsetPagination,
useOnline, useOnline,
usePageLeave, usePageLeave,
useScreenOrientation,
useParallax, useParallax,
useParentElement, useParentElement,
usePerformanceObserver, usePerformanceObserver,
usePermission,
usePointer, usePointer,
usePointerLock, usePointerLock,
usePointerSwipe, usePointerSwipe,
usePreferredColorScheme, usePreferredColorScheme,
usePreferredContrast, usePreferredContrast,
usePreferredDark,
usePreferredLanguages, usePreferredLanguages,
usePreferredReducedMotion, usePreferredReducedMotion,
usePreferredReducedTransparency, usePreferredReducedTransparency,
usePrevious, usePrevious,
useRafFn,
useRefHistory,
useResizeObserver,
useSSRWidth,
useScreenOrientation,
useScreenSafeArea, useScreenSafeArea,
useScriptTag, useScriptTag,
useScroll,
useScrollLock, useScrollLock,
useSessionStorage, useSessionStorage,
useShare, useShare,
@@ -9685,21 +9679,27 @@ export {
useSpeechRecognition, useSpeechRecognition,
useSpeechSynthesis, useSpeechSynthesis,
useStepper, useStepper,
useStorage,
useStorageAsync, useStorageAsync,
useStyleTag, useStyleTag,
useSupported,
useSwipe, useSwipe,
useTemplateRefsList, useTemplateRefsList,
useTextDirection, useTextDirection,
useTextSelection, useTextSelection,
useTextareaAutosize, useTextareaAutosize,
refThrottled as useThrottle,
useThrottleFn,
useThrottledRefHistory, useThrottledRefHistory,
useTimeAgo, useTimeAgo,
formatTimeAgo, useTimeout,
useTimeoutFn,
useTimeoutPoll, useTimeoutPoll,
useTimestamp, useTimestamp,
useTitle, useTitle,
TransitionPresets, useToNumber,
executeTransition, useToString,
useToggle,
useTransition, useTransition,
useUrlSearchParams, useUrlSearchParams,
useUserMedia, useUserMedia,
@@ -9714,6 +9714,18 @@ export {
useWebWorkerFn, useWebWorkerFn,
useWindowFocus, useWindowFocus,
useWindowScroll, useWindowScroll,
useWindowSize useWindowSize,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchPausable,
watchThrottled,
watchTriggerable,
watchWithFilter,
whenever
}; };
//# sourceMappingURL=chunk-P2XGSYO7.js.map //# sourceMappingURL=vitepress___@vueuse_core.js.map

View File

@@ -168,7 +168,7 @@ import {
withMemo, withMemo,
withModifiers, withModifiers,
withScopeId withScopeId
} from "./chunk-HVR2FF6M.js"; } from "./chunk-EAEFJUV4.js";
export { export {
BaseTransition, BaseTransition,
BaseTransitionPropsValidators, BaseTransitionPropsValidators,

38
.vitepress/config.ts Normal file
View File

@@ -0,0 +1,38 @@
import { defineConfig } from 'vitepress';
export default defineConfig({
lang: 'ru-RU',
title: 'Код-стайл React/NextJS и TypeScript',
description: 'Правила и стандарты разработки фронтенд-проектов на React/NextJS и TypeScript',
themeConfig: {
siteTitle: 'Frontend Style Guide',
sidebar: [
{
text: 'Базовые правила',
items: [
{ text: 'Технологии/библиотеки', link: '/parts/1-tech-stack' },
{ text: 'Архитектура', link: '/parts/2-architecture' },
{ text: 'Стиль кода', link: '/parts/3-code-style' },
{ text: 'Именование', link: '/parts/4-naming' },
{ text: 'Документирование', link: '/parts/5-documentation' },
{ text: 'Типизация', link: '/parts/6-typing' },
],
},
{
text: 'Прикладные разделы',
items: [
{ text: 'Структура проекта', link: '/parts/7-project-structure' },
{ text: 'Компоненты', link: '/parts/8-components' },
{ text: 'Стили', link: '/parts/9-styles' },
{ text: 'Изображения/спрайты', link: '/parts/10-images-sprites' },
{ text: 'Видео', link: '/parts/11-video' },
{ text: 'API', link: '/parts/12-api' },
{ text: 'Stores', link: '/parts/13-stores' },
{ text: 'Хуки', link: '/parts/14-hooks' },
{ text: 'Шрифты', link: '/parts/15-fonts' },
{ text: 'Локализация', link: '/parts/16-localization' },
],
},
],
},
});

View File

@@ -0,0 +1,12 @@
.VPNavBarTitle .title {
white-space: normal;
line-height: 1.2;
padding: 6px 0;
}
.VPNavBarTitle .title span {
display: block;
min-width: 0;
max-width: 100%;
overflow-wrap: anywhere;
}

View File

@@ -0,0 +1,4 @@
import DefaultTheme from 'vitepress/theme';
import './custom.css';
export default DefaultTheme;

View File

@@ -18,7 +18,7 @@ title: Стиль кода
```ts ```ts
// JavaScript/TypeScript // JavaScript/TypeScript
const message = 'Привет, мир!'; const message = 'Привет, мир!';
const name = 'GramPay'; const name = 'ProjectName';
``` ```
```tsx ```tsx

46
README.md Normal file
View File

@@ -0,0 +1,46 @@
# Код-стайл для фронтенд-проектов на React/NextJS и TypeScript
Этот репозиторий содержит документацию с правилами разработки фронтенд-проектов на React/NextJS и TypeScript.
## Как запустить документацию
1. Установите зависимости:
```bash
npm install
```
2. Запустите локальный сервер документации:
```bash
npm run dev
```
Документация будет доступна по адресу http://localhost:5173
3. Для сборки статики:
```bash
npm run build
```
4. Для предпросмотра собранной документации:
```bash
npm run serve
```
## Где находятся документы
- Главная страница документации — `index.md`.
- Основные разделы — в `parts/` (каждый раздел — отдельный markdown-файл).
- Конфигурация VitePress — `.vitepress/config.ts`.
- `README.md` — описание проекта и не связан с `parts/`.
## Генерация .cursorrules
- Файл `.cursorrules` собирается из содержимого `parts/`.
- Команда:
```bash
npm run docs
```
## Как дополнять документацию
- Добавляйте новые разделы в папку `parts/`.
- Обновляйте sidebar в `.vitepress/config.ts` для навигации.
- Используйте только русский язык.

View File

@@ -2,7 +2,7 @@ import concatMd, { concatMdSync } from "concat-md";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
const resultMd = concatMdSync("./docs/parts", { const resultMd = concatMdSync("./parts", {
toc: false, toc: false,
sorter: (a, b) => { sorter: (a, b) => {
// Извлекаем номер из начала имени файла (например, "1" из "1-assistent.md") // Извлекаем номер из начала имени файла (например, "1" из "1-assistent.md")
@@ -16,8 +16,8 @@ const resultMd = concatMdSync("./docs/parts", {
} }
}); });
// Записываем результат в файл docs/.cursorrules // Записываем результат в файл .cursorrules в корне проекта
const outputPath = path.join("./docs", ".cursorrules"); const outputPath = path.join("./", ".cursorrules");
fs.writeFileSync(outputPath, resultMd, "utf8"); fs.writeFileSync(outputPath, resultMd, "utf8");
console.log(`Файл .cursorrules успешно создан: ${outputPath}`); console.log(`Файл .cursorrules успешно создан: ${outputPath}`);

View File

@@ -1,275 +0,0 @@
import {
useMediaQuery
} from "./chunk-P2XGSYO7.js";
import {
computed,
ref,
shallowRef,
watch
} from "./chunk-HVR2FF6M.js";
// node_modules/vitepress/dist/client/theme-default/index.js
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default4 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default5 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
import { default as default6 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
import { default as default7 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default8 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default9 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default10 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default11 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
import { default as default12 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
import { default as default13 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
import { default as default14 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
import { default as default15 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default16 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
import { default as default17 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default18 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default19 } from "/home/gromov/projects/docs/react-ts/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
import { onContentUpdated } from "vitepress";
// node_modules/vitepress/dist/client/theme-default/composables/outline.js
import { getScrollOffset } from "vitepress";
// node_modules/vitepress/dist/client/theme-default/support/utils.js
import { withBase } from "vitepress";
// node_modules/vitepress/dist/client/theme-default/composables/data.js
import { useData as useData$ } from "vitepress";
var useData = useData$;
// node_modules/vitepress/dist/client/theme-default/support/utils.js
function ensureStartingSlash(path) {
return path.startsWith("/") ? path : `/${path}`;
}
// node_modules/vitepress/dist/client/theme-default/support/sidebar.js
function getSidebar(_sidebar, path) {
if (Array.isArray(_sidebar))
return addBase(_sidebar);
if (_sidebar == null)
return [];
path = ensureStartingSlash(path);
const dir = Object.keys(_sidebar).sort((a, b) => {
return b.split("/").length - a.split("/").length;
}).find((dir2) => {
return path.startsWith(ensureStartingSlash(dir2));
});
const sidebar = dir ? _sidebar[dir] : [];
return Array.isArray(sidebar) ? addBase(sidebar) : addBase(sidebar.items, sidebar.base);
}
function getSidebarGroups(sidebar) {
const groups = [];
let lastGroupIndex = 0;
for (const index in sidebar) {
const item = sidebar[index];
if (item.items) {
lastGroupIndex = groups.push(item);
continue;
}
if (!groups[lastGroupIndex]) {
groups.push({ items: [] });
}
groups[lastGroupIndex].items.push(item);
}
return groups;
}
function addBase(items, _base) {
return [...items].map((_item) => {
const item = { ..._item };
const base = item.base || _base;
if (base && item.link)
item.link = base + item.link;
if (item.items)
item.items = addBase(item.items, base);
return item;
});
}
// node_modules/vitepress/dist/client/theme-default/composables/sidebar.js
function useSidebar() {
const { frontmatter, page, theme: theme2 } = useData();
const is960 = useMediaQuery("(min-width: 960px)");
const isOpen = ref(false);
const _sidebar = computed(() => {
const sidebarConfig = theme2.value.sidebar;
const relativePath = page.value.relativePath;
return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : [];
});
const sidebar = ref(_sidebar.value);
watch(_sidebar, (next, prev) => {
if (JSON.stringify(next) !== JSON.stringify(prev))
sidebar.value = _sidebar.value;
});
const hasSidebar = computed(() => {
return frontmatter.value.sidebar !== false && sidebar.value.length > 0 && frontmatter.value.layout !== "home";
});
const leftAside = computed(() => {
if (hasAside)
return frontmatter.value.aside == null ? theme2.value.aside === "left" : frontmatter.value.aside === "left";
return false;
});
const hasAside = computed(() => {
if (frontmatter.value.layout === "home")
return false;
if (frontmatter.value.aside != null)
return !!frontmatter.value.aside;
return theme2.value.aside !== false;
});
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value);
const sidebarGroups = computed(() => {
return hasSidebar.value ? getSidebarGroups(sidebar.value) : [];
});
function open() {
isOpen.value = true;
}
function close() {
isOpen.value = false;
}
function toggle() {
isOpen.value ? close() : open();
}
return {
isOpen,
sidebar,
sidebarGroups,
hasSidebar,
hasAside,
leftAside,
isSidebarEnabled,
open,
close,
toggle
};
}
// node_modules/vitepress/dist/client/theme-default/composables/outline.js
var ignoreRE = /\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/;
var resolvedHeaders = [];
function getHeaders(range) {
const headers = [
...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")
].filter((el) => el.id && el.hasChildNodes()).map((el) => {
const level = Number(el.tagName[1]);
return {
element: el,
title: serializeHeader(el),
link: "#" + el.id,
level
};
});
return resolveHeaders(headers, range);
}
function serializeHeader(h) {
let ret = "";
for (const node of h.childNodes) {
if (node.nodeType === 1) {
if (ignoreRE.test(node.className))
continue;
ret += node.textContent;
} else if (node.nodeType === 3) {
ret += node.textContent;
}
}
return ret.trim();
}
function resolveHeaders(headers, range) {
if (range === false) {
return [];
}
const levelsRange = (typeof range === "object" && !Array.isArray(range) ? range.level : range) || 2;
const [high, low] = typeof levelsRange === "number" ? [levelsRange, levelsRange] : levelsRange === "deep" ? [2, 6] : levelsRange;
return buildTree(headers, high, low);
}
function buildTree(data, min, max) {
resolvedHeaders.length = 0;
const result = [];
const stack = [];
data.forEach((item) => {
const node = { ...item, children: [] };
let parent = stack[stack.length - 1];
while (parent && parent.level >= node.level) {
stack.pop();
parent = stack[stack.length - 1];
}
if (node.element.classList.contains("ignore-header") || parent && "shouldIgnore" in parent) {
stack.push({ level: node.level, shouldIgnore: true });
return;
}
if (node.level > max || node.level < min)
return;
resolvedHeaders.push({ element: node.element, link: node.link });
if (parent)
parent.children.push(node);
else
result.push(node);
stack.push(node);
});
return result;
}
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
function useLocalNav() {
const { theme: theme2, frontmatter } = useData();
const headers = shallowRef([]);
const hasLocalNav = computed(() => {
return headers.value.length > 0;
});
onContentUpdated(() => {
headers.value = getHeaders(frontmatter.value.outline ?? theme2.value.outline);
});
return {
headers,
hasLocalNav
};
}
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
var theme = {
Layout,
enhanceApp: ({ app }) => {
app.component("Badge", VPBadge);
}
};
var without_fonts_default = theme;
export {
default2 as VPBadge,
default3 as VPButton,
default4 as VPDocAsideSponsors,
default5 as VPFeatures,
default6 as VPHomeContent,
default7 as VPHomeFeatures,
default8 as VPHomeHero,
default9 as VPHomeSponsors,
default10 as VPImage,
default11 as VPLink,
default12 as VPNavBarSearch,
default13 as VPSocialLink,
default14 as VPSocialLinks,
default15 as VPSponsors,
default16 as VPTeamMembers,
default17 as VPTeamPage,
default18 as VPTeamPageSection,
default19 as VPTeamPageTitle,
without_fonts_default as default,
useLocalNav,
useSidebar
};
//# sourceMappingURL=@theme_index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,40 +0,0 @@
{
"hash": "cec988b5",
"configHash": "5db47d6f",
"lockfileHash": "5778a81f",
"browserHash": "0fd0e715",
"optimized": {
"vue": {
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "854c3817",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "0d2d3b96",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "def20a1e",
"needsInterop": false
},
"@theme/index": {
"src": "../../../../node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
"fileHash": "e2e9e175",
"needsInterop": false
}
},
"chunks": {
"chunk-P2XGSYO7": {
"file": "chunk-P2XGSYO7.js"
},
"chunk-HVR2FF6M": {
"file": "chunk-HVR2FF6M.js"
}
}
}

View File

@@ -1,583 +0,0 @@
import {
DefaultMagicKeysAliasMap,
StorageSerializers,
TransitionPresets,
assert,
breakpointsAntDesign,
breakpointsBootstrapV5,
breakpointsElement,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsQuasar,
breakpointsSematic,
breakpointsTailwind,
breakpointsVuetify,
breakpointsVuetifyV2,
breakpointsVuetifyV3,
bypassFilter,
camelize,
clamp,
cloneFnJSON,
computedAsync,
computedEager,
computedInject,
computedWithControl,
containsProp,
controlledRef,
createEventHook,
createFetch,
createFilterWrapper,
createGlobalState,
createInjectionState,
createRef,
createReusableTemplate,
createSharedComposable,
createSingletonPromise,
createTemplatePromise,
createUnrefFn,
customStorageEventName,
debounceFilter,
defaultDocument,
defaultLocation,
defaultNavigator,
defaultWindow,
executeTransition,
extendRef,
formatDate,
formatTimeAgo,
get,
getLifeCycleTarget,
getSSRHandler,
hasOwn,
hyphenate,
identity,
increaseWithUnit,
injectLocal,
invoke,
isClient,
isDef,
isDefined,
isIOS,
isObject,
isWorker,
makeDestructurable,
mapGamepadToXbox360Controller,
noop,
normalizeDate,
notNullish,
now,
objectEntries,
objectOmit,
objectPick,
onClickOutside,
onElementRemoval,
onKeyDown,
onKeyPressed,
onKeyStroke,
onKeyUp,
onLongPress,
onStartTyping,
pausableFilter,
promiseTimeout,
provideLocal,
provideSSRWidth,
pxValue,
rand,
reactify,
reactifyObject,
reactiveComputed,
reactiveOmit,
reactivePick,
refAutoReset,
refDebounced,
refDefault,
refThrottled,
refWithControl,
resolveRef,
resolveUnref,
set,
setSSRHandler,
syncRef,
syncRefs,
templateRef,
throttleFilter,
timestamp,
toArray,
toReactive,
toRef,
toRefs,
toValue,
tryOnBeforeMount,
tryOnBeforeUnmount,
tryOnMounted,
tryOnScopeDispose,
tryOnUnmounted,
unrefElement,
until,
useActiveElement,
useAnimate,
useArrayDifference,
useArrayEvery,
useArrayFilter,
useArrayFind,
useArrayFindIndex,
useArrayFindLast,
useArrayIncludes,
useArrayJoin,
useArrayMap,
useArrayReduce,
useArraySome,
useArrayUnique,
useAsyncQueue,
useAsyncState,
useBase64,
useBattery,
useBluetooth,
useBreakpoints,
useBroadcastChannel,
useBrowserLocation,
useCached,
useClipboard,
useClipboardItems,
useCloned,
useColorMode,
useConfirmDialog,
useCountdown,
useCounter,
useCssVar,
useCurrentElement,
useCycleList,
useDark,
useDateFormat,
useDebounceFn,
useDebouncedRefHistory,
useDeviceMotion,
useDeviceOrientation,
useDevicePixelRatio,
useDevicesList,
useDisplayMedia,
useDocumentVisibility,
useDraggable,
useDropZone,
useElementBounding,
useElementByPoint,
useElementHover,
useElementSize,
useElementVisibility,
useEventBus,
useEventListener,
useEventSource,
useEyeDropper,
useFavicon,
useFetch,
useFileDialog,
useFileSystemAccess,
useFocus,
useFocusWithin,
useFps,
useFullscreen,
useGamepad,
useGeolocation,
useIdle,
useImage,
useInfiniteScroll,
useIntersectionObserver,
useInterval,
useIntervalFn,
useKeyModifier,
useLastChanged,
useLocalStorage,
useMagicKeys,
useManualRefHistory,
useMediaControls,
useMediaQuery,
useMemoize,
useMemory,
useMounted,
useMouse,
useMouseInElement,
useMousePressed,
useMutationObserver,
useNavigatorLanguage,
useNetwork,
useNow,
useObjectUrl,
useOffsetPagination,
useOnline,
usePageLeave,
useParallax,
useParentElement,
usePerformanceObserver,
usePermission,
usePointer,
usePointerLock,
usePointerSwipe,
usePreferredColorScheme,
usePreferredContrast,
usePreferredDark,
usePreferredLanguages,
usePreferredReducedMotion,
usePreferredReducedTransparency,
usePrevious,
useRafFn,
useRefHistory,
useResizeObserver,
useSSRWidth,
useScreenOrientation,
useScreenSafeArea,
useScriptTag,
useScroll,
useScrollLock,
useSessionStorage,
useShare,
useSorted,
useSpeechRecognition,
useSpeechSynthesis,
useStepper,
useStorage,
useStorageAsync,
useStyleTag,
useSupported,
useSwipe,
useTemplateRefsList,
useTextDirection,
useTextSelection,
useTextareaAutosize,
useThrottleFn,
useThrottledRefHistory,
useTimeAgo,
useTimeout,
useTimeoutFn,
useTimeoutPoll,
useTimestamp,
useTitle,
useToNumber,
useToString,
useToggle,
useTransition,
useUrlSearchParams,
useUserMedia,
useVModel,
useVModels,
useVibrate,
useVirtualList,
useWakeLock,
useWebNotification,
useWebSocket,
useWebWorker,
useWebWorkerFn,
useWindowFocus,
useWindowScroll,
useWindowSize,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchPausable,
watchThrottled,
watchTriggerable,
watchWithFilter,
whenever
} from "./chunk-P2XGSYO7.js";
import "./chunk-HVR2FF6M.js";
export {
DefaultMagicKeysAliasMap,
StorageSerializers,
TransitionPresets,
assert,
computedAsync as asyncComputed,
refAutoReset as autoResetRef,
breakpointsAntDesign,
breakpointsBootstrapV5,
breakpointsElement,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsQuasar,
breakpointsSematic,
breakpointsTailwind,
breakpointsVuetify,
breakpointsVuetifyV2,
breakpointsVuetifyV3,
bypassFilter,
camelize,
clamp,
cloneFnJSON,
computedAsync,
computedEager,
computedInject,
computedWithControl,
containsProp,
computedWithControl as controlledComputed,
controlledRef,
createEventHook,
createFetch,
createFilterWrapper,
createGlobalState,
createInjectionState,
reactify as createReactiveFn,
createRef,
createReusableTemplate,
createSharedComposable,
createSingletonPromise,
createTemplatePromise,
createUnrefFn,
customStorageEventName,
debounceFilter,
refDebounced as debouncedRef,
watchDebounced as debouncedWatch,
defaultDocument,
defaultLocation,
defaultNavigator,
defaultWindow,
computedEager as eagerComputed,
executeTransition,
extendRef,
formatDate,
formatTimeAgo,
get,
getLifeCycleTarget,
getSSRHandler,
hasOwn,
hyphenate,
identity,
watchIgnorable as ignorableWatch,
increaseWithUnit,
injectLocal,
invoke,
isClient,
isDef,
isDefined,
isIOS,
isObject,
isWorker,
makeDestructurable,
mapGamepadToXbox360Controller,
noop,
normalizeDate,
notNullish,
now,
objectEntries,
objectOmit,
objectPick,
onClickOutside,
onElementRemoval,
onKeyDown,
onKeyPressed,
onKeyStroke,
onKeyUp,
onLongPress,
onStartTyping,
pausableFilter,
watchPausable as pausableWatch,
promiseTimeout,
provideLocal,
provideSSRWidth,
pxValue,
rand,
reactify,
reactifyObject,
reactiveComputed,
reactiveOmit,
reactivePick,
refAutoReset,
refDebounced,
refDefault,
refThrottled,
refWithControl,
resolveRef,
resolveUnref,
set,
setSSRHandler,
syncRef,
syncRefs,
templateRef,
throttleFilter,
refThrottled as throttledRef,
watchThrottled as throttledWatch,
timestamp,
toArray,
toReactive,
toRef,
toRefs,
toValue,
tryOnBeforeMount,
tryOnBeforeUnmount,
tryOnMounted,
tryOnScopeDispose,
tryOnUnmounted,
unrefElement,
until,
useActiveElement,
useAnimate,
useArrayDifference,
useArrayEvery,
useArrayFilter,
useArrayFind,
useArrayFindIndex,
useArrayFindLast,
useArrayIncludes,
useArrayJoin,
useArrayMap,
useArrayReduce,
useArraySome,
useArrayUnique,
useAsyncQueue,
useAsyncState,
useBase64,
useBattery,
useBluetooth,
useBreakpoints,
useBroadcastChannel,
useBrowserLocation,
useCached,
useClipboard,
useClipboardItems,
useCloned,
useColorMode,
useConfirmDialog,
useCountdown,
useCounter,
useCssVar,
useCurrentElement,
useCycleList,
useDark,
useDateFormat,
refDebounced as useDebounce,
useDebounceFn,
useDebouncedRefHistory,
useDeviceMotion,
useDeviceOrientation,
useDevicePixelRatio,
useDevicesList,
useDisplayMedia,
useDocumentVisibility,
useDraggable,
useDropZone,
useElementBounding,
useElementByPoint,
useElementHover,
useElementSize,
useElementVisibility,
useEventBus,
useEventListener,
useEventSource,
useEyeDropper,
useFavicon,
useFetch,
useFileDialog,
useFileSystemAccess,
useFocus,
useFocusWithin,
useFps,
useFullscreen,
useGamepad,
useGeolocation,
useIdle,
useImage,
useInfiniteScroll,
useIntersectionObserver,
useInterval,
useIntervalFn,
useKeyModifier,
useLastChanged,
useLocalStorage,
useMagicKeys,
useManualRefHistory,
useMediaControls,
useMediaQuery,
useMemoize,
useMemory,
useMounted,
useMouse,
useMouseInElement,
useMousePressed,
useMutationObserver,
useNavigatorLanguage,
useNetwork,
useNow,
useObjectUrl,
useOffsetPagination,
useOnline,
usePageLeave,
useParallax,
useParentElement,
usePerformanceObserver,
usePermission,
usePointer,
usePointerLock,
usePointerSwipe,
usePreferredColorScheme,
usePreferredContrast,
usePreferredDark,
usePreferredLanguages,
usePreferredReducedMotion,
usePreferredReducedTransparency,
usePrevious,
useRafFn,
useRefHistory,
useResizeObserver,
useSSRWidth,
useScreenOrientation,
useScreenSafeArea,
useScriptTag,
useScroll,
useScrollLock,
useSessionStorage,
useShare,
useSorted,
useSpeechRecognition,
useSpeechSynthesis,
useStepper,
useStorage,
useStorageAsync,
useStyleTag,
useSupported,
useSwipe,
useTemplateRefsList,
useTextDirection,
useTextSelection,
useTextareaAutosize,
refThrottled as useThrottle,
useThrottleFn,
useThrottledRefHistory,
useTimeAgo,
useTimeout,
useTimeoutFn,
useTimeoutPoll,
useTimestamp,
useTitle,
useToNumber,
useToString,
useToggle,
useTransition,
useUrlSearchParams,
useUserMedia,
useVModel,
useVModels,
useVibrate,
useVirtualList,
useWakeLock,
useWebNotification,
useWebSocket,
useWebWorker,
useWebWorkerFn,
useWindowFocus,
useWindowScroll,
useWindowSize,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchPausable,
watchThrottled,
watchTriggerable,
watchWithFilter,
whenever
};
//# sourceMappingURL=vitepress___@vueuse_core.js.map

View File

@@ -1,7 +0,0 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}

View File

@@ -1,38 +0,0 @@
import { defineConfig } from 'vitepress';
export default defineConfig({
lang: 'ru-RU',
title: 'Документация Gram Pay',
description: 'Документация по проекту Gram Pay',
themeConfig: {
sidebar: [
{
text: 'Введение',
items: [
{ text: 'Ассистент', link: '/parts/1-assistent' },
{ text: 'Общие принципы', link: '/parts/3-general-principles' },
{ text: 'Архитектура', link: '/parts/4-arkhitektura' },
{ text: 'Стиль кода', link: '/parts/5-code-style' },
{ text: 'Именование', link: '/parts/6-naming' },
{ text: 'Документирование', link: '/parts/7-docs' },
{ text: 'Типизация', link: '/parts/8-typing' },
{ text: 'Локализация', link: '/parts/9-localization' },
],
},
{
text: 'FSD и слои',
items: [
{ text: 'Stores', link: '/parts/10-stores' },
{ text: 'CSS', link: '/parts/11-css' },
{ text: 'Компоненты', link: '/parts/12-components' },
{ text: 'Hooks', link: '/parts/13-hooks' },
{ text: 'API-хуки', link: '/parts/14-api-hooks' },
{ text: 'API', link: '/parts/15-api' },
],
},
],
nav: [
{ text: 'Главная', link: '/' },
],
},
});

View File

@@ -1,36 +0,0 @@
# Документация Gram Pay
## Как запустить документацию
1. Установите зависимости:
```bash
npm install
```
2. Запустите локальный сервер документации:
```bash
npm run docs:dev
```
Документация будет доступна по адресу http://localhost:5173
3. Для сборки статики:
```bash
npm run docs:build
```
4. Для предпросмотра собранной документации:
```bash
npm run docs:serve
```
## Где находятся документы
- Вся документация хранится в папке `docs/`.
- Основные разделы — в `docs/parts/` (каждый раздел — отдельный markdown-файл).
- Главная страница — `docs/index.md`.
- Конфигурация VitePress — `docs/.vitepress/config.ts`.
## Как дополнять документацию
- Добавляйте новые разделы в папку `docs/parts/`.
- Обновляйте sidebar в `docs/.vitepress/config.ts` для навигации.
- Используйте только русский язык.

View File

@@ -1,19 +0,0 @@
# Документация Gram Pay
Добро пожаловать в документацию проекта Gram Pay.
- Проект использует архитектуру FSD, строгую типизацию, Mantine, Zustand, SWR, Zod, PostCSS, i18n и другие современные подходы.
- Все правила, чек-листы и стандарты приведены в разделах слева.
## Основные разделы
- [Ассистент](./parts/1-assistent.md)
- [Чек-лист](./parts/2-check-list.md)
- [Архитектура](./parts/4-arkhitektura.md)
- [Стиль кода](./parts/5-code-style.md)
- [Типизация](./parts/8-typing.md)
- [API](./parts/15-api.md)
---
Для навигации используйте меню слева.

20
index.md Normal file
View File

@@ -0,0 +1,20 @@
# Код-стайл для фронтенд-проектов на React/NextJS и TypeScript
Добро пожаловать в документацию код-стайла для фронтенд-разработки.
- Рекомендации охватывают архитектуру (FSD), типизацию, именование, компоненты, хуки, API, CSS и локализацию.
- Все правила и стандарты приведены в разделах слева.
## Основные разделы
- [Ассистент](./parts/1-assistent.md)
- [Общие принципы](./parts/3-general-principles.md)
- [Архитектура](./parts/4-arkhitektura.md)
- [Стиль кода](./parts/5-code-style.md)
- [Типизация](./parts/8-typing.md)
- [Компоненты](./parts/12-components.md)
- [API](./parts/15-api.md)
---
Для навигации используйте меню слева.

View File

@@ -4,11 +4,10 @@
"type": "module", "type": "module",
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"docs": "concat-md --toc --hide-anchor-links --sorter=number docs/parts > ./docs/README.md", "docs": "node ./concat-md.js",
"docs1": "node ./docs/concat-md.js", "dev": "vitepress dev .",
"docs:dev": "vitepress dev docs", "build": "vitepress build .",
"docs:build": "vitepress build docs", "serve": "vitepress serve ."
"docs:serve": "vitepress serve docs"
}, },
"dependencies": { "dependencies": {
"concat-md": "^0.5.1" "concat-md": "^0.5.1"

20
parts/1-tech-stack.md Normal file
View File

@@ -0,0 +1,20 @@
---
title: Стек технологий и библиотек
---
# Стек технологий и библиотек
Базовый стек технологий и библиотек, на который опираются проекты и примеры в документации.
## Что используем обычно
- **TypeScript** — типизация всей логики и компонентов.
- **FSD (Feature-Sliced Design)** — структура проекта и границы модулей.
- **React + Next.js** — основной стек для UI и приложения.
- **Mantine UI** — базовые UI-компоненты.
- **SWR** — получение данных по GET (кеширование и revalidate).
- **Zustand** — глобальное состояние.
- **i18next (i18n)** — локализация всех пользовательских текстов.
- **Vitest** — тестирование.
- **PostCSS Modules** — изоляция стилей.
- **Mobile First** — подход к адаптивной верстке.

View File

0
parts/11-video.md Normal file
View File

0
parts/12-api.md Normal file
View File

0
parts/13-stores.md Normal file
View File

0
parts/14-hooks.md Normal file
View File

0
parts/15-fonts.md Normal file
View File

0
parts/16-localization.md Normal file
View File

49
parts/2-architecture.md Normal file
View File

@@ -0,0 +1,49 @@
---
title: Архитектура
---
# Архитектура
Архитектура построена на FSD (FeatureSliced Design) и строгих границах модулей.
Цель — разделить ответственность, упростить сопровождение и контроль зависимостей.
## Принципы
- Разделять UI, бизнес-логику и инфраструктуру.
- Держать зависимости однонаправленными.
- Открывать наружу только публичный API модулей.
- Не допускать циклических зависимостей.
## Слои
- **app** — инициализация приложения, роутинг, конфигурации, глобальные провайдеры.
- **screens** — экраны и их композиция.
- **layouts** — каркас и шаблоны страниц.
- **widgets** — крупные блоки интерфейса, собирающие несколько сценариев.
- **features** — отдельные пользовательские действия и сценарии.
- **entities** — бизнес-сущности и их модель.
- **shared** — переиспользуемая инфраструктура, утилиты и базовые UIкомпоненты.
## Правила зависимостей
- Допустимые импорты идут сверху вниз: `app → screens → layouts → widgets → features → entities → shared`.
- Импорты между слоями — через публичный API.
- Внутри одного слоя — относительные импорты.
## Публичный API модулей
- Каждый модуль экспортирует наружу только то, что нужно другим слоям.
- Внешние импорты идут только через `index`‑файл модуля.
- Внутренние файлы не импортируются напрямую извне.
## Границы ответственности
- Бизнес‑логика не размещается в UIкомпонентах.
- UIкомпоненты должны быть максимально простыми и предсказуемыми.
- Связь между независимыми сценариями поднимается на уровень выше.
## Типовые ошибки
- Импорт из более высокого слоя в более низкий.
- Смешивание логики нескольких слоёв в одном модуле.
- Прямые импорты внутренних файлов, минуя публичный API.

164
parts/3-code-style.md Normal file
View File

@@ -0,0 +1,164 @@
---
title: Стиль кода
---
# Стиль кода
Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость.
## Отступы и переносы
- Использовать 2 пробела для отступов.
- Не использовать табы.
- Одна инструкция — одна строка.
- Между логическими блоками оставлять пустую строку по необходимости, если это улучшает читаемость.
- В многострочных конструкциях выравнивать закрывающую скобку по началу выражения.
**Хорошо**
```ts
const payload = {
id: 1,
name: 'User',
meta: {
role: 'admin',
},
};
```
**Плохо**
```ts
const payload = { id: 1, name: 'User', meta: { role: 'admin' } };
```
## Длина строк
- Ориентироваться на 100 символов, но превышение допустимо, если строка читается легко.
- Переносить выражение на новые строки, когда строка становится плохо читаемой.
- Не переносить строку внутри строковых литералов без необходимости.
**Хорошо**
```ts
const config = createRequestConfig(
endpoint,
{
headers: {
'X-Request-Id': requestId,
'X-User-Id': userId,
},
params: {
page,
pageSize,
sort: 'createdAt',
},
},
timeoutMs,
);
```
**Плохо**
```ts
const config = createRequestConfig(endpoint, { headers: { 'X-Request-Id': requestId, 'X-User-Id': userId }, params: { page, pageSize, sort: 'createdAt' } }, timeoutMs);
```
## Кавычки
- В JavaScript/TypeScript использовать одинарные кавычки.
- В JSX/TSX для атрибутов использовать двойные кавычки.
- Шаблонные строки использовать только при интерполяции или многострочном тексте.
**Хорошо**
```ts
const label = 'Сохранить';
const title = `Привет, ${name}`;
```
```tsx
<input type="text" placeholder="Введите имя" />
```
**Плохо**
```ts
const label = "Сохранить";
const title = 'Привет, ' + name;
```
```tsx
<input type='text' placeholder='Введите имя' />
```
## Точки с запятой и запятые
- Допускаются упущения точки с запятой, если код остаётся читаемым и однозначным.
- В многострочных массивах, объектах и параметрах функции запятая в конце допускается, но не обязательна.
## Импорты
- В именованных импортах использовать пробелы внутри фигурных скобок.
- Типы импортировать через `import type`.
- `default` импорт и экспорт избегать, использовать именованные.
- Избегать импорта всего модуля через `*`.
**Хорошо**
```ts
import { MyComponent } from 'MyComponent';
import type { User } from '../model/types';
```
**Плохо**
```ts
import MyComponent from 'MyComponent';
import type {User} from '../model/types';
```
## Ранние возвраты (early return)
- Использовать ранние возвраты для упрощения чтения.
- Избегать `else` после `return`.
**Хорошо**
```ts
const getName = (user?: { name: string }) => {
if (!user) {
return 'Гость';
}
return user.name;
};
```
**Плохо**
```ts
const getName = (user?: { name: string }) => {
if (user) {
return user.name;
} else {
return 'Гость';
}
};
```
## Форматирование объектов и массивов
- В многострочных объектах каждое свойство на новой строке.
- В многострочных массивах каждый элемент на новой строке.
- Объекты и массивы можно писать в одну строку, если длина строки не превышает 100 символов.
- В однострочных объектах и массивах использовать пробелы после запятых.
**Хорошо**
```ts
const roles = ['admin', 'editor'];
const options = { id: 1, name: 'User' };
const config = {
url: '/api/users',
method: 'GET',
params: { page: 1, pageSize: 20 },
};
```
**Плохо**
```ts
const roles = ['admin','editor'];
const options = { id: 1,name: 'User' };
const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } };
```

0
parts/4-naming.md Normal file
View File

0
parts/5-documentation.md Normal file
View File

0
parts/6-typing.md Normal file
View File

View File

0
parts/8-components.md Normal file
View File

0
parts/9-styles.md Normal file
View File