From 10f2e32ecddd156a9daca360aa4e3716ab1a7f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20Schl=C3=BCter?= Date: Tue, 16 Oct 2018 11:05:16 +0200 Subject: [PATCH] Add alphabetical artist overview (#26) --- .../airsonic_ui/components/artist/views.cljs | 48 ++++++++++++++++--- src/cljs/airsonic_ui/routes.cljs | 12 +++-- src/cljs/airsonic_ui/views.cljs | 4 +- src/cljs/airsonic_ui/views/breadcrumbs.cljs | 5 ++ src/sass/app.sass | 18 +++++++ 5 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/cljs/airsonic_ui/components/artist/views.cljs b/src/cljs/airsonic_ui/components/artist/views.cljs index 60a8391..1e7a228 100644 --- a/src/cljs/airsonic_ui/components/artist/views.cljs +++ b/src/cljs/airsonic_ui/components/artist/views.cljs @@ -1,5 +1,7 @@ (ns airsonic-ui.components.artist.views (:require [airsonic-ui.components.collection.views :as collection] + [airsonic-ui.routes :as routes] + [airsonic-ui.components.debug.views :refer [debug]] [clojure.string :as str])) (defn link-button [attrs children] @@ -19,6 +21,14 @@ (let [href (str "https://musicbrainz.org/artist/" (:musicBrainzId artist-info))] [link-button {:href href} "See on musicbrainz"])) +(defn artist-links [artist-info] + (when-not (empty? (select-keys artist-info [:lastFmUrl :musicBrainzId])) + [:div.field.is-grouped + (when (:lastFmUrl artist-info) + [lastfm-link artist-info]) + (when (:musicBrainzId artist-info) + [musicbrainz-link artist-info])])) + (defn detail "Creates a nice artist page displaying the artist's name, bio (if available and listing) their albums." @@ -26,13 +36,37 @@ [:div [:section.hero>div.hero-body [:div.container - [:h2.title (:name artist)] + [:h1.title (:name artist)] [:div.content [lastfm-bio artist-info] - (when-not (empty? (select-keys artist-info [:lastFmUrl :musicBrainzId])) - [:div.field.is-grouped - (when (:lastFmUrl artist-info) - [lastfm-link artist-info]) - (when (:musicBrainzId artist-info) - [musicbrainz-link artist-info])])]]] + [artist-links artist-info]]]] [:section.section>div.container [collection/listing (:album artist)]]]) + +(defn alphabetical-listing + [artists] + [:div.alphabetical-list + (for [group artists] + ^{:key (:name group)} + [:div.group + [:h1.subtitle.is-4 (:name group)] + [:ol.artist-links + (for [artist (:artist group)] + (let [href (routes/url-for ::routes/artist.detail (select-keys artist [:id]))] + ^{:key (:id artist)} [:li [:a {:href href} (:name artist)]]))]])]) + +(defn overview + "Displays the alphabetical listing of all artists along with some additional + information about the collection" + [{:keys [artists]}] + (let [artists (:index artists) + ;; TODO: Calculations in views should be avoided + artists-count (count (mapcat :artist artists)) + album-count (->> (mapcat :artist artists) + (map :albumCount) + (reduce +))] + [:div + [:section.hero.is-small>div.hero-body + [:div.container + [:h1.title "Artists"] + [:p.subtitle.is-5.has-text-grey [:strong artists-count] " artists in your collection with " [:strong album-count] " albums"]]] + [:section.section>div.container [alphabetical-listing artists]]])) \ No newline at end of file diff --git a/src/cljs/airsonic_ui/routes.cljs b/src/cljs/airsonic_ui/routes.cljs index 9f8a94d..fcb2ed1 100644 --- a/src/cljs/airsonic_ui/routes.cljs +++ b/src/cljs/airsonic_ui/routes.cljs @@ -9,7 +9,8 @@ (r/router [["/" ::login] ["/library" ::library] ["/library/:criteria" ::library] - ["/artist/:id" ::artist.detail] + ["/artists" ::artist.overview] + ["/artists/:id" ::artist.detail] ["/album/:id" ::album.detail] ["/search" ::search] ["/podcast" ::podcast.overview] @@ -24,8 +25,9 @@ ([k params query] (str "#" (r/resolve router k params query)))) ;; which routes need valid login credentials? -(def protected-routes #{::library ::artist.detail ::album.detail ::search - ::podcast.overview ::podcast.detail}) +(def protected-routes + #{::library ::artist.overview ::artist.detail ::album.detail ::search + ::podcast.overview ::podcast.detail}) ;; which data should be requested for which route? can either be a vector or a function returning a vector @@ -46,6 +48,10 @@ [:api/request "getAlbumList2" {:type criteria, :size 20, :offset (* 20 (dec page))}]] [:routes/do-navigation [route-id {:criteria "recent"} {:page 1}]])) +(defmethod -route-events ::artist.overview + [route-id params query] + [:api/request "getArtists"]) + (defmethod -route-events ::artist.detail [route-id params query] (let [params (select-keys params [:id])] diff --git a/src/cljs/airsonic_ui/views.cljs b/src/cljs/airsonic_ui/views.cljs index 2ee6902..4693854 100644 --- a/src/cljs/airsonic_ui/views.cljs +++ b/src/cljs/airsonic_ui/views.cljs @@ -73,7 +73,8 @@ [navbar-dropdown "Library" [[{:href (url-for ::routes/library {:criteria "recent"})} "Recently played"] [{:href (url-for ::routes/library {:criteria "newest"})} "Newest additions"] - [{:href (url-for ::routes/library {:criteria "starred"})} "Starred"]]]) + [{:href (url-for ::routes/library {:criteria "starred"})} "Starred"] + [{:href (url-for ::routes/artist.overview)} "By artist"]]]) (when podcast-role #_(let [podcast-url (url-for ::routes/podcast.overview)] [navbar-dropdown "Podcast" {:href podcast-url} @@ -111,6 +112,7 @@ [breadcrumbs route content] (case route-id ::routes/library [library/main route content] + ::routes/artist.overview [artist/overview content] ::routes/artist.detail [artist/detail content] ::routes/album.detail [collection/detail content] ::routes/search [search/results content] diff --git a/src/cljs/airsonic_ui/views/breadcrumbs.cljs b/src/cljs/airsonic_ui/views/breadcrumbs.cljs index 1ecb5aa..164a960 100644 --- a/src/cljs/airsonic_ui/views/breadcrumbs.cljs +++ b/src/cljs/airsonic_ui/views/breadcrumbs.cljs @@ -20,12 +20,17 @@ (def start [(url-for ::routes/library) "Start"]) +(defmethod breadcrumbs ::routes/artist.overview [_ _] + [bulma-breadcrumbs start "Artists"]) + (defmethod breadcrumbs ::routes/artist.detail [_ {:keys [artist]}] [bulma-breadcrumbs start + [(url-for ::routes/artist.overview) "Artists"] (:name artist)]) (defmethod breadcrumbs ::routes/album.detail [_ {:keys [album]}] [bulma-breadcrumbs start + [(url-for ::routes/artist.overview) "Artists"] [(url-for ::routes/artist.detail {:id (:artistId album)}) (:artist album)] (:name album)]) diff --git a/src/sass/app.sass b/src/sass/app.sass index 0aa69a2..5c54d57 100644 --- a/src/sass/app.sass +++ b/src/sass/app.sass @@ -192,6 +192,24 @@ .missing-cover display: inline-block +.artist.overview + .alphabetical-list + column-count: 2 + column-gap: 1.2rem + + ol + list-style: none + + +tablet + column-count: 3 + +widescreen + column-count: 4 + + .group + margin-bottom: 1.5rem + .subtitle.is-4 + margin-bottom: 1rem + .album.detail .collection-info list-style: none