From a0e24f597901828a68d63d53d614e5a47a986fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20Schl=C3=BCter?= Date: Sat, 2 Jun 2018 11:21:58 +0200 Subject: [PATCH] Add generated covers for items that have none --- package-lock.json | 13 ++++++ package.json | 1 + src/cljs/airsonic_ui/views.cljs | 3 +- src/cljs/airsonic_ui/views/cover.cljs | 61 +++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d741b7d..bfe4d02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,14 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@hugojosefson/color-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@hugojosefson/color-hash/-/color-hash-2.0.3.tgz", + "integrity": "sha512-ASaDCIwQmyeH6eXdG1Nf2zMOr85Ljp13/8qBSPtYkY1hAr6URRAPG+15i2ogXh/caSolZ4mGfP7MwHPLm/V2Dw==", + "requires": { + "string-hash": "^1.1.3" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -5844,6 +5852,11 @@ } } }, + "string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", diff --git a/package.json b/package.json index c9dca08..2fe8833 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "url": "git://github.com/heyarne/airsonic-ui.git" }, "dependencies": { + "@hugojosefson/color-hash": "^2.0.3", "bulma": "^0.7.1", "create-react-class": "^15.6.3", "react": "^16.3.2", diff --git a/src/cljs/airsonic_ui/views.cljs b/src/cljs/airsonic_ui/views.cljs index 12dbd30..d719a37 100644 --- a/src/cljs/airsonic_ui/views.cljs +++ b/src/cljs/airsonic_ui/views.cljs @@ -30,9 +30,10 @@ (defn sidebar [user] [:aside.menu.section - [:p.menu-label (str "User: " (:name user))] + [:p.menu-label user] [:ul.menu-list [:li [:a "Settings"]] + ;; FIXME: Create proper logout event [:li [:a {:on-click #(dispatch [::events/initialize-db]) :href "#"} "Logout"]]]]) ;; putting everything together diff --git a/src/cljs/airsonic_ui/views/cover.cljs b/src/cljs/airsonic_ui/views/cover.cljs index bf0731d..82297f0 100644 --- a/src/cljs/airsonic_ui/views/cover.cljs +++ b/src/cljs/airsonic_ui/views/cover.cljs @@ -1,15 +1,68 @@ (ns airsonic-ui.views.cover - (:require [re-frame.core :refer [subscribe]] + (:require [clojure.string :as str] + [re-frame.core :refer [subscribe]] + [reagent.core :as reagent] [airsonic-ui.subs :as subs] - [airsonic-ui.utils.api :as api])) + [airsonic-ui.utils.api :as api] + ["@hugojosefson/color-hash" :as ColorHash])) + +(def color-hash (ColorHash.)) + +(defn palette + "Generate a hsl palette of two colors that's unique for a given item" + [item] + (let [[h s l] (js->clj (.hsl color-hash (str (:name item) (:artist item)))) + s (str (* 100 s) "%") + l (str (* 100 l) "%")] + (->> + [[h s l] + [(mod (+ h (* h 0.3) 10) 360) s l]] + (map #(str "hsl(" (str/join "," %) ")"))))) ;; FIXME: The direct dependency on these subs is a bit ugly +(defn generate-cover [canvas item] + (let [ctx (.getContext canvas "2d") + size (.-clientWidth canvas) + [a b] (palette item) + pad (* 0.02 size) + gradient (doto (.createLinearGradient ctx pad 0 (- size pad) size) + (.addColorStop 0 a) + (.addColorStop 1 b))] + (set! (.-fillStyle ctx) gradient) + (.fillRect ctx 0 0 size size))) + +(defn missing-cover + [item size] + (let [dom-node (reagent/atom nil)] + (reagent/create-class + {:component-did-update + (fn [this] + (let [canvas @dom-node] + (set! (.. canvas -style -width) "100%") + (set! (. canvas -width) (.-offsetWidth canvas)) + (set! (. canvas -height) (.-offsetWidth canvas)) + (generate-cover canvas item))) + + :component-did-mount + (fn [this] + (reset! dom-node (reagent/dom-node this))) + + :reagent-render + (fn [] + @dom-node + [:canvas.missing-cover])}))) + +(defn has-cover? [item] + (:coverArt item)) + (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")}]])) + (if (has-cover? item) + [:img {:src (url size) + :srcSet (str (url size) ", " (url (* 2 size)) " 2x")}] + [missing-cover item size])]))