diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..6b665aaa --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} diff --git a/index.html b/index.html index 8e36d194..ca702bc5 100644 --- a/index.html +++ b/index.html @@ -2,14 +2,80 @@ - My Page - - + Buy list + + -

Hello World

-

Hello Git

-
Hi 2018!!!
+
+
+
+ + +
+ +
+ Помідори + 2 + +
+ +
+ Печиво +
+ + 2 + +
+
+ + +
+
+ +
+ +
+ + 1 + +
+
+ + +
+
+
+ +
+

Залишилося

+
+ + Печиво + 2 + + + Сир + 1 + +
+ +

Куплено

+
+ + Помідори + 2 + +
+
+
+ +
+
+ BuyList +
Виконала:
Брюховецька Юліана
+
+
\ No newline at end of file diff --git a/main.css b/main.css index 16c28b97..00675192 100644 --- a/main.css +++ b/main.css @@ -1,8 +1,381 @@ -h1 { - color: red; +:root { + --bg-body: #d6d6d6; + --bg-card: white; + --border-color: #e0e0e0; + --divider-color: #d6d6d6; + --shadow-color: rgba(0, 0, 0, 0.1); + + --primary-color: rgb(86, 86, 243); + --secondary-bg: rgb(235, 231, 231); + --side-container-amount: rgb(255, 153, 0); + --border-special-color: #70ace8; + --accent-purple: #4b0082; + --badge-purple: #a100ff; + --badge-hover: #1a1abd; + + --button-reduce-color: rgb(241, 54, 54); + --button-add-color: rgb(36, 199, 36); + --red: red; + + --text-main: #000000; + --text-muted: #555555; + --text-light: white; +} + +html { + font-family: sans-serif; + background-color: var(--bg-body); +} + +.main-wrapper { + display: flex; + justify-content: center; + gap: 30px; + padding: 30px 20px; + flex-wrap: wrap; + align-items: flex-start; +} + +.main-container, .side-container { + background-color: var(--bg-card); + border-radius: 8px; + box-shadow: 0 4px 15px var(--shadow-color); + border: 1px solid var(--border-color); +} + +.main-container { + padding: 20px; + width: 100%; + max-width: 600px; + box-sizing: border-box; +} + +.side-container { + padding-left: 15px; + width: 100%; + max-width: 350px; + box-sizing: border-box; +} + +.side-container__header { + position: relative; + margin: 0; + padding: 15px 0 15px 0; +} + +.side-container__header::after { + content: ""; + position: absolute; + bottom: 0; + left: -20px; + right: -20px; + height: 1px; + background-color: var(--divider-color); +} + +.side-container__header--middle::before { + content: ""; + position: absolute; + top: 0; + left: -15px; + right: -15px; + height: 1px; + background-color: var(--divider-color); +} + +.side-container__items { + display: flex; + gap: 8px; + padding: 15px 0 15px 0; +} + +.product { + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + padding: 15px; + position: relative; +} + +.last-product { + padding-bottom: 0; +} + +.product__name, .product__input-field { + grid-column: 1; + justify-self: start; +} + +.product__counter { + grid-column: 2; + justify-self: center; + display: flex; + align-items: center; + gap: 5px; +} + +.product__actions, .product > .product__buy-button { + grid-column: 3; + justify-self: end; + display: flex; + gap: 5px; +} + +.product::after { + content: ""; + position: absolute; + bottom: 0; + left: -20px; + right: -20px; + height: 1px; + background-color: var(--divider-color); +} + +.product:last-child::after { + display: none; +} + +.product__crossed { + text-decoration: line-through; +} + +[data-tooltip] { + position: relative; +} + +[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + left: 50%; + bottom: -5%; + transform: translateX(-50%) translateY(100%) scale(0.5); + background-color: var(--accent-purple); + color: var(--text-light); + padding: 5px 10px; + border-radius: 8px; + font-size: 12px; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + z-index: 10; +} + +[data-tooltip]:hover::after { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(110%) scale(1); +} + +.find-item { + display: flex; + position: relative; + padding-bottom: 20px; +} + +.find-item__input { + flex-grow: 1; + font-size: 16px; + border: 1px solid #e2e2e2; + border-right: none; + border-radius: 4px 0 0 4px; +} + +.find-item::after { + content: ""; + position: absolute; + bottom: 0; + left: -20px; + right: -20px; + height: 1px; + background-color: var(--divider-color); +} + +input[type="text"] { + padding: 10px 15px; +} + +.product-item { + font-size: 12px; + background-color: var(--secondary-bg); + height: 25px; + display: inline-block; + padding: 5px; + border-radius: 5px; + line-height: 25px; +} + +.product-item__bought { + text-decoration: line-through; +} + +.product-item__amount { + font-weight: 600; + background-color: var(--side-container-amount); + border-radius: 10px; + color: var(--text-light); + + display: inline-block; + height: 20px; + width: 20px; + text-align: center; + line-height: 20px; +} + +.find-item__add-button { + font-weight: 600; + background-color: var(--primary-color); + color: var(--text-light); + border: 0; + border-radius: 0 4px 4px 0; + padding: 5px 10px; + cursor: pointer; +} + +.product__buy-button { + font-weight: 600; + color: var(--text-muted); + padding: 8px 15px; + border: 1px solid var(--divider-color); + border-radius: 4px; + transition: 0.2s; + cursor: pointer; +} + +.product__buy-button:hover { + background-color: #f9f9f9; +} + +.product__amount { + background-color: var(--divider-color); + padding: 5px 10px; + border: 0; + border-radius: 4px; +} + +.product__input-field { + height: 8px; + width: 110px; + border: 2px solid var(--border-special-color); + border-radius: 4px; + font-size: 12px; + box-shadow: 0 0 7px var(--border-special-color); +} + +.product__buy-button, +.product__round-button, +.product__cancel-button, +.find-item__add-button { + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2), + inset 0 -3px 0 rgba(0, 0, 0, 0.1); + cursor: pointer; + border: 1px solid rgba(0, 0, 0, 0.1); +} + +.pale { + opacity: 0.5; } -.text2018 { - color: #ff59c0; - font-size: 40px; +.product__cancel-button { + font-weight: 600; + height: 32px; + width: 32px; + background-color: var(--red); + color: var(--text-light); + border: 0; + border-radius: 4px; + padding: 5px 10px; + cursor: pointer; +} + +.product__round-button { + box-sizing: border-box; + font-weight: 600; + height: 32px; + width: 32px; + border: 0; + border-radius: 50%; + padding: 5px 10px; + cursor: pointer; +} + +.remove { + color: var(--text-light); + background-color: var(--button-reduce-color); +} + +.add { + color: var(--text-light); + background-color: var(--button-add-color); +} + +.badge { + position: fixed; + bottom: 0; + left: 20px; + background-color: var(--badge-purple); + color: var(--text-light); + padding: 10px 20px; + border-radius: 10px 10px 0 0; + cursor: pointer; + transition: all 0.4s ease-in-out; + + height: 45px; + text-align: center; +} + +.badge-title { + font-weight: bold; + font-size: 20px; +} + +.personal-info { + font-size: 14px; + text-align: center; + line-height: 1.4; + opacity: 0; + transition: opacity 0.3s ease; +} + +.badge:hover { + height: 90px; + background-color: var(--badge-hover); +} + +.badge:hover .personal-info { + opacity: 1; +} + +@media print { + body { + background-color: var(--bg-card); + } + .badge { + height: 90px; + background-color: var(--bg-card); + color: var(--text-main); + border: 2px solid var(--text-main); + bottom: 10px; + } + .badge-title { + font-weight: bold; + font-size: 20px; + } + + .personal-info { + color: var(--text-main); + opacity: 1; + } +} + +@media (max-width: 500px) { + .main-wrapper { + flex-direction: column; + align-items: center; + } + + .main-container, .side-container { + max-width: 100%; + width: 100%; + } } \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 00000000..271e2a91 --- /dev/null +++ b/main.js @@ -0,0 +1,252 @@ +'use strict' + +let products = [ + { id: 1, name: "Помідори", amount: 2, bought: true, edit: false }, + { id: 2, name: "Печиво", amount: 2, bought: false, edit: false }, + { id: 3, name: "Сир", amount: 1, bought: false, edit: false }, +] +const inputItem = document.querySelector(".find-item__input"); +const addBtn = document.querySelector(".find-item__add-button"); + +const productsList = document.querySelector(".main-container"); + +const sideContainers = document.querySelectorAll(".side-container__items"); +const leftItems = sideContainers[0]; +const boughtItems = sideContainers[1]; + +function addProducts() { + const name = inputItem.value.trim(); + + if (name === '') { + return; + } + + let maxId = 0; + products.forEach(product => { + if (product.id > maxId) { + maxId = product.id; + } + }); + + const newId = maxId + 1; + + const newProduct = { + id: newId, + name: name, + amount: 1, + bought: false, + edit: false, + } + + products.push(newProduct); + + inputItem.value = ""; + inputItem.focus(); + + render(); +} + +addBtn.addEventListener("click", addProducts); + +inputItem.addEventListener("keydown", function(e) { + if (e.key === "Enter") { + addProducts(); + } +}); + +function render() { + const findItem = document.querySelector(".find-item"); + + productsList.innerHTML = ""; + + if (findItem) { + productsList.appendChild(findItem); + } + + products.forEach((product, index) => { + const productRow = document.createElement("div"); + + const isLast = index === products.length - 1; + + productRow.className = `product ${isLast ? 'last-product' : ''}`; + + if (product.bought) { + const nameSpan = document.createElement("span"); + nameSpan.className = "product__name product__crossed"; + nameSpan.textContent = product.name; + + const amountSpan = document.createElement("span"); + amountSpan.className = "product__amount"; + amountSpan.textContent = product.amount; + + const unbuyBtn = document.createElement("button"); + unbuyBtn.className = "product__buy-button"; + unbuyBtn.setAttribute("data-tooltip", "Відмінити покупку"); + unbuyBtn.textContent = "Не куплено"; + unbuyBtn.addEventListener("click", () => toggleBought(product.id)); + + productRow.appendChild(nameSpan); + productRow.appendChild(amountSpan); + productRow.appendChild(unbuyBtn); + } else { + let nameElement; + + if (product.edit) { + nameElement = document.createElement("input"); + nameElement.type = "text"; + nameElement.className = "product__input-field"; + nameElement.value = product.name; + nameElement.id = `edit-input-${product.id}`; + + nameElement.addEventListener("blur", () => finishEdit(product.id)); + + nameElement.addEventListener("keydown", (e) => { + if (e.key === "Enter") nameElement.blur(); + }); + + } else { + nameElement = document.createElement("span"); + nameElement.className = "product__name"; + nameElement.textContent = product.name; + nameElement.addEventListener("click", () => startEdit(product.id)); + } + + const counterDiv = document.createElement("div"); + counterDiv.className = "product__counter"; + + const minusBtn = document.createElement("button"); + minusBtn.className = `product__round-button remove ${product.amount <= 1 ? 'pale' : ''}`; + minusBtn.setAttribute("data-tooltip", "Зменшити"); + minusBtn.textContent = "−"; + minusBtn.addEventListener("click", () => decreaseAmount(product.id)); + + const amountSpan = document.createElement("span"); + amountSpan.className = "product__amount"; + amountSpan.textContent = product.amount; + + const plusBtn = document.createElement("button"); + plusBtn.className = "product__round-button add"; + plusBtn.setAttribute("data-tooltip", "Збільшити"); + plusBtn.textContent = "+"; + plusBtn.addEventListener("click", () => increaseAmount(product.id)); + + counterDiv.appendChild(minusBtn); + counterDiv.appendChild(amountSpan); + counterDiv.appendChild(plusBtn); + + const actionsDiv = document.createElement("div"); + actionsDiv.className = "product__actions"; + + const buyBtn = document.createElement("button"); + buyBtn.className = "product__buy-button"; + buyBtn.setAttribute("data-tooltip", "Позначити як куплене"); + buyBtn.textContent = "Куплено"; + buyBtn.addEventListener("click", () => toggleBought(product.id)); + + const deleteBtn = document.createElement("button"); + deleteBtn.className = "product__cancel-button"; + deleteBtn.setAttribute("data-tooltip", "Видалити товар"); + deleteBtn.textContent = "х"; + deleteBtn.addEventListener("click", () => deleteProduct(product.id)); + + actionsDiv.appendChild(buyBtn); + actionsDiv.appendChild(deleteBtn); + + productRow.appendChild(nameElement); + productRow.appendChild(counterDiv); + productRow.appendChild(actionsDiv); + } + + productsList.appendChild(productRow); + + if (product.edit) { + const editInput = document.getElementById(`edit-input-${product.id}`); + if (editInput) { + editInput.focus(); + editInput.selectionStart = editInput.selectionEnd = editInput.value.length; + } + } + }); + + leftItems.innerHTML = ""; + boughtItems.innerHTML = ""; + + products.forEach(product => { + const itemSpan = document.createElement("span"); + + const badgeSpan = document.createElement("span"); + badgeSpan.className = "product-item__amount"; + badgeSpan.textContent = product.amount; + + itemSpan.textContent = product.name + " "; + itemSpan.appendChild(badgeSpan); + + if (!product.bought) { + itemSpan.className = "product-item"; + leftItems.appendChild(itemSpan); + } else { + itemSpan.className = "product-item product-item__bought"; + boughtItems.appendChild(itemSpan); + } + }); +} + +function toggleBought(id) { + products = products.map(product => { + if (product.id === id) { + return { ...product, bought: !product.bought }; + } + return product; + }); + render(); +} + +function increaseAmount(id) { + products = products.map(product => { + if (product.id === id) { + return { ...product, amount: product.amount + 1 }; + } + return product; + }); + render(); +} + +function decreaseAmount(id) { + products = products.map(product => { + if (product.id === id && product.amount > 1) { + return { ...product, amount: product.amount - 1 }; + } + return product; + }); + render(); +} + +function deleteProduct(id) { + products = products.filter(product => product.id !== id); + render(); +} + +function startEdit(id) { + products = products.map(product => { + if (product.id === id) { + return { ...product, edit: true }; + } + return product; + }); + render(); +} + +function finishEdit(id) { + const editInput = document.getElementById(`edit-input-${id}`); + + products = products.map(product => { + if (product.id === id) { + const newName = editInput && editInput.value.trim() !== "" ? editInput.value.trim() : product.name; + return { ...product, name: newName, edit: false }; + } + return product; + }); + render(); +} + +render(); \ No newline at end of file