diff --git a/.eslintrc.js b/.eslintrc.js
index fe0f890..88c68a4 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -15,5 +15,8 @@ module.exports = {
"ecmaVersion": 2018,
"sourceType": "module"
},
+ "rules": {
+ "no-param-reassign": [2, { "props": false }]
+ }
};
diff --git a/debug.log b/debug.log
index 571b8a3..ae6bd58 100644
--- a/debug.log
+++ b/debug.log
@@ -5,3 +5,6 @@
[0112/191140.288:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
[0113/181410.359:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
[0114/181756.347:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[0118/180712.859:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[0121/174104.700:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[0125/183609.977:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
diff --git a/package-lock.json b/package-lock.json
index 140608e..dab33e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9168,6 +9168,11 @@
"mimic-fn": "^2.1.0"
}
},
+ "openweather-apis": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/openweather-apis/-/openweather-apis-4.4.1.tgz",
+ "integrity": "sha512-/t3IVSEwLFQN2xBdu4iAib9OifLzdAbea/OCokchZgvMOgwMEmr8g/pRz2HjuYQpHp6HWaiS2dMf5h48LJPGug=="
+ },
"opn": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
diff --git a/package.json b/package.json
index 18bbc67..4915573 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"dependencies": {
"chart.js": "^2.9.3",
"core-js": "^3.4.7",
+ "openweather-apis": "^4.4.1",
"regenerator-runtime": "^0.13.3"
}
}
diff --git a/src/assets/audio/ambient.mp3 b/src/assets/audio/ambient.mp3
new file mode 100644
index 0000000..b11c7aa
Binary files /dev/null and b/src/assets/audio/ambient.mp3 differ
diff --git a/src/assets/audio/birds-waves.mp3 b/src/assets/audio/birds-waves.mp3
new file mode 100644
index 0000000..4f13460
Binary files /dev/null and b/src/assets/audio/birds-waves.mp3 differ
diff --git a/src/assets/audio/birds.mp3 b/src/assets/audio/birds.mp3
new file mode 100644
index 0000000..fc41555
Binary files /dev/null and b/src/assets/audio/birds.mp3 differ
diff --git a/src/assets/audio/cafe.mp3 b/src/assets/audio/cafe.mp3
new file mode 100644
index 0000000..ea51963
Binary files /dev/null and b/src/assets/audio/cafe.mp3 differ
diff --git a/src/assets/audio/thunder.mp3 b/src/assets/audio/thunder.mp3
new file mode 100644
index 0000000..03f8845
Binary files /dev/null and b/src/assets/audio/thunder.mp3 differ
diff --git a/src/assets/audio/waves.mp3 b/src/assets/audio/waves.mp3
new file mode 100644
index 0000000..193bb34
Binary files /dev/null and b/src/assets/audio/waves.mp3 differ
diff --git a/src/assets/fonts/fonts-calculator/Crystal.ttf b/src/assets/fonts/fonts-calculator/Crystal.ttf
new file mode 100644
index 0000000..3c6f5fd
Binary files /dev/null and b/src/assets/fonts/fonts-calculator/Crystal.ttf differ
diff --git a/src/assets/fonts/fonts-calculator/Roboto-Bold.ttf b/src/assets/fonts/fonts-calculator/Roboto-Bold.ttf
new file mode 100644
index 0000000..d3f01ad
Binary files /dev/null and b/src/assets/fonts/fonts-calculator/Roboto-Bold.ttf differ
diff --git a/src/assets/fonts/fonts-calculator/Roboto-Regular.ttf b/src/assets/fonts/fonts-calculator/Roboto-Regular.ttf
new file mode 100644
index 0000000..2c97eea
Binary files /dev/null and b/src/assets/fonts/fonts-calculator/Roboto-Regular.ttf differ
diff --git a/src/assets/fonts/fonts-calculator/symbol.ttf b/src/assets/fonts/fonts-calculator/symbol.ttf
new file mode 100644
index 0000000..fd1c033
Binary files /dev/null and b/src/assets/fonts/fonts-calculator/symbol.ttf differ
diff --git a/src/assets/fonts/fonts-weather/owfont-regular.eot b/src/assets/fonts/fonts-weather/owfont-regular.eot
new file mode 100644
index 0000000..d536096
Binary files /dev/null and b/src/assets/fonts/fonts-weather/owfont-regular.eot differ
diff --git a/src/assets/fonts/fonts-weather/owfont-regular.otf b/src/assets/fonts/fonts-weather/owfont-regular.otf
new file mode 100644
index 0000000..42e6ffa
Binary files /dev/null and b/src/assets/fonts/fonts-weather/owfont-regular.otf differ
diff --git a/src/assets/fonts/fonts-weather/owfont-regular.svg b/src/assets/fonts/fonts-weather/owfont-regular.svg
new file mode 100644
index 0000000..6969ffb
--- /dev/null
+++ b/src/assets/fonts/fonts-weather/owfont-regular.svg
@@ -0,0 +1,394 @@
+
+
+
diff --git a/src/assets/fonts/fonts-weather/owfont-regular.ttf b/src/assets/fonts/fonts-weather/owfont-regular.ttf
new file mode 100644
index 0000000..2b1683c
Binary files /dev/null and b/src/assets/fonts/fonts-weather/owfont-regular.ttf differ
diff --git a/src/assets/fonts/fonts-weather/owfont-regular.woff b/src/assets/fonts/fonts-weather/owfont-regular.woff
new file mode 100644
index 0000000..591f3d0
Binary files /dev/null and b/src/assets/fonts/fonts-weather/owfont-regular.woff differ
diff --git a/src/assets/img/metal.jpg b/src/assets/img/metal.jpg
new file mode 100644
index 0000000..f110b03
Binary files /dev/null and b/src/assets/img/metal.jpg differ
diff --git a/src/assets/img/weather.jpg b/src/assets/img/weather.jpg
new file mode 100644
index 0000000..da1f426
Binary files /dev/null and b/src/assets/img/weather.jpg differ
diff --git a/src/css/style.css b/src/css/style.css
index 57253ac..bf8399e 100644
--- a/src/css/style.css
+++ b/src/css/style.css
@@ -3,6 +3,7 @@
--accent-color-contrast: #120C0E;
--error-color: #f00;
--text-color: #000;
+ --input-outline-color: #ccc;
--app-background-color: #fff;
--header-footer-text-color: #FDF6A1;
}
diff --git a/src/index.html b/src/index.html
index 1a45397..cfc5301 100644
--- a/src/index.html
+++ b/src/index.html
@@ -4,7 +4,8 @@
-
+
+
Start Page
diff --git a/src/js/components/auth/auth.css b/src/js/components/auth/auth.css
new file mode 100644
index 0000000..89918b0
--- /dev/null
+++ b/src/js/components/auth/auth.css
@@ -0,0 +1,105 @@
+.modal-shadow {
+ position: fixed;
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.5);
+ top: 0;
+}
+
+.modal {
+ width: 300px;
+ padding: 10px 0;
+ background-color: var(--modal-background-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-radius: 9px;
+}
+
+.auth {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ border-radius: 10px;
+ width: 300px;
+ background-color: var(--accent-color-contrast);
+}
+
+.auth-header {
+ margin-top: 15px;
+ font-size: 33px;
+ line-height: 33px;
+ color: var(--header-footer-text-color);
+}
+
+.auth-description {
+ margin: 10px 10px 20px 10px;
+ font-size: 16px;
+ color: var(--header-footer-text-color);
+}
+
+.auth-form {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+}
+
+.auth-inputs {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 10px;
+ background-color: var(--header-footer-text-color);
+ width: 100%;
+}
+
+.auth-form-input {
+ max-width: 260px;
+ width: calc(100% - 20px);
+ font-size: 16px;
+ padding: 12px;
+ margin: 10px;
+ border: 1px solid var(--input-outline-color);
+ border-radius: 5px;
+}
+
+.auth-form-error {
+ max-width: 260px;
+ color: var(--error-color);
+ margin-bottom: 20px;
+}
+
+.auth-button {
+ font-weight: bold;
+ margin: 10px;
+ padding: 10px 20px;
+ font-size: 18px;
+ background-color: var(--header-footer-text-color);
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.button-register {
+ background-color: transparent;
+ color: var(--header-footer-text-color);
+}
+
+.auth-button:focus {
+ outline:none;
+ box-shadow: none;
+}
+
+.button-log-in:hover {
+ background-color: var(--app-background-color);
+}
+
+.button-register:hover {
+ color: var(--app-background-color);
+}
diff --git a/src/js/components/auth/auth.js b/src/js/components/auth/auth.js
new file mode 100644
index 0000000..0c427d7
--- /dev/null
+++ b/src/js/components/auth/auth.js
@@ -0,0 +1,176 @@
+import './auth.css';
+import * as Constants from '../../data/constants';
+import create from '../../utils/create';
+import { validatePassword, validateEmail } from './validation';
+import * as RemoteAuth from '../../services/auth';
+
+export class Auth {
+ constructor(register) {
+ this.isLogin = register;
+ this.modelContainer = create('div', 'modal-shadow');
+ this.modal = create('div', 'auth');
+ this.modelContainer.appendChild(this.modal);
+ this.modelContainer.addEventListener('click', this.clickShadow.bind(this));
+ document.body.appendChild(this.modelContainer);
+ this.render();
+ this.addListeners();
+ }
+
+ render() {
+ const formCaption = (this.isLogin) ? 'Login' : 'Register';
+ const emailInput = (this.isLogin) ? '' : `;
+ `;
+ const buttonLogin = (this.isLogin) ? 'Login' : 'Register';
+ const buttonRegister = (this.isLogin) ? 'Register' : 'Login';
+ const template = `
+
+ Insert your e-mail and password.
+
+ `;
+ this.modal.innerHTML = template;
+ }
+
+ addListeners() {
+ this.regBtn = document.querySelector('.button-register');
+ this.loginBtn = document.querySelector('.button-log-in');
+ if (this.isLogin) {
+ this.regBtn.addEventListener('click', this.switchForm.bind(this));
+ this.loginBtn.addEventListener('click', this.login.bind(this));
+ } else {
+ this.regBtn.addEventListener('click', this.switchForm.bind(this));
+ this.loginBtn.addEventListener('click', this.register.bind(this));
+ const password = document.querySelector('#auth-password');
+ password.addEventListener('change', this.validatePassword.bind(this));
+ const email = document.querySelector('#auth-email');
+ email.addEventListener('change', this.validateEmail.bind(this));
+ }
+ }
+
+ register(evt) {
+ evt.preventDefault();
+ const username = document.querySelector('#auth-username');
+ const email = document.querySelector('#auth-email');
+ const password = document.querySelector('#auth-password');
+ this.registerUser(username.value, email.value, password.value);
+ }
+
+ login(evt) {
+ evt.preventDefault();
+ const username = document.querySelector('#auth-username');
+ const password = document.querySelector('#auth-password');
+ this.loginUser(username.value, password.value);
+ }
+
+ switchForm() {
+ this.isLogin = !this.isLogin;
+ this.modal.innerHTML = '';
+ this.render();
+ this.addListeners();
+ }
+
+ validatePassword(evt) {
+ const mess = document.querySelector('.auth-form-error');
+ if (!validatePassword(evt.target.value)) {
+ mess.innerText = 'password must contain digits, uppercase and lovercase letters, special symbols';
+ } else {
+ mess.innerText ='';
+ }
+ }
+
+ validateEmail(evt) {
+ const mess = document.querySelector('.auth-form-error');
+ if (!validateEmail(evt.target.value)) {
+ mess.innerText = 'incorrect email';
+ } else {
+ mess.innerText ='';
+ }
+ }
+
+ clickShadow(evt) {
+ if(evt.target === this.modelContainer) {
+ this.closeModal();
+ }
+ }
+
+ closeModal() {
+ document.body.removeChild(this.modelContainer);
+ window.myapp.header.deleteLoginForm();
+ }
+
+ async registerUser(username, email, password) {
+ try {
+ const res = await RemoteAuth.registerUser(username, email, password);
+ if (res.statusCode === 200) {
+ localStorage.setItem(Constants.userItemLocalStorage, JSON.stringify(res.token));
+ window.myapp.header.setLogged();
+ this.closeModal();
+ }
+ if (res.statusCode === 400) {
+ const mess = document.querySelector('.auth-form-error');
+ mess.innerText = `${res.reason}`;
+ }
+ } catch (err) {
+ const mess = document.querySelector('.auth-form-error');
+ mess.innerText = `${err.name}: ${err.message}`;
+ }
+ }
+
+ async loginUser(username, password) {
+ try {
+ const res = await RemoteAuth.loginUser(username, password);
+ if (res.statusCode === 200) {
+ localStorage.setItem(Constants.userItemLocalStorage, JSON.stringify(res.token));
+ window.myapp.header.setLogged();
+ this.closeModal();
+ }
+ if (res.statusCode === 403) {
+ const mess = document.querySelector('.auth-form-error');
+ mess.innerText = `${res.reason}`;
+ }
+ } catch (err) {
+ const mess = document.querySelector('.auth-form-error');
+ mess.innerText = `${err.name}: ${err.message}`;
+ }
+ }
+}
+
+export default Auth;
diff --git a/src/js/components/auth/validation.js b/src/js/components/auth/validation.js
new file mode 100644
index 0000000..8d15ccd
--- /dev/null
+++ b/src/js/components/auth/validation.js
@@ -0,0 +1,10 @@
+export const validatePassword = function validatePassword(password) {
+ const re = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?!.*\s).{8,15}$/;
+ return re.test(password);
+};
+
+export const validateEmail = function validateEmail(email) {
+ // eslint-disable-next-line no-useless-escape,max-len
+ const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ return re.test(String(email).toLowerCase());
+};
diff --git a/src/js/components/base-menu/baseMenu.css b/src/js/components/base-menu/baseMenu.css
index 5cfb3be..07cee15 100644
--- a/src/js/components/base-menu/baseMenu.css
+++ b/src/js/components/base-menu/baseMenu.css
@@ -36,6 +36,9 @@
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
padding: 40px;
background-color: #ffffff;
}
@@ -51,7 +54,9 @@
.cross {
width: 25px;
height: 25px;
+ padding: 14px;
background: url(../../../assets/img/Group.png);
+ background-repeat: no-repeat;
}
.cross:hover {
@@ -103,4 +108,15 @@
-webkit-transform: translate(400px);
transform: translate(400px);
}
+
+@media (max-width: 1700px) {
+ .baseMenu {
+ width: 320px;
+ -webkit-transform: translate(320px);
+ transform: translate(320px);
+ }
+ .header-block {
+ padding: 30px;
+ }
+}
/*# sourceMappingURL=baseMenu.css.map */
\ No newline at end of file
diff --git a/src/js/components/base-menu/baseMenu.scss b/src/js/components/base-menu/baseMenu.scss
index a53c5e3..ece1d33 100644
--- a/src/js/components/base-menu/baseMenu.scss
+++ b/src/js/components/base-menu/baseMenu.scss
@@ -29,10 +29,11 @@ $width: 400px;
.header-block {
display: flex;
justify-content: space-between;
+ align-items: center;
padding: 40px;
background-color: #ffffff;
- .header-caption{
+ .header-caption {
background-color: #ffffff;
}
}
@@ -44,7 +45,9 @@ $width: 400px;
.cross {
width: 25px;
height: 25px;
+ padding: 14px;
background: url(../../../assets/img/Group.png);
+ background-repeat: no-repeat;
&:hover {
cursor: pointer;
@@ -89,3 +92,17 @@ $width: 400px;
.baseMenu.hide {
transform: translate($width);
}
+
+
+@media (max-width: 1700px) {
+ $width: 320px;
+
+ .baseMenu {
+ width: $width;
+ transform: translate($width);
+ }
+
+ .header-block {
+ padding: 30px;
+ }
+}
\ No newline at end of file
diff --git a/src/js/components/calculator/css/fonts.css b/src/js/components/calculator/css/fonts.css
new file mode 100644
index 0000000..7744f61
--- /dev/null
+++ b/src/js/components/calculator/css/fonts.css
@@ -0,0 +1,31 @@
+@font-face {
+ font-family: 'Crystal';
+ src: url('../../../../assets/fonts/fonts-calculator/Crystal.ttf')
+ format('truetype');
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Roboto';
+ src: url('../../../../assets/fonts/fonts-calculator/Roboto-Regular.ttf')
+ format('truetype');
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Roboto';
+ src: url('../../../../assets/fonts/fonts-calculator/Roboto-Bold.ttf')
+ format('truetype');
+ font-weight: 700;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Symbol';
+ src: url('../../../../assets/fonts/fonts-calculator/symbol.ttf')
+ format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
diff --git a/src/js/components/calculator/css/normalize.css b/src/js/components/calculator/css/normalize.css
new file mode 100644
index 0000000..cbe9a2e
--- /dev/null
+++ b/src/js/components/calculator/css/normalize.css
@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+/* main {
+ display: block;
+} */
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/src/js/components/calculator/css/style.css b/src/js/components/calculator/css/style.css
new file mode 100644
index 0000000..e13e3d0
--- /dev/null
+++ b/src/js/components/calculator/css/style.css
@@ -0,0 +1,170 @@
+* {
+ box-sizing: border-box;
+ font-family: Roboto, sans-serif;
+}
+
+.block.calc {
+ background-color: transparent;
+}
+
+.calculator {
+ /* width: 400px; */
+ min-height: 550px;
+ padding: 30px;
+ border-radius: 20px;
+ background-image: url('../../../../assets/img/metal.jpg');
+}
+
+@media only screen and (max-width: 540px) {
+ .calculator {
+ width: 320px;
+ height: 550px;
+ padding: 20px;
+ }
+}
+
+.output {
+ width: 100%;
+ margin-bottom: 30px;
+ background-color: rgba(0, 0, 0, 0.75);
+}
+
+.output .result,
+.output .expression {
+ height: 50px;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding-right: 10px;
+ overflow: hidden;
+}
+
+@media only screen and (max-width: 540px) {
+ .output .result,
+ .output .expression {
+ height: 50px;
+ }
+}
+
+.output .result p {
+ font-family: Crystal, sans-serif;
+ font-size: 35px;
+ line-height: 36px;
+ text-align: right;
+ word-wrap: break-word;
+ word-break: break-all;
+ color: rgba(255, 255, 255, 0.75);
+}
+
+@media only screen and (max-width: 540px) {
+ .output .result p {
+ font-size: 22px;
+ }
+}
+
+.output .expression p {
+ font-family: monospace;
+ font-size: 24px;
+ line-height: 140%;
+ text-align: right;
+ color: #b1ffb1;
+}
+
+@media only screen and (max-width: 540px) {
+ .output .expression p {
+ font-size: 18px;
+ }
+}
+
+.calculator-grid {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: stretch;
+}
+
+.calculator-grid > button {
+ cursor: pointer;
+ width: 70px;
+ height: 44px;
+ border-radius: 10px;
+ font-size: 30px;
+ border: none;
+ outline: none;
+ background-color: #ccc;
+ margin-right: 6px;
+ box-shadow: 2px 2px 2px 2px rgba(0, 0, 0, 0.5);
+}
+
+@media only screen and (max-width: 540px) {
+ .calculator-grid > button {
+ width: 55px;
+ height: 45px;
+ border-radius: 7px;
+ font-size: 30px;
+ }
+}
+
+.calculator-grid > button:nth-child(4n + 1) {
+ margin-right: 0;
+}
+
+.calculator-grid > button:hover {
+ background-color: rgba(255, 255, 255, 0.9);
+}
+
+.note {
+ width: 500px;
+ color: #fff;
+ background-color: rgba(0, 0, 0, 0.5);
+ padding: 20px;
+ margin: 0 auto;
+}
+
+@media only screen and (max-width: 540px) {
+ .note {
+ width: 320px;
+ }
+}
+
+.note h2 {
+ text-align: center;
+}
+
+@media only screen and (max-width: 540px) {
+ .note h2 {
+ font-size: 30px;
+ }
+}
+
+@media (max-width: 1699px) {
+ .calculator-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ grid-gap: 10px;
+ }
+
+ .output {
+ grid-column: 1/5;
+ }
+
+ .calculator-grid > button {
+ margin-right: 0;
+ width: 50px;
+ height: 44px;
+ border-radius: 10px;
+ font-size: 24px;
+ }
+}
+
+@media (max-width: 359px) {
+ .calculator {
+ width: 300px;
+ }
+
+ .note {
+ width: 300px;
+ }
+}
diff --git a/src/js/components/calculator/js/calculator.js b/src/js/components/calculator/js/calculator.js
new file mode 100644
index 0000000..1a44ff9
--- /dev/null
+++ b/src/js/components/calculator/js/calculator.js
@@ -0,0 +1,123 @@
+import { expressionCalculator, opPriorities } from './expression-calculator';
+import '../css/normalize.css';
+import '../css/fonts.css';
+import '../css/style.css';
+
+export class Calculator {
+ constructor(parentNode) {
+ this.parentNode = parentNode;
+ this.render();
+ this.result = 0;
+ this.resultElem = document.querySelector('[data-result]');
+ this.expression = '';
+ this.expressionElem = document.querySelector('[data-expression]');
+ this.addEventListeners();
+ }
+
+ handleBackspace() {
+ const len = this.expression.length;
+ this.expression = this.expression.substr(0, len - 1);
+ this.expressionElem.innerHTML = this.fixExpression(this.expression);
+ }
+
+ handleClearAll() {
+ this.result = 0;
+ this.expression = '';
+ this.expressionElem.innerText = this.expression;
+ this.resultElem.innerText = this.result;
+ }
+
+ handlePlusMinus() {
+ const length = this.expression.length;
+ const str = this.expression;
+ this.expression =
+ str[length - 1] === '!' ? str.substr(0, length - 1) : str + '!';
+ this.expressionElem.innerHTML = this.fixExpression(this.expression);
+ }
+
+ handleEqual() {
+ const isOp = opPriorities[this.expression[0]] ? true : false;
+ if (isOp) {
+ if (!isNaN(this.result)) {
+ this.result = expressionCalculator(this.result + this.expression);
+ }
+ } else {
+ this.result = expressionCalculator(this.expression);
+ }
+ this.resultElem.innerText = isNaN(this.result) ? 'Error' : this.result;
+ this.expression = '';
+ this.expressionElem.innerText = '';
+ }
+
+ fixExpression(expr) {
+ expr = expr.replaceAll('r', '√');
+ expr = expr.replaceAll('-', '—');
+ expr = expr.replaceAll('!', '‐');
+ return expr;
+ }
+
+ addEventListeners() {
+ const btns = document.querySelectorAll('[data-code]');
+ btns.forEach((elem) => {
+ elem.addEventListener('click', (evt) => {
+ const code = evt.target.dataset.code;
+ this.expression += code;
+ this.expressionElem.innerHTML = this.fixExpression(this.expression);
+ });
+ });
+
+ const backspaceButton = document.querySelector('[data-backspace]');
+ backspaceButton.addEventListener('click', () => this.handleBackspace());
+
+ const clearallButton = document.querySelector('[data-all-clear]');
+ clearallButton.addEventListener('click', () => this.handleClearAll());
+
+ const plusminusButton = document.querySelector('[data-plus-minus]');
+ plusminusButton.addEventListener('click', () => this.handlePlusMinus());
+
+ const equalsButton = document.querySelector('[data-equals]');
+ equalsButton.addEventListener('click', () => this.handleEqual());
+ }
+
+ render() {
+ this.parentNode.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+}
diff --git a/src/js/components/calculator/js/expression-calculator.js b/src/js/components/calculator/js/expression-calculator.js
new file mode 100644
index 0000000..4dc11d5
--- /dev/null
+++ b/src/js/components/calculator/js/expression-calculator.js
@@ -0,0 +1,121 @@
+export const opPriorities = {"+":1, "-":1, "/":2, "*":2, "r":3, "^":3};
+let num_stack = [];
+let op_stack = [];
+
+export function expressionCalculator(expr) {
+ let ret;
+ try {
+ if (checkBrackets(expr) == false) throw new Error('ExpressionError: Brackets must be paired');
+ let parsedExpr = parseString(expr);
+ let len = parsedExpr.length;
+
+ for(let i = 0; i < len; i++) {
+ if (typeof(parsedExpr[i]) == "number") num_stack.push(parsedExpr[i]);
+ else if (parsedExpr[i] == "(") op_stack.push(parsedExpr[i]);
+ else if (parsedExpr[i] == ")") {
+ while(op_stack[op_stack.length - 1] != '(') doOperations();
+ op_stack.pop();
+ }
+ else {
+ while(true) {
+ if(op_stack.length == 0 || op_stack[op_stack.length - 1] == '(' || opPriorities[parsedExpr[i]] > opPriorities[op_stack[op_stack.length - 1]]) {
+ op_stack.push(parsedExpr[i]);
+ break;
+ }
+ else doOperations();
+ }
+ }
+ }
+ while(op_stack.length != 0) doOperations();
+ ret = toFixed(num_stack.pop());
+ }
+ catch(err) {
+ console.log(err.message);
+ return NaN;
+ }
+ finally {
+ num_stack = [];
+ op_stack = [];
+ }
+ return ret;
+}
+
+function checkBrackets(expr) {
+ let open_brackets = 0;
+ let closed_brackets = 0;
+ let len = expr.length;
+ for(let i = 0; i < len; i++) {
+ if(expr[i] == '(') open_brackets++;
+ else if(expr[i] == ')') closed_brackets++;
+ }
+ if(open_brackets == closed_brackets) return true;
+ else return false;
+}
+
+function parseString(expr) {
+ let arr = [];
+ let len = expr.length;
+ let number = '';
+ for(let i = 0; i < len; i++) {
+ let code = expr.charCodeAt(i);
+ if(code >= 48 && code <=57 || code === '.'.charCodeAt() || code === '!'.charCodeAt()) number += expr[i];
+ else {
+ if(number != '') {
+ number = number.replace('!','-');
+ arr.push(parseFloat(number));
+ number = '';
+ }
+ if(expr[i] != ' ') arr.push(expr[i]);
+ }
+ }
+ if(number != '') {
+ number = number.replace('!','-');
+ arr.push(parseFloat(number));
+ }
+ return arr;
+}
+
+function doOperations() {
+ const cur_op = op_stack.pop();
+
+ let val;
+ if (cur_op === 'r') {
+ const x = num_stack.pop();
+ if(x < 0) {
+ throw new Error("Square root from negative number");
+ }
+ val = Math.sqrt(x);
+ } else {
+ const y = num_stack.pop();
+ const x = num_stack.pop();
+ val = calculateOperation(x, y, cur_op);
+ }
+ num_stack.push(val);
+}
+
+function calculateOperation(arg1, arg2, op) {
+ let res = 0;
+ switch (op) {
+ case '+':
+ res = arg1 + arg2; break;
+ case '-':
+ res = arg1 - arg2; break;
+ case '*':
+ res = arg1 * arg2; break;
+ case '/':
+ if(arg2 == 0) {
+ throw new Error("Division by zero");
+ }
+ res = arg1 / arg2; break;
+ case '%':
+ res = arg1 * arg2 / 100; break;
+ case '^':
+ res = Math.pow(arg1, arg2);
+ }
+ return res;
+}
+
+function toFixed(value) {
+ var power = Math.pow(10, 14);
+ return String(Math.round(value * power) / power);
+}
diff --git a/src/js/components/command-menu/command-menu.css b/src/js/components/command-menu/command-menu.css
index 7d4e9af..2c79ab5 100644
--- a/src/js/components/command-menu/command-menu.css
+++ b/src/js/components/command-menu/command-menu.css
@@ -1 +1,49 @@
-/* Стили списка команд */
\ No newline at end of file
+.menu-manager .menu-item:hover, .other-items .options:hover {
+ -webkit-transition: all 0.2s ease-in-out;
+ transition: all 0.2s ease-in-out;
+ background-color: rgba(78, 167, 166, 0.6);
+ border-radius: 9em;
+ -webkit-box-shadow: inset 1px 1px 10px #f3faf7;
+ box-shadow: inset 1px 1px 10px #f3faf7;
+}
+
+.menu-manager {
+ padding: 10px;
+}
+
+.menu-manager .menu-item {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ margin: 15px 10px;
+ padding: 6px;
+}
+
+.menu-manager .menu-item p {
+ margin: 0 15px;
+}
+
+.menu-manager .submit {
+ padding: 5px 10px;
+}
+
+.menu-manager .submit.active-item {
+ background-color: #dc3545;
+}
+
+.other-items {
+ padding: 10px;
+}
+
+.other-items .options {
+ cursor: pointer;
+ margin: 0px 10px;
+ padding: 6px 20px;
+}
+/*# sourceMappingURL=command-menu.css.map */
\ No newline at end of file
diff --git a/src/js/components/command-menu/command-menu.js b/src/js/components/command-menu/command-menu.js
index 4901190..02f804f 100644
--- a/src/js/components/command-menu/command-menu.js
+++ b/src/js/components/command-menu/command-menu.js
@@ -1,10 +1,105 @@
-import "./command-menu.css";
+import './command-menu.css';
import Menu from '../base-menu/baseMenu';
+import { classListBlocks } from '../../data/constants';
+import create from '../../utils/create';
+import OptionsMenu from '../options-menu/options-menu';
+
+const blockNames = [
+ 'Finance',
+ 'News (RSS)',
+ 'Popular likns',
+ 'Shops',
+ 'Travels',
+ 'Google',
+ 'Weather',
+ 'To Do',
+ 'Calculator',
+];
+
+const getClassListBlocks = () => {
+ let blockList = [];
+
+ const localBlockList = JSON.parse(localStorage.getItem('classListBlocks'));
+
+ if (localBlockList) {
+ blockList = localBlockList;
+ } else {
+ localStorage.setItem('classListBlocks', JSON.stringify(classListBlocks));
+ }
+ return blockList;
+};
class CommandMenu extends Menu {
- constructor(clickedElement, caption, obj) {
+ constructor(clickedElement, caption) {
super(clickedElement, caption);
+ this.managerBlock = create('div', 'menu-manager');
+ this.renderContent();
+ }
+
+ fillManagerBlock() {
+ this.managerBlock.innerHTML = '';
+
+ const localClassList = JSON.parse(localStorage.getItem('classListBlocks'));
+ localClassList.forEach((name, index) => {
+ const html = `${blockNames[index]}
+ `;
+ const item = create(
+ 'div',
+ `menu-item item-${name.class}`,
+ html,
+ this.managerBlock
+ );
+
+ const block = this.parentNode.querySelector(`.block.${name.class}`);
+
+ if (!name.active) block.classList.add('hidden-block');
+ if (name.active) {
+ block.classList.remove('hidden-block');
+ item.lastElementChild.textContent = 'hide';
+ item.lastElementChild.classList.add('active-item');
+ }
+ });
+ }
+
+ changePosition(e) {
+ const classId = e.target.dataset.btn;
+
+ const localClassList = JSON.parse(localStorage.getItem('classListBlocks'));
+
+ const newClassList = localClassList.map((item) => {
+ if (item.class === classId && item.active)
+ return { ...item, active: false };
+ if (item.class === classId && !item.active)
+ return { ...item, active: true };
+ return item;
+ });
+
+ localStorage.setItem('classListBlocks', JSON.stringify(newClassList));
+
+ this.fillManagerBlock();
+ this.addBtnListener();
+ }
+
+ addBtnListener() {
+ const buttons = this.parentNode.querySelectorAll('.menu-item .submit');
+ buttons.forEach((btn) => {
+ btn.onclick = this.changePosition.bind(this);
+ return btn;
+ });
+ }
+
+ renderContent() {
+ const contentBlock = document.querySelector('.menu-content.Main');
+ contentBlock.appendChild(this.managerBlock);
+
+ getClassListBlocks();
+ this.fillManagerBlock();
+ this.addBtnListener();
+
+ const otherMenuItems = create('div', 'other-items', '', contentBlock);
+ const options = create('div', 'options', 'Options', otherMenuItems);
+ this.optionsMenu = new OptionsMenu(options, 'Options');
}
}
diff --git a/src/js/components/command-menu/command-menu.scss b/src/js/components/command-menu/command-menu.scss
new file mode 100644
index 0000000..f949c76
--- /dev/null
+++ b/src/js/components/command-menu/command-menu.scss
@@ -0,0 +1,48 @@
+%hoverItem {
+ transition: all 0.2s ease-in-out;
+ background-color: rgba(78, 167, 166, 0.6);
+ border-radius: 9em;
+ box-shadow: inset 1px 1px 10px #f3faf7;
+}
+
+.menu-manager {
+ padding: 10px;
+
+ .menu-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 15px 10px;
+ padding: 6px;
+
+ p {
+ margin: 0 15px;
+ }
+
+ &:hover {
+ @extend %hoverItem;
+ }
+ }
+
+ .submit {
+ padding: 5px 10px;
+ }
+
+ .submit.active-item {
+ background-color: #dc3545;
+ }
+}
+
+.other-items {
+ padding: 10px;
+
+ .options {
+ cursor: pointer;
+ margin: 0px 10px;
+ padding: 6px 20px;
+
+ &:hover {
+ @extend %hoverItem;
+ }
+ }
+}
diff --git a/src/js/components/finance/finance-menu.js b/src/js/components/finance/finance-menu.js
new file mode 100644
index 0000000..8ac1f41
--- /dev/null
+++ b/src/js/components/finance/finance-menu.js
@@ -0,0 +1,38 @@
+// import './rss-menu.css';
+import Menu from '../base-menu/baseMenu';
+import create from '../../utils/create';
+
+class FinanceMenu extends Menu {
+ constructor(clickedElement, caption) {
+ super(clickedElement, caption);
+ this.renderContent();
+ }
+
+ addDangerBtn() {
+ const menuContent = this.parentNode.querySelector('.menu-content.Fina');
+
+ create(
+ 'div',
+ 'danger-block',
+ ``,
+ menuContent
+ );
+ }
+
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.finance');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector(`[data-btn="finance"]`);
+ mainMenuBtn.click();
+ this.hide.bind(this)();
+ });
+ }
+
+ renderContent() {
+ this.addDangerBtn();
+ this.addDangerBtnListener();
+ }
+}
+
+export default FinanceMenu;
diff --git a/src/js/components/finance/finance.css b/src/js/components/finance/finance.css
index 61d41ff..ac960da 100644
--- a/src/js/components/finance/finance.css
+++ b/src/js/components/finance/finance.css
@@ -3,7 +3,7 @@ h3 {
font-weight: bold;
padding: 10px 22px;
height: 45px;
- background-color: #EEEEEE;
+ background-color: #eeeeee;
}
.currencyList {
@@ -20,15 +20,24 @@ h3 {
margin: 5px;
}
-.currencyChoiceBlock {
+.wrapCurrencyChoiceBlock {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
-ms-flex-pack: distribute;
justify-content: space-around;
+ margin: 0 5px;
+}
+
+.currencyChoiceBlock select:last-child {
+ margin-left: 10px;
}
#line-chart {
height: 300px;
+ width: 100%;
+ padding: 5px;
}
/*# sourceMappingURL=finance.css.map */
\ No newline at end of file
diff --git a/src/js/components/finance/finance.js b/src/js/components/finance/finance.js
index 5ff56a8..5947245 100644
--- a/src/js/components/finance/finance.js
+++ b/src/js/components/finance/finance.js
@@ -1,35 +1,36 @@
-import "./finance.css";
-import Chart from "chart.js";
+import './finance.css';
+import Chart from 'chart.js';
+import FinanceMenu from './finance-menu';
-const nbrbURL = "https://www.nbrb.by/api/exrates/rates?periodicity=0";
+const nbrbURL = 'https://www.nbrb.by/api/exrates/rates?periodicity=0';
const extraCurrencyData = [
- { Cur_Abbreviation: "AUD", Cur_ID: 170, Cur_Scale: 1 },
- { Cur_Abbreviation: "BGN", Cur_ID: 191, Cur_Scale: 1 },
- { Cur_Abbreviation: "UAH", Cur_ID: 290, Cur_Scale: 100 },
- { Cur_Abbreviation: "DKK", Cur_ID: 291, Cur_Scale: 10 },
- { Cur_Abbreviation: "USD", Cur_ID: 145, Cur_Scale: 1 },
- { Cur_Abbreviation: "EUR", Cur_ID: 292, Cur_Scale: 1 },
- { Cur_Abbreviation: "PLN", Cur_ID: 293, Cur_Scale: 10 },
- { Cur_Abbreviation: "JPY", Cur_ID: 355, Cur_Scale: 100 },
- { Cur_Abbreviation: "IRR", Cur_ID: 303, Cur_Scale: 100000 },
- { Cur_Abbreviation: "ISK", Cur_ID: 294, Cur_Scale: 100 },
- { Cur_Abbreviation: "CAD", Cur_ID: 23, Cur_Scale: 1 },
- { Cur_Abbreviation: "CNY", Cur_ID: 304, Cur_Scale: 10 },
- { Cur_Abbreviation: "KWD", Cur_ID: 72, Cur_Scale: 1 },
- { Cur_Abbreviation: "MDL", Cur_ID: 296, Cur_Scale: 10 },
- { Cur_Abbreviation: "NZD", Cur_ID: 286, Cur_Scale: 1 },
- { Cur_Abbreviation: "NOK", Cur_ID: 297, Cur_Scale: 10 },
- { Cur_Abbreviation: "RUB", Cur_ID: 298, Cur_Scale: 100 },
- { Cur_Abbreviation: "XDR", Cur_ID: 299, Cur_Scale: 1 },
- { Cur_Abbreviation: "SGD", Cur_ID: 119, Cur_Scale: 1 },
- { Cur_Abbreviation: "KGS", Cur_ID: 300, Cur_Scale: 100 },
- { Cur_Abbreviation: "KZT", Cur_ID: 301, Cur_Scale: 1000 },
- { Cur_Abbreviation: "TRY", Cur_ID: 302, Cur_Scale: 10 },
- { Cur_Abbreviation: "GBP", Cur_ID: 143, Cur_Scale: 1 },
- { Cur_Abbreviation: "CZK", Cur_ID: 305, Cur_Scale: 100 },
- { Cur_Abbreviation: "SEK", Cur_ID: 306, Cur_Scale: 10 },
- { Cur_Abbreviation: "CHF", Cur_ID: 130, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'AUD', Cur_ID: 170, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'BGN', Cur_ID: 191, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'UAH', Cur_ID: 290, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'DKK', Cur_ID: 291, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'USD', Cur_ID: 145, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'EUR', Cur_ID: 292, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'PLN', Cur_ID: 293, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'JPY', Cur_ID: 355, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'IRR', Cur_ID: 303, Cur_Scale: 100000 },
+ { Cur_Abbreviation: 'ISK', Cur_ID: 294, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'CAD', Cur_ID: 23, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'CNY', Cur_ID: 304, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'KWD', Cur_ID: 72, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'MDL', Cur_ID: 296, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'NZD', Cur_ID: 286, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'NOK', Cur_ID: 297, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'RUB', Cur_ID: 298, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'XDR', Cur_ID: 299, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'SGD', Cur_ID: 119, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'KGS', Cur_ID: 300, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'KZT', Cur_ID: 301, Cur_Scale: 1000 },
+ { Cur_Abbreviation: 'TRY', Cur_ID: 302, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'GBP', Cur_ID: 143, Cur_Scale: 1 },
+ { Cur_Abbreviation: 'CZK', Cur_ID: 305, Cur_Scale: 100 },
+ { Cur_Abbreviation: 'SEK', Cur_ID: 306, Cur_Scale: 10 },
+ { Cur_Abbreviation: 'CHF', Cur_ID: 130, Cur_Scale: 1 },
];
const getRateForDayRequest = async () => {
@@ -48,9 +49,9 @@ const getRateForDayRequest = async () => {
const getCurrencyPairData = async () => {
const data = await getRateForDayRequest();
- const eur = data.find((currency) => currency.Cur_Abbreviation === "EUR");
- const usd = data.find((currency) => currency.Cur_Abbreviation === "USD");
- const rub = data.find((currency) => currency.Cur_Abbreviation === "RUB");
+ const eur = data.find((currency) => currency.Cur_Abbreviation === 'EUR');
+ const usd = data.find((currency) => currency.Cur_Abbreviation === 'USD');
+ const rub = data.find((currency) => currency.Cur_Abbreviation === 'RUB');
return {
eur,
usd,
@@ -60,7 +61,7 @@ const getCurrencyPairData = async () => {
const getDataForChart = async (currencyId) => {
const currentDate = new Date();
- const dataDate = currentDate.toString().split(" ");
+ const dataDate = currentDate.toString().split(' ');
const day = dataDate[0];
const month = dataDate[1];
const date = dataDate[2];
@@ -68,7 +69,7 @@ const getDataForChart = async (currencyId) => {
const responseForYear = await fetch(
`https://www.nbrb.by/API/ExRates/Rates/Dynamics/${currencyId}
- ?startDate=Tue%2C+31+Dec+2019+21%3A00%3A00+GMT&endDate=${day}
+ ?startDate=Tue%2C+3+Mar+2020+21%3A00%3A00+GMT&endDate=${day}
%2C+${date}+${month}+${year}+21%3A00%3A00+GMT`
);
@@ -77,8 +78,8 @@ const getDataForChart = async (currencyId) => {
class Finance {
constructor(parentNode) {
this.parentNode = parentNode;
- this.currencyList = document.createElement("div");
- this.currencyChoiceBlock = document.createElement("div");
+ this.currencyList = document.createElement('div');
+ this.currencyChoiceBlock = document.createElement('div');
this.chart = false;
this.render();
}
@@ -86,10 +87,10 @@ class Finance {
async createPairEurUsd() {
const { eur, usd } = await getCurrencyPairData();
- const eurUsd = document.createElement("p");
+ const eurUsd = document.createElement('p');
- this.currencyList.classList.add("currencyList");
- eurUsd.classList.add("eurUsd");
+ this.currencyList.classList.add('currencyList');
+ eurUsd.classList.add('eurUsd');
eurUsd.textContent = `EUR/USD: ${(
eur.Cur_OfficialRate /
@@ -102,9 +103,9 @@ class Finance {
async createPairEurRub() {
const { eur, rub } = await getCurrencyPairData();
- const eurRub = document.createElement("p");
+ const eurRub = document.createElement('p');
- eurRub.classList.add("eurRub");
+ eurRub.classList.add('eurRub');
eurRub.textContent = `EUR/RUB: ${(
eur.Cur_OfficialRate /
@@ -117,9 +118,9 @@ class Finance {
async createPairBlrUsd() {
const { usd } = await getCurrencyPairData();
- const blrUsd = document.createElement("p");
+ const blrUsd = document.createElement('p');
- blrUsd.classList.add("blrUsd");
+ blrUsd.classList.add('blrUsd');
blrUsd.textContent = `USD/BLR: ${(
usd.Cur_OfficialRate / usd.Cur_Scale
@@ -129,13 +130,13 @@ class Finance {
}
createSelect(selectName, selectedItem) {
- const select = document.createElement("select");
+ const select = document.createElement('select');
select.name = selectName;
const fragment = document.createDocumentFragment();
extraCurrencyData.forEach((currency) => {
- const option = document.createElement("option");
+ const option = document.createElement('option');
option.value = `${currency.Cur_ID}`;
if (currency.Cur_Abbreviation === selectedItem) option.selected = true;
option.textContent = `${currency.Cur_Abbreviation}`;
@@ -149,25 +150,32 @@ class Finance {
}
renderCurrencyChoiceBlock() {
- this.currencyChoiceBlock.classList.add("currencyChoiceBlock");
- this.currencyChoiceBlock.textContent = "Select currency pair ";
- this.parentNode.appendChild(this.currencyChoiceBlock);
+ const wrapCurrencyChoiceBlock = document.createElement('div');
+ const titleCurrencyChoiceBlock = document.createElement('div');
+
+ titleCurrencyChoiceBlock.textContent = 'Select currency pair ';
+ wrapCurrencyChoiceBlock.classList.add('wrapCurrencyChoiceBlock');
+ this.currencyChoiceBlock.classList.add('currencyChoiceBlock');
+
+ wrapCurrencyChoiceBlock.appendChild(titleCurrencyChoiceBlock);
+ wrapCurrencyChoiceBlock.appendChild(this.currencyChoiceBlock);
+ this.parentNode.appendChild(wrapCurrencyChoiceBlock);
}
axesLinearChart(updatedDate, currencyDynamic, rateCurrencyPair) {
if (this.chart) {
- const previousChart = document.querySelector(".chartBlock");
+ const previousChart = document.querySelector('.chartBlock');
previousChart.parentElement.removeChild(previousChart);
}
- const chartBlock = document.createElement("div");
- chartBlock.classList.add("chartBlock");
- chartBlock.innerHTML = ``;
+ const chartBlock = document.createElement('div');
+ chartBlock.classList.add('chartBlock');
+ chartBlock.innerHTML = ``;
this.parentNode.appendChild(chartBlock);
- const ctx = document.getElementById("line-chart").getContext("2d");
+ const ctx = document.getElementById('line-chart').getContext('2d');
this.chart = new Chart(ctx, {
- type: "line",
+ type: 'line',
data: {
datasets: [
{
@@ -176,8 +184,8 @@ class Finance {
} Rate: ${rateCurrencyPair}`,
data: currencyDynamic,
fill: false,
- borderColor: "red",
- backgroundColor: "red",
+ borderColor: 'red',
+ backgroundColor: 'red',
radius: 1,
borderWidth: 1,
},
@@ -211,7 +219,7 @@ class Finance {
dates.forEach((dateItem) => shortDates.push(dateItem.slice(0, 10)));
- if (select === "selectLeft") {
+ if (select === 'selectLeft') {
currencyDynamicsLeft = [];
yearData.forEach((val) =>
currencyDynamicsLeft.push(
@@ -219,7 +227,7 @@ class Finance {
)
);
}
- if (select === "selectRight") {
+ if (select === 'selectRight') {
currencyDynamicsRight = [];
yearData.forEach((val) =>
currencyDynamicsRight.push(
@@ -240,9 +248,9 @@ class Finance {
);
};
- getYearCurrencyData(292, "selectLeft");
+ getYearCurrencyData(292, 'selectLeft');
setTimeout(() => {
- getYearCurrencyData(145, "selectRight");
+ getYearCurrencyData(145, 'selectRight');
}, 0);
let flag = false;
@@ -255,23 +263,33 @@ class Finance {
}
}
- const selectLeft = await this.createSelect("selectLeft", "EUR");
- const selectRight = await this.createSelect("selectRight", "USD");
+ const selectLeft = await this.createSelect('selectLeft', 'EUR');
+ const selectRight = await this.createSelect('selectRight', 'USD');
- selectLeft.addEventListener("click", addClickedCurrency);
- selectRight.addEventListener("click", addClickedCurrency);
+ selectLeft.addEventListener('click', addClickedCurrency);
+ selectRight.addEventListener('click', addClickedCurrency);
}
render() {
- const caption = document.createElement("h3");
- caption.textContent = "Finance";
- this.parentNode.appendChild(caption);
+ this.parentNode.innerHTML = `
+
+ `;
this.createPairEurUsd();
this.createPairEurRub();
this.createPairBlrUsd();
this.parentNode.appendChild(this.currencyList);
this.renderCurrencyChoiceBlock();
this.getFinanceData();
+
+ this.btnMenu = this.parentNode.querySelector('.dot-menu');
+ this.rssMenu = new FinanceMenu(this.btnMenu, 'Finance');
}
}
diff --git a/src/js/components/finance/finance.scss b/src/js/components/finance/finance.scss
index 44aa675..03a0460 100644
--- a/src/js/components/finance/finance.scss
+++ b/src/js/components/finance/finance.scss
@@ -3,24 +3,36 @@ h3 {
font-weight: bold;
padding: 10px 22px;
height: 45px;
- background-color: #EEEEEE;
+ background-color: #eeeeee;
}
-.currencyList{
+.currencyList {
display: flex;
justify-content: space-between;
}
-.currencyList p{
+.currencyList p {
font-size: 0.7rem;
margin: 5px;
}
-.currencyChoiceBlock{
+.wrapCurrencyChoiceBlock {
display: flex;
+ flex-wrap: wrap;
justify-content: space-around;
+ margin: 0 5px;
}
-#line-chart{
+.currencyChoiceBlock {
+ select {
+ &:last-child {
+ margin-left: 10px;
+ }
+ }
+}
+
+#line-chart {
height: 300px;
-}
\ No newline at end of file
+ width: 100%;
+ padding: 5px;
+}
diff --git a/src/js/components/footer/footer.css b/src/js/components/footer/footer.css
index aaff4c0..002b683 100644
--- a/src/js/components/footer/footer.css
+++ b/src/js/components/footer/footer.css
@@ -12,7 +12,7 @@ footer {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
- height: 50px;
+ min-height: 50px;
padding: 0 40px;
background-color: var(--accent-color-contrast);
color: var(--header-footer-text-color);
@@ -49,4 +49,28 @@ footer span {
height: 35px;
margin-right: 10px;
}
+
+@media (max-width: 767px) {
+ footer {
+ padding: 0 20px 10px 20px;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ }
+ footer .rsschool-logo {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ }
+ footer .github-logo {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ }
+ footer a {
+ font-size: 0.8rem;
+ margin: 0 5px;
+ text-align: center;
+ }
+}
/*# sourceMappingURL=footer.css.map */
\ No newline at end of file
diff --git a/src/js/components/footer/footer.scss b/src/js/components/footer/footer.scss
index 33d4a96..2ddba42 100644
--- a/src/js/components/footer/footer.scss
+++ b/src/js/components/footer/footer.scss
@@ -4,7 +4,7 @@ footer {
flex: 0 0 auto;
justify-content: space-between;
align-items: center;
- height: 50px;
+ min-height: 50px;
padding: 0 40px;
background-color: var(--accent-color-contrast);
color: var(--header-footer-text-color);
@@ -35,3 +35,25 @@ footer span {
height: 35px;
margin-right: 10px;
}
+
+@media (max-width: 767px) {
+ footer {
+ padding: 0 20px 10px 20px;
+ flex-wrap: wrap;
+ justify-content: center;
+
+ .rsschool-logo {
+ transform: scale(0.8);
+ }
+
+ .github-logo {
+ transform: scale(0.8);
+ }
+
+ a {
+ font-size: 0.8rem;
+ margin: 0 5px;
+ text-align: center;
+ }
+ }
+}
diff --git a/src/js/components/google-menu/google-menu.js b/src/js/components/google-menu/google-menu.js
index eeddf97..a3b1d84 100644
--- a/src/js/components/google-menu/google-menu.js
+++ b/src/js/components/google-menu/google-menu.js
@@ -1,19 +1,29 @@
// import "./google-menu.css";
-import { fullGoogleLinks, faviconUrl } from "../../data/constants";
-import Menu from "../base-menu/baseMenu";
-import Google from "../google/google";
+import { fullGoogleLinks, faviconUrl } from '../../data/constants';
+import Menu from '../base-menu/baseMenu';
+import Google from '../google/google';
+import { getOptionItems } from '../options-menu/options-menu';
+
+const getImage = (website) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`;
+ } else {
+ img = '';
+ }
+ return img;
+};
const getFullLinks = () => {
let fullLinks = [];
- const localGoogleLinks = JSON.parse(
- localStorage.getItem("fullGoogleLinks")
- );
+ const localGoogleLinks = JSON.parse(localStorage.getItem('fullGoogleLinks'));
if (localGoogleLinks) {
fullLinks = localGoogleLinks;
} else {
fullLinks = fullGoogleLinks;
- localStorage.setItem("fullGoogleLinks", JSON.stringify(fullGoogleLinks));
+ localStorage.setItem('fullGoogleLinks', JSON.stringify(fullGoogleLinks));
}
return fullLinks;
};
@@ -21,13 +31,13 @@ const getFullLinks = () => {
const getGoogleLinks = () => {
let googleLinks = [];
- const localGoogleLinks = JSON.parse(localStorage.getItem("googleLinks"));
+ const localGoogleLinks = JSON.parse(localStorage.getItem('googleLinks'));
if (localGoogleLinks) {
googleLinks = localGoogleLinks;
} else {
googleLinks = fullGoogleLinks.slice(0, 7);
- localStorage.setItem("googleLinks", JSON.stringify(googleLinks));
+ localStorage.setItem('googleLinks', JSON.stringify(googleLinks));
}
return googleLinks;
};
@@ -45,8 +55,8 @@ class GoogleMenu extends Menu {
(website) => website.title === title
);
- let check = "";
- if (activeLinks) check = "checked";
+ let check = '';
+ if (activeLinks) check = 'checked';
return check;
}
@@ -67,36 +77,36 @@ class GoogleMenu extends Menu {
localGoogleLinks.push(necessaryService);
}
- localStorage.setItem("googleLinks", JSON.stringify(localGoogleLinks));
+ localStorage.setItem('googleLinks', JSON.stringify(localGoogleLinks));
}
clearMenuContent() {
const websites = document.querySelectorAll(`.website.google`);
websites.forEach((link) => link.parentElement.removeChild(link));
- const nameWebsite = document.querySelector(".name-input.google");
- const urlWebsite = document.querySelector(".url-input.google");
+ const nameWebsite = document.querySelector('.name-input.google');
+ const urlWebsite = document.querySelector('.url-input.google');
- if (nameWebsite) nameWebsite.value = "";
- if (urlWebsite) urlWebsite.value = "";
+ if (nameWebsite) nameWebsite.value = '';
+ if (urlWebsite) urlWebsite.value = '';
}
fillMenuContent() {
this.clearMenuContent();
- const menuContent = document.querySelector(".menu-content.Goog");
+ const menuContent = document.querySelector('.menu-content.Goog');
const fragment = document.createDocumentFragment();
const fullLocalLinks = getFullLinks();
fullLocalLinks.forEach((website) => {
const check = this.findActiveWebsite(website.title);
- const web = document.createElement("div");
- web.classList.add("website", "google");
+ const web = document.createElement('div');
+ web.classList.add('website', 'google');
web.innerHTML = `
`;
@@ -106,9 +116,9 @@ class GoogleMenu extends Menu {
}
createForm() {
- const menuContent = document.querySelector(".menu-content.Goog");
- const form = document.createElement("div");
- form.classList.add("form");
+ const menuContent = document.querySelector('.menu-content.Goog');
+ const form = document.createElement('div');
+ form.classList.add('form');
form.innerHTML = `
@@ -121,14 +131,17 @@ class GoogleMenu extends Menu {
+
+
+
`;
menuContent.appendChild(form);
}
createObjForSet() {
- const nameWebsite = document.querySelector(".name-input.google");
- const urlWebsite = document.querySelector(".url-input.google");
+ const nameWebsite = document.querySelector('.name-input.google');
+ const urlWebsite = document.querySelector('.url-input.google');
const title = nameWebsite.value;
const url = urlWebsite.value;
@@ -148,31 +161,30 @@ class GoogleMenu extends Menu {
const data = this.createObjForSet();
if (data) {
const fullLocalLinks = JSON.parse(
- localStorage.getItem("fullGoogleLinks")
+ localStorage.getItem('fullGoogleLinks')
);
fullLocalLinks.push(data);
- localStorage.setItem("fullGoogleLinks", JSON.stringify(fullLocalLinks));
+ localStorage.setItem('fullGoogleLinks', JSON.stringify(fullLocalLinks));
}
}
cleanLocalLinks() {
- localStorage.removeItem("fullGoogleLinks");
- localStorage.removeItem("googleLinks");
- Google.prototype.fillContentBlock(this.privateClass, "googleLinks");
+ localStorage.removeItem('fullGoogleLinks');
+ localStorage.removeItem('googleLinks');
+ Google.prototype.fillContentBlock(this.privateClass, 'googleLinks');
}
changeLinks(e) {
const websiteClickedCheckbox = e.target.dataset.google;
const activeWebsite = this.findActiveWebsite(websiteClickedCheckbox);
- console.log(activeWebsite, websiteClickedCheckbox);
this.changeWebsiteArray(activeWebsite, websiteClickedCheckbox);
- Google.prototype.fillContentBlock(this.privateClass, "googleLinks");
+ Google.prototype.fillContentBlock(this.privateClass, 'googleLinks');
}
addListenerToBtn() {
const btnSub = document.querySelector(`.submit.google`);
- btnSub.addEventListener("click", () => {
+ btnSub.addEventListener('click', () => {
this.createObjForSet.bind(this)();
this.setObjData.bind(this)();
this.fillMenuContent.bind(this)();
@@ -182,7 +194,7 @@ class GoogleMenu extends Menu {
addListenerToDelBtn() {
const btnDel = document.querySelector(`.delete.google`);
- btnDel.addEventListener("click", () => {
+ btnDel.addEventListener('click', () => {
this.cleanLocalLinks();
this.fillMenuContent.bind(this)();
this.addListenerToLabel.bind(this)();
@@ -192,16 +204,31 @@ class GoogleMenu extends Menu {
addListenerToLabel() {
const labels = this.parentNode.querySelectorAll(`.input-google`);
labels.forEach((label) =>
- label.addEventListener("click", this.changeLinks.bind(this))
+ label.addEventListener('click', this.changeLinks.bind(this))
);
}
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.google');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector('[data-btn="google"]');
+ const btnDel = document.querySelector('.delete.google');
+
+ mainMenuBtn.click();
+ btnDel.click();
+
+ this.hide.bind(this)();
+ });
+ }
+
renderContent() {
this.fillMenuContent();
this.createForm();
this.addListenerToLabel();
this.addListenerToBtn();
this.addListenerToDelBtn();
+ this.addDangerBtnListener();
}
}
diff --git a/src/js/components/google/google.js b/src/js/components/google/google.js
index 4456c97..f9ce6a0 100644
--- a/src/js/components/google/google.js
+++ b/src/js/components/google/google.js
@@ -2,7 +2,29 @@
import "./google.css";
import { fullGoogleLinks } from "../../data/constants";
import GoogleMenu from "../google-menu/google-menu";
+import { getOptionItems } from "../options-menu/options-menu";
+const getImage = (url) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`
+ } else {
+ img = '';
+ }
+ return img;
+}
+
+const getTargetBlank = () => {
+ let targetBlank;
+ const optionTarget = getOptionItems()[1];
+ if (optionTarget.checked) {
+ targetBlank = '_blank'
+ } else {
+ targetBlank = ''
+ }
+ return targetBlank;
+}
class Google {
constructor(obj) {
this.parentNode = obj.parentNode;
@@ -43,8 +65,8 @@ class Google {
website.classList.add("websites", `${myClass}`);
website.innerHTML = `
-
-
+
+ ${getImage(web.favicon)}
${web.title}
`;
diff --git a/src/js/components/header/header.css b/src/js/components/header/header.css
index e28019d..0046fd0 100644
--- a/src/js/components/header/header.css
+++ b/src/js/components/header/header.css
@@ -21,4 +21,12 @@ h1 {
font-size: 30px;
color: var(--header-footer-text-color);
}
+
+.login-btn {
+ background: transparent;
+ color: var(--header-footer-text-color);
+ cursor: pointer;
+ outline: none;
+ border: none;
+}
/*# sourceMappingURL=header.css.map */
\ No newline at end of file
diff --git a/src/js/components/header/header.js b/src/js/components/header/header.js
index 2523c4e..0d28584 100644
--- a/src/js/components/header/header.js
+++ b/src/js/components/header/header.js
@@ -2,6 +2,9 @@ import './header.css';
import * as Constants from '../../data/constants';
import create from '../../utils/create';
import Pages from '../pages/pages';
+import {Auth} from '../auth/auth';
+import * as RemoteAuth from '../../services/auth';
+
import CommandMenu from '../command-menu/command-menu';
class Header {
@@ -12,16 +15,45 @@ class Header {
render() {
const img = document.createElement('img');
- img.src = "./img/sp.jpg";
+ img.src = "./img/sp.jpg";
this.pages = new Pages();
+ const isLogged = RemoteAuth.isLogged();
+ const btnLoginCaption = (isLogged) ? `Logout
` : `Login
`;
+ this.btnLogin = create('button', 'login-btn', btnLoginCaption);
this.btnMenu = create('button', 'menu-btn', `
`);
- this.header = create('header', 'header', [img, this.pages.getMenu(), this.btnMenu], this.parentNode);
+ this.header = create('header', 'header', [img, this.pages.getMenu(), this.btnLogin, this.btnMenu], this.parentNode);
+ const handler = (isLogged) ? this.logout.bind(this) : this.showLoginForm.bind(this);
+ this.btnLogin.addEventListener('click', handler);
this.showMenu();
}
showMenu() {
- this.sideMenu = new CommandMenu(this.btnMenu, 'Main Menu');
- }
+ setTimeout(() => {
+ this.sideMenu = new CommandMenu(this.btnMenu, 'Main Menu');
+ }, 0);
+ }
+
+ showLoginForm() {
+ this.auth = new Auth(true);
+ }
+
+ deleteLoginForm() {
+ this.auth = null;
+ console.log('delete');
+ }
+
+ logout() {
+// localStorage.removeItem(Constants.userItemLocalStorage);
+ this.btnLogin.removeEventListener('click', this.logout.bind(this));
+ this.btnLogin.addEventListener('click', this.showLoginForm.bind(this));
+ this.btnLogin.innerText = 'Login';
+ }
+
+ setLogged() {
+ this.btnLogin.addEventListener('click', this.logout.bind(this));
+ this.btnLogin.removeEventListener('click', this.showLoginForm.bind(this));
+ this.btnLogin.innerText = 'Logout';
+ }
}
export default Header;
diff --git a/src/js/components/main/main.css b/src/js/components/main/main.css
index 2b42e5f..0189c10 100644
--- a/src/js/components/main/main.css
+++ b/src/js/components/main/main.css
@@ -1,13 +1,24 @@
main {
- flex: 1 0 auto;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
padding: 20px;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
}
.container {
float: left;
- column-width: auto;
- column-count: 4;
- column-gap: 20px;
+ -webkit-column-width: auto;
+ column-width: auto;
+ -webkit-column-count: 4;
+ column-count: 4;
+ -webkit-column-gap: 20px;
+ column-gap: 20px;
}
.block {
@@ -19,41 +30,89 @@ main {
}
.masonry {
- margin: 0;
+ margin: 0;
+ display: -ms-grid;
display: grid;
- grid-template-rows: 1fr auto;
+ -ms-grid-rows: 1fr auto;
+ grid-template-rows: 1fr auto;
margin-bottom: 20px;
- break-inside: avoid;
+ -webkit-column-break-inside: avoid;
+ break-inside: avoid;
}
.bl1 {
- height: 400px;
+ height: 400px;
}
+
.bl2 {
- height: 500px;
+ height: 500px;
}
+
.bl3 {
- height: 600px;
+ height: 600px;
}
+
.bl4 {
- height: 350px;
+ height: 350px;
}
+
.bl5 {
- height: 300px;
+ height: 300px;
}
+
.bl6 {
- height: 250px;
+ height: 250px;
}
+
.bl7 {
- height: 600px;
+ height: 600px;
}
+
.bl8 {
- height: 450px;
+ height: 450px;
}
+
.bl9 {
- height: 350px;
+ height: 350px;
}
+.block.hidden-block {
+ display: none;
+}
+@media (max-width: 1699px) {
+ .block {
+ width: 320px;
+ }
+}
+
+@media (max-width: 1379px) {
+ .container {
+ -webkit-column-count: 3;
+ column-count: 3;
+ }
+}
+
+@media (max-width: 1079px) {
+ .container {
+ -webkit-column-count: 2;
+ column-count: 2;
+ }
+}
+
+@media (max-width: 767px) {
+ main {
+ padding: 20px 0;
+ }
+ .container {
+ -webkit-column-count: 1;
+ column-count: 1;
+ }
+}
+@media (max-width: 359px) {
+ .block {
+ width: 300px;
+ }
+}
/*# sourceMappingURL=main.css.map */
\ No newline at end of file
diff --git a/src/js/components/main/main.js b/src/js/components/main/main.js
index 4b3ddd9..c05ab01 100644
--- a/src/js/components/main/main.js
+++ b/src/js/components/main/main.js
@@ -1,11 +1,14 @@
-import "./main.css";
+import './main.css';
import create from '../../utils/create';
-import Finance from "../finance/finance";
-import Rss from "../rss-news/rss";
-import Popular from "../popular-links/popular";
-import Shops from "../shops/shops";
-import Travel from "../travel/travel";
-import Google from "../google/google";
+import Finance from '../finance/finance';
+import Rss from '../rss-news/rss';
+import Popular from '../popular-links/popular';
+import Shops from '../shops/shops';
+import Travel from '../travel/travel';
+import Google from '../google/google';
+import Weather from '../weather/weather';
+import ToDo from '../todo/todo';
+import { Calculator } from '../calculator/js/calculator';
class Main {
constructor(parentNode) {
@@ -14,58 +17,73 @@ class Main {
}
render() {
- const main = create("main", "", null, this.parentNode);
- const container = create("div", "container", null, main);
+ const main = create('main', '', null, this.parentNode);
+ const container = create('div', 'container', null, main);
- const financeContainer = document.createElement("div");
- financeContainer.classList.add("block", "finance", "masonry");
+ const financeContainer = document.createElement('div');
+ financeContainer.classList.add('block', 'finance', 'masonry');
container.appendChild(financeContainer);
this.fin = new Finance(financeContainer);
- const rssNewsContainer = document.createElement("div");
- rssNewsContainer.classList.add("block", "rss", "masonry");
+ const rssNewsContainer = document.createElement('div');
+ rssNewsContainer.classList.add('block', 'rss', 'masonry');
container.appendChild(rssNewsContainer);
this.rss = new Rss(rssNewsContainer);
- const popularContainer = document.createElement("div");
- popularContainer.classList.add("block", "popular", "masonry");
+ const popularContainer = document.createElement('div');
+ popularContainer.classList.add('block', 'popular', 'masonry');
container.appendChild(popularContainer);
this.popularContainer = new Popular({
parentNode: popularContainer,
- privateClass: "popular",
- caption: "Popular links",
- arrayDataName: "popularLinks",
+ privateClass: 'popular',
+ caption: 'Popular links',
+ arrayDataName: 'popularLinks',
});
- const shopsContainer = document.createElement("div");
- shopsContainer.classList.add("block", "shops", "masonry");
+ const shopsContainer = document.createElement('div');
+ shopsContainer.classList.add('block', 'shops', 'masonry');
container.appendChild(shopsContainer);
this.shopsContainer = new Shops({
parentNode: shopsContainer,
- privateClass: "shops",
- caption: "Shops",
- arrayDataName: "shopsLinks",
+ privateClass: 'shops',
+ caption: 'Shops',
+ arrayDataName: 'shopsLinks',
});
- const travelContainer = document.createElement("div");
- travelContainer.classList.add("block", "travel", "masonry");
+ const travelContainer = document.createElement('div');
+ travelContainer.classList.add('block', 'travel', 'masonry');
container.appendChild(travelContainer);
this.travelContainer = new Travel({
parentNode: travelContainer,
- privateClass: "travel",
- caption: "Travels",
- arrayDataName: "travelLinks",
+ privateClass: 'travel',
+ caption: 'Travels',
+ arrayDataName: 'travelLinks',
});
- const googleContainer = document.createElement("div");
- googleContainer.classList.add("block", "google", "masonry");
+ const googleContainer = document.createElement('div');
+ googleContainer.classList.add('block', 'google', 'masonry');
container.appendChild(googleContainer);
this.googleContainer = new Google({
parentNode: googleContainer,
- privateClass: "google",
- caption: "Google",
- arrayDataName: "googleLinks",
+ privateClass: 'google',
+ caption: 'Google',
+ arrayDataName: 'googleLinks',
});
+
+ const weatherContainer = document.createElement('div');
+ weatherContainer.classList.add('block', 'weather', 'masonry');
+ container.appendChild(weatherContainer);
+ this.weatherContainer = new Weather(weatherContainer);
+
+ const toDoContainer = document.createElement('div');
+ toDoContainer.classList.add('block', 'todo', 'masonry');
+ container.appendChild(toDoContainer);
+ this.toDoContainer = new ToDo(toDoContainer);
+
+ const calc = document.createElement('div');
+ calc.classList.add('block', 'calc', 'masonry');
+ container.appendChild(calc);
+ this.calc = new Calculator(calc);
}
}
diff --git a/src/js/components/main/main.scss b/src/js/components/main/main.scss
index 19d261e..5475f87 100644
--- a/src/js/components/main/main.scss
+++ b/src/js/components/main/main.scss
@@ -1,15 +1,94 @@
main {
- width: 100%;
- height: calc(100vh - 120px);
- background-color: var(--accent-color-light);
+ flex: 1 0 auto;
padding: 20px;
display: flex;
- flex-wrap: wrap;
+ justify-content: center;
+}
+
+.container {
+ float: left;
+ column-width: auto;
+ column-count: 4;
+ column-gap: 20px;
}
.block {
width: 400px;
background-color: var(--app-background-color);
- margin: 5px;
+ height: -webkit-fit-content;
+ height: -moz-fit-content;
height: fit-content;
}
+
+.masonry {
+ margin: 0;
+ display: grid;
+ grid-template-rows: 1fr auto;
+ margin-bottom: 20px;
+ break-inside: avoid;
+}
+
+.bl1 {
+ height: 400px;
+}
+.bl2 {
+ height: 500px;
+}
+.bl3 {
+ height: 600px;
+}
+.bl4 {
+ height: 350px;
+}
+.bl5 {
+ height: 300px;
+}
+.bl6 {
+ height: 250px;
+}
+.bl7 {
+ height: 600px;
+}
+.bl8 {
+ height: 450px;
+}
+.bl9 {
+ height: 350px;
+}
+
+.block.hidden-block {
+ display: none;
+}
+
+@media (max-width: 1699px) {
+ .block {
+ width: 320px;
+ }
+}
+
+@media (max-width: 1379px) {
+ .container {
+ column-count: 3;
+ }
+}
+
+@media (max-width: 1079px) {
+ .container {
+ column-count: 2;
+ }
+}
+
+@media (max-width: 767px) {
+ main {
+ padding: 20px 0;
+ }
+ .container {
+ column-count: 1;
+ }
+}
+
+@media (max-width: 359px) {
+ .block {
+ width: 300px;
+ }
+}
diff --git a/src/js/components/options-menu/options-menu.css b/src/js/components/options-menu/options-menu.css
new file mode 100644
index 0000000..029c450
--- /dev/null
+++ b/src/js/components/options-menu/options-menu.css
@@ -0,0 +1,98 @@
+.menu-content.Opti {
+ padding: 15px;
+}
+
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+.switch input {
+ display: none;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+}
+
+.slider:before {
+ position: absolute;
+ content: '';
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+}
+
+input:checked + .slider {
+ background-color: #2196f3;
+}
+
+input:focus + .slider {
+ -webkit-box-shadow: 0 0 1px #2196f3;
+ box-shadow: 0 0 1px #2196f3;
+}
+
+input:checked + .slider:before {
+ -webkit-transform: translateX(26px);
+ transform: translateX(26px);
+}
+
+.slider.round {
+ border-radius: 34px;
+}
+
+.slider.round:before {
+ border-radius: 50%;
+}
+
+.items-block {
+ display: -ms-grid;
+ display: grid;
+ grid-gap: 20px;
+}
+
+.option {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.select-block {
+ margin: 15px 0;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.select-block .select-sound {
+ padding: 10px 30px 10px 10px;
+ outline: none;
+ border-radius: 5px;
+}
+/*# sourceMappingURL=options-menu.css.map */
\ No newline at end of file
diff --git a/src/js/components/options-menu/options-menu.js b/src/js/components/options-menu/options-menu.js
new file mode 100644
index 0000000..e92b49f
--- /dev/null
+++ b/src/js/components/options-menu/options-menu.js
@@ -0,0 +1,279 @@
+import './options-menu.css';
+import Menu from '../base-menu/baseMenu';
+import create from '../../utils/create';
+
+const optionItems = [
+ {
+ title: 'Show images for websites',
+ checked: true,
+ myClass: 'favicon-item',
+ },
+ {
+ title: 'Open link in new tab',
+ checked: true,
+ myClass: 'target-blank',
+ },
+ {
+ title: 'Turn on background sound',
+ checked: false,
+ myClass: 'bg-sound',
+ },
+];
+
+const sounds = [
+ {
+ name: 'ambient',
+ src: 'audio/ambient.mp3',
+ selected: false,
+ },
+ {
+ name: 'birds-waves',
+ src: 'audio/birds-waves.mp3',
+ selected: false,
+ },
+ {
+ name: 'birds',
+ src: 'audio/birds.mp3',
+ selected: true,
+ },
+ {
+ name: 'cafe',
+ src: 'audio/cafe.mp3',
+ selected: false,
+ },
+ {
+ name: 'thunder',
+ src: 'audio/thunder.mp3',
+ selected: false,
+ },
+ {
+ name: 'waves',
+ src: 'audio/waves.mp3',
+ selected: false,
+ },
+];
+
+export const getOptionItems = () => {
+ let tempOptionItems;
+
+ const localOptionItems = JSON.parse(localStorage.getItem('optionItems'));
+
+ if (localOptionItems) {
+ tempOptionItems = localOptionItems;
+ } else {
+ tempOptionItems = optionItems;
+ localStorage.setItem('optionItems', JSON.stringify(optionItems));
+ }
+ return tempOptionItems;
+};
+
+export const getOptionFavicon = () => {
+ let optionFavicon;
+
+ const localOptionFavicon = JSON.parse(localStorage.getItem('optionFavicon'));
+
+ if (localOptionFavicon) {
+ optionFavicon = localOptionFavicon;
+ } else {
+ optionFavicon = optionItems[0];
+ localStorage.setItem('optionFavicon', JSON.stringify(optionItems[0]));
+ }
+ return optionFavicon;
+};
+
+const getSoundList = () => {
+ let soundList = [];
+
+ const localSoundList = JSON.parse(localStorage.getItem('soundList'));
+
+ if (localSoundList) {
+ soundList = localSoundList;
+ } else {
+ soundList = sounds;
+ localStorage.setItem('soundList', JSON.stringify(sounds));
+ }
+ return soundList;
+};
+
+class OptionsMenu extends Menu {
+ constructor(clickedElement, caption, privateClass) {
+ super(clickedElement, caption);
+ this.contentBlock = this.parentNode.querySelector('.menu-content.Opti');
+ this.renderContent();
+ this.privateClass = privateClass;
+ }
+
+ fillItemsBlock() {
+ const itemsBlock = create('div', 'items-block', '', this.contentBlock);
+ const localOptionItems = getOptionItems();
+
+ localOptionItems.forEach((item) => {
+ const option = create('div', `option ${item.myClass}`, ``, itemsBlock);
+
+ create('div', `title-${item.myClass}`, `${item.title}`, option);
+
+ const check = item.checked && 'checked';
+ const toggleHtml = `
+
+ `;
+ create('div', `toggle-switch`, toggleHtml, option);
+ });
+ }
+
+ addSelectListener(value) {
+ const localSoundList = JSON.parse(localStorage.getItem('soundList'));
+ const newList = localSoundList.map((sound) => {
+ if (sound.name === value) {
+ return { ...sound, selected: true };
+ } else {
+ return { ...sound, selected: false };
+ }
+ });
+
+ localStorage.setItem('soundList', JSON.stringify(newList));
+ this.playSound();
+ }
+
+ createSelectSound() {
+ const selectBlock = create(
+ 'div',
+ 'select-block',
+ 'Choose sound',
+ this.contentBlock
+ );
+ const select = create('select', 'select-sound', '', selectBlock);
+
+ const localSoundList = getSoundList();
+
+ localSoundList.forEach((sound) => {
+ const option = create('option', 'option-sound', `${sound.name}`, select);
+ option.value = `${sound.name}`;
+ if (sound.selected) option.selected = true;
+ });
+
+ select.onclick = (e) => this.addSelectListener.bind(this)(e.target.value);
+ }
+
+ creteAudioElements() {
+ sounds.forEach((item) => {
+ const audio = document.createElement('audio');
+ audio.classList.add(`audio-${item.name}`);
+ audio.src = item.src;
+ audio.loop = true;
+ this.contentBlock.appendChild(audio);
+ });
+ }
+
+ stopCurrentSound(selectedSound) {
+ const currentSound = JSON.parse(localStorage.getItem('currentSound'));
+
+ if (!currentSound) return;
+ if (currentSound.name === selectedSound.name) return;
+
+ const audio = this.contentBlock.querySelector(
+ `.audio-${currentSound.name}`
+ );
+
+ audio.pause();
+ audio.currentTime = 0;
+ }
+
+ playSound() {
+ const toggle = this.contentBlock.querySelector('.checkbox-bg-sound');
+
+ const localSoundList = getSoundList();
+ const selectedSound = localSoundList.find(
+ (sound) => sound.selected === true
+ );
+ this.stopCurrentSound(selectedSound);
+
+ localStorage.setItem('currentSound', JSON.stringify(selectedSound));
+
+ const audio = this.contentBlock.querySelector(
+ `.audio-${selectedSound.name}`
+ );
+
+ if (toggle.checked) audio.play();
+ if (!toggle.checked) {
+ audio.pause();
+ audio.currentTime = 0;
+ }
+ }
+
+ toggleCheckboxSound() {
+ const toggle = this.contentBlock.querySelector('.checkbox-bg-sound');
+ toggle.onclick = () => this.playSound.bind(this)();
+ }
+
+ toggleFaviconRequest() {
+ const currentRequest = getOptionItems();
+
+ if (currentRequest[0].checked) {
+ localStorage.setItem(
+ 'optionItems',
+ JSON.stringify([
+ { ...currentRequest[0], checked: false },
+ currentRequest[1],
+ currentRequest[2],
+ ])
+ );
+ } else {
+ localStorage.setItem(
+ 'optionItems',
+ JSON.stringify([
+ { ...currentRequest[0], checked: true },
+ currentRequest[1],
+ currentRequest[2],
+ ])
+ );
+ }
+ }
+
+ toggleCheckboxFavicon() {
+ const toggle = this.contentBlock.querySelector('.checkbox-favicon-item');
+ toggle.onclick = () => this.toggleFaviconRequest.bind(this)();
+ }
+
+ toggleTargetBlank() {
+ const currentRequest = getOptionItems();
+
+ if (currentRequest[1].checked) {
+ localStorage.setItem(
+ 'optionItems',
+ JSON.stringify([
+ currentRequest[0],
+ { ...currentRequest[1], checked: false },
+ currentRequest[2],
+ ])
+ );
+ } else {
+ localStorage.setItem(
+ 'optionItems',
+ JSON.stringify([
+ currentRequest[0],
+ { ...currentRequest[1], checked: true },
+ currentRequest[2],
+ ])
+ );
+ }
+ }
+
+ toggleCheckboxTargetBlank() {
+ const toggle = this.contentBlock.querySelector('.checkbox-target-blank');
+ toggle.onclick = () => this.toggleTargetBlank.bind(this)();
+ }
+
+ renderContent() {
+ this.fillItemsBlock();
+ this.createSelectSound();
+ this.creteAudioElements();
+ this.toggleCheckboxSound();
+ this.toggleCheckboxFavicon();
+ this.toggleCheckboxTargetBlank();
+ }
+}
+
+export default OptionsMenu;
diff --git a/src/js/components/options-menu/options-menu.scss b/src/js/components/options-menu/options-menu.scss
new file mode 100644
index 0000000..cf41302
--- /dev/null
+++ b/src/js/components/options-menu/options-menu.scss
@@ -0,0 +1,84 @@
+.menu-content.Opti{
+ padding: 15px;
+}
+
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+.switch input {
+ display: none;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+}
+
+.slider:before {
+ position: absolute;
+ content: '';
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+}
+
+input:checked + .slider {
+ background-color: #2196f3;
+}
+
+input:focus + .slider {
+ box-shadow: 0 0 1px #2196f3;
+}
+
+input:checked + .slider:before {
+ -webkit-transform: translateX(26px);
+ -ms-transform: translateX(26px);
+ transform: translateX(26px);
+}
+
+.slider.round {
+ border-radius: 34px;
+}
+
+.slider.round:before {
+ border-radius: 50%;
+}
+
+.items-block {
+ display: grid;
+ grid-gap: 20px;
+}
+
+.option {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.select-block {
+ margin: 15px 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .select-sound {
+ padding: 10px 30px 10px 10px;
+ outline: none;
+ border-radius: 5px;
+ }
+}
diff --git a/src/js/components/pages/pages.js b/src/js/components/pages/pages.js
index d9d563b..eb7c65b 100644
--- a/src/js/components/pages/pages.js
+++ b/src/js/components/pages/pages.js
@@ -56,7 +56,7 @@ class Pages {
}
addPage(name, color = Constants.DEFAULT_COLOR) {
- this.pages.push({ name: name, color: color });
+ this.pages.push({ name, color });
this.curPage = this.pages.length - 1;
const li = this.createLiElem(name);
location.hash = encodeURI(name);
@@ -65,7 +65,7 @@ class Pages {
deletePage(name) {
if (this.pages.length > 1) {
- let i = undefined;
+ let i;
this.pages.forEach((elem, idx) => {
if(elem.name === name) {
i = idx;
diff --git a/src/js/components/popular-links/popular.js b/src/js/components/popular-links/popular.js
index fe3e469..d30416d 100644
--- a/src/js/components/popular-links/popular.js
+++ b/src/js/components/popular-links/popular.js
@@ -1,7 +1,29 @@
import PopMenu from "../popular-menu/popular-menu";
import "./popular.css";
import { fullPopularLinks } from "../../data/constants";
+import { getOptionItems } from "../options-menu/options-menu";
+const getImage = (url) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`
+ } else {
+ img = '';
+ }
+ return img;
+}
+
+const getTargetBlank = () => {
+ let targetBlank;
+ const optionTarget = getOptionItems()[1];
+ if (optionTarget.checked) {
+ targetBlank = '_blank'
+ } else {
+ targetBlank = ''
+ }
+ return targetBlank;
+}
class Popular {
constructor(obj) {
this.parentNode = obj.parentNode;
@@ -34,6 +56,7 @@ class Popular {
myClass = this.privateClass,
arrayDataName = this.arrayDataName
) {
+
this.clearLinks(myClass);
const localPopularLinks = this.getPopularLinks(arrayDataName || this.arrayDataName);
const content = document.querySelector(`.${myClass}.popular-content`);
@@ -42,8 +65,8 @@ class Popular {
website.classList.add("websites", `${myClass}`);
website.innerHTML = `
-
-
+
+ ${getImage(web.favicon)}
${web.title}
`;
diff --git a/src/js/components/popular-menu/popular-menu.css b/src/js/components/popular-menu/popular-menu.css
index 116bdd0..dcc4f58 100644
--- a/src/js/components/popular-menu/popular-menu.css
+++ b/src/js/components/popular-menu/popular-menu.css
@@ -42,6 +42,7 @@
.website .website-logo {
width: 24px;
+ margin-right: 15px;
}
.form {
@@ -83,8 +84,8 @@
padding: 10px;
}
-.btn-block .delete,
-.btn-block .submit {
+.delete {
+ background-color: gray;
margin: 0 15px;
padding: 10px 15px;
border-radius: 5px;
@@ -94,21 +95,96 @@
font-size: 0.8rem;
}
-.btn-block .delete:hover,
-.btn-block .submit:hover {
+.delete:hover {
-webkit-transform: scale(1.1);
transform: scale(1.1);
- -webkit-transition: all 0.2s ease-in-out;
- transition: all 0.2s ease-in-out;
+ -webkit-transition: all 0.1s ease-in-out;
+ transition: all 0.1s ease-in-out;
border-radius: 5px;
cursor: pointer;
}
-.btn-block .delete {
- background-color: #dc3545;
+.delete:active {
+ -webkit-transform: scale(0.9);
+ transform: scale(0.9);
}
-.btn-block .submit {
+.submit {
background-color: #007bff;
+ margin: 0 15px;
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: none;
+ outline: none;
+ color: #f6f6f6;
+ font-size: 0.8rem;
+}
+
+.submit:hover {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+ -webkit-transition: all 0.1s ease-in-out;
+ transition: all 0.1s ease-in-out;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.submit:active {
+ -webkit-transform: scale(0.9);
+ transform: scale(0.9);
+}
+
+.danger-block {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ margin-top: 50px;
+}
+
+.danger {
+ background-color: #dc3545;
+ margin: 0 15px;
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: none;
+ outline: none;
+ color: #f6f6f6;
+ font-size: 0.8rem;
+}
+
+.danger:hover {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+ -webkit-transition: all 0.1s ease-in-out;
+ transition: all 0.1s ease-in-out;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.danger:active {
+ -webkit-transform: scale(0.9);
+ transform: scale(0.9);
+}
+
+@media (max-width: 1700px) {
+ .btn-block {
+ display: -ms-grid;
+ display: grid;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ grid-gap: 20px;
+ }
+ .submit {
+ -ms-grid-row: 1;
+ -ms-grid-row-span: 1;
+ grid-row: 1/2;
+ }
+ .danger-block {
+ margin-top: 10px;
+ }
}
/*# sourceMappingURL=popular-menu.css.map */
\ No newline at end of file
diff --git a/src/js/components/popular-menu/popular-menu.js b/src/js/components/popular-menu/popular-menu.js
index ee3919b..64e0a19 100644
--- a/src/js/components/popular-menu/popular-menu.js
+++ b/src/js/components/popular-menu/popular-menu.js
@@ -1,19 +1,31 @@
-import "./popular-menu.css";
-import { fullPopularLinks, faviconUrl } from "../../data/constants";
-import Menu from "../base-menu/baseMenu";
-import Popular from "../popular-links/popular";
+import './popular-menu.css';
+import { fullPopularLinks, faviconUrl } from '../../data/constants';
+import Menu from '../base-menu/baseMenu';
+import Popular from '../popular-links/popular';
+import { getOptionItems } from '../options-menu/options-menu';
+
+const getImage = (website) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`;
+ } else {
+ img = '';
+ }
+ return img;
+};
const getFullLinks = () => {
let fullLinks = [];
const localPopularLinks = JSON.parse(
- localStorage.getItem("fullPopularLinks")
+ localStorage.getItem('fullPopularLinks')
);
if (localPopularLinks) {
fullLinks = localPopularLinks;
} else {
fullLinks = fullPopularLinks;
- localStorage.setItem("fullPopularLinks", JSON.stringify(fullPopularLinks));
+ localStorage.setItem('fullPopularLinks', JSON.stringify(fullPopularLinks));
}
return fullLinks;
};
@@ -21,13 +33,13 @@ const getFullLinks = () => {
const getPopularLinks = () => {
let popularLinks = [];
- const localPopularLinks = JSON.parse(localStorage.getItem("popularLinks"));
+ const localPopularLinks = JSON.parse(localStorage.getItem('popularLinks'));
if (localPopularLinks) {
popularLinks = localPopularLinks;
} else {
popularLinks = fullPopularLinks.slice(0, 6);
- localStorage.setItem("popularLinks", JSON.stringify(popularLinks));
+ localStorage.setItem('popularLinks', JSON.stringify(popularLinks));
}
return popularLinks;
};
@@ -45,8 +57,8 @@ class PopMenu extends Menu {
(website) => website.title === title
);
- let check = "";
- if (activeLinks) check = "checked";
+ let check = '';
+ if (activeLinks) check = 'checked';
return check;
}
@@ -67,36 +79,36 @@ class PopMenu extends Menu {
localPopularLinks.push(necessaryService);
}
- localStorage.setItem("popularLinks", JSON.stringify(localPopularLinks));
+ localStorage.setItem('popularLinks', JSON.stringify(localPopularLinks));
}
clearMenuContent() {
const websites = document.querySelectorAll(`.website.popular`);
websites.forEach((link) => link.parentElement.removeChild(link));
- const nameWebsite = document.querySelector(".name-input.popular");
- const urlWebsite = document.querySelector(".url-input.popular");
+ const nameWebsite = document.querySelector('.name-input.popular');
+ const urlWebsite = document.querySelector('.url-input.popular');
- if (nameWebsite) nameWebsite.value = "";
- if (urlWebsite) urlWebsite.value = "";
+ if (nameWebsite) nameWebsite.value = '';
+ if (urlWebsite) urlWebsite.value = '';
}
fillMenuContent() {
this.clearMenuContent();
- const menuContent = document.querySelector(".menu-content.Popu");
+ const menuContent = document.querySelector('.menu-content.Popu');
const fragment = document.createDocumentFragment();
const fullLocalLinks = getFullLinks();
fullLocalLinks.forEach((website) => {
const check = this.findActiveWebsite(website.title);
- const web = document.createElement("div");
- web.classList.add("website", "popular");
+ const web = document.createElement('div');
+ web.classList.add('website', 'popular');
web.innerHTML = `
`;
@@ -106,9 +118,9 @@ class PopMenu extends Menu {
}
createForm() {
- const menuContent = document.querySelector(".menu-content.Popu");
- const form = document.createElement("div");
- form.classList.add("form");
+ const menuContent = document.querySelector('.menu-content.Popu');
+ const form = document.createElement('div');
+ form.classList.add('form');
form.innerHTML = `
@@ -121,14 +133,17 @@ class PopMenu extends Menu {
+
+
+
`;
menuContent.appendChild(form);
}
createObjForSet() {
- const nameWebsite = document.querySelector(".name-input.popular");
- const urlWebsite = document.querySelector(".url-input.popular");
+ const nameWebsite = document.querySelector('.name-input.popular');
+ const urlWebsite = document.querySelector('.url-input.popular');
const title = nameWebsite.value;
const url = urlWebsite.value;
@@ -148,31 +163,30 @@ class PopMenu extends Menu {
const data = this.createObjForSet();
if (data) {
const fullLocalLinks = JSON.parse(
- localStorage.getItem("fullPopularLinks")
+ localStorage.getItem('fullPopularLinks')
);
fullLocalLinks.push(data);
- localStorage.setItem("fullPopularLinks", JSON.stringify(fullLocalLinks));
+ localStorage.setItem('fullPopularLinks', JSON.stringify(fullLocalLinks));
}
}
cleanLocalLinks() {
- localStorage.removeItem("fullPopularLinks");
- localStorage.removeItem("popularLinks");
- Popular.prototype.fillContentBlock(this.privateClass, "popularLinks");
+ localStorage.removeItem('fullPopularLinks');
+ localStorage.removeItem('popularLinks');
+ Popular.prototype.fillContentBlock(this.privateClass, 'popularLinks');
}
changeLinks(e) {
const websiteClickedCheckbox = e.target.dataset.popular;
const activeWebsite = this.findActiveWebsite(websiteClickedCheckbox);
- console.log(activeWebsite, websiteClickedCheckbox);
this.changeWebsiteArray(activeWebsite, websiteClickedCheckbox);
- Popular.prototype.fillContentBlock(this.privateClass, "popularLinks");
+ Popular.prototype.fillContentBlock(this.privateClass, 'popularLinks');
}
addListenerToBtn() {
const btnSub = document.querySelector(`.submit.popular`);
- btnSub.addEventListener("click", () => {
+ btnSub.addEventListener('click', () => {
this.createObjForSet.bind(this)();
this.setObjData.bind(this)();
this.fillMenuContent.bind(this)();
@@ -182,7 +196,7 @@ class PopMenu extends Menu {
addListenerToDelBtn() {
const btnDel = document.querySelector(`.delete.popular`);
- btnDel.addEventListener("click", () => {
+ btnDel.addEventListener('click', () => {
this.cleanLocalLinks();
this.fillMenuContent.bind(this)();
this.addListenerToLabel.bind(this)();
@@ -192,16 +206,31 @@ class PopMenu extends Menu {
addListenerToLabel() {
const labels = this.parentNode.querySelectorAll(`.input-popular`);
labels.forEach((label) =>
- label.addEventListener("click", this.changeLinks.bind(this))
+ label.addEventListener('click', this.changeLinks.bind(this))
);
}
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.popular');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector('[data-btn="popular"]');
+ const btnDel = document.querySelector('.delete.popular');
+
+ mainMenuBtn.click();
+ btnDel.click();
+
+ this.hide.bind(this)();
+ });
+ }
+
renderContent() {
this.fillMenuContent();
this.createForm();
this.addListenerToLabel();
this.addListenerToBtn();
this.addListenerToDelBtn();
+ this.addDangerBtnListener();
}
}
diff --git a/src/js/components/popular-menu/popular-menu.scss b/src/js/components/popular-menu/popular-menu.scss
index d471d7b..f2f9e24 100644
--- a/src/js/components/popular-menu/popular-menu.scss
+++ b/src/js/components/popular-menu/popular-menu.scss
@@ -33,6 +33,7 @@
.website-logo {
width: 24px;
+ margin-right: 15px;
}
}
@@ -61,34 +62,85 @@
}
}
+%button {
+ margin: 0 15px;
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: none;
+ outline: none;
+ color: #f6f6f6;
+ font-size: 0.8rem;
+
+ &:hover {
+ transform: scale(1.1);
+ transition: all 0.1s ease-in-out;
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ &:active {
+ transform: scale(0.9);
+ }
+}
+
+@mixin button($color) {
+ background-color: $color;
+ margin: 0 15px;
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: none;
+ outline: none;
+ color: #f6f6f6;
+ font-size: 0.8rem;
+
+ &:hover {
+ transform: scale(1.1);
+ transition: all 0.1s ease-in-out;
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ &:active {
+ transform: scale(0.9);
+ }
+}
+
.btn-block {
display: flex;
justify-content: space-between;
padding: 10px;
+}
+.delete {
+ @include button(gray);
+}
- .delete,
- .submit {
- margin: 0 15px;
- padding: 10px 15px;
- border-radius: 5px;
- border: none;
- outline: none;
- color: #f6f6f6;
- font-size: 0.8rem;
-
- &:hover {
- transform: scale(1.1);
- transition: all 0.2s ease-in-out;
- border-radius: 5px;
- cursor: pointer;
- }
+.submit {
+ @include button(#007bff);
+}
+
+.danger-block {
+ display: flex;
+ justify-content: center;
+ margin-top: 50px;
+}
+
+.danger {
+ @include button(#dc3545);
+}
+
+
+@media (max-width: 1700px) {
+ .btn-block {
+ display: grid;
+ justify-content: center;
+ grid-gap: 20px;
}
- .delete {
- background-color: #dc3545;
+ .submit{
+ grid-row: 1/2;
}
- .submit {
- background-color: #007bff;
+ .danger-block {
+ margin-top: 10px;
}
-}
+}
\ No newline at end of file
diff --git a/src/js/components/rss-menu/rss-menu.css b/src/js/components/rss-menu/rss-menu.css
index b94bc4f..4e0500b 100644
--- a/src/js/components/rss-menu/rss-menu.css
+++ b/src/js/components/rss-menu/rss-menu.css
@@ -26,7 +26,7 @@
-ms-flex-align: center;
align-items: center;
cursor: pointer;
- margin-left: 10px;
+ margin-left: 15px;
}
.bookmark-logo {
diff --git a/src/js/components/rss-menu/rss-menu.js b/src/js/components/rss-menu/rss-menu.js
index 29b5dc4..3456c70 100644
--- a/src/js/components/rss-menu/rss-menu.js
+++ b/src/js/components/rss-menu/rss-menu.js
@@ -1,28 +1,29 @@
-import "./rss-menu.css";
-import Menu from "../base-menu/baseMenu";
-import Rss, { fullUrlArray } from "../rss-news/rss";
+import './rss-menu.css';
+import Menu from '../base-menu/baseMenu';
+import Rss, { fullUrlArray } from '../rss-news/rss';
+import create from '../../utils/create';
const findActiveBookmark = (service) => {
- const localUrlArray = JSON.parse(localStorage.getItem("urlArray"));
+ const localUrlArray = JSON.parse(localStorage.getItem('urlArray'));
const activeBookmark = localUrlArray.some(
(bookmark) => bookmark.service === service
);
- let check = "";
- if (activeBookmark) check = "checked";
+ let check = '';
+ if (activeBookmark) check = 'checked';
return check;
};
const fillMenuContent = () => {
- const menuContent = document.querySelector(".menu-content.Book");
+ const menuContent = document.querySelector('.menu-content.Book');
const fragment = document.createDocumentFragment();
fullUrlArray.forEach((service) => {
const check = findActiveBookmark(service.service);
- const bookmark = document.createElement("div");
- bookmark.classList.add("bookmark");
+ const bookmark = document.createElement('div');
+ bookmark.classList.add('bookmark');
bookmark.innerHTML = `
@@ -36,8 +37,19 @@ const fillMenuContent = () => {
menuContent.appendChild(fragment);
};
+const addDangerBtn = () => {
+ const menuContent = document.querySelector('.menu-content.Book');
+
+ create(
+ 'div',
+ 'danger-block',
+ ``,
+ menuContent
+ );
+};
+
const changeUrlArray = (activeService, serviceClickedCheckbox) => {
- const localUrlArray = JSON.parse(localStorage.getItem("urlArray"));
+ const localUrlArray = JSON.parse(localStorage.getItem('urlArray'));
if (activeService) {
const index = localUrlArray.findIndex(
@@ -51,7 +63,7 @@ const changeUrlArray = (activeService, serviceClickedCheckbox) => {
localUrlArray.push(necessaryService);
}
- localStorage.setItem("urlArray", JSON.stringify(localUrlArray));
+ localStorage.setItem('urlArray', JSON.stringify(localUrlArray));
};
const changeBookmarks = (e) => {
@@ -70,12 +82,25 @@ class RssMenu extends Menu {
}
addListenerToLabel() {
- const labels = this.parentNode.querySelectorAll(".input");
- labels.forEach((label) => label.addEventListener("click", changeBookmarks));
+ const labels = this.parentNode.querySelectorAll('.input');
+ labels.forEach((label) => label.addEventListener('click', changeBookmarks));
+ }
+
+ addDangerBtnListener() {
+ const dangerBtn = document.querySelector('.danger.rss');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector(`[data-btn="rss"]`);
+ mainMenuBtn.click();
+ this.hide.bind(this)();
+ localStorage.removeItem('urlArray');
+ });
}
renderContent() {
fillMenuContent();
+ addDangerBtn();
+ this.addDangerBtnListener();
this.addListenerToLabel();
}
}
diff --git a/src/js/components/rss-menu/rss-menu.scss b/src/js/components/rss-menu/rss-menu.scss
index 068eec4..8c0eceb 100644
--- a/src/js/components/rss-menu/rss-menu.scss
+++ b/src/js/components/rss-menu/rss-menu.scss
@@ -16,7 +16,7 @@
display: flex;
align-items: center;
cursor: pointer;
- margin-left: 10px;
+ margin-left: 15px;
}
.bookmark-logo {
diff --git a/src/js/components/rss-news/rss.css b/src/js/components/rss-news/rss.css
index 542248e..a6f6b73 100644
--- a/src/js/components/rss-news/rss.css
+++ b/src/js/components/rss-news/rss.css
@@ -87,20 +87,19 @@
}
.topic {
- display: -ms-grid;
- display: grid;
+ margin: 10px 0;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
- -ms-grid-columns: 1fr 5fr;
- grid-template-columns: 1fr 5fr;
- grid-gap: 10px;
- margin: 5px 0;
}
.topic .topic-img {
width: 60px;
max-height: 40px;
+ margin-right: 10px;
}
.topic .topic-link {
diff --git a/src/js/components/rss-news/rss.js b/src/js/components/rss-news/rss.js
index b9aee15..be034f7 100644
--- a/src/js/components/rss-news/rss.js
+++ b/src/js/components/rss-news/rss.js
@@ -1,71 +1,72 @@
-import "./rss.css";
-import RssMenu from "../rss-menu/rss-menu";
+import './rss.css';
+import RssMenu from '../rss-menu/rss-menu';
+import { getOptionItems } from '../options-menu/options-menu';
export const fullUrlArray = [
{
- service: "Lenta-ru",
- logo: "https://lenta.ru/images/small_logo.png",
+ service: 'Lenta-ru',
+ logo: 'https://lenta.ru/images/small_logo.png',
links: [
- "https://lenta.ru/rss/news",
- "https://lenta.ru/rss/top7",
- "https://lenta.ru/rss/last24",
- "https://lenta.ru/rss/articles",
- "https://lenta.ru/rss/news/russia",
- "https://lenta.ru/rss/photo",
+ 'https://lenta.ru/rss/news',
+ 'https://lenta.ru/rss/top7',
+ 'https://lenta.ru/rss/last24',
+ 'https://lenta.ru/rss/articles',
+ 'https://lenta.ru/rss/news/russia',
+ 'https://lenta.ru/rss/photo',
],
},
{
- service: "Газета-Ru",
- logo: "https://img.gazeta.ru/files3/677/4728677/gazeta_logo.jpg",
+ service: 'Газета-Ru',
+ logo: 'https://img.gazeta.ru/files3/677/4728677/gazeta_logo.jpg',
links: [
- "https://www.gazeta.ru/export/rss/first.xml",
- "https://www.gazeta.ru/export/rss/lenta.xml",
- "https://www.gazeta.ru/export/rss/lastnews.xml",
- "https://www.gazeta.ru/export/rss/politics.xml",
- "https://www.gazeta.ru/export/rss/business.xml",
- "https://www.gazeta.ru/export/rss/social.xml",
+ 'https://www.gazeta.ru/export/rss/first.xml',
+ 'https://www.gazeta.ru/export/rss/lenta.xml',
+ 'https://www.gazeta.ru/export/rss/lastnews.xml',
+ 'https://www.gazeta.ru/export/rss/politics.xml',
+ 'https://www.gazeta.ru/export/rss/business.xml',
+ 'https://www.gazeta.ru/export/rss/social.xml',
],
},
{
- service: "TUT-BY",
- logo: "https://img.tyt.by/i/rss/news/logo.gif",
+ service: 'TUT-BY',
+ logo: 'https://img.tyt.by/i/rss/news/logo.gif',
links: [
- "https://news.tut.by/rss/index.rss",
- "https://news.tut.by/rss/economics.rss",
- "https://news.tut.by/rss/society.rss",
+ 'https://news.tut.by/rss/index.rss',
+ 'https://news.tut.by/rss/economics.rss',
+ 'https://news.tut.by/rss/society.rss',
],
},
{
- service: "Yahoo",
- logo: "http://l.yimg.com/rz/d/yahoo_news_en-US_s_f_p_168x21_news.png",
+ service: 'Yahoo',
+ logo: 'http://l.yimg.com/rz/d/yahoo_news_en-US_s_f_p_168x21_news.png',
links: [
- "https://www.yahoo.com/news/rss",
- "https://finance.yahoo.com/news/rssindex",
+ 'https://www.yahoo.com/news/rss',
+ 'https://finance.yahoo.com/news/rssindex',
],
},
{
- service: "cnn",
- logo: "http://i2.cdn.turner.com/cnn/2015/images/09/24/cnn.digital.png",
+ service: 'cnn',
+ logo: 'http://i2.cdn.turner.com/cnn/2015/images/09/24/cnn.digital.png',
links: [
- "http://rss.cnn.com/rss/edition.rss",
- "http://rss.cnn.com/rss/edition_world.rss",
+ 'http://rss.cnn.com/rss/edition.rss',
+ 'http://rss.cnn.com/rss/edition_world.rss',
],
},
{
- service: "Un-org",
+ service: 'Un-org',
logo:
- "https://news.un.org/en/sites/all/themes/bootstrap_un_news/images/un-emblem-for-rss.png",
+ 'https://news.un.org/en/sites/all/themes/bootstrap_un_news/images/un-emblem-for-rss.png',
links: [
- "https://news.un.org/feed/subscribe/en/news/all/rss.xml",
- "https://news.un.org/feed/subscribe/en/news/topic/health/feed/rss.xml",
+ 'https://news.un.org/feed/subscribe/en/news/all/rss.xml',
+ 'https://news.un.org/feed/subscribe/en/news/topic/health/feed/rss.xml',
],
},
{
- service: "bbc",
- logo: "http://news.bbcimg.co.uk/nol/shared/img/bbc_news_120x60.gif",
+ service: 'bbc',
+ logo: 'http://news.bbcimg.co.uk/nol/shared/img/bbc_news_120x60.gif',
links: [
- "http://feeds.bbci.co.uk/news/world/rss.xml",
- "http://feeds.bbci.co.uk/news/politics/rss.xml",
+ 'http://feeds.bbci.co.uk/news/world/rss.xml',
+ 'http://feeds.bbci.co.uk/news/politics/rss.xml',
],
},
];
@@ -73,47 +74,47 @@ export const fullUrlArray = [
let urlArray = [];
const getUrlArray = () => {
- const localUrlArray = JSON.parse(localStorage.getItem("urlArray"));
+ const localUrlArray = JSON.parse(localStorage.getItem('urlArray'));
if (localUrlArray) {
urlArray = localUrlArray;
} else {
urlArray.push(fullUrlArray[0]);
- localStorage.setItem("urlArray", JSON.stringify(urlArray));
+ localStorage.setItem('urlArray', JSON.stringify(urlArray));
}
return urlArray;
};
const clearBookmarks = () => {
- const bookmarks = document.querySelectorAll(".logo-bookmark");
+ const bookmarks = document.querySelectorAll('.logo-bookmark');
bookmarks.forEach((bookmark) => bookmark.parentElement.removeChild(bookmark));
};
const setNewsTitle = (text) => {
- const title = document.querySelector(".title");
+ const title = document.querySelector('.title');
title.textContent = text;
};
const setNumberPage = (currentNumber, amountNumbers) => {
- const currentPage = document.querySelector(".current-page");
- const amountPages = document.querySelector(".amount-pages");
+ const currentPage = document.querySelector('.current-page');
+ const amountPages = document.querySelector('.amount-pages');
currentPage.textContent = currentNumber;
amountPages.textContent = amountNumbers;
};
const showErrorApi = (text) => {
- const body = document.querySelector("body");
- const block = document.createElement("div");
+ const body = document.querySelector('body');
+ const block = document.createElement('div');
block.textContent = text;
- block.classList.add("error");
+ block.classList.add('error');
body.appendChild(block);
setTimeout(() => {
- const hiddenBlock = document.createElement("div");
+ const hiddenBlock = document.createElement('div');
hiddenBlock.textContent = text;
- hiddenBlock.classList.add("hiddenBlock", "hide");
+ hiddenBlock.classList.add('hiddenBlock', 'hide');
body.appendChild(hiddenBlock);
block.parentElement.removeChild(block);
setTimeout(() => {
@@ -122,16 +123,16 @@ const showErrorApi = (text) => {
}, 3000);
};
-const jsonApi = "https://api.rss2json.com/v1/api.json?rss_url=";
-const apiKey = "&api_key=j0hwglpcodohzh4p4j8pdhejx1kdhkgtxmxgba6n";
+const jsonApi = 'https://api.rss2json.com/v1/api.json?rss_url=';
+const apiKey = '&api_key=j0hwglpcodohzh4p4j8pdhejx1kdhkgtxmxgba6n';
-const getRss = async (url = "https://lenta.ru/rss/news") => {
+const getRss = async (url = 'https://lenta.ru/rss/news') => {
const request = await fetch(`${jsonApi}${url}${apiKey}`);
const data = await request.json();
- const status = data.status === "error";
+ const status = data.status === 'error';
if (status) {
- showErrorApi("You are converting new feeds in a very short period");
+ showErrorApi('You are converting new feeds in a very short period');
throw new Error("Api doesn't provides with information");
}
@@ -139,10 +140,34 @@ const getRss = async (url = "https://lenta.ru/rss/news") => {
};
const clearContentBlock = () => {
- const topics = document.querySelectorAll(".topic");
+ const topics = document.querySelectorAll('.topic');
topics.forEach((topic) => topic.parentElement.removeChild(topic));
};
+const getImage = (url) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`;
+ } else {
+ img = '';
+ }
+ return img;
+};
+
+const getTargetBlank = () => {
+ let targetBlank;
+ const optionTarget = getOptionItems()[1];
+ if (optionTarget.checked) {
+ targetBlank = '_blank';
+ } else {
+ targetBlank = '';
+ }
+ return targetBlank;
+};
+
class Rss {
constructor(parentNode) {
this.parentNode = parentNode;
@@ -154,14 +179,14 @@ class Rss {
fillNewsBookmarks() {
clearBookmarks();
const localUrlArray = getUrlArray();
- const bookmarksContainer = document.querySelector(".bookmarks");
+ const bookmarksContainer = document.querySelector('.bookmarks');
localUrlArray.forEach((service) => {
- const bookmark = document.createElement("img");
- bookmark.classList.add("logo-bookmark", `${service.service}`);
+ const bookmark = document.createElement('img');
+ bookmark.classList.add('logo-bookmark', `${service.service}`);
bookmark.src = service.logo;
bookmarksContainer.appendChild(bookmark);
- bookmark.addEventListener("click", () => {
+ bookmark.addEventListener('click', () => {
this.listenerBookmark(service);
});
});
@@ -184,24 +209,21 @@ class Rss {
const url = service.links[this.numberLink];
const rssNews = await getRss(url);
- const content = document.querySelector(".content");
+ const content = document.querySelector('.content');
clearContentBlock();
rssNews.items.forEach((news) => {
const correctTitle =
- news.description.includes("
+ ${getImage(news.enclosure.link)}
${news.title}
+ }" target="${getTargetBlank()}">${news.title}
`;
content.appendChild(topic);
});
@@ -211,8 +233,8 @@ class Rss {
}
changePage(service) {
- const prevPage = document.querySelector(".prev-page");
- const nextPage = document.querySelector(".next-page");
+ const prevPage = document.querySelector('.prev-page');
+ const nextPage = document.querySelector('.next-page');
prevPage.onclick = () => {
this.fillContentBlock(service, -1);
@@ -249,8 +271,8 @@ class Rss {
this.fillNewsBookmarks.bind(this)();
this.fillContentBlock(urlArray[0], 0);
this.changePage(urlArray[0]);
- this.btnMenu = this.parentNode.querySelector(".rss-menu");
- this.rssMenu = new RssMenu(this.btnMenu, "Bookmark manager");
+ this.btnMenu = this.parentNode.querySelector('.rss-menu');
+ this.rssMenu = new RssMenu(this.btnMenu, 'Bookmark manager');
}
}
diff --git a/src/js/components/rss-news/rss.scss b/src/js/components/rss-news/rss.scss
index 6568c25..d828b72 100644
--- a/src/js/components/rss-news/rss.scss
+++ b/src/js/components/rss-news/rss.scss
@@ -72,15 +72,15 @@
}
.topic {
- display: grid;
+ margin: 10px 0;
+ display: flex;
align-items: center;
- grid-template-columns: 1fr 5fr;
- grid-gap: 10px;
- margin: 5px 0;
.topic-img {
width: 60px;
max-height: 40px;
+
+ margin-right: 10px;
}
.topic-link {
diff --git a/src/js/components/shops-menu/shops-menu.js b/src/js/components/shops-menu/shops-menu.js
index d9b3147..d03bcbf 100644
--- a/src/js/components/shops-menu/shops-menu.js
+++ b/src/js/components/shops-menu/shops-menu.js
@@ -1,17 +1,29 @@
-import "./shops-menu.css";
-import { fullShopsLinks, faviconUrl } from "../../data/constants";
-import Menu from "../base-menu/baseMenu";
-import Shops from "../shops/shops";
+import './shops-menu.css';
+import { fullShopsLinks, faviconUrl } from '../../data/constants';
+import Menu from '../base-menu/baseMenu';
+import Shops from '../shops/shops';
+import { getOptionItems } from '../options-menu/options-menu';
+
+const getImage = (website) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`;
+ } else {
+ img = '';
+ }
+ return img;
+};
const getFullLinks = () => {
let fullLinks = [];
- const localShopsLinks = JSON.parse(localStorage.getItem("fullShopsLinks"));
+ const localShopsLinks = JSON.parse(localStorage.getItem('fullShopsLinks'));
if (localShopsLinks) {
fullLinks = localShopsLinks;
} else {
fullLinks = fullShopsLinks;
- localStorage.setItem("fullShopsLinks", JSON.stringify(fullShopsLinks));
+ localStorage.setItem('fullShopsLinks', JSON.stringify(fullShopsLinks));
}
return fullLinks;
};
@@ -19,13 +31,13 @@ const getFullLinks = () => {
const getShopsLinks = () => {
let shopsLinks = [];
- const localShopsLinks = JSON.parse(localStorage.getItem("shopsLinks"));
+ const localShopsLinks = JSON.parse(localStorage.getItem('shopsLinks'));
if (localShopsLinks) {
shopsLinks = localShopsLinks;
} else {
shopsLinks = fullShopsLinks.slice(0, 6);
- localStorage.setItem("shopsLinks", JSON.stringify(shopsLinks));
+ localStorage.setItem('shopsLinks', JSON.stringify(shopsLinks));
}
return shopsLinks;
};
@@ -43,8 +55,8 @@ class ShopsMenu extends Menu {
(website) => website.title === title
);
- let check = "";
- if (activeLinks) check = "checked";
+ let check = '';
+ if (activeLinks) check = 'checked';
return check;
}
@@ -65,36 +77,36 @@ class ShopsMenu extends Menu {
localShopsLinks.push(necessaryService);
}
- localStorage.setItem("shopsLinks", JSON.stringify(localShopsLinks));
+ localStorage.setItem('shopsLinks', JSON.stringify(localShopsLinks));
}
clearMenuContent() {
const websites = document.querySelectorAll(`.website.shops`);
websites.forEach((link) => link.parentElement.removeChild(link));
- const nameWebsite = document.querySelector(".name-input.shops");
- const urlWebsite = document.querySelector(".url-input.shops");
+ const nameWebsite = document.querySelector('.name-input.shops');
+ const urlWebsite = document.querySelector('.url-input.shops');
- if (nameWebsite) nameWebsite.value = "";
- if (urlWebsite) urlWebsite.value = "";
+ if (nameWebsite) nameWebsite.value = '';
+ if (urlWebsite) urlWebsite.value = '';
}
fillMenuContent() {
this.clearMenuContent();
- const menuContent = document.querySelector(".menu-content.Shop");
+ const menuContent = document.querySelector('.menu-content.Shop');
const fragment = document.createDocumentFragment();
const fullLocalLinks = getFullLinks();
fullLocalLinks.forEach((website) => {
const check = this.findActiveWebsite(website.title);
- const web = document.createElement("div");
- web.classList.add("website", "shops");
+ const web = document.createElement('div');
+ web.classList.add('website', 'shops');
web.innerHTML = `
`;
@@ -104,10 +116,10 @@ class ShopsMenu extends Menu {
}
createForm() {
- const menuContent = document.querySelector(".menu-content.Shop");
+ const menuContent = document.querySelector('.menu-content.Shop');
- const form = document.createElement("div");
- form.classList.add("form");
+ const form = document.createElement('div');
+ form.classList.add('form');
form.innerHTML = `
@@ -120,14 +132,17 @@ class ShopsMenu extends Menu {
+
+
+
`;
menuContent.appendChild(form);
}
createObjForSet() {
- const nameWebsite = document.querySelector(".name-input.shops");
- const urlWebsite = document.querySelector(".url-input.shops");
+ const nameWebsite = document.querySelector('.name-input.shops');
+ const urlWebsite = document.querySelector('.url-input.shops');
const title = nameWebsite.value;
const url = urlWebsite.value;
// const faviconUrl = "https://www.google.com/s2/favicons?domain=";
@@ -147,16 +162,16 @@ class ShopsMenu extends Menu {
setObjData() {
const data = this.createObjForSet();
if (data) {
- const fullLocalLinks = JSON.parse(localStorage.getItem("fullShopsLinks"));
+ const fullLocalLinks = JSON.parse(localStorage.getItem('fullShopsLinks'));
fullLocalLinks.push(data);
- localStorage.setItem("fullShopsLinks", JSON.stringify(fullLocalLinks));
+ localStorage.setItem('fullShopsLinks', JSON.stringify(fullLocalLinks));
}
}
cleanLocalLinks() {
- localStorage.removeItem("fullShopsLinks");
- localStorage.removeItem("shopsLinks");
- Shops.prototype.fillContentBlock(this.privateClass, "shopsLinks");
+ localStorage.removeItem('fullShopsLinks');
+ localStorage.removeItem('shopsLinks');
+ Shops.prototype.fillContentBlock(this.privateClass, 'shopsLinks');
}
changeLinks(e) {
@@ -164,13 +179,12 @@ class ShopsMenu extends Menu {
const activeWebsite = this.findActiveWebsite(websiteClickedCheckbox);
this.changeWebsiteArray(activeWebsite, websiteClickedCheckbox);
- console.log("Ok");
- Shops.prototype.fillContentBlock(this.privateClass, "shopsLinks");
+ Shops.prototype.fillContentBlock(this.privateClass, 'shopsLinks');
}
addListenerToBtn() {
const btnSub = document.querySelector(`.submit.shops`);
- btnSub.addEventListener("click", () => {
+ btnSub.addEventListener('click', () => {
this.createObjForSet.bind(this)();
this.setObjData.bind(this)();
this.fillMenuContent.bind(this)();
@@ -180,7 +194,7 @@ class ShopsMenu extends Menu {
addListenerToDelBtn() {
const btnDel = document.querySelector(`.delete.shops`);
- btnDel.addEventListener("click", () => {
+ btnDel.addEventListener('click', () => {
this.cleanLocalLinks();
this.fillMenuContent.bind(this)();
this.addListenerToLabel.bind(this)();
@@ -190,16 +204,31 @@ class ShopsMenu extends Menu {
addListenerToLabel() {
const labels = this.parentNode.querySelectorAll(`.input-shops`);
labels.forEach((label) =>
- label.addEventListener("click", this.changeLinks.bind(this))
+ label.addEventListener('click', this.changeLinks.bind(this))
);
}
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.shops');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector('[data-btn="shops"]');
+ const btnDel = document.querySelector('.delete.shops');
+
+ mainMenuBtn.click();
+ btnDel.click();
+
+ this.hide.bind(this)();
+ });
+ }
+
renderContent() {
this.fillMenuContent();
this.createForm();
this.addListenerToLabel();
this.addListenerToBtn();
this.addListenerToDelBtn();
+ this.addDangerBtnListener();
}
}
diff --git a/src/js/components/shops/shops.js b/src/js/components/shops/shops.js
index 0aa1b37..91b334c 100644
--- a/src/js/components/shops/shops.js
+++ b/src/js/components/shops/shops.js
@@ -2,7 +2,29 @@
import { fullShopsLinks } from "../../data/constants";
import ShopsMenu from "../shops-menu/shops-menu";
import "./shops.css";
+import { getOptionItems } from "../options-menu/options-menu";
+const getImage = (url) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`
+ } else {
+ img = '';
+ }
+ return img;
+}
+
+const getTargetBlank = () => {
+ let targetBlank;
+ const optionTarget = getOptionItems()[1];
+ if (optionTarget.checked) {
+ targetBlank = '_blank'
+ } else {
+ targetBlank = ''
+ }
+ return targetBlank;
+}
class Shops {
constructor(obj) {
this.parentNode = obj.parentNode;
@@ -45,8 +67,8 @@ class Shops {
website.classList.add("websites", `${myClass}`);
website.innerHTML = `
-
-
+
+ ${getImage(web.favicon)}
${web.title}
`;
diff --git a/src/js/components/todo/todo-menu.js b/src/js/components/todo/todo-menu.js
new file mode 100644
index 0000000..5750165
--- /dev/null
+++ b/src/js/components/todo/todo-menu.js
@@ -0,0 +1,39 @@
+// import './rss-menu.css';
+import Menu from '../base-menu/baseMenu';
+import create from '../../utils/create';
+
+class TodoMenu extends Menu {
+ constructor(clickedElement, caption) {
+ super(clickedElement, caption);
+ this.renderContent();
+ }
+
+ addDangerBtn() {
+ const menuContent = this.parentNode.querySelector('.menu-content.ToDo');
+
+ create(
+ 'div',
+ 'danger-block',
+ ``,
+ menuContent
+ );
+ }
+
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.todo');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector(`[data-btn="todo"]`);
+ mainMenuBtn.click();
+ this.hide.bind(this)();
+ localStorage.removeItem('todo');
+ });
+ }
+
+ renderContent() {
+ this.addDangerBtn();
+ this.addDangerBtnListener();
+ }
+}
+
+export default TodoMenu;
diff --git a/src/js/components/todo/todo.css b/src/js/components/todo/todo.css
new file mode 100644
index 0000000..ad59cc5
--- /dev/null
+++ b/src/js/components/todo/todo.css
@@ -0,0 +1,94 @@
+.todo-content {
+ padding: 10px 15px;
+}
+
+.add-item {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ padding: 5px;
+}
+
+.input-task {
+ width: 85%;
+ border-radius: 25px;
+ padding-left: 10px;
+}
+
+.input-task:hover, .input-task:focus {
+ border-radius: 25px;
+ outline: none;
+ -webkit-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+ box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+}
+
+.input-task.new-task {
+ width: 82%;
+ border: 2px solid #6b6b6b;
+}
+
+.add-task {
+ margin-left: -45px;
+ background-color: dodgerblue;
+ color: white;
+ border-radius: 25px;
+ padding: 10px 12px;
+ border: none;
+ outline: none;
+}
+
+.add-task:hover {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+ -webkit-transition: all 0.1s ease-in-out;
+ transition: all 0.1s ease-in-out;
+ cursor: pointer;
+}
+
+.task {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ padding: 5px;
+}
+
+.task .resolved {
+ text-decoration: line-through;
+ opacity: 0.6;
+}
+
+.task .input-task {
+ width: 75%;
+ margin: 5px;
+ font-size: 0.9rem;
+ border: none;
+}
+
+.delete-task {
+ background-color: tomato;
+ margin-right: 5px;
+ color: white;
+ border: 0px;
+ border-radius: 25px;
+ padding: 5px 7px;
+ border: none;
+ outline: none;
+}
+
+.delete-task:hover {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+ -webkit-transition: all 0.1s ease-in-out;
+ transition: all 0.1s ease-in-out;
+ cursor: pointer;
+}
+/*# sourceMappingURL=todo.css.map */
\ No newline at end of file
diff --git a/src/js/components/todo/todo.js b/src/js/components/todo/todo.js
new file mode 100644
index 0000000..8b87457
--- /dev/null
+++ b/src/js/components/todo/todo.js
@@ -0,0 +1,272 @@
+import TodoMenu from './todo-menu';
+import './todo.css';
+
+const tasks = {
+ started: ['First task', 'Second task'],
+ completed: ['Solved task'],
+};
+
+const getTasks = () => {
+ let allTasks = {};
+
+ const localTasks = JSON.parse(localStorage.getItem('todo'));
+
+ if (localTasks) {
+ allTasks = localTasks;
+ } else {
+ allTasks = { ...tasks };
+ localStorage.setItem('todo', JSON.stringify(allTasks));
+ }
+ return allTasks;
+};
+
+class ToDo {
+ constructor(parentNode) {
+ this.parentNode = parentNode;
+ this.flag = true;
+ this.render();
+ }
+
+ fillActiveTaskBlock() {
+ const localTasks = getTasks();
+ const startBlock = this.parentNode.querySelector('.started');
+
+ startBlock.innerHTML = '';
+
+ localTasks.started.forEach((task, index) => {
+ const startedTask = document.createElement('div');
+ startedTask.classList.add('active-task', 'task');
+ startedTask.dataset.task = `task${index}`;
+ startedTask.innerHTML = `
+
+
+
+ `;
+ startBlock.appendChild(startedTask);
+ this.addDelBtnListener();
+ this.addCheckListener();
+ this.addInputListeners();
+ });
+ }
+
+ fillCompletedTaskBlock() {
+ const localTasks = getTasks();
+ const completeBlock = this.parentNode.querySelector('.completed');
+ const title = document.createElement('div');
+ title.classList.add('complete-title');
+
+ completeBlock.innerHTML = '';
+
+ localTasks.completed.forEach((task, index) => {
+ const completed = document.createElement('div');
+ completed.classList.add('complete-task', 'task');
+ completed.dataset.task = `task${index}${index}`;
+ completed.innerHTML = `
+
+
+
+ `;
+ completeBlock.appendChild(completed);
+ this.addDelBtnListener();
+ this.addCheckListener();
+ this.addInputListeners();
+ });
+ }
+
+ addNewTask() {
+ const localTasks = getTasks();
+ const input = this.parentNode.querySelector('.new-task');
+
+ if (input.value) localTasks.started.unshift(input.value);
+ localStorage.setItem('todo', JSON.stringify(localTasks));
+
+ input.value = '';
+ this.fillActiveTaskBlock();
+ }
+
+ addAddBtnListener() {
+ const addBtn = this.parentNode.querySelector('.add-task');
+ addBtn.addEventListener('click', this.addNewTask.bind(this));
+ }
+
+ addMainInputListener() {
+ const input = this.parentNode.querySelector('.new-task');
+ input.addEventListener('keypress', (e) => {
+ if (e.keyCode === 13) {
+ this.addNewTask.bind(this)();
+ input.blur();
+ }
+ });
+ }
+
+ delete(id) {
+ const localTasks = getTasks();
+ const deletedTask = this.parentNode.querySelector(`.input${id}`);
+
+ const startedTasks = localTasks.started.filter(
+ (task) => task !== deletedTask.value
+ );
+ const completedTasks = localTasks.completed.filter(
+ (task) => task !== deletedTask.value
+ );
+
+ localStorage.setItem(
+ 'todo',
+ JSON.stringify({
+ started: startedTasks,
+ completed: completedTasks,
+ })
+ );
+
+ this.fillActiveTaskBlock();
+ this.fillCompletedTaskBlock();
+ }
+
+ addDelBtnListener() {
+ const delBtn = this.parentNode.querySelectorAll('.delete-task');
+ delBtn.forEach((btn) => {
+ btn.onclick = (e) => {
+ const { id } = e.target.dataset;
+ this.delete.bind(this)(id);
+ };
+ });
+ }
+
+ addCheckListener() {
+ const checkboxes = this.parentNode.querySelectorAll('.checkbox-task');
+ checkboxes.forEach((checkbox) => {
+ checkbox.onclick = (e) => {
+ const { id } = e.target.dataset;
+ this.checkTask.bind(this)(id);
+ };
+ });
+ }
+
+ replaceStartedTask(id) {
+ const { started, completed } = getTasks();
+ const checkedTask = this.parentNode.querySelector(`.input${id}`);
+
+ const checked = started.find((task) => task === checkedTask.value);
+ completed.unshift(checked);
+ const startedTasks = started.filter((task) => task !== checkedTask.value);
+
+ localStorage.setItem(
+ 'todo',
+ JSON.stringify({
+ started: startedTasks,
+ completed,
+ })
+ );
+
+ this.fillActiveTaskBlock();
+ this.fillCompletedTaskBlock();
+ }
+
+ replaceCompletedTask(id) {
+ const { started, completed } = getTasks();
+ const checkedTask = this.parentNode.querySelector(`.input${id}`);
+
+ const checked = completed.find((task) => task === checkedTask.value);
+ started.push(checked);
+ const completedTasks = completed.filter(
+ (task) => task !== checkedTask.value
+ );
+
+ localStorage.setItem(
+ 'todo',
+ JSON.stringify({
+ started,
+ completed: completedTasks,
+ })
+ );
+
+ this.fillActiveTaskBlock();
+ this.fillCompletedTaskBlock();
+ }
+
+ checkTask(id) {
+ const checkbox = this.parentNode.querySelector(`.checkbox${id}`);
+
+ if (checkbox.checked) this.replaceStartedTask(id);
+ if (!checkbox.checked) this.replaceCompletedTask(id);
+ }
+
+ memorizeInputText(e) {
+ if (!this.flag) return;
+ this.flag = false;
+ const { id } = e.target.dataset;
+ const input = this.parentNode.querySelector(`.input${id}`);
+ localStorage.setItem('inputText', JSON.stringify(input.value));
+ }
+
+ setInputText(memorizedText, currentText) {
+ const { started, completed } = getTasks();
+ const indStartedTask = started.findIndex((text) => text === memorizedText);
+ const indCompletedTask = completed.findIndex(
+ (text) => text === memorizedText
+ );
+
+ if (indStartedTask !== -1) started[indStartedTask] = currentText;
+ if (indCompletedTask !== -1) completed[indCompletedTask] = currentText;
+
+ localStorage.setItem('todo', JSON.stringify({ started, completed }));
+
+ this.fillActiveTaskBlock();
+ this.fillCompletedTaskBlock();
+ }
+
+ getInputText(e) {
+ const memorizedText = JSON.parse(localStorage.getItem('inputText'));
+ const { id } = e.target.dataset;
+
+ const input = this.parentNode.querySelector(`.input${id}`);
+ const currentText = input.value;
+
+ this.setInputText(memorizedText, currentText);
+ this.flag = true;
+ }
+
+ addInputListeners() {
+ const textInputs = this.parentNode.querySelectorAll('.input-text');
+ textInputs.forEach((input) => {
+ input.onclick = (e) => this.memorizeInputText.bind(this)(e);
+ input.onblur = (e) => this.getInputText.bind(this)(e);
+ input.onkeypress = (e) => {
+ if (e.keyCode === 13) input.onblur(e);
+ };
+ });
+ }
+
+ render() {
+ this.parentNode.innerHTML = `
+
+
+
+
+
+
+
Active:
+
+
Completed:
+
+
+ `;
+ this.fillActiveTaskBlock();
+ this.fillCompletedTaskBlock();
+ this.addAddBtnListener();
+ this.addMainInputListener();
+ this.addInputListeners();
+
+ this.btnMenu = this.parentNode.querySelector('.dot-menu');
+ this.rssMenu = new TodoMenu(this.btnMenu, 'ToDo');
+ }
+}
+
+export default ToDo;
diff --git a/src/js/components/todo/todo.scss b/src/js/components/todo/todo.scss
new file mode 100644
index 0000000..f996555
--- /dev/null
+++ b/src/js/components/todo/todo.scss
@@ -0,0 +1,80 @@
+.todo-content {
+ padding: 10px 15px;
+}
+
+.add-item {
+ display: flex;
+ justify-content: space-between;
+ padding: 5px;
+}
+
+.input-task {
+ width: 85%;
+ border-radius: 25px;
+ padding-left: 10px;
+
+ &:hover,
+ &:focus {
+ border-radius: 25px;
+ outline: none;
+ box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+ }
+}
+
+.input-task.new-task {
+ width: 82%;
+ border: 2px solid rgb(107, 107, 107);
+}
+
+.add-task {
+ margin-left: -45px;
+ background-color: dodgerblue;
+ color: white;
+ border-radius: 25px;
+ padding: 10px 12px;
+ border: none;
+ outline: none;
+
+ &:hover {
+ transform: scale(1.1);
+ transition: all 0.1s ease-in-out;
+ cursor: pointer;
+ }
+}
+
+.task {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+
+ .resolved {
+ text-decoration: line-through;
+ opacity: 0.6;
+ }
+}
+
+.task .input-task {
+ width: 75%;
+ margin: 5px;
+ font-size: 0.9rem;
+ border: none;
+}
+
+.delete-task {
+ background-color: tomato;
+ margin-right: 5px;
+ color: white;
+ border: 0px;
+ border-radius: 25px;
+ // padding: 5px 6px 2px 6px;
+ padding: 5px 7px;
+ border: none;
+ outline: none;
+
+ &:hover {
+ transform: scale(1.1);
+ transition: all 0.1s ease-in-out;
+ cursor: pointer;
+ }
+}
diff --git a/src/js/components/travel-menu/travel-menu.js b/src/js/components/travel-menu/travel-menu.js
index 423a2c0..eb39d1f 100644
--- a/src/js/components/travel-menu/travel-menu.js
+++ b/src/js/components/travel-menu/travel-menu.js
@@ -1,19 +1,29 @@
-import "./travel-menu.css";
-import { fullTravelLinks, faviconUrl } from "../../data/constants";
-import Menu from "../base-menu/baseMenu";
-import Travel from "../travel/travel";
+import './travel-menu.css';
+import { fullTravelLinks, faviconUrl } from '../../data/constants';
+import Menu from '../base-menu/baseMenu';
+import Travel from '../travel/travel';
+import { getOptionItems } from '../options-menu/options-menu';
+
+const getImage = (website) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`;
+ } else {
+ img = '';
+ }
+ return img;
+};
const getFullLinks = () => {
let fullLinks = [];
- const localTravelLinks = JSON.parse(
- localStorage.getItem("fullTravelLinks")
- );
+ const localTravelLinks = JSON.parse(localStorage.getItem('fullTravelLinks'));
if (localTravelLinks) {
fullLinks = localTravelLinks;
} else {
fullLinks = fullTravelLinks;
- localStorage.setItem("fullTravelLinks", JSON.stringify(fullTravelLinks));
+ localStorage.setItem('fullTravelLinks', JSON.stringify(fullTravelLinks));
}
return fullLinks;
};
@@ -21,13 +31,13 @@ const getFullLinks = () => {
const getTravelLinks = () => {
let travelLinks = [];
- const localTravelLinks = JSON.parse(localStorage.getItem("travelLinks"));
+ const localTravelLinks = JSON.parse(localStorage.getItem('travelLinks'));
if (localTravelLinks) {
travelLinks = localTravelLinks;
} else {
travelLinks = fullTravelLinks.slice(0, 6);
- localStorage.setItem("travelLinks", JSON.stringify(travelLinks));
+ localStorage.setItem('travelLinks', JSON.stringify(travelLinks));
}
return travelLinks;
};
@@ -45,8 +55,8 @@ class TravelMenu extends Menu {
(website) => website.title === title
);
- let check = "";
- if (activeLinks) check = "checked";
+ let check = '';
+ if (activeLinks) check = 'checked';
return check;
}
@@ -67,36 +77,36 @@ class TravelMenu extends Menu {
localTravelLinks.push(necessaryService);
}
- localStorage.setItem("travelLinks", JSON.stringify(localTravelLinks));
+ localStorage.setItem('travelLinks', JSON.stringify(localTravelLinks));
}
clearMenuContent() {
const websites = document.querySelectorAll(`.website.travel`);
websites.forEach((link) => link.parentElement.removeChild(link));
- const nameWebsite = document.querySelector(".name-input.travel");
- const urlWebsite = document.querySelector(".url-input.travel");
+ const nameWebsite = document.querySelector('.name-input.travel');
+ const urlWebsite = document.querySelector('.url-input.travel');
- if (nameWebsite) nameWebsite.value = "";
- if (urlWebsite) urlWebsite.value = "";
+ if (nameWebsite) nameWebsite.value = '';
+ if (urlWebsite) urlWebsite.value = '';
}
fillMenuContent() {
this.clearMenuContent();
- const menuContent = document.querySelector(".menu-content.Trav");
+ const menuContent = document.querySelector('.menu-content.Trav');
const fragment = document.createDocumentFragment();
const fullLocalLinks = getFullLinks();
fullLocalLinks.forEach((website) => {
const check = this.findActiveWebsite(website.title);
- const web = document.createElement("div");
- web.classList.add("website", "travel");
+ const web = document.createElement('div');
+ web.classList.add('website', 'travel');
web.innerHTML = `
`;
@@ -106,9 +116,9 @@ class TravelMenu extends Menu {
}
createForm() {
- const menuContent = document.querySelector(".menu-content.Trav");
- const form = document.createElement("div");
- form.classList.add("form");
+ const menuContent = document.querySelector('.menu-content.Trav');
+ const form = document.createElement('div');
+ form.classList.add('form');
form.innerHTML = `
@@ -121,14 +131,17 @@ class TravelMenu extends Menu {
+
+
+
`;
menuContent.appendChild(form);
}
createObjForSet() {
- const nameWebsite = document.querySelector(".name-input.travel");
- const urlWebsite = document.querySelector(".url-input.travel");
+ const nameWebsite = document.querySelector('.name-input.travel');
+ const urlWebsite = document.querySelector('.url-input.travel');
const title = nameWebsite.value;
const url = urlWebsite.value;
@@ -148,17 +161,17 @@ class TravelMenu extends Menu {
const data = this.createObjForSet();
if (data) {
const fullLocalLinks = JSON.parse(
- localStorage.getItem("fullTravelLinks")
+ localStorage.getItem('fullTravelLinks')
);
fullLocalLinks.push(data);
- localStorage.setItem("fullTravelLinks", JSON.stringify(fullLocalLinks));
+ localStorage.setItem('fullTravelLinks', JSON.stringify(fullLocalLinks));
}
}
cleanLocalLinks() {
- localStorage.removeItem("fullTravelLinks");
- localStorage.removeItem("travelLinks");
- Travel.prototype.fillContentBlock(this.privateClass, "travelLinks");
+ localStorage.removeItem('fullTravelLinks');
+ localStorage.removeItem('travelLinks');
+ Travel.prototype.fillContentBlock(this.privateClass, 'travelLinks');
}
changeLinks(e) {
@@ -166,12 +179,12 @@ class TravelMenu extends Menu {
const activeWebsite = this.findActiveWebsite(websiteClickedCheckbox);
this.changeWebsiteArray(activeWebsite, websiteClickedCheckbox);
- Travel.prototype.fillContentBlock(this.privateClass, "travelLinks");
+ Travel.prototype.fillContentBlock(this.privateClass, 'travelLinks');
}
addListenerToBtn() {
const btnSub = document.querySelector(`.submit.travel`);
- btnSub.addEventListener("click", () => {
+ btnSub.addEventListener('click', () => {
this.createObjForSet.bind(this)();
this.setObjData.bind(this)();
this.fillMenuContent.bind(this)();
@@ -181,7 +194,7 @@ class TravelMenu extends Menu {
addListenerToDelBtn() {
const btnDel = document.querySelector(`.delete.travel`);
- btnDel.addEventListener("click", () => {
+ btnDel.addEventListener('click', () => {
this.cleanLocalLinks();
this.fillMenuContent.bind(this)();
this.addListenerToLabel.bind(this)();
@@ -191,16 +204,31 @@ class TravelMenu extends Menu {
addListenerToLabel() {
const labels = this.parentNode.querySelectorAll(`.input-travel`);
labels.forEach((label) =>
- label.addEventListener("click", this.changeLinks.bind(this))
+ label.addEventListener('click', this.changeLinks.bind(this))
);
}
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.travel');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector('[data-btn="travel"]');
+ const btnDel = document.querySelector('.delete.travel');
+
+ mainMenuBtn.click();
+ btnDel.click();
+
+ this.hide.bind(this)();
+ });
+ }
+
renderContent() {
this.fillMenuContent();
this.createForm();
this.addListenerToLabel();
this.addListenerToBtn();
this.addListenerToDelBtn();
+ this.addDangerBtnListener();
}
}
diff --git a/src/js/components/travel/travel.js b/src/js/components/travel/travel.js
index 10fbc35..bfc6173 100644
--- a/src/js/components/travel/travel.js
+++ b/src/js/components/travel/travel.js
@@ -2,7 +2,29 @@
import "./travel.css";
import { fullTravelLinks } from "../../data/constants";
import TravelMenu from "../travel-menu/travel-menu";
+import { getOptionItems } from "../options-menu/options-menu";
+const getImage = (url) => {
+ const optionFavicon = getOptionItems()[0];
+ let img;
+ if (optionFavicon.checked) {
+ img = `
`
+ } else {
+ img = '';
+ }
+ return img;
+}
+
+const getTargetBlank = () => {
+ let targetBlank;
+ const optionTarget = getOptionItems()[1];
+ if (optionTarget.checked) {
+ targetBlank = '_blank'
+ } else {
+ targetBlank = ''
+ }
+ return targetBlank;
+}
class Travel {
constructor(obj) {
this.parentNode = obj.parentNode;
@@ -43,8 +65,8 @@ class Travel {
website.classList.add("websites", `${myClass}`);
website.innerHTML = `
-
-
+
+ ${getImage(web.favicon)}
${web.title}
`;
diff --git a/src/js/components/weather/owfont-regular.css b/src/js/components/weather/owfont-regular.css
new file mode 100644
index 0000000..bc17040
--- /dev/null
+++ b/src/js/components/weather/owfont-regular.css
@@ -0,0 +1,559 @@
+/*!
+ * owfont-regular 1.0.0 by Deniz Fuchidzhiev - http://websygen.com
+ * License - font: SIL OFL 1.1, css: MIT License
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+ font-family: 'owfont';
+ /* src: url('fonts/owfont-regular.eot?v=1.0.0'); */
+ src: url('../../../assets/fonts/fonts-weather/owfont-regular.eot?v=1.0.0');
+ src: url('../../../assets/fonts/fonts-weather/owfont-regular.eot?#iefix&v=1.0.0') format('embedded-opentype'),
+ url('../../../assets/fonts/fonts-weather/owfont-regular.woff') format('woff'),
+ url('../../../assets/fonts/fonts-weather/owfont-regular.ttf') format('truetype'),
+ url('../../../assets/fonts/fonts-weather/owfont-regular.svg#owf-regular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+.owf {
+ display: inline-block;
+ font: normal normal normal 14px/1 owfont;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ transform: translate(0, 0);
+}
+/* makes the font 33% larger relative to the icon container */
+.owf-lg {
+ font-size: 1.33333333em;
+ line-height: 0.75em;
+ vertical-align: -15%;
+}
+.owf-2x {
+ font-size: 2em;
+}
+.owf-3x {
+ font-size: 3em;
+}
+.owf-4x {
+ font-size: 4em;
+}
+.owf-5x {
+ font-size: 5em;
+}
+.owf-fw {
+ width: 1.28571429em;
+ text-align: center;
+}
+.owf-ul {
+ padding-left: 0;
+ margin-left: 2.14285714em;
+ list-style-type: none;
+}
+.owf-ul > li {
+ position: relative;
+}
+.owf-li {
+ position: absolute;
+ left: -2.14285714em;
+ width: 2.14285714em;
+ top: 0.14285714em;
+ text-align: center;
+}
+.owf-li.owf-lg {
+ left: -1.85714286em;
+}
+.owf-border {
+ padding: .2em .25em .15em;
+ border: solid 0.08em #eeeeee;
+ border-radius: .1em;
+}
+.owf-pull-right {
+ float: right;
+}
+.owf-pull-left {
+ float: left;
+}
+.owf.owf-pull-left {
+ margin-right: .3em;
+}
+.owf.owf-pull-right {
+ margin-left: .3em;
+}
+
+/* owfont uses the Unicode Private Use Area (PUA) to ensure screen
+ readers do not read off random characters that represent icons */
+
+/* Weather Condition Codes */
+
+/* Thunderstorm - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* thunderstorm with light rain */
+.owf-200:before,
+.owf-200-d:before,
+.owf-200-n:before {
+ content: "\EB28";
+}
+/* thunderstorm with rain */
+.owf-201:before,
+.owf-201-d:before,
+.owf-201-n:before {
+ content: "\EB29";
+}
+/* thunderstorm with heavy rain */
+.owf-202:before,
+.owf-202-d:before,
+.owf-202-n:before {
+ content: "\EB2A";
+}
+/* light thunderstorm */
+.owf-210:before,
+.owf-210-d:before,
+.owf-210-n:before {
+ content: "\EB32";
+}
+/* thunderstorm */
+.owf-211:before,
+.owf-211-d:before,
+.owf-211-n:before {
+ content: "\EB33";
+}
+/* heavy thunderstorm */
+.owf-212:before,
+.owf-212-d:before,
+.owf-212-n:before {
+ content: "\EB34";
+}
+/* ragged thunderstorm */
+.owf-221:before,
+.owf-221-d:before,
+.owf-221-n:before {
+ content: "\EB3D";
+}
+/* thunderstorm with light drizzle */
+.owf-230:before,
+.owf-230-d:before,
+.owf-230-n:before {
+ content: "\EB46";
+}
+/* thunderstorm with drizzle */
+.owf-231:before,
+.owf-231-d:before,
+.owf-231-n:before {
+ content: "\EB47";
+}
+/* thunderstorm with heavy drizzle */
+.owf-232:before,
+.owf-232-d:before,
+.owf-232-n:before {
+ content: "\EB48";
+}
+
+/* Drizzle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* light intensity drizzle */
+.owf-300:before,
+.owf-300-d:before,
+.owf-300-n:before {
+ content: "\EB8C";
+}
+/* drizzle */
+.owf-301:before,
+.owf-301-d:before,
+.owf-301-n:before {
+ content: "\EB8D";
+}
+/* heavy intensity drizzle */
+.owf-302:before,
+.owf-302-d:before,
+.owf-302-n:before {
+ content: "\EB8E";
+}
+/* light intensity drizzle rain */
+.owf-310:before,
+.owf-310-d:before,
+.owf-310-n:before {
+ content: "\EB96";
+}
+/* drizzle rain */
+.owf-311:before,
+.owf-311-d:before,
+.owf-311-n:before {
+ content: "\EB97";
+}
+/* heavy intensity drizzle rain */
+.owf-312:before,
+.owf-312-d:before,
+.owf-312-n:before {
+ content: "\EB98";
+}
+/* shower rain and drizzle */
+.owf-313:before,
+.owf-313-d:before,
+.owf-313-n:before {
+ content: "\EB99";
+}
+/* heavy shower rain and drizzle*/
+.owf-314:before,
+.owf-314-d:before,
+.owf-314-n:before {
+ content: "\EB9A";
+}
+/* shower drizzle */
+.owf-321:before,
+.owf-321-d:before,
+.owf-321-n:before {
+ content: "\EBA1";
+}
+
+/* Rain - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* light rain */
+.owf-500:before,
+.owf-500-d:before,
+.owf-500-n:before {
+ content: "\EC54";
+}
+/* moderate rain */
+.owf-501:before,
+.owf-501-d:before,
+.owf-501-n:before {
+ content: "\EC55";
+}
+/* heavy intensity rain */
+.owf-502:before,
+.owf-502-d:before,
+.owf-502-n:before {
+ content: "\EC56";
+}
+/* very heavy rain */
+.owf-503:before,
+.owf-503-d:before,
+.owf-503-n:before {
+ content: "\EC57";
+}
+/* extreme rain */
+.owf-504:before,
+.owf-504-d:before,
+.owf-504-n:before {
+ content: "\EC58";
+}
+/* freezing rain */
+.owf-511:before,
+.owf-511-d:before,
+.owf-511-n:before {
+ content: "\EC5F";
+}
+/* light intensity shower rain */
+.owf-520:before,
+.owf-520-d:before,
+.owf-520-n:before {
+ content: "\EC68";
+}
+/* shower rain */
+.owf-521:before,
+.owf-521-d:before,
+.owf-521-n:before {
+ content: "\EC69";
+}
+/* heavy intensity shower rain */
+.owf-522:before,
+.owf-522-d:before,
+.owf-522-n:before {
+ content: "\EC6A";
+}
+/* ragged shower rain */
+.owf-531:before,
+.owf-531-d:before,
+.owf-531-n:before {
+ content: "\EC73";
+}
+
+/* Snow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* light snow */
+.owf-600:before,
+.owf-600-d:before,
+.owf-600-n:before {
+ content: "\ECB8";
+}
+/* snow */
+.owf-601:before,
+.owf-601-d:before,
+.owf-601-n:before {
+ content: "\ECB9";
+}
+/* heavy snow */
+.owf-602:before,
+.owf-602-d:before,
+.owf-602-n:before {
+ content: "\ECBA";
+}
+/* sleet */
+.owf-611:before,
+.owf-611-d:before,
+.owf-611-n:before {
+ content: "\ECC3";
+}
+/* shower sleet */
+.owf-612:before,
+.owf-612-d:before,
+.owf-612-n:before {
+ content: "\ECC4";
+}
+/* light rain and snow */
+.owf-615:before,
+.owf-615-d:before,
+.owf-615-n:before {
+ content: "\ECC7";
+}
+/* rain and snow */
+.owf-616:before,
+.owf-616-d:before,
+.owf-616-n:before {
+ content: "\ECC8";
+}
+/* light shower snow */
+.owf-620:before,
+.owf-620-d:before,
+.owf-620-n:before {
+ content: "\ECCC";
+}
+/* shower snow */
+.owf-621:before,
+.owf-621-d:before,
+.owf-621-n:before {
+ content: "\ECCD";
+}
+/* heavy shower snow */
+.owf-622:before,
+.owf-622-d:before,
+.owf-622-n:before {
+ content: "\ECCE";
+}
+
+/* Atmosphere - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* mist */
+.owf-701:before,
+.owf-701-d:before,
+.owf-701-n:before {
+ content: "\ED1D";
+}
+/* smoke */
+.owf-711:before,
+.owf-711-d:before,
+.owf-711-n:before {
+ content: "\ED27";
+}
+/* haze */
+.owf-721:before,
+.owf-721-d:before,
+.owf-721-n:before {
+ content: "\ED31";
+}
+/* Sand/Dust Whirls */
+.owf-731:before,
+.owf-731-d:before,
+.owf-731-n:before {
+ content: "\ED3B";
+}
+/* Fog */
+.owf-741:before,
+.owf-741-d:before,
+.owf-741-n:before {
+ content: "\ED45";
+}
+/* sand */
+.owf-751:before,
+.owf-751-d:before,
+.owf-751-n:before {
+ content: "\ED4F";
+}
+/* dust */
+.owf-761:before,
+.owf-761-d:before,
+.owf-761-n:before {
+ content: "\ED59";
+}
+/* VOLCANIC ASH */
+.owf-762:before,
+.owf-762-d:before,
+.owf-762-n:before {
+ content: "\ED5A";
+}
+/* SQUALLS */
+.owf-771:before,
+.owf-771-d:before,
+.owf-771-n:before {
+ content: "\ED63";
+}
+/* TORNADO */
+.owf-781:before,
+.owf-781-d:before,
+.owf-781-n:before {
+ content: "\ED6D";
+}
+
+/* Clouds - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* sky is clear */ /* Calm */
+.owf-800:before,
+.owf-800-d:before,
+.owf-951:before,
+.owf-951-d:before {
+ content: "\ED80";
+}
+.owf-800-n:before,
+.owf-951-n:before {
+ content: "\F168";
+}
+/* few clouds */
+.owf-801:before,
+.owf-801-d:before {
+ content: "\ED81";
+}
+.owf-801-n:before {
+ content: "\F169";
+}
+/* scattered clouds */
+.owf-802:before,
+.owf-802-d:before {
+ content: "\ED82";
+}
+.owf-802-n:before {
+ content: "\F16A";
+}
+/* broken clouds */
+.owf-803:before,
+.owf-803-d:before,
+.owf-803-n:before {
+ content: "\ED83";
+}
+/* overcast clouds */
+.owf-804:before,
+.owf-804-d:before,
+.owf-804-n:before {
+ content: "\ED84";
+}
+
+/* Extreme - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* tornado */
+.owf-900:before,
+.owf-900-d:before,
+.owf-900-n:before {
+ content: "\EDE4";
+}
+/* tropical storm */
+.owf-901:before,
+.owf-901-d:before,
+.owf-901-n:before {
+ content: "\EDE5";
+}
+/* hurricane */
+.owf-902:before,
+.owf-902-d:before,
+.owf-902-n:before {
+ content: "\EDE6";
+}
+/* cold */
+.owf-903:before,
+.owf-903-d:before,
+.owf-903-n:before {
+ content: "\EDE7";
+}
+/* hot */
+.owf-904:before,
+.owf-904-d:before,
+.owf-904-n:before {
+ content: "\EDE8";
+}
+/* windy */
+.owf-905:before,
+.owf-905-d:before,
+.owf-905-n:before {
+ content: "\EDE9";
+}
+/* hail */
+.owf-906:before,
+.owf-906-d:before,
+.owf-906-n:before {
+ content: "\EDEA";
+}
+
+/* Additional - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Setting */
+.owf-950:before,
+.owf-950-d:before,
+.owf-950-n:before {
+ content: "\EE16";
+}
+/* Light breeze */
+.owf-952:before,
+.owf-952-d:before,
+.owf-952-n:before {
+ content: "\EE18";
+}
+/* Gentle Breeze */
+.owf-953:before,
+.owf-953-d:before,
+.owf-953-n:before {
+ content: "\EE19";
+}
+/* Moderate breeze */
+.owf-954:before,
+.owf-954-d:before,
+.owf-954-n:before {
+ content: "\EE1A";
+}
+/* Fresh Breeze */
+.owf-955:before,
+.owf-955-d:before,
+.owf-955-n:before {
+ content: "\EE1B";
+}
+/* Strong Breeze */
+.owf-956:before,
+.owf-956-d:before,
+.owf-956-n:before {
+ content: "\EE1C";
+}
+/* High wind, near gale */
+.owf-957:before,
+.owf-957-d:before,
+.owf-957-n:before {
+ content: "\EE1D";
+}
+/* Gale */
+.owf-958:before,
+.owf-958-d:before,
+.owf-958-n:before {
+ content: "\EE1E";
+}
+/* Severe Gale */
+.owf-959:before,
+.owf-959-d:before,
+.owf-959-n:before {
+ content: "\EE1F";
+}
+/* Storm */
+.owf-960:before,
+.owf-960-d:before,
+.owf-960-n:before {
+ content: "\EE20";
+}
+/* Violent Storm */
+.owf-961:before,
+.owf-961-d:before,
+.owf-961-n:before {
+ content: "\EE21";
+}
+/* Hurricane */
+.owf-962:before,
+.owf-962-d:before,
+.owf-962-n:before {
+ content: "\EE22";
+}
\ No newline at end of file
diff --git a/src/js/components/weather/weather-menu.js b/src/js/components/weather/weather-menu.js
new file mode 100644
index 0000000..7c618ba
--- /dev/null
+++ b/src/js/components/weather/weather-menu.js
@@ -0,0 +1,39 @@
+// import './rss-menu.css';
+import Menu from '../base-menu/baseMenu';
+import create from '../../utils/create';
+
+class WeatherMenu extends Menu {
+ constructor(clickedElement, caption) {
+ super(clickedElement, caption);
+ this.renderContent();
+ }
+
+ addDangerBtn() {
+ const menuContent = this.parentNode.querySelector('.menu-content.Weat');
+
+ create(
+ 'div',
+ 'danger-block',
+ ``,
+ menuContent
+ );
+ }
+
+ addDangerBtnListener() {
+ const dangerBtn = this.parentNode.querySelector('.danger.weather');
+
+ dangerBtn.addEventListener('click', () => {
+ const mainMenuBtn = this.parentNode.querySelector(`[data-btn="weather"]`);
+ mainMenuBtn.click();
+ this.hide.bind(this)();
+ localStorage.removeItem('city');
+ });
+ }
+
+ renderContent() {
+ this.addDangerBtn();
+ this.addDangerBtnListener();
+ }
+}
+
+export default WeatherMenu;
diff --git a/src/js/components/weather/weather.css b/src/js/components/weather/weather.css
new file mode 100644
index 0000000..d6e20b5
--- /dev/null
+++ b/src/js/components/weather/weather.css
@@ -0,0 +1,19 @@
+.weather-content {
+ text-align: center;
+ background-image: url(../../../assets/img/weather.jpg);
+ background-size: cover;
+ display: -ms-grid;
+ display: grid;
+ grid-gap: 5px;
+ padding: 10px;
+ text-shadow: 0px 0px 10px #e4b18c;
+}
+
+.city:focus,
+.city:hover {
+ border-radius: 25px;
+ outline: none;
+ -webkit-box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+ box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+}
+/*# sourceMappingURL=weather.css.map */
\ No newline at end of file
diff --git a/src/js/components/weather/weather.js b/src/js/components/weather/weather.js
new file mode 100644
index 0000000..bb80169
--- /dev/null
+++ b/src/js/components/weather/weather.js
@@ -0,0 +1,122 @@
+import './weather.css';
+import './owfont-regular.css';
+import WeatherMenu from './weather-menu';
+
+class Weather {
+ constructor(parentNode) {
+ this.parentNode = parentNode;
+ this.render();
+ }
+
+ getDomElements() {
+ const weatherIcon = this.parentNode.querySelector('.weather-icon');
+ const temperature = this.parentNode.querySelector('.temperature');
+ const humidity = this.parentNode.querySelector('.humidity');
+ const wind = this.parentNode.querySelector('.wind');
+ const weatherDescription = this.parentNode.querySelector(
+ '.weather-description'
+ );
+ const city = this.parentNode.querySelector('.city');
+
+ return {
+ weatherIcon,
+ temperature,
+ humidity,
+ wind,
+ weatherDescription,
+ city,
+ };
+ }
+
+ addListeners() {
+ const { city } = this.getDomElements();
+ city.addEventListener('keypress', this.setCity.bind(this));
+ city.addEventListener('blur', this.setCity.bind(this));
+ city.addEventListener('click', () => (city.textContent = ''));
+ }
+
+ async getWeatherData() {
+ const { city } = this.getDomElements();
+
+ if (localStorage.getItem('city') === null) {
+ city.textContent = 'Minsk';
+ } else {
+ city.textContent = localStorage.getItem('city');
+ }
+ const url = `https://api.openweathermap.org/data/2.5/weather?q=${city.textContent}&lang=en&appid=543c9bb3c115ee39476506208d454b41&units=metric`;
+ const res = await fetch(url);
+ const data = await res.json();
+ if (!res.ok) city.textContent = 'Enter correct city';
+
+ return data;
+ }
+
+ async fillWeatherBlock() {
+ const data = await this.getWeatherData();
+ const {
+ weatherIcon,
+ temperature,
+ humidity,
+ wind,
+ weatherDescription,
+ } = this.getDomElements();
+
+ weatherIcon.className = 'weather-icon owf';
+ weatherIcon.classList.add(`owf-${data.weather[0].id}`);
+ temperature.textContent = `${data.main.temp}°C`;
+ humidity.textContent = `Humidity ${data.main.humidity} %`;
+ wind.textContent = `Wind speed ${data.wind.speed} m/s`;
+ weatherDescription.textContent = data.weather[0].description;
+ }
+
+ setCity(e) {
+ const { city } = this.getDomElements();
+ const pressedEnter = e.which === 13 || e.keyCode === 13;
+ const cityEntered =
+ e.target.innerText !== '' && e.target.innerText !== 'Minsk';
+ this.fillWeatherBlock.bind(this);
+ if (e.type === 'keypress') {
+ if (pressedEnter) {
+ city.blur();
+ if (cityEntered) {
+ localStorage.setItem('city', e.target.innerText);
+ city.blur();
+ this.fillWeatherBlock();
+ }
+ }
+ } else if (e.target.innerText === '') {
+ city.textContent = localStorage.getItem('city') || 'Minsk';
+ } else {
+ localStorage.setItem('city', e.target.innerText);
+ this.fillWeatherBlock();
+ }
+ }
+
+ render() {
+ this.parentNode.innerHTML = `
+
+
+ `;
+ this.fillWeatherBlock();
+ this.addListeners();
+
+ this.btnMenu = this.parentNode.querySelector('.dot-menu');
+ this.rssMenu = new WeatherMenu(this.btnMenu, 'Weather');
+ }
+}
+
+export default Weather;
diff --git a/src/js/components/weather/weather.scss b/src/js/components/weather/weather.scss
new file mode 100644
index 0000000..41d104c
--- /dev/null
+++ b/src/js/components/weather/weather.scss
@@ -0,0 +1,16 @@
+.weather-content{
+ text-align: center;
+ background-image: url(../../../assets/img/weather.jpg);
+ background-size: cover;
+ display: grid;
+ grid-gap: 5px;
+ padding: 10px;
+ text-shadow: 0px 0px 10px rgb(228, 177, 140);
+}
+
+.city:focus,
+.city:hover{
+ border-radius: 25px;
+ outline: none;
+ box-shadow: 0px 0px 5px 0px rgba(50, 50, 50, 0.75);
+}
\ No newline at end of file
diff --git a/src/js/data/constants.js b/src/js/data/constants.js
index ee5ec59..edd1fab 100644
--- a/src/js/data/constants.js
+++ b/src/js/data/constants.js
@@ -1,184 +1,225 @@
-export const APP_NAME = "Start Page";
+export const APP_NAME = 'Start Page';
+
+export const backend = 'https://startpage-be.herokuapp.com';
+export const userItemLocalStorage = 'startpage-user';
export const DEVELOPERS = [
{
- user: "natein",
- link: "https://github.com/natein",
+ user: 'natein',
+ link: 'https://github.com/natein',
},
{
- user: "vadim-bykov",
- link: "https://github.com/vadim-bykov",
+ user: 'vadim-bykov',
+ link: 'https://github.com/vadim-bykov',
},
];
-export const DEFAULT_COLOR = "#F5D678";
+export const DEFAULT_COLOR = '#F5D678';
export const INITIAL_PAGE = [
{
- name: "Start Page",
+ name: 'Start Page',
color: DEFAULT_COLOR,
},
];
-export const COURSE_LINK = "https://rs.school/js/";
-export const COURSE_NAME = "JavaScript/Front-end 2020Q3";
+export const COURSE_LINK = 'https://rs.school/js/';
+export const COURSE_NAME = 'JavaScript/Front-end 2020Q3';
-export const faviconUrl =
- "https://www.google.com/s2/favicons?sz=48&domain_url=";
+export const faviconUrl = 'https://www.google.com/s2/favicons?sz=48&domain_url=';
export const fullPopularLinks = [
{
- title: "Wikipedia",
- url: "https://ru.wikipedia.org/",
+ title: 'Wikipedia',
+ url: 'https://ru.wikipedia.org/',
favicon: `${faviconUrl}https://ru.wikipedia.org/`,
},
{
- title: "YouTube",
- url: "https://www.youtube.com/",
+ title: 'YouTube',
+ url: 'https://www.youtube.com/',
favicon: `${faviconUrl}https://www.youtube.com/`,
},
{
- title: "facebook",
- url: "https://www.facebook.com/",
+ title: 'facebook',
+ url: 'https://www.facebook.com/',
favicon: `${faviconUrl}https://www.facebook.com/`,
},
{
- title: "ВКонтакте",
- url: "https://vk.com/",
+ title: 'ВКонтакте',
+ url: 'https://vk.com/',
favicon: `${faviconUrl}https://vk.com/`,
},
{
- title: "Одноклассники",
- url: "https://ok.ru/",
+ title: 'Одноклассники',
+ url: 'https://ok.ru/',
favicon: `${faviconUrl}https://ok.ru/`,
},
{
- title: "Yandex",
- url: "https://yandex.ru/",
+ title: 'Yandex',
+ url: 'https://yandex.ru/',
favicon: `${faviconUrl}https://yandex.ru/`,
},
{
- title: "Linkedin",
- url: "https://www.linkedin.com/",
+ title: 'Linkedin',
+ url: 'https://www.linkedin.com/',
favicon: `${faviconUrl}https://www.linkedin.com/`,
},
];
export const fullShopsLinks = [
{
- title: "Joom",
- url: "https://www.joom.com/",
+ title: 'Joom',
+ url: 'https://www.joom.com/',
favicon: `${faviconUrl}https://www.joom.com/`,
},
{
- title: "Из рук в руки",
- url: "https://irr.ru/",
+ title: 'Из рук в руки',
+ url: 'https://irr.ru/',
favicon: `${faviconUrl}https://irr.ru/`,
},
{
- title: "Lamoda",
- url: "https://www.lamoda.ru/",
+ title: 'Lamoda',
+ url: 'https://www.lamoda.ru/',
favicon: `${faviconUrl}https://www.lamoda.ru/`,
},
{
- title: "Wildberries",
- url: "https://www.wildberries.ru/",
+ title: 'Wildberries',
+ url: 'https://www.wildberries.ru/',
favicon: `${faviconUrl}https://www.wildberries.ru/`,
},
{
- title: "Drom",
- url: "https://www.drom.ru/",
+ title: 'Drom',
+ url: 'https://www.drom.ru/',
favicon: `${faviconUrl}https://www.drom.ru/`,
},
{
- title: "Avito",
- url: "https://www.avito.ru/rossiya",
+ title: 'Avito',
+ url: 'https://www.avito.ru/rossiya',
favicon: `${faviconUrl}https://www.avito.ru/rossiya`,
},
{
- title: "Onliner",
- url: "https://www.onliner.by/",
+ title: 'Onliner',
+ url: 'https://www.onliner.by/',
favicon: `${faviconUrl}https://www.onliner.by/`,
},
];
export const fullTravelLinks = [
{
- title: "Booking",
- url: "https://www.booking.com/",
+ title: 'Booking',
+ url: 'https://www.booking.com/',
favicon: `${faviconUrl}https://www.booking.com/`,
},
{
- title: "Tripadvisor",
- url: "https://www.tripadvisor.ru/",
+ title: 'Tripadvisor',
+ url: 'https://www.tripadvisor.ru/',
favicon: `${faviconUrl}https://www.tripadvisor.ru/`,
},
{
- title: "Tophotels",
- url: "https://tophotels.ru/",
+ title: 'Tophotels',
+ url: 'https://tophotels.ru/',
favicon: `${faviconUrl}https://tophotels.ru/`,
},
{
- title: "Skyscanner",
- url: "https://www.skyscanner.net/",
+ title: 'Skyscanner',
+ url: 'https://www.skyscanner.net/',
favicon: `${faviconUrl}https://www.skyscanner.net/`,
},
{
- title: "Expedia",
- url: "https://www.expedia.com/",
+ title: 'Expedia',
+ url: 'https://www.expedia.com/',
favicon: `${faviconUrl}https://www.expedia.com/`,
},
{
- title: "Joinpro",
- url: "http://www.joinpro.ru/",
+ title: 'Joinpro',
+ url: 'http://www.joinpro.ru/',
favicon: `${faviconUrl}http://www.joinpro.ru/`,
},
{
- title: "Turpravda",
- url: "https://www.turpravda.com/",
+ title: 'Turpravda',
+ url: 'https://www.turpravda.com/',
favicon: `${faviconUrl}https://www.turpravda.com/`,
},
];
export const fullGoogleLinks = [
{
- title: "Sign in",
- url: "https://plus.google.com/",
+ title: 'Sign in',
+ url: 'https://plus.google.com/',
favicon: `${faviconUrl}https://plus.google.com/`,
},
{
- title: "News",
- url: "https://news.google.com/",
+ title: 'News',
+ url: 'https://news.google.com/',
favicon: `${faviconUrl}https://news.google.com/`,
},
{
- title: "Maps",
- url: "https://www.google.com/maps/",
+ title: 'Maps',
+ url: 'https://www.google.com/maps/',
favicon: `${faviconUrl}https://www.google.com/maps/`,
},
{
- title: "Calendar",
- url: "https://calendar.google.com/calendar/u/0/r?pli=1",
+ title: 'Calendar',
+ url: 'https://calendar.google.com/calendar/u/0/r?pli=1',
favicon: `${faviconUrl}https://calendar.google.com/calendar/u/0/r?pli=1`,
},
{
- title: "Play",
- url: "https://play.google.com/store",
+ title: 'Play',
+ url: 'https://play.google.com/store',
favicon: `${faviconUrl}https://play.google.com/store`,
},
{
- title: "Blogger",
- url: "https://www.blogger.com/",
+ title: 'Blogger',
+ url: 'https://www.blogger.com/',
favicon: `${faviconUrl}https://www.blogger.com/`,
},
{
- title: "Translate",
- url: "https://translate.google.com/",
+ title: 'Translate',
+ url: 'https://translate.google.com/',
favicon: `${faviconUrl}https://translate.google.com/`,
},
{
- title: "Drive",
- url: "https://drive.google.com/",
+ title: 'Drive',
+ url: 'https://drive.google.com/',
favicon: `${faviconUrl}https://drive.google.com/`,
},
];
+
+export const classListBlocks = [
+ {
+ class: 'finance',
+ active: true,
+ },
+ {
+ class: 'rss',
+ active: true,
+ },
+ {
+ class: 'popular',
+ active: true,
+ },
+ {
+ class: 'shops',
+ active: true,
+ },
+ {
+ class: 'travel',
+ active: true,
+ },
+ {
+ class: 'google',
+ active: true,
+ },
+ {
+ class: 'weather',
+ active: true,
+ },
+ {
+ class: 'todo',
+ active: true,
+ },
+ {
+ class: 'calc',
+ active: false,
+ },
+];
diff --git a/src/js/services/auth.js b/src/js/services/auth.js
new file mode 100644
index 0000000..c7bfc1d
--- /dev/null
+++ b/src/js/services/auth.js
@@ -0,0 +1,54 @@
+import * as Constants from '../data/constants';
+
+const { backend, userItemLocalStorage } = Constants;
+
+// Регистрация пользователя
+// Если задать уже имеющийся email или username, возвращает
+// statusCode: 400, reason: "User username is already registered"
+
+export function isLogged() {
+ const token = localStorage.getItem(userItemLocalStorage);
+ return !!(token);
+}
+
+export async function registerUser(username, email = '', password) {
+ const rawResponse = await fetch(`${backend}/auth/register`, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ username, email, password }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {statusCode: code, token: "uuid"}
+ }
+
+ const errorText = await rawResponse.text();
+ throw new Error(errorText);
+}
+
+// Логин
+// Если задать неправильный password или username, возвращает
+// statusCode: 403, reason: "Invalid username or password"
+
+export async function loginUser(username, password) {
+ const rawResponse = await fetch(`${backend}/auth/login`, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ username, password }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {statusCode: code, token: "uuid"}
+ }
+
+ const errorText = await rawResponse.text();
+ throw new Error(errorText);
+}
diff --git a/src/js/services/pages.js b/src/js/services/pages.js
index c6fd3df..9ec8f4d 100644
--- a/src/js/services/pages.js
+++ b/src/js/services/pages.js
@@ -1,22 +1,154 @@
+import ServiceError from './service-error';
+import * as Constants from '../data/constants';
+
+const { backend } = Constants;
+
+// Модуль получает данные страниц
+// При невалидном token ответ
+// 403 (Forbidden) Error: You are not authorized
+
export function getPages() {
- const locStorage = localStorage.getItem("startpage_pages");
+ const locStorage = localStorage.getItem('startpage_pages');
return (locStorage) ? JSON.parse(locStorage) : null;
}
export function getCurrentPage() {
- const locStorage = localStorage.getItem("startpage_curPage");
+ const locStorage = localStorage.getItem('startpage_curPage');
return (locStorage) ? JSON.parse(locStorage) : null;
}
export function setPages(obj) {
- localStorage.setItem("startpage_pages", JSON.stringify(obj));
+ localStorage.setItem('startpage_pages', JSON.stringify(obj));
}
export function setCurrentPage(idx) {
- localStorage.setItem("startpage_curPage", JSON.stringify(idx))
+ localStorage.setItem('startpage_curPage', JSON.stringify(idx));
}
export function clearPages() {
- localStorage.removeItem("startpage_pages");
- localStorage.removeItem("startpage_curPage");
+ localStorage.removeItem('startpage_pages');
+ localStorage.removeItem('startpage_curPage');
+}
+
+// Получить список всех страниц
+
+export async function getPagesList(token) {
+ const rawResponse = await fetch(`${backend}/pages`, {
+ method: 'GET',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // [{id: "uuid", userId: "uuid", name: "Page title", data: "{json}"}]
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Получить страницу по идентификатору
+
+export async function getPageById(id, token) {
+ const rawResponse = await fetch(`${backend}/pages/${id}`, {
+ method: 'GET',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", userId: "uuid", name: "Page title", after: null, data: "{json}"}
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Page not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Создать новую страницу
+// name - наименование страницы
+// data - данные блоков страницы
+
+export async function createNewPage(name, after, data, token) {
+ const rawResponse = await fetch(`${backend}/pages`, {
+ method: 'POST',
+ headers: {
+ authorization: `${token}`,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ name, after, data }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", userId: "uuid", name: "Page title", after: null, data: "{json}"}
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Удалить страницу по идентификатору
+
+export async function deletePageById(id, token) {
+ const rawResponse = await fetch(`${backend}/pages/${id}`, {
+ method: 'DELETE',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ return true;
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Page not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw new ServiceError(errorText, rawResponse.status);
+}
+
+// Обновить страницу по идентификатору
+// name - наименование страницы
+// data - данные блоков страницы
+
+export async function updatePagesById(id, name, after, data, token) {
+ const rawResponse = await fetch(`${backend}/pages/${id}`, {
+ method: 'PUT',
+ headers: {
+ authorization: `${token}`,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ name, after, data }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", userId: "uuid", name: "Page title", after: null, data: "{json}"}
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Page not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
}
diff --git a/src/js/services/service-error.js b/src/js/services/service-error.js
new file mode 100644
index 0000000..8e7ee40
--- /dev/null
+++ b/src/js/services/service-error.js
@@ -0,0 +1,8 @@
+class ServiceError extends Error {
+ constructor(message, status) {
+ super(message);
+ this.status = status;
+ }
+}
+
+export default ServiceError;
diff --git a/src/js/services/todos.js b/src/js/services/todos.js
new file mode 100644
index 0000000..e1a1c85
--- /dev/null
+++ b/src/js/services/todos.js
@@ -0,0 +1,134 @@
+import ServiceError from './service-error';
+import * as Constants from '../data/constants';
+
+const { backend } = Constants;
+
+// Модуль получает данные для списка ToDo
+// При невалидном token ответ
+// 403 (Forbidden) Error: You are not authorized
+
+// Получить все задачи
+
+export async function taskList(token) {
+ const rawResponse = await fetch(`${backend}/todos`, {
+ method: 'GET',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // [{id: "uuid", title: "Task title", complete: true, userId: "uuid"}]
+ }
+
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Получить задачу по идентификатору
+
+export async function taskById(id, token) {
+ const rawResponse = await fetch(`${backend}/todos/${id}`, {
+ method: 'GET',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", title: "Task title", complete: true, userId: "uuid"}
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Task not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Создать новую задачу
+// title - наименование
+// complete - состояние задачи.
+// true - выполнено, false - не выполнено, null - не установлено
+
+export async function createNewTask(title, complete, token) {
+ const rawResponse = await fetch(`${backend}/todos`, {
+ method: 'POST',
+ headers: {
+ authorization: `${token}`,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ title, complete }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", title: "Task title", complete: true, userId: "uuid"}
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}
+
+// Удалить задачу по идентификатору
+
+export async function deleteTaskById(id, token) {
+ const rawResponse = await fetch(`${backend}/todos/${id}`, {
+ method: 'DELETE',
+ headers: {
+ authorization: `${token}`,
+ },
+ });
+
+ if (rawResponse.ok) {
+ return true;
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Task not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw new ServiceError(errorText, rawResponse.status);
+}
+
+// Обновить задачу по идентификатору
+// title - наименование
+// complete - состояние задачи.
+// true - выполнено, false - не выполнено, null - не установлено
+
+export async function updateTaskById(id, title, complete, token) {
+ const rawResponse = await fetch(`${backend}/todos/${id}`, {
+ method: 'PUT',
+ headers: {
+ authorization: `${token}`,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ title, complete }),
+ });
+
+ if (rawResponse.ok) {
+ const content = await rawResponse.json();
+ return content; // {id: "uuid", title: "Task title", complete: true, userId: "uuid"}]
+ }
+ if (rawResponse.status === 403) {
+ throw new ServiceError('You are not authorized', rawResponse.status);
+ }
+ if (rawResponse.status === 404) {
+ throw new ServiceError('Task not found', rawResponse.status);
+ }
+ const errorText = await rawResponse.text();
+ throw Error(errorText);
+}