diff --git a/index.html b/index.html
index 233b51d..724e297 100644
--- a/index.html
+++ b/index.html
@@ -1073,6 +1073,14 @@
autocapitalize="off"
spellcheck="false"
/>
+
@@ -1642,14 +1650,41 @@
-
+
+
+
{
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)}`);
diff --git a/js/ui.js b/js/ui.js
index ad3d21a..73891c9 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -539,6 +539,33 @@ export class UIRenderer {
.join('')}`;
}
+ 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');
diff --git a/styles.css b/styles.css
index 1501260..49de3b9 100644
--- a/styles.css
+++ b/styles.css
@@ -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);
}