diff --git a/src/cljs/airsonic_ui/components/library/views.cljs b/src/cljs/airsonic_ui/components/library/views.cljs index 80be183..b969824 100644 --- a/src/cljs/airsonic_ui/components/library/views.cljs +++ b/src/cljs/airsonic_ui/components/library/views.cljs @@ -1,26 +1,59 @@ (ns airsonic-ui.components.library.views (:require [airsonic-ui.routes :as routes :refer [url-for]] - [airsonic-ui.views.album :as album])) + [airsonic-ui.views.album :as album] + [airsonic-ui.helpers :refer [add-classes]])) -(defn tabs [items active-item] +(defn tabs [{:keys [items active-item]}] [:div.tabs [:ul (for [[idx [route label]] (map-indexed vector items)] - (do - (println route label active-item) - ^{:key idx} [:li (when (= route active-item) + (let [[_ params _] route] + ^{:key idx} [:li (when (= params active-item) {:class-name "is-active"}) [:a {:href (apply url-for route)} label]]))]]) +(defn pagination + "Builds a pagination, calling `url-fn` for every rendered page link with the + page as its argument. When `max-pages` is `nil` an infinite pagination + will be rendered." + [{:keys [url-fn max-pages current-page]}] + [:nav.pagination.is-centered {:role "pagination", :aria-label "pagination"} + [:a.pagination-previous (if (> current-page 1) + {:href (url-fn (dec current-page))} + {:disabled true}) "Previous page"] + [:a.pagination-next (if (= max-pages current-page) + {:disabled true} + {:href (url-fn (inc current-page))}) "Next page"] + [:ul.pagination-list + (when (> current-page 3) + ^{:key "ellipsis-before"} [:li>span.pagination-ellipsis "…"]) + (for [page (range (max 1 (- current-page 2)) + (if max-pages + (min (+ current-page 3) (inc max-pages)) + (+ current-page 3)))] + (let [current-page? (= page current-page)] + ^{:key page} [(cond-> :li>a.pagination-link + current-page? (add-classes :is-current)) + (cond-> {:href (url-fn page), :aria-label (str "Page " page)} + (= page current-page) (assoc :aria-current "page")) page])) + (when (or (not max-pages) (< max-pages (- max-pages 3))) + ^{:key "ellipsis-after"} [:li>span.pagination-ellipsis "…"])]]) + (defn main [route {:keys [scan-status album-list]}] - (println scan-status "status") - [:div - [:h2.title "Your library"] - (if (:count scan-status) - [:p.subtitle.is-5.has-text-grey "Containing " [:strong (:count scan-status)] " items"] - (when (:scanning scan-status) - [:p.subtitle.is-5.has-text-grey "Scanning…"])) - (let [items [[[::routes/library {:criteria "recent"} nil] "Recently played"] - [[::routes/library {:criteria "newest"} nil] "Newest additions"] - [[::routes/library {:criteria "starred"} nil] "Starred"]]] - [tabs items route]) - [album/listing (:album album-list)]]) + (let [[_ {:keys [criteria]} {:keys [page] :or {page 1}}] route + pagination [pagination {:current-page (int page) + :max-pages 5 + :url-fn #(url-for ::routes/library {:criteria criteria} {:page %})}]] + [:div + [:h2.title "Your library"] + (if (:count scan-status) + [:p.subtitle.is-5.has-text-grey "Containing " [:strong (:count scan-status)] " items"] + (when (:scanning scan-status) + [:p.subtitle.is-5.has-text-grey "Scanning…"])) + (let [items [[[::routes/library {:criteria "recent"} nil] "Recently played"] + [[::routes/library {:criteria "newest"} nil] "Newest additions"] + [[::routes/library {:criteria "starred"} nil] "Starred"]]] + [tabs {:items items :active-item {:criteria criteria}}]) + pagination + [:section.section + [album/listing (:album album-list)]] + pagination])) diff --git a/src/cljs/airsonic_ui/routes.cljs b/src/cljs/airsonic_ui/routes.cljs index 61cb69d..d22f088 100644 --- a/src/cljs/airsonic_ui/routes.cljs +++ b/src/cljs/airsonic_ui/routes.cljs @@ -31,11 +31,11 @@ (defmethod -route-events :default [route-id params query] nil) (defmethod -route-events ::library - [route-id {:keys [criteria]} query] + [route-id {:keys [criteria]} {:keys [page]}] (if criteria [[:api/request "getScanStatus"] - [:api/request "getAlbumList2" {:type criteria, :size 20}]] - [:routes/do-navigation [route-id {:criteria "recent"} query]])) + [:api/request "getAlbumList2" {:type criteria, :size 20, :offset (* 20 (dec page))}]] + [:routes/do-navigation [route-id {:criteria "recent"} {:page 1}]])) (defmethod -route-events ::artist-view [route-id params query] diff --git a/src/cljs/airsonic_ui/views/audio_player.cljs b/src/cljs/airsonic_ui/views/audio_player.cljs index c8bd791..09a66d0 100644 --- a/src/cljs/airsonic_ui/views/audio_player.cljs +++ b/src/cljs/airsonic_ui/views/audio_player.cljs @@ -29,7 +29,7 @@ (dispatch [::events/set-playback-mode (if (= playback-mode :shuffled) :linear :shuffled)])) -(defn- advance-repeat-mode [current-mode] +(defn- toggle-repeat-mode [current-mode] (let [modes (cycle '(:repeat-none :repeat-all :repeat-single)) next-mode (->> (drop-while (partial not= current-mode) modes) (second))] @@ -45,7 +45,7 @@ nil))] [:div.field.has-addons ^{:key :shuffle-button} [shuffle-button {:on-click (toggle-shuffle playback-mode)} [icon :random]] - ^{:key :repeat-button} [repeat-button {:on-click (advance-repeat-mode repeat-mode)} [icon :loop]]])) + ^{:key :repeat-button} [repeat-button {:on-click (toggle-repeat-mode repeat-mode)} [icon :loop]]])) (def logo-url "./img/airsonic-light-350x100.png") @@ -54,7 +54,7 @@ playlist @(subscribe [:audio/playlist]) playback-status @(subscribe [:audio/playback-status]) is-playing? @(subscribe [:audio/is-playing?])] - [:nav.navbar.is-fixed-bottom.playback-area + [:nav.navbar.is-fixed-bottom.audio-player [:div.navbar-brand [:div.navbar-item [:img {:src logo-url}]]] diff --git a/src/sass/app.sass b/src/sass/app.sass index aefb50f..1ea4dad 100644 --- a/src/sass/app.sass +++ b/src/sass/app.sass @@ -29,7 +29,7 @@ min-height: calc(100vh - 2.5rem) // bottom bar -.playback-area +.audio-player background: $dark color: $light