Улучшена мобильная адаптация и поведение фильтров на главной

This commit is contained in:
2026-04-16 16:42:47 +00:00
parent 09b66be20f
commit 342d9e3cfc
4 changed files with 314 additions and 2 deletions

View File

@@ -17,6 +17,9 @@
clearBtn: document.getElementById("clearBtn"),
modeInfra: document.getElementById("modeInfra"),
modeIb: document.getElementById("modeIb"),
resultSection: document.querySelector(".result"),
filtersSection: document.querySelector(".board"),
activeFilters: document.getElementById("activeFilters"),
};
let clickAudioCtx = null;
@@ -130,9 +133,12 @@
else if (!allowedVendors.has(vendor.id)) node.classList.add("dim");
node.textContent = vendor.name;
node.addEventListener("click", () => {
if (state.selectedVendors.has(vendor.id)) state.selectedVendors.delete(vendor.id);
const wasSelected = state.selectedVendors.has(vendor.id);
if (wasSelected) state.selectedVendors.delete(vendor.id);
else state.selectedVendors.add(vendor.id);
render();
if (wasSelected) scrollAfterDeselect();
else scrollToResultsSmooth();
});
el.vendorList.appendChild(node);
}
@@ -148,9 +154,12 @@
else if (!allowedCategories.has(category.id)) node.classList.add("dim");
node.textContent = category.name;
node.addEventListener("click", () => {
if (state.selectedCategories.has(category.id)) state.selectedCategories.delete(category.id);
const wasSelected = state.selectedCategories.has(category.id);
if (wasSelected) state.selectedCategories.delete(category.id);
else state.selectedCategories.add(category.id);
render();
if (wasSelected) scrollAfterDeselect();
else scrollToResultsSmooth();
});
el.categoryList.appendChild(node);
}
@@ -213,9 +222,82 @@
el.modeIb.classList.toggle("active", state.scope === "ib");
document.body.classList.toggle("scope-ib", state.scope === "ib");
renderChips();
renderActiveFilters();
renderResults();
}
function scrollToResultsSmooth() {
if (!el.resultSection) return;
const top = Math.max(el.resultSection.getBoundingClientRect().top + window.scrollY - 10, 0);
window.scrollTo({ top, behavior: "smooth" });
}
function scrollToFiltersSmooth() {
if (!el.filtersSection) return;
const top = Math.max(el.filtersSection.getBoundingClientRect().top + window.scrollY - 8, 0);
window.scrollTo({ top, behavior: "smooth" });
}
function scrollToTopSmooth() {
window.scrollTo({ top: 0, behavior: "smooth" });
}
function scrollAfterDeselect() {
if (window.innerWidth > 980) {
scrollToTopSmooth();
return;
}
scrollToFiltersSmooth();
}
function renderActiveFilters() {
if (!el.activeFilters) return;
el.activeFilters.innerHTML = "";
const vendorsById = new Map(state.data.vendors.map(v => [v.id, v.name]));
const categoriesById = new Map(state.data.categories.map(c => [c.id, c.name]));
const items = [];
for (const id of state.selectedVendors) {
const name = vendorsById.get(id);
if (name) items.push({ kind: "Вендор", name, id, type: "vendor" });
}
for (const id of state.selectedCategories) {
const name = categoriesById.get(id);
if (name) items.push({ kind: "Категория", name, id, type: "category" });
}
if (items.length === 0) {
el.activeFilters.style.display = "none";
return;
}
el.activeFilters.style.display = "flex";
for (const item of items) {
const node = document.createElement("div");
node.className = "active-filter";
const text = document.createElement("span");
text.innerHTML = `<span class="kind">${item.kind}:</span> ${item.name}`;
node.appendChild(text);
const remove = document.createElement("button");
remove.className = "remove";
remove.type = "button";
remove.setAttribute("aria-label", `Убрать фильтр ${item.name}`);
remove.textContent = "×";
remove.addEventListener("click", () => {
if (item.type === "vendor") state.selectedVendors.delete(item.id);
else state.selectedCategories.delete(item.id);
render();
scrollToFiltersSmooth();
});
node.appendChild(remove);
el.activeFilters.appendChild(node);
}
}
async function loadScopeData(scope) {
const res = await fetch(`/api/data?scope=${encodeURIComponent(scope)}`);
state.data = await res.json();
@@ -258,6 +340,7 @@
el.vendorSearch.value = "";
el.categorySearch.value = "";
render();
scrollAfterDeselect();
});
el.modeInfra.addEventListener("click", () => {