From abc718dd424ff0284b50d3778bca30387976ae5d Mon Sep 17 00:00:00 2001 From: Yevhenii32 Date: Wed, 18 Jun 2025 00:02:13 +0300 Subject: [PATCH] Lab03 --- index.html | 83 +++++++++++++++++--- main.css | 221 +++++++++++++++++++++++++++++++++++++++++++++++++---- script.js | 159 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 436 insertions(+), 27 deletions(-) create mode 100644 script.js diff --git a/index.html b/index.html index 5971bf7..8d68630 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,77 @@ - - - - My Page - - - + + + + + Document + - - Apple - 4 - +
+
+
+ + +
+ +
+ +
+ +
+
+ Печиво +
+
+ + 2 + +
+
+
+ + +
+
+
+ +
+
+ +
+
+ + 1 + +
+
+
+ + +
+
+
+
+ +
+

Залишилося

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

Куплено

+
+
Помідори 2
+
+
+
+ + \ No newline at end of file diff --git a/main.css b/main.css index 00bc872..01dced7 100644 --- a/main.css +++ b/main.css @@ -1,17 +1,206 @@ -.product-item { - background-color: gray; - display: inline-block; - height: 25px; - padding: 5px; - border-radius: 5px; -} +* {box-sizing: border-box;} + body { + font-family: sans-serif; + background: #eee; + margin: 0; + padding: 20px; + } + .app { + display: flex; + gap: 20px; + flex-wrap: wrap; + align-items: flex-start; + } + .card { + background: white; + padding: 20px; + border-radius: 6px; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); + } + .card:first-child { + flex: 1 1 450px; + } + .card:last-child { + flex: 0 1 300px; + } + .input-group { + display: flex; + width: 100%; + margin-bottom: 20px; + } + .input-group input[type="text"] { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px 0 0 4px; + background: #f1f1f1; + } + .input-group button { + padding: 10px 20px; + background: #0d6efd; + color: white; + border: none; + border-radius: 0 4px 4px 0; + cursor: pointer; + } + .item { + border-bottom: 1px solid #ccc; + padding: 10px 0; + } + .item-row { + display: grid; + grid-template-columns: 1fr auto 1fr auto; + align-items: center; + gap: 10px; + } + .item-name { + min-width: 120px; + } + .item-name.bought { + text-decoration: line-through; + } + .counter-wrapper { + display: flex; + justify-content: center; + width: 100px; + margin: 0 auto; + } + .counter-controls { + display: flex; + align-items: center; + gap: 4px; + } + .qty { + width: 30px; + text-align: center; + padding: 5px; + background: #f1f1f1; + border-radius: 4px; + font-weight: bold; + } + .actions { + display: flex; + align-items: center; + gap: 10px; + justify-content: flex-end; + } + .btn { + width: 32px; + height: 32px; + border: none; + color: white; + font-size: 18px; + font-weight: bold; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + } + .btn.green { + background: #28a745; + border-radius: 50%; + } + .btn.red { + background: #dc3545; + border-radius: 50%; + } + .btn.remove { + background: #dc3545; + border-radius: 4px; + } + .status-btn { + background: #f8f9fa; + border: 1px solid #ccc; + padding: 6px 12px; + border-radius: 6px; + cursor: pointer; + white-space: nowrap; + } + .badge-list { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 10px; + } + .badge { + background: #f1f1f1; + color: black; + border-radius: 12px; + padding: 6px 12px; + font-size: 14px; + display: flex; + align-items: center; + gap: 5px; + } + .badge .count { + background: #ff6f00; + color: white; + border-radius: 50%; + padding: 2px 8px; + font-size: 13px; + } + .footer-badge { + position: fixed; + bottom: 0; + left: 0; + background-color: #4a148c; + color: white; + padding: 10px 20px; + border-top-right-radius: 20px; + transition: all 0.5s ease; + cursor: pointer; + } + .footer-badge:hover { + bottom: 20px; + background-color: #082384; + } + .footer-badge::after { + content: 'Kovalenko Yevhenii'; + display: block; + font-size: 12px; + opacity: 0; + transition: opacity 0.5s ease; + } + .footer-badge:hover::after { + opacity: 1; + } -.amount { - background-color: yellow; - border-radius: 10px; - - display: inline-block; - height: 20px; - width: 20px; - text-align: center; -} \ No newline at end of file + @media (max-width: 500px) { + .app { + flex-direction: column; + } + .item-row { + grid-template-columns: 1fr; + } + .counter-wrapper { + justify-content: flex-start; + margin: 0; + } + .actions { + justify-content: flex-start; + } + } + button[data-tooltip] { + position: relative; + } + button[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%) translateY(10px) scale(0.95); + background: #6a0dad; + color: white; + padding: 4px 8px; + border-radius: 8px; + font-size: 12px; + white-space: nowrap; + opacity: 0; + transition: all 0.3s; + pointer-events: none; + } + button[data-tooltip]:hover::after { + opacity: 1; + transform: translateX(-50%) translateY(0) scale(1); + } + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..6342165 --- /dev/null +++ b/script.js @@ -0,0 +1,159 @@ + +//Задаємо змінні +document.addEventListener("DOMContentLoaded", () => { + const input = document.querySelector(".input-group input"); + const addButton = document.querySelector(".input-group button"); + const itemList = document.querySelector(".card:first-child"); + const badgeLeft = document.querySelectorAll(".badge-list")[0]; + const badgeBought = document.querySelectorAll(".badge-list")[1]; + + //Створення або завантаження списку + let items = JSON.parse(localStorage.getItem("buylist")) || [ + { name: "Помідори", count: 2, bought: true }, + { name: "Печиво", count: 2, bought: false }, + { name: "Сир", count: 1, bought: false }, + ]; +//Збереження поточного списку + function saveState() { + localStorage.setItem("buylist", JSON.stringify(items)); + } +// + function render() { + document.querySelectorAll(".item").forEach((el, i) => { + if (i > 0) el.remove(); + }); + badgeLeft.innerHTML = ""; + badgeBought.innerHTML = ""; + + items.forEach((item, index) => { + const itemDiv = document.createElement("div"); + itemDiv.className = "item"; + + const row = document.createElement("div"); + row.className = "item-row"; + + // Назва товару + const nameSpan = document.createElement("span"); + nameSpan.className = "item-name"; + nameSpan.textContent = item.name; + if (item.bought) nameSpan.classList.add("bought"); + else { + nameSpan.addEventListener("click", () => editName(nameSpan, index)); + } + + row.appendChild(nameSpan); + + // Лічильник + const counter = document.createElement("div"); + counter.className = "counter-wrapper"; + const controls = document.createElement("div"); + controls.className = "counter-controls"; + + if (!item.bought) { + const minus = document.createElement("button"); + minus.textContent = "−"; + minus.className = "btn red"; + minus.setAttribute("data-tooltip", "Зменшити"); + minus.disabled = item.count <= 1; + minus.onclick = () => { + item.count--; + saveState(); + render(); + }; + + const plus = document.createElement("button"); + plus.textContent = "+"; + plus.className = "btn green"; + plus.setAttribute("data-tooltip", "Збільшити"); + plus.onclick = () => { + item.count++; + saveState(); + render(); + }; + + controls.append(minus, createQty(item.count), plus); + } else { + controls.appendChild(createQty(item.count)); + } + + counter.appendChild(controls); + row.appendChild(counter); + + // Дії + const actions = document.createElement("div"); + actions.className = "actions"; + const statusBtn = document.createElement("button"); + statusBtn.className = "status-btn"; + statusBtn.setAttribute("data-tooltip", item.bought ? "Позначити як не куплене" : "Позначити як куплене"); + statusBtn.textContent = item.bought ? "Не куплено" : "Куплено"; + statusBtn.onclick = () => { + item.bought = !item.bought; + saveState(); + render(); + }; + actions.appendChild(statusBtn); + + if (!item.bought) { + const removeBtn = document.createElement("button"); + removeBtn.textContent = "×"; + removeBtn.className = "btn remove"; + removeBtn.setAttribute("data-tooltip", "Видалити"); + removeBtn.onclick = () => { + items.splice(index, 1); + saveState(); + render(); + }; + actions.appendChild(removeBtn); + } + + row.appendChild(actions); + itemDiv.appendChild(row); + itemList.appendChild(itemDiv); + + const badge = document.createElement("div"); + badge.className = "badge"; + badge.innerHTML = `${item.bought ? '' + item.name + '' : `${item.name}`} ${item.count}`; + (item.bought ? badgeBought : badgeLeft).appendChild(badge); + }); + } + + function createQty(count) { + const span = document.createElement("span"); + span.className = "qty"; + span.textContent = count; + return span; + } +// Зміна назви товару + function editName(span, index) { + const input = document.createElement("input"); + input.type = "text"; + input.value = items[index].name; + input.className = "item-name"; + input.onblur = () => { + items[index].name = input.value.trim() || items[index].name; + saveState(); + render(); + }; + span.replaceWith(input); + input.focus(); + } + + addButton.onclick = () => addItem(); + input.addEventListener("keydown", e => { + if (e.key === "Enter") addItem(); + }); +//Додавання товару + function addItem() { + const name = input.value.trim(); + if (name) { + items.push({ name, count: 1, bought: false }); + input.value = ""; + input.focus(); + saveState(); + render(); + } + } + + render(); + +});