1
0
Fork 0
mirror of https://github.com/heyarne/airsonic-ui.git synced 2026-05-06 18:33:38 +02:00
airsonic-ui/src/cljs/airsonic_ui/components/collection/views.cljs
2019-12-08 02:07:12 +01:00

101 lines
3.9 KiB
Clojure

(ns airsonic-ui.components.collection.views
"A collection is a list of audio files that belong together (e.g. an album or
a podcast's overview)"
(:require [re-frame.core :refer [subscribe]]
[bulma.icon :refer [icon]]
[bulma.dropdown.views :refer [dropdown]]
[airsonic-ui.helpers :as h]
[airsonic-ui.routes :as routes]
[airsonic-ui.views.cover :refer [cover card]]))
(defn collection-info [{:keys [songCount duration year]}]
(vec (cond-> [:ul.is-smaller.collection-info
[:li [icon :audio-spectrum] (str songCount (if (= 1 songCount)
" track" " tracks"))]
[:li [icon :clock] (h/format-duration duration)]]
year (conj [:li [icon :calendar] (str "Released in " year)]))))
;; TODO: Maybe this view belongs somewhere else?
;; Something like a collection-grid component?
(defn album-card
"A single element in a grid of albums. Shows the cover, artist and album name."
[{:keys [artist artistId name id] :as album}]
[card album
:url-fn #(routes/url-for ::routes/album.detail {:id id})
:content [:div
;; link to album
[:div.title.is-5
[:a {:href (routes/url-for ::routes/album.detail {:id id})
:title name} name]]
;; link to artist page
[:div.subtitle.is-6 [:a {:href (routes/url-for ::routes/artist.detail {:id artistId})
:title artist} artist]]]])
(defn listing [albums]
;; always show 5 in a row
[:div.columns.is-multiline.is-mobile
(for [[idx album] (map-indexed vector albums)]
^{:key idx} [:div.column.is-one-fifth-desktop.is-one-quarter-tablet.is-half-mobile
[album-card album]])])
;; TODO: Avoid duplication
(defn artist-link [{id :artistId, artist :artist}]
(if id
[:a {:href (routes/url-for ::routes/artist.detail {:id id})} artist]
artist))
(defn song-link [{:keys [songs song idx]}]
[:a
{:href "#" :on-click (h/muted-dispatch [:audio-player/play-all songs idx] :sync? true)}
(:title song)])
(defn song-actions [song]
[dropdown {:items [{:label "Play Next" :event [:audio-player/enqueue-next song]}
{:label "Play Last" :event [:audio-player/enqueue-last song]}]}])
(defn default-thead []
[:thead>tr
[:td.is-narrow]
[:td.song-artist "Artist"]
[:td.song-title "Title"]
[:td.song-duration "Duration"]
[:td.is-narrow]])
(defn default-tbody [{:keys [songs current-song]}]
[:tbody
(for [[idx song] (map-indexed vector songs)]
^{:key idx}
[(if (= (:id song) (:id current-song)) :tr.is-playing :tr)
[:td.song-tracknr.is-narrow (:track song)]
[:td.song-artist [artist-link song]]
[:td.song-title [song-link {:songs songs
:song song
:idx idx}]]
[:td.song-duration (h/format-duration (:duration song) :brief? true)]
[:td.song-actions.is-narrow [song-actions song]]])])
(defn song-table [{:keys [songs thead tbody]
:or {thead default-thead, tbody default-tbody}}]
;; we subscribe here instead of one level higher up to make this a more
;; reusable component; this way we can for example get a list of all songs
;; in a search result and easily highlight the currently playing track
(let [current-song @(subscribe [:audio/current-song])]
[:table.song-listing-table.table.is-fullwidth
[thead]
[tbody {:songs songs, :current-song current-song}]]))
(defn detail
"Shows a detail view of a single album, listing all "
[{:keys [album]}]
[:div
[:section.hero.is-small>div.hero-body
[:div.container
[:article.collection-header.media
[:div.media-left [cover album 128]]
[:div.media-content
[:h2.title (:name album)]
[:h3.subtitle (:artist album)]
[collection-info album]]]]]
[:section.section>div.container
[song-table {:songs (:song album)}]]])