first
This commit is contained in:
11
.editorconfig
Normal file
11
.editorconfig
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
132
.gitignore
vendored
Normal file
132
.gitignore
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
1211
docs/.cursorrules
Normal file
1211
docs/.cursorrules
Normal file
File diff suppressed because it is too large
Load Diff
275
docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
275
docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
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
|
||||||
7
docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
40
docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
40
docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12644
docs/.vitepress/cache/deps/chunk-HVR2FF6M.js
vendored
Normal file
12644
docs/.vitepress/cache/deps/chunk-HVR2FF6M.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
docs/.vitepress/cache/deps/chunk-HVR2FF6M.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/chunk-HVR2FF6M.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
9719
docs/.vitepress/cache/deps/chunk-P2XGSYO7.js
vendored
Normal file
9719
docs/.vitepress/cache/deps/chunk-P2XGSYO7.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
docs/.vitepress/cache/deps/chunk-P2XGSYO7.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/chunk-P2XGSYO7.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
3
docs/.vitepress/cache/deps/package.json
vendored
Normal file
3
docs/.vitepress/cache/deps/package.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
4505
docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
4505
docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
583
docs/.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
583
docs/.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
@@ -0,0 +1,583 @@
|
|||||||
|
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
|
||||||
7
docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"sources": [],
|
||||||
|
"sourcesContent": [],
|
||||||
|
"mappings": "",
|
||||||
|
"names": []
|
||||||
|
}
|
||||||
343
docs/.vitepress/cache/deps/vue.js
vendored
Normal file
343
docs/.vitepress/cache/deps/vue.js
vendored
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
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-HVR2FF6M.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
docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
7
docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"sources": [],
|
||||||
|
"sourcesContent": [],
|
||||||
|
"mappings": "",
|
||||||
|
"names": []
|
||||||
|
}
|
||||||
38
docs/.vitepress/config.ts
Normal file
38
docs/.vitepress/config.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
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: '/' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
36
docs/README.md
Normal file
36
docs/README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Документация 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` для навигации.
|
||||||
|
- Используйте только русский язык.
|
||||||
23
docs/concat-md.js
Normal file
23
docs/concat-md.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import concatMd, { concatMdSync } from "concat-md";
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
const resultMd = concatMdSync("./docs/parts", {
|
||||||
|
toc: false,
|
||||||
|
sorter: (a, b) => {
|
||||||
|
// Извлекаем номер из начала имени файла (например, "1" из "1-assistent.md")
|
||||||
|
const getNumber = (filename) => {
|
||||||
|
const match = filename.match(/^(\d+)/);
|
||||||
|
return match ? parseInt(match[1], 10) : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Сортировка по возрастанию (1, 2, 3...)
|
||||||
|
return getNumber(a) - getNumber(b);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Записываем результат в файл docs/.cursorrules
|
||||||
|
const outputPath = path.join("./docs", ".cursorrules");
|
||||||
|
fs.writeFileSync(outputPath, resultMd, "utf8");
|
||||||
|
|
||||||
|
console.log(`Файл .cursorrules успешно создан: ${outputPath}`);
|
||||||
19
docs/index.md
Normal file
19
docs/index.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Документация 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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Для навигации используйте меню слева.
|
||||||
19
docs/parts/1-assistent.md
Normal file
19
docs/parts/1-assistent.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Ассистент
|
||||||
|
|
||||||
|
## Для ассистента
|
||||||
|
|
||||||
|
- Всегда используй Русский язык для общения и генерации документации/комментариев/коммитов.
|
||||||
|
- Всегда следуй этим правилам при генерации кода и ответах.
|
||||||
|
- Всегда пиши план действий перед генерацией кода.
|
||||||
|
- Всегда спрашивай разрешения у пользователя перед генерацией кода.
|
||||||
|
- Всегда проверяй, что код соответствует линтингу и форматированию.
|
||||||
|
- Всегда сверяйся с чек-листом при генерации кода.
|
||||||
|
- Не предлагай решения, которые противоречат этим правилам этого файла.
|
||||||
|
- Если не уверен — уточни у пользователя, не гадай, не придумывай.
|
||||||
|
|
||||||
|
## Обязательность чек-листов
|
||||||
|
|
||||||
|
- Все чек-листы, приведённые в правилах, обязательны к исполнению.
|
||||||
|
- Ассистент обязан сверяться с чек-листом при выполнении любой задачи, связанной с кодом.
|
||||||
|
- Нельзя сокращать, игнорировать или опускать пункты чек-листа — каждый пункт должен быть выполнен или явно отмечен как невыполнимый с объяснением причины.
|
||||||
|
- В каждом ответе, связанном с генерацией или изменением кода, ассистент обязан ссылаться на соответствующий чек-лист и подтверждать его выполнение.
|
||||||
84
docs/parts/10-stores.md
Normal file
84
docs/parts/10-stores.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
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 и смысл полей (см. [правила документирования кода](#правило-для-документирования-кода)).
|
||||||
|
- [ ] Нет неиспользуемого или невалидного кода.
|
||||||
|
- [ ] Экспорт через индексный файл.
|
||||||
227
docs/parts/11-css.md
Normal file
227
docs/parts/11-css.md
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
---
|
||||||
|
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 или используются переменные.
|
||||||
88
docs/parts/12-components.md
Normal file
88
docs/parts/12-components.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
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.
|
||||||
68
docs/parts/13-hooks.md
Normal file
68
docs/parts/13-hooks.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Хуки (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.
|
||||||
|
- [ ] Документировано только назначение хука (см. [правила документирования кода](#правило-для-документирования-кода)).
|
||||||
|
- [ ] Нет неиспользуемого или невалидного кода.
|
||||||
|
- [ ] Экспорт только именованный через индексный файл.
|
||||||
124
docs/parts/14-api-hooks.md
Normal file
124
docs/parts/14-api-hooks.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Хуки 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 напрямую в компонентах, только через хуки.**
|
||||||
|
- [ ] Обработка состояний загрузки, ошибки и данных реализована корректно.
|
||||||
|
- [ ] Не происходит дублирования логики, связанной с получением данных.
|
||||||
|
- [ ] Нет неиспользуемого или невалидного кода.
|
||||||
242
docs/parts/15-api.md
Normal file
242
docs/parts/15-api.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# 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.
|
||||||
|
- [ ] Нет дублирования логики и неиспользуемого кода.
|
||||||
21
docs/parts/3-general-principles.md
Normal file
21
docs/parts/3-general-principles.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
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) для локализации всех пользовательских текстов.
|
||||||
22
docs/parts/4-arkhitektura.md
Normal file
22
docs/parts/4-arkhitektura.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
title: Архитектура
|
||||||
|
---
|
||||||
|
|
||||||
|
# Архитектура
|
||||||
|
|
||||||
|
## Архитектура проекта
|
||||||
|
В проекте используется FSD (Feature-Sliced Design) архитектура.
|
||||||
|
|
||||||
|
- **FSD-границы**
|
||||||
|
- Не нарушать границы слоёв (например, feature не может импортировать из widgets).
|
||||||
|
- Бизнес-логика должна быть вынесена в хуки или сервисы.
|
||||||
|
- **Импорты**
|
||||||
|
- Внутри слоя — относительные импорты.
|
||||||
|
- Между слоями — абсолютные импорты.
|
||||||
|
- **Требования**
|
||||||
|
- Не смешивать логику разных слоёв.
|
||||||
|
- Не хранить бизнес-логику в UI-компонентах.
|
||||||
|
- **Именование**
|
||||||
|
- Файлы и папки kebab-case.
|
||||||
|
|
||||||
|
---
|
||||||
74
docs/parts/5-code-style.md
Normal file
74
docs/parts/5-code-style.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
title: Стиль кода
|
||||||
|
---
|
||||||
|
|
||||||
|
# Стиль кода
|
||||||
|
|
||||||
|
## Отступы
|
||||||
|
|
||||||
|
Используем 2 пробела для отступов во всём проекте. Не используем табы.
|
||||||
|
|
||||||
|
|
||||||
|
## Кавычки
|
||||||
|
|
||||||
|
Используем **одинарные кавычки** для строк в JavaScript/TypeScript, и **двойные кавычки** для атрибутов в JSX/TSX.
|
||||||
|
|
||||||
|
**Пример:**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// JavaScript/TypeScript
|
||||||
|
const message = 'Привет, мир!';
|
||||||
|
const name = 'GramPay';
|
||||||
|
```
|
||||||
|
|
||||||
|
```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`.
|
||||||
18
docs/parts/6-naming.md
Normal file
18
docs/parts/6-naming.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
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`
|
||||||
69
docs/parts/7-docs.md
Normal file
69
docs/parts/7-docs.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
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 — статус выполнения
|
||||||
|
*/
|
||||||
|
```
|
||||||
187
docs/parts/8-typing.md
Normal file
187
docs/parts/8-typing.md
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
---
|
||||||
|
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`, `{}`).
|
||||||
|
- [ ] Для внешних библиотек используются официальные типы или собственные декларации.
|
||||||
|
- [ ] Нет неявного приведения типов, все типы читаемы и прозрачны.
|
||||||
12
docs/parts/9-localization.md
Normal file
12
docs/parts/9-localization.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Локализация
|
||||||
|
---
|
||||||
|
|
||||||
|
# Локализация
|
||||||
|
|
||||||
|
## Правила использования локализации
|
||||||
|
|
||||||
|
- Все пользовательские тексты должны быть вынесены в локализационные файлы.
|
||||||
|
- Для каждого компонента создавать папку `locales/` с файлами `ru.json`, `en.json` и т.д.
|
||||||
|
- Новые namespace обязательно регистрировать в экземпляре i18n (см. `app/i18n.ts`).
|
||||||
|
- В коде использовать только функцию перевода из i18n, не использовать "жёстко" прописанные строки.
|
||||||
5760
package-lock.json
generated
Normal file
5760
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "react-ts docs",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"docs": "concat-md --toc --hide-anchor-links --sorter=number docs/parts > ./docs/README.md",
|
||||||
|
"docs1": "node ./docs/concat-md.js",
|
||||||
|
"docs:dev": "vitepress dev docs",
|
||||||
|
"docs:build": "vitepress build docs",
|
||||||
|
"docs:serve": "vitepress serve docs"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"concat-md": "^0.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitepress": "^1.6.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user