diff --git a/app.js b/app.js new file mode 100644 index 00000000..7c2c2e97 --- /dev/null +++ b/app.js @@ -0,0 +1,140 @@ +const STORAGE_KEY = 'shopping_list_items'; +const initialProducts = [ + { id: 1, name: 'Помідори', quantity: 2, isBought: true }, + { id: 2, name: 'Печиво', quantity: 2, isBought: false }, + { id: 3, name: 'Сир', quantity: 1, isBought: false } +]; + +let products = JSON.parse(localStorage.getItem(STORAGE_KEY)) || initialProducts; +function saveState() { + localStorage.setItem(STORAGE_KEY, JSON.stringify(products)); +} + +const inputNewItem = document.querySelector('.add-item input'); +const btnAddItem = document.querySelector('.btn-add'); +const itemsList = document.querySelector('.items-list'); +const leftStatsContainer = document.querySelector('.stats-section .stats-card:nth-child(1) .stats-tags'); +const rightStatsContainer = document.querySelector('.stats-section .stats-card:nth-child(2) .stats-tags'); + +function render() { + itemsList.innerHTML = ''; + leftStatsContainer.innerHTML = ''; + rightStatsContainer.innerHTML = ''; + + products.forEach(product => { + const li = document.createElement('li'); + li.className = `item-row ${product.isBought ? 'bought' : ''}`; + + if (product.isBought) { + li.innerHTML = ` + ${product.name} +
+ ${product.quantity} + +
+ `; + li.querySelector('.btn-status').addEventListener('click', () => toggleStatus(product.id)); + } else { + const isMinusDisabled = product.quantity === 1 ? 'disabled' : ''; + li.innerHTML = ` + ${product.name} +
+ + ${product.quantity} + + + +
+ `; + li.querySelector('.plus').addEventListener('click', () => changeQuantity(product.id, 1)); + if (product.quantity > 1) { + li.querySelector('.minus').addEventListener('click', () => changeQuantity(product.id, -1)); + } + li.querySelector('.buy').addEventListener('click', () => toggleStatus(product.id)); + li.querySelector('.delete').addEventListener('click', () => deleteProduct(product.id)); + const nameSpan = li.querySelector('.item-name'); + nameSpan.addEventListener('click', () => activateEditMode(nameSpan, product.id)); + } + itemsList.appendChild(li); + const tag = document.createElement('span'); + tag.className = `tag ${product.isBought ? 'bought-tag' : ''}`; + tag.innerHTML = `${product.name} ${product.quantity}`; + + if (product.isBought) { + rightStatsContainer.appendChild(tag); + } else { + leftStatsContainer.appendChild(tag); + } + }); + saveState(); +} + +function addProduct() { + const name = inputNewItem.value.trim(); + if (!name) return; + const newProduct = { + id: Date.now(), + name: name, + quantity: 1, + isBought: false + }; + products.push(newProduct); + inputNewItem.value = ''; + inputNewItem.focus(); + + render(); +} + +btnAddItem.addEventListener('click', addProduct); +inputNewItem.addEventListener('keydown', (e) => { + if (e.key === 'Enter') addProduct(); +}); + +function deleteProduct(id) { + products = products.filter(p => p.id !== id); + render(); +} + +function changeQuantity(id, amount) { + const product = products.find(p => p.id === id); + if (product) { + product.quantity += amount; + render(); + } +} + +function toggleStatus(id) { + const product = products.find(p => p.id === id); + if (product) { + product.isBought = !product.isBought; + render(); + } +} + +function activateEditMode(spanElement, id) { + const currentName = spanElement.textContent; + const input = document.createElement('input'); + input.type = 'text'; + input.className = 'item-name-edit'; + input.value = currentName; + spanElement.replaceWith(input); + input.focus(); + + function saveNewName() { + const newName = input.value.trim(); + const product = products.find(p => p.id === id); + + if (product && newName) { + product.name = newName; + } + render(); + } + input.addEventListener('blur', saveNewName); + input.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + input.blur(); + } + }); +} + +render(); diff --git a/index.html b/index.html index 5971bf7d..ab4a0d41 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,43 @@ - - + + - My Page - - - + + BuyList - Shopping Cart + - - Apple - 4 - + +
+
+
+ + +
+ +
+ + +
+ +
+
+ BuyList + Виконав Паламарчук Ярослав +
+
+ + - \ No newline at end of file + diff --git a/main.css b/main.css index 00bc872e..dd067e9d 100644 --- a/main.css +++ b/main.css @@ -1,17 +1,140 @@ -.product-item { - background-color: gray; - display: inline-block; - height: 25px; - padding: 5px; - border-radius: 5px; -} - -.amount { - background-color: yellow; - border-radius: 10px; - - display: inline-block; - height: 20px; - width: 20px; - text-align: center; -} \ No newline at end of file +:root { + --primary-blue: #4a86e8; + --danger-red: #d9534f; + --success-green: #5cb85c; + --bg-gray: #e0e0e0; + --purple: #6f42c1; +} + +body { + font-family: Arial, sans-serif; + background-color: var(--bg-gray); + margin: 0; + padding: 20px; +} + +.container { + display: flex; + max-width: 1000px; + margin: 50px auto; + gap: 20px; + align-items: flex-start; +} + +.card { + background: white; + border-radius: 4px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + padding: 20px; +} + +.items-section { flex: 2; } +.stats-section { flex: 1; display: flex; flex-direction: column; gap: 20px; } + +.add-item { display: flex; gap: 10px; margin-bottom: 20px; border-bottom: 1px solid #eee; padding-bottom: 20px; } +.add-item input { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 4px; } +.btn-add { background: var(--primary-blue); color: white; border: none; padding: 10px 25px; border-radius: 4px; font-weight: bold; cursor: pointer; } + +.item-row { + display: flex; justify-content: space-between; align-items: center; + padding: 15px 0; border-bottom: 1px solid #eee; +} +.item-name-edit { border: 1px solid #4a86e8; padding: 5px; width: 120px; } +.item-controls { display: flex; align-items: center; gap: 8px; } + +.btn-round { + width: 32px; height: 32px; border-radius: 50%; border: none; + color: white; font-weight: bold; cursor: pointer; +} +.minus { background: #d9534f; } +.minus.disabled { background: #f2dede; color: #a94442; opacity: 0.6; } +.plus { background: #5cb85c; } +.delete { background: #d9534f; margin-left: 10px; } + +.btn-status { + border: 1px solid #ddd; background: #f9f9f9; padding: 8px 15px; + border-radius: 4px; cursor: pointer; font-size: 14px; +} +.bought .item-name { text-decoration: line-through; color: #555; } + +.quantity-badge { background: #eee; padding: 5px 12px; border-radius: 4px; font-weight: bold; min-width: 20px; text-align: center; } + +.stats-card h3 { margin-top: 0; font-size: 22px; } +.stats-tags { display: flex; flex-wrap: wrap; gap: 8px; } +.tag { background: #eee; padding: 5px 10px; border-radius: 5px; font-size: 13px; color: #666; font-weight: bold; } +.tag-num { background: #e67e22; color: white; border-radius: 50%; padding: 1px 6px; font-size: 11px; margin-left: 5px; } +.bought-tag { text-decoration: line-through; } + +.badge-container { + position: fixed; + bottom: 0; + left: 40px; + z-index: 1000; +} + +.badge { + background: var(--purple); + color: white; + padding: 15px 25px; + border-radius: 15px 15px 0 0; + transform: translateY(40px); + transition: transform 0.5s ease, background 0.3s ease; + display: flex; + flex-direction: column; + align-items: center; + cursor: default; +} + +.badge:hover { + transform: translateY(0); + background: #5a32a3; +} + +.badge-author { margin-top: 10px; font-size: 12px; opacity: 0.9; } + +@media (max-width: 650px) { + .container { flex-direction: column; padding: 10px; } + .items-section, .stats-section { width: 100%; } +} + +[data-tooltip] { position: relative; } + +[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%) translateY(10px) scale(0.8); + background: var(--purple); + color: white; + padding: 5px 10px; + border-radius: 8px; + font-size: 12px; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + pointer-events: none; + margin-bottom: 8px; +} + +[data-tooltip]:hover::after { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(0) scale(1); +} + +@media print { + body { background: white; } + .badge-container { position: absolute; bottom: 20px; left: 20px; } + .badge { + background: white !important; + border: 2px solid var(--purple); + color: var(--purple) !important; + transform: none !important; + } + .badge-title { display: none; } + .badge-author::before { content: "Паламарчук Ярослав"; font-size: 16px; font-weight: bold; } + .badge-author { font-size: 0; } + .btn-add, .btn-round, .delete { display: none; } +}