Add auto-expand vault functionality to sidebar filter with improved clear button visibility and restructured input layouts for both search and filter components

This commit is contained in:
Bruno Charest 2026-03-22 13:24:06 -04:00
parent 3a86450a73
commit d9add8dcba
3 changed files with 115 additions and 33 deletions

View File

@ -623,20 +623,31 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Sidebar filter // Sidebar filter
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function initSidebarFilter() { async function initSidebarFilter() {
const input = document.getElementById("sidebar-filter-input"); const input = document.getElementById("sidebar-filter-input");
const caseBtn = document.getElementById("sidebar-filter-case-btn"); const caseBtn = document.getElementById("sidebar-filter-case-btn");
const clearBtn = document.getElementById("sidebar-filter-clear-btn"); const clearBtn = document.getElementById("sidebar-filter-clear-btn");
input.addEventListener("input", () => { input.addEventListener("input", async () => {
const hasText = input.value.length > 0;
clearBtn.style.display = hasText ? "flex" : "none";
if (hasText) {
// Expand all vaults and load their contents for filtering
await expandAllVaultsForFiltering();
}
const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase(); const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase();
filterSidebarTree(q); filterSidebarTree(q);
filterTagCloud(q); filterTagCloud(q);
}); });
caseBtn.addEventListener("click", () => { caseBtn.addEventListener("click", async () => {
sidebarFilterCaseSensitive = !sidebarFilterCaseSensitive; sidebarFilterCaseSensitive = !sidebarFilterCaseSensitive;
caseBtn.classList.toggle("active"); caseBtn.classList.toggle("active");
if (input.value.trim()) {
await expandAllVaultsForFiltering();
}
const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase(); const q = sidebarFilterCaseSensitive ? input.value.trim() : input.value.trim().toLowerCase();
filterSidebarTree(q); filterSidebarTree(q);
filterTagCloud(q); filterTagCloud(q);
@ -644,11 +655,26 @@
clearBtn.addEventListener("click", () => { clearBtn.addEventListener("click", () => {
input.value = ""; input.value = "";
clearBtn.style.display = "none";
sidebarFilterCaseSensitive = false; sidebarFilterCaseSensitive = false;
caseBtn.classList.remove("active"); caseBtn.classList.remove("active");
filterSidebarTree(""); filterSidebarTree("");
filterTagCloud(""); filterTagCloud("");
}); });
// Initially hide clear button
clearBtn.style.display = "none";
}
async function expandAllVaultsForFiltering() {
const vaultItems = document.querySelectorAll(".vault-item");
for (const vaultItem of vaultItems) {
const vaultName = vaultItem.getAttribute("data-vault");
const childContainer = document.getElementById(`vault-children-${vaultName}`);
if (childContainer && childContainer.classList.contains("collapsed")) {
await toggleVault(vaultItem, vaultName, true);
}
}
} }
function filterSidebarTree(query) { function filterSidebarTree(query) {
@ -1263,7 +1289,13 @@
const caseBtn = document.getElementById("search-case-btn"); const caseBtn = document.getElementById("search-case-btn");
const clearBtn = document.getElementById("search-clear-btn"); const clearBtn = document.getElementById("search-clear-btn");
// Initially hide clear button
clearBtn.style.display = "none";
input.addEventListener("input", () => { input.addEventListener("input", () => {
const hasText = input.value.length > 0;
clearBtn.style.display = hasText ? "flex" : "none";
clearTimeout(searchTimeout); clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => { searchTimeout = setTimeout(() => {
const q = input.value.trim(); const q = input.value.trim();
@ -1284,6 +1316,7 @@
clearBtn.addEventListener("click", () => { clearBtn.addEventListener("click", () => {
input.value = ""; input.value = "";
clearBtn.style.display = "none";
searchCaseSensitive = false; searchCaseSensitive = false;
caseBtn.classList.remove("active"); caseBtn.classList.remove("active");
showWelcome(); showWelcome();

View File

@ -78,7 +78,9 @@
<div class="header-center"> <div class="header-center">
<div class="search-wrapper"> <div class="search-wrapper">
<i data-lucide="search" class="search-icon" style="width:16px;height:16px"></i> <i data-lucide="search" class="search-icon" style="width:16px;height:16px"></i>
<div class="search-input-wrapper">
<input type="text" id="search-input" placeholder="Recherche..." autocomplete="off"> <input type="text" id="search-input" placeholder="Recherche..." autocomplete="off">
<div class="search-actions">
<button class="search-btn" id="search-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse"> <button class="search-btn" id="search-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse">
<span>Aa</span> <span>Aa</span>
</button> </button>
@ -87,6 +89,8 @@
</button> </button>
</div> </div>
</div> </div>
</div>
</div>
<div class="header-right"> <div class="header-right">
<div class="header-menu"> <div class="header-menu">
@ -158,7 +162,9 @@
<!-- Sidebar filter --> <!-- Sidebar filter -->
<div class="sidebar-filter"> <div class="sidebar-filter">
<i data-lucide="filter" class="sidebar-filter-icon" style="width:14px;height:14px"></i> <i data-lucide="filter" class="sidebar-filter-icon" style="width:14px;height:14px"></i>
<div class="sidebar-filter-input-wrapper">
<input type="text" id="sidebar-filter-input" placeholder="Filtrer fichiers et tags..." autocomplete="off"> <input type="text" id="sidebar-filter-input" placeholder="Filtrer fichiers et tags..." autocomplete="off">
<div class="sidebar-filter-actions">
<button class="sidebar-filter-btn" id="sidebar-filter-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse"> <button class="sidebar-filter-btn" id="sidebar-filter-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse">
<span>Aa</span> <span>Aa</span>
</button> </button>
@ -166,6 +172,8 @@
<i data-lucide="x" style="width:14px;height:14px"></i> <i data-lucide="x" style="width:14px;height:14px"></i>
</button> </button>
</div> </div>
</div>
</div>
<div class="custom-dropdown sidebar-dropdown" id="vault-quick-select-dropdown"> <div class="custom-dropdown sidebar-dropdown" id="vault-quick-select-dropdown">
<button class="custom-dropdown-trigger" type="button" aria-haspopup="listbox" aria-expanded="false"> <button class="custom-dropdown-trigger" type="button" aria-haspopup="listbox" aria-expanded="false">

View File

@ -153,11 +153,27 @@ a:hover {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px;
} }
.search-wrapper input { .search-wrapper .search-icon {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
pointer-events: none;
z-index: 1;
}
.search-input-wrapper {
position: relative;
flex: 1; flex: 1;
display: flex;
align-items: center;
}
.search-input-wrapper input {
width: 100%;
padding: 8px 14px 8px 38px; padding: 8px 14px 8px 38px;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 6px; border-radius: 6px;
@ -168,26 +184,29 @@ a:hover {
outline: none; outline: none;
transition: border-color 200ms ease, background 200ms ease; transition: border-color 200ms ease, background 200ms ease;
} }
.search-wrapper input:focus {
.search-input-wrapper input:focus {
border-color: var(--accent); border-color: var(--accent);
} }
.search-wrapper .search-icon {
.search-actions {
position: absolute; position: absolute;
left: 10px; right: 4px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
color: var(--text-secondary); display: flex;
pointer-events: none; align-items: center;
gap: 4px;
} }
.search-btn { .search-btn {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 32px; width: 28px;
height: 32px; height: 28px;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 6px; border-radius: 4px;
background: var(--bg-secondary); background: var(--bg-secondary);
color: var(--text-secondary); color: var(--text-secondary);
cursor: pointer; cursor: pointer;
@ -196,6 +215,7 @@ a:hover {
font-weight: 600; font-weight: 600;
transition: all 150ms ease; transition: all 150ms ease;
padding: 0; padding: 0;
flex-shrink: 0;
} }
.search-btn:hover { .search-btn:hover {
@ -554,8 +574,16 @@ select {
align-items: center; align-items: center;
gap: 6px; gap: 6px;
} }
.sidebar-filter input {
.sidebar-filter-input-wrapper {
position: relative;
flex: 1; flex: 1;
display: flex;
align-items: center;
}
.sidebar-filter-input-wrapper input {
width: 100%;
padding: 6px 10px 6px 32px; padding: 6px 10px 6px 32px;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 6px; border-radius: 6px;
@ -566,31 +594,44 @@ select {
outline: none; outline: none;
transition: border-color 200ms ease; transition: border-color 200ms ease;
} }
.sidebar-filter input:focus {
.sidebar-filter-input-wrapper input:focus {
border-color: var(--accent); border-color: var(--accent);
} }
.sidebar-filter-icon { .sidebar-filter-icon {
position: absolute; position: absolute;
left: 22px; left: 10px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
color: var(--text-muted); color: var(--text-muted);
pointer-events: none; pointer-events: none;
z-index: 1;
}
.sidebar-filter-actions {
position: absolute;
right: 4px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
gap: 4px;
} }
.sidebar-filter-btn { .sidebar-filter-btn {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 28px; width: 24px;
height: 28px; height: 24px;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 4px; border-radius: 4px;
background: var(--bg-secondary); background: var(--bg-secondary);
color: var(--text-secondary); color: var(--text-secondary);
cursor: pointer; cursor: pointer;
font-family: 'JetBrains Mono', monospace; font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem; font-size: 0.65rem;
font-weight: 600; font-weight: 600;
transition: all 150ms ease; transition: all 150ms ease;
padding: 0; padding: 0;