From a5abf6bd5ff53ec0770e5651be64b50980ee0c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D1=96=D0=BA=D1=96=D1=82=D0=B0=20=D0=A0=D1=96=D0=B7?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA?= Date: Sat, 16 May 2026 23:43:36 +0300 Subject: [PATCH 1/2] feat: add form with label --- index.html | 44 +++++++--- style.css | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+), 11 deletions(-) create mode 100644 style.css diff --git a/index.html b/index.html index 5971bf7d..0c197174 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,38 @@ - - + + - My Page - - - + + Buy List + - - Apple - 4 - +
+
+
+ + +
+
    +
    + + +
    + +
    +
    Buy List
    +
    Created by:
    Різник Нікіта
    +
    + + - \ No newline at end of file + diff --git a/style.css b/style.css new file mode 100644 index 00000000..43a9e715 --- /dev/null +++ b/style.css @@ -0,0 +1,238 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: sans-serif; +} + +body { + background-color: #e0e0e0; + padding: 20px; + color: #333; +} + +button { + cursor: pointer; + border: none; + border-radius: 4px; + padding: 10px 15px; + font-weight: bold; + transition: opacity 0.2s; +} + +button:hover { + opacity: 0.8; +} + +.container { + display: flex; + gap: 20px; + max-width: 1000px; + margin: 0 auto; +} + +.left-panel { + flex: 2; + background: #fff; + padding: 20px; + border-radius: 4px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +.right-panel { + flex: 1; + display: flex; + flex-direction: column; + gap: 20px; +} + +.stats-section { + background: #fff; + padding: 20px; + border-radius: 4px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +@media (max-width: 650px) { + .container { + flex-direction: column; + } +} + +.add-item-form { + display: flex; + gap: 10px; + margin-bottom: 20px; + border-bottom: 1px solid #eee; + padding-bottom: 20px; +} + +#item-input { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.btn-blue { + background-color: #2185d0; + color: white; +} + +.items-list { + list-style: none; +} + +.item-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid #eee; +} + +.item-row.bought .item-name { + text-decoration: line-through; + color: #888; +} + +.item-controls, +.item-actions { + display: flex; + align-items: center; + gap: 5px; +} + +.btn-minus { + background: #ffb3b3; + color: white; + border-radius: 50%; + width: 30px; + height: 30px; + padding: 0; +} + +.btn-plus { + background: #21ba45; + color: white; + border-radius: 50%; + width: 30px; + height: 30px; + padding: 0; +} + +.btn-buy { + background: #f3f3f3; + border: 1px solid #ccc; + color: #333; + width: 100px; +} + +.btn-delete { + background: #db2828; + color: white; + width: 30px; + height: 30px; + padding: 0; +} + +.qty-display { + background: #f3f3f3; + padding: 5px 15px; + border-radius: 4px; + border: 1px solid #ccc; +} + +[data-tooltip] { + position: relative; +} + +[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + bottom: 130%; + left: 50%; + transform: translateX(-50%) scale(0.5); + transform-origin: bottom center; + background-color: darkviolet; + color: white; + padding: 5px 10px; + border-radius: 8px; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transition: all 0.3s ease; + z-index: 1000; + font-size: 12px; + font-weight: normal; +} + +[data-tooltip]:hover::after { + opacity: 1; + transform: translateX(-50%) scale(1); +} + +.author-badge { + position: fixed; + bottom: 0; + left: 20px; + background-color: #4b0082; + color: white; + padding: 10px 20px; + border-radius: 15px 15px 0 0; + text-align: center; + transition: background-color 0.4s ease, transform 0.4s ease; + transform: translateY(45px); + cursor: default; + z-index: 9999; +} + +.badge-title { + font-weight: bold; + font-size: 18px; + margin-bottom: 25px; +} + +.badge-author { + font-size: 14px; + opacity: 0; + transition: opacity 0.4s; +} + +.author-badge:hover { + transform: translateY(0); + background-color: #8a2be2; +} + +.author-badge:hover .badge-author { + opacity: 1; +} + +@media print { + body { + background: white; + } + + .author-badge { + position: static; + transform: translateY(0); + background-color: white !important; + border: 2px solid #4b0082 !important; + color: black !important; + } + + .badge-title { + display: none; + } + + .badge-author { + opacity: 1; + display: block; + color: black; + margin-top: 0; + } + + .badge-author::before { + display: none; + } +} \ No newline at end of file From b40f8a7833f16496794ca18e30b2af46bba291fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D1=96=D0=BA=D1=96=D1=82=D0=B0=20=D0=A0=D1=96=D0=B7?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA?= Date: Sat, 23 May 2026 23:55:47 +0300 Subject: [PATCH 2/2] Add buy list interactions --- script.js | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ style.css | 33 +++++++++- 2 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 script.js diff --git a/script.js b/script.js new file mode 100644 index 00000000..e8f6d27e --- /dev/null +++ b/script.js @@ -0,0 +1,178 @@ +let items = [ + { name: "Молоко", quantity: 1, bought: false }, + { name: "Хліб", quantity: 1, bought: false }, + { name: "Сир", quantity: 1, bought: false } +]; + +const itemInput = document.getElementById("item-input"); +const addButton = document.getElementById("add-btn"); +const itemsList = document.getElementById("items-list"); +const statsRemaining = document.getElementById("stats-remaining"); +const statsBought = document.getElementById("stats-bought"); + +function addItem() { + const name = itemInput.value.trim(); + + if (name !== "") { + items.push({ name: name, quantity: 1, bought: false }); + itemInput.value = ""; + render(); + } + + itemInput.focus(); +} + +function deleteItem(index) { + items.splice(index, 1); + render(); +} + +function changeQuantity(index, value) { + items[index].quantity += value; + + if (items[index].quantity < 1) { + items[index].quantity = 1; + } + + render(); +} + +function changeBought(index) { + items[index].bought = !items[index].bought; + render(); +} + +function editName(index, nameElement) { + if (items[index].bought) { + return; + } + + const editInput = document.createElement("input"); + editInput.type = "text"; + editInput.value = items[index].name; + editInput.className = "edit-input"; + + nameElement.replaceWith(editInput); + editInput.focus(); + + editInput.addEventListener("blur", function () { + const newName = editInput.value.trim(); + + if (newName !== "") { + items[index].name = newName; + } + + render(); + }); +} + +function createButton(text, className) { + const button = document.createElement("button"); + button.textContent = text; + button.className = className; + return button; +} + +function renderItems() { + itemsList.innerHTML = ""; + + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const row = document.createElement("li"); + row.className = "item-row"; + + if (item.bought) { + row.className += " bought"; + } + + const name = document.createElement("span"); + name.textContent = item.name; + name.className = "item-name"; + name.addEventListener("click", function () { + editName(i, name); + }); + + const controls = document.createElement("div"); + controls.className = "item-controls"; + + const quantity = document.createElement("span"); + quantity.textContent = item.quantity; + quantity.className = "qty-display"; + + if (!item.bought) { + const minusButton = createButton("-", "btn-minus"); + minusButton.disabled = item.quantity === 1; + minusButton.addEventListener("click", function () { + changeQuantity(i, -1); + }); + + const plusButton = createButton("+", "btn-plus"); + plusButton.addEventListener("click", function () { + changeQuantity(i, 1); + }); + + controls.appendChild(minusButton); + controls.appendChild(quantity); + controls.appendChild(plusButton); + } else { + controls.appendChild(quantity); + } + + const actions = document.createElement("div"); + actions.className = "item-actions"; + + const buyButton = createButton(item.bought ? "Не куплено" : "Куплено", "btn-buy"); + buyButton.addEventListener("click", function () { + changeBought(i); + }); + actions.appendChild(buyButton); + + if (!item.bought) { + const deleteButton = createButton("x", "btn-delete"); + deleteButton.addEventListener("click", function () { + deleteItem(i); + }); + actions.appendChild(deleteButton); + } + + row.appendChild(name); + row.appendChild(controls); + row.appendChild(actions); + itemsList.appendChild(row); + } +} + +function addStat(container, item) { + const stat = document.createElement("span"); + stat.className = "stat-item"; + stat.textContent = item.name + " " + item.quantity; + container.appendChild(stat); +} + +function renderStats() { + statsRemaining.innerHTML = ""; + statsBought.innerHTML = ""; + + for (let i = 0; i < items.length; i++) { + if (items[i].bought) { + addStat(statsBought, items[i]); + } else { + addStat(statsRemaining, items[i]); + } + } +} + +function render() { + renderItems(); + renderStats(); +} + +addButton.addEventListener("click", addItem); + +itemInput.addEventListener("keydown", function (event) { + if (event.key === "Enter") { + addItem(); + } +}); + +render(); diff --git a/style.css b/style.css index 43a9e715..89ca4b74 100644 --- a/style.css +++ b/style.css @@ -24,6 +24,11 @@ button:hover { opacity: 0.8; } +button:disabled { + cursor: default; + opacity: 0.4; +} + .container { display: flex; gap: 20px; @@ -96,6 +101,18 @@ button:hover { color: #888; } +.item-name { + flex: 1; + cursor: pointer; +} + +.edit-input { + flex: 1; + padding: 8px; + border: 1px solid #2185d0; + border-radius: 4px; +} + .item-controls, .item-actions { display: flex; @@ -143,6 +160,20 @@ button:hover { border: 1px solid #ccc; } +.stats-container { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 12px; +} + +.stat-item { + background: #f3f3f3; + border-radius: 4px; + padding: 6px 10px; + color: #333; +} + [data-tooltip] { position: relative; } @@ -235,4 +266,4 @@ button:hover { .badge-author::before { display: none; } -} \ No newline at end of file +}