Skip to content

Commit bd601a1

Browse files
committed
feat: Enhance search functionality with clear button and metadata display
1 parent ecdbfaf commit bd601a1

File tree

3 files changed

+122
-13
lines changed

3 files changed

+122
-13
lines changed

index.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,12 @@ <h3>EXPLORER</h3>
7575
</div>
7676

7777
<div class="search-box">
78-
<span class="material-symbols-outlined">search</span>
79-
<input type="text" id="fileSearch" placeholder="Search files..." class="search-input">
78+
<div class="search-field">
79+
<span class="material-symbols-outlined">search</span>
80+
<input type="text" id="fileSearch" placeholder="Search files or folders" class="search-input" autocomplete="off">
81+
<button type="button" class="search-clear" id="searchClear" aria-label="Clear search">×</button>
82+
</div>
83+
<small class="search-meta" id="searchMeta">Search file and folder names (case-insensitive)</small>
8084
</div>
8185

8286
<div class="sidebar-select">

index.js

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@
369369
};
370370
const D = {
371371
side: $safe('sidebar'), tog: $safe('toggleSidebar'), tree: $safe('fileTree'),
372-
search: $safe('fileSearch'), sel: $safe('selectDirBtn'),
372+
search: $safe('fileSearch'), searchMeta: $safe('searchMeta'), searchClear: $safe('searchClear'),
373+
sel: $safe('selectDirBtn'),
373374
exp: $safe('expandAll'), col: $safe('collapseAll'),
374375
all: $safe('selectAll'), none: $safe('deselectAll'),
375376
gen: $safe('generateContextBtn'), ed: $safe('codeEditor'),
@@ -867,6 +868,8 @@
867868
D.tok.textContent = '0';
868869
D.sz.textContent = '0 B';
869870
D.pron.textContent = 'zero tokens';
871+
if (D.search) D.search.value = '';
872+
updateTreeSearch('');
870873
D.lang.textContent = '-';
871874
// Clear search
872875
D.search.value = '';
@@ -960,6 +963,57 @@
960963
};
961964
// Pass parents array for lines
962965
const renderSub = (nodes, lv, parents) => render(nodes, lv, [], parents).map(x => x.html).join('');
966+
967+
const openTreeParents = item => {
968+
let current = item.parentElement;
969+
while (current) {
970+
if (current.classList && current.classList.contains('tree-children')) {
971+
current.classList.add('open');
972+
const parentItem = current.parentElement;
973+
if (parentItem && parentItem.classList.contains('tree-item')) {
974+
const btn = parentItem.querySelector('.expand-btn');
975+
if (btn) {
976+
btn.classList.add('expanded');
977+
const arrowImg = btn.querySelector('.tree-arrow');
978+
if (arrowImg) {
979+
arrowImg.src = 'public/arrowDown.svg';
980+
arrowImg.setAttribute('data-arrow', 'down');
981+
}
982+
}
983+
}
984+
current = parentItem ? parentItem.parentElement : null;
985+
continue;
986+
}
987+
current = current.parentElement;
988+
}
989+
};
990+
991+
const updateTreeSearch = query => {
992+
const term = (query || '').trim().toLowerCase();
993+
const items = document.querySelectorAll('.tree-item');
994+
let matches = 0;
995+
const total = items.length;
996+
items.forEach(item => {
997+
const nameEl = item.querySelector('.file-name');
998+
const name = nameEl ? nameEl.textContent.toLowerCase() : '';
999+
const path = (item.dataset.path || '').toLowerCase();
1000+
const match = !term || name.includes(term) || path.includes(term);
1001+
item.style.display = match ? '' : 'none';
1002+
item.classList.toggle('search-match', !!term && match);
1003+
if (term && match) {
1004+
matches += 1;
1005+
openTreeParents(item);
1006+
}
1007+
});
1008+
if (D.searchMeta) {
1009+
D.searchMeta.textContent = term
1010+
? `${matches} match${matches === 1 ? '' : 'es'} of ${total}`
1011+
: 'Search file and folder names (case-insensitive)';
1012+
}
1013+
if (D.searchClear) {
1014+
D.searchClear.hidden = !term;
1015+
}
1016+
};
9631017
// ============================================================================
9641018
// FILE LOADING - ASYNC CHUNKS (ENHANCED FILTERING & UI UPDATE)
9651019
// ============================================================================
@@ -1023,6 +1077,7 @@
10231077
const items = render(S.tree);
10241078
D.tree.innerHTML = items.map(x => x.html).join('');
10251079
S.rendered = items.length;
1080+
if (D.search) updateTreeSearch(D.search.value);
10261081
stats();
10271082
toast(`Loaded ${S.files.length} files`, 'success');
10281083
} catch (e) {
@@ -1576,13 +1631,25 @@
15761631
stats();
15771632
}
15781633
};
1579-
if (D.search) D.search.addEventListener('input', e => {
1580-
const q = e.target.value.toLowerCase();
1581-
document.querySelectorAll('.tree-item').forEach(item => {
1582-
const n = item.querySelector('.file-name').textContent.toLowerCase();
1583-
item.style.display = n.includes(q) ? '' : 'none';
1634+
if (D.search) {
1635+
D.search.addEventListener('input', e => updateTreeSearch(e.target.value));
1636+
D.search.addEventListener('keydown', e => {
1637+
if (e.key === 'Escape') {
1638+
e.target.value = '';
1639+
updateTreeSearch('');
1640+
}
15841641
});
1585-
});
1642+
}
1643+
if (D.searchClear) {
1644+
D.searchClear.hidden = true;
1645+
D.searchClear.addEventListener('click', () => {
1646+
if (D.search) {
1647+
D.search.value = '';
1648+
updateTreeSearch('');
1649+
D.search.focus();
1650+
}
1651+
});
1652+
}
15861653
const togFold = o => {
15871654
document.querySelectorAll('.expand-btn').forEach(btn => {
15881655
const item = btn.closest('.tree-item');

style.css

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -417,14 +417,21 @@ html, body {
417417
}
418418

419419
.search-box {
420-
position: relative;
421420
padding: 8px 12px;
422421
flex-shrink: 0;
422+
display: flex;
423+
flex-direction: column;
424+
gap: 4px;
425+
}
426+
427+
.search-field {
428+
position: relative;
429+
width: 100%;
423430
}
424431

425-
.search-box .material-symbols-outlined {
432+
.search-field .material-symbols-outlined {
426433
position: absolute;
427-
left: 20px;
434+
left: 14px;
428435
top: 50%;
429436
transform: translateY(-50%);
430437
color: var(--text-secondary);
@@ -434,7 +441,7 @@ html, body {
434441

435442
.search-input {
436443
width: 100%;
437-
padding: 6px 8px 6px 32px;
444+
padding: 6px 8px 6px 34px;
438445
background: var(--bg-editor);
439446
border: 1px solid var(--border-color);
440447
border-radius: 4px;
@@ -448,6 +455,31 @@ html, body {
448455
border-color: var(--color-accent);
449456
}
450457

458+
.search-clear {
459+
position: absolute;
460+
right: 8px;
461+
top: 50%;
462+
transform: translateY(-50%);
463+
background: transparent;
464+
border: none;
465+
color: var(--text-secondary);
466+
font-size: 14px;
467+
padding: 0;
468+
cursor: pointer;
469+
opacity: 0.6;
470+
transition: opacity 0.2s ease;
471+
}
472+
473+
.search-clear:hover {
474+
opacity: 1;
475+
}
476+
477+
.search-meta {
478+
font-size: 10px;
479+
color: var(--text-secondary);
480+
line-height: 1.2;
481+
}
482+
451483
.sidebar-select {
452484
padding: 0 12px;
453485
flex-shrink: 0;
@@ -558,6 +590,12 @@ html, body {
558590
transform: translateX(2px);
559591
}
560592

593+
.tree-item.search-match > .tree-item-content {
594+
background: rgba(59, 130, 246, 0.18);
595+
border: 1px solid rgba(59, 130, 246, 0.3);
596+
transform: translateX(0);
597+
}
598+
561599
.tree-item-content:active {
562600
background: rgba(255, 255, 255, 0.12);
563601
transform: translateX(0);

0 commit comments

Comments
 (0)