Артем Леванов commited on
Commit
41a71fd
·
1 Parent(s): 06870fc

first commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .editorconfig +22 -0
  2. .eslintrc.cjs +55 -0
  3. .gitignore +27 -0
  4. .prettierrc +12 -0
  5. .storybook/main.ts +25 -0
  6. .storybook/preview.tsx +45 -0
  7. index.html +13 -0
  8. package.json +71 -0
  9. plop/generation/common/api.js +141 -0
  10. plop/generation/common/component.js +55 -0
  11. plop/generation/common/form.js +55 -0
  12. plop/generation/common/slice.js +55 -0
  13. plop/generation/common/store.js +45 -0
  14. plop/generation/entities/entitiesComponent.js +40 -0
  15. plop/generation/entities/entity.js +75 -0
  16. plop/generation/features/feature.js +95 -0
  17. plop/generation/features/featuresComponent.js +40 -0
  18. plop/generation/pages/page.js +36 -0
  19. plop/generation/shared/shared.js +40 -0
  20. plop/generation/widgets/widget.js +40 -0
  21. plop/plopfile.js +51 -0
  22. plop/templates/api/createApi.hbs +18 -0
  23. plop/templates/api/deleteApi.hbs +15 -0
  24. plop/templates/api/fetchApi.hbs +10 -0
  25. plop/templates/api/fetchByIdApi.hbs +13 -0
  26. plop/templates/api/updateApi.hbs +17 -0
  27. plop/templates/component/component.hbs +16 -0
  28. plop/templates/component/component.stories.hbs +18 -0
  29. plop/templates/component/component.style.hbs +5 -0
  30. plop/templates/component/index.hbs +1 -0
  31. plop/templates/form/form.hbs +72 -0
  32. plop/templates/form/form.stories.hbs +18 -0
  33. plop/templates/form/form.style.hbs +9 -0
  34. plop/templates/layers/entities/cardUi/cardUi.hbs +31 -0
  35. plop/templates/layers/entities/cardUi/cardUi.stories.hbs +20 -0
  36. plop/templates/layers/entities/cardUi/cardUi.style.hbs +20 -0
  37. plop/templates/layers/entities/rootIndex.hbs +4 -0
  38. plop/templates/layers/entities/store/store.hbs +10 -0
  39. plop/templates/layers/entities/types/slice.hbs +4 -0
  40. plop/templates/layers/entities/types/sliceSchema.hbs +4 -0
  41. plop/templates/layers/features/createUi/createUi.hbs +30 -0
  42. plop/templates/layers/features/createUi/createUi.style.hbs +5 -0
  43. plop/templates/layers/features/deleteUi/deleteUi.hbs +27 -0
  44. plop/templates/layers/features/deleteUi/deleteUi.style.hbs +5 -0
  45. plop/templates/layers/features/editUi/editUi.hbs +31 -0
  46. plop/templates/layers/features/editUi/editUi.style.hbs +5 -0
  47. plop/templates/layers/features/rootIndex.hbs +4 -0
  48. plop/templates/layers/features/store/store.hbs +12 -0
  49. plop/templates/layers/features/types/sliceSchema.hbs +6 -0
  50. plop/templates/layers/rootIndex/rootIndex.hbs +1 -0
.editorconfig ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Файл с настройками для редактора.
2
+ #
3
+ # Если вы разрабатываете в редакторе WebStorm, BBEdit, Coda или SourceLair
4
+ # этот файл уже поддерживается и не нужно производить никаких дополнительных
5
+ # действий.
6
+ #
7
+ # Если вы ведёте разработку в другом редакторе, зайдите
8
+ # на https://editorconfig.org и в разделе «Download a Plugin»
9
+ # скачайте дополнение для вашего редактора.
10
+
11
+ root = true
12
+
13
+ [*]
14
+ charset = utf-8
15
+ end_of_line = lf
16
+ indent_size = 4
17
+ indent_style = space
18
+ insert_final_newline = true
19
+ trim_trailing_whitespace = true
20
+
21
+ [*.{json,md}]
22
+ indent_size = 2
.eslintrc.cjs ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ "env": {
3
+ "browser": true,
4
+ "es2021": true
5
+ },
6
+ "extends": [
7
+ 'plugin:react/recommended',
8
+ 'plugin:@tanstack/eslint-plugin-query/recommended',
9
+ 'plugin:storybook/recommended',
10
+ 'airbnb',
11
+ 'plugin:prettier/recommended'
12
+ ],
13
+ "overrides": [
14
+ {
15
+ "env": {
16
+ "node": true
17
+ },
18
+ "files": [
19
+ ".eslintrc.{js,cjs}"
20
+ ],
21
+ "parserOptions": {
22
+ "sourceType": "script"
23
+ }
24
+ }
25
+ ],
26
+ "parser": "@typescript-eslint/parser",
27
+ "parserOptions": {
28
+ "ecmaVersion": "latest",
29
+ "sourceType": "module"
30
+ },
31
+ "plugins": [
32
+ "@typescript-eslint",
33
+ "react",
34
+ "@tanstack/query"
35
+ ],
36
+ "ignorePatterns": ["*.svg", "*.json"],
37
+ "rules": {
38
+ "react/jsx-filename-extension": ["error", { "extensions": [".tsx"] }],
39
+ 'import/no-unresolved': 'off',
40
+ 'import/prefer-default-export': 'off',
41
+ 'no-unused-vars': 'warn',
42
+ 'react/require-default-props': 'off',
43
+ 'react/react-in-jsx-scope': 'off',
44
+ 'react/jsx-props-no-spreading': 'warn',
45
+ 'react/function-component-definition': 'off',
46
+ 'no-shadow': 'off',
47
+ 'import/extensions': 'off',
48
+ 'import/no-extraneous-dependencies': 'off',
49
+ 'no-underscore-dangle': 'off',
50
+ 'no-param-reassign': 'off',
51
+ 'no-undef': 'off',
52
+ "react/jsx-max-props-per-line": ['error', {maximum: 3}],
53
+ "prettier/prettier": ['error', {arrowParens: 'always'}]
54
+ }
55
+ }
.gitignore ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ build
13
+ package-lock.json
14
+ dist-ssr
15
+ *.local
16
+ .env
17
+
18
+ # Editor directories and files
19
+ .vscode/*
20
+ !.vscode/extensions.json
21
+ .idea
22
+ .DS_Store
23
+ *.suo
24
+ *.ntvs*
25
+ *.njsproj
26
+ *.sln
27
+ *.sw?
.prettierrc ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "printWidth": 130,
3
+ "semi": true,
4
+ "singleQuote": true,
5
+ "tabWidth": 4,
6
+ "jsxSingleQuote": false,
7
+ "bracketSpacing": true,
8
+ "trailingComma": "es5",
9
+ "arrowParens": "always",
10
+ "jsxBracketSameLine": false,
11
+ "endOfLine": "lf"
12
+ }
.storybook/main.ts ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { StorybookConfig } from '@storybook/react-vite';
2
+ import svgr from 'vite-plugin-svgr';
3
+
4
+ const config: StorybookConfig = {
5
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
6
+ addons: [
7
+ '@storybook/addon-links',
8
+ '@storybook/addon-essentials',
9
+ '@storybook/addon-onboarding',
10
+ '@storybook/addon-interactions',
11
+ ],
12
+ framework: {
13
+ name: '@storybook/react-vite',
14
+ options: {},
15
+ },
16
+ docs: {
17
+ autodocs: 'tag',
18
+ },
19
+ viteFinal: async (config) => {
20
+ config.plugins.push(svgr());
21
+
22
+ return config;
23
+ },
24
+ };
25
+ export default config;
.storybook/preview.tsx ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Preview } from '@storybook/react';
2
+ import { QueryProvider } from '../src/app/providers/QueryProvider';
3
+ import ThemeProvider from '../src/app/providers/ThemeProviders/ui/ThemeProvider';
4
+ import { useTheme } from '../src/app/providers/ThemeProviders';
5
+ import '../src/app/globalStyles/styles.scss';
6
+
7
+ const preview: Preview = {
8
+ parameters: {
9
+ actions: { argTypesRegex: '^on[A-Z].*' },
10
+ controls: {
11
+ matchers: {
12
+ color: /(background|color)$/i,
13
+ date: /Date$/i,
14
+ },
15
+ },
16
+ },
17
+ globalTypes: {
18
+ theme: {
19
+ description: 'Выбрать тему',
20
+ defaultValue: 'light',
21
+ toolbar: {
22
+ title: 'Theme',
23
+ icon: 'circlehollow',
24
+ items: ['light', 'dark'],
25
+ dynamicTitle: true,
26
+ },
27
+ },
28
+ },
29
+ decorators: [
30
+ (Story, context) => {
31
+ const { toggleTheme } = useTheme();
32
+ toggleTheme(context.globals.theme);
33
+
34
+ return (
35
+ <QueryProvider>
36
+ <ThemeProvider>
37
+ <Story />
38
+ </ThemeProvider>
39
+ </QueryProvider>
40
+ );
41
+ },
42
+ ],
43
+ };
44
+
45
+ export default preview;
index.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="description" content="Добро пожаловать" />
7
+ <title>Добро пожаловать!</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
package.json ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "webrise-vite-start",
3
+ "description": "node 20.11.0",
4
+ "private": true,
5
+ "version": "0.0.0",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
+ "preview": "vite preview",
11
+ "storybook": "storybook dev -p 6006",
12
+ "build-storybook": "storybook build",
13
+ "plop:entity": "plop entity --plopfile ./plop/plopfile.js",
14
+ "plop:feature": "plop feature --plopfile ./plop/plopfile.js",
15
+ "plop:page": "plop page --plopfile ./plop/plopfile.js",
16
+ "plop:shared": "plop shared --plopfile ./plop/plopfile.js",
17
+ "plop:widget": "plop widget --plopfile ./plop/plopfile.js",
18
+ "plop:api": "plop api --plopfile ./plop/plopfile.js",
19
+ "plop:form": "plop form --plopfile ./plop/plopfile.js",
20
+ "plop:store": "plop store --plopfile ./plop/plopfile.js",
21
+ "plop:slice": "plop slice --plopfile ./plop/plopfile.js",
22
+ "plop:component": "plop component --plopfile ./plop/plopfile.js"
23
+ },
24
+ "dependencies": {
25
+ "@hookform/resolvers": "^3.3.4",
26
+ "@tanstack/react-query": "^5.18.1",
27
+ "@tanstack/react-query-devtools": "^5.18.1",
28
+ "axios": "^1.6.7",
29
+ "inputmask": "^5.0.8",
30
+ "react": "^18.2.0",
31
+ "react-dom": "^18.2.0",
32
+ "react-hook-form": "^7.50.0",
33
+ "react-router-dom": "^6.22.0",
34
+ "zod": "^3.22.4",
35
+ "zustand": "^4.5.0"
36
+ },
37
+ "devDependencies": {
38
+ "@storybook/addon-essentials": "^7.6.14",
39
+ "@storybook/addon-interactions": "^7.6.14",
40
+ "@storybook/addon-links": "^7.6.14",
41
+ "@storybook/addon-onboarding": "^1.0.11",
42
+ "@storybook/blocks": "^7.6.14",
43
+ "@storybook/builder-vite": "^7.6.14",
44
+ "@storybook/react": "^7.6.14",
45
+ "@storybook/react-vite": "^7.6.14",
46
+ "@storybook/test": "^7.6.14",
47
+ "@tanstack/eslint-plugin-query": "^5.18.1",
48
+ "@types/react": "^18.2.43",
49
+ "@types/react-dom": "^18.2.17",
50
+ "@typescript-eslint/eslint-plugin": "^6.19.1",
51
+ "@typescript-eslint/parser": "^6.19.1",
52
+ "@vitejs/plugin-react": "^4.2.1",
53
+ "eslint": "^8.56.0",
54
+ "eslint-config-airbnb": "^19.0.4",
55
+ "eslint-config-prettier": "^9.1.0",
56
+ "eslint-plugin-import": "^2.29.1",
57
+ "eslint-plugin-jsx-a11y": "^6.8.0",
58
+ "eslint-plugin-prettier": "^5.1.3",
59
+ "eslint-plugin-react": "^7.33.2",
60
+ "eslint-plugin-react-hooks": "^4.6.0",
61
+ "eslint-plugin-react-refresh": "^0.4.5",
62
+ "eslint-plugin-storybook": "^0.6.15",
63
+ "plop": "^4.0.1",
64
+ "prettier": "^3.2.4",
65
+ "sass": "^1.70.0",
66
+ "storybook": "^7.6.14",
67
+ "typescript": "^5.2.2",
68
+ "vite": "^5.0.8",
69
+ "vite-plugin-svgr": "^4.2.0"
70
+ }
71
+ }
plop/generation/common/api.js ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const api = (plop) => {
2
+ plop.setGenerator('api', {
3
+ description: 'Создает апи',
4
+ prompts: [
5
+ {
6
+ type: 'list',
7
+ name: 'apiType',
8
+ message: 'Какой тип запроса?',
9
+ choices: [
10
+ {
11
+ name: 'Запрос списка (fetchNames)',
12
+ value: 'fetchList',
13
+ },
14
+ {
15
+ name: 'Запрос по id (fetchNameById)',
16
+ value: 'fetchById',
17
+ },
18
+ {
19
+ name: 'Создание слайса (createName)',
20
+ value: 'create',
21
+ },
22
+ {
23
+ name: 'Обновление слайса (updateName)',
24
+ value: 'update',
25
+ },
26
+ {
27
+ name: 'Удаление слайса (deleteName)',
28
+ value: 'delete',
29
+ },
30
+ ],
31
+ },
32
+ {
33
+ type: 'list',
34
+ name: 'layerName',
35
+ message: 'В какой слой положить?',
36
+ choices: [
37
+ {
38
+ name: 'entities',
39
+ value: 'entities',
40
+ },
41
+ {
42
+ name: 'features',
43
+ value: 'features',
44
+ },
45
+ {
46
+ name: 'widgets',
47
+ value: 'widgets',
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ type: 'input',
53
+ name: 'sliceName',
54
+ message: 'В какой слайс?',
55
+ },
56
+ ],
57
+ actions: (data) => {
58
+ let actionList = [];
59
+
60
+ switch (data.apiType) {
61
+ case 'fetchList':
62
+ actionList = [
63
+ {
64
+ type: 'add',
65
+ path: '../src/{{layerName}}/{{sliceName}}/api/fetch{{sliceName}}s.ts',
66
+ templateFile: './templates/api/fetchApi.hbs',
67
+ },
68
+ {
69
+ type: 'add',
70
+ path: '../src/{{layerName}}/{{sliceName}}/lib/query/useFetch{{sliceName}}s.tsx',
71
+ templateFile: './templates/query/fetchQuery.hbs',
72
+ },
73
+ ];
74
+ break;
75
+ case 'fetchById':
76
+ actionList = [
77
+ {
78
+ type: 'add',
79
+ path: '../src/{{layerName}}/{{sliceName}}/api/fetch{{sliceName}}ById.ts',
80
+ templateFile: './templates/api/fetchByIdApi.hbs',
81
+ },
82
+ {
83
+ type: 'add',
84
+ path: '../src/{{layerName}}/{{sliceName}}/lib/query/useFetch{{sliceName}}ById.tsx',
85
+ templateFile: './templates/query/fetchByIdQuery.hbs',
86
+ },
87
+ ];
88
+ break;
89
+ case 'create':
90
+ actionList = [
91
+ {
92
+ type: 'add',
93
+ path: '../src/{{layerName}}/{{sliceName}}/api/create{{sliceName}}.ts',
94
+ templateFile: './templates/api/createApi.hbs',
95
+ },
96
+ {
97
+ type: 'add',
98
+ path: '../src/{{layerName}}/{{sliceName}}/lib/query/useCreate{{sliceName}}.tsx',
99
+ templateFile: './templates/query/createQuery.hbs',
100
+ },
101
+ ];
102
+ break;
103
+ case 'update':
104
+ actionList = [
105
+ {
106
+ type: 'add',
107
+ path: '../src/{{layerName}}/{{sliceName}}/api/update{{sliceName}}.ts',
108
+ templateFile: './templates/api/updateApi.hbs',
109
+ },
110
+ {
111
+ type: 'add',
112
+ path: '../src/{{layerName}}/{{sliceName}}/lib/query/useUpdate{{sliceName}}.tsx',
113
+ templateFile: './templates/query/updateQuery.hbs',
114
+ },
115
+ ];
116
+ break;
117
+ case 'delete':
118
+ actionList = [
119
+ {
120
+ type: 'add',
121
+ path: '../src/{{layerName}}/{{sliceName}}/api/delete{{sliceName}}.ts',
122
+ templateFile: './templates/api/deleteApi.hbs',
123
+ },
124
+ {
125
+ type: 'add',
126
+ path: '../src/{{layerName}}/{{sliceName}}/lib/query/useDelete{{sliceName}}.tsx',
127
+ templateFile: './templates/query/deleteQuery.hbs',
128
+ },
129
+ ];
130
+ break;
131
+ default:
132
+ console.log('Нет такого типа');
133
+ break;
134
+ }
135
+
136
+ return actionList;
137
+ },
138
+ });
139
+ };
140
+
141
+ module.exports = api;
plop/generation/common/component.js ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const component = (plop) => {
2
+ plop.setGenerator('component', {
3
+ description: 'Создает стандартный компонент',
4
+ prompts: [
5
+ {
6
+ type: 'list',
7
+ name: 'layerName',
8
+ message: 'В какой слой положить?',
9
+ choices: [
10
+ {
11
+ name: 'entities',
12
+ value: 'entities',
13
+ },
14
+ {
15
+ name: 'features',
16
+ value: 'features',
17
+ },
18
+ {
19
+ name: 'widgets',
20
+ value: 'widgets',
21
+ },
22
+ ],
23
+ },
24
+ {
25
+ type: 'input',
26
+ name: 'sliceName',
27
+ message: 'В какой слайс?',
28
+ },
29
+ {
30
+ type: 'input',
31
+ name: 'name',
32
+ message: 'Название компонента?',
33
+ },
34
+ ],
35
+ actions: [
36
+ {
37
+ type: 'add',
38
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.tsx',
39
+ templateFile: './templates/component/component.hbs',
40
+ },
41
+ {
42
+ type: 'add',
43
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.module.scss',
44
+ templateFile: './templates/component/component.style.hbs',
45
+ },
46
+ {
47
+ type: 'add',
48
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.stories.tsx',
49
+ templateFile: './templates/component/component.stories.hbs',
50
+ },
51
+ ],
52
+ });
53
+ };
54
+
55
+ module.exports = component;
plop/generation/common/form.js ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const form = (plop) => {
2
+ plop.setGenerator('form', {
3
+ description: 'Создает стандартную форму',
4
+ prompts: [
5
+ {
6
+ type: 'list',
7
+ name: 'layerName',
8
+ message: 'В какой слой положить?',
9
+ choices: [
10
+ {
11
+ name: 'entities',
12
+ value: 'entities',
13
+ },
14
+ {
15
+ name: 'features',
16
+ value: 'features',
17
+ },
18
+ {
19
+ name: 'widgets',
20
+ value: 'widgets',
21
+ },
22
+ ],
23
+ },
24
+ {
25
+ type: 'input',
26
+ name: 'sliceName',
27
+ message: 'В какой слайс?',
28
+ },
29
+ {
30
+ type: 'input',
31
+ name: 'name',
32
+ message: 'Название компонента?',
33
+ },
34
+ ],
35
+ actions: [
36
+ {
37
+ type: 'add',
38
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.tsx',
39
+ templateFile: './templates/form/form.hbs',
40
+ },
41
+ {
42
+ type: 'add',
43
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.module.scss',
44
+ templateFile: './templates/form/form.style.hbs',
45
+ },
46
+ {
47
+ type: 'add',
48
+ path: '../src/{{layerName}}/{{sliceName}}/ui/{{name}}/{{name}}.stories.tsx',
49
+ templateFile: './templates/form/form.stories.hbs',
50
+ },
51
+ ],
52
+ });
53
+ };
54
+
55
+ module.exports = form;
plop/generation/common/slice.js ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const slice = (plop) => {
2
+ plop.setGenerator('slice', {
3
+ description: 'Создает слайс',
4
+ prompts: [
5
+ {
6
+ type: 'list',
7
+ name: 'layerName',
8
+ message: 'В какой слой положить?',
9
+ choices: [
10
+ {
11
+ name: 'entities',
12
+ value: 'entities',
13
+ },
14
+ {
15
+ name: 'features',
16
+ value: 'features',
17
+ },
18
+ {
19
+ name: 'widgets',
20
+ value: 'widgets',
21
+ },
22
+ ],
23
+ },
24
+ {
25
+ type: 'input',
26
+ name: 'name',
27
+ message: 'Название слайса?',
28
+ },
29
+ ],
30
+ actions: [
31
+ {
32
+ type: 'add',
33
+ path: '../src/{{layerName}}/{{name}}/ui/{{name}}.tsx',
34
+ templateFile: './templates/component/component.hbs',
35
+ },
36
+ {
37
+ type: 'add',
38
+ path: '../src/{{layerName}}/{{name}}/ui/{{name}}.module.scss',
39
+ templateFile: './templates/component/component.style.hbs',
40
+ },
41
+ {
42
+ type: 'add',
43
+ path: '../src/{{layerName}}/{{name}}/ui/{{name}}.stories.tsx',
44
+ templateFile: './templates/component/component.stories.hbs',
45
+ },
46
+ {
47
+ type: 'add',
48
+ path: '../src/{{layerName}}/{{name}}/index.ts',
49
+ templateFile: './templates/layers/rootIndex/rootIndex.hbs',
50
+ },
51
+ ],
52
+ });
53
+ };
54
+
55
+ module.exports = slice;
plop/generation/common/store.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const store = (plop) => {
2
+ plop.setGenerator('store', {
3
+ description: 'Создает стор',
4
+ prompts: [
5
+ {
6
+ type: 'list',
7
+ name: 'layerName',
8
+ message: 'В какой слой положить?',
9
+ choices: [
10
+ {
11
+ name: 'entities',
12
+ value: 'entities',
13
+ },
14
+ {
15
+ name: 'features',
16
+ value: 'features',
17
+ },
18
+ {
19
+ name: 'widgets',
20
+ value: 'widgets',
21
+ },
22
+ ],
23
+ },
24
+ {
25
+ type: 'input',
26
+ name: 'sliceName',
27
+ message: 'В какой слайс?',
28
+ },
29
+ ],
30
+ actions: [
31
+ {
32
+ type: 'add',
33
+ path: '../src/{{layerName}}/{{sliceName}}/model/store/use{{sliceName}}Store.ts',
34
+ templateFile: './templates/store/store.hbs',
35
+ },
36
+ {
37
+ type: 'add',
38
+ path: '../src/{{layerName}}/{{sliceName}}/model/types/{{lowerCase sliceName}}Schema.ts',
39
+ templateFile: './templates/store/storeSchema.hbs',
40
+ },
41
+ ],
42
+ });
43
+ };
44
+
45
+ module.exports = store;
plop/generation/entities/entitiesComponent.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const entitiesComponent = (plop) => {
2
+ plop.setGenerator('e-component', {
3
+ description: 'Создает стандартный компонент в сущности',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'name',
8
+ message: 'Название компонента?',
9
+ },
10
+ {
11
+ type: 'input',
12
+ name: 'sliceName',
13
+ message: 'Название слайса?',
14
+ },
15
+ ],
16
+ actions: (data) => {
17
+ data.layerName = 'entity';
18
+
19
+ return [
20
+ {
21
+ type: 'add',
22
+ path: '../src/entities/{{sliceName}}/ui/{{name}}/{{name}}.tsx',
23
+ templateFile: './templates/component/component.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/entities/{{sliceName}}/ui/{{name}}/{{name}}.module.scss',
28
+ templateFile: './templates/component/component.style.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/entities/{{sliceName}}/ui/{{name}}/{{name}}.stories.tsx',
33
+ templateFile: './templates/component/component.stories.hbs',
34
+ },
35
+ ];
36
+ },
37
+ });
38
+ };
39
+
40
+ module.exports = entitiesComponent;
plop/generation/entities/entity.js ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const entity = (plop) => {
2
+ plop.setGenerator('entity', {
3
+ description: 'Создает слайс в сущности',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'sliceName',
8
+ message: 'Название слайса?',
9
+ },
10
+ ],
11
+ actions: (data) => {
12
+ data.layerName = 'entity';
13
+
14
+ return [
15
+ {
16
+ type: 'add',
17
+ path: '../src/entities/{{sliceName}}/ui/{{sliceName}}Card/{{sliceName}}Card.tsx',
18
+ templateFile: './templates/layers/entities/cardUi/cardUi.hbs',
19
+ },
20
+ {
21
+ type: 'add',
22
+ path: '../src/entities/{{sliceName}}/ui/{{sliceName}}Card/{{sliceName}}Card.module.scss',
23
+ templateFile: './templates/layers/entities/cardUi/cardUi.style.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/entities/{{sliceName}}/ui/{{sliceName}}Card/{{sliceName}}Card.stories.tsx',
28
+ templateFile: './templates/layers/entities/cardUi/cardUi.stories.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/entities/{{sliceName}}/model/store/use{{sliceName}}Store.ts',
33
+ templateFile: './templates/layers/entities/store/store.hbs',
34
+ },
35
+ {
36
+ type: 'add',
37
+ path: '../src/entities/{{sliceName}}/model/types/{{lowerCase sliceName}}Schema.ts',
38
+ templateFile: './templates/layers/entities/types/sliceSchema.hbs',
39
+ },
40
+ {
41
+ type: 'add',
42
+ path: '../src/entities/{{sliceName}}/model/types/{{lowerCase sliceName}}.ts',
43
+ templateFile: './templates/layers/entities/types/slice.hbs',
44
+ },
45
+ {
46
+ type: 'add',
47
+ path: '../src/entities/{{sliceName}}/api/fetch{{sliceName}}s.ts',
48
+ templateFile: './templates/api/fetchApi.hbs',
49
+ },
50
+ {
51
+ type: 'add',
52
+ path: '../src/entities/{{sliceName}}/lib/query/useFetch{{sliceName}}s.tsx',
53
+ templateFile: './templates/query/fetchQuery.hbs',
54
+ },
55
+ {
56
+ type: 'add',
57
+ path: '../src/entities/{{sliceName}}/api/fetch{{sliceName}}ById.ts',
58
+ templateFile: './templates/api/fetchByIdApi.hbs',
59
+ },
60
+ {
61
+ type: 'add',
62
+ path: '../src/entities/{{sliceName}}/lib/query/useFetch{{sliceName}}ById.tsx',
63
+ templateFile: './templates/query/fetchByIdQuery.hbs',
64
+ },
65
+ {
66
+ type: 'add',
67
+ path: '../src/entities/{{sliceName}}/index.ts',
68
+ templateFile: './templates/layers/entities/rootIndex.hbs',
69
+ },
70
+ ];
71
+ },
72
+ });
73
+ };
74
+
75
+ module.exports = entity;
plop/generation/features/feature.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const feature = (plop) => {
2
+ plop.setGenerator('feature', {
3
+ description: 'Создает слайс в фиче',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'sliceName',
8
+ message: 'Название слайса?',
9
+ },
10
+ ],
11
+ actions: (data) => {
12
+ data.layerName = 'feature';
13
+
14
+ return [
15
+ {
16
+ type: 'add',
17
+ path: '../src/features/{{sliceName}}/ui/Create{{sliceName}}/Create{{sliceName}}.tsx',
18
+ templateFile: './templates/layers/features/createUi/createUi.hbs',
19
+ },
20
+ {
21
+ type: 'add',
22
+ path: '../src/features/{{sliceName}}/ui/Create{{sliceName}}/Create{{sliceName}}.module.scss',
23
+ templateFile: './templates/layers/features/createUi/createUi.style.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/features/{{sliceName}}/ui/Edit{{sliceName}}/Edit{{sliceName}}.tsx',
28
+ templateFile: './templates/layers/features/editUi/editUi.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/features/{{sliceName}}/ui/Edit{{sliceName}}/Edit{{sliceName}}.module.scss',
33
+ templateFile: './templates/layers/features/editUi/editUi.style.hbs',
34
+ },
35
+ {
36
+ type: 'add',
37
+ path: '../src/features/{{sliceName}}/ui/Delete{{sliceName}}/Delete{{sliceName}}.tsx',
38
+ templateFile: './templates/layers/features/deleteUi/deleteUi.hbs',
39
+ },
40
+ {
41
+ type: 'add',
42
+ path: '../src/features/{{sliceName}}/ui/Delete{{sliceName}}/Delete{{sliceName}}.module.scss',
43
+ templateFile: './templates/layers/features/deleteUi/deleteUi.style.hbs',
44
+ },
45
+ {
46
+ type: 'add',
47
+ path: '../src/features/{{sliceName}}/model/store/use{{sliceName}}Store.ts',
48
+ templateFile: './templates/layers/features/store/store.hbs',
49
+ },
50
+ {
51
+ type: 'add',
52
+ path: '../src/features/{{sliceName}}/model/types/{{lowerCase sliceName}}Schema.ts',
53
+ templateFile: './templates/layers/features/types/sliceSchema.hbs',
54
+ },
55
+ {
56
+ type: 'add',
57
+ path: '../src/features/{{sliceName}}/api/create{{sliceName}}.ts',
58
+ templateFile: './templates/api/createApi.hbs',
59
+ },
60
+ {
61
+ type: 'add',
62
+ path: '../src/features/{{sliceName}}/lib/query/useCreate{{sliceName}}.tsx',
63
+ templateFile: './templates/query/createQuery.hbs',
64
+ },
65
+ {
66
+ type: 'add',
67
+ path: '../src/features/{{sliceName}}/api/update{{sliceName}}.ts',
68
+ templateFile: './templates/api/updateApi.hbs',
69
+ },
70
+ {
71
+ type: 'add',
72
+ path: '../src/features/{{sliceName}}/lib/query/useUpdate{{sliceName}}.tsx',
73
+ templateFile: './templates/query/updateQuery.hbs',
74
+ },
75
+ {
76
+ type: 'add',
77
+ path: '../src/features/{{sliceName}}/api/delete{{sliceName}}.ts',
78
+ templateFile: './templates/api/deleteApi.hbs',
79
+ },
80
+ {
81
+ type: 'add',
82
+ path: '../src/features/{{sliceName}}/lib/query/useDelete{{sliceName}}.tsx',
83
+ templateFile: './templates/query/deleteQuery.hbs',
84
+ },
85
+ {
86
+ type: 'add',
87
+ path: '../src/features/{{sliceName}}/index.ts',
88
+ templateFile: './templates/layers/features/rootIndex.hbs',
89
+ },
90
+ ];
91
+ },
92
+ });
93
+ };
94
+
95
+ module.exports = feature;
plop/generation/features/featuresComponent.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const featuresComponent = (plop) => {
2
+ plop.setGenerator('f-component', {
3
+ description: 'Создает стандартный компонент в фиче',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'name',
8
+ message: 'Название компонента?',
9
+ },
10
+ {
11
+ type: 'input',
12
+ name: 'sliceName',
13
+ message: 'Название слайса?',
14
+ },
15
+ ],
16
+ actions: (data) => {
17
+ data.layerName = 'feature';
18
+
19
+ return [
20
+ {
21
+ type: 'add',
22
+ path: '../src/features/{{sliceName}}/ui/{{name}}/{{name}}.tsx',
23
+ templateFile: './templates/component/component.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/features/{{sliceName}}/ui/{{name}}/{{name}}.module.scss',
28
+ templateFile: './templates/component/component.style.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/features/{{sliceName}}/ui/{{name}}/{{name}}.stories.tsx',
33
+ templateFile: './templates/component/component.stories.hbs',
34
+ },
35
+ ];
36
+ },
37
+ });
38
+ };
39
+
40
+ module.exports = featuresComponent;
plop/generation/pages/page.js ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const page = (plop) => {
2
+ plop.setGenerator('page', {
3
+ description: 'Создает страницу',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'name',
8
+ message: 'Название страницы?',
9
+ },
10
+ ],
11
+ actions: [
12
+ {
13
+ type: 'add',
14
+ path: '../src/pages/{{name}}/ui/{{name}}.tsx',
15
+ templateFile: './templates/page/page.hbs',
16
+ },
17
+ {
18
+ type: 'add',
19
+ path: '../src/pages/{{name}}/ui/{{name}}.async.tsx',
20
+ templateFile: './templates/page/page.async.hbs',
21
+ },
22
+ {
23
+ type: 'add',
24
+ path: '../src/pages/{{name}}/ui/{{name}}.module.scss',
25
+ templateFile: './templates/page/page.style.hbs',
26
+ },
27
+ {
28
+ type: 'add',
29
+ path: '../src/pages/{{name}}/index.ts',
30
+ templateFile: './templates/page/index.hbs',
31
+ },
32
+ ],
33
+ });
34
+ };
35
+
36
+ module.exports = page;
plop/generation/shared/shared.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const shared = (plop) => {
2
+ plop.setGenerator('shared', {
3
+ description: 'Создает ui компонент в shared слое',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'name',
8
+ message: 'Название компонента?',
9
+ },
10
+ ],
11
+ actions: (data) => {
12
+ data.layerName = 'shared';
13
+
14
+ return [
15
+ {
16
+ type: 'add',
17
+ path: '../src/shared/ui/{{name}}/{{name}}.tsx',
18
+ templateFile: './templates/component/component.hbs',
19
+ },
20
+ {
21
+ type: 'add',
22
+ path: '../src/shared/ui/{{name}}/{{name}}.module.scss',
23
+ templateFile: './templates/component/component.style.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/shared/ui/{{name}}/{{name}}.stories.tsx',
28
+ templateFile: './templates/component/component.stories.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/shared/ui/{{name}}/index.ts',
33
+ templateFile: './templates/component/index.hbs',
34
+ },
35
+ ];
36
+ },
37
+ });
38
+ };
39
+
40
+ module.exports = shared;
plop/generation/widgets/widget.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const widget = (plop) => {
2
+ plop.setGenerator('widget', {
3
+ description: 'Создает слайс в виджете',
4
+ prompts: [
5
+ {
6
+ type: 'input',
7
+ name: 'name',
8
+ message: 'Название слайса?',
9
+ },
10
+ ],
11
+ actions: (data) => {
12
+ data.layerName = 'widgets';
13
+
14
+ return [
15
+ {
16
+ type: 'add',
17
+ path: '../src/widgets/{{name}}/ui/{{name}}.tsx',
18
+ templateFile: './templates/component/component.hbs',
19
+ },
20
+ {
21
+ type: 'add',
22
+ path: '../src/widgets/{{name}}/ui/{{name}}.module.scss',
23
+ templateFile: './templates/component/component.style.hbs',
24
+ },
25
+ {
26
+ type: 'add',
27
+ path: '../src/widgets/{{name}}/ui/{{name}}.stories.tsx',
28
+ templateFile: './templates/component/component.stories.hbs',
29
+ },
30
+ {
31
+ type: 'add',
32
+ path: '../src/widgets/{{name}}/index.ts',
33
+ templateFile: './templates/layers/rootIndex/rootIndex.hbs',
34
+ },
35
+ ];
36
+ },
37
+ });
38
+ };
39
+
40
+ module.exports = widget;
plop/plopfile.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const api = require('./generation/common/api');
2
+ const page = require('./generation/pages/page');
3
+ const form = require('./generation/common/form');
4
+ const store = require('./generation/common/store');
5
+ const slice = require('./generation/common/slice');
6
+ const shared = require('./generation/shared/shared');
7
+ const widget = require('./generation/widgets/widget');
8
+ const entity = require('./generation/entities/entity');
9
+ const feature = require('./generation/features/feature');
10
+ const component = require('./generation/common/component');
11
+ const entitiesComponent = require('./generation/entities/entitiesComponent');
12
+ const featuresComponent = require('./generation/features/featuresComponent');
13
+
14
+ const config = (plop) => {
15
+ // Common
16
+ api(plop);
17
+ form(plop);
18
+ store(plop);
19
+ slice(plop);
20
+ component(plop);
21
+
22
+ // Entities
23
+ entity(plop);
24
+ entitiesComponent(plop);
25
+
26
+ // Features
27
+ feature(plop);
28
+ featuresComponent(plop);
29
+
30
+ // Pages
31
+ page(plop);
32
+
33
+ // Shared
34
+ shared(plop);
35
+
36
+ // Widget
37
+ widget(plop);
38
+
39
+ // Helpers
40
+ // Первая большая буква
41
+ plop.setHelper('capitalize', (text) => {
42
+ return text.charAt(0).toUpperCase() + text.slice(1);
43
+ });
44
+
45
+ // Все с маленькой
46
+ plop.setHelper('lowerCase', (text) => {
47
+ return text.toLowerCase();
48
+ });
49
+ };
50
+
51
+ module.exports = config;
plop/templates/api/createApi.hbs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { $api } from '@/shared/api/axiosInstance';
2
+ import { {{sliceName}}Type } from '@/entities/{{sliceName}}';
3
+
4
+ type Create{{sliceName}}Props = {
5
+ user_id: number;
6
+ };
7
+
8
+ type Create{{sliceName}}Response = {
9
+ status: number;
10
+ message: string;
11
+ {{lowerCase sliceName}}: {{sliceName}}Type;
12
+ };
13
+
14
+ export const create{{sliceName}} = async (props: Create{{sliceName}}Props) => {
15
+ const { data } = await $api.post<Create{{sliceName}}Response>(`/{{lowerCase sliceName}}s/create`, props);
16
+
17
+ return data;
18
+ };
plop/templates/api/deleteApi.hbs ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { $api } from '@/shared/api/axiosInstance';
2
+
3
+ type Delete{{sliceName}}Props = {
4
+ {{lowerCase sliceName}}_id: number;
5
+ };
6
+ type Delete{{sliceName}}Response = {
7
+ status: number;
8
+ message: string;
9
+ };
10
+
11
+ export const delete{{sliceName}} = async (props: Delete{{sliceName}}Props) => {
12
+ const { data } = await $api.post<Delete{{sliceName}}Response>(`/{{lowerCase sliceName}}s/delete`, props);
13
+
14
+ return data;
15
+ };
plop/templates/api/fetchApi.hbs ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { {{sliceName}}Type } from '../model/types/{{lowerCase sliceName}}';
2
+ import { $api } from '@/shared/api/axiosInstance';
3
+
4
+ type Fetch{{sliceName}}sResponse = {{sliceName}}Type[];
5
+
6
+ export const fetch{{sliceName}}s = async () => {
7
+ const { data } = await $api.get<Fetch{{sliceName}}sResponse>(`/{{lowerCase sliceName}}s`);
8
+
9
+ return data;
10
+ };
plop/templates/api/fetchByIdApi.hbs ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { {{sliceName}}Type } from '../model/types/{{lowerCase sliceName}}';
2
+ import { $api } from '@/shared/api/axiosInstance';
3
+
4
+ type Fetch{{sliceName}}ByIdProps = {
5
+ {{lowerCase sliceName}}_id: number;
6
+ };
7
+ type Fetch{{sliceName}}ByIdResponse = {{sliceName}}Type;
8
+
9
+ export const fetch{{sliceName}}ById = async (props: Fetch{{sliceName}}ByIdProps) => {
10
+ const { data } = await $api.post<Fetch{{sliceName}}ByIdResponse>('/{{lowerCase sliceName}}-by-id', props);
11
+
12
+ return data;
13
+ };
plop/templates/api/updateApi.hbs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { $api } from '@/shared/api/axiosInstance';
2
+
3
+ type Update{{sliceName}}Props = {
4
+ {{lowerCase sliceName}}_id: number;
5
+ user_id: number;
6
+ };
7
+
8
+ type Update{{sliceName}}Response = {
9
+ status: number;
10
+ message: string;
11
+ };
12
+
13
+ export const update{{sliceName}} = async (props: Update{{sliceName}}Props) => {
14
+ const { data } = await $api.post<Update{{sliceName}}Response>(`/{{lowerCase sliceName}}s/update`, props);
15
+
16
+ return data;
17
+ };
plop/templates/component/component.hbs ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { classNames } from '@/shared/lib/classNames/classNames';
2
+ import cls from './{{name}}.module.scss';
3
+
4
+ interface {{name}}Props {
5
+ className?: string;
6
+ }
7
+
8
+ export const {{name}} = (props: {{name}}Props) => {
9
+ const { className } = props;
10
+
11
+ return (
12
+ <div className={classNames(cls.{{name}}, {}, [className])}>
13
+ <p>{{name}}</p>
14
+ </div>
15
+ );
16
+ };
plop/templates/component/component.stories.hbs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { {{name}} } from './{{name}}';
3
+
4
+ const meta = {
5
+ title: '{{capitalize layerName}}/{{name}}',
6
+ component: {{name}},
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof {{name}}>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Primary: Story = {
17
+ args: {},
18
+ };
plop/templates/component/component.style.hbs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .{{name}} {
4
+ display: block;
5
+ }
plop/templates/component/index.hbs ADDED
@@ -0,0 +1 @@
 
 
1
+ export { {{name}} } from './{{name}}';
plop/templates/form/form.hbs ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { z } from 'zod';
2
+ import { zodResolver } from '@hookform/resolvers/zod';
3
+ import { FormProvider, useForm } from 'react-hook-form';
4
+ import { HInput } from '@/shared/ui/FormComponents';
5
+ import { classNames } from '@/shared/lib/classNames/classNames';
6
+ import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button';
7
+ import cls from './{{name}}.module.scss';
8
+
9
+ const {{name}}Schema = z.object({
10
+ title: z //
11
+ .string()
12
+ .min(1, { message: 'Заполните поле' })
13
+ .max(255),
14
+ body: z //
15
+ .string()
16
+ .min(1, { message: 'Заполните поле' })
17
+ .max(255),
18
+ });
19
+
20
+ type {{name}}Type = z.infer<typeof {{name}}Schema>;
21
+
22
+ interface {{name}}Props {
23
+ className?: string
24
+ }
25
+
26
+ const defaultValues = {
27
+ first: '',
28
+ second: '',
29
+ };
30
+
31
+ export const {{name}} = (props: {{name}}Props) => {
32
+ const { className } = props;
33
+
34
+ const methods = useForm<{{name}}Type>({
35
+ defaultValues,
36
+ resolver: zodResolver({{name}}Schema),
37
+ });
38
+
39
+ const { handleSubmit } = methods;
40
+
41
+ const submitHandler = async (data: {{name}}Type) => {
42
+ console.log('data: ', data);
43
+ };
44
+
45
+ return (
46
+ <div className={classNames(cls.{{name}}, {}, [className])}>
47
+ <FormProvider {...methods}>
48
+ <form onSubmit={handleSubmit(submitHandler)}>
49
+ <HInput //
50
+ className={cls.field}
51
+ name="first"
52
+ placeholder="Введите название"
53
+ />
54
+ <HInput //
55
+ className={cls.field}
56
+ name="second"
57
+ placeholder="Введите описание"
58
+ />
59
+ <Button
60
+ theme={ButtonTheme.PRIMARY}
61
+ size={ButtonSize.XL}
62
+ type="submit"
63
+ // showSpinner={isAddUserLoading}
64
+ // disabled={isAddUserLoading}
65
+ >
66
+ Сохранить
67
+ </Button>
68
+ </form>
69
+ </FormProvider>
70
+ </div>
71
+ );
72
+ };
plop/templates/form/form.stories.hbs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { {{name}} } from './{{name}}';
3
+
4
+ const meta = {
5
+ title: '{{capitalize layerName}}/{{name}}',
6
+ component: {{name}},
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof {{name}}>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Primary: Story = {
17
+ args: {},
18
+ };
plop/templates/form/form.style.hbs ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .{{name}} {
4
+ display: block;
5
+ }
6
+
7
+ .field {
8
+ margin-bottom: 12px;
9
+ }
plop/templates/layers/entities/cardUi/cardUi.hbs ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ReactNode } from 'react';
2
+ import { classNames } from '@/shared/lib/classNames/classNames';
3
+ import { {{sliceName}}Type } from '../../model/types/{{lowerCase sliceName}}';
4
+ import cls from './{{sliceName}}Card.module.scss';
5
+
6
+ interface {{sliceName}}CardProps {
7
+ className?: string;
8
+ {{lowerCase sliceName}}: {{sliceName}}Type;
9
+ editButton?: ReactNode;
10
+ deleteButton?: ReactNode;
11
+ }
12
+
13
+ export const {{sliceName}}Card = (props: {{sliceName}}CardProps) => {
14
+ const { className, {{lowerCase sliceName}}, editButton, deleteButton } = props;
15
+
16
+ return (
17
+ <div className={classNames(cls.{{sliceName}}Card, {}, [className])}>
18
+ <div className={cls.content}>
19
+ <div className={cls.name}>
20
+ {
21
+ {{lowerCase sliceName}}.title
22
+ }
23
+ </div>
24
+ <div className={cls.buttons}>
25
+ {editButton}
26
+ {deleteButton}
27
+ </div>
28
+ </div>
29
+ </div>
30
+ );
31
+ };
plop/templates/layers/entities/cardUi/cardUi.stories.hbs ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { {{sliceName}}Card } from './{{sliceName}}Card';
3
+
4
+ const meta = {
5
+ title: '{{capitalize layerName}}/{{sliceName}}Card',
6
+ component: {{sliceName}}Card,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof {{sliceName}}Card>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Primary: Story = {
17
+ args: {
18
+ {{lowerCase sliceName}}: { id: 1, title: 'CardName' },
19
+ },
20
+ };
plop/templates/layers/entities/cardUi/cardUi.style.hbs ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .{{sliceName}}Card {
4
+ display: block;
5
+ }
6
+
7
+ .content {
8
+ display: flex;
9
+ justify-content: space-between;
10
+ align-items: center;
11
+ padding: 12px;
12
+ border-radius: 8px;
13
+ border: 1px solid var(--s-accent-c);
14
+ }
15
+
16
+ .buttons {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 4px;
20
+ }
plop/templates/layers/entities/rootIndex.hbs ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ export { {{sliceName}}Card } from './ui/{{sliceName}}Card/{{sliceName}}Card';
2
+ export type { {{sliceName}}Type } from './model/types/post';
3
+ export { useFetch{{sliceName}}s } from './lib/query/useFetch{{sliceName}}s';
4
+ export { useFetch{{sliceName}}ById } from './lib/query/useFetch{{sliceName}}ById';
plop/templates/layers/entities/store/store.hbs ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { create } from 'zustand';
2
+ import { devtools } from 'zustand/middleware';
3
+ import { {{sliceName}}Schema } from '../types/{{lowerCase sliceName}}Schema';
4
+
5
+ export const use{{sliceName}}Store = create<{{sliceName}}Schema>()(
6
+ devtools((set, get) => ({
7
+ isModalActive: false,
8
+ toggleModal: () => set({ isModalActive: !get().isModalActive }),
9
+ }))
10
+ );
plop/templates/layers/entities/types/slice.hbs ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ export interface {{sliceName}}Type {
2
+ id: number;
3
+ title: string;
4
+ }
plop/templates/layers/entities/types/sliceSchema.hbs ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ export interface {{sliceName}}Schema {
2
+ isModalActive: boolean;
3
+ toggleModal: () => void;
4
+ }
plop/templates/layers/features/createUi/createUi.hbs ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { classNames } from '@/shared/lib/classNames/classNames';
2
+ import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button';
3
+ import { use{{sliceName}}Store } from '../../model/store/use{{sliceName}}Store';
4
+ import cls from './Create{{sliceName}}.module.scss';
5
+
6
+ interface Create{{sliceName}}Props {
7
+ className?: string;
8
+ }
9
+
10
+ export const Create{{sliceName}} = (props: Create{{sliceName}}Props) => {
11
+ const { className } = props;
12
+ const toggleModal = use{{sliceName}}Store((state) => state.toggleModal);
13
+ const changingEditable{{sliceName}} = use{{sliceName}}Store((state) => state.changingEditable{{sliceName}});
14
+
15
+ const openEdit{{sliceName}}Form = () => {
16
+ changingEditable{{sliceName}}(undefined);
17
+ toggleModal();
18
+ };
19
+
20
+ return (
21
+ <Button
22
+ className={classNames(cls.Create{{sliceName}}, {}, [className])}
23
+ theme={ButtonTheme.PRIMARY}
24
+ size={ButtonSize.XL}
25
+ onClick={openEdit{{sliceName}}Form}
26
+ >
27
+ Создать слайс
28
+ </Button>
29
+ );
30
+ };
plop/templates/layers/features/createUi/createUi.style.hbs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .Create{{sliceName}} {
4
+ margin-bottom: 48px;
5
+ }
plop/templates/layers/features/deleteUi/deleteUi.hbs ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { classNames } from '@/shared/lib/classNames/classNames';
2
+ import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button';
3
+ import { useDelete{{sliceName}} } from '../../lib/query/useDelete{{sliceName}}';
4
+ import cls from './Delete{{sliceName}}.module.scss';
5
+
6
+ interface Delete{{sliceName}}Props {
7
+ className?: string;
8
+ {{lowerCase sliceName}}Id: number;
9
+ }
10
+
11
+ export const Delete{{sliceName}} = (props: Delete{{sliceName}}Props) => {
12
+ const { className, {{lowerCase sliceName}}Id } = props;
13
+ const { mutate: onDelete } = useDelete{{sliceName}}();
14
+
15
+ return (
16
+ <Button
17
+ className={classNames(cls.Delete{{sliceName}}, {}, [className])}
18
+ theme={ButtonTheme.PRIMARY}
19
+ size={ButtonSize.S}
20
+ onClick={() => onDelete({
21
+ {{lowerCase sliceName}}_id: {{lowerCase sliceName}}Id
22
+ })}
23
+ >
24
+ Удалить
25
+ </Button>
26
+ );
27
+ };
plop/templates/layers/features/deleteUi/deleteUi.style.hbs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .Delete{{sliceName}} {
4
+ display: block;
5
+ }
plop/templates/layers/features/editUi/editUi.hbs ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { classNames } from '@/shared/lib/classNames/classNames';
2
+ import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button';
3
+ import { use{{sliceName}}Store } from '../../model/store/use{{sliceName}}Store';
4
+ import cls from './Edit{{sliceName}}.module.scss';
5
+
6
+ interface Edit{{sliceName}}Props {
7
+ className?: string;
8
+ {{sliceName}}Id: number;
9
+ }
10
+
11
+ export const Edit{{sliceName}} = (props: Edit{{sliceName}}Props) => {
12
+ const { className, {{sliceName}}Id } = props;
13
+ const toggleModal = use{{sliceName}}Store((state) => state.toggleModal);
14
+ const changingEditable{{sliceName}} = use{{sliceName}}Store((state) => state.changingEditable{{sliceName}});
15
+
16
+ const openEdit{{sliceName}}Form = (id: number) => {
17
+ changingEditable{{sliceName}}(id);
18
+ toggleModal();
19
+ };
20
+
21
+ return (
22
+ <Button
23
+ className={classNames(cls.Edit{{sliceName}}, {}, [className])}
24
+ theme={ButtonTheme.PRIMARY}
25
+ size={ButtonSize.S}
26
+ onClick={() => openEdit{{sliceName}}Form({{sliceName}}Id)}
27
+ >
28
+ Изменить
29
+ </Button>
30
+ );
31
+ };
plop/templates/layers/features/editUi/editUi.style.hbs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ @import '@/app/globalStyles/config/mixin.scss';
2
+
3
+ .Edit{{sliceName}} {
4
+ display: block;
5
+ }
plop/templates/layers/features/rootIndex.hbs ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ export { Create{{sliceName}} } from './ui/Create{{sliceName}}/Create{{sliceName}}';
2
+ export { Edit{{sliceName}} } from './ui/Edit{{sliceName}}/Edit{{sliceName}}';
3
+ export { use{{sliceName}}Store } from './model/store/use{{sliceName}}Store';
4
+ export { Delete{{sliceName}} } from './ui/Delete{{sliceName}}/Delete{{sliceName}}';
plop/templates/layers/features/store/store.hbs ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { create } from 'zustand';
2
+ import { devtools } from 'zustand/middleware';
3
+ import { {{sliceName}}Schema } from '../types/{{lowerCase sliceName}}Schema';
4
+
5
+ export const use{{sliceName}}Store = create<{{sliceName}}Schema>()(
6
+ devtools((set, get) => ({
7
+ isModalActive: false,
8
+ editable{{sliceName}}: undefined,
9
+ toggleModal: () => set({ isModalActive: !get().isModalActive }),
10
+ changingEditable{{sliceName}}: ({{lowerCase sliceName}}Id) => set({ editable{{sliceName}}Id: {{lowerCase sliceName}}Id }),
11
+ }))
12
+ );
plop/templates/layers/features/types/sliceSchema.hbs ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export interface {{sliceName}}Schema {
2
+ isModalActive: boolean;
3
+ editable{{sliceName}}Id?: number;
4
+ toggleModal: () => void;
5
+ changingEditable{{sliceName}}: ({{lowerCase sliceName}}Id?: number) => void;
6
+ }
plop/templates/layers/rootIndex/rootIndex.hbs ADDED
@@ -0,0 +1 @@
 
 
1
+ export { {{name}} } from './ui/{{name}}';