diff --git a/basket_script.js b/basket_script.js
new file mode 100644
index 0000000..21ca870
--- /dev/null
+++ b/basket_script.js
@@ -0,0 +1,184 @@
+'use strict';
+
+// класс товара в корзине
+class BasketItem {
+ constructor(title, price, quantity, picture) {
+ this.title = title;
+ this.price = price;
+ this.picture = picture;
+ this.quantity = quantity;
+ }
+
+ render() {
+ return `
+ ${this.picture}
+
${this.title}
+
${this.price} руб
+
+
${this.quantity*this.price} руб
+
+
`;
+ }
+}
+
+// класс Корзины товаров
+class BasketList {
+ constructor() {
+ this.shopCartList = [];
+ }
+
+ #makeGETRequest(url) {
+ console.log('Направляю запрос корзины')
+ return new Promise((resolve, reject) => {
+ let xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window .ActiveXObject) {
+ xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ console.log('корзина получена')
+ resolve(xhr.response);
+ } else {
+ reject();
+ }
+ }
+ }
+
+ xhr.open( 'GET' , url, true );
+ xhr.send();
+ });
+ }
+
+ #makePOSTRequest(url, data) {
+ return new Promise((resolve, reject) => {
+ let xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ resolve(xhr.response);
+ } else {
+ reject();
+ }
+ }
+ }
+ xhr.open('POST', `/${url}`, true);
+ xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
+ xhr.send(data);
+ });
+ }
+
+ getShopCartList() {
+ this.#makeGETRequest(`/shopCartData`)
+ .then((data) => {
+ this.shopCartList = JSON.parse(data);
+ this.render();
+ })
+ .catch(() => {
+ console.log('Error: data not found');
+ });
+ }
+
+ toggle() {
+ document.querySelector('.basket_container').classList.toggle('hidden');
+ }
+
+ showSummary() {
+ let totalPrice = 0;
+ let totalQuantity = 0;
+
+ this.shopCartList.forEach(({ price, quantity }) => {
+ totalPrice += price*quantity;
+ totalQuantity += quantity;
+ });
+
+ document.querySelector('.total_quantity').innerHTML = `${totalQuantity}`;
+ document.querySelector('.total_price').innerHTML = `${totalPrice}`;
+ }
+
+ render() {
+ let html = '';
+
+ this.shopCartList.forEach(({ title, price, quantity, picture }) => {
+ const basketItem = new BasketItem(title, price, quantity, picture);
+ html += basketItem.render();
+ });
+
+ document.querySelector('.basket_list').innerHTML = html;
+
+ this.showSummary();
+
+ // для инициализации возможности удаления изменения количесвта товара при "раскрытии" корзины
+ if (this.shopCartList.length > 0) {
+ let changeShopCart = document.querySelector('.basket_container');
+ changeShopCart.addEventListener('click', (event) => {
+ // console.log('click');
+ event.stopImmediatePropagation(); //для предотвращения повторных запросов при ререндеринге корзины
+
+ if (event.target.className == 'product_delete') {
+ let name = event.target.parentNode.parentNode.childNodes[3].innerText;
+ const productToDelete = {"title": name};
+ this.delete(JSON.stringify(productToDelete));
+ } else if (event.target.className == 'change_quantity') {
+ let newQuantity = +event.target.value;
+ let name = event.target.parentNode.childNodes[3].innerText;
+ const productToChange = {"title": name, "quantity": newQuantity};
+
+ if (newQuantity < 1) {
+ this.delete(JSON.stringify(productToChange));
+ } else {
+ this.changeQuantity(JSON.stringify(productToChange));
+ }
+ }
+ });
+ }
+ }
+
+ // добавление товара
+ add(item) {
+ this.#makePOSTRequest('addToCart', item)
+ .then((data) => {
+ console.log('товар добавлен');
+ })
+ .catch(() => {
+ console.log('Error: data not found');
+ });
+ }
+
+ // удаление товара
+ delete(item) {
+ this.#makePOSTRequest('deleteFromCart', item)
+ .then((data) => {
+ this.shopCartList = JSON.parse(data);
+ if (this.shopCartList.length == 0) {
+ this.shopCartList = [];
+ }
+ this.render();
+ })
+ .catch(() => {
+ console.log('Error: data not found');
+ });
+ }
+
+ // изменение количества товара внутри корзины
+ changeQuantity(item) {
+ this.#makePOSTRequest('changeQuantity', item)
+ .then((data) => {
+ this.shopCartList = JSON.parse(data);
+ this.render();
+ })
+ .catch(() => {
+ console.log('Error: data not found');
+ });
+ }
+}
diff --git a/cart.json b/cart.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/cart.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/responses/catalog.json b/catalog.json
similarity index 100%
rename from responses/catalog.json
rename to catalog.json
diff --git a/catalog_script.js b/catalog_script.js
new file mode 100644
index 0000000..4fbe568
--- /dev/null
+++ b/catalog_script.js
@@ -0,0 +1,101 @@
+'use strict';
+
+
+const shopCart = [];
+
+const API_URL = 'https://raw.githubusercontent.com/zagidulin/JavaScript/master/responses';
+
+class ProductItem {
+ constructor(title, price, link) {
+ this.title = title;
+ this.price = price;
+ this.link = link;
+ }
+
+ render() {
+ return ``;
+ }
+}
+
+
+class ProductsList {
+ constructor() {
+ this.products = [];
+ this.filteredProducts = [];
+ }
+
+ #makeGETRequest(url) {
+ return new Promise((resolve, reject) => {
+ let xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new XMLHttpRequest();
+ } else if (window .ActiveXObject) {
+ xhr = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ console.log('католог получен')
+ resolve(xhr.response);
+ } else {
+ reject();
+ }
+ }
+ }
+
+ xhr.open( 'GET' , url, true );
+ xhr.send();
+ });
+ }
+
+ render() {
+ let html = '';
+ this.filteredProducts.forEach(({ title, price, link }) => {
+ const productItem = new ProductItem(title, price, link);
+ html += productItem.render();
+ });
+
+ document.querySelector('.catalog').innerHTML = html;
+ }
+
+ getCatalog(list) {
+ if (list && list.length > 0) {
+ this.render();
+ } else {
+ this.#makeGETRequest(`/catalogData`)
+ .then((data) => {
+ this.products = JSON.parse(data);
+ this.filteredProducts = JSON.parse(data);
+ this.render();
+ })
+ .catch(() => {
+ console.log('Error: data not found');
+ });
+ }
+ }
+
+ total() {
+ let total = 0;
+ this.products.forEach(({ price }) => {
+ total += price;
+ });
+
+ console.log('Сумма всех цен: ', total);
+ }
+
+ filterProducts(value) {
+ const regexp = new RegExp(value, 'i');
+ this.filteredProducts = this.products.filter(product => regexp.test(product.title));
+ this.getCatalog(this.filteredProducts);
+ }
+}
diff --git a/image/heder.jpg b/image/heder.jpg
new file mode 100644
index 0000000..69bc24b
Binary files /dev/null and b/image/heder.jpg differ
diff --git a/image/k2_alexis_80_pro.jpg b/image/k2_alexis_80_pro.jpg
new file mode 100644
index 0000000..30dfcc4
Binary files /dev/null and b/image/k2_alexis_80_pro.jpg differ
diff --git a/image/logo_2.png b/image/logo_2.png
new file mode 100644
index 0000000..e17b23b
Binary files /dev/null and b/image/logo_2.png differ
diff --git a/image/rollerblade_macroblade_84W.jpg b/image/rollerblade_macroblade_84W.jpg
new file mode 100644
index 0000000..3440093
Binary files /dev/null and b/image/rollerblade_macroblade_84W.jpg differ
diff --git a/image/seba_frx_80.jpg b/image/seba_frx_80.jpg
new file mode 100644
index 0000000..687ea1a
Binary files /dev/null and b/image/seba_frx_80.jpg differ
diff --git a/image/twister_edge.jpg b/image/twister_edge.jpg
new file mode 100644
index 0000000..f6b0492
Binary files /dev/null and b/image/twister_edge.jpg differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..5fb40ee
--- /dev/null
+++ b/index.html
@@ -0,0 +1,66 @@
+
+
+
+
+ Rollerskates
+
+
+
+
+
+
+
+
Роликовые коньки
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..7c4ba19
--- /dev/null
+++ b/main.js
@@ -0,0 +1,94 @@
+'use strict';
+
+window.addEventListener('load', () => {
+ const catalogList = new ProductsList();
+ const shopingCart = new BasketList();
+
+ catalogList.getCatalog();
+
+ let catalog = document.querySelector('.catalog');
+ let basket = document.querySelector('.cart-button');
+
+ let findValue = document.querySelector('.products_filter');
+ // let findButton = document.getElementById('find');
+
+
+ catalog.addEventListener('click', (event) => {
+ // console.log(event);
+ if (event.target.innerText == 'buy') {
+ // console.log(event);
+ let name = event.target.parentNode.childNodes[4].innerText;
+ let price = +event.target.parentNode.childNodes[6].childNodes[0].innerText;
+ let image = event.target.parentNode.childNodes[1].childNodes[1].childNodes[1].outerHTML;
+ let item = {"title": name, "price": price, "picture": image};
+ // item = JSON.stringify(item);
+ shopingCart.add(JSON.stringify(item));
+ // makePOSTRequest('addToCart', item);
+ // shopingCart.add(name, price, image);
+ }
+ });
+
+ basket.addEventListener('click', (event) => {
+ shopingCart.getShopCartList();
+ shopingCart.toggle();
+ });
+
+ Vue.component('search-field', {
+ template: `
+
+ Поиск по каталогу:
+
+
+ `,
+ data() {
+ return {
+ productName: '',
+ }
+ },
+ methods: {
+ filter(event) {
+ this.productName = event.target.value;
+ catalogList.filterProducts(this.productName);
+ }
+ }
+ });
+
+ new Vue({
+ el: '.searchapp',
+ });
+
+ Vue.component('basket-list', {
+ template: `
+
+ `,
+ methods: {
+ closeBasket() {
+ shopingCart.toggle();
+ }
+ }
+ });
+
+ new Vue({
+ el: '.basketapp',
+ });
+
+});
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..f73c44b
--- /dev/null
+++ b/server.js
@@ -0,0 +1,105 @@
+const express = require('express');
+// const bodyParser = require('body-parser');
+const fs = require('fs');
+// console.log(fs);
+
+const app = express();
+const jsonParser = express.json();
+// app.use(bodyParser.json());
+
+app.listen(3000, () => {
+console.log('server is running on port 3000!');
+});
+
+app.use(express.static('.'));
+
+app.get('/catalogData', (req, res) => {
+ fs.readFile('catalog.json', 'utf8', (err, data) => {
+ res.send(data);
+ });
+});
+
+app.get('/shopCartData', (req, res) => {
+ fs.readFile('cart.json', 'utf8', (err, data) => {
+ res.send(data);
+ });
+});
+
+app.post('/addToCart', jsonParser, (req, res) => {
+ fs.readFile('cart.json', 'utf8', (err, data) => {
+ const cart = JSON.parse(data);
+ const item = req.body;
+
+ // составляем список товаров из корзины
+ let productsInCart = [];
+ cart.forEach(({ title }) => productsInCart.push(title));
+ // если товар уже есть в корзине увеличить количество
+ if (productsInCart.includes(item.title)) {
+ for (let i = 0; i < cart.length; i++) {
+ if (cart[i].title == item.title) {
+ cart[i].quantity += 1;
+ break;
+ }
+ }
+ // иначе добавить в корзину
+ } else {
+ item.quantity = 1;
+ cart.push(item);
+ }
+
+ fs.writeFile('cart.json', JSON.stringify(cart), (err) => {
+ if (err) {
+ res.send('{"result": 0}');
+ } else {
+ res.send('{"result": 1}');
+ }
+ });
+ });
+});
+
+app.post('/deleteFromCart', jsonParser, (req, res) => {
+ fs.readFile('cart.json', 'utf8', (err, data) => {
+ const cart = JSON.parse(data);
+ const item = req.body;
+ console.log('запрос к серверу');
+ // console.log(cart.length);
+ for (let i = 0; i < cart.length; i++) {
+ if (cart[i].title == item.title) {
+ cart.splice(i, 1);
+ break;
+ }
+ }
+
+ fs.writeFile('cart.json', JSON.stringify(cart), (err) => {
+ if (err) {
+ res.send('{"result": 0}');
+ } else {
+ res.send(JSON.stringify(cart));
+ }
+ });
+ });
+});
+
+
+
+app.post('/changeQuantity', jsonParser, (req, res) => {
+ fs.readFile('cart.json', 'utf8', (err, data) => {
+ const cart = JSON.parse(data);
+ const item = req.body;
+
+ for (let i = 0; i < cart.length; i++) {
+ if (cart[i].title == item.title) {
+ cart[i].quantity = item.quantity;
+ break;
+ }
+ }
+
+ fs.writeFile('cart.json', JSON.stringify(cart), (err) => {
+ if (err) {
+ res.send('{"result": 0}');
+ } else {
+ res.send(JSON.stringify(cart));
+ }
+ });
+ });
+});
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..01133bd
--- /dev/null
+++ b/style.css
@@ -0,0 +1,511 @@
+body {
+ background: #f8f8f8;
+}
+
+p {
+ color: #484343;
+ font-size: 16px;
+ font-weight: 400;
+ text-align: left;
+ line-height: 24px;
+ font-family: Tahoma, Geneva, sans-serif;
+}
+
+h1 {
+ font-family: Tahoma, Geneva, sans-serif;
+ font-style: italic;
+}
+
+h3 {
+ font-family: ‘Times New Roman’, Times, serif;
+}
+
+a {
+ font-family: Tahoma, Geneva, sans-serif;
+}
+
+hr {
+ clear: both;
+}
+
+button {
+ background: darkorange;
+ border-radius: 10px;
+ min-width: 80px;
+ min-height: 40px;
+ font-family: Tahoma, Geneva, sans-serif;
+ font-size: 16px;
+ border: none;
+ color: #fff;
+ margin-bottom: 3px;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+button:hover {
+ background: orange;
+}
+
+button:focus {
+ box-shadow: 0 0 0 1px gray;
+ outline: none;
+
+}
+
+iframe {
+ height: 374px;
+ width: 100%;
+}
+
+.wraper {
+ min-height: 100%;
+ max-width: 1200px;
+ position: relative;
+ margin: 0 auto;
+}
+
+.main-wall {
+ background-image: url(image/s1200.jfif);
+ background-repeat: no-repeat;
+ min-height: 801px;
+ position: relative;
+}
+
+.hidden {
+ display: none;
+}
+
+.picture {
+ outline: 1px solid #52dbd3;
+ float: left;
+}
+
+.short {
+ overflow: hidden;
+ padding-left: 10px;
+}
+
+.description {
+ clear: both;
+ padding-top: 1px;
+}
+
+.picture:hover {
+ outline: none;
+}
+
+.container {
+ width: 100%;
+ margin: 0 auto;
+ position: relative;
+}
+
+.main-page {
+ float: right;
+ margin-right: 20px;
+}
+
+.main-page-text {
+ color: #fff;
+}
+
+.header {
+ position: relative;
+ height: 100px;
+ margin: 0 auto;
+ background-image: url(image/heder.jpg);
+ min-width: 600px;
+}
+
+#logo {
+ margin: 11px 0 0 30px;
+ width: 156px;
+ height: 78px;
+ display: inline-block;
+ vertical-align: bottom;
+ position: absolute;
+}
+
+.main_menu {
+ text-align: right;
+ position: absolute;
+ min-width: 414px;
+ min-height: 90px;
+ right: 0;
+}
+
+.menulist {
+ font-family: Tahoma, Geneva, sans-serif;
+ font-weight: 900;
+ font-size: 1.3em;
+ display: inline-block;
+ margin-top: 35px;
+}
+
+.menulist li {
+ margin-right: 25px;
+ display: inline;
+}
+
+.menulist li:last-child {
+ margin-right: 125px;
+}
+
+.menulist li a {
+ color: silver;
+ text-decoration: none;
+}
+
+.menulist li a:hover {
+ color: #52dbd3;
+ text-decoration: overline;
+ background: inherit;
+}
+
+.cart {
+ position: absolute;
+ display: inline-block;
+ right: 5px;
+ bottom: 0;
+}
+
+.cart-button {
+ display: inline-block;
+ float: right;
+ color: #fff;
+ font-size: 10px;
+ font-weight: 700;
+ line-height: 20px;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ width: 92px;
+ height: 20px;
+ box-shadow: 0 2px 5px 1px rgba(109, 109, 109, 0.35);
+ border-radius: 23px;
+ text-align: center;
+ text-decoration: none;
+ position: relative;
+ border: 1px solid #ffffff;
+}
+
+.cart-button:hover {
+ background-color: #ffffff;
+ color: #212121;
+}
+
+.cart-button:active {
+ box-shadow: none;
+ border: none;
+}
+
+.catalog a:hover {
+ background: #eaeaea;
+}
+
+.features {
+ color: #484343;
+ font-size: 16px;
+ font-weight: 400;
+ font-family: Tahoma, Geneva, sans-serif;
+ line-height: 20px;
+}
+
+.heading {
+ color: #000;
+ font-size: 18px;
+ font-weight: 400;
+ background: #eaeaea;
+}
+
+#short {
+ color: #707070;
+ font-size: 14px;
+ font-style: italic;
+ line-height: 16px;
+}
+
+.user {
+ color: blue;
+ font-size: 14px;
+ font-family: ‘Courier New’, Courier, monospace;
+ text-transform: capitalize;
+}
+
+#email:focus {
+ color: yellow;
+ background: gray;
+}
+
+.product:first-letter {
+ font-family: ‘Courier New’, Courier, monospace; /* Шрифт первой буквы */
+ font-size: 200%; /* Размер шрифта первого символа */
+ color: orange;
+}
+
+.catalog {
+ text-align: center;
+}
+
+.product_preview {
+ display: inline-block;
+ width: 200px;
+ text-align: center;
+ vertical-align: top;
+ margin-left: 20px;
+}
+
+.preview_image {
+ display: inline-block;
+ width: 120px;
+ height: 120px;
+}
+
+.product_preview p {
+ text-align: center;
+}
+
+.catalog div:first-child {
+ margin-left: 0;
+}
+
+.catalog img {
+ outline: 1px solid silver;
+}
+
+.prod a {
+ height: 280px;
+ width: 200px;
+}
+
+.catalog-menu {
+ text-align: center;
+ font-family: Tahoma, Geneva, sans-serif;
+ margin-bottom: 40px;
+}
+
+.clearfix {
+ clear: both;
+}
+
+.search {
+ text-align: right;
+ color: #484343;
+ font-size: 12px;
+ font-weight: 400;
+ font-family: Tahoma, Geneva, sans-serif;
+}
+
+.search input {
+ /*float: right;*/
+ margin-bottom: 20px;
+}
+
+.catalog-menu-list {
+ display: inline;
+ margin-right: 25px;
+ font-family: Tahoma, Geneva, sans-serif;
+ padding: 5px;
+}
+
+.catalog-active {
+ /*border-top: 2px solid #000;*/
+ border-bottom: 2px solid #52dbd3;
+}
+
+.catalog-active a {
+ color: #000;
+}
+
+.catalog-link {
+ font-family: ‘Times New Roman’, sans-serif;
+ text-decoration: none;
+ color: grey;
+ font-weight: 700;
+}
+
+
+.catalog-menu-list a:hover {
+ color: #000;
+}
+
+/* корзина */
+
+.basket_container {
+ position: absolute;
+ top: 105px;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #f8f8f8;
+}
+
+.close {
+ position: absolute;
+ right: 25px;
+ color: darkblue;
+ border: 2px solid darkblue;
+ border-radius: 20%;
+ padding: 1px 5px;
+}
+
+.close:hover {
+ color: red;
+ border: 2px solid red;
+}
+
+.basket_container .head {
+ margin: 25px auto;
+}
+
+.h2 {
+ margin-top: 10px;
+}
+
+.basket_list {
+ position: relative;
+}
+
+.basket_record {
+ width: 60%;
+ min-width: 670px;
+ display: block;
+ margin: 10px auto;
+ border-bottom: 1px solid grey;
+ position: relative;
+}
+
+.basket_list .basket_record {
+ position: relative;
+ display: block;
+ height: 170px;
+ float: none;
+}
+
+.basket_list span.product_name {
+ margin-left: 1em;
+ width: 8em;
+ position: relative;
+ display: block;
+ float: left;
+}
+
+.basket_list span.product_price {
+ margin-left: 1em;
+ width: 7em;
+ position: relative;
+ display: block;
+ float: left;
+}
+
+.basket_list span.product_cost {
+ margin-left: 1em;
+ width: 7em;
+ position: relative;
+ display: block;
+ float: left;
+}
+
+.basket_delete {
+ display: inline-block;
+ /*padding: 10px 0;*/
+}
+
+.basket_delete a {
+ text-decoration: none;
+ color: #000;
+}
+
+.basket_delete a:hover {
+ text-decoration: none;
+ color: red;
+}
+
+.basket_summary p {
+ color: #484343;
+ font-size: 20px;
+ font-weight: 900;
+ text-align: left;
+ line-height: 24px;
+ font-family: Tahoma, Geneva, sans-serif;
+ margin-top: 20px;
+ margin-left: 20px;
+}
+
+.basket_list input[type="number"] {
+ width: 3em;
+ position: relative;
+ display: block;
+ float: left;
+}
+
+.basket_list .basket_record button {
+ margin-top: 50px;
+ margin-left: 390px;
+ width: 150px;
+ position: absolute;
+ display: block;
+ float: left;
+}
+
+.basket_list button {
+ margin-left: 45px;
+ width: 150px;
+ display: block;
+ float: left;
+}
+
+.basket_container button a {
+ text-decoration: none;
+ color: #555;
+}
+
+.basket_container img {
+ display: block;
+ float: left;
+ width: 120px;
+ border-radius: 25px;
+}
+
+.basket_container input[type="submit"] {
+ width: 150px;
+ display: block;
+ float: left;
+ margin-bottom: 25px;
+}
+
+.basket_container .basket_summary {
+ display: block;
+ margin-left: 50px;
+ margin-bottom: 15px;
+ color: #555;
+}
+
+.make_order {
+ margin-left: 50px;
+}
+
+
+/*Далее код для прижатия "подвала" к нижней части страницы*/
+html, body {
+ height: 100%
+}
+
+.forfooter {
+ height: 60px;
+ max-width: 1200px;
+}
+
+.footer {
+ height: 60px;
+ background-color: #eaeaea;
+ margin-top: -60px;
+ max-width: 1200px;
+ margin: -60px auto 0 auto;
+}
+
+.footer p {
+ text-align: right;
+ margin-right: 90px;
+ margin-top: 10px;
+}
+