diff --git a/src/app.js b/src/app.js
index 1ea858c..b501391 100644
--- a/src/app.js
+++ b/src/app.js
@@ -15,6 +15,7 @@ import authServiceApi from './api/AuthServiceAPI';
import userInfoService from './services/UserInfoService';
import {EVENTS, ROUTES} from './core/consts';
import UsersPage from './pages/users/components/page/Page';
+import {DocumentationPage} from './pages/documentation/components/page/Page';
const initAppComponents = () => {
const mainMenu = new MainMenu();
@@ -40,6 +41,7 @@ const initAppComponents = () => {
{url: ROUTES.USERS, pageComponent: UsersPage},
{url: ROUTES.LOGIN, pageComponent: LoginPage},
{url: ROUTES.PROFILE, pageComponent: ProfilePage},
+ {url: ROUTES.DOCUMENTATION, pageComponent: DocumentationPage},
]);
/**
diff --git a/src/core/components/code-editor/CodeEditor.css b/src/core/components/code-editor/CodeEditor.css
new file mode 100644
index 0000000..aebd781
--- /dev/null
+++ b/src/core/components/code-editor/CodeEditor.css
@@ -0,0 +1,3 @@
+.CodeEditor__editor {
+ width: 100%;
+}
\ No newline at end of file
diff --git a/src/core/components/code-editor/CodeEditor.js b/src/core/components/code-editor/CodeEditor.js
new file mode 100644
index 0000000..957313b
--- /dev/null
+++ b/src/core/components/code-editor/CodeEditor.js
@@ -0,0 +1,43 @@
+import ace from 'ace-builds/src-noconflict/ace';
+import theme from 'ace-builds/src-noconflict/theme-github';
+import {Mode as JSONMode} from 'ace-builds/src-noconflict/mode-json';
+import Component from '../component/Component';
+import {CODE_EDITOR_MODE} from '../../consts';
+import './CodeEditor.css';
+
+const Modes = {
+ [CODE_EDITOR_MODE.JSON]: JSONMode,
+};
+
+export class CodeEditor extends Component {
+ constructor ({
+ parentNode,
+ id,
+ mode,
+ rows = 5,
+ } = {}) {
+ super('#code-editor', parentNode);
+
+ this.editorContainer = this.mainNode.querySelector('.CodeEditor__editor');
+ this.editorContainer.setAttribute('id', id);
+
+ this.editorContainer.style.minHeight = `${Math.round(rows * 24.33)}px`;
+
+ this.editor = ace.edit(id);
+ this.editor.session.setMode(new Modes[mode]());
+
+ this.editor.setTheme(theme);
+ }
+
+ setValue = (value) => {
+ this.editor.setValue(value);
+ }
+
+ getValue = () => {
+ return this.editor.getValue();
+ }
+
+ disabled = (value) => {
+ this.editor.setReadOnly(value);
+ }
+}
diff --git a/src/core/components/form-code-editor/FormCodeEditor.css b/src/core/components/form-code-editor/FormCodeEditor.css
new file mode 100644
index 0000000..dc43d93
--- /dev/null
+++ b/src/core/components/form-code-editor/FormCodeEditor.css
@@ -0,0 +1,13 @@
+.FormCodeEditor {
+ position: relative;
+}
+
+.FormCodeEditor__input {
+ position: absolute;
+ z-index: -1000;
+}
+
+.FormCodeEditor__input:invalid + .FormCodeEditor__editor {
+ border: 1px solid var(--bs-red);
+ border-radius: .25rem;
+}
\ No newline at end of file
diff --git a/src/core/components/form-code-editor/FormCodeEditor.js b/src/core/components/form-code-editor/FormCodeEditor.js
new file mode 100644
index 0000000..43035ef
--- /dev/null
+++ b/src/core/components/form-code-editor/FormCodeEditor.js
@@ -0,0 +1,69 @@
+import Component from '../component/Component';
+import {CodeEditor} from '../code-editor/CodeEditor';
+import './FormCodeEditor.css';
+import {EVENTS} from '../../consts';
+
+export class FormCodeEditor extends Component {
+ constructor (parentNode, {
+ id,
+ mode,
+ label,
+ required = false,
+ initValue = '',
+ className = '',
+ rows,
+ } = {}) {
+ super('#form-code-editor', parentNode);
+
+ this.label = this.mainNode.querySelector('.form-label');
+ this.labelText = this.mainNode.querySelector('.FormCodeEditor__label');
+ this.star = this.mainNode.querySelector('.FormCodeEditor__star');
+ this.editorContainer = this.mainNode.querySelector('.FormCodeEditor__editor');
+ this.errorText = this.mainNode.querySelector('.FormCodeEditor__errorText');
+ this.input = this.mainNode.querySelector('.FormCodeEditor__input');
+
+ this.addEventListener(this.editorContainer, EVENTS.CLICK, this.clearError);
+ this.addEventListener(this.editorContainer, EVENTS.KEYDOWN, this.clearError);
+
+ this.labelText.textContent = label;
+
+ this.editor = this.createComponent(CodeEditor, {
+ parentNode: this.editorContainer,
+ id,
+ mode,
+ rows,
+ });
+
+ if (className) {
+ this.editorContainer.classList.add(className);
+ }
+
+ if (required) {
+ this.star.textContent = ' *';
+ }
+
+ this.setValue(initValue);
+
+ }
+
+ disabled = (value) => {
+ this.editor.disabled(value);
+ }
+
+ getValue = () => {
+ return this.editor.getValue();
+ }
+
+ setValue = (value) => {
+ this.editor.setValue(value);
+ }
+
+ setError = (errorMessage) => {
+ this.errorText.textContent = errorMessage;
+ this.input.setCustomValidity(errorMessage);
+ }
+
+ clearError = () => {
+ this.setError('');
+ }
+}
diff --git a/src/core/components/form-control/FormControl.js b/src/core/components/form-control/FormControl.js
index cbf96a7..330086f 100644
--- a/src/core/components/form-control/FormControl.js
+++ b/src/core/components/form-control/FormControl.js
@@ -88,7 +88,7 @@ class FormControl extends Component {
}
clearError = () => {
- this.errorText.textContent = '';
+ this.setError('');
}
getInputTagName = (type) => {
diff --git a/src/core/components/main-menu/MainMenu.js b/src/core/components/main-menu/MainMenu.js
index cab54d9..122de39 100644
--- a/src/core/components/main-menu/MainMenu.js
+++ b/src/core/components/main-menu/MainMenu.js
@@ -22,6 +22,10 @@ const NAV_MENU = [
title: 'Пользователи',
url: ROUTES.USERS,
},
+ {
+ title: 'Документация',
+ url: ROUTES.DOCUMENTATION,
+ },
{
title: 'Личный кабинет',
url: ROUTES.PROFILE,
diff --git a/src/core/consts.js b/src/core/consts.js
index 4909547..3e65c45 100644
--- a/src/core/consts.js
+++ b/src/core/consts.js
@@ -69,4 +69,9 @@ export const ROUTES = {
USERS: '/users',
LOGIN: '/login',
PROFILE: '/profile',
+ DOCUMENTATION: '/documentation',
+};
+
+export const CODE_EDITOR_MODE = {
+ JSON: 'json',
};
diff --git a/src/pages/documentation/components/page/Page.js b/src/pages/documentation/components/page/Page.js
new file mode 100644
index 0000000..9a412d1
--- /dev/null
+++ b/src/pages/documentation/components/page/Page.js
@@ -0,0 +1,16 @@
+import Component from '../../../../core/components/component/Component';
+import {TAG_NAME} from '../../../../core/consts';
+
+export class DocumentationPage extends Component {
+ constructor (mainNodeSelector, parentNode) {
+ super(mainNodeSelector, parentNode);
+
+ this.createElement({
+ tagName: TAG_NAME.DIV,
+ parentNode: this.mainNode,
+ options: {
+ textContent: 'Документация',
+ },
+ });
+ }
+}
diff --git a/src/pages/storages/components/api-table-view-form/ApiTableViewForm.css b/src/pages/storages/components/api-table-view-form/ApiTableViewForm.css
index 50e5e9d..b33a859 100644
--- a/src/pages/storages/components/api-table-view-form/ApiTableViewForm.css
+++ b/src/pages/storages/components/api-table-view-form/ApiTableViewForm.css
@@ -1,6 +1,3 @@
-.Api__value-input {
- height: 200px;
-}
.Api__view-controls {
position: sticky;
bottom: 0;
diff --git a/src/pages/storages/components/api-table-view-form/ApiTableViewForm.js b/src/pages/storages/components/api-table-view-form/ApiTableViewForm.js
index 245d98d..a24a499 100644
--- a/src/pages/storages/components/api-table-view-form/ApiTableViewForm.js
+++ b/src/pages/storages/components/api-table-view-form/ApiTableViewForm.js
@@ -1,11 +1,12 @@
import Component from '../../../../core/components/component/Component';
import ModalSidebar from '../../../../core/components/modal-sidebar/ModalSibebar';
import FormControl from '../../../../core/components/form-control/FormControl';
-import {FORM_TYPES, EVENTS, MODES} from '../../../../core/consts';
+import {EVENTS, MODES, CODE_EDITOR_MODE} from '../../../../core/consts';
import './ApiTableViewForm.css';
import storageApi from '../../api/StorageServiceAPI';
import routeService from '../../../../services/RouteService';
import {HooksComponent} from '../hooks-component/HooksComponent';
+import {FormCodeEditor} from '../../../../core/components/form-code-editor/FormCodeEditor';
const TITLE_MODES = {
[MODES.Create]: 'Создание нового хранилища',
@@ -52,11 +53,11 @@ class ApiTableViewForm extends Component {
label: 'Краткое описание',
required: true,
}),
- this.valueInput = this.createComponent(FormControl, this.form, {
+ this.valueInput = this.createComponent(FormCodeEditor, this.form, {
id: 'api-value-input',
- type: FORM_TYPES.TEXTAREA,
className: 'Api__value-input',
label: 'Содержимое хранилища',
+ mode: CODE_EDITOR_MODE.JSON,
required: true,
}),
];