Merge pull request #154 from blacksigkill/feature/playlist-search

add a search bar in playlists to quickly find titles
This commit is contained in:
Eduard Prigoana 2026-02-05 15:54:41 +02:00 committed by GitHub
commit 31c9890db8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 0 deletions

View file

@ -1642,6 +1642,14 @@
</div>
</div>
</header>
<div class="track-list-search-container">
<input
type="text"
id="track-list-search-input"
placeholder="Search tracks..."
class="track-list-search-input"
/>
</div>
<div id="playlist-detail-tracklist" class="track-list"></div>
<section

View file

@ -539,6 +539,43 @@ export class UIRenderer {
.join('')}</div>`;
}
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}`);

View file

@ -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);
}