Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
<!DOCTYPE html>
<html>
<head lang="uk">
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>My Page</title>


<link rel="stylesheet" type="text/css" href="main.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Buy List</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<span class="product-item">
Apple
<span class="amount">4</span>
</span>
<div class="app-wrapper">
<div class="grid-container">

<main class="left-panel">
<div class="add-item-bar">
<input type="text" id="new-item-input" placeholder="Назва товару">
<button id="add-btn" class="btn-blue" data-tooltip="Додати новий товар">Додати</button>
</div>

<div id="items-list"></div>
</main>

<aside class="right-panel">
<section class="stats-block">
<h2>Залишилося</h2>
<div class="tag-container" id="left-stats"></div>
</section>

<section class="stats-block">
<h2>Куплено</h2>
<div class="tag-container" id="bought-stats"></div>
</section>
</aside>
</div>
</div>

<div class="author-badge">
<span class="badge-title">Buy List</span>
<span class="badge-author-name">Created by Hordii</span>
</div>

<script src="smth.js"></script>
</body>
</html>
110 changes: 96 additions & 14 deletions main.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,99 @@
.product-item {
background-color: gray;
display: inline-block;
height: 25px;
padding: 5px;
border-radius: 5px;
* { box-sizing: border-box; font-family: sans-serif; }
body { background: #000; display: flex; justify-content: center; padding: 40px 20px; margin: 0; }

.app-wrapper {
background: #dfdfdf;
padding: 20px;
width: 100%;
max-width: 900px;
}

.grid-container { display: flex; gap: 20px; }
.left-panel { flex: 2; display: flex; flex-direction: column; }
.right-panel { flex: 1; display: flex; flex-direction: column; gap: 15px; }

@media (max-width: 500px) {
.grid-container { flex-direction: column; }
}
.add-item-bar {
display: flex;
border: 1px solid #ccc;
border-bottom: none;
border-radius: 5px 5px 0 0;
background: #fff;
overflow: hidden;
}
.add-item-bar input { flex: 1; padding: 15px; border: none; outline: none; font-size: 16px; }
.btn-blue { background: #2185d0; padding: 0 30px; font-size: 16px; }
.item-row {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
padding: 12px 15px;
background: #fff;
border: 1px solid #ccc;
border-bottom: none;
}
.item-row:last-child {
border-bottom: 1px solid #ccc;
border-radius: 0 0 5px 5px;
}
.item-name, .item-input { font-size: 16px; color: #333; }
.item-input { border: 1px solid #2185d0; padding: 6px 10px; border-radius: 4px; outline: none; max-width: 140px; }
.crossed { text-decoration: line-through; }
.item-controls { display: flex; justify-content: center; align-items: center; gap: 8px; }
.item-actions { display: flex; justify-content: flex-end; gap: 5px; }

button { cursor: pointer; outline: none; border: none; color: #fff; font-weight: bold; }
.btn-circle { width: 32px; height: 32px; border-radius: 50%; font-size: 18px; }
.btn-delete { background-color: #db2828; width: 34px; height: 34px; border-radius: 4px; font-size: 16px; }
.btn-minus { background-color: #db2828; }
.btn-plus { background-color: #21ba45; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-status {
background: #e0e1e2; color: #333;
padding: 8px 12px; border-radius: 4px;
border: 1px solid #ccc; font-size: 13px;
}
.qty-badge { background: #e0e1e2; padding: 6px 12px; border-radius: 4px; font-weight: bold; color: #333; border: 1px solid #ccc;}
.stats-block { background: #fff; padding: 20px; border-radius: 5px; border: 1px solid #ccc; }
.stats-block h2 { margin: 0 0 15px 0; font-size: 18px; border-bottom: 1px solid #eee; padding-bottom: 10px; color: #222;}
.tag-container { display: flex; gap: 8px; }

.product-item {
background-color: #e0e1e2;
display: inline-flex; align-items: center; gap: 8px;
height: 30px; padding: 0 10px; border-radius: 4px;
font-size: 13px; font-weight: bold; color: #333;
}
.amount {
background-color: yellow;
border-radius: 10px;

display: inline-block;
height: 20px;
width: 20px;
text-align: center;
}
background-color: #f2711c; color: white; border-radius: 50%;
display: inline-flex; justify-content: center; align-items: center;
height: 22px; width: 22px; font-size: 12px;
}

[data-tooltip] { position: relative; }
[data-tooltip]::after {
content: attr(data-tooltip); position: absolute;
bottom: 130%; left: 50%; transform: translateX(-50%) translateY(10px) scale(0.8);
background: #8b00ff; color: #fff; padding: 6px 10px; border-radius: 5px;
font-size: 12px; opacity: 0; visibility: hidden; transition: 0.2s; z-index: 10; font-weight: normal;
}
[data-tooltip]:hover::after { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0) scale(1); }

.author-badge {
position: fixed; bottom: 0; left: 0; background: #4b0082; color: #fff;
padding: 15px 20px; border-radius: 10px 10px 0 0; font-weight: bold; font-size: 20px;
cursor: pointer; transition: 0.3s; z-index: 9999;
}
.badge-author-name { display: block; max-height: 0; opacity: 0; overflow: hidden; transition: 0.3s; font-size: 14px; font-weight: normal; }
.author-badge:hover { background: #8b00ff; padding-bottom: 25px; }
.author-badge:hover .badge-author-name { max-height: 30px; opacity: 1; margin-top: 5px; }

@media print {
body { background: none; }
.app-wrapper { border: none; background: none; box-shadow: none; }
.author-badge { background: #fff !important; color: #000 !important; border: 2px solid #8b00ff; border-bottom: none; }
.badge-title { display: none; }
.badge-author-name { max-height: none; opacity: 1; margin: 0; font-weight: bold; font-size: 20px; }
}
179 changes: 179 additions & 0 deletions smth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
'use strict';

let buyList = JSON.parse(localStorage.getItem('buyList')) || [
{ id: 1, name: 'Помідори', qty: 2, isBought: true },
{ id: 2, name: 'Печиво', qty: 2, isBought: false },
{ id: 3, name: 'Сир', qty: 1, isBought: false }
];

Comment on lines +3 to +8
function saveState() {
localStorage.setItem('buyList', JSON.stringify(buyList));
}

function render() {
const listContainer = document.getElementById('items-list');
const leftStats = document.getElementById('left-stats');
const boughtStats = document.getElementById('bought-stats');

listContainer.innerHTML = '';
leftStats.innerHTML = '';
boughtStats.innerHTML = '';

buyList.forEach(item => {
const article = document.createElement('article');
article.className = 'item-row';
article.dataset.id = item.id;

const nameSpan = document.createElement('span');
nameSpan.className = item.isBought ? 'item-name crossed' : 'item-name';
nameSpan.setAttribute('data-tooltip', item.isBought ? 'Редагування заборонено' : 'Натисніть, щоб редагувати');
nameSpan.textContent = item.name;

const controlsDiv = document.createElement('div');
controlsDiv.className = 'item-controls';

if (!item.isBought) {
const minusBtn = document.createElement('button');
minusBtn.className = 'btn-circle btn-minus';
minusBtn.dataset.action = 'minus';
minusBtn.setAttribute('data-tooltip', 'Зменшити кількість');
minusBtn.textContent = '-';
if (item.qty === 1) minusBtn.disabled = true;

const qtyBadge = document.createElement('span');
qtyBadge.className = 'qty-badge';
qtyBadge.textContent = item.qty;

const plusBtn = document.createElement('button');
plusBtn.className = 'btn-circle btn-plus';
plusBtn.dataset.action = 'plus';
plusBtn.setAttribute('data-tooltip', 'Збільшити кількість');
plusBtn.textContent = '+';

controlsDiv.append(minusBtn, qtyBadge, plusBtn);
} else {
const qtyBadge = document.createElement('span');
qtyBadge.className = 'qty-badge';
qtyBadge.textContent = item.qty;
controlsDiv.append(qtyBadge);
}

const actionsDiv = document.createElement('div');
actionsDiv.className = 'item-actions';

const statusBtn = document.createElement('button');
statusBtn.className = 'btn-status';
statusBtn.dataset.action = 'toggle';
statusBtn.setAttribute('data-tooltip', item.isBought ? 'Скасувати покупку' : 'Відмітити як куплене');
statusBtn.textContent = item.isBought ? 'Не куплено' : 'Куплено';

actionsDiv.append(statusBtn);

if (!item.isBought) {
const deleteBtn = document.createElement('button');
deleteBtn.className = 'btn-delete';
deleteBtn.dataset.action = 'delete';
deleteBtn.setAttribute('aria-label', 'Видалити');
deleteBtn.setAttribute('data-tooltip', 'Видалити');
deleteBtn.textContent = '✖';
actionsDiv.append(deleteBtn);
}
article.append(nameSpan, controlsDiv, actionsDiv);
listContainer.append(article);

const statItem = document.createElement('span');
statItem.className = 'product-item';

const statName = document.createElement('span');
if (item.isBought) statName.className = 'crossed';
statName.textContent = item.name;

const statAmount = document.createElement('span');
statAmount.className = item.isBought ? 'amount crossed' : 'amount';
statAmount.textContent = item.qty;

statItem.append(statName, statAmount);

if (item.isBought) {
boughtStats.append(statItem);
} else {
leftStats.append(statItem);
}
});
saveState();
}
Comment on lines +103 to +104

const inputField = document.getElementById('new-item-input');
const addBtn = document.getElementById('add-btn');

function addItem() {
const name = inputField.value.trim();
if (!name) return;
buyList.push({
id: Date.now(),
name: name,
qty: 1,
isBought: false
});
inputField.value = '';
inputField.focus();
render();
}

addBtn.addEventListener('click', addItem);
inputField.addEventListener('keypress', (e) => {
if (e.key === 'Enter') addItem();
});
Comment on lines +124 to +126

document.getElementById('items-list').addEventListener('click', (e) => {
const article = e.target.closest('.item-row');
if (!article) return;

const id = Number(article.dataset.id);
const item = buyList.find(i => i.id === id);
if (!item) return;

const action = e.target.dataset.action;

if (action === 'delete') {
buyList = buyList.filter(i => i.id !== id);
render();
}
else if (action === 'plus') {
item.qty++;
render();
}
else if (action === 'minus') {
if (item.qty > 1) {
item.qty--;
render();
}
}
else if (action === 'toggle') {
item.isBought = !item.isBought;
render();
}

if (e.target.classList.contains('item-name') && !item.isBought) {
const input = document.createElement('input');
input.type = 'text';
input.className = 'item-input';
input.value = item.name;

e.target.replaceWith(input);
input.focus();

const saveEdit = () => {
const newName = input.value.trim();
if (newName) item.name = newName;
render();
};

input.addEventListener('blur', saveEdit);
input.addEventListener('keypress', (event) => {
if (event.key === 'Enter') input.blur();
});
Comment on lines +173 to +175
}
});

render();