From f8772b20b7d55c03f244b2bcff037ee70a9c4ef5 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Tue, 24 Feb 2026 12:49:53 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20tag=20UI=20=E2=80=94=20two-field=20desig?= =?UTF-8?q?n=20with=20active/inactive=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scraped tags default to inactive (won't be added). Click a tag to move it between active (green, will be imported) and inactive (muted, from webpage). Manually added/searched tags go directly to active. Co-Authored-By: Claude Opus 4.6 --- app/templates/import.html | 123 +++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 41 deletions(-) diff --git a/app/templates/import.html b/app/templates/import.html index a7b9df6..297d70b 100644 --- a/app/templates/import.html +++ b/app/templates/import.html @@ -124,33 +124,41 @@ .add-btn:hover { border-color: var(--accent); color: var(--text); } /* Tags */ + .tag-section-label { + font-size: 0.8rem; + color: var(--text-dim); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.03em; + margin-bottom: 0.3rem; + } .tag-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; - min-height: 32px; + min-height: 28px; } .tag-chip { display: inline-flex; align-items: center; - gap: 0.3rem; - background: var(--accent); - color: #fff; - padding: 0.25rem 0.5rem; + padding: 0.25rem 0.6rem; border-radius: 999px; font-size: 0.85rem; line-height: 1.2; - } - .tag-chip button { - background: none; - border: none; - color: rgba(255,255,255,0.7); cursor: pointer; - font-size: 0.9rem; - padding: 0; - line-height: 1; + transition: opacity 0.15s; + user-select: none; + } + .tag-chip:hover { opacity: 0.8; } + .tag-chip.tag-active { + background: var(--success, #2ea043); + color: #fff; + } + .tag-chip.tag-inactive { + background: var(--surface2); + color: var(--text-dim); + border: 1px solid var(--border); } - .tag-chip button:hover { color: #fff; } .tag-search-wrap { position: relative; margin-top: 0.5rem; @@ -245,12 +253,15 @@ -
+ +
+ +
{% if has_mealie %} @@ -352,9 +363,10 @@ function populatePreview(r) { instList.innerHTML = ''; (r.instructions || []).forEach(t => addInstruction(t)); - // Tags - document.getElementById('tagChips').innerHTML = ''; - (r.tags || []).forEach(t => addTagChip(t)); + // Tags — scraped tags go to inactive (user must opt-in) + document.getElementById('tagsActive').innerHTML = ''; + document.getElementById('tagsInactive').innerHTML = ''; + (r.tags || []).forEach(t => addTagChip(t, false)); } function addIngredient(item) { @@ -430,7 +442,7 @@ function gatherRecipe() { }); const tags = []; - document.querySelectorAll('#tagChips .tag-chip').forEach(el => { + document.querySelectorAll('#tagsActive .tag-chip').forEach(el => { tags.push(el.dataset.tag); }); @@ -529,25 +541,54 @@ async function loadExistingTags() { } catch (e) { /* ignore */ } } -function addTagChip(name) { - name = name.trim(); - if (!name) return; - // Avoid duplicates - const chips = document.getElementById('tagChips'); - for (const c of chips.querySelectorAll('.tag-chip')) { - if (c.dataset.tag.toLowerCase() === name.toLowerCase()) return; +function tagExistsIn(name, containerId) { + const container = document.getElementById(containerId); + for (const c of container.querySelectorAll('.tag-chip')) { + if (c.dataset.tag.toLowerCase() === name.toLowerCase()) return true; } - const chip = document.createElement('span'); - chip.className = 'tag-chip'; - chip.dataset.tag = name; - chip.innerHTML = escHtml(name) + ' '; - chips.appendChild(chip); + return false; } -function getActiveTags() { - const tags = []; - document.querySelectorAll('#tagChips .tag-chip').forEach(el => tags.push(el.dataset.tag.toLowerCase())); - return tags; +function addTagChip(name, active) { + name = name.trim(); + if (!name) return; + // Avoid duplicates in both areas + if (tagExistsIn(name, 'tagsActive') || tagExistsIn(name, 'tagsInactive')) return; + + const chip = document.createElement('span'); + chip.dataset.tag = name; + chip.textContent = name; + chip.onclick = function() { toggleTag(this); }; + + if (active) { + chip.className = 'tag-chip tag-active'; + document.getElementById('tagsActive').appendChild(chip); + } else { + chip.className = 'tag-chip tag-inactive'; + document.getElementById('tagsInactive').appendChild(chip); + } +} + +function toggleTag(chip) { + if (chip.classList.contains('tag-active')) { + // Move to inactive + chip.classList.remove('tag-active'); + chip.classList.add('tag-inactive'); + document.getElementById('tagsInactive').appendChild(chip); + } else { + // Move to active + chip.classList.remove('tag-inactive'); + chip.classList.add('tag-active'); + document.getElementById('tagsActive').appendChild(chip); + } +} + +function getAllTagNames() { + const names = []; + document.querySelectorAll('#tagsActive .tag-chip, #tagsInactive .tag-chip').forEach(el => { + names.push(el.dataset.tag.toLowerCase()); + }); + return names; } function onTagSearch() { @@ -557,7 +598,7 @@ function onTagSearch() { if (!q) { dropdown.classList.remove('open'); return; } - const active = getActiveTags(); + const allNames = getAllTagNames(); // Merge tags from both sources, track origin const seen = {}; for (const t of existingTags.mealie || []) { @@ -571,9 +612,9 @@ function onTagSearch() { seen[k].sources.push('T'); } - // Filter by query, exclude already-added + // Filter by query, exclude already-present tags const matches = Object.values(seen) - .filter(e => e.name.toLowerCase().includes(q) && !active.includes(e.name.toLowerCase())) + .filter(e => e.name.toLowerCase().includes(q) && !allNames.includes(e.name.toLowerCase())) .slice(0, 10); let html = ''; @@ -585,7 +626,7 @@ function onTagSearch() { } // "Add new" option if exact match not found - const exactExists = matches.some(m => m.name.toLowerCase() === q) || active.includes(q); + const exactExists = matches.some(m => m.name.toLowerCase() === q) || allNames.includes(q); if (!exactExists && q) { html += '
' + '+ "' + escHtml(input.value.trim()) + '" hozzáadása
'; @@ -596,7 +637,7 @@ function onTagSearch() { } function selectTag(name) { - addTagChip(name); + addTagChip(name, true); // manually added → active const input = document.getElementById('tagSearch'); input.value = ''; document.getElementById('tagDropdown').classList.remove('open'); @@ -608,7 +649,7 @@ function onTagKeydown(e) { e.preventDefault(); const val = e.target.value.trim(); if (val) { - addTagChip(val); + addTagChip(val, true); // manually added → active e.target.value = ''; document.getElementById('tagDropdown').classList.remove('open'); }