сворачивание / разворачивание элементов дерева при поиске

This commit is contained in:
Илья Братских 2026-06-28 14:43:45 +03:00 committed by KBAHTNET
parent 45fedcd359
commit c187c66737
2 changed files with 44 additions and 3 deletions

View File

@ -105,11 +105,19 @@
<label class="toggle-row">
<span>
<strong>Показывать теги дерева</strong>
<small>Тип сервиса рядом с элементом</small>
<small>Поисковые теги рядом с элементом</small>
</span>
<input type="checkbox" data-show-tree-tags />
</label>
<label class="toggle-row">
<span>
<strong>Авто раскрывать поиск</strong>
<small>Сворачивать ветки без совпадений</small>
</span>
<input type="checkbox" data-auto-collapse-search />
</label>
<div class="control-group accent-group">
<span>Акцент</span>
<button

View File

@ -139,6 +139,7 @@ const defaultPreferences = {
accent: "violet",
showNumbers: false,
showTreeTags: true,
autoCollapseSearch: true,
sidebarWidth: 390,
};
const availableViews = ["cards", "list", "compact-cards", "compact-list"];
@ -158,6 +159,7 @@ const viewButtons = document.querySelectorAll("[data-view]");
const accentButtons = document.querySelectorAll("[data-accent]");
const showNumbersInput = document.querySelector("[data-show-numbers]");
const showTreeTagsInput = document.querySelector("[data-show-tree-tags]");
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
const emptyTemplate = document.querySelector("#empty-template");
renderNavigationTree();
@ -247,6 +249,13 @@ showTreeTagsInput.addEventListener("change", () => {
savePreferences(preferences);
});
autoCollapseSearchInput.addEventListener("change", () => {
preferences.autoCollapseSearch = autoCollapseSearchInput.checked;
applyPreferences(preferences);
renderNavigationTree();
savePreferences(preferences);
});
sidebarResizer.addEventListener("pointerdown", (event) => {
event.preventDefault();
document.body.classList.add("is-resizing-sidebar");
@ -423,15 +432,37 @@ function matchesQuery(item, group, section, query) {
return haystack.includes(query);
}
function groupMatchesQuery(group, section, query) {
if (!query) {
return true;
}
return (
matchesText([group.number, group.title, group.description, section.title], query) ||
group.items.some((item) => matchesQuery(item, group, section, query))
);
}
function matchesText(values, query) {
if (!query) {
return true;
}
return normalize(values.join(" ")).includes(query);
}
function renderNavigationTree() {
const query = normalize(searchInput.value);
const shouldAutoCollapse = Boolean(query && preferences.autoCollapseSearch);
const fragment = document.createDocumentFragment();
ecosystemSections.forEach((section) => {
const sectionOwnMatch = matchesText([section.number, section.title, section.description], query);
const sectionHasMatches = sectionOwnMatch || section.groups.some((group) => groupMatchesQuery(group, section, query));
const sectionNode = document.createElement("details");
sectionNode.className = "tree-section";
sectionNode.dataset.collapseKey = getTreeSectionId(section);
sectionNode.open = getSavedOpenState(sectionNode.dataset.collapseKey);
sectionNode.open = shouldAutoCollapse ? sectionHasMatches : getSavedOpenState(sectionNode.dataset.collapseKey);
const sectionSummary = document.createElement("summary");
sectionSummary.innerHTML = `
@ -443,10 +474,11 @@ function renderNavigationTree() {
sectionNode.append(sectionSummary);
section.groups.forEach((group) => {
const groupHasMatches = groupMatchesQuery(group, section, query);
const groupNode = document.createElement("details");
groupNode.className = "tree-group";
groupNode.dataset.collapseKey = getTreeGroupId(group);
groupNode.open = getSavedOpenState(groupNode.dataset.collapseKey);
groupNode.open = shouldAutoCollapse ? groupHasMatches : getSavedOpenState(groupNode.dataset.collapseKey);
const groupSummary = document.createElement("summary");
groupSummary.innerHTML = `
@ -576,6 +608,7 @@ function applyPreferences(nextPreferences) {
document.documentElement.dataset.showTreeTags = String(Boolean(nextPreferences.showTreeTags));
showNumbersInput.checked = Boolean(nextPreferences.showNumbers);
showTreeTagsInput.checked = Boolean(nextPreferences.showTreeTags);
autoCollapseSearchInput.checked = Boolean(nextPreferences.autoCollapseSearch);
setActiveButton(themeButtons, "theme", nextPreferences.theme);
setActiveButton(viewButtons, "view", nextPreferences.view);
setActiveButton(accentButtons, "accent", nextPreferences.accent);