stromboli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit e3db10e2f70fba19014b8001f014a75cc7a09b37
parent 0ea2fff030bbbf0fda29a223c8f16874d6b49978
Author: breadcat <breadcat@users.noreply.github.com>
Date:   Fri,  6 Feb 2026 12:19:12 +0000

Add filter box to file browser

Diffstat:
Mmain.go | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 93 insertions(+), 5 deletions(-)

diff --git a/main.go b/main.go @@ -117,8 +117,17 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { background: #2d2d2d; border-bottom: 1px solid #3d3d3d; font-size: 0.9rem; - overflow-x: auto; + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + } + .breadcrumb-path { + flex: 1; + overflow: hidden; white-space: nowrap; + text-overflow: ellipsis; + min-width: 0; } .breadcrumb span { color: #4a9eff; @@ -127,6 +136,40 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { border-radius: 3px; } .breadcrumb span:hover { background: #3d3d3d; } + .filter-toggle { + background: #3d3d3d; + border: none; + color: #e0e0e0; + padding: 0.5rem 0.75rem; + border-radius: 4px; + cursor: pointer; + font-size: 0.9rem; + margin-left: 0.5rem; + flex-shrink: 0; + } + .filter-toggle:hover { background: #4d4d4d; } + .filter-toggle.active { background: #4a9eff; color: #000; } + .filter-bar { + padding: 0.75rem 1rem; + background: #2d2d2d; + border-bottom: 1px solid #3d3d3d; + display: none; + } + .filter-bar.visible { display: block; } + .filter-input { + width: 100%; + padding: 0.5rem; + background: #1a1a1a; + border: 1px solid #3d3d3d; + border-radius: 4px; + color: #e0e0e0; + font-size: 0.9rem; + } + .filter-input:focus { + outline: none; + border-color: #4a9eff; + } + .filter-input::placeholder { color: #666; } .file-list { flex: 1; overflow-y: auto; @@ -230,7 +273,13 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { </header> <div class="container"> <div class="browser"> - <div class="breadcrumb" id="breadcrumb"></div> + <div class="breadcrumb" id="breadcrumb"> + <div class="breadcrumb-path" id="breadcrumbPath"></div> + <button class="filter-toggle" id="filterToggle" onclick="toggleFilter()">&#x1F50D;</button> + </div> + <div class="filter-bar" id="filterBar"> + <input type="text" class="filter-input" id="filterInput" placeholder="Filter files and folders..." oninput="applyFilter()"> + </div> <div class="file-list" id="fileList"> <div class="loading">Loading...</div> </div> @@ -246,13 +295,52 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { <script> let currentPath = ''; let currentVideo = null; + let allFiles = []; + let filterVisible = false; + + function toggleFilter() { + filterVisible = !filterVisible; + const filterBar = document.getElementById('filterBar'); + const filterToggle = document.getElementById('filterToggle'); + const filterInput = document.getElementById('filterInput'); + + if (filterVisible) { + filterBar.classList.add('visible'); + filterToggle.classList.add('active'); + filterInput.focus(); + } else { + filterBar.classList.remove('visible'); + filterToggle.classList.remove('active'); + filterInput.value = ''; + renderFileList(allFiles); + } + } + + function applyFilter() { + const filterText = document.getElementById('filterInput').value.toLowerCase(); + + if (!filterText) { + renderFileList(allFiles); + return; + } + + const filtered = allFiles.filter(file => + file.name.toLowerCase().includes(filterText) + ); + + renderFileList(filtered); + } function browse(path = '') { currentPath = path; fetch('/api/browse?path=' + encodeURIComponent(path)) .then(r => r.json()) .then(files => { + allFiles = files; updateBreadcrumb(path); + + // Clear filter when changing directories + document.getElementById('filterInput').value = ''; renderFileList(files); }) .catch(err => { @@ -263,7 +351,7 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { function updateBreadcrumb(path) { const parts = path ? path.split('/').filter(p => p) : []; - const breadcrumb = document.getElementById('breadcrumb'); + const breadcrumbPath = document.getElementById('breadcrumbPath'); let html = '<span onclick="browse(\'\')">Home</span>'; let accumulated = ''; @@ -274,14 +362,14 @@ func handleIndex(w http.ResponseWriter, r *http.Request) { html += ' / <span onclick="browse(\'' + thisPath + '\')">' + part + '</span>'; }); - breadcrumb.innerHTML = html; + breadcrumbPath.innerHTML = html; } function renderFileList(files) { const list = document.getElementById('fileList'); if (files.length === 0) { - list.innerHTML = '<div class="loading">Empty directory</div>'; + list.innerHTML = '<div class="loading">No matches found</div>'; return; }