From 6b66d7b3f44a5e870f1428e5c49e8a920c0cf0ed Mon Sep 17 00:00:00 2001 From: BlackSigkill Date: Thu, 5 Feb 2026 13:30:37 +0100 Subject: [PATCH] add a search bar in playlists to quickly find titles --- index.html | 8 ++++++++ js/ui.js | 43 +++++++++++++++++++++++++++++++++++++++++++ styles.css | 28 ++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/index.html b/index.html index 7c5b05c..233b51d 100644 --- a/index.html +++ b/index.html @@ -1642,6 +1642,14 @@ +
+ +
`; } + setupTracklistSearch(searchInputId = 'track-list-search-input', tracklistContainerId = 'playlist-detail-tracklist') { + const searchInput = document.getElementById(searchInputId); + const tracklistContainer = document.getElementById(tracklistContainerId); + + if (!searchInput || !tracklistContainer) return; + + // Remove previous listener if exists + const oldListener = searchInput._searchListener; + if (oldListener) { + searchInput.removeEventListener('input', oldListener); + } + + // Create new listener + const listener = () => { + const query = searchInput.value.toLowerCase().trim(); + const trackItems = tracklistContainer.querySelectorAll('.track-item'); + + trackItems.forEach((item) => { + const trackData = trackDataStore.get(item); + if (!trackData) { + item.style.display = ''; + return; + } + + const title = (trackData.title || '').toLowerCase(); + const artist = (trackData.artist?.name || trackData.artists?.[0]?.name || '').toLowerCase(); + const album = (trackData.album?.title || '').toLowerCase(); + + const matches = title.includes(query) || artist.includes(query) || album.includes(query); + item.style.display = matches ? '' : 'none'; + }); + }; + + searchInput._searchListener = listener; + searchInput.addEventListener('input', listener); + } + renderListWithTracks(container, tracks, showCover, append = false, useTrackNumber = false) { const fragment = document.createDocumentFragment(); const tempDiv = document.createElement('div'); @@ -2085,6 +2122,9 @@ export class UIRenderer { isUserPlaylist: true, }); document.title = `${playlistData.name || playlistData.title} - Monochrome`; + + // Setup playlist search + this.setupTracklistSearch(); } else { // If source was explicitly 'user' and we didn't find it, fail. if (source === 'user') { @@ -2154,6 +2194,9 @@ export class UIRenderer { recentActivityManager.addPlaylist(playlist); document.title = playlist.title || 'Artist Mix'; } + + // Setup playlist search + this.setupTracklistSearch(); } catch (error) { console.error('Failed to load playlist:', error); tracklistContainer.innerHTML = createPlaceholder(`Could not load playlist details. ${error.message}`); diff --git a/styles.css b/styles.css index 6620248..1501260 100644 --- a/styles.css +++ b/styles.css @@ -5515,3 +5515,31 @@ textarea:focus { min-width: 30px; } } + +/* Track List Search */ +.track-list-search-container { + margin: 1rem 0; +} + +.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); +}