Major images page refactor.

This commit is contained in:
Andrey Antukh 2016-10-19 17:42:24 +02:00
parent 5b995f78aa
commit 2143bb6e04
6 changed files with 326 additions and 105 deletions

View File

@ -2,8 +2,7 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;; ;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz> ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.data.images (ns uxbox.main.data.images
(:require [cuerdas.core :as str] (:require [cuerdas.core :as str]
@ -26,10 +25,8 @@
(defrecord Initialize [type id] (defrecord Initialize [type id]
rs/UpdateEvent rs/UpdateEvent
(-apply-update [_ state] (-apply-update [_ state]
(let [type (or type :builtin) (let [type (or type :own)
id (or id (if (= type :builtin) 1 nil))
data {:type type :id id :selected #{}}] data {:type type :id id :selected #{}}]
(println "initialize:" data)
(-> state (-> state
(assoc-in [:dashboard :images] data) (assoc-in [:dashboard :images] data)
(assoc-in [:dashboard :section] :dashboard/images)))) (assoc-in [:dashboard :section] :dashboard/images))))
@ -159,8 +156,8 @@
(rx/of (update-collection id)))) (rx/of (update-collection id))))
(defn rename-collection (defn rename-collection
[item name] [id name]
(RenameCollection. item name)) (RenameCollection. id name))
;; --- Delete Collection ;; --- Delete Collection
@ -193,7 +190,7 @@
(def allowed-file-types #{"image/jpeg" "image/png"}) (def allowed-file-types #{"image/jpeg" "image/png"})
(defrecord CreateImages [coll-id files] (defrecord CreateImages [id files]
rs/WatchEvent rs/WatchEvent
(-apply-watch [_ state s] (-apply-watch [_ state s]
(letfn [(image-size [file] (letfn [(image-size [file]
@ -202,7 +199,7 @@
(allowed-file? [file] (allowed-file? [file]
(contains? allowed-file-types (.-type file))) (contains? allowed-file-types (.-type file)))
(prepare [[file [width height]]] (prepare [[file [width height]]]
{:coll coll-id {:collection id
:mimetype (.-type file) :mimetype (.-type file)
:id (uuid/random) :id (uuid/random)
:file file :file file
@ -217,12 +214,13 @@
(rx/map image-created))))) (rx/map image-created)))))
(defn create-images (defn create-images
[coll-id files] [id files]
(CreateImages. coll-id files)) {:pre [(or (uuid? id) (nil? id))]}
(CreateImages. id files))
;; --- Images Fetched ;; --- Images Fetched
(defrecord ImagesFetched [coll-id items] (defrecord ImagesFetched [items]
rs/UpdateEvent rs/UpdateEvent
(-apply-update [_ state] (-apply-update [_ state]
(reduce (fn [state {:keys [id] :as image}] (reduce (fn [state {:keys [id] :as image}]
@ -231,58 +229,77 @@
items))) items)))
(defn images-fetched (defn images-fetched
[coll-id items] [items]
(ImagesFetched. coll-id items)) (ImagesFetched. items))
;; --- Fetch Images ;; --- Fetch Images
(defrecord FetchImages [coll-id] (defrecord FetchImages [id]
rs/WatchEvent rs/WatchEvent
(-apply-watch [_ state s] (-apply-watch [_ state s]
(let [params {:coll coll-id}] (let [params {:coll id}]
(->> (rp/req :fetch/images params) (->> (rp/req :fetch/images params)
(rx/map :payload) (rx/map :payload)
(rx/map #(images-fetched coll-id %)))))) (rx/map images-fetched)))))
(defn fetch-images (defn fetch-images
[coll-id] "Fetch a list of images of the selected collection"
(FetchImages. coll-id)) [id]
{:pre [(or (uuid? id) (nil? id))]}
(FetchImages. id))
;; --- Fetch Image
(declare image-fetched)
(defrecord FetchImage [id]
rs/WatchEvent
(-apply-watch [_ state stream]
(let [existing (get-in state [:images-by-id id])]
(if existing
(rx/empty)
(->> (rp/req :fetch/image {:id id})
(rx/map :payload)
(rx/map image-fetched))))))
(defn fetch-image
"Conditionally fetch image by its id. If image
is already loaded, this event is noop."
[id]
{:pre [(uuid? id)]}
(FetchImage. id))
;; --- Image Fetched
(defrecord ImageFetched [image]
rs/UpdateEvent
(-apply-update [_ state]
(let [id (:id image)]
(update state :images-by-id assoc id image))))
(defn image-fetched
[image]
{:pre [(map? image)]}
(ImageFetched. image))
;; --- Delete Images ;; --- Delete Images
(defrecord DeleteImage [coll-id image-id] (defrecord DeleteImage [id]
rs/UpdateEvent rs/UpdateEvent
(-apply-update [_ state] (-apply-update [_ state]
(update state [:images-by-id] dissoc image-id)) (-> state
(update :images-by-id dissoc id)
(update-in [:dashboard :images :selected] disj id)))
rs/WatchEvent rs/WatchEvent
(-apply-watch [_ state s] (-apply-watch [_ state s]
(->> (rp/req :delete/image image-id) (->> (rp/req :delete/image id)
(rx/ignore)))) (rx/ignore))))
(defn delete-image (defn delete-image
[coll-id image-id] [id]
{:pre [(uuid? coll-id) {:pre [(uuid? id)]}
(uuid? image-id)]} (DeleteImage. id))
(DeleteImage. coll-id image-id))
;; --- Remove Image
(defrecord RemoveImages [id images]
rs/UpdateEvent
(-apply-update [_ state]
#_(update-in state [:image-colls-by-id id :data]
#(set/difference % images)))
rs/WatchEvent
(-apply-watch [_ state s]
(rx/of (update-collection id))))
(defn remove-images
"Remove image in a collection."
[id images]
(RemoveImages. id images))
;; --- Select image ;; --- Select image
@ -314,9 +331,9 @@
(defrecord DeleteSelected [] (defrecord DeleteSelected []
rs/WatchEvent rs/WatchEvent
(-apply-watch [_ state stream] (-apply-watch [_ state stream]
(let [{:keys [id selected]} (get-in state [:dashboard :images])] (let [selected (get-in state [:dashboard :images :selected])]
(rx/of (remove-images id selected) (->> (rx/from-coll selected)
#(assoc-in % [:dashboard :images :selected] #{}))))) (rx/map delete-image)))))
(defn delete-selected (defn delete-selected
[] []

View File

@ -40,20 +40,28 @@
(defmethod request :fetch/images (defmethod request :fetch/images
[_ {:keys [coll]}] [_ {:keys [coll]}]
(let [params {:url (str url "/library/image-collections/" coll "/images") (let [url (if coll
(str url "/library/image-collections/" coll "/images")
(str url "/library/image-collections/images"))
params {:url url :method :get}]
(send! params)))
(defmethod request :fetch/image
[_ {:keys [id]}]
(let [params {:url (str url "/library/images/" id)
:method :get}] :method :get}]
(send! params))) (send! params)))
(defmethod request :create/image (defmethod request :create/image
[_ {:keys [coll id file width height mimetype] :as body}] [_ {:keys [collection id file width height mimetype] :as body}]
(let [body (doto (js/FormData.) (let [body (doto (js/FormData.)
(.append "mimetype" mimetype) (.append "mimetype" mimetype)
;; (.append "collection" (str coll)) (.append "collection" (str collection))
(.append "file" file) (.append "file" file)
(.append "width" width) (.append "width" width)
(.append "height" height) (.append "height" height)
(.append "id" id)) (.append "id" id))
params {:url (str url "/library/image-collections/" coll "/images") params {:url (str url "/library/images/")
:method :post :method :post
:body body}] :body body}]
(send! params))) (send! params)))

View File

@ -166,19 +166,148 @@
(defn- new-element-lightbox-render (defn- new-element-lightbox-render
[own] [own]
(html (html
[:div.lightbox-body ;;------Element lightbox
[:h3 "New element"]
[:div.row-flex ;;[:div.lightbox-body
[:div.lightbox-big-btn ;;[:h3 "New element"]
[:span.big-svg i/shapes] ;;[:div.row-flex
[:span.text "Go to workspace"]] ;;[:div.lightbox-big-btn
[:div.lightbox-big-btn ;;[:span.big-svg i/shapes]
[:span.big-svg.upload i/exit] ;;[:span.text "Go to workspace"]]
[:span.text "Upload file"]]] ;;[:div.lightbox-big-btn
;;[:span.big-svg.upload i/exit]
;;[:span.text "Upload file"]]]
;;[:a.close {:href "#"
;;:on-click #(do (dom/prevent-default %)
;;(udl/close!))}
;;i/close]]
;;------Upload image lightbox
;;[:div.lightbox-body
;;[:h3 "Import image"]
;;[:div.row-flex
;;[:div.lightbox-big-btn
;;[:span.big-svg i/image]
;;[:span.text "Select from library"]]
;;[:div.lightbox-big-btn
;;[:span.big-svg.upload i/exit]
;;[:span.text "Upload file"]]]
;;[:a.close {:href "#"
;;:on-click #(do (dom/prevent-default %)
;;(udl/close!))}
;;i/close]]
;;------Upload image library lightbox
[:div.lightbox-body.big-lightbox
[:h3 "Import image from library"]
[:div.import-img-library
[:div.library-actions
[:ul.toggle-library
[:li.standard.current "STANDARD"]
[:li.your-images "YOUR IMAGES"]]
[:select.input-select
[:option "Library 1"]
[:option "Library 2"]
[:option "Library 3"]
[:option "Library 4"]
[:option "Library 5"]
[:option "Library 6"]]]
[:div.library-content
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
[:div.library-item
[:div.library-item-th
{:style
{:background-image "url('https://images.unsplash.com/photo-1441986380878-c4248f5b8b5b?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&w=1080&fit=max&s=486f09671860a11e70bdd0a45e7c5014')"}}]
[:span "image_name.jpg"]]
]]
[:a.close {:href "#" [:a.close {:href "#"
:on-click #(do (dom/prevent-default %) :on-click #(do (dom/prevent-default %)
(udl/close!))} (udl/close!))}
i/close]])) i/close]]
))
(def ^:private new-element-lightbox (def ^:private new-element-lightbox
(mx/component (mx/component

View File

@ -6,25 +6,19 @@
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com> ;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.dashboard.images (ns uxbox.main.ui.dashboard.images
(:require [sablono.core :as html :refer-macros [html]] (:require [cuerdas.core :as str]
[rum.core :as rum]
[cuerdas.core :as str]
[lentes.core :as l] [lentes.core :as l]
[uxbox.util.i18n :as t :refer (tr)] [uxbox.util.i18n :as t :refer (tr)]
[uxbox.main.state :as st] [uxbox.main.state :as st]
[uxbox.util.rstore :as rs] [uxbox.util.rstore :as rs]
[uxbox.main.library :as library]
[uxbox.main.data.dashboard :as dd]
[uxbox.main.data.lightbox :as udl] [uxbox.main.data.lightbox :as udl]
[uxbox.main.data.images :as di] [uxbox.main.data.images :as di]
[uxbox.main.ui.icons :as i] [uxbox.main.ui.icons :as i]
[uxbox.util.mixins :as mx :include-macros true] [uxbox.util.mixins :as mx :include-macros true]
[uxbox.main.ui.lightbox :as lbx] [uxbox.main.ui.lightbox :as lbx]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.library-bar :as ui.library-bar]
[uxbox.main.ui.dashboard.header :refer (header)] [uxbox.main.ui.dashboard.header :refer (header)]
[uxbox.util.data :as data :refer (read-string)] [uxbox.util.data :as data :refer (read-string)]
[uxbox.util.lens :as ul]
[uxbox.util.dom :as dom])) [uxbox.util.dom :as dom]))
;; --- Helpers & Constants ;; --- Helpers & Constants
@ -65,15 +59,6 @@
(-> (l/key :images-by-id) (-> (l/key :images-by-id)
(l/derive st/state))) (l/derive st/state)))
;; (def ^:private collections-ref
;; (-> (l/lens vals)
;; (l/derive collections-map-ref)))
;; (defn- focus-collection
;; [id]
;; (-> (l/key id)
;; (l/derive collections-map-ref)))
;; --- Page Title ;; --- Page Title
(mx/defcs page-title (mx/defcs page-title
@ -117,7 +102,7 @@
[:span.close {:on-click on-cancel} i/close]] [:span.close {:on-click on-cancel} i/close]]
[:span.dashboard-title-field [:span.dashboard-title-field
{:on-double-click on-edit} {:on-double-click on-edit}
(:name coll)])] (:name coll "Storage")])]
(if (and (not own?) coll) (if (and (not own?) coll)
[:div.edition [:div.edition
(if edit? (if edit?
@ -127,19 +112,26 @@
;; --- Nav ;; --- Nav
(defn react-count-images
[id]
(->> (mx/react images-ref)
(vals)
(filter #(= id (:collection %)))
(count)))
(mx/defc nav-item (mx/defc nav-item
{:mixins [mx/static]} {:mixins [mx/static mx/reactive]}
[collection selected?] [{:keys [id type name] :as coll} selected?]
(letfn [(on-click [event] (letfn [(on-click [event]
(let [type (:type collection) (let [type (or type :own)]
id (:id collection)]
(rs/emit! (di/select-collection type id))))] (rs/emit! (di/select-collection type id))))]
(let [images (count (:images collection []))] (let [num-images (react-count-images id)]
[:li {:on-click on-click [:li {:on-click on-click
:class-name (when selected? "current")} :class-name (when selected? "current")}
[:span.element-title (:name collection)] [:span.element-title
(if coll name "Storage")]
[:span.element-subtitle [:span.element-subtitle
(tr "ds.num-elements" (t/c images))]]))) (tr "ds.num-elements" (t/c num-images))]])))
(mx/defc nav-section (mx/defc nav-section
{:mixins [mx/static mx/reactive]} {:mixins [mx/static mx/reactive]}
@ -156,6 +148,8 @@
[:a.btn-primary [:a.btn-primary
{:on-click #(rs/emit! (di/create-collection))} {:on-click #(rs/emit! (di/create-collection))}
"+ New library"]]) "+ New library"]])
(when own?
(nav-item nil (nil? selected)))
(for [coll collections (for [coll collections
:let [selected? (= (:id coll) selected) :let [selected? (= (:id coll) selected)
key (str (:id coll))]] key (str (:id coll))]]
@ -179,12 +173,13 @@
[:div.library-bar [:div.library-bar
[:div.library-bar-inside [:div.library-bar-inside
[:ul.library-tabs [:ul.library-tabs
[:li {:class-name (when builtin? "current")
:on-click (partial select-tab :builtin)}
"STANDARD"]
[:li {:class-name (when own? "current") [:li {:class-name (when own? "current")
:on-click (partial select-tab :own)} :on-click (partial select-tab :own)}
"YOUR LIBRARIES"]] "YOUR IMAGES"]
[:li {:class-name (when builtin? "current")
:on-click (partial select-tab :builtin)}
"IMAGES STORE"]]
(nav-section type id colls)]]))) (nav-section type id colls)]])))
;; --- Grid ;; --- Grid
@ -208,15 +203,15 @@
:on-change on-file-selected}]])) :on-change on-file-selected}]]))
(mx/defc grid-options (mx/defc grid-options
[coll] [{:keys [type] :as coll}]
(let [own? (= (:type coll) :own)] (let [editable? (or (= type :own) (nil? coll))]
(letfn [(delete [] (letfn [(delete []
(rs/emit! (di/delete-selected))) (rs/emit! (di/delete-selected)))
(on-delete [event] (on-delete [event]
(udl/open! :confirm {:on-accept delete}))] (udl/open! :confirm {:on-accept delete}))]
;; MULTISELECT OPTIONS BAR ;; MULTISELECT OPTIONS BAR
[:div.multiselect-bar [:div.multiselect-bar
(if own? (if editable?
[:div.multiselect-nav [:div.multiselect-nav
#_[:span.move-item.tooltip.tooltip-top #_[:span.move-item.tooltip.tooltip-top
{:alt "Move to"} {:alt "Move to"}
@ -251,19 +246,18 @@
(mx/defc grid (mx/defc grid
{:mixins [mx/static mx/reactive]} {:mixins [mx/static mx/reactive]}
[{:keys [id type selected] :as state}] [{:keys [id type selected] :as state}]
(let [filtering (:filter state) (let [editable? (or (= type :own) (nil? id))
filtering (:filter state)
ordering (:order state) ordering (:order state)
own? (= type :own) images (mx/react images-ref)
images (rum/react images-ref)
images (->> (vals images) images (->> (vals images)
(filter #(= id (:collection %))) (filter #(= id (:collection %)))
(filter-images-by filtering) (filter-images-by filtering)
(sort-images-by ordering))] (sort-images-by ordering))]
[:div.dashboard-grid-content [:div.dashboard-grid-content
[:div.dashboard-grid-row [:div.dashboard-grid-row
(when own? (when editable? (grid-form id))
(grid-form id))
(for [image images (for [image images
:let [id (:id image) :let [id (:id image)
selected? (contains? selected id)]] selected? (contains? selected id)]]
@ -273,13 +267,11 @@
(mx/defc content (mx/defc content
{:mixins [mx/static]} {:mixins [mx/static]}
[{:keys [type id selected] :as state} coll] [{:keys [type id selected] :as state} coll]
(let [own? (= type :own)] [:section.dashboard-grid.library
(when coll (page-title coll)
[:section.dashboard-grid.library (grid state)
(page-title coll) (when (seq selected)
(grid state) (grid-options coll))])
(when (seq selected)
(grid-options coll))])))
;; --- Menu ;; --- Menu

View File

@ -15,6 +15,7 @@
[uxbox.main.ui.shapes.circle :as circle] [uxbox.main.ui.shapes.circle :as circle]
[uxbox.main.ui.shapes.text :as text] [uxbox.main.ui.shapes.text :as text]
[uxbox.main.ui.shapes.path :as path] [uxbox.main.ui.shapes.path :as path]
[uxbox.main.ui.shapes.image :as image]
[uxbox.main.geom :as geom])) [uxbox.main.geom :as geom]))
;; --- Helpers ;; --- Helpers
@ -34,6 +35,7 @@
:icon (icon/icon-component shape) :icon (icon/icon-component shape)
:rect (rect/rect-component shape) :rect (rect/rect-component shape)
:path (path/path-component shape) :path (path/path-component shape)
:image (image/image-component shape)
:circle (circle/circle-component shape))) :circle (circle/circle-component shape)))
(mx/defc component-container (mx/defc component-container

View File

@ -0,0 +1,73 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.shapes.image
(:require [beicon.core :as rx]
[lentes.core :as l]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.http :as http]
[uxbox.util.rstore :as rs]
[uxbox.main.state :as st]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.data.images :as udi]
[uxbox.main.geom :as geom]))
;; --- Refs
(defn image-ref
[id]
(-> (l/in [:images-by-id id])
(l/derive st/state)))
;; --- Image Component
(declare image-shape)
(defn- will-mount
[own]
(let [{:keys [image-id]} (first (:rum/args own))]
(rs/emit! (udi/fetch-image image-id))
own))
(mx/defcs image-component
{:mixins [mx/static mx/reactive]
:will-mount will-mount}
[own {:keys [id image-id] :as shape}]
(let [selected (mx/react common/selected-ref)
image (mx/react (image-ref image-id))
selected? (contains? selected id)
local (:rum/local own)
on-mouse-down #(common/on-mouse-down % shape selected)]
(when image
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down}
(image-shape (assoc shape :image image))])))
;; --- Image Shape
(mx/defc image-shape
{:mixins [mx/static]}
[{:keys [id x1 y1 image] :as shape}]
(let [key (str "shape-" id)
;; rfm (geom/transformation-matrix shape)
size (geom/size shape)
props {:x x1 :y y1 :id key :key key
:preserve-aspect-ratio "none"
:xlink-href (:url image)}
attrs (-> (attrs/extract-style-attrs shape)
(merge props size))]
[:image attrs]))
;; --- Image SVG
(mx/defc image-svg
{:mixins [mx/static]}
[{:keys [data id view-box] :as shape}]
(let [key (str "image-svg-" id)
view-box (apply str (interpose " " view-box))
props {:view-box view-box :id key :key key}]
[:svg props data]))