feat: add sort filter chips to albums and favorites views
This commit is contained in:
1 parent
751cc05b89
commit
47f1605965
4 files changed
+40
-6
No files matched your search
+14
@@ -193,6 +193,13 @@
|
|||||||
<!-- ALBUMS -->
|
<!-- ALBUMS -->
|
||||||
<div class="page" id="page-albums">
|
<div class="page" id="page-albums">
|
||||||
<div class="page-header"><div class="page-title">Alben</div></div>
|
<div class="page-header"><div class="page-title">Alben</div></div>
|
||||||
|
<div id="albums-sort-chips" class="sort-chips">
|
||||||
|
<button class="sort-chip active" data-sort="alphabeticalByName" onclick="loadAlbums('alphabeticalByName')">A–Z</button>
|
||||||
|
<button class="sort-chip" data-sort="alphabeticalByArtist" onclick="loadAlbums('alphabeticalByArtist')">Künstler</button>
|
||||||
|
<button class="sort-chip" data-sort="newest" onclick="loadAlbums('newest')">Neueste</button>
|
||||||
|
<button class="sort-chip" data-sort="recent" onclick="loadAlbums('recent')">Zuletzt gespielt</button>
|
||||||
|
<button class="sort-chip" data-sort="frequent" onclick="loadAlbums('frequent')">Meistgespielt</button>
|
||||||
|
</div>
|
||||||
<div id="albums-grid" class="grid grid-4"></div>
|
<div id="albums-grid" class="grid grid-4"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -218,6 +225,13 @@
|
|||||||
<!-- STARRED -->
|
<!-- STARRED -->
|
||||||
<div class="page" id="page-starred">
|
<div class="page" id="page-starred">
|
||||||
<div class="page-header"><div class="page-title">Favoriten ⭐</div></div>
|
<div class="page-header"><div class="page-title">Favoriten ⭐</div></div>
|
||||||
|
<div id="starred-sort-chips" class="sort-chips">
|
||||||
|
<button class="sort-chip active" data-sort="newest" onclick="loadStarred('newest')">Neueste</button>
|
||||||
|
<button class="sort-chip" data-sort="oldest" onclick="loadStarred('oldest')">Älteste</button>
|
||||||
|
<button class="sort-chip" data-sort="az" onclick="loadStarred('az')">A–Z</button>
|
||||||
|
<button class="sort-chip" data-sort="artist" onclick="loadStarred('artist')">Künstler</button>
|
||||||
|
<button class="sort-chip" data-sort="plays" onclick="loadStarred('plays')">Meistgespielt</button>
|
||||||
|
</div>
|
||||||
<div id="starred-songs" class="song-list"></div>
|
<div id="starred-songs" class="song-list"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ import {
|
|||||||
navigate, _navGoBack, _navLoad, onLocalSearch, onMobileSearch,
|
navigate, _navGoBack, _navLoad, onLocalSearch, onMobileSearch,
|
||||||
onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum,
|
onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum,
|
||||||
searchSimilarArtist, searchAndPreview, loadItunesAlbum, expandArtistBio,
|
searchSimilarArtist, searchAndPreview, loadItunesAlbum, expandArtistBio,
|
||||||
loadRandom,
|
loadAlbums, loadStarred, loadRandom,
|
||||||
} from './views.js';
|
} from './views.js';
|
||||||
import { loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll } from './spotify.js';
|
import { loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll } from './spotify.js';
|
||||||
import {
|
import {
|
||||||
@@ -282,7 +282,7 @@ Object.assign(window, {
|
|||||||
openSettings, closeSettings, saveSettings, confirmDisconnect, checkBackend,
|
openSettings, closeSettings, saveSettings, confirmDisconnect, checkBackend,
|
||||||
openSidebar, closeSidebar, switchNavMode, showCtxMenu,
|
openSidebar, closeSidebar, switchNavMode, showCtxMenu,
|
||||||
// Views
|
// Views
|
||||||
loadRandom, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll,
|
loadAlbums, loadStarred, loadRandom, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll,
|
||||||
executeSpotifyDownload,
|
executeSpotifyDownload,
|
||||||
openPlModal, closePlModal, addSongsToPlaylist, createAndAddPlaylist, createPlaylistPrompt,
|
openPlModal, closePlModal, addSongsToPlaylist, createAndAddPlaylist, createPlaylistPrompt,
|
||||||
showSongInfo, closeInfoModal,
|
showSongInfo, closeInfoModal,
|
||||||
|
|||||||
+19
-4
@@ -154,11 +154,16 @@ export async function loadArtists() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── ALBUMS ───
|
// ─── ALBUMS ───
|
||||||
export async function loadAlbums() {
|
let _albumSort = 'alphabeticalByName';
|
||||||
|
|
||||||
|
export async function loadAlbums(type = _albumSort) {
|
||||||
|
_albumSort = type;
|
||||||
|
document.querySelectorAll('#albums-sort-chips .sort-chip').forEach(c =>
|
||||||
|
c.classList.toggle('active', c.dataset.sort === type));
|
||||||
const g = document.getElementById('albums-grid');
|
const g = document.getElementById('albums-grid');
|
||||||
g.innerHTML = '<div class="spinner"></div>';
|
g.innerHTML = '<div class="spinner"></div>';
|
||||||
try {
|
try {
|
||||||
const r = await api('getAlbumList2', '&type=alphabeticalByName&size=500');
|
const r = await api('getAlbumList2', `&type=${type}&size=500`);
|
||||||
g.innerHTML = '';
|
g.innerHTML = '';
|
||||||
(r.albumList2?.album || []).forEach(a => g.appendChild(makeAlbumCard(a)));
|
(r.albumList2?.album || []).forEach(a => g.appendChild(makeAlbumCard(a)));
|
||||||
} catch(e) { g.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; }
|
} catch(e) { g.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; }
|
||||||
@@ -632,12 +637,22 @@ export async function quickPlayAlbum(a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── STARRED / RANDOM ───
|
// ─── STARRED / RANDOM ───
|
||||||
export async function loadStarred() {
|
let _starredSort = 'newest';
|
||||||
|
|
||||||
|
export async function loadStarred(sort = _starredSort) {
|
||||||
|
_starredSort = sort;
|
||||||
|
document.querySelectorAll('#starred-sort-chips .sort-chip').forEach(c =>
|
||||||
|
c.classList.toggle('active', c.dataset.sort === sort));
|
||||||
const el = document.getElementById('starred-songs');
|
const el = document.getElementById('starred-songs');
|
||||||
el.innerHTML = '<div class="spinner"></div>';
|
el.innerHTML = '<div class="spinner"></div>';
|
||||||
try {
|
try {
|
||||||
const r = await api('getStarred2');
|
const r = await api('getStarred2');
|
||||||
const songs = (r.starred2?.song || []).map(s => ({...s,_starred:true}));
|
let songs = (r.starred2?.song || []).map(s => ({...s, _starred: true}));
|
||||||
|
if (sort === 'newest') songs.sort((a, b) => new Date(b.starred||0) - new Date(a.starred||0));
|
||||||
|
else if (sort === 'oldest') songs.sort((a, b) => new Date(a.starred||0) - new Date(b.starred||0));
|
||||||
|
else if (sort === 'az') songs.sort((a, b) => (a.title||'').localeCompare(b.title||''));
|
||||||
|
else if (sort === 'artist') songs.sort((a, b) => (a.artist||'').localeCompare(b.artist||''));
|
||||||
|
else if (sort === 'plays') songs.sort((a, b) => (b.playCount||0) - (a.playCount||0));
|
||||||
el.innerHTML = '';
|
el.innerHTML = '';
|
||||||
if(!songs.length) { el.innerHTML = '<div class="empty-state"><div class="icon">⭐</div><p>Noch keine Favoriten</p></div>'; return; }
|
if(!songs.length) { el.innerHTML = '<div class="empty-state"><div class="icon">⭐</div><p>Noch keine Favoriten</p></div>'; return; }
|
||||||
songs.forEach((s,i) => el.appendChild(makeSongItem(s, i, songs)));
|
songs.forEach((s,i) => el.appendChild(makeSongItem(s, i, songs)));
|
||||||
|
|||||||
@@ -713,6 +713,11 @@ nav{flex:1;overflow-y:auto;padding:4px 10px}
|
|||||||
.similar-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:24px}
|
.similar-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:24px}
|
||||||
.similar-chip{padding:6px 12px;background:var(--surface);border:1px solid var(--border2);border-radius:20px;font-size:12px;font-weight:600;cursor:pointer;transition:border-color .15s,color .15s}
|
.similar-chip{padding:6px 12px;background:var(--surface);border:1px solid var(--border2);border-radius:20px;font-size:12px;font-weight:600;cursor:pointer;transition:border-color .15s,color .15s}
|
||||||
.similar-chip:hover{border-color:var(--accent);color:var(--accent)}
|
.similar-chip:hover{border-color:var(--accent);color:var(--accent)}
|
||||||
|
.sort-chips{display:flex;flex-wrap:nowrap;gap:6px;margin-bottom:16px;overflow-x:auto;padding-bottom:4px;-webkit-overflow-scrolling:touch;scrollbar-width:none}
|
||||||
|
.sort-chips::-webkit-scrollbar{display:none}
|
||||||
|
.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}
|
||||||
.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{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-item:hover{background:var(--surface)}
|
||||||
.topsong-num{font-size:11px;color:var(--text3);font-family:var(--mono);text-align:center}
|
.topsong-num{font-size:11px;color:var(--text3);font-family:var(--mono);text-align:center}
|
||||||
|
|||||||
Reference in new issue
Block a user