UI improvements: search dropdown, layout fixes, taller step fields
- Recipe search now shows dropdown suggestions while typing; full results load on Enter or clicking "Keresés" button - Search field moved above tag filter; active filter tags below input - Instruction textarea doubled in height (60px → 120px) on both import and edit pages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -98,7 +98,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
.instruction-row textarea { margin-bottom: 0; flex: 1; min-height: 60px; }
|
.instruction-row textarea { margin-bottom: 0; flex: 1; min-height: 120px; }
|
||||||
.instruction-row button {
|
.instruction-row button {
|
||||||
background: var(--danger);
|
background: var(--danger);
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
.instruction-row textarea { margin-bottom: 0; flex: 1; min-height: 60px; }
|
.instruction-row textarea { margin-bottom: 0; flex: 1; min-height: 120px; }
|
||||||
.instruction-row button {
|
.instruction-row button {
|
||||||
background: var(--danger);
|
background: var(--danger);
|
||||||
border: none;
|
border: none;
|
||||||
|
|||||||
+99
-24
@@ -30,23 +30,44 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --- Search & filter bar --- */
|
/* --- Search & filter bar --- */
|
||||||
.search-bar {
|
.search-section {
|
||||||
display: flex;
|
|
||||||
gap: 0.75rem;
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
.search-bar .search-input-wrap {
|
.search-row {
|
||||||
flex: 1;
|
display: flex;
|
||||||
min-width: 200px;
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.search-bar input[type="text"] {
|
.search-row input[type="text"] {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
|
||||||
.tag-filter-wrap {
|
|
||||||
min-width: 200px;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
}
|
||||||
|
.search-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 60px;
|
||||||
|
background: var(--surface2);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
max-height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 110;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.search-dropdown.open { display: block; }
|
||||||
|
.search-dropdown-item {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.search-dropdown-item:hover { background: var(--accent-glow); }
|
||||||
|
.tag-filter-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.tag-filter-wrap input[type="text"] {
|
.tag-filter-wrap input[type="text"] {
|
||||||
@@ -56,7 +77,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.3rem;
|
gap: 0.3rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
.filter-chip {
|
.filter-chip {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -275,17 +296,19 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search & tag filter -->
|
<!-- Search -->
|
||||||
<div class="search-bar">
|
<div class="search-section">
|
||||||
<div class="search-input-wrap">
|
<div class="search-row">
|
||||||
<input type="text" id="recipeSearch" placeholder="Recept keresése..."
|
<input type="text" id="recipeSearch" placeholder="Recept keresése..."
|
||||||
oninput="onSearchInput()" autocomplete="off">
|
oninput="onSearchInput()" onkeydown="onSearchKeydown(event)" autocomplete="off">
|
||||||
|
<button class="btn btn-primary" onclick="executeSearch()">Keresés</button>
|
||||||
|
<div id="searchDropdown" class="search-dropdown"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tag-filter-wrap">
|
<div class="tag-filter-wrap">
|
||||||
<div class="active-filter-tags" id="activeFilterTags"></div>
|
|
||||||
<input type="text" id="tagFilterSearch" placeholder="Szűrés címke szerint..."
|
<input type="text" id="tagFilterSearch" placeholder="Szűrés címke szerint..."
|
||||||
autocomplete="off" oninput="onFilterTagSearch()" onfocus="onFilterTagSearch()">
|
autocomplete="off" oninput="onFilterTagSearch()" onfocus="onFilterTagSearch()">
|
||||||
<div id="tagFilterDropdown" class="tag-dropdown"></div>
|
<div id="tagFilterDropdown" class="tag-dropdown"></div>
|
||||||
|
<div class="active-filter-tags" id="activeFilterTags"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -371,12 +394,60 @@ function switchBackend(b) {
|
|||||||
function onSearchInput() {
|
function onSearchInput() {
|
||||||
clearTimeout(searchTimeout);
|
clearTimeout(searchTimeout);
|
||||||
searchTimeout = setTimeout(() => {
|
searchTimeout = setTimeout(() => {
|
||||||
currentPage = 1;
|
loadSearchSuggestions();
|
||||||
selectedIds.clear();
|
|
||||||
loadRecipes();
|
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSearchKeydown(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('searchDropdown').classList.remove('open');
|
||||||
|
executeSearch();
|
||||||
|
} else if (e.key === 'Escape') {
|
||||||
|
document.getElementById('searchDropdown').classList.remove('open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeSearch() {
|
||||||
|
document.getElementById('searchDropdown').classList.remove('open');
|
||||||
|
currentPage = 1;
|
||||||
|
selectedIds.clear();
|
||||||
|
loadRecipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSearchSuggestions() {
|
||||||
|
const q = document.getElementById('recipeSearch').value.trim();
|
||||||
|
const dropdown = document.getElementById('searchDropdown');
|
||||||
|
if (!q) { dropdown.classList.remove('open'); return; }
|
||||||
|
|
||||||
|
const params = new URLSearchParams({ page: 1, per_page: 8, search: q });
|
||||||
|
if (activeFilterTagIds.length) params.set('tag_ids', activeFilterTagIds.join(','));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/api/recipes/' + currentBackend + '?' + params);
|
||||||
|
const data = await resp.json();
|
||||||
|
if (!data.ok || data.items.length === 0) {
|
||||||
|
dropdown.classList.remove('open');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let html = '';
|
||||||
|
for (const r of data.items) {
|
||||||
|
html += '<div class="search-dropdown-item" onclick="selectSearchItem(\'' +
|
||||||
|
escHtml(r.name).replace(/'/g, "\\'") + '\')">' + escHtml(r.name) + '</div>';
|
||||||
|
}
|
||||||
|
dropdown.innerHTML = html;
|
||||||
|
dropdown.classList.add('open');
|
||||||
|
} catch (e) {
|
||||||
|
dropdown.classList.remove('open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectSearchItem(name) {
|
||||||
|
document.getElementById('recipeSearch').value = name;
|
||||||
|
document.getElementById('searchDropdown').classList.remove('open');
|
||||||
|
executeSearch();
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Tag filter ===== */
|
/* ===== Tag filter ===== */
|
||||||
async function loadBackendTags() {
|
async function loadBackendTags() {
|
||||||
try {
|
try {
|
||||||
@@ -444,12 +515,16 @@ function renderFilterChips() {
|
|||||||
wrap.innerHTML = html;
|
wrap.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Close dropdown on outside click ===== */
|
/* ===== Close dropdowns on outside click ===== */
|
||||||
document.addEventListener('click', e => {
|
document.addEventListener('click', e => {
|
||||||
const wrap = document.querySelector('.tag-filter-wrap');
|
const tagWrap = document.querySelector('.tag-filter-wrap');
|
||||||
if (wrap && !wrap.contains(e.target)) {
|
if (tagWrap && !tagWrap.contains(e.target)) {
|
||||||
document.getElementById('tagFilterDropdown').classList.remove('open');
|
document.getElementById('tagFilterDropdown').classList.remove('open');
|
||||||
}
|
}
|
||||||
|
const searchRow = document.querySelector('.search-row');
|
||||||
|
if (searchRow && !searchRow.contains(e.target)) {
|
||||||
|
document.getElementById('searchDropdown').classList.remove('open');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ===== Load recipes ===== */
|
/* ===== Load recipes ===== */
|
||||||
|
|||||||
Reference in New Issue
Block a user