diff --git a/index.html b/index.html index c2feb8b..43005d4 100644 --- a/index.html +++ b/index.html @@ -45,6 +45,7 @@
  • Go to artist
  • Go to album
  • Copy link
  • +
  • Open in new tab
  • Track info
  • Open original URL
  • Download
  • @@ -1164,6 +1165,19 @@ +
    +
    +
    + Show Editor's Picks + Display curated album selections on the home page +
    + +
    diff --git a/js/events.js b/js/events.js index 9d46e89..cbccdee 100644 --- a/js/events.js +++ b/js/events.js @@ -1067,6 +1067,15 @@ export async function handleTrackAction( navigator.clipboard.writeText(url).then(() => { showNotification('Link copied to clipboard!'); }); + } else if (action === 'open-in-new-tab') { + // Use stored href from card if available, otherwise construct URL + const contextMenu = document.getElementById('context-menu'); + const storedHref = contextMenu?._contextHref; + const url = storedHref + ? `${window.location.origin}${storedHref}` + : `${window.location.origin}/track/${item.id || item.uuid}`; + + window.open(url, '_blank'); } else if (action === 'track-info') { // Show detailed track info modal const isTracker = item.isTracker; diff --git a/js/settings.js b/js/settings.js index 7007a55..8f37ad2 100644 --- a/js/settings.js +++ b/js/settings.js @@ -919,6 +919,14 @@ export function initializeSettings(scrobbler, player, api, ui) { }); } + const showEditorsPicksToggle = document.getElementById('show-editors-picks-toggle'); + if (showEditorsPicksToggle) { + showEditorsPicksToggle.checked = homePageSettings.shouldShowEditorsPicks(); + showEditorsPicksToggle.addEventListener('change', (e) => { + homePageSettings.setShowEditorsPicks(e.target.checked); + }); + } + // Sidebar Section Toggles const sidebarShowHomeToggle = document.getElementById('sidebar-show-home-toggle'); if (sidebarShowHomeToggle) { diff --git a/js/storage.js b/js/storage.js index 22fd1e7..6c85fd8 100644 --- a/js/storage.js +++ b/js/storage.js @@ -969,6 +969,21 @@ export const homePageSettings = { setShowJumpBackIn(enabled) { localStorage.setItem(this.SHOW_JUMP_BACK_IN_KEY, enabled ? 'true' : 'false'); }, + + SHOW_EDITORS_PICKS_KEY: 'home-show-editors-picks', + + shouldShowEditorsPicks() { + try { + const val = localStorage.getItem(this.SHOW_EDITORS_PICKS_KEY); + return val === null ? true : val === 'true'; + } catch { + return true; + } + }, + + setShowEditorsPicks(enabled) { + localStorage.setItem(this.SHOW_EDITORS_PICKS_KEY, enabled ? 'true' : 'false'); + }, }; export const sidebarSectionSettings = { diff --git a/js/ui.js b/js/ui.js index 3759815..02134e1 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1414,6 +1414,7 @@ export class UIRenderer { this.renderHomeSongs(); this.renderHomeAlbums(); + this.renderHomeEditorsPicks(); this.renderHomeArtists(); this.renderHomeRecent(); } @@ -1518,6 +1519,63 @@ export class UIRenderer { } } + async renderHomeEditorsPicks(forceRefresh = false) { + const picksContainer = document.getElementById('home-editors-picks'); + const section = document.getElementById('home-editors-picks-section'); + + if (!homePageSettings.shouldShowEditorsPicks()) { + if (section) section.style.display = 'none'; + return; + } + + if (section) section.style.display = ''; + + if (picksContainer) { + if (forceRefresh) picksContainer.innerHTML = this.createSkeletonCards(6); + else if (picksContainer.children.length > 0 && !picksContainer.querySelector('.skeleton')) return; + + try { + const response = await fetch('/editors-picks.json'); + if (!response.ok) throw new Error("Failed to load editor's picks"); + + const data = await response.json(); + const albumIds = data.albums || []; + + if (albumIds.length === 0) { + picksContainer.innerHTML = createPlaceholder("No editor's picks available."); + return; + } + + // Fetch album details + const albums = []; + for (const albumId of albumIds.slice(0, 12)) { + try { + const result = await this.api.getAlbum(albumId); + if (result && result.album) albums.push(result.album); + } catch (e) { + console.warn(`Failed to load album ${albumId}:`, e); + } + } + + if (albums.length > 0) { + picksContainer.innerHTML = albums.map((a) => this.createAlbumCardHTML(a)).join(''); + albums.forEach((a) => { + const el = picksContainer.querySelector(`[data-album-id="${a.id}"]`); + if (el) { + trackDataStore.set(el, a); + this.updateLikeState(el, 'album', a.id); + } + }); + } else { + picksContainer.innerHTML = createPlaceholder("No editor's picks available."); + } + } catch (e) { + console.error("Failed to load editor's picks:", e); + picksContainer.innerHTML = createPlaceholder("Failed to load editor's picks."); + } + } + } + async renderHomeArtists(forceRefresh = false) { const artistsContainer = document.getElementById('home-recommended-artists'); const section = artistsContainer?.closest('.content-section'); diff --git a/public/editors-picks.json b/public/editors-picks.json new file mode 100644 index 0000000..1622ae3 --- /dev/null +++ b/public/editors-picks.json @@ -0,0 +1,5 @@ +{ + "name": "Editor's Picks", + "description": "Curated selection of standout albums handpicked by the monochrome team", + "albums": ["4527433", "90502209"] +} diff --git a/todo.md b/todo.md index 2a72170..97d3c92 100644 --- a/todo.md +++ b/todo.md @@ -2,8 +2,6 @@ Sorted by ease of implementation (easiest to hardest): -- [ ] Editor's Picks: Create a JSON file of curated album IDs with metadata for the home screen. Include an option to disable in settings to avoid extra API calls. - - [ ] Update notifications: Add ability to show the update popup in settings, with an option to automatically update (enabled by default) - [ ] Volume curve option: Add setting to switch between exponential and linear volume scaling - [ ] Custom fonts: Allow users to change fonts in settings or add custom fonts from Google Fonts or direct links