mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-07 02:33:39 +02:00
Move all source files to src folder
This commit is contained in:
parent
cdf3785f82
commit
47c37e198c
20 changed files with 24 additions and 9 deletions
23
src/cljs/airsonic_ui/views/album.cljs
Normal file
23
src/cljs/airsonic_ui/views/album.cljs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(ns airsonic-ui.views.album
|
||||
(:require [airsonic-ui.routes :as routes :refer [url-for]]
|
||||
[airsonic-ui.views.cover :refer [cover]]))
|
||||
|
||||
(defn preview [album]
|
||||
(let [{:keys [artist artistId name coverArt id]} album]
|
||||
[:article.card.album-preview
|
||||
[:div.card-image
|
||||
[:a {:href (url-for ::routes/album-view {:id id})} [cover album 256]]]
|
||||
[:div.card-content
|
||||
;; link to album
|
||||
[:div.title.is-5
|
||||
[:a {:href (url-for ::routes/album-view {:id id})} name]]
|
||||
;; link to artist page
|
||||
[:div.subtitle.is-6 [:a {:href (url-for ::routes/artist-view {:id artistId})} artist]]]]))
|
||||
|
||||
(defn listing [albums]
|
||||
;; always show 5 in a row
|
||||
[:div
|
||||
(for [albums (partition-all 5 albums)]
|
||||
[:div.columns
|
||||
(for [[idx album] (map-indexed vector albums)]
|
||||
[:div.column {:key idx} [preview album]])])])
|
||||
41
src/cljs/airsonic_ui/views/bottom_bar.cljs
Normal file
41
src/cljs/airsonic_ui/views/bottom_bar.cljs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
(ns airsonic-ui.views.bottom-bar
|
||||
(:require [re-frame.core :refer [dispatch subscribe]]
|
||||
[airsonic-ui.events :as events]
|
||||
[airsonic-ui.subs :as subs]
|
||||
[airsonic-ui.views.cover :refer [cover]]))
|
||||
|
||||
;; currently playing / coming next / audio controls...
|
||||
|
||||
(defn current-song-info [{:keys [item status]}]
|
||||
[:article
|
||||
[:div (:artist item) " - " (:title item)]
|
||||
[:progress.progress.is-tiny {:value (:current-time status)
|
||||
:max (:duration item)}]])
|
||||
|
||||
(defn playback-controls []
|
||||
[:div.field.has-addons
|
||||
(let [buttons [["previous" ::events/previous-song]
|
||||
["play / pause" ::events/toggle-play-pause]
|
||||
["next" ::events/next-song]]]
|
||||
(map (fn [[label event]]
|
||||
[:p.control>button.button.is-light {:on-click #(dispatch [event])} label])
|
||||
buttons))])
|
||||
|
||||
(def logo-url "https://airsonic.github.io/airsonic-ui/assets/images/logo/airsonic-dark-350x100.png")
|
||||
|
||||
(defn bottom-bar []
|
||||
(let [currently-playing @(subscribe [::subs/currently-playing])]
|
||||
[:nav.navbar.is-fixed-bottom
|
||||
[:div.navbar-brand
|
||||
[:div.navbar-item
|
||||
[:img {:src logo-url}]]]
|
||||
[:div.navbar-menu.is-active
|
||||
(if currently-playing
|
||||
;; show song info
|
||||
[:section.level
|
||||
[:div.level-left>article.media
|
||||
[:div.media-left [cover (:item currently-playing) 48]]
|
||||
[:div.media-content [current-song-info currently-playing]]]
|
||||
[:div.level-right [playback-controls]]]
|
||||
;; not playing anything
|
||||
[:span "Currently no song selected"])]]))
|
||||
37
src/cljs/airsonic_ui/views/breadcrumbs.cljs
Normal file
37
src/cljs/airsonic_ui/views/breadcrumbs.cljs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
(ns airsonic-ui.views.breadcrumbs
|
||||
(:require [airsonic-ui.routes :as routes :refer [url-for]]))
|
||||
|
||||
;; Breadcrumbs are implemented in such a way that they provide a stringent
|
||||
;; hierarchy no matter how you came to the url. They should allow easy
|
||||
;; navigation upwards that hierarchy (e.g. album -> artist)
|
||||
|
||||
(defn content-type
|
||||
"Helper to see what kind of server response"
|
||||
[content]
|
||||
(cond
|
||||
(and (vector? (:album content)) (:id content)) :artist
|
||||
(vector? (:song content)) :album
|
||||
:else :unknown-content))
|
||||
|
||||
(defn- bulma-breadcrumbs [& items]
|
||||
[:nav.breadcrumb {:aria-label "breadcrumbs"}
|
||||
[:ul
|
||||
(for [[idx [href label]] (map-indexed vector (butlast items))]
|
||||
[:li {:key idx} [:a {:href href} label]])
|
||||
[:li.is-active>a (last items)]]])
|
||||
|
||||
(defmulti breadcrumbs content-type)
|
||||
|
||||
(defmethod breadcrumbs :default [content]
|
||||
[bulma-breadcrumbs "Start"])
|
||||
|
||||
(defmethod breadcrumbs :artist [content]
|
||||
[bulma-breadcrumbs
|
||||
[(url-for ::routes/main) "Start"]
|
||||
(:name content)])
|
||||
|
||||
(defmethod breadcrumbs :album [content]
|
||||
[bulma-breadcrumbs
|
||||
[(url-for ::routes/main) "Start"]
|
||||
[(url-for ::routes/artist-view {:id (:artistId content)}) (:artist content)]
|
||||
(:name content)])
|
||||
15
src/cljs/airsonic_ui/views/cover.cljs
Normal file
15
src/cljs/airsonic_ui/views/cover.cljs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(ns airsonic-ui.views.cover
|
||||
(:require [re-frame.core :refer [subscribe]]
|
||||
[airsonic-ui.subs :as subs]
|
||||
[airsonic-ui.api :as api]))
|
||||
|
||||
;; FIXME: The direct dependency on these subs is a bit ugly
|
||||
|
||||
(defn cover
|
||||
[item size]
|
||||
(let [server @(subscribe [::subs/server])
|
||||
login @(subscribe [::subs/login])
|
||||
url (partial api/cover-url server login item)]
|
||||
[:figure {:class-name (str "image is-" size "x" size)}
|
||||
[:img {:src (url size)
|
||||
:srcset (str (url size) ", " (url (* 2 size)) " 2x")}]]))
|
||||
42
src/cljs/airsonic_ui/views/login.cljs
Normal file
42
src/cljs/airsonic_ui/views/login.cljs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(ns airsonic-ui.views.login
|
||||
(:require [reagent.core :as r]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[airsonic-ui.events :as events]))
|
||||
|
||||
(defn- >reset!
|
||||
"Sends an event's target values to the given atom"
|
||||
[atom]
|
||||
#(reset! atom (.. % -target -value)))
|
||||
|
||||
;; login form
|
||||
|
||||
(defn login-form []
|
||||
(let [user (r/atom "")
|
||||
pass (r/atom "")
|
||||
server (r/atom (.. js/window -location -origin))
|
||||
submit (fn [e]
|
||||
(.preventDefault e)
|
||||
(dispatch [::events/authenticate @user @pass @server]))]
|
||||
(fn []
|
||||
[:section.hero.is-fullheight>div.hero-body
|
||||
[:div.container.has-text-centered>div.column.is-4.is-offset-4
|
||||
[:h3.title.has-text-grey "Airsonic"]
|
||||
[:p.subtitle.has-text-grey "Please login to proceed"]
|
||||
[:div.box
|
||||
[:form {:on-submit submit}
|
||||
[:div.field>div.control
|
||||
[:input.input.is-large {:type "text"
|
||||
:name "user"
|
||||
:placeholder "Username"
|
||||
:on-change (>reset! user)}]]
|
||||
[:div.field>div.control
|
||||
[:input.input.is-large {:type "password"
|
||||
:name "pass"
|
||||
:placeholder "Password"
|
||||
:on-change (>reset! pass)}]]
|
||||
[:div.field>div.control
|
||||
[:input.input.is-large {:type "text"
|
||||
:name "server"
|
||||
:on-change (>reset! server)
|
||||
:value @server}]]
|
||||
[:button.button.is-block.is-info.is-large.is-fullwidth {:type "submit"} "Submit"]]]]])))
|
||||
23
src/cljs/airsonic_ui/views/song.cljs
Normal file
23
src/cljs/airsonic_ui/views/song.cljs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
(ns airsonic-ui.views.song
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
[airsonic-ui.events :as events]
|
||||
[airsonic-ui.routes :as routes :refer [url-for]]))
|
||||
|
||||
(defn item [songs song]
|
||||
(let [artist-id (:artistId song)]
|
||||
[:div
|
||||
[:a
|
||||
(when artist-id {:href (url-for ::routes/artist-view {:id artist-id})})
|
||||
(:artist song)]
|
||||
" - "
|
||||
[:a
|
||||
{:href "#" :on-click (fn [e]
|
||||
(.preventDefault e)
|
||||
(dispatch [::events/play-songs songs song]))}
|
||||
(:title song)]]))
|
||||
|
||||
;; FIXME: This is very similar to album-listing
|
||||
|
||||
(defn listing [songs]
|
||||
[:ul (for [[idx song] (map-indexed vector songs)]
|
||||
[:li {:key idx} [item songs song]])])
|
||||
Loading…
Add table
Add a link
Reference in a new issue