Add custom product with full nutrients, bigger + buttons with border
Custom product: - "+" button next to search on Products tab - showAddProductModal: name, KBJU, + all MICRO_FIELDS (34 nutrient fields) - All optional except name - Creates product with source="manual" - Refreshes search after save Button style: - .add-btn: 0.5px border with primary color, rounded corners (6px) - Min 40x36px for finger-friendly tapping on retina - Flexbox centered content
This commit is contained in:
parent
b4b2914d00
commit
f871e5bb28
2 changed files with 72 additions and 4 deletions
|
|
@ -478,12 +478,18 @@ select {
|
|||
|
||||
.add-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
border: 0.5px solid var(--primary);
|
||||
border-radius: 6px;
|
||||
color: var(--primary);
|
||||
font-size: 22px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
padding: 0 4px;
|
||||
padding: 4px 10px;
|
||||
min-width: 40px;
|
||||
min-height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.log-list {
|
||||
|
|
|
|||
|
|
@ -1197,8 +1197,11 @@ async function renderProducts(container) {
|
|||
<button class="sub-tab" data-tab="recipes">Рецепты</button>
|
||||
</div>
|
||||
<div id="products-tab">
|
||||
<input id="prod-search" class="search-input" type="search"
|
||||
placeholder="Название, бренд или ингредиент..." />
|
||||
<div style="display:flex;gap:8px;align-items:center">
|
||||
<input id="prod-search" class="search-input" type="search" style="flex:1"
|
||||
placeholder="Название, бренд или ингредиент..." />
|
||||
<button class="add-btn" id="add-custom-product" title="Свой продукт">+</button>
|
||||
</div>
|
||||
<div id="prod-count" class="prod-count"></div>
|
||||
<div id="prod-results" class="prod-list"></div>
|
||||
</div>
|
||||
|
|
@ -1339,6 +1342,65 @@ async function renderProducts(container) {
|
|||
|
||||
listEl.innerHTML = `<div class="prod-hint">Введите название продукта</div>`;
|
||||
input.focus();
|
||||
|
||||
// Add custom product button
|
||||
const addCustomBtn = container.querySelector("#add-custom-product");
|
||||
if (addCustomBtn) addCustomBtn.onclick = () => showAddProductModal(() => doSearch(true));
|
||||
}
|
||||
|
||||
function showAddProductModal(onSaved) {
|
||||
const microHtml = MICRO_FIELDS.map(f => {
|
||||
return `<div class="form-group micro-field">
|
||||
<label>${f.label}</label>
|
||||
<input id="np-${f.key}" type="number" inputmode="decimal" step="any" placeholder="—" />
|
||||
</div>`;
|
||||
}).join("");
|
||||
|
||||
showModal(`
|
||||
<h3>Новый продукт</h3>
|
||||
<div class="form-group">
|
||||
<label>Название</label>
|
||||
<input id="np-name" type="text" placeholder="Тесто для чебуреков" />
|
||||
</div>
|
||||
<div style="display:flex;gap:8px">
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>ккал/100г</label>
|
||||
<input id="np-kcal" type="number" inputmode="decimal" placeholder="260" />
|
||||
</div>
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Б</label>
|
||||
<input id="np-protein" type="number" inputmode="decimal" step="0.1" placeholder="7" />
|
||||
</div>
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Ж</label>
|
||||
<input id="np-fat" type="number" inputmode="decimal" step="0.1" placeholder="4" />
|
||||
</div>
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>У</label>
|
||||
<input id="np-carbs" type="number" inputmode="decimal" step="0.1" placeholder="48" />
|
||||
</div>
|
||||
</div>
|
||||
<p style="color:var(--muted);font-size:12px;margin:8px 0 4px">Нутриенты на 100г (опционально):</p>
|
||||
<div class="micro-grid">${microHtml}</div>`,
|
||||
async overlay => {
|
||||
const name = overlay.querySelector("#np-name").value.trim();
|
||||
if (!name) return false;
|
||||
const data = {
|
||||
name,
|
||||
kcal_per_100g: parseFloat(overlay.querySelector("#np-kcal").value) || null,
|
||||
protein_per_100g: parseFloat(overlay.querySelector("#np-protein").value) || null,
|
||||
fat_per_100g: parseFloat(overlay.querySelector("#np-fat").value) || null,
|
||||
carbs_per_100g: parseFloat(overlay.querySelector("#np-carbs").value) || null,
|
||||
source: "manual",
|
||||
};
|
||||
for (const f of MICRO_FIELDS) {
|
||||
let val = parseFloat(overlay.querySelector(`#np-${f.key}`).value) || null;
|
||||
if (val && f.mult) val *= f.mult;
|
||||
data[f.key] = val;
|
||||
}
|
||||
await DB.addProduct(data);
|
||||
if (onSaved) onSaved();
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue