Loading frontend/SongList.mjs +28 −67 Changes for frontend/SongList.mjs: 28 added lines, 67 removed lines. Original line number Diff line number Diff line // frontend/SongList.mjs import ArtistGroup from "./components/pieces/ArtistGroup.mjs" import Message from "./components/pieces/Message.mjs" import ClearSearchLink from "./components/pieces/ClearSearchLink.mjs" import SongItem from "./components/pieces/SongItem.mjs" import PaginationControls from "./components/pieces/PaginationControls.mjs" import SongListModel from "./SongListModel.mjs" Loading Loading @@ -32,99 +35,57 @@ const SongList = { } = model.getProcessedSongsForView(currentView, searchTerm) const artistsOnPage = Object.keys(groupedSongs) let messageElement = null // Hilfsfunktion für den "Suche zurücksetzen"-Link const createClearSearchLink = totalFavs => { return m( "a.clear-search-link", { onclick: e => { e.preventDefault() if (onSearchTermChange) onSearchTermChange("") }, href: "#", role: "button", tabindex: 0, onkeypress: e => { if ( (e.key === "Enter" || e.key === " ") && onSearchTermChange ) { e.preventDefault() onSearchTermChange("") } }, }, `alle ${totalFavs} Favoriten anzeigen`, ) } // Nachrichten-Rendering basierend auf dem `message`-Objekt oder String // Message rendering let messageElement = null if (message && typeof message === "object") { if (message.type === "filtered_favorites_some_hidden") { messageElement = m("p.view-message", [ messageElement = m(Message, [ `Deine Suche zeigt ${message.showing} von deinen insgesamt ${message.total} Favoriten. `, `Möchtest du `, createClearSearchLink(message.total), m(ClearSearchLink, { totalFavs: message.total, onClear: () => onSearchTermChange && onSearchTermChange("") }), `?`, ]) } else if ( message.type === "filtered_favorites_none_found_by_search" ) { messageElement = m("p.view-message", [ } else if (message.type === "filtered_favorites_none_found_by_search") { messageElement = m(Message, [ `Deine Suche ergab keine Treffer unter deinen ${message.total} Favoriten. `, `Möchtest du `, createClearSearchLink(message.total), m(ClearSearchLink, { totalFavs: message.total, onClear: () => onSearchTermChange && onSearchTermChange("") }), `?`, ]) } // Hier könnten weitere Objekt-Nachrichtentypen behandelt werden } else if (message && typeof message === "string") { // String-Nachrichten werden angezeigt, wenn totalFilteredItems 0 ist // ODER wenn es eine spezifische Ansicht wie 'popular' ist, die immer eine Nachricht hat. if (totalFilteredItems === 0 || currentView === "popular") { messageElement = m("p.view-message", message) messageElement = m(Message, message) } } // Fallback-Nachricht, wenn keine spezifische Nachricht erstellt wurde, // aber absolut keine Items vorhanden sind (über alle Seiten). // Dies sollte durch getProcessedSongsForView abgedeckt sein, ist aber ein Sicherheitsnetz. if (!messageElement && totalFilteredItems === 0 && !model.isLoading) { messageElement = m( "p.view-message", "Keine Songs entsprechen den aktuellen Kriterien.", ) messageElement = m(Message, "Keine Songs entsprechen den aktuellen Kriterien.") } const elementsToRender = [] if (messageElement) { // Wenn eine Nachricht zum Anzeigen vorhanden ist elementsToRender.push(messageElement) } if (hasContentOnPage) { elementsToRender.push( artistsOnPage.map(artist => m( "div.artist-group", { key: `${currentView}-${searchTerm || "all"}-${artist}-${currentPage}`, }, [ m("h2.artist-name", artist), groupedSongs[artist].map(s => m(SongItem, { key: s.id, song: s, onToggleFavorite: model.toggleFavorite.bind(model), }), ), ], ), ), m(ArtistGroup, { artist, songs: groupedSongs[artist], currentView, searchTerm, currentPage, onToggleFavorite: model.toggleFavorite.bind(model), }) ) ) } Loading @@ -134,7 +95,7 @@ const SongList = { currentPage: currentPage, totalPages: totalPages, onPageChange: model.onPageChange.bind(model), }), }) ) } Loading frontend/components/pieces/ArtistGroup.mjs 0 → 100644 +25 −0 Changes for frontend/components/pieces/ArtistGroup.mjs: 25 added lines, 0 removed lines. Original line number Diff line number Diff line import SongItem from "./SongItem.mjs" const ArtistGroup = { view: function(vnode) { const { artist, songs, currentView, searchTerm, currentPage, onToggleFavorite } = vnode.attrs return m( "div.artist-group", { key: `${currentView}-${searchTerm || "all"}-${artist}-${currentPage}`, }, [ m("h2.artist-name", artist), songs.map(s => m(SongItem, { key: s.id, song: s, onToggleFavorite, }) ), ] ) }, } export default ArtistGroup No newline at end of file frontend/components/pieces/ClearSearchLink.mjs 0 → 100644 +26 −0 Changes for frontend/components/pieces/ClearSearchLink.mjs: 26 added lines, 0 removed lines. Original line number Diff line number Diff line const ClearSearchLink = { view: function(vnode) { const { totalFavs, onClear } = vnode.attrs return m( "a.clear-search-link", { onclick: e => { e.preventDefault() if (onClear) onClear() }, href: "#", role: "button", tabindex: 0, onkeypress: e => { if ((e.key === "Enter" || e.key === " ") && onClear) { e.preventDefault() onClear() } }, }, `alle ${totalFavs} Favoriten anzeigen`, ) }, } export default ClearSearchLink No newline at end of file frontend/components/pieces/Message.mjs 0 → 100644 +7 −0 Changes for frontend/components/pieces/Message.mjs: 7 added lines, 0 removed lines. Original line number Diff line number Diff line const Message = { view: function(vnode) { return m("p.view-message", vnode.children) }, } export default Message No newline at end of file Loading
frontend/SongList.mjs +28 −67 Changes for frontend/SongList.mjs: 28 added lines, 67 removed lines. Original line number Diff line number Diff line // frontend/SongList.mjs import ArtistGroup from "./components/pieces/ArtistGroup.mjs" import Message from "./components/pieces/Message.mjs" import ClearSearchLink from "./components/pieces/ClearSearchLink.mjs" import SongItem from "./components/pieces/SongItem.mjs" import PaginationControls from "./components/pieces/PaginationControls.mjs" import SongListModel from "./SongListModel.mjs" Loading Loading @@ -32,99 +35,57 @@ const SongList = { } = model.getProcessedSongsForView(currentView, searchTerm) const artistsOnPage = Object.keys(groupedSongs) let messageElement = null // Hilfsfunktion für den "Suche zurücksetzen"-Link const createClearSearchLink = totalFavs => { return m( "a.clear-search-link", { onclick: e => { e.preventDefault() if (onSearchTermChange) onSearchTermChange("") }, href: "#", role: "button", tabindex: 0, onkeypress: e => { if ( (e.key === "Enter" || e.key === " ") && onSearchTermChange ) { e.preventDefault() onSearchTermChange("") } }, }, `alle ${totalFavs} Favoriten anzeigen`, ) } // Nachrichten-Rendering basierend auf dem `message`-Objekt oder String // Message rendering let messageElement = null if (message && typeof message === "object") { if (message.type === "filtered_favorites_some_hidden") { messageElement = m("p.view-message", [ messageElement = m(Message, [ `Deine Suche zeigt ${message.showing} von deinen insgesamt ${message.total} Favoriten. `, `Möchtest du `, createClearSearchLink(message.total), m(ClearSearchLink, { totalFavs: message.total, onClear: () => onSearchTermChange && onSearchTermChange("") }), `?`, ]) } else if ( message.type === "filtered_favorites_none_found_by_search" ) { messageElement = m("p.view-message", [ } else if (message.type === "filtered_favorites_none_found_by_search") { messageElement = m(Message, [ `Deine Suche ergab keine Treffer unter deinen ${message.total} Favoriten. `, `Möchtest du `, createClearSearchLink(message.total), m(ClearSearchLink, { totalFavs: message.total, onClear: () => onSearchTermChange && onSearchTermChange("") }), `?`, ]) } // Hier könnten weitere Objekt-Nachrichtentypen behandelt werden } else if (message && typeof message === "string") { // String-Nachrichten werden angezeigt, wenn totalFilteredItems 0 ist // ODER wenn es eine spezifische Ansicht wie 'popular' ist, die immer eine Nachricht hat. if (totalFilteredItems === 0 || currentView === "popular") { messageElement = m("p.view-message", message) messageElement = m(Message, message) } } // Fallback-Nachricht, wenn keine spezifische Nachricht erstellt wurde, // aber absolut keine Items vorhanden sind (über alle Seiten). // Dies sollte durch getProcessedSongsForView abgedeckt sein, ist aber ein Sicherheitsnetz. if (!messageElement && totalFilteredItems === 0 && !model.isLoading) { messageElement = m( "p.view-message", "Keine Songs entsprechen den aktuellen Kriterien.", ) messageElement = m(Message, "Keine Songs entsprechen den aktuellen Kriterien.") } const elementsToRender = [] if (messageElement) { // Wenn eine Nachricht zum Anzeigen vorhanden ist elementsToRender.push(messageElement) } if (hasContentOnPage) { elementsToRender.push( artistsOnPage.map(artist => m( "div.artist-group", { key: `${currentView}-${searchTerm || "all"}-${artist}-${currentPage}`, }, [ m("h2.artist-name", artist), groupedSongs[artist].map(s => m(SongItem, { key: s.id, song: s, onToggleFavorite: model.toggleFavorite.bind(model), }), ), ], ), ), m(ArtistGroup, { artist, songs: groupedSongs[artist], currentView, searchTerm, currentPage, onToggleFavorite: model.toggleFavorite.bind(model), }) ) ) } Loading @@ -134,7 +95,7 @@ const SongList = { currentPage: currentPage, totalPages: totalPages, onPageChange: model.onPageChange.bind(model), }), }) ) } Loading
frontend/components/pieces/ArtistGroup.mjs 0 → 100644 +25 −0 Changes for frontend/components/pieces/ArtistGroup.mjs: 25 added lines, 0 removed lines. Original line number Diff line number Diff line import SongItem from "./SongItem.mjs" const ArtistGroup = { view: function(vnode) { const { artist, songs, currentView, searchTerm, currentPage, onToggleFavorite } = vnode.attrs return m( "div.artist-group", { key: `${currentView}-${searchTerm || "all"}-${artist}-${currentPage}`, }, [ m("h2.artist-name", artist), songs.map(s => m(SongItem, { key: s.id, song: s, onToggleFavorite, }) ), ] ) }, } export default ArtistGroup No newline at end of file
frontend/components/pieces/ClearSearchLink.mjs 0 → 100644 +26 −0 Changes for frontend/components/pieces/ClearSearchLink.mjs: 26 added lines, 0 removed lines. Original line number Diff line number Diff line const ClearSearchLink = { view: function(vnode) { const { totalFavs, onClear } = vnode.attrs return m( "a.clear-search-link", { onclick: e => { e.preventDefault() if (onClear) onClear() }, href: "#", role: "button", tabindex: 0, onkeypress: e => { if ((e.key === "Enter" || e.key === " ") && onClear) { e.preventDefault() onClear() } }, }, `alle ${totalFavs} Favoriten anzeigen`, ) }, } export default ClearSearchLink No newline at end of file
frontend/components/pieces/Message.mjs 0 → 100644 +7 −0 Changes for frontend/components/pieces/Message.mjs: 7 added lines, 0 removed lines. Original line number Diff line number Diff line const Message = { view: function(vnode) { return m("p.view-message", vnode.children) }, } export default Message No newline at end of file