diff --git a/package-lock.json b/package-lock.json
index 937a670..2aac94d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1216,6 +1216,12 @@
"loader-utils": "^1.1.0"
}
},
+ "@types/classnames": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.8.tgz",
+ "integrity": "sha512-3UrLzPnz8u+MMXuJTF++389IfLSQUbl5F3ry9WCxva0BKG5H/oo5NuPRXk+HrpPU1+5pVHSWhnVWRzIaFQ7QuQ==",
+ "dev": true
+ },
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@@ -1251,12 +1257,28 @@
"integrity": "sha512-/OMMBnjVtDuwX1tg2pkYVSqRIDSmNTnvVvmvP/2xiMAAWf4a5+JozrApCrO4WCAILmXVxfNoQ3E+0HJbNpFVGg==",
"dev": true
},
+ "@types/prop-types": {
+ "version": "15.7.1",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz",
+ "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==",
+ "dev": true
+ },
"@types/q": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
+ "@types/react": {
+ "version": "16.8.18",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.18.tgz",
+ "integrity": "sha512-lUXdKzRqWR4FebR5tGHkLCqnvQJS4fdXKCBrNGGbglqZg2gpU+J82pMONevQODUotATs9fc9k66bx3/St8vReg==",
+ "dev": true,
+ "requires": {
+ "@types/prop-types": "*",
+ "csstype": "^2.2.0"
+ }
+ },
"@types/tapable": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz",
@@ -4085,6 +4107,11 @@
}
}
},
+ "classnames": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
+ "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
+ },
"clean-css": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
@@ -4890,6 +4917,12 @@
"cssom": "0.3.x"
}
},
+ "csstype": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz",
+ "integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg==",
+ "dev": true
+ },
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -7306,8 +7339,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"aproba": {
"version": "1.2.0",
@@ -7350,8 +7382,7 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"concat-map": {
"version": "0.0.1",
@@ -7362,8 +7393,7 @@
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -7480,8 +7510,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"ini": {
"version": "1.3.5",
@@ -7493,7 +7522,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -7508,7 +7536,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -7516,14 +7543,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -7542,7 +7567,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -7623,8 +7647,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -7636,7 +7659,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
@@ -7722,8 +7744,7 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -7759,7 +7780,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -7779,7 +7799,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
- "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -7823,14 +7842,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
- "dev": true,
- "optional": true
+ "dev": true
}
}
},
diff --git a/package.json b/package.json
index 9ede333..0ffd460 100644
--- a/package.json
+++ b/package.json
@@ -10,11 +10,14 @@
],
"dependencies": {
"react": "16.8.6",
- "react-dom": "16.8.6"
+ "react-dom": "16.8.6",
+ "classnames": "latest"
},
"devDependencies": {
"@hellroot/eslint-config": "1.8.0",
"@hellroot/stylelint-config": "1.1.0",
+ "@types/classnames": "2.2.8",
+ "@types/react": "16.8.18",
"eslint": "5.12.0",
"npm-run-all": "4.1.5",
"prettier": "1.17.0",
diff --git a/public/index.html b/public/index.html
index 9a8ef8f..5d57a79 100644
--- a/public/index.html
+++ b/public/index.html
@@ -8,7 +8,7 @@
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
-
React App
+ Яндекс.Почта
diff --git a/src/app/app.css b/src/app/app.css
deleted file mode 100644
index 1c4d511..0000000
--- a/src/app/app.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.app {
- text-align: center;
-}
-
-.app-header {
- display: flex;
- min-height: 100vh;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background-color: #282c34;
- color: #fff;
- font-size: calc(10px + 2vmin);
-}
-
-.app-link {
- color: #61dafb;
-}
-
-@keyframes app-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/app/app.jsx b/src/app/app.jsx
deleted file mode 100644
index f759eed..0000000
--- a/src/app/app.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React, { Component } from 'react';
-
-import './app.css';
-
-export class App extends Component {
- render() {
- return (
-
- );
- }
-}
diff --git a/src/app/app.module.css b/src/app/app.module.css
new file mode 100644
index 0000000..21d4fcd
--- /dev/null
+++ b/src/app/app.module.css
@@ -0,0 +1,29 @@
+@font-face {
+ font-family: YandexSansBold;
+ /*src: url(fonts/YandexSansDisplay-Bold.ttf);*/
+}
+
+@font-face {
+ font-family: YandexSansThin;
+ /*src: url(/src/app/fonts/YandexSansDisplay-Thin.ttf);*/
+}
+
+@font-face {
+ font-family: HelveticaNeue;
+ /*src: url(/src/app/fonts/HelveticaNeueCyr-Medium.otf);*/
+}
+
+@font-face {
+ font-family: HelveticaNeueLight;
+ /*src: url(/src/app/fonts/HelveticaNeueCyr-Light.otf);*/
+}
+
+body {
+ position: relative;
+
+ min-width: 750px;
+ max-width: 1600px;
+ padding: 0;
+ margin: 0 auto;
+ background: #e5eaf0;
+}
diff --git a/src/app/app.test.jsx b/src/app/app.test.jsx
deleted file mode 100644
index 81be6fa..0000000
--- a/src/app/app.test.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
-import { App } from './app';
-
-it('renders without crashing', () => {
- const div = document.createElement('div');
-
- ReactDOM.render(, div);
- ReactDOM.unmountComponentAtNode(div);
-});
diff --git a/src/app/app.tsx b/src/app/app.tsx
new file mode 100644
index 0000000..40fb9c9
--- /dev/null
+++ b/src/app/app.tsx
@@ -0,0 +1,31 @@
+import React, { Component } from 'react';
+
+import styles from './app.module.css';
+import { Header } from './structure/header/header';
+import { Menu } from './structure/menu/menu';
+import { MainContent } from './structure/main-content/mainContent';
+
+export interface LetterType {
+ key: string;
+ id: string;
+ // classList: string[];
+ text: string[];
+ author : string;
+ topic : string;
+ date : string;
+ isChecked: boolean;
+ isVisible: boolean;
+}
+
+
+export class App extends Component {
+ render() {
+ return (
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/app/fonts/HelveticaNeueCyr-Light.otf b/src/app/fonts/HelveticaNeueCyr-Light.otf
new file mode 100755
index 0000000..7ced49a
Binary files /dev/null and b/src/app/fonts/HelveticaNeueCyr-Light.otf differ
diff --git a/src/app/fonts/HelveticaNeueCyr-Medium.otf b/src/app/fonts/HelveticaNeueCyr-Medium.otf
new file mode 100755
index 0000000..a2cde16
Binary files /dev/null and b/src/app/fonts/HelveticaNeueCyr-Medium.otf differ
diff --git a/src/app/fonts/YandexSansDisplay-Bold.ttf b/src/app/fonts/YandexSansDisplay-Bold.ttf
new file mode 100755
index 0000000..d901f4b
Binary files /dev/null and b/src/app/fonts/YandexSansDisplay-Bold.ttf differ
diff --git a/src/app/fonts/YandexSansDisplay-Thin.ttf b/src/app/fonts/YandexSansDisplay-Thin.ttf
new file mode 100755
index 0000000..3b8e196
Binary files /dev/null and b/src/app/fonts/YandexSansDisplay-Thin.ttf differ
diff --git a/src/app/index.js b/src/app/index.ts
similarity index 100%
rename from src/app/index.js
rename to src/app/index.ts
diff --git a/src/app/structure/header/header.module.css b/src/app/structure/header/header.module.css
new file mode 100644
index 0000000..2d68080
--- /dev/null
+++ b/src/app/structure/header/header.module.css
@@ -0,0 +1,36 @@
+/*Start SearchInput*/
+
+.header {
+ margin-top: 7px;
+ margin-bottom: 18px;
+ margin-left: 22px;
+}
+
+.header__lines,
+.header__mainLogo {
+ margin: 0;
+ float: left;
+}
+
+.header__lines {
+ margin-top: 12px;
+ float: left;
+}
+
+.header__line {
+ width: 20px;
+ height: 3px;
+ margin-top: 4px;
+ background-color: #000000;
+}
+
+.header__mainLogo {
+ margin-top: 7px;
+ margin-left: 11px;
+}
+
+.clearfix:after {
+ display: table;
+ clear: both;
+ content: '';
+}
diff --git a/src/app/structure/header/header.tsx b/src/app/structure/header/header.tsx
new file mode 100644
index 0000000..8f43b6d
--- /dev/null
+++ b/src/app/structure/header/header.tsx
@@ -0,0 +1,24 @@
+import React, { Component } from 'react';
+
+import styles from './header.module.css';
+import logo from './images/logo.png';
+import classNames from 'classnames';
+import { SearchInput } from './searchInput/searchInput';
+
+export class Header extends Component {
+ render() {
+ return (
+
+
+
+

+
+
+
+ );
+ }
+}
diff --git a/src/app/structure/header/images/logo.png b/src/app/structure/header/images/logo.png
new file mode 100644
index 0000000..e79b98c
Binary files /dev/null and b/src/app/structure/header/images/logo.png differ
diff --git a/src/app/structure/header/images/reset.png b/src/app/structure/header/images/reset.png
new file mode 100644
index 0000000..ab907a0
Binary files /dev/null and b/src/app/structure/header/images/reset.png differ
diff --git a/src/app/structure/header/searchInput/searchInput.module.css b/src/app/structure/header/searchInput/searchInput.module.css
new file mode 100644
index 0000000..9904a40
--- /dev/null
+++ b/src/app/structure/header/searchInput/searchInput.module.css
@@ -0,0 +1,32 @@
+.header__search {
+ width: 37%;
+ height: 32px;
+ margin-top: 11px;
+ margin-left: 114px;
+ background: #f2f5f8;
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
+ float: left;
+}
+
+.header__input {
+ display: inline-block;
+ width: calc(100% - 50px);
+ height: 26px;
+ margin-left: 16px;
+
+ border: none;
+ background: none;
+ outline: none;
+ vertical-align: center;
+}
+
+.header__button {
+ width: 12px;
+ height: 12px;
+ padding: 0;
+ margin: 10px;
+
+ border: none;
+ background: #f2f5f8;
+ float: right;
+}
diff --git a/src/app/structure/header/searchInput/searchInput.tsx b/src/app/structure/header/searchInput/searchInput.tsx
new file mode 100644
index 0000000..b6d1ba2
--- /dev/null
+++ b/src/app/structure/header/searchInput/searchInput.tsx
@@ -0,0 +1,29 @@
+import React, { Component } from 'react';
+
+import styles from './searchInput.module.css';
+import reset from '../images/reset.png';
+
+export class SearchInput extends Component {
+
+ private inputVal ?: HTMLInputElement;
+
+ resetForm = () => {
+ this.inputVal!.value = '';
+ };
+
+ render() {
+ return (
+
+
(this.inputVal = el.target)}
+ placeholder="Поиск"
+ className={styles.header__input}
+ />
+
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/all-functions/allFunctions.module.css b/src/app/structure/main-content/all-functions/allFunctions.module.css
new file mode 100644
index 0000000..33ac520
--- /dev/null
+++ b/src/app/structure/main-content/all-functions/allFunctions.module.css
@@ -0,0 +1,37 @@
+.clearfix:after {
+ display: table;
+ clear: both;
+ content: '';
+}
+
+.check {
+ width: 16px;
+ height: 16px;
+ margin: 12px;
+
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ background-color: #ffffff;
+ border-radius: 3px;
+ float: left;
+}
+
+.hiddenCheck {
+ display: none;
+}
+
+.mainBlock__mailFunctions {
+ height: 40px;
+
+ border-bottom: 2px solid rgba(0, 0, 0, 0.15);
+}
+
+.mainBlock__allFunctions {
+ padding-top: 6px;
+ margin: 0;
+}
+
+.mainBlock__func {
+ display: inline-block;
+ margin-left: 20px;
+ list-style: none;
+}
diff --git a/src/app/structure/main-content/all-functions/allFunctions.tsx b/src/app/structure/main-content/all-functions/allFunctions.tsx
new file mode 100644
index 0000000..3174990
--- /dev/null
+++ b/src/app/structure/main-content/all-functions/allFunctions.tsx
@@ -0,0 +1,81 @@
+import React, { Component } from 'react';
+
+import styles from './allFunctions.module.css';
+import { Button } from './button/button';
+import classNames from 'classnames';
+
+interface IProps {
+ isLetterOpened : boolean;
+ isChecked : boolean;
+ newMailOnClick: () => void;
+ deleteLetter: () => void;
+ selectAll: () => void;
+}
+
+export class AllFunctions extends Component {
+ constructor(props : IProps) {
+ super(props);
+ this.props = props;
+ }
+
+ public readonly props: IProps;
+
+ doNothing = () => {};
+
+ render() {
+ return (
+
+
{
+ if (!this.props.isLetterOpened) this.props.selectAll();
+ }}
+ />
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/all-functions/button/button.module.css b/src/app/structure/main-content/all-functions/button/button.module.css
new file mode 100644
index 0000000..65a6f25
--- /dev/null
+++ b/src/app/structure/main-content/all-functions/button/button.module.css
@@ -0,0 +1,13 @@
+.mainBlock__refFunc {
+ border: none;
+ background: none;
+ color: #cccccc;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 13px;
+ font-weight: 500;
+ text-decoration: none;
+}
+
+.mainBlock__refFunc:hover {
+ border-bottom: 2px solid #cccccc;
+}
diff --git a/src/app/structure/main-content/all-functions/button/button.tsx b/src/app/structure/main-content/all-functions/button/button.tsx
new file mode 100644
index 0000000..4516f29
--- /dev/null
+++ b/src/app/structure/main-content/all-functions/button/button.tsx
@@ -0,0 +1,33 @@
+import React, { Component } from 'react';
+
+import styles from './button.module.css';
+
+interface IProps {
+ action : () => void;
+ id : string;
+ title : string;
+ isLetterOpened : boolean;
+}
+export class Button extends Component {
+ constructor(props : IProps ) {
+ super(props);
+ this.props = props;
+ }
+
+ public readonly props: IProps;
+
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/footer/footer.module.css b/src/app/structure/main-content/footer/footer.module.css
new file mode 100644
index 0000000..2a868f3
--- /dev/null
+++ b/src/app/structure/main-content/footer/footer.module.css
@@ -0,0 +1,20 @@
+.footer {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+
+ width: 100%;
+ height: 26px;
+ padding-top: 5px;
+
+ border-top: 2px solid rgba(140, 140, 140, 0.45);
+ background-color: white;
+ color: #9b9b9b;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 0.7em;
+}
+
+.footer__texts {
+ margin-right: 20px;
+ float: right;
+}
diff --git a/src/app/structure/main-content/footer/footer.tsx b/src/app/structure/main-content/footer/footer.tsx
new file mode 100644
index 0000000..f56122b
--- /dev/null
+++ b/src/app/structure/main-content/footer/footer.tsx
@@ -0,0 +1,18 @@
+import React, { Component } from 'react';
+
+import styles from './footer.module.css';
+import { FooterText } from './footerText/footerText';
+
+export class Footer extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/footer/footerText/footerText.module.css b/src/app/structure/main-content/footer/footerText/footerText.module.css
new file mode 100644
index 0000000..f9d6c77
--- /dev/null
+++ b/src/app/structure/main-content/footer/footerText/footerText.module.css
@@ -0,0 +1,5 @@
+.footer__ref {
+ margin-right: 10px;
+ color: #9b9b9b;
+ text-decoration: none;
+}
diff --git a/src/app/structure/main-content/footer/footerText/footerText.tsx b/src/app/structure/main-content/footer/footerText/footerText.tsx
new file mode 100644
index 0000000..149b15a
--- /dev/null
+++ b/src/app/structure/main-content/footer/footerText/footerText.tsx
@@ -0,0 +1,22 @@
+import React, { Component } from 'react';
+
+import styles from './footerText.module.css';
+
+interface IProps {
+ id :string;
+ text : string;
+}
+
+export class FooterText extends Component {
+ constructor(props : IProps) {
+ super(props);
+
+ }
+ render() {
+ return (
+
+ {this.props.text}
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/letters/letter-page/img/reset.png b/src/app/structure/main-content/letters/letter-page/img/reset.png
new file mode 100644
index 0000000..ab907a0
Binary files /dev/null and b/src/app/structure/main-content/letters/letter-page/img/reset.png differ
diff --git a/src/app/structure/main-content/letters/letter-page/letterPage.module.css b/src/app/structure/main-content/letters/letter-page/letterPage.module.css
new file mode 100644
index 0000000..e5e8816
--- /dev/null
+++ b/src/app/structure/main-content/letters/letter-page/letterPage.module.css
@@ -0,0 +1,25 @@
+.mainBlock__letterContent {
+ position: absolute;
+ top: 42px;
+
+ overflow: scroll;
+ width: 100%;
+ height: calc(100% - 70px);
+ padding: 0;
+ background: #ffffff;
+ color: #000000;
+ float: left;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 0.8em;
+ font-weight: 700;
+}
+
+.mainBlock__paragraph {
+ padding: 10px;
+ margin-top: 10px;
+}
+
+.close {
+ padding: 15px;
+ float: right;
+}
diff --git a/src/app/structure/main-content/letters/letter-page/letterPage.tsx b/src/app/structure/main-content/letters/letter-page/letterPage.tsx
new file mode 100644
index 0000000..dcd6a72
--- /dev/null
+++ b/src/app/structure/main-content/letters/letter-page/letterPage.tsx
@@ -0,0 +1,32 @@
+import React, { Component } from 'react';
+
+import styles from './letterPage.module.css';
+import reset from './img/reset.png';
+
+interface IProps {
+ closeLetter : () => void;
+ text : string[];
+}
+
+export class LetterPage extends Component {
+ constructor(props : IProps) {
+ super(props);
+ }
+
+ render() {
+ return (
+
+

{
+ this.props.closeLetter();
+ }}
+ />
+
{this.props.text}
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/ebay.png b/src/app/structure/main-content/letters/letters-list/letter/icons/ebay.png
new file mode 100644
index 0000000..c9edef4
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/ebay.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/facebook.png b/src/app/structure/main-content/letters/letters-list/letter/icons/facebook.png
new file mode 100644
index 0000000..2d7290c
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/facebook.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/live.png b/src/app/structure/main-content/letters/letters-list/letter/icons/live.png
new file mode 100644
index 0000000..19f8a27
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/live.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/reddit.png b/src/app/structure/main-content/letters/letters-list/letter/icons/reddit.png
new file mode 100644
index 0000000..a297ce9
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/reddit.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/twitter.png b/src/app/structure/main-content/letters/letters-list/letter/icons/twitter.png
new file mode 100644
index 0000000..41e07c1
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/twitter.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/yandex.png b/src/app/structure/main-content/letters/letters-list/letter/icons/yandex.png
new file mode 100644
index 0000000..df4059c
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/yandex.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/icons/youtube.png b/src/app/structure/main-content/letters/letters-list/letter/icons/youtube.png
new file mode 100644
index 0000000..f06f858
Binary files /dev/null and b/src/app/structure/main-content/letters/letters-list/letter/icons/youtube.png differ
diff --git a/src/app/structure/main-content/letters/letters-list/letter/letter.module.css b/src/app/structure/main-content/letters/letters-list/letter/letter.module.css
new file mode 100644
index 0000000..2a4ca4a
--- /dev/null
+++ b/src/app/structure/main-content/letters/letters-list/letter/letter.module.css
@@ -0,0 +1,113 @@
+.check {
+ width: 16px;
+ height: 16px;
+ margin: 12px;
+
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ background-color: #ffffff;
+ border-radius: 3px;
+ float: left;
+}
+
+.mainBlock__topic {
+ overflow: hidden;
+ width: 30%;
+ min-width: 30px;
+ height: 18px;
+ margin-top: 11px;
+ margin-left: 2%;
+ color: #000000;
+ float: left;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 0.8em;
+}
+
+.mainBlock__letter {
+ height: 40px;
+
+ border-bottom: 2px solid #e2e2e2;
+ list-style: none;
+}
+
+.mainBlock__img {
+ height: 30px;
+ margin-top: 5px;
+ margin-left: 2%;
+ float: left;
+ text-align: center;
+}
+
+.mainBlock__mailFrom {
+ overflow: hidden;
+ width: 29%;
+ height: 18px;
+ margin: 10px;
+ float: left;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 0.8em;
+}
+
+.mainBlock__mailNotRead {
+ width: 10px;
+ height: 10px;
+ margin-top: 15px;
+ margin-left: 10px;
+ background: #6287bd;
+ border-radius: 50%;
+ float: left;
+}
+
+.hidden {
+ visibility: hidden;
+}
+
+.boldText {
+ font-weight: 700;
+}
+
+.mainBlock__date {
+ overflow: hidden;
+ width: 6%;
+ height: 15px;
+ margin-top: 12px;
+ margin-right: 2%;
+ color: #9b9b9b;
+ float: right;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 11px;
+}
+
+.animationInsert {
+ animation: inserting 0.5s linear;
+}
+
+.animationDelete {
+ animation: deleting 0.6s linear;
+}
+
+@keyframes inserting {
+ 0% {
+ transform: scale(0.5);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes down {
+ 0% {
+ transform: translateY(-40px);
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes deleting {
+ 0% {
+ transform: scale(1);
+ }
+ 100% {
+ transform: scale(0.5);
+ }
+}
diff --git a/src/app/structure/main-content/letters/letters-list/letter/letter.tsx b/src/app/structure/main-content/letters/letters-list/letter/letter.tsx
new file mode 100644
index 0000000..60f2db2
--- /dev/null
+++ b/src/app/structure/main-content/letters/letters-list/letter/letter.tsx
@@ -0,0 +1,65 @@
+import React, { Component } from 'react';
+
+import styles from './letter.module.css';
+import logo1 from './icons/ebay.png';
+import logo2 from './icons/yandex.png';
+import logo3 from './icons/live.png';
+import logo4 from './icons/facebook.png';
+import logo5 from './icons/twitter.png';
+import logo6 from './icons/reddit.png';
+import logo7 from './icons/youtube.png';
+import { LetterType } from '../../../../../app';
+import classNames from 'classnames';
+
+interface IProps {
+ key : string;
+ letterStates: LetterType;
+ isChecked: boolean;
+ openLetter: (text: string[]) => void;
+ onCheckboxChange: (id: string) => void;
+}
+
+export class Letter extends Component {
+ constructor(props: IProps) {
+ super(props);
+
+ this.firms = {
+ ebay: logo1,
+ yandex: logo2,
+ live: logo3,
+ facebook: logo4,
+ twitter: logo5,
+ reddit: logo6,
+ youtube: logo7
+ };
+ }
+
+ private readonly firms: { [id: string]: string };
+
+ render() {
+ return (
+
+
+
this.props.onCheckboxChange(this.props.letterStates.id)}
+ checked={this.props.isChecked}
+ />
+
this.props.openLetter(this.props.letterStates.text)}>
+
+

+
+
{this.props.letterStates.author}
+
+ {this.props.letterStates.topic}
+
+
+
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/letters/letters-list/letterList.tsx b/src/app/structure/main-content/letters/letters-list/letterList.tsx
new file mode 100644
index 0000000..26be550
--- /dev/null
+++ b/src/app/structure/main-content/letters/letters-list/letterList.tsx
@@ -0,0 +1,39 @@
+import React, { Component } from 'react';
+
+import styles from './lettersList.module.css';
+import { Letter } from './letter/letter';
+import { LetterType } from '../../../../app';
+
+interface IProps {
+ letters : LetterType[];
+ openLetter : (text : string[]) => void;
+ onCheckboxChange : (id : string) => void;
+ checkedLetters: { [id: string]: boolean };
+}
+export class LetterList extends Component
{
+ constructor(props : IProps){
+ super(props);
+ this.props = props;
+ }
+
+ public readonly props: IProps;
+
+ render() {
+ return (
+
+ {this.props.letters.map(letter => {
+ if (letter.isVisible)
+ return (
+
+ );
+ })}
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/letters/letters-list/lettersList.module.css b/src/app/structure/main-content/letters/letters-list/lettersList.module.css
new file mode 100644
index 0000000..72af51c
--- /dev/null
+++ b/src/app/structure/main-content/letters/letters-list/lettersList.module.css
@@ -0,0 +1,10 @@
+.mainBlock__allLetters {
+ overflow: scroll;
+ height: calc(100vh - 14px);
+ padding: 0;
+ margin: 0;
+}
+
+.allLetterDown {
+ animation: down 0.6s linear;
+}
diff --git a/src/app/structure/main-content/letters/letters.tsx b/src/app/structure/main-content/letters/letters.tsx
new file mode 100644
index 0000000..4ad08d0
--- /dev/null
+++ b/src/app/structure/main-content/letters/letters.tsx
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+
+import { LetterPage } from './letter-page/letterPage';
+import { LetterList } from './letters-list/letterList';
+import { LetterType } from '../../../app';
+
+interface IProps {
+ isLetterOpened : boolean;
+ openedLetterText : string[];
+ closeLetter : () => void;
+ openLetter : (text : string[]) => void;
+ onCheckboxChange : (id : string) => void;
+ letters : LetterType[];
+ checkedLetters: { [id: string]: boolean };
+}
+
+export class Letters extends Component {
+ constructor(props : IProps){
+ super(props);
+ this.props = props;
+ }
+
+ public readonly props: IProps;
+
+ render() {
+ return this.props.isLetterOpened ? (
+
+ ) : (
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/mainContent.module.css b/src/app/structure/main-content/mainContent.module.css
new file mode 100644
index 0000000..6672331
--- /dev/null
+++ b/src/app/structure/main-content/mainContent.module.css
@@ -0,0 +1,14 @@
+.mainBlock {
+ position: relative;
+
+ width: calc(100% - 230px);
+ min-width: 515px;
+ min-height: 300px;
+ padding: 0;
+ margin: 0 20px 14px 22px;
+
+ background-color: #ffffff;
+ border-radius: 3px;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.34);
+ float: right;
+}
diff --git a/src/app/structure/main-content/mainContent.tsx b/src/app/structure/main-content/mainContent.tsx
new file mode 100644
index 0000000..29de842
--- /dev/null
+++ b/src/app/structure/main-content/mainContent.tsx
@@ -0,0 +1,146 @@
+import React, { Component } from 'react';
+
+import styles from './mainContent.module.css';
+import { Letters } from './letters/letters';
+import { AllFunctions } from './all-functions/allFunctions';
+import { generateNewLetter, randomInt } from './scripts/generator';
+import { Footer } from './footer/footer';
+import { LetterType } from '../../app';
+
+const LETTERS_ON_PAGE = 30;
+
+interface IState {
+ isLetterOpened: false;
+ openedLetterText: string[];
+ letters: LetterType[];
+ isAllChecked: boolean;
+ checkedLetters: { [id: string]: boolean };
+}
+
+export class MainContent extends Component {
+ public constructor(props : any) {
+ super(props);
+
+ this.state = {
+ isLetterOpened: false,
+ openedLetterText: [],
+ letters: [],
+ isAllChecked: false,
+ checkedLetters: {}
+ };
+
+ this.onCheckboxChange.bind(this);
+ this.selectAll.bind(this);
+ this.newMail.bind(this);
+ this.deleteLetter.bind(this);
+ this.getRandomLetter.bind(this);
+ this.openLetter.bind(this);
+ this.closeLetter.bind(this);
+
+ setTimeout(this.getRandomLetter, 100);
+ }
+
+ public readonly state: IState;
+
+ public onCheckboxChange = (id: string) => {
+ this.setState((prevState : IState)=> {
+ const newCheckedLetters : { [id: string]: boolean } = prevState.checkedLetters;
+ newCheckedLetters[id] = !newCheckedLetters[id];
+ return {
+ isAllChecked: false,
+ checkedLetters: newCheckedLetters
+ };
+ });
+ };
+
+ public newMail = () => {
+ const newLetter : LetterType = generateNewLetter();
+ this.setState((prevState : IState)=> {
+ const newCheckedLetters = prevState.checkedLetters;
+ const newLetters = prevState.letters;
+ newCheckedLetters[newLetter.id] = false;
+ for (let i = newLetters.length - 1; i >= LETTERS_ON_PAGE - 1; i--) {
+ newLetters[i].isVisible = false;
+ newLetters[i].isChecked = false;
+ newCheckedLetters[newLetters[i].key] = false;
+ }
+ return {
+ letters: [newLetter, ...newLetters],
+ checkedLetters: newCheckedLetters,
+ isAllChecked: false
+ };
+ });
+ };
+
+ private getRandomLetter = () => {
+ const t = randomInt(10, 300000) + 300000;
+ this.newMail();
+ setTimeout(this.getRandomLetter, t);
+ };
+
+ public selectAll = () => {
+ this.setState((prevState : IState) => {
+ const newCheckedLetters = prevState.checkedLetters;
+ prevState.letters.forEach(letter => {
+ if (letter.isVisible) {
+ newCheckedLetters[letter.key] = !prevState.isAllChecked;
+ }
+ });
+ return {
+ isAllChecked: !prevState.isAllChecked,
+ checkedLetters: newCheckedLetters
+ };
+ });
+ };
+
+ public deleteLetter = () => {
+ this.setState((prevState : IState) => {
+ const newLetters = prevState.letters.filter(letter => !prevState.checkedLetters[letter.key]);
+ for (let i = 0; i < Math.min(newLetters.length, LETTERS_ON_PAGE); i++) {
+ newLetters[i].isVisible = true;
+ }
+ return {
+ letters: newLetters,
+ isAllChecked: false
+ };
+ });
+ };
+
+ public openLetter = (text : string[]) => {
+ this.setState({
+ isLetterOpened: true,
+ openedLetterText: text
+ });
+ };
+
+ public closeLetter = () => {
+ this.setState({
+ isLetterOpened: false,
+ openedLetterText: null
+ });
+ };
+
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/src/app/structure/main-content/scripts/generator.ts b/src/app/structure/main-content/scripts/generator.ts
new file mode 100644
index 0000000..fc79de9
--- /dev/null
+++ b/src/app/structure/main-content/scripts/generator.ts
@@ -0,0 +1,119 @@
+const companies = ['ebay', 'facebook', 'live', 'yandex', 'live', 'reddit', 'twitter', 'youtube'];
+const topics = [
+ 'Внимание!',
+ 'Добро пожаловать!',
+ 'Обновление',
+ 'Получите приз!',
+ 'Восстановление аккаунта',
+ 'Ищем сотрудников',
+ 'Спасибо за отзыв'
+];
+const hello = ['Здравствуйте!', 'Добрый день!', 'Привет!', 'Приветствую!', 'Салют!'];
+const word1 = ['Я', 'Меня зовут', 'Это'];
+const firstName = ['Виталий', 'Андрей', 'Владимир', 'Алексей', 'Артём', 'Антон'];
+const secondName = [
+ 'Соболев',
+ 'Чиркин',
+ 'Борисов',
+ 'Орехов',
+ 'Гаврилов',
+ 'Иванов',
+ 'Сергеев',
+ 'Онегин'
+];
+const phrase1 = [
+ 'Так вышло, что',
+ 'Нам стало известно, что',
+ 'Сообщаем вам, что',
+ 'Как вы могли заметить,',
+ 'С сегоднящнего дня'
+];
+const nouns1 = ['эксперт', 'редактор', 'программист', 'рабочий'];
+const verbs = [
+ 'взломал',
+ 'проверил',
+ 'удалил',
+ 'исправил',
+ 'закрыл',
+ 'заметил',
+ 'пометил',
+ 'пересмотрел',
+ 'передал'
+];
+const nouns2 = ['счет', 'аккаунт', 'пароль', 'кабинет'];
+const adjectives = [
+ 'идеальный',
+ 'прямой',
+ 'обратный',
+ 'наш',
+ 'постоянный',
+ 'великолепный',
+ 'исключительный',
+ 'личный',
+ 'ваш'
+];
+
+let counter = 0;
+
+export function randomInt(min: number, max : number) {
+ return Math.floor((max - min) * Math.random() + min);
+}
+
+function randFromList(list : any) {
+ return list[randomInt(0, list.length)];
+}
+
+const randomDate = () => {
+ const m = randomInt(1, 12);
+ let day = randomInt(1, 30);
+ if (m === 2) day = Math.min(28, day);
+ const month = [
+ 'янв',
+ 'фев',
+ 'мар',
+ 'апр',
+ 'май',
+ 'июн',
+ 'июл',
+ 'авг',
+ 'сен',
+ 'окт',
+ 'ноя',
+ 'дек'
+ ];
+ return `${String(day)} ${String(month[m - 1])}`;
+};
+
+function generateText(sender:string) {
+ const textContent = [
+ `${randFromList(hello)} ${randFromList(word1)} ${randFromList(firstName)} ${randFromList(
+ secondName
+ )}, глава компании ${sender.toUpperCase()}.`
+ ];
+ textContent.push(
+ `${randFromList(phrase1)} ${randFromList(adjectives)} ${randFromList(nouns1)} ${randFromList(
+ verbs
+ )} ${randFromList(adjectives)} ${randFromList(nouns2)}.`
+ );
+ return textContent;
+}
+
+export const generateNewLetter = () => {
+ counter++;
+ const id = counter;
+ const author = randFromList(companies);
+ const text = generateText(author);
+ const topic = randFromList(topics);
+ const date = randomDate();
+
+ return {
+ key: `id${id}`,
+ id: `id${id}`,
+ text: text,
+ author : author,
+ topic : topic,
+ date : date,
+ isChecked: false,
+ isVisible: true
+ };
+};
diff --git a/src/app/structure/menu/menu.module.css b/src/app/structure/menu/menu.module.css
new file mode 100644
index 0000000..a826262
--- /dev/null
+++ b/src/app/structure/menu/menu.module.css
@@ -0,0 +1,53 @@
+.menu {
+ width: 147px;
+ max-width: 170px;
+ margin-left: 22px;
+ float: left;
+}
+
+.menu__toWrite {
+ width: 147px;
+ height: 32px;
+
+ border: none;
+ background-color: #6287bd;
+ border-radius: 3px;
+ color: #ffffff;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 12px;
+}
+
+.menu__toWrite:hover {
+ box-shadow: 2px 2px rgba(0, 0, 0, 0.6);
+}
+
+.menu__bar {
+ padding: 0;
+}
+
+.menu__action {
+ width: 147px;
+ height: 22px;
+ margin-top: 2px;
+ border-radius: 3px;
+ list-style: none;
+}
+
+.menu__textRef {
+ display: block;
+ padding-left: 10px;
+ color: #555555;
+ font-family: "'HelveticaNeue'", sans-serif;
+ font-size: 11px;
+ font-weight: 500;
+ line-height: 22px;
+ text-decoration: none;
+}
+
+.menu__action:hover {
+ background-color: #cdd6e4;
+}
+
+.menu__textRef:hover {
+ font-weight: 700;
+}
diff --git a/src/app/structure/menu/menu.tsx b/src/app/structure/menu/menu.tsx
new file mode 100644
index 0000000..d16a1ce
--- /dev/null
+++ b/src/app/structure/menu/menu.tsx
@@ -0,0 +1,35 @@
+import React, { Component } from 'react';
+
+import styles from './menu.module.css';
+
+const actions = [
+ { title: 'Входящие', fragment: 'inbox' },
+ { title: 'Отправленные', fragment: 'sent' },
+ { title: 'Удалённые', fragment: 'deleted' },
+ { title: 'Спам', fragment: 'spam' },
+ { title: 'Черновики', fragment: 'drafts' },
+ { title: 'Создать папку', fragment: 'createdir' }
+];
+
+export class Menu extends Component {
+ render() {
+ return (
+
+ );
+ }
+}