diff --git a/.eslintrc.json b/.eslintrc.json
index 9061692da..165b37538 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -15,6 +15,14 @@
"no-console": 0,
"import/extensions": 0,
"quotes": 0,
- "semi": 0
+ "semi": 0,
+ "no-underscore-dangle": 0,
+ "no-tabs": 0,
+ "lines-between-class-members": 0,
+ "class-methods-use-this": 0,
+ "no-undef": 0,
+ "no-param-reassign": 0,
+ "import/prefer-default-export": 0,
+ "import/no-extraneous-dependencies": 0
}
}
diff --git a/.stylelintrc.json b/.stylelintrc.json
index eff256099..5d5ff9fcf 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,3 +1,4 @@
{
- "extends": "stylelint-config-standard-scss"
+ "extends": "stylelint-config-standard-scss",
+ "ignoreFiles": ["build/*", "node_modules/*", "static/*"]
}
diff --git a/_proxyProps.js b/_proxyProps.js
deleted file mode 100644
index d28d8bbac..000000000
--- a/_proxyProps.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const props = {
- name: 'Abby',
- chat: 'the last of us. Part II',
- getChat() {
- this._privateMethod();
- },
- _privateMethod() {
- console.log(this._privateProp);
- },
- __privateMethodToo() {},
- _privateProp: 'Нельзя получить просто так',
-};
-
-const proxyProps = new Proxy(props, {
- get(o, name) {
- if (name.search('_') !== -1) {
- // console.log('Нет прав');
- // return false;
- }
-
- return o[name];
- // return o[name];
- },
- set(o, name, newValue) {
- if (name.search('_') !== -1) {
- throw new Error('Нет прав');
- }
-
- o[name] = newValue;
-
- return true;
- },
- deleteProperty(o, name) {
- if (name.search('_') !== -1) {
- throw new Error('Нет прав');
- }
-
- return true;
- },
-});
-
-// proxyProps.getChat();
-// delete proxyProps.chat;
-
-// proxyProps.newProp = 2;
-// console.log(proxyProps.newProp);
-
-try {
- proxyProps._newPrivateProp = 'Super game';
-} catch (error) {
- console.log(error);
-}
-
-console.log(props);
-
-// try {
-// delete proxyProps._privateProp;
-// } catch (error) {
-// console.log(error); // Error: Нет прав
-// }
-
-/*
- * Вывод в консоль следующий:
-Нельзя получить просто так
-2
-Error: Нет прав
-Error: Нет прав
-*/
diff --git a/package-lock.json b/package-lock.json
index 2b92ab99c..5a0c0ac7a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,11 +8,13 @@
"name": "messenger",
"version": "0.0.0",
"dependencies": {
- "pug": "^3.0.2"
+ "pug": "^3.0.2",
+ "uuid": "^9.0.1"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/pug": "^2.0.6",
+ "@types/uuid": "^9.0.4",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
"concurrently": "^8.2.1",
@@ -22,7 +24,6 @@
"sass": "^1.66.1",
"stylelint": "^15.10.3",
"stylelint-config-standard-scss": "^11.0.0",
- "uuid": "^9.0.1",
"vite": "^4.4.5"
},
"engines": {
@@ -1069,6 +1070,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/uuid": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz",
+ "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==",
+ "dev": true
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz",
@@ -6448,7 +6455,6 @@
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
- "dev": true,
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
@@ -7409,6 +7415,12 @@
"@types/node": "*"
}
},
+ "@types/uuid": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz",
+ "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==",
+ "dev": true
+ },
"@typescript-eslint/eslint-plugin": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz",
@@ -11360,8 +11372,7 @@
"uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
- "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
- "dev": true
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
},
"validate-npm-package-license": {
"version": "3.0.4",
diff --git a/package.json b/package.json
index 93d1234a9..3b0406ca9 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"devDependencies": {
"@types/express": "^4.17.17",
"@types/pug": "^2.0.6",
+ "@types/uuid": "^9.0.4",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
"concurrently": "^8.2.1",
@@ -25,10 +26,10 @@
"sass": "^1.66.1",
"stylelint": "^15.10.3",
"stylelint-config-standard-scss": "^11.0.0",
- "uuid": "^9.0.1",
"vite": "^4.4.5"
},
"dependencies": {
- "pug": "^3.0.2"
+ "pug": "^3.0.2",
+ "uuid": "^9.0.1"
}
}
diff --git a/src/404/404.ts b/src/404/404.ts
new file mode 100644
index 000000000..2433ffdea
--- /dev/null
+++ b/src/404/404.ts
@@ -0,0 +1,15 @@
+import { render } from "../utils/index";
+import { ErrorPage } from "../pages/index";
+
+import "../scss/index.scss";
+
+const props = {
+ title: '404',
+ text: 'who seeks will always find',
+ linkText: 'go to chats page',
+ linkHref: '/chats-and-chat/',
+}
+
+const page = new ErrorPage(props);
+
+render(page);
diff --git a/src/404/index.html b/src/404/index.html
new file mode 100644
index 000000000..cb37bcf87
--- /dev/null
+++ b/src/404/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ 404 page
+
+
+
+
+
+
diff --git a/src/500/500.ts b/src/500/500.ts
new file mode 100644
index 000000000..4b36001e8
--- /dev/null
+++ b/src/500/500.ts
@@ -0,0 +1,15 @@
+import { render } from "../utils/index";
+import { ErrorPage } from "../pages/index";
+
+import "../scss/index.scss";
+
+const props = {
+ title: '500',
+ text: 'something went wrong',
+ linkText: 'go to chats page',
+ linkHref: '/chats-and-chat/',
+}
+
+const page = new ErrorPage(props);
+
+render(page);
diff --git a/src/500/index.html b/src/500/index.html
new file mode 100644
index 000000000..96bda3a4c
--- /dev/null
+++ b/src/500/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ 500 page
+
+
+
+
+
+
diff --git a/src/chats-and-chat/chats-and-chat.ts b/src/chats-and-chat/chats-and-chat.ts
new file mode 100644
index 000000000..2db5caf47
--- /dev/null
+++ b/src/chats-and-chat/chats-and-chat.ts
@@ -0,0 +1,8 @@
+import { render } from "../utils/index";
+import { ChatsAndChat } from "../pages/index";
+
+import "../scss/index.scss";
+
+const page = new ChatsAndChat();
+
+render(page);
diff --git a/src/chats-and-chat/index.html b/src/chats-and-chat/index.html
new file mode 100644
index 000000000..9955f2bb3
--- /dev/null
+++ b/src/chats-and-chat/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Chats and chat page
+
+
+
+
+
+
diff --git a/src/components/AuthorizationForm/AuthorizationForm.tmp.pug b/src/components/AuthorizationForm/AuthorizationForm.tmp.pug
new file mode 100644
index 000000000..034d78a4b
--- /dev/null
+++ b/src/components/AuthorizationForm/AuthorizationForm.tmp.pug
@@ -0,0 +1,7 @@
+form.form
+ if (title)
+ h1.form__title= title
+ .form__field!= fieldLogin
+ .form__field!= fieldPassword
+ .form__field.form__field--accent!= sendBtn
+ .form__field.t-right!= link
diff --git a/src/components/AuthorizationForm/AuthorizationForm.ts b/src/components/AuthorizationForm/AuthorizationForm.ts
new file mode 100644
index 000000000..346ae2484
--- /dev/null
+++ b/src/components/AuthorizationForm/AuthorizationForm.ts
@@ -0,0 +1,20 @@
+import { Block } from "../../core/index";
+import template from "./AuthorizationForm.tmp.pug";
+import { getValuesFromForm } from "../utils/index";
+
+export default class AuthorizationForm extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ events: new Map([
+ ['submit', (event: object) => getValuesFromForm(event, this)],
+ ]),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/components/Button/Button.tmp.pug b/src/components/Button/Button.tmp.pug
index bd2c8044a..05c97b708 100644
--- a/src/components/Button/Button.tmp.pug
+++ b/src/components/Button/Button.tmp.pug
@@ -1 +1 @@
-button.btn text
+button(class=className, type=type, form=form)= text
diff --git a/src/components/Button/Button.ts b/src/components/Button/Button.ts
index c3ad80a4a..a4c786a57 100644
--- a/src/components/Button/Button.ts
+++ b/src/components/Button/Button.ts
@@ -1,9 +1,11 @@
import { Block } from "../../core/index";
import template from "./Button.tmp.pug";
+import "./Button.scss";
+
export default class Button extends Block {
- constructor(props) {
- super('button', props);
+ constructor(props?: object) {
+ super('div', props);
}
render() {
diff --git a/src/components/EditingPasswordForm/EditingPasswordForm.tmp.pug b/src/components/EditingPasswordForm/EditingPasswordForm.tmp.pug
new file mode 100644
index 000000000..c99ac1ada
--- /dev/null
+++ b/src/components/EditingPasswordForm/EditingPasswordForm.tmp.pug
@@ -0,0 +1,5 @@
+form#userSettingsForm.user-settings__form
+ ul.user-settings__list
+ li.user-settings__list-item!= currentPassword
+ li.user-settings__list-item!= newPassword
+ li.user-settings__list-item!= repeatNewPassword
diff --git a/src/components/EditingPasswordForm/EditingPasswordForm.ts b/src/components/EditingPasswordForm/EditingPasswordForm.ts
new file mode 100644
index 000000000..facbb6277
--- /dev/null
+++ b/src/components/EditingPasswordForm/EditingPasswordForm.ts
@@ -0,0 +1,20 @@
+import { Block } from "../../core/index";
+import template from "./EditingPasswordForm.tmp.pug";
+import { getValuesFromForm } from "../utils/index";
+
+export default class EditingPasswordForm extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ events: new Map([
+ ['submit', (event: object) => getValuesFromForm(event, this)],
+ ]),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/components/EditingSettingsForm/EditingSettingsForm.tmp.pug b/src/components/EditingSettingsForm/EditingSettingsForm.tmp.pug
new file mode 100644
index 000000000..63528fb32
--- /dev/null
+++ b/src/components/EditingSettingsForm/EditingSettingsForm.tmp.pug
@@ -0,0 +1,25 @@
+form#userSettingsForm.user-settings__form
+ ul.user-settings__list
+ li.user-settings__list-item!= nickname
+ li.user-settings__list-item!= firstName
+ li.user-settings__list-item!= secondName
+ li.user-settings__list-item!= email
+ li.user-settings__list-item!= phone
+
+ //ul.user-settings__list
+ li.user-settings__list-item
+ label.user-settings__list-item-name(for="display_name") Nickname:
+ input.user-settings__list-item-value.t-right(id="display_name" type="text" name="display_name" value="user name")
+ li.user-settings__list-item
+ label.user-settings__list-item-name(for="first_name") First name:
+ input.user-settings__list-item-value.t-right(id="first_name" type="text" name="first_name" value="first name")
+ li.user-settings__list-item
+ label.user-settings__list-item-name(for="second_name") Second name:
+ input.user-settings__list-item-value.t-right(id="second_name" type="text" name="second_name" value="second name")
+ li.user-settings__list-item
+ label.user-settings__list-item-name(for="email") Email:
+ input.user-settings__list-item-value.t-right(id="email" type="text" name="email" value="test@test.ru")
+ li.user-settings__list-item
+ label.user-settings__list-item-name(for="phone") Phone:
+ input.user-settings__list-item-value.t-right(id="phone" type="text" name="phone" value="+7 (000) 000-00-00")
+ //input(type="file", name="avatar", hidden)
diff --git a/src/components/EditingSettingsForm/EditingSettingsForm.ts b/src/components/EditingSettingsForm/EditingSettingsForm.ts
new file mode 100644
index 000000000..199368c04
--- /dev/null
+++ b/src/components/EditingSettingsForm/EditingSettingsForm.ts
@@ -0,0 +1,20 @@
+import { Block } from "../../core/index";
+import template from "./EditingSettingsForm.tmp.pug";
+import { getValuesFromForm } from "../utils/index";
+
+export default class EditingSettingsForm extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ events: new Map([
+ ['submit', (event: object) => getValuesFromForm(event, this)],
+ ]),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/components/field-text/field-text.scss b/src/components/FieldText/FieldText.scss
similarity index 72%
rename from src/components/field-text/field-text.scss
rename to src/components/FieldText/FieldText.scss
index 27435d690..23ff0d704 100644
--- a/src/components/field-text/field-text.scss
+++ b/src/components/FieldText/FieldText.scss
@@ -24,6 +24,10 @@
}
&__help-text {
+ display: none;
+ margin-top: 8px;
+ font-size: 12px;
+ color: #333;
}
&--white {
@@ -44,4 +48,15 @@
border-radius: 50px;
}
}
+
+ &--invalid {
+ #{$block-name}__input {
+ box-shadow: var(--on-error);
+ color: tomato;
+ }
+
+ #{$block-name}__help-text {
+ display: block;
+ }
+ }
}
diff --git a/src/components/FieldText/FieldText.tmp.pug b/src/components/FieldText/FieldText.tmp.pug
new file mode 100644
index 000000000..1523c9432
--- /dev/null
+++ b/src/components/FieldText/FieldText.tmp.pug
@@ -0,0 +1,7 @@
+label.field-text(class=mods)
+ if(typeof(title) !== 'undefined' && title)
+ span.field-text__name= title
+ span.field-text__input-wrap
+ input.field-text__input(type=type, name=name, value=value, data-pattern=pattern placeholder=placeholder, autocomplete="off")
+ if(typeof(helpText) !== 'undefined' && helpText)
+ span.field-text__help-text= helpText
diff --git a/src/components/FieldText/FieldText.ts b/src/components/FieldText/FieldText.ts
new file mode 100644
index 000000000..b0b0f5e0e
--- /dev/null
+++ b/src/components/FieldText/FieldText.ts
@@ -0,0 +1,34 @@
+import { Block } from "../../core/index";
+import template from "./FieldText.tmp.pug";
+import templateSetting from "./FieldTextSetting.tmp.pug";
+import { validateField } from "../utils/index";
+
+import "./FieldText.scss";
+
+export default class FieldText extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ events: new Map([
+ ['blur', validateField],
+ ]),
+ }
+
+ super('div', newProps);
+ }
+
+ public value() {
+ return this.element.querySelector('input').value;
+ }
+
+ public validate() {
+ const input = this.element.querySelector('input');
+ validateField(input);
+ }
+
+ render() {
+ const isSettingTmp = this.props.tmp;
+
+ return this.compile(isSettingTmp ? templateSetting : template, this.props);
+ }
+}
diff --git a/src/components/FieldText/FieldTextSetting.tmp.pug b/src/components/FieldText/FieldTextSetting.tmp.pug
new file mode 100644
index 000000000..8ecad9bd5
--- /dev/null
+++ b/src/components/FieldText/FieldTextSetting.tmp.pug
@@ -0,0 +1,6 @@
+.field-text
+ if(typeof(title) !== 'undefined' && title)
+ label.user-settings__list-item-name(for=name)= title
+ input.user-settings__list-item-value.t-right(id=name, type=type, name=name, value=value, data-pattern=pattern, placeholder=placeholder)
+ if(typeof(helpText) !== 'undefined' && helpText)
+ span.field-text__help-text= helpText
diff --git a/src/components/Link/Link.tmp.pug b/src/components/Link/Link.tmp.pug
new file mode 100644
index 000000000..205d5c9ba
--- /dev/null
+++ b/src/components/Link/Link.tmp.pug
@@ -0,0 +1 @@
+a.link(class=className, href=href)= text
diff --git a/src/components/Link/Link.ts b/src/components/Link/Link.ts
new file mode 100644
index 000000000..b63fcbc4d
--- /dev/null
+++ b/src/components/Link/Link.ts
@@ -0,0 +1,12 @@
+import { Block } from "../../core/index";
+import template from "./Link.tmp.pug";
+
+export default class Link extends Block {
+ constructor(props?: object) {
+ super('div', props);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/components/RegistrationForm/RegistrationForm.tmp.pug b/src/components/RegistrationForm/RegistrationForm.tmp.pug
new file mode 100644
index 000000000..0448cc793
--- /dev/null
+++ b/src/components/RegistrationForm/RegistrationForm.tmp.pug
@@ -0,0 +1,11 @@
+form.form
+ if (title)
+ h1.form__title= title
+ .form__field!= fieldFirstName
+ .form__field!= fieldSecondName
+ .form__field!= fieldEmail
+ .form__field!= fieldPhone
+ .form__field!= fieldLogin
+ .form__field!= fieldPassword
+ .form__field.form__field--accent!= sendBtn
+ .form__field.t-right!= link
diff --git a/src/components/RegistrationForm/RegistrationForm.ts b/src/components/RegistrationForm/RegistrationForm.ts
new file mode 100644
index 000000000..7979493bc
--- /dev/null
+++ b/src/components/RegistrationForm/RegistrationForm.ts
@@ -0,0 +1,20 @@
+import { Block } from "../../core/index";
+import template from "./RegistrationForm.tmp.pug";
+import { getValuesFromForm } from "../utils/index";
+
+export default class RegistrationForm extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ events: new Map([
+ ['submit', (event: object) => getValuesFromForm(event, this)],
+ ]),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/components/field-text/field-text.pug b/src/components/field-text/field-text.pug
deleted file mode 100644
index 23345c704..000000000
--- a/src/components/field-text/field-text.pug
+++ /dev/null
@@ -1,47 +0,0 @@
-mixin field-text(props)
-
- //- Принимает:
- //- props {
- //- title: '' {string} - текст с названием (выводится над полем)
- //- isTextarea: false {bool} - флаг input/textarea
- //- helpText: '' {string} - пояснение под полем
- //- mods: '' {string} - модификаторы блока
- //- val: '' {string} - текст в поле
- //- attrs: {object} - любые атрибуты для input/textarea
- //- type: {string}
- //- placeholder: {string}
- //- Вызов:
- +field-text({
- title: 'Название',
- isTextarea: true,
- helpText: 'Подсказка',
- mods: '',
- val: '',
- attrs: {
- name: 'comment',
- }
- })
-
- -
- if(typeof(props) === 'undefined') {
- var props = {};
- }
- var allMods = '';
- if(typeof(props.mods) !== 'undefined' && props.mods) {
- var modsList = props.mods.split(',');
- for (var i = 0; i < modsList.length; i++) {
- allMods = allMods + ' field-text--' + modsList[i].trim();
- }
- }
-
- label.field-text(class=allMods)&attributes(attributes)
- if(typeof(props.title) !== 'undefined' && props.title)
- span.field-text__name!= props.title
- span.field-text__input-wrap
- if(typeof(props.isTextarea) !== 'undefined' && props.isTextarea)
- textarea.field-text__input&attributes(props.attrs)= props.val
- else
- input.field-text__input(type=(typeof(props.attrs) !== 'undefined' && props.attrs.type) ? props.attrs.type : 'text', value=props.val)&attributes(props.attrs)
- if(typeof(props.helpText) !== 'undefined' && props.helpText)
- span.field-text__help-text!= props.helpText
- block
diff --git a/src/components/form/form.pug b/src/components/form/form.pug
deleted file mode 100644
index a3c425577..000000000
--- a/src/components/form/form.pug
+++ /dev/null
@@ -1,45 +0,0 @@
-mixin form(title, mods)
-
- //- Принимает:
- //- title {string} - form title
- //- mods {string} - список модификаторов
- //- Вызов:
- +form('title', 'mods')
- +form-field()
- some html
- +form-field()
- some html
-
- -
- var allMods = '';
- if(typeof(mods) !== 'undefined' && mods) {
- var modsList = mods.split(',');
- for (var i = 0; i < modsList.length; i++) {
- allMods = allMods + ' form--' + modsList[i].trim();
- }
- }
-
- form.form(class=allMods)&attributes(attributes)
- if (title)
- h1.form__title= title
- block
-
-mixin form-field(mods)
-
- //- Принимает:
- //- mods {string} - список модификаторов
- //- Вызов:
- +form-field()
- some html
-
- -
- var allMods = '';
- if(typeof(mods) !== 'undefined' && mods) {
- var modsList = mods.split(',');
- for (var i = 0; i < modsList.length; i++) {
- allMods = allMods + ' form__field--' + modsList[i].trim();
- }
- }
-
- .form__field(class=allMods)&attributes(attributes)
- block
diff --git a/src/components/form/form.scss b/src/components/form/form.scss
deleted file mode 100644
index c6c755485..000000000
--- a/src/components/form/form.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-.form {
- $block-name: &;
-
- margin-left: auto;
- margin-right: auto;
- padding: 50px;
- width: 400px;
- max-width: 100%;
- border-radius: var(--b-radius);
- background-color: var(--bg-whiteSmoke);
-
- &__title {
- margin-bottom: 70px;
- font-size: 35px;
- font-weight: 500;
- text-align: center;
- }
-
- &__field {
- & + & {
- margin-top: 20px;
- }
-
- & + &--accent {
- margin-top: 40px;
- }
- }
-}
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 000000000..bfd40e712
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,17 @@
+import AuthorizationForm from "./AuthorizationForm/AuthorizationForm";
+import RegistrationForm from "./RegistrationForm/RegistrationForm";
+import EditingSettingsForm from "./EditingSettingsForm/EditingSettingsForm"
+import EditingPasswordForm from "./EditingPasswordForm/EditingPasswordForm";
+import FieldText from "./FieldText/FieldText";
+import Button from "./Button/Button";
+import Link from "./Link/Link";
+
+export {
+ AuthorizationForm,
+ RegistrationForm,
+ EditingSettingsForm,
+ EditingPasswordForm,
+ FieldText,
+ Button,
+ Link,
+}
diff --git a/src/components/utils/getValuesFromForm.ts b/src/components/utils/getValuesFromForm.ts
new file mode 100644
index 000000000..973d954b4
--- /dev/null
+++ b/src/components/utils/getValuesFromForm.ts
@@ -0,0 +1,21 @@
+type Event = {
+ preventDefault: Function
+}
+
+type Instance = {
+ children: PropertyKey,
+}
+
+export default function getValuesFromForm(event: Event, instance: Instance) {
+ event.preventDefault();
+ const formValues: Record = {};
+
+ Object.entries(instance.children).forEach(([name, child]: [string, any]) => {
+ if (child.value) {
+ formValues[name] = child.value();
+ child.validate();
+ }
+ })
+
+ console.log(formValues);
+}
diff --git a/src/components/utils/index.ts b/src/components/utils/index.ts
new file mode 100644
index 000000000..4674dd817
--- /dev/null
+++ b/src/components/utils/index.ts
@@ -0,0 +1,7 @@
+import validateField from "./validateField";
+import getValuesFromForm from "./getValuesFromForm";
+
+export {
+ validateField,
+ getValuesFromForm,
+};
diff --git a/src/components/utils/validateField.ts b/src/components/utils/validateField.ts
new file mode 100644
index 000000000..e7290dbc4
--- /dev/null
+++ b/src/components/utils/validateField.ts
@@ -0,0 +1,33 @@
+interface DOMStringMap {
+ [name: string]: string | undefined
+}
+
+interface HTMLInputElement {
+ value: string,
+ dataset: DOMStringMap,
+ closest: Function,
+}
+
+interface EventTarget {
+ target: HTMLInputElement,
+}
+
+export default function validateField(event: EventTarget): void {
+ const input = event.target || event;
+ const { value } = input;
+ const { pattern } = input.dataset;
+
+ if (!pattern) {
+ return;
+ }
+
+ const parent = input.closest('.field-text');
+ const errClass = 'field-text--invalid';
+ const regExp = new RegExp(pattern, 'g');
+
+ if (!regExp.test(value)) {
+ parent?.classList.add(errClass);
+ } else {
+ parent?.classList.remove(errClass);
+ }
+}
diff --git a/src/core/Block.js b/src/core/Block.js
deleted file mode 100644
index 779eb2815..000000000
--- a/src/core/Block.js
+++ /dev/null
@@ -1,217 +0,0 @@
-/* eslint-disable */
-
-import EventBus from "./EventBus";
-import { v4 as uuid } from "uuid";
-
-export default class Block {
- static EVENTS = {
- INIT: "init",
- FLOW_CDM: "flow:component-did-mount",
- FLOW_CDU: "flow:component-did-update",
- FLOW_RENDER: "flow:render",
- };
-
- _element = null;
- _meta = null;
- _id = null;
-
- constructor(tagName = "div", propsAndChildren = {}) {
- const { children, props } = this._getChildren(propsAndChildren);
- const eventBus = new EventBus();
-
- this.children = children;
- this._meta = {
- tagName,
- props,
- };
-
- if (props.withId) {
- this._id = uuid();
- this.props = this._makePropsProxy({...props, __id: this._id});
- } else {
- this.props = this._makePropsProxy(props);
- }
-
- this.eventBus = () => eventBus;
- this._registerEvents(eventBus);
-
- eventBus.emit(Block.EVENTS.INIT);
- }
-
- _registerEvents(eventBus) {
- eventBus.on(Block.EVENTS.INIT, this.init.bind(this));
- eventBus.on(Block.EVENTS.FLOW_CDM, this._componentDidMount.bind(this));
- eventBus.on(Block.EVENTS.FLOW_CDU, this._componentDidUpdate.bind(this));
- eventBus.on(Block.EVENTS.FLOW_RENDER, this._render.bind(this));
- }
-
- _unregisterEvents(eventBus) {
- eventBus.off(Block.EVENTS.INIT, this.init.bind(this));
- eventBus.off(Block.EVENTS.FLOW_CDM, this._componentDidMount.bind(this));
- eventBus.off(Block.EVENTS.FLOW_CDU, this._componentDidUpdate.bind(this));
- eventBus.off(Block.EVENTS.FLOW_RENDER, this._render.bind(this));
- }
-
- _getChildren(propsAndChildren) {
- const children = {};
- const props = {};
-
- Object.entries(propsAndChildren).forEach(([key, value]) => {
- if (value instanceof Block) {
- children[key] = value;
- } else {
- props[key] = value;
- }
- })
-
- return { children, props };
- }
-
- init() {
- console.log('init');
- this._createResources();
- this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
- }
-
- _createResources() {
- const { tagName } = this._meta;
- this._element = this._createDocumentElement(tagName);
- }
-
- _createDocumentElement(tagName) {
- const element = document.createElement(tagName);
- if (this._id) {
- element.dataset.id = this._id;
- }
-
- return element;
- }
-
- _componentDidMount() {
- console.log('_componentDidMount');
- this.componentDidMount();
- // this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
- }
-
- // Может переопределять пользователь, необязательно трогать
- componentDidMount(oldProps) {
- console.log('componentDidMount');
-
- dispatchComponentDidMoun();
- }
-
- dispatchComponentDidMoun() {
- console.log('dispatchComponentDidMoun');
- this.eventBus().emit(Block.EVENTS.FLOW_CDM);
- }
-
- _componentDidUpdate(oldProps, newProps) {
- console.log('_componentDidUpdate');
- const response = this.componentDidUpdate(oldProps, newProps);
- }
-
- // Может переопределять пользователь, необязательно трогать
- componentDidUpdate(oldProps, newProps) {
- console.log('componentDidUpdate');
- console.log(oldProps);
- console.log(newProps);
- // this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
- // return true;
-
-
- if (true) {
- return true;
- }
-
- return false;
- }
-
- setProps = newProps => {
- console.log('setProps');
- if (!newProps) {
- return;
- }
-
- // this.eventBus().emit(Block.EVENTS.FLOW_CDU, this.props, newProps);
- // Object.assign(this.props, newProps);
- // this.eventBus().emit(Block.EVENTS.FLOW_CDU);
- };
-
- get element() {
- return this._element;
- }
-
- _render() {
- const block = this.render();
-
- this._removeEvents();
-
- this._element.innerHTML = block;
-
- this._addEvents();
- }
-
- // Может переопределять пользователь, необязательно трогать
- render() {
- console.log('render');
- }
-
- compile(template, props) {
- const propsAndStubs = {...props};
-
- Object.entries(this.children).forEach(([key, child]) => {
- propsAndStubs[key] = ``;
- })
-
- console.log(propsAndStubs);
-
- return template(propsAndStubs);
- }
-
- _addEvents() {
- const {events = new Map()} = this.props;
-
- events.forEach((eventFun, eventName) => {
- this._element.addEventListener(eventName, eventFun);
- })
- }
-
- _removeEvents() {
- const {events = new Map()} = this.props;
-
- events.forEach((eventFun, eventName) => {
- this._element.removeEventListener(eventName, eventFun);
- })
- }
-
- getContent() {
- return this.element;
- }
-
- _makePropsProxy(props) {
- // Можно и так передать this
- // Такой способ больше не применяется с приходом ES6+
- const self = this;
- const proxyProps = new Proxy(props, {
- set(target, prop, newValue) {
- if (prop.indexOf('_') === 0) {
- throw new Error('Permission denied');
- }
-
- target[prop] = newValue;
- self.eventBus().emit(Block.EVENTS.FLOW_CDU);
-
- return true;
- },
- deleteProperty() {
- throw new Error('Permission denied');
- },
- })
-
- return proxyProps;
- }
-
- show() {}
-
- hide() {}
-}
diff --git a/src/core/Block.ts b/src/core/Block.ts
new file mode 100644
index 000000000..3ee89534b
--- /dev/null
+++ b/src/core/Block.ts
@@ -0,0 +1,228 @@
+import { v4 as uuid } from "uuid";
+import EventBus from "./EventBus";
+
+// использую any, потому что не получилось типизировать по хорошему,
+// а время на исходе)
+
+export default class Block {
+ children: any;
+ props: any;
+ eventBus: () => EventBus;
+
+ static EVENTS = {
+ INIT: "init",
+ FLOW_CDM: "flow:component-did-mount",
+ FLOW_CDU: "flow:component-did-update",
+ FLOW_RENDER: "flow:render",
+ };
+
+ _element: any = null;
+ _meta: any = null;
+ _id: any = null;
+
+ constructor(tagName = "div", propsAndChildren = {}) {
+ const { children, props } = this._getChildren(propsAndChildren);
+ const eventBus = new EventBus();
+
+ this.children = children;
+
+ this._meta = {
+ tagName,
+ props,
+ };
+
+ if (props.withId) {
+ this._id = uuid();
+ this.props = this._makePropsProxy({ ...props, __id: this._id });
+ } else {
+ this.props = this._makePropsProxy(props);
+ }
+
+ this.eventBus = () => eventBus;
+
+ this._registerEvents(eventBus);
+
+ eventBus.emit(Block.EVENTS.INIT);
+ }
+
+ _registerEvents(eventBus: EventBus) {
+ eventBus.on(Block.EVENTS.INIT, this.init.bind(this));
+ eventBus.on(Block.EVENTS.FLOW_CDM, this._componentDidMount.bind(this));
+ eventBus.on(Block.EVENTS.FLOW_CDU, this._componentDidUpdate.bind(this));
+ eventBus.on(Block.EVENTS.FLOW_RENDER, this._render.bind(this));
+ }
+
+ _getChildren(propsAndChildren: any) {
+ const children: any = {};
+ const props: any = {};
+
+ Object.entries(propsAndChildren).forEach(([key, value]) => {
+ if (value instanceof Block) {
+ children[key] = value;
+ } else {
+ props[key] = value;
+ }
+ })
+
+ return { children, props };
+ }
+
+ init() {
+ this._createResources();
+ this.eventBus().emit(Block.EVENTS.FLOW_RENDER);
+ }
+
+ _createResources() {
+ const { tagName } = this._meta;
+ this._element = this._createDocumentElement(tagName);
+ }
+
+ _createDocumentElement(tagName: string): any {
+ const element = document.createElement(tagName);
+ if (this._id) {
+ element.dataset.id = this._id;
+ }
+
+ return element;
+ }
+
+ _componentDidMount() {
+ this.componentDidMount();
+
+ Object.values(this.children).forEach((child: any) => {
+ child.dispatchComponentDidMount();
+ });
+ }
+
+ // Может переопределять пользователь, необязательно трогать
+ componentDidMount(oldProps?: any) {
+ console.log(oldProps);
+ }
+
+ dispatchComponentDidMount() {}
+
+ setProps = (newProps: any) => {
+ if (!newProps) {
+ return;
+ }
+
+ this._componentDidUpdate(this.props, newProps);
+ // this.eventBus().emit(Block.EVENTS.FLOW_CDU, this.props, newProps);
+ // Object.assign(this.props, newProps);
+ // this.eventBus().emit(Block.EVENTS.FLOW_CDU);
+ };
+
+ _componentDidUpdate(oldProps: any, newProps: any) {
+ const response = this.componentDidUpdate(oldProps, newProps);
+
+ if (response) {
+ Object.assign(oldProps, newProps);
+ }
+ }
+
+ // Может переопределять пользователь, необязательно трогать
+ componentDidUpdate(oldProps: any, newProps: any) {
+ let update = false;
+ Object.keys(newProps).forEach((key) => {
+ if (oldProps[key] !== newProps[key]) {
+ update = true;
+ }
+ })
+
+ return update;
+ }
+
+ _render() {
+ const block = this.render();
+
+ this._removeEvents();
+ this._element.innerHTML = '';
+
+ this._element.appendChild(block);
+ this._addEvents();
+ }
+
+ // Может переопределять пользователь, необязательно трогать
+ render(): any {}
+
+ compile(template: Function, props: any) {
+ if (this.children) {
+ const propsAndStubs = { ...props };
+
+ Object.entries(this.children).forEach(([key, child]: [string, any]) => {
+ propsAndStubs[key] = ``;
+ })
+
+ const fragment = this._createDocumentElement('template');
+ fragment.innerHTML = template(propsAndStubs);
+
+ Object.values(this.children).forEach((child: any) => {
+ const stub = fragment.content.querySelector(`[data-id="${child._id}"]`);
+ stub.replaceWith(child.getContent());
+ });
+
+ return fragment.content;
+ }
+
+ return template(props);
+ }
+
+ _addEvents() {
+ const { events = new Map() } = this.props;
+
+ events.forEach((eventFun: Function, eventName: string) => {
+ if (eventName === 'blur') {
+ this._element.querySelector('input')?.addEventListener(eventName, eventFun);
+ } else {
+ this._element.addEventListener(eventName, eventFun);
+ }
+ })
+ }
+
+ _removeEvents() {
+ const { events = new Map() } = this.props;
+
+ events.forEach((eventFun: Function, eventName: string) => {
+ if (eventName === 'blur') {
+ this._element.querySelector('input')?.removeEventListener(eventName, eventFun);
+ } else {
+ this._element.removeEventListener(eventName, eventFun);
+ }
+
+ // if (eventName === 'submit') {
+ // this._element.querySelector('form')?.removeEventListener(eventName, eventFun);
+ // } else {
+ // this._element.removeEventListener(eventName, eventFun);
+ // }
+ })
+ }
+
+ getContent() {
+ return this.element;
+ }
+
+ get element() {
+ return this._element;
+ }
+
+ _makePropsProxy(props: any) {
+ const self = this;
+ const proxyProps = new Proxy(props, {
+ set(target: any, prop: string, newValue) {
+ if (prop.indexOf('_') === 0) {
+ throw new Error('Permission denied');
+ }
+
+ target[prop] = newValue;
+ self.eventBus().emit(Block.EVENTS.INIT);
+
+ return true;
+ },
+ deleteProperty() {
+ throw new Error('Permission denied');
+ },
+ })
+
+ return proxyProps;
+ }
+}
diff --git a/src/core/index.js b/src/core/index.ts
similarity index 100%
rename from src/core/index.js
rename to src/core/index.ts
diff --git a/src/editing-password/editing-password.ts b/src/editing-password/editing-password.ts
new file mode 100644
index 000000000..012a7c9c8
--- /dev/null
+++ b/src/editing-password/editing-password.ts
@@ -0,0 +1,8 @@
+import { render } from "../utils/index";
+import { EditingPassword } from "../pages/index";
+
+import "../scss/index.scss";
+
+const page = new EditingPassword();
+
+render(page);
diff --git a/src/editing-password/index.html b/src/editing-password/index.html
new file mode 100644
index 000000000..5bdc0f74b
--- /dev/null
+++ b/src/editing-password/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Editing password page
+
+
+
+
+
+
diff --git a/src/editing-settings/editing-settings.ts b/src/editing-settings/editing-settings.ts
new file mode 100644
index 000000000..94e454f26
--- /dev/null
+++ b/src/editing-settings/editing-settings.ts
@@ -0,0 +1,8 @@
+import { render } from "../utils/index";
+import { EditingSettings } from "../pages/index";
+
+import "../scss/index.scss";
+
+const page = new EditingSettings();
+
+render(page);
diff --git a/src/editing-settings/index.html b/src/editing-settings/index.html
new file mode 100644
index 000000000..c4daa207a
--- /dev/null
+++ b/src/editing-settings/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Editing settings page
+
+
+
+
+
+
diff --git a/src/index.html b/src/index.html
index a4251a4ba..1e268a943 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,8 +1,9 @@
+
- Chats
+ Authorization page
diff --git a/src/index.ts b/src/index.ts
index 2fdd32322..de1c14736 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,11 +1,8 @@
-import Button from "./components/Button/Button";
+import { render } from "./utils/index";
+import { Authorization } from "./pages/index";
-const button = new Button({
- text: 'Click me',
-})
+import "./scss/index.scss";
-document.addEventListener('DOMContentLoaded', () => {
- const app = document.getElementById('app');
+const page = new Authorization();
- app.innerHTML = button;
-})
+render(page);
diff --git a/src/pages/404.pug b/src/pages/404.pug
deleted file mode 100644
index 2b60f3bbe..000000000
--- a/src/pages/404.pug
+++ /dev/null
@@ -1,16 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = '404 page';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- section.error-page
- h1.error-page__title 404
- p.error-page__description who seeks will always find
- .error-page__bottom
- a.error-page__link.link(href="chats-and-chat.html") go to chats page
-
diff --git a/src/pages/500.pug b/src/pages/500.pug
deleted file mode 100644
index 7c9677bf0..000000000
--- a/src/pages/500.pug
+++ /dev/null
@@ -1,16 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = '500 page';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- section.error-page
- h1.error-page__title 500
- p.error-page__description something went wrong
- .error-page__bottom
- a.error-page__link.link(href="chats-and-chat.html") go to chats page
-
diff --git a/src/pages/Authorization/Authorization.tmp.pug b/src/pages/Authorization/Authorization.tmp.pug
new file mode 100644
index 000000000..d6145b8c0
--- /dev/null
+++ b/src/pages/Authorization/Authorization.tmp.pug
@@ -0,0 +1 @@
+.page__content!= authForm
diff --git a/src/pages/Authorization/Authorization.ts b/src/pages/Authorization/Authorization.ts
new file mode 100644
index 000000000..84ebb16fa
--- /dev/null
+++ b/src/pages/Authorization/Authorization.ts
@@ -0,0 +1,52 @@
+import { Block } from "../../core/index";
+import template from "./Authorization.tmp.pug";
+import {
+ AuthorizationForm,
+ FieldText,
+ Button,
+ Link,
+} from "../../components/index";
+
+const authForm = new AuthorizationForm({
+ withId: true,
+ title: 'Sign in',
+ fieldLogin: new FieldText({
+ withId: true,
+ title: 'Login:',
+ type: 'text',
+ name: 'login',
+ helpText: `
+ от 3 до 20 символов, латиница, может содержать цифры,
+ но не состоять из них, без пробелов, без спецсимволов (допустимы дефис и нижнее подчёркивание)
+ `,
+ pattern: '(?=^.{3,20}$)[a-zA-Z_-]+[0-9_-a-zA-Z]*',
+ }),
+ fieldPassword: new FieldText({
+ withId: true,
+ title: 'Password:',
+ type: 'password',
+ name: 'password',
+ value: '',
+ helpText: 'от 8 до 40 символов, обязательно хотя бы одна заглавная буква и цифра',
+ pattern: '(?=^.{8,40}$)(?=.*[A-Z])(?=.*[0-9]).*',
+ }),
+ sendBtn: new Button({
+ className: 'btn btn--w-100 btn--big',
+ type: 'submit',
+ text: 'Sign in',
+ }),
+ link: new Link({
+ href: '/registration/',
+ text: 'Sign up',
+ }),
+})
+
+export default class Authorization extends Block {
+ constructor(props?: object) {
+ super('div', { ...props, authForm });
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/ChatsAndChat/ChatsAndChat.tmp.pug b/src/pages/ChatsAndChat/ChatsAndChat.tmp.pug
new file mode 100644
index 000000000..9533c251c
--- /dev/null
+++ b/src/pages/ChatsAndChat/ChatsAndChat.tmp.pug
@@ -0,0 +1,64 @@
+.chats-and-chat
+ aside.sidebar
+ .sidebar__f
+ form.search!= fieldSearch
+ .sidebar__s
+ .sidebar__s-inner
+ .chats
+ each val in [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+ article.chat(tabindex="0")
+ .chat__f
+ .avatar
+ img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
+ .chat__s
+ .chat__s-f
+ h6.name Chat name
+ time.chat__time 10:45
+ .chat__s-s
+ p.chat__last-message last message last message last message last message last message last message
+
+ .sidebar__t
+ .user-information
+ .user-information__f
+ .user-information__f-f
+ .avatar
+ img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
+ .user-information__f-s
+ h6.name User name
+
+ .user-information__s
+ button.settings(type="button") ...
+
+ .chat-area
+ .chat-area__f
+ .chat-area__f-f
+ .chat-area__info
+ .chat-area__info-l
+ .avatar
+ img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
+ .chat-area__info-r
+ h6.name Chat name
+
+ .chat-area__f-s
+ button.settings(type="button") ...
+
+ .chat-area__s
+ .messages-area
+ .messages-area__f
+ .messages-area__conversation
+ each val in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ .messages-area__conversation-item.messages-area__conversation-received
+ .messages-area__conversation-message
+ | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
+ .messages-area__conversation-message
+ | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
+
+ .messages-area__conversation-item.messages-area__conversation-sent
+ .messages-area__conversation-message
+ | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
+
+ .messages-area__s
+ .messages-area__s-inner!= fieldMessage
+ .messages-area__buttons
+ button.settings(type="button") ...
+ button.settings(type="button") ...
diff --git a/src/pages/ChatsAndChat/ChatsAndChat.ts b/src/pages/ChatsAndChat/ChatsAndChat.ts
new file mode 100644
index 000000000..6de8f8968
--- /dev/null
+++ b/src/pages/ChatsAndChat/ChatsAndChat.ts
@@ -0,0 +1,33 @@
+import { Block } from "../../core/index";
+import template from "./ChatsAndChat.tmp.pug";
+import {
+ FieldText,
+} from "../../components/index";
+
+const fieldSearch = new FieldText({
+ withId: true,
+ mods: 'field-text--center field-text--white',
+ type: 'text',
+ name: 'search',
+ value: '',
+ placeholder: 'search',
+})
+
+const fieldMessage = new FieldText({
+ withId: true,
+ mods: 'field-text--main',
+ type: 'text',
+ name: 'message',
+ value: '',
+ placeholder: 'Type a message',
+})
+
+export default class ChatsAndChat extends Block {
+ constructor(props?: object) {
+ super('div', { ...props, fieldSearch, fieldMessage });
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/EditingPassword/EditingPassword.tmp.pug b/src/pages/EditingPassword/EditingPassword.tmp.pug
new file mode 100644
index 000000000..534777381
--- /dev/null
+++ b/src/pages/EditingPassword/EditingPassword.tmp.pug
@@ -0,0 +1,11 @@
+.modal
+ .modal__inner
+ button.modal__close(title="Close modal")
+ .modal__content
+ section.user-settings
+ .user-settings__f
+ .user-settings__avatar
+ h2.user-settings__name= userName
+
+ .user-settings__s!= userSettings
+ .user-settings__t!= saveBtn
diff --git a/src/pages/EditingPassword/EditingPassword.ts b/src/pages/EditingPassword/EditingPassword.ts
new file mode 100644
index 000000000..4d7572fbb
--- /dev/null
+++ b/src/pages/EditingPassword/EditingPassword.ts
@@ -0,0 +1,60 @@
+import { Block } from "../../core/index";
+import template from "./EditingPassword.tmp.pug";
+import {
+ EditingPasswordForm,
+ FieldText,
+ Button,
+} from "../../components/index";
+
+export default class EditingPassword extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ userName: 'User name',
+ userSettings: new EditingPasswordForm({
+ currentPassword: new FieldText({
+ withId: true,
+ title: 'Current password:',
+ type: 'password',
+ name: 'old_password',
+ value: 'jzuXon8ZOT',
+ helpText: 'от 8 до 40 символов, обязательно хотя бы одна заглавная буква и цифра',
+ pattern: '(?=^.{8,40}$)(?=.*[A-Z])(?=.*\\d).*',
+ tmp: 'setting',
+ }),
+ newPassword: new FieldText({
+ withId: true,
+ title: 'New password:',
+ type: 'password',
+ name: 'new_password',
+ value: '',
+ helpText: 'от 8 до 40 символов, обязательно хотя бы одна заглавная буква и цифра',
+ pattern: '(?=^.{8,40}$)(?=.*[A-Z])(?=.*\\d).*',
+ tmp: 'setting',
+ }),
+ repeatNewPassword: new FieldText({
+ withId: true,
+ title: 'Repeat new password:',
+ type: 'password',
+ name: 'repeat_password',
+ value: '',
+ helpText: 'от 8 до 40 символов, обязательно хотя бы одна заглавная буква и цифра',
+ pattern: '(?=^.{8,40}$)(?=.*[A-Z])(?=.*\\d).*',
+ tmp: 'setting',
+ }),
+ }),
+ saveBtn: new Button({
+ className: 'link',
+ type: 'submit',
+ form: 'userSettingsForm',
+ text: 'Save password',
+ }),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/EditingSettings/EditingSettings.tmp.pug b/src/pages/EditingSettings/EditingSettings.tmp.pug
new file mode 100644
index 000000000..534777381
--- /dev/null
+++ b/src/pages/EditingSettings/EditingSettings.tmp.pug
@@ -0,0 +1,11 @@
+.modal
+ .modal__inner
+ button.modal__close(title="Close modal")
+ .modal__content
+ section.user-settings
+ .user-settings__f
+ .user-settings__avatar
+ h2.user-settings__name= userName
+
+ .user-settings__s!= userSettings
+ .user-settings__t!= saveBtn
diff --git a/src/pages/EditingSettings/EditingSettings.ts b/src/pages/EditingSettings/EditingSettings.ts
new file mode 100644
index 000000000..fbce677dc
--- /dev/null
+++ b/src/pages/EditingSettings/EditingSettings.ts
@@ -0,0 +1,97 @@
+import { Block } from "../../core/index";
+import template from "./EditingSettings.tmp.pug";
+import {
+ EditingSettingsForm,
+ FieldText,
+ Button,
+} from "../../components/index";
+
+export default class EditingSettings extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ userName: 'User name',
+ userSettings: new EditingSettingsForm({
+ nickname: new FieldText({
+ withId: true,
+ title: 'Nickname:',
+ type: 'text',
+ name: 'display_name',
+ value: 'userNickName',
+ helpText: `
+ латиница или кириллица, без пробелов и без цифр,
+ нет спецсимволов (допустим только дефис)
+ `,
+ pattern: '^[a-zA-Zа-яА-Я-]+$',
+ tmp: 'setting',
+ }),
+ firstName: new FieldText({
+ withId: true,
+ title: 'First name:',
+ type: 'text',
+ name: 'first_name',
+ value: 'Firstname',
+ helpText: `
+ латиница или кириллица, первая буква должна быть заглавной,
+ без пробелов и без цифр, нет спецсимволов (допустим только дефис)
+ `,
+ pattern: '(?=^[A-ZА-Я])[a-zA-Zа-яА-Я-]+$',
+ tmp: 'setting',
+ }),
+ secondName: new FieldText({
+ withId: true,
+ title: 'Second name:',
+ type: 'text',
+ name: 'second_name',
+ value: 'Sirstname',
+ helpText: `
+ латиница или кириллица, первая буква должна быть заглавной,
+ без пробелов и без цифр, нет спецсимволов (допустим только дефис)
+ `,
+ pattern: '(?=^[A-ZА-Я])[a-zA-Zа-яА-Я-]+$',
+ tmp: 'setting',
+ }),
+ email: new FieldText({
+ withId: true,
+ title: 'Email:',
+ type: 'text',
+ inputmode: 'email',
+ name: 'email',
+ value: 'test@test.ru',
+ helpText: `
+ латиница, может включать цифры и спецсимволы вроде дефиса и подчёркивания,
+ обязательно должна быть «собака» (@) и точка после неё,
+ но перед точкой обязательно должны быть буквы
+ `,
+ pattern: '^[a-zA-Z\\d_-]+@[a-z]+\\.[a-z]{2,3}$',
+ tmp: 'setting',
+ }),
+ phone: new FieldText({
+ withId: true,
+ title: 'Phone:',
+ type: 'text',
+ inputmode: 'tel',
+ name: 'phone',
+ value: '+70000000000',
+ helpText: `
+ от 10 до 15 символов, состоит из цифр, может начинается с плюса.
+ `,
+ pattern: '(?=^.{10,15}$)\\+?[0-9]+$',
+ tmp: 'setting',
+ }),
+ }),
+ saveBtn: new Button({
+ className: 'link',
+ type: 'submit',
+ form: 'userSettingsForm',
+ text: 'Save settings',
+ }),
+ }
+
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/ErrorPage/ErrorPage.tmp.pug b/src/pages/ErrorPage/ErrorPage.tmp.pug
new file mode 100644
index 000000000..342bbab9d
--- /dev/null
+++ b/src/pages/ErrorPage/ErrorPage.tmp.pug
@@ -0,0 +1,7 @@
+.page__content
+ section.error-page
+ h1.error-page__title= title
+ p.error-page__description= text
+ .error-page__bottom
+ a.error-page__link.link(href=linkHref)= linkText
+
diff --git a/src/pages/ErrorPage/ErrorPage.ts b/src/pages/ErrorPage/ErrorPage.ts
new file mode 100644
index 000000000..1796546d7
--- /dev/null
+++ b/src/pages/ErrorPage/ErrorPage.ts
@@ -0,0 +1,12 @@
+import { Block } from "../../core/index";
+import template from "./ErrorPage.tmp.pug";
+
+export default class ErrorPage extends Block {
+ constructor(props?: object) {
+ super('div', props);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/UserSettings/UserSettings.tmp.pug b/src/pages/UserSettings/UserSettings.tmp.pug
new file mode 100644
index 000000000..79f236a9c
--- /dev/null
+++ b/src/pages/UserSettings/UserSettings.tmp.pug
@@ -0,0 +1,33 @@
+.modal
+ .modal__inner
+ button.modal__close(title="Close modal")
+ .modal__content
+ section.user-settings
+ .user-settings__f
+ .user-settings__avatar
+ h2.user-settings__name= userName
+
+ .user-settings__s
+ ul.user-settings__list
+ li.user-settings__list-item
+ span.user-settings__list-item-name Nickname:
+ span.user-settings__list-item-value user name
+ li.user-settings__list-item
+ span.user-settings__list-item-name First name:
+ span.user-settings__list-item-value first name
+ li.user-settings__list-item
+ span.user-settings__list-item-name Second name:
+ span.user-settings__list-item-value second name
+ li.user-settings__list-item
+ span.user-settings__list-item-name Email:
+ span.user-settings__list-item-value test@test.ru
+ li.user-settings__list-item
+ span.user-settings__list-item-name Phone:
+ span.user-settings__list-item-value +7 (000) 000-00-00
+ li.user-settings__list-item
+ span.user-settings__list-item-name Login:
+ span.user-settings__list-item-value mylogin
+
+ .user-settings__t
+ | !{linkToSettings}
+ | !{linkToPassword}
diff --git a/src/pages/UserSettings/UserSettings.ts b/src/pages/UserSettings/UserSettings.ts
new file mode 100644
index 000000000..9775596bb
--- /dev/null
+++ b/src/pages/UserSettings/UserSettings.ts
@@ -0,0 +1,25 @@
+import { Block } from "../../core/index";
+import template from "./UserSettings.tmp.pug";
+import { Link } from "../../components/index";
+
+export default class ChatsAndChat extends Block {
+ constructor(props?: object) {
+ const newProps = {
+ ...props,
+ userName: 'User name',
+ linkToSettings: new Link({
+ href: '/editing-settings/',
+ text: 'Change settings',
+ }),
+ linkToPassword: new Link({
+ href: '/editing-password/',
+ text: 'Change password',
+ }),
+ }
+ super('div', newProps);
+ }
+
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/chats-and-chat.pug b/src/pages/chats-and-chat.pug
deleted file mode 100644
index 4f13737c8..000000000
--- a/src/pages/chats-and-chat.pug
+++ /dev/null
@@ -1,90 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = 'Chats and chat';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- .chats-and-chat
- aside.sidebar
- .sidebar__f
- form.search
- +field-text({
- mods: 'white, center',
- val: '',
- attrs: {
- name: 'search',
- placeholder: 'search',
- }
- })
-
- .sidebar__s
- .sidebar__s-inner
- .chats
- each val in [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15]
- article.chat(tabindex="0")
- .chat__f
- .avatar
- img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
- .chat__s
- .chat__s-f
- h6.name Chat name
- time.chat__time 10:45
- .chat__s-s
- p.chat__last-message last message last message last message last message last message last message
-
- .sidebar__t
- .user-information
- .user-information__f
- .user-information__f-f
- .avatar
- img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
- .user-information__f-s
- h6.name User name
-
- .user-information__s
- button.settings(type="button") ...
-
- .chat-area
- .chat-area__f
- .chat-area__f-f
- .chat-area__info
- .chat-area__info-l
- .avatar
- img.avatar__img(src="img/avatar-dummy-1.jpg", alt="user name avatar", loading="lazy")
- .chat-area__info-r
- h6.name Chat name
-
- .chat-area__f-s
- button.settings(type="button") ...
-
- .chat-area__s
- .messages-area
- .messages-area__f
- .messages-area__conversation
- each val in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- .messages-area__conversation-item.messages-area__conversation-received
- .messages-area__conversation-message
- | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
- .messages-area__conversation-message
- | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
-
- .messages-area__conversation-item.messages-area__conversation-sent
- .messages-area__conversation-message
- | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Voluptatum iste non corrupti molestias. Provident dolorum nostrum quasi id modi cumque doloribus nemo, beatae veritatis rem. Ducimus, amet dicta? Adipisci, corrupti?
-
- .messages-area__s
- .messages-area__s-inner
- +field-text({
- mods: 'main',
- attrs: {
- name: 'message',
- placeholder: 'Type a message',
- }
- })
- .messages-area__buttons
- button.settings(type="button") ...
- button.settings(type="button") ...
diff --git a/src/pages/index.ts b/src/pages/index.ts
new file mode 100644
index 000000000..e3f957b3f
--- /dev/null
+++ b/src/pages/index.ts
@@ -0,0 +1,17 @@
+import Authorization from "./Authorization/Authorization";
+import Registration from "./Registration/Registration";
+import ErrorPage from "./ErrorPage/ErrorPage";
+import ChatsAndChat from "./ChatsAndChat/ChatsAndChat";
+import UserSettings from "./UserSettings/UserSettings"
+import EditingSettings from "./EditingSettings/EditingSettings"
+import EditingPassword from "./EditingPassword/EditingPassword";
+
+export {
+ Authorization,
+ Registration,
+ ErrorPage,
+ ChatsAndChat,
+ UserSettings,
+ EditingSettings,
+ EditingPassword,
+}
diff --git a/src/pages/registration.pug b/src/pages/registration.pug
deleted file mode 100644
index 43c765c8b..000000000
--- a/src/pages/registration.pug
+++ /dev/null
@@ -1,58 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = 'Registration page';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- +form('Sign up')
- +form-field()
- +field-text({
- title: 'First name:',
- attrs: {
- name: 'first_name',
- }
- })
- +form-field()
- +field-text({
- title: 'Second name:',
- attrs: {
- name: 'second_name',
- }
- })
- +form-field()
- +field-text({
- title: 'Email:',
- attrs: {
- name: 'email',
- }
- })
- +form-field()
- +field-text({
- title: 'Phone:',
- attrs: {
- name: 'phone',
- }
- })
- +form-field()
- +field-text({
- title: 'Login:',
- attrs: {
- name: 'login',
- }
- })
- +form-field()
- +field-text({
- title: 'Password:',
- attrs: {
- type: 'password',
- name: 'password',
- }
- })
- +form-field('accent')
- +btn('Create profile', 'w-100, big')(type="button")
- +form-field().t-right
- a.link(href="index.html") Sign in
diff --git a/src/pages/registration/registration.tmp.pug b/src/pages/registration/registration.tmp.pug
index b1eb73fa0..1c3aa7595 100644
--- a/src/pages/registration/registration.tmp.pug
+++ b/src/pages/registration/registration.tmp.pug
@@ -1,20 +1 @@
-form.form
- h1.form__title Sign in
-
- .form__field
- label.field-text
- span.field-text__name Login:
- span.field-text__input-wrap
- input.field-text__input(type='text', name='login')
-
- .form__field
- label.field-text
- span.field-text__name Password:
- span.field-text__input-wrap
- input.field-text__input(type='password', name='password')
-
- .form__field.form__field--accent
- button.btn.btn--w-100.btn--big(type='button') Sign in
-
- .form__field.t-right
- a.link(href='#') Sign up
+.page__content!= registratonForm
diff --git a/src/pages/registration/registration.ts b/src/pages/registration/registration.ts
index 647480a0c..edd4c0221 100644
--- a/src/pages/registration/registration.ts
+++ b/src/pages/registration/registration.ts
@@ -1,15 +1,98 @@
-// import { compileClient } from 'pug';
-// // import { Block } from '../../core/index';
+import { Block } from "../../core/index";
+import template from "./Registration.tmp.pug";
+import {
+ RegistrationForm,
+ FieldText,
+ Button,
+ Link,
+} from "../../components/index";
-// const template = 'p #{name} is a #{occupation}';
-// const data = { name: 'John Doe', occupation: 'gardener' };
+const registratonForm = new RegistrationForm({
+ withId: true,
+ title: 'Sign up',
+ fieldFirstName: new FieldText({
+ withId: true,
+ title: 'First name:',
+ type: 'text',
+ name: 'first_name',
+ helpText: `
+ латиница или кириллица, первая буква должна быть заглавной,
+ без пробелов и без цифр, нет спецсимволов (допустим только дефис)
+ `,
+ pattern: '(?=^[A-ZА-Я])[a-zA-Zа-яА-Я-]+$',
+ }),
+ fieldSecondName: new FieldText({
+ withId: true,
+ title: 'Second name:',
+ type: 'text',
+ name: 'second_name',
+ helpText: `
+ латиница или кириллица, первая буква должна быть заглавной,
+ без пробелов и без цифр, нет спецсимволов (допустим только дефис)
+ `,
+ pattern: '(?=^[A-ZА-Я])[a-zA-Zа-яА-Я-]+$',
+ }),
+ fieldEmail: new FieldText({
+ withId: true,
+ title: 'Email:',
+ type: 'text',
+ inputmode: 'email',
+ name: 'email',
+ helpText: `
+ латиница, может включать цифры и спецсимволы вроде дефиса и подчёркивания,
+ обязательно должна быть «собака» (@) и точка после неё,
+ но перед точкой обязательно должны быть буквы
+ `,
+ pattern: '^[a-zA-Z\\d_-]+@[a-z]+\\.[a-z]{2,3}$',
+ }),
+ fieldPhone: new FieldText({
+ withId: true,
+ title: 'Phone:',
+ type: 'text',
+ inputmode: 'tel',
+ name: 'phone',
+ helpText: `
+ от 10 до 15 символов, состоит из цифр, может начинается с плюса.
+ `,
+ pattern: '(?=^.{10,15}$)\\+?[0-9]+$',
+ }),
+ fieldLogin: new FieldText({
+ withId: true,
+ title: 'Login:',
+ type: 'text',
+ name: 'login',
+ helpText: `
+ от 3 до 20 символов, латиница, может содержать цифры,
+ но не состоять из них, без пробелов, без спецсимволов (допустимы дефис и нижнее подчёркивание)
+ `,
+ pattern: '(?=^.{3,20}$)[a-zA-Z_-]+[\\d_-a-zA-Z]*',
+ }),
+ fieldPassword: new FieldText({
+ withId: true,
+ title: 'Password:',
+ type: 'password',
+ name: 'password',
+ value: '',
+ helpText: 'от 8 до 40 символов, обязательно хотя бы одна заглавная буква и цифра',
+ pattern: '(?=^.{8,40}$)(?=.*[A-Z])(?=.*\\d).*',
+ }),
+ sendBtn: new Button({
+ className: 'btn btn--w-100 btn--big',
+ type: 'submit',
+ text: 'Sign in',
+ }),
+ link: new Link({
+ href: '/',
+ text: 'Sign in',
+ }),
+})
-// // export default class RegistrationPage extends Block {
-// // render() {
-// // return compileClient(template, data);
-// // }
-// // }
+export default class Registration extends Block {
+ constructor(props?: object) {
+ super('div', { ...props, registratonForm });
+ }
-// const res = compileClient(template, data);
-
-// export { res };
+ render() {
+ return this.compile(template, this.props);
+ }
+}
diff --git a/src/pages/sign-in.pug b/src/pages/sign-in.pug
deleted file mode 100644
index 9d1ab23de..000000000
--- a/src/pages/sign-in.pug
+++ /dev/null
@@ -1,30 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = 'Sign in';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- +form('Sign in')
- +form-field()
- +field-text({
- title: 'Login:',
- attrs: {
- name: 'login',
- }
- })
- +form-field()
- +field-text({
- title: 'Password:',
- attrs: {
- type: 'password',
- name: 'password',
- }
- })
- +form-field('accent')
- +btn('Sign in', 'w-100, big')(type="button")
- +form-field().t-right
- a.link(href="registration.html") Sign up
diff --git a/src/pages/user-editing-settings.pug b/src/pages/user-editing-settings.pug
deleted file mode 100644
index e4c6e1848..000000000
--- a/src/pages/user-editing-settings.pug
+++ /dev/null
@@ -1,41 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = 'User editing settings';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- .modal
- .modal__inner
- button.modal__close(title="Close modal")
- .modal__content
- section.user-settings
- .user-settings__f
- .user-settings__avatar
- h2.user-settings__name User name
-
- .user-settings__s
- form#userSettingsForm.user-settings__form
- ul.user-settings__list
- li.user-settings__list-item
- label.user-settings__list-item-name(for="display_name") Nickname:
- input.user-settings__list-item-value.t-right(id="display_name" type="text" name="display_name" value="user name")
- li.user-settings__list-item
- label.user-settings__list-item-name(for="first_name") First name:
- input.user-settings__list-item-value.t-right(id="first_name" type="text" name="first_name" value="first name")
- li.user-settings__list-item
- label.user-settings__list-item-name(for="second_name") Second name:
- input.user-settings__list-item-value.t-right(id="second_name" type="text" name="second_name" value="second name")
- li.user-settings__list-item
- label.user-settings__list-item-name(for="email") Email:
- input.user-settings__list-item-value.t-right(id="email" type="text" name="email" value="test@test.ru")
- li.user-settings__list-item
- label.user-settings__list-item-name(for="phone") Phone:
- input.user-settings__list-item-value.t-right(id="phone" type="text" name="phone" value="+7 (000) 000-00-00")
- input(type="file", name="avatar", hidden)
-
- .user-settings__t
- button.link(type="button") Save settings
diff --git a/src/pages/user-settings.pug b/src/pages/user-settings.pug
deleted file mode 100644
index 5e86ffffa..000000000
--- a/src/pages/user-settings.pug
+++ /dev/null
@@ -1,43 +0,0 @@
-extends ../layout/main.pug
-
-block meta
- - const pageName = 'User settings';
-
- title= pageName
- meta(name='description', content=pageName)
-
-block content
-
- .modal
- .modal__inner
- button.modal__close(title="Close modal")
- .modal__content
- section.user-settings
- .user-settings__f
- .user-settings__avatar
- h2.user-settings__name User name
-
- .user-settings__s
- ul.user-settings__list
- li.user-settings__list-item
- span.user-settings__list-item-name Nickname:
- span.user-settings__list-item-value user name
- li.user-settings__list-item
- span.user-settings__list-item-name First name:
- span.user-settings__list-item-value first name
- li.user-settings__list-item
- span.user-settings__list-item-name Second name:
- span.user-settings__list-item-value second name
- li.user-settings__list-item
- span.user-settings__list-item-name Email:
- span.user-settings__list-item-value test@test.ru
- li.user-settings__list-item
- span.user-settings__list-item-name Phone:
- span.user-settings__list-item-value +7 (000) 000-00-00
- li.user-settings__list-item
- span.user-settings__list-item-name Login:
- span.user-settings__list-item-value mylogin
-
- .user-settings__t
- button.link(type="button") Change settings
- button.link(type="button") Change password
diff --git a/src/registration/index.html b/src/registration/index.html
new file mode 100644
index 000000000..ba9f4ce2d
--- /dev/null
+++ b/src/registration/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Registration page
+
+
+
+
+
+
diff --git a/src/registration/registration.ts b/src/registration/registration.ts
new file mode 100644
index 000000000..a6640ec49
--- /dev/null
+++ b/src/registration/registration.ts
@@ -0,0 +1,8 @@
+import { render } from "../utils/index";
+import { Registration } from "../pages/index";
+
+import "../scss/index.scss";
+
+const page = new Registration();
+
+render(page);
diff --git a/src/scss/index.scss b/src/scss/index.scss
new file mode 100644
index 000000000..d0a275cb0
--- /dev/null
+++ b/src/scss/index.scss
@@ -0,0 +1,3 @@
+@import "./reset.scss";
+@import "./main.scss";
+@import "./additions.scss";
diff --git a/src/scss/main.scss b/src/scss/main.scss
index 5d971f5dc..eaebafa48 100644
--- a/src/scss/main.scss
+++ b/src/scss/main.scss
@@ -35,6 +35,7 @@
--h-indent: 15px;
--b-radius: 5px;
--on-focus: 0 0 0 2px var(--m-color-1);
+ --on-error: 0 0 0 2px tomato;
--m-color-1: #784dd4;
--m-color-1-1: #5e36b2;
@@ -199,6 +200,18 @@ body {
font-weight: 500;
font-size: 15px;
+ .field-text,
+ > div:first-child {
+ width: 100%;
+ }
+
+ .field-text {
+ display: flex;
+ justify-content: space-between;
+ align-content: center;
+ flex-wrap: wrap;
+ }
+
& + & {
margin-top: 15px;
}
@@ -209,6 +222,10 @@ body {
&__list-item-value {
color: var(--t-l-grey-1);
+
+ @at-root .field-text--invalid & {
+ color: tomato;
+ }
}
&__t {
@@ -398,6 +415,7 @@ body {
width: 60px;
height: 60px;
border-radius: 50%;
+ background-color: var(--t-l-grey-3);
&__img {
width: 100%;
@@ -519,9 +537,13 @@ body {
gap: var(--indent-h);
width: 100%;
- .field-text {
+ > div:first-child {
width: 75%;
}
+
+ .field-text {
+ width: 100%;
+ }
}
&__conversation {
@@ -563,3 +585,34 @@ body {
gap: 5px var(--indent-h);
}
}
+
+/* ----- .form ----- */
+
+.form {
+ $block-name: &;
+
+ margin-left: auto;
+ margin-right: auto;
+ padding: 50px;
+ width: 400px;
+ max-width: 100%;
+ border-radius: var(--b-radius);
+ background-color: var(--bg-whiteSmoke);
+
+ &__title {
+ margin-bottom: 70px;
+ font-size: 35px;
+ font-weight: 500;
+ text-align: center;
+ }
+
+ &__field {
+ & + & {
+ margin-top: 20px;
+ }
+
+ & + &--accent {
+ margin-top: 40px;
+ }
+ }
+}
diff --git a/src/scss/style.scss b/src/scss/style.scss
deleted file mode 100644
index 8453c1f8f..000000000
--- a/src/scss/style.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-@import "./reset.scss";
-
-@import "./main.scss";
-
-@import "../components/btn/btn.scss";
-@import "../components/field-text/field-text.scss";
-@import "../components/form/form.scss";
-
-@import "./additions.scss";
diff --git a/src/user-settings/index.html b/src/user-settings/index.html
new file mode 100644
index 000000000..3dc836112
--- /dev/null
+++ b/src/user-settings/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ User settings page
+
+
+
+
+
+
diff --git a/src/user-settings/user-settings.ts b/src/user-settings/user-settings.ts
new file mode 100644
index 000000000..24f43142a
--- /dev/null
+++ b/src/user-settings/user-settings.ts
@@ -0,0 +1,8 @@
+import { render } from "../utils/index";
+import { UserSettings } from "../pages/index";
+
+import "../scss/index.scss";
+
+const page = new UserSettings();
+
+render(page);
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 000000000..bb2b1416b
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,5 @@
+import render from "./render";
+
+export {
+ render,
+}
diff --git a/src/utils/render.ts b/src/utils/render.ts
new file mode 100644
index 000000000..fbc45d394
--- /dev/null
+++ b/src/utils/render.ts
@@ -0,0 +1,11 @@
+type Page = {
+ getContent: Function
+}
+
+export default function render(page: Page) {
+ document.addEventListener('DOMContentLoaded', () => {
+ const app = document.getElementById('app');
+
+ app?.append(page.getContent());
+ })
+}
diff --git a/tsconfig.json b/tsconfig.json
index 9db061ae1..dec7251c9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,5 +18,6 @@
"sourceMap": true,
"strictNullChecks": true,
},
- "include": ["src"]
+ "include": ["src", "types/pug.d.ts"],
+ "exclude": ["node_modules", "build", "static"]
}
diff --git a/types/pug.d.ts b/types/pug.d.ts
new file mode 100644
index 000000000..1485f02a0
--- /dev/null
+++ b/types/pug.d.ts
@@ -0,0 +1 @@
+declare module "*.pug";
diff --git a/vite.config.ts b/vite.config.ts
index 6bf5a05d4..1f6e297fe 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -4,12 +4,26 @@ import pugPrecompile from './vite-plugin-pug-precompile';
const root = resolve(__dirname, 'src');
+console.log(__dirname);
+
export default defineConfig({
root,
base: '',
build: {
outDir: resolve(__dirname, 'build'),
emptyOutDir: true,
+ rollupOptions: {
+ input: {
+ index: resolve(__dirname, 'src/index.html'),
+ registration: resolve(__dirname, 'src/registration/index.html'),
+ page404: resolve(__dirname, 'src/404/index.html'),
+ page500: resolve(__dirname, 'src/500/index.html'),
+ chatsAndchat: resolve(__dirname, 'src/chats-and-chat/index.html'),
+ userSettings: resolve(__dirname, 'src/user-settings/index.html'),
+ editingSettings: resolve(__dirname, 'src/editing-settings/index.html'),
+ editingPassword: resolve(__dirname, 'src/editing-password/index.html'),
+ },
+ },
},
publicDir: resolve(__dirname, 'static'),
plugins: [pugPrecompile()],