2х рядный режим для дерева

This commit is contained in:
Илья Братских 2026-06-28 15:07:32 +03:00 committed by KBAHTNET
parent 6aa5daf9ea
commit 15c6215eef
3 changed files with 88 additions and 5 deletions

View File

@ -132,11 +132,20 @@
<label class="toggle-row">
<span>
<strong>Показывать теги дерева</strong>
<small>Поисковые теги рядом с элементом</small>
<small>Теги рядом с элементом, без 2 колонок</small>
</span>
<input type="checkbox" data-show-tree-tags />
</label>
<!-- Элементы внутри папок дерева отображаются в две колонки без тегов. -->
<label class="toggle-row">
<span>
<strong>2 колонки в дереве</strong>
<small>Компактный вид элементов папок</small>
</span>
<input type="checkbox" data-tree-two-column />
</label>
<!-- Управляет тем, раскрывает ли поиск только ветки с совпадениями. -->
<label class="toggle-row">
<span>

View File

@ -171,6 +171,7 @@ const defaultPreferences = {
customAccentAngle: 135,
showNumbers: false,
showTreeTags: true,
treeTwoColumn: false,
autoCollapseSearch: true,
sidebarWidth: 390,
};
@ -206,6 +207,7 @@ const customAccentAngleValue = document.querySelector("[data-custom-accent-angle
const customAccentPreview = document.querySelector("[data-custom-accent-preview]");
const showNumbersInput = document.querySelector("[data-show-numbers]");
const showTreeTagsInput = document.querySelector("[data-show-tree-tags]");
const treeTwoColumnInput = document.querySelector("[data-tree-two-column]");
const autoCollapseSearchInput = document.querySelector("[data-auto-collapse-search]");
const emptyTemplate = document.querySelector("#empty-template");
@ -326,8 +328,26 @@ showNumbersInput.addEventListener("change", () => {
});
// Показывает/скрывает поисковые теги в файловом дереве.
// Взаимоисключимо с двухколоночным режимом элементов папок.
showTreeTagsInput.addEventListener("change", () => {
preferences.showTreeTags = showTreeTagsInput.checked;
if (preferences.showTreeTags) {
preferences.treeTwoColumn = false;
}
applyPreferences(preferences);
savePreferences(preferences);
});
// Компактный двухколоночный режим элементов внутри папок дерева.
// Взаимоисключимо с отображением тегов.
treeTwoColumnInput.addEventListener("change", () => {
preferences.treeTwoColumn = treeTwoColumnInput.checked;
if (preferences.treeTwoColumn) {
preferences.showTreeTags = false;
if (preferences.sidebarWidth < 480) {
preferences.sidebarWidth = 480;
}
}
applyPreferences(preferences);
savePreferences(preferences);
});
@ -349,7 +369,9 @@ sidebarResizer.addEventListener("pointerdown", (event) => {
const handlePointerMove = (moveEvent) => {
const layoutLeft = document.querySelector(".app-layout").getBoundingClientRect().left;
preferences.sidebarWidth = Math.round(clamp(moveEvent.clientX - layoutLeft, 260, 560));
preferences.sidebarWidth = Math.round(
clamp(moveEvent.clientX - layoutLeft, 260, getSidebarMaxWidth(preferences)),
);
applyPreferences(preferences);
};
@ -754,19 +776,39 @@ function applyPreferences(nextPreferences) {
360,
);
if (nextPreferences.treeTwoColumn) {
nextPreferences.showTreeTags = false;
} else if (nextPreferences.showTreeTags) {
nextPreferences.treeTwoColumn = false;
}
document.documentElement.dataset.theme = nextPreferences.theme;
document.documentElement.dataset.accent = nextPreferences.accent;
applyAccentVariables(nextPreferences);
document.documentElement.style.setProperty(
"--sidebar-width",
`${clamp(Number(nextPreferences.sidebarWidth) || defaultPreferences.sidebarWidth, 260, 560)}px`,
`${clamp(
Number(nextPreferences.sidebarWidth) || defaultPreferences.sidebarWidth,
260,
getSidebarMaxWidth(nextPreferences),
)}px`,
);
document.documentElement.style.setProperty(
"--shell-max-width",
nextPreferences.treeTwoColumn ? "1920px" : "1560px",
);
document.documentElement.style.setProperty(
"--sidebar-max-width",
`${getSidebarMaxWidth(nextPreferences)}px`,
);
catalog.classList.remove("cards-view", "list-view", "compact-cards-view", "compact-list-view");
catalog.classList.add(`${nextPreferences.view}-view`);
document.documentElement.dataset.showNumbers = String(Boolean(nextPreferences.showNumbers));
document.documentElement.dataset.showTreeTags = String(Boolean(nextPreferences.showTreeTags));
document.documentElement.dataset.treeTwoColumn = String(Boolean(nextPreferences.treeTwoColumn));
showNumbersInput.checked = Boolean(nextPreferences.showNumbers);
showTreeTagsInput.checked = Boolean(nextPreferences.showTreeTags);
treeTwoColumnInput.checked = Boolean(nextPreferences.treeTwoColumn);
autoCollapseSearchInput.checked = Boolean(nextPreferences.autoCollapseSearch);
customAccentFromInput.value = nextPreferences.customAccentFrom;
customAccentToInput.value = nextPreferences.customAccentTo;
@ -930,6 +972,11 @@ function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
// Максимальная ширина sidebar зависит от режима дерева.
function getSidebarMaxWidth(nextPreferences) {
return nextPreferences.treeTwoColumn ? 760 : 560;
}
// ============================================================================
// localStorage helpers
// ============================================================================

View File

@ -24,6 +24,8 @@
--card-x: 50%;
--card-y: 50%;
--sidebar-width: 390px;
--shell-max-width: 1560px;
--sidebar-max-width: 560px;
}
/* Светлая тема переопределяет только токены, структура стилей остается общей. */
@ -128,7 +130,7 @@ a {
========================================================================== */
.shell {
width: min(1560px, calc(100% - 28px));
width: min(var(--shell-max-width), calc(100% - 28px));
margin: 0 auto;
padding: 20px 0;
}
@ -269,6 +271,27 @@ html[data-show-tree-tags="false"] .tree-node small {
display: none;
}
/* Двухколоночный режим элементов внутри папок дерева. */
html[data-tree-two-column="true"] {
--shell-max-width: 1920px;
--sidebar-max-width: 760px;
}
html[data-tree-two-column="true"] .tree-items {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 2px 8px;
}
html[data-tree-two-column="true"] .tree-node.tree-file {
grid-template-columns: 16px minmax(0, 1fr);
min-height: 24px;
font-size: 0.8rem;
}
html[data-tree-two-column="true"] .tree-node.tree-file small {
display: none;
}
/* Подсветка совпадений поиска в дереве и в карточках. */
.search-mark {
border-radius: 4px;
@ -1357,7 +1380,7 @@ html[data-theme="light"] .accent-swatch-custom {
@media (max-width: 720px) {
.shell {
width: min(100% - 22px, 1320px);
width: min(var(--shell-max-width), calc(100% - 22px));
padding: 14px 0;
}
@ -1385,6 +1408,10 @@ html[data-theme="light"] .accent-swatch-custom {
overflow: auto;
}
html[data-tree-two-column="true"] .tree-items {
grid-template-columns: 1fr;
}
.control-panel,
.catalog-section,
.empty-state {