diff --git a/index.html b/index.html index 73a4e61..decc656 100644 --- a/index.html +++ b/index.html @@ -232,6 +232,10 @@ +
+ + +
@@ -265,6 +269,10 @@ +
+ + +
diff --git a/src/main.js b/src/main.js index 26db326..7716599 100644 --- a/src/main.js +++ b/src/main.js @@ -15,7 +15,7 @@ import { navigate, _navGoBack, _navLoad, onLocalSearch, onMobileSearch, onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum, searchSimilarArtist, searchAndPreview, loadItunesAlbum, expandArtistBio, - loadAlbums, loadStarred, loadRandom, + loadAlbums, loadStarred, loadRandom, filterStarred, filterPlaylist, } from './views.js'; import { loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll } from './spotify.js'; import { @@ -282,7 +282,7 @@ Object.assign(window, { openSettings, closeSettings, saveSettings, confirmDisconnect, checkBackend, openSidebar, closeSidebar, switchNavMode, showCtxMenu, // Views - loadAlbums, loadStarred, loadRandom, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll, + loadAlbums, loadStarred, loadRandom, filterStarred, filterPlaylist, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll, executeSpotifyDownload, openPlModal, closePlModal, addSongsToPlaylist, createAndAddPlaylist, createPlaylistPrompt, showSongInfo, closeInfoModal, diff --git a/src/views.js b/src/views.js index 740c799..75b54f4 100644 --- a/src/views.js +++ b/src/views.js @@ -557,11 +557,22 @@ export async function loadPlaylistDetail(pl) { }; sl.innerHTML = ''; sl.classList.add('pl-draggable'); + const plSearch = document.getElementById('playlist-search'); + if (plSearch) plSearch.value = ''; songs.forEach((s,i) => sl.appendChild(makeSongItem(s, i, songs, { noArtistLink: true, noAlbumLink: true }))); _initPlaylistDragDrop(sl, songs, S._currentPlaylist); } catch(e) { sl.innerHTML = `

${e.message}

`; } } +export function filterPlaylist(val) { + const q = val.trim().toLowerCase(); + document.querySelectorAll('#playlist-songs .song-item').forEach(item => { + const title = (item.querySelector('.song-title')?.textContent || '').toLowerCase(); + const artist = (item.querySelector('.song-artist')?.textContent || '').toLowerCase(); + item.style.display = (!q || title.includes(q) || artist.includes(q)) ? '' : 'none'; + }); +} + function _initPlaylistDragDrop(container, songs, pl) { let dragSrc = null; let saveTimer = null; @@ -645,6 +656,8 @@ export async function loadStarred(sort = _starredSort) { c.classList.toggle('active', c.dataset.sort === sort)); const el = document.getElementById('starred-songs'); el.innerHTML = '
'; + const searchEl = document.getElementById('starred-search'); + if (searchEl) searchEl.value = ''; try { const r = await api('getStarred2'); let songs = (r.starred2?.song || []).map(s => ({...s, _starred: true})); @@ -659,6 +672,15 @@ export async function loadStarred(sort = _starredSort) { } catch(e) { el.innerHTML = `

${e.message}

`; } } +export function filterStarred(val) { + const q = val.trim().toLowerCase(); + document.querySelectorAll('#starred-songs .song-item').forEach(item => { + const title = (item.querySelector('.song-title')?.textContent || '').toLowerCase(); + const artist = (item.querySelector('.song-artist')?.textContent || '').toLowerCase(); + item.style.display = (!q || title.includes(q) || artist.includes(q)) ? '' : 'none'; + }); +} + export async function loadRandom() { const el = document.getElementById('random-songs'); el.innerHTML = '
'; diff --git a/styles.css b/styles.css index 0b61d0f..69ee737 100644 --- a/styles.css +++ b/styles.css @@ -718,6 +718,11 @@ nav{flex:1;overflow-y:auto;padding:4px 10px} .sort-chip{padding:6px 14px;background:var(--surface);border:1px solid var(--border2);border-radius:20px;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;color:var(--text2);font-family:var(--font);transition:border-color .15s,color .15s,background .15s} .sort-chip:hover{border-color:var(--accent);color:var(--accent)} .sort-chip.active{background:var(--accent);border-color:var(--accent);color:#000} +.list-search-wrap{position:relative;margin-bottom:12px} +.list-search-wrap svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text3);pointer-events:none} +.list-search{width:100%;box-sizing:border-box;padding:8px 12px 8px 32px;background:var(--surface);border:1px solid var(--border2);border-radius:8px;color:var(--text1);font-size:13px;font-family:var(--font);outline:none;transition:border-color .15s} +.list-search:focus{border-color:var(--accent)} +.list-search::placeholder{color:var(--text3)} .topsong-item{display:grid;grid-template-columns:28px 44px 1fr auto;align-items:center;gap:10px;padding:7px 10px;border-radius:8px;cursor:pointer;transition:background .15s} .topsong-item:hover{background:var(--surface)} .topsong-num{font-size:11px;color:var(--text3);font-family:var(--mono);text-align:center}