Replace collapsible sidebar panels with tab-based navigation for vaults and tags with debounced filtering and dynamic placeholder text
This commit is contained in:
+65
-66
@@ -22,10 +22,8 @@
|
||||
let sidebarFilterCaseSensitive = false;
|
||||
let searchCaseSensitive = false;
|
||||
let _iconDebounceTimer = null;
|
||||
const panelState = {
|
||||
vault: true,
|
||||
tag: true,
|
||||
};
|
||||
let activeSidebarTab = "vaults";
|
||||
let filterDebounce = null;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File extension → Lucide icon mapping
|
||||
@@ -435,7 +433,7 @@
|
||||
|
||||
function scrollTreeItemIntoView(element, alignToTop) {
|
||||
if (!element) return;
|
||||
const scrollContainer = document.getElementById("vault-panel-content");
|
||||
const scrollContainer = document.getElementById("sidebar-panel-vaults");
|
||||
if (!scrollContainer) return;
|
||||
|
||||
const containerRect = scrollContainer.getBoundingClientRect();
|
||||
@@ -483,7 +481,7 @@
|
||||
}
|
||||
|
||||
async function focusVaultInSidebar(vaultName) {
|
||||
setPanelExpanded("vault", true);
|
||||
switchSidebarTab("vaults");
|
||||
const vaultItem = document.querySelector(`.vault-item[data-vault="${CSS.escape(vaultName)}"]`);
|
||||
if (!vaultItem) return;
|
||||
document.querySelectorAll(".vault-item.focused").forEach((el) => el.classList.remove("focused"));
|
||||
@@ -567,7 +565,7 @@
|
||||
}
|
||||
|
||||
async function focusPathInSidebar(vaultName, targetPath, options) {
|
||||
setPanelExpanded("vault", true);
|
||||
switchSidebarTab("vaults");
|
||||
|
||||
const vaultItem = document.querySelector(`.vault-item[data-vault="${CSS.escape(vaultName)}"]`);
|
||||
if (!vaultItem) return;
|
||||
@@ -701,46 +699,59 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Sidebar filter
|
||||
// ---------------------------------------------------------------------------
|
||||
async function initSidebarFilter() {
|
||||
function initSidebarFilter() {
|
||||
const input = document.getElementById("sidebar-filter-input");
|
||||
const caseBtn = document.getElementById("sidebar-filter-case-btn");
|
||||
const clearBtn = document.getElementById("sidebar-filter-clear-btn");
|
||||
|
||||
input.addEventListener("input", async () => {
|
||||
|
||||
input.addEventListener("input", () => {
|
||||
const hasText = input.value.length > 0;
|
||||
clearBtn.style.display = hasText ? "flex" : "none";
|
||||
|
||||
const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase();
|
||||
|
||||
if (hasText) {
|
||||
await performTreeSearch(q);
|
||||
} else {
|
||||
await restoreSidebarTree();
|
||||
}
|
||||
|
||||
filterTagCloud(q);
|
||||
clearTimeout(filterDebounce);
|
||||
filterDebounce = setTimeout(async () => {
|
||||
const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase();
|
||||
if (hasText) {
|
||||
if (activeSidebarTab === "vaults") {
|
||||
await performTreeSearch(q);
|
||||
} else {
|
||||
filterTagCloud(q);
|
||||
}
|
||||
} else {
|
||||
if (activeSidebarTab === "vaults") {
|
||||
await restoreSidebarTree();
|
||||
} else {
|
||||
filterTagCloud("");
|
||||
}
|
||||
}
|
||||
}, 220);
|
||||
});
|
||||
|
||||
|
||||
caseBtn.addEventListener("click", async () => {
|
||||
sidebarFilterCaseSensitive = !sidebarFilterCaseSensitive;
|
||||
caseBtn.classList.toggle("active");
|
||||
const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase();
|
||||
if (input.value.trim()) {
|
||||
await performTreeSearch(q);
|
||||
if (activeSidebarTab === "vaults") {
|
||||
await performTreeSearch(q);
|
||||
} else {
|
||||
filterTagCloud(q);
|
||||
}
|
||||
}
|
||||
filterTagCloud(q);
|
||||
});
|
||||
|
||||
clearBtn.addEventListener("click", () => {
|
||||
|
||||
clearBtn.addEventListener("click", async () => {
|
||||
input.value = "";
|
||||
clearBtn.style.display = "none";
|
||||
sidebarFilterCaseSensitive = false;
|
||||
caseBtn.classList.remove("active");
|
||||
restoreSidebarTree();
|
||||
filterTagCloud("");
|
||||
clearTimeout(filterDebounce);
|
||||
if (activeSidebarTab === "vaults") {
|
||||
await restoreSidebarTree();
|
||||
} else {
|
||||
filterTagCloud("");
|
||||
}
|
||||
});
|
||||
|
||||
// Initially hide clear button
|
||||
|
||||
clearBtn.style.display = "none";
|
||||
}
|
||||
|
||||
@@ -1284,47 +1295,36 @@
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Collapsible panels and help modal
|
||||
// Sidebar tabs
|
||||
// ---------------------------------------------------------------------------
|
||||
function initCollapsiblePanels() {
|
||||
bindPanelToggle("vault", "vault-panel-toggle", "vault-panel-content");
|
||||
bindPanelToggle("tag", "tag-panel-toggle", "tag-panel-content");
|
||||
setPanelExpanded("vault", true);
|
||||
setPanelExpanded("tag", true);
|
||||
}
|
||||
|
||||
function bindPanelToggle(panelKey, toggleId, contentId) {
|
||||
const toggle = document.getElementById(toggleId);
|
||||
const content = document.getElementById(contentId);
|
||||
if (!toggle || !content) return;
|
||||
toggle.addEventListener("click", () => {
|
||||
setPanelExpanded(panelKey, !panelState[panelKey]);
|
||||
function initSidebarTabs() {
|
||||
document.querySelectorAll(".sidebar-tab").forEach((tab) => {
|
||||
tab.addEventListener("click", () => switchSidebarTab(tab.dataset.tab));
|
||||
});
|
||||
}
|
||||
|
||||
function setPanelExpanded(panelKey, expanded) {
|
||||
panelState[panelKey] = expanded;
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
const toggle = document.getElementById(`${panelKey}-panel-toggle`);
|
||||
const content = document.getElementById(`${panelKey}-panel-content`);
|
||||
if (!toggle || !content) return;
|
||||
toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
content.classList.toggle("collapsed", !expanded);
|
||||
const iconEl = toggle.querySelector("[data-lucide]");
|
||||
if (iconEl) {
|
||||
iconEl.setAttribute("data-lucide", expanded ? "chevron-down" : "chevron-right");
|
||||
function switchSidebarTab(tab) {
|
||||
activeSidebarTab = tab;
|
||||
document.querySelectorAll(".sidebar-tab").forEach((btn) => {
|
||||
const isActive = btn.dataset.tab === tab;
|
||||
btn.classList.toggle("active", isActive);
|
||||
btn.setAttribute("aria-selected", isActive ? "true" : "false");
|
||||
});
|
||||
document.querySelectorAll(".sidebar-tab-panel").forEach((panel) => {
|
||||
const isActive = panel.id === `sidebar-panel-${tab}`;
|
||||
panel.classList.toggle("active", isActive);
|
||||
});
|
||||
const filterInput = document.getElementById("sidebar-filter-input");
|
||||
if (filterInput) {
|
||||
filterInput.placeholder = tab === "vaults" ? "Filtrer fichiers..." : "Filtrer tags...";
|
||||
}
|
||||
if (panelKey === "tag") {
|
||||
const tagSection = document.getElementById("tag-cloud-section");
|
||||
const resizeHandle = document.getElementById("tag-resize-handle");
|
||||
if (tagSection) tagSection.classList.toggle("collapsed-panel", !expanded);
|
||||
if (resizeHandle) resizeHandle.classList.toggle("hidden", !expanded);
|
||||
const query = filterInput
|
||||
? (sidebarFilterCaseSensitive ? filterInput.value.trim() : filterInput.value.trim().toLowerCase())
|
||||
: "";
|
||||
if (query) {
|
||||
if (tab === "vaults") performTreeSearch(query);
|
||||
else filterTagCloud(query);
|
||||
}
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle("vault-collapsed", !panelState.vault);
|
||||
sidebar.classList.toggle("tag-collapsed", !panelState.tag);
|
||||
}
|
||||
safeCreateIcons();
|
||||
}
|
||||
|
||||
function initHelpModal() {
|
||||
@@ -2017,12 +2017,11 @@
|
||||
initSearch();
|
||||
initMobile();
|
||||
initVaultContext();
|
||||
initCollapsiblePanels();
|
||||
initSidebarTabs();
|
||||
initHelpModal();
|
||||
initConfigModal();
|
||||
initSidebarFilter();
|
||||
initSidebarResize();
|
||||
initTagResize();
|
||||
initEditor();
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user