mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-07 02:33:39 +02:00
Improvements to currently playing queue (#48)
* First sloppy import of code from heyarne/reagent-movable * Consistently use "current queue" to avoid confusion * Update shadow-cljs, re-frame and debux * Solve styling problem when sorting table rows * Make sortable component more reusable * Refactor playlist to use a sorted-map * Make sure current queue is displayed again * Fix sorting when converting a shuffled into a linear playlist * Implement set-current-track * Implement song-move in playlist * Add autoprefixer * Implement drag and drop reordering in current queue * Fix broken dev sass build * Bump some dependencies * Move airsonic-ui.views.icon to bulma.icon * Implement reusable dropdown in bulma.dropdown * Immediately render reordered tracks, reimplement actions in album view * Use new song-table on search result page * Make song-table more reusable * Remove current song * Implement go to source in current queue * Remove unused song view
This commit is contained in:
parent
f0324a236d
commit
8bf222a6e8
29 changed files with 1773 additions and 869 deletions
|
|
@ -1,31 +1,36 @@
|
|||
(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 [airsonic-ui.helpers :refer [format-duration]]
|
||||
[airsonic-ui.routes :as routes :refer [url-for]]
|
||||
[airsonic-ui.views.cover :refer [cover card]]
|
||||
[airsonic-ui.views.icon :refer [icon]]
|
||||
[airsonic-ui.views.song :as song]))
|
||||
(: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] (format-duration duration)]]
|
||||
[:li [icon :clock] (h/format-duration duration)]]
|
||||
year (conj [:li [icon :calendar] (str "Released in " year)]))))
|
||||
|
||||
(defn album-card [album]
|
||||
(let [{:keys [artist artistId name id]} album]
|
||||
[card album
|
||||
:url-fn #(url-for ::routes/album.detail {:id id})
|
||||
:content [:div
|
||||
;; link to album
|
||||
[:div.title.is-5
|
||||
[:a {:href (url-for ::routes/album.detail {:id id})
|
||||
:title name} name]]
|
||||
;; link to artist page
|
||||
[:div.subtitle.is-6 [:a {:href (url-for ::routes/artist.detail {:id artistId})
|
||||
:title artist} artist]]]]))
|
||||
;; 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
|
||||
|
|
@ -34,8 +39,54 @@
|
|||
^{: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
|
||||
"Lists all songs in an album"
|
||||
"Shows a detail view of a single album, listing all "
|
||||
[{:keys [album]}]
|
||||
[:div
|
||||
[:section.hero.is-small>div.hero-body
|
||||
|
|
@ -46,4 +97,5 @@
|
|||
[:h2.title (:name album)]
|
||||
[:h3.subtitle (:artist album)]
|
||||
[collection-info album]]]]]
|
||||
[:section.section>div.container [song/listing (:song album)]]])
|
||||
[:section.section>div.container
|
||||
[song-table {:songs (:song album)}]]])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue