Merge pull request #155 from blacksigkill/feature/discard-search

Discard search with "x" button
This commit is contained in:
Eduard Prigoana 2026-02-05 18:49:14 +02:00 committed by GitHub
commit 9ac90d8fab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 120 additions and 39 deletions

View file

@ -1073,6 +1073,14 @@
autocapitalize="off"
spellcheck="false"
/>
<button
type="button"
class="search-clear-btn btn-icon"
title="Clear search"
style="display: none"
>
&times;
</button>
<div id="search-history" class="search-history" style="display: none"></div>
</form>
</header>
@ -1642,14 +1650,41 @@
</div>
</div>
</header>
<div class="track-list-search-container">
<form class="track-list-search-container" onsubmit="return false;">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="search-icon"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<input
type="text"
type="search"
id="track-list-search-input"
placeholder="Search tracks..."
class="track-list-search-input"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
</div>
<button
type="button"
class="search-clear-btn btn-icon"
title="Clear search"
style="display: none"
>
&times;
</button>
</form>
<div id="playlist-detail-tracklist" class="track-list"></div>
<section

View file

@ -1274,6 +1274,9 @@ document.addEventListener('DOMContentLoaded', async () => {
const searchForm = document.getElementById('search-form');
const searchInput = document.getElementById('search-input');
// Setup clear button for search bar
ui.setupSearchClearButton(searchInput);
const performSearch = debounce((query) => {
if (query) {
navigate(`/search/${encodeURIComponent(query)}`);

View file

@ -539,6 +539,33 @@ export class UIRenderer {
.join('')}</div>`;
}
setupSearchClearButton(inputElement, clearBtnSelector = '.search-clear-btn') {
if (!inputElement) return;
const clearBtn = inputElement.parentElement?.querySelector(clearBtnSelector);
if (!clearBtn) return;
// Remove old listener if exists
const oldListener = clearBtn._clearListener;
if (oldListener) clearBtn.removeEventListener('click', oldListener);
// Toggle visibility based on input value
const toggleVisibility = () => {
clearBtn.style.display = inputElement.value.trim() ? 'flex' : 'none';
};
// Clear input on click
const clearListener = () => {
inputElement.value = '';
inputElement.dispatchEvent(new Event('input'));
inputElement.focus();
};
inputElement.addEventListener('input', toggleVisibility);
clearBtn._clearListener = clearListener;
clearBtn.addEventListener('click', clearListener);
}
setupTracklistSearch(
searchInputId = 'track-list-search-input',
tracklistContainerId = 'playlist-detail-tracklist'
@ -548,6 +575,9 @@ export class UIRenderer {
if (!searchInput || !tracklistContainer) return;
// Setup clear button
this.setupSearchClearButton(searchInput);
// Remove previous listener if exists
const oldListener = searchInput._searchListener;
if (oldListener) {
@ -1944,6 +1974,11 @@ export class UIRenderer {
async renderPlaylistPage(playlistId, source = null) {
this.showPage('playlist');
// Reset search input for new playlist
const searchInput = document.getElementById('track-list-search-input');
if (searchInput) searchInput.value = '';
const imageEl = document.getElementById('playlist-detail-image');
const titleEl = document.getElementById('playlist-detail-title');
const metaEl = document.getElementById('playlist-detail-meta');

View file

@ -474,14 +474,8 @@ kbd {
}
.search-bar svg.search-icon {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: var(--muted-foreground);
width: 20px;
height: 20px;
pointer-events: none;
}
.sidebar-nav .nav-item a:hover {
@ -576,20 +570,11 @@ kbd {
}
.search-bar {
position: relative;
width: 80%;
max-width: 100%;
display: flex;
align-items: center;
}
.search-bar input {
width: 100%;
padding: 0.75rem 0.75rem 0.75rem 2.5rem;
background-color: var(--input);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--foreground);
font-size: 1rem;
transition:
box-shadow var(--transition-fast),
@ -597,10 +582,52 @@ kbd {
background-color var(--transition-fast);
}
.search-bar input:focus {
/* Shared search bar styles */
.search-bar,
.track-list-search-container {
position: relative;
display: flex;
align-items: center;
}
.search-bar svg.search-icon,
.track-list-search-container svg.search-icon {
position: absolute;
left: 0.75rem;
top: 50%;
transform: translateY(-50%);
color: var(--muted-foreground);
pointer-events: none;
}
.search-bar input,
.track-list-search-input {
width: 100%;
padding: 0.75rem 2.5rem;
background-color: var(--input);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--foreground);
transition:
box-shadow var(--transition-fast),
border-color var(--transition-fast);
}
.search-bar input:focus,
.track-list-search-input:focus {
outline: none;
border-color: var(--ring);
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb), 0.2);
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb) / 0.2);
}
.search-clear-btn {
position: absolute;
right: 0.25rem;
top: 50%;
transform: translateY(-50%);
font-size: 1.5rem;
line-height: 1;
z-index: 1;
}
body.has-page-background .search-bar input {
@ -5522,24 +5549,5 @@ textarea:focus {
}
.track-list-search-input {
width: 100%;
padding: 0.75rem 1rem;
background-color: var(--input);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--foreground);
font-size: 0.95rem;
transition:
box-shadow var(--transition-fast),
border-color var(--transition-fast);
}
.track-list-search-input:focus {
outline: none;
border-color: var(--ring);
box-shadow: 0 0 0 3px rgb(var(--highlight-rgb) / 0.2);
}
.track-list-search-input::placeholder {
color: var(--muted-foreground);
}