🎉 Edit assets

This commit is contained in:
Andrés Moya 2020-07-30 14:52:58 +02:00
parent af2c49dd16
commit d40f27e18c
10 changed files with 364 additions and 63 deletions

View file

@ -10,6 +10,7 @@
[beicon.core :as rx]
[clojure.set :as set]
[potok.core :as ptk]
[uxbox.common.data :as d]
[uxbox.common.spec :as us]
[uxbox.main.repo :as rp]
[uxbox.main.store :as st]
@ -249,21 +250,85 @@
(declare create-color-result)
(defn create-color
[library-id color]
(s/assert (s/nilable uuid?) library-id)
[file-id color]
(s/assert (s/nilable uuid?) file-id)
(ptk/reify ::create-color
ptk/WatchEvent
(watch [_ state s]
(->> (rp/mutation! :create-color {:library-id library-id
(->> (rp/mutation! :create-color {:file-id file-id
:content color
:name color})
(rx/map (partial create-color-result library-id))))))
(rx/map (partial create-color-result file-id))))))
(defn create-color-result
[library-id item]
[file-id color]
(ptk/reify ::create-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:library-items :palettes library-id] #(into [item] %) )))))
(assoc-in [:workspace-colors (:id color)] color)
(assoc-in [:workspace-local :color-for-rename] (:id color))))))
(def clear-color-for-rename
(ptk/reify ::clear-color-for-rename
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-local :color-for-rename] nil))))
(declare rename-color-result)
(defn rename-color
[file-id color-id name]
(ptk/reify ::rename-color
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/mutation! :rename-color {:id color-id
:name name})
(rx/map (partial rename-color-result file-id))))))
(defn rename-color-result
[file-id color]
(ptk/reify ::rename-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc-in [:workspace-colors (:id color)] color)))))
(declare update-color-result)
(defn update-color
[file-id color-id content]
(ptk/reify ::update-color
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/mutation! :update-color {:id color-id
:content content})
(rx/map (partial update-color-result file-id))))))
(defn update-color-result
[file-id color]
(ptk/reify ::update-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc-in [:workspace-colors (:id color)] color)))))
(declare delete-color-result)
(defn delete-color
[file-id color-id]
(ptk/reify ::delete-color
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/mutation! :delete-color {:id color-id})
(rx/map #(delete-color-result file-id color-id))))))
(defn delete-color-result
[file-id color-id]
(ptk/reify ::delete-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(d/dissoc-in [:workspace-colors color-id])))))

View file

@ -324,7 +324,7 @@
;; --- Upload Image
(declare image-uploaded)
(def allowed-file-types #{"image/jpeg" "image/png" "image/webp"})
(def allowed-file-types #{"image/jpeg" "image/png" "image/webp" "image/svg+xml"})
(def max-file-size (* 5 1024 1024))
;; TODO: unify with create-images at main/data/images.cljs

View file

@ -19,6 +19,7 @@
[uxbox.main.ui.icons :as i]
[uxbox.main.data.workspace :as dw]
[uxbox.main.data.images :as di]
[uxbox.main.data.colors :as dcol]
[uxbox.main.refs :as refs]
[uxbox.main.store :as st]
[uxbox.main.ui.keyboard :as kbd]
@ -30,18 +31,46 @@
[uxbox.util.i18n :as i18n :refer [tr]]
[uxbox.util.data :refer [classnames]]
[uxbox.main.data.library :as dlib]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]]
[uxbox.main.ui.components.tab-container :refer [tab-container tab-element]]
[uxbox.main.ui.components.file-uploader :refer [file-uploader]]
[uxbox.main.ui.components.context-menu :refer [context-menu]]))
(defn matches-search
[name search-term]
(if (empty? search-term)
(if (str/empty? search-term)
true
(let [st (str/trim (str/lower search-term))
nm (str/trim (str/lower name))]
(str/includes? nm st))))
(mf/defc modal-edit-color
[{:keys [color-value on-accept on-cancel] :as ctx}]
(let [state (mf/use-state {:current-color color-value})]
(letfn [(accept [event]
(dom/prevent-default event)
(modal/hide!)
(when on-accept (on-accept (:current-color @state))))
(cancel [event]
(dom/prevent-default event)
(modal/hide!)
(when on-cancel (on-cancel)))]
[:div.modal-create-color
[:h3.modal-create-color-title (tr "modal.create-color.new-color")]
[:& colorpicker {:value (:current-color @state)
:colors (into-array @most-used-colors)
:disable-opacity true
:on-change #(swap! state assoc :current-color %)}]
[:input.btn-primary {:type "button"
:value (tr "ds.button.save")
:on-click accept}]
[:a.close {:href "#" :on-click cancel} i/close]])))
(mf/defc graphics-box
[{:keys [library-id images] :as props}]
(let [state (mf/use-state {:menu-open false
@ -104,25 +133,125 @@
:on-close #(swap! state assoc :menu-open false)
:top (:top @state)
:left (:left @state)
:options [[(tr "workspace.assets.delete") delete-graphic]]}]]
]))
:options [[(tr "workspace.assets.delete") delete-graphic]]}]]]))
(mf/defc color-item
[{:keys [color library-id] :as props}]
(let [workspace-local @refs/workspace-local
color-for-rename (:color-for-rename workspace-local)
edit-input-ref (mf/use-ref)
state (mf/use-state {:menu-open false
:top nil
:left nil
:editing (= color-for-rename (:id color))})
rename-color
(fn [name]
(st/emit! (dcol/rename-color library-id (:id color) name)))
edit-color
(fn [value opacity]
(st/emit! (dcol/update-color library-id (:id color) value)))
delete-color
(fn []
(st/emit! (dcol/delete-color library-id (:id color))))
rename-color-clicked
(fn [event]
(dom/prevent-default event)
(swap! state assoc :editing true))
input-blur
(fn [event]
(let [target (dom/event->target event)
name (dom/get-value target)]
(rename-color name)
(st/emit! dcol/clear-color-for-rename)
(swap! state assoc :editing false)))
input-key-down
(fn [event]
(when (kbd/esc? event)
(st/emit! dcol/clear-color-for-rename)
(swap! state assoc :editing false))
(when (kbd/enter? event)
(input-blur event)))
edit-color-clicked
(fn [event]
(modal/show! modal-edit-color
{:color-value (:content color)
:on-accept edit-color}))
on-context-menu
(fn [event]
(let [pos (dom/get-client-position event)
top (:y pos)
left (- (:x pos) 20)]
(dom/prevent-default event)
(swap! state assoc
:menu-open true
:top top
:left left)))]
(mf/use-effect
(mf/deps (:editing @state))
#(when (:editing @state)
(let [edit-input (mf/ref-val edit-input-ref)]
(dom/select-text! edit-input))
nil))
[:div.group-list-item {:on-context-menu on-context-menu}
[:div.color-block {:style {:background-color (:content color)}}]
(if (:editing @state)
[:input.element-name
{:type "text"
:ref edit-input-ref
:on-blur input-blur
:on-key-down input-key-down
:auto-focus true
:default-value (:name color "")}]
[:div.name-block
{:on-double-click rename-color-clicked}
(:name color)
(when-not (= (:name color) (:content color))
[:span (:content color)])])
[:& context-menu
{:selectable false
:show (:menu-open @state)
:on-close #(swap! state assoc :menu-open false)
:top (:top @state)
:left (:left @state)
:options [[(tr "workspace.assets.rename") rename-color-clicked]
[(tr "workspace.assets.edit") edit-color-clicked]
[(tr "workspace.assets.delete") delete-color]]}]]))
(mf/defc colors-box
[{:keys [colors] :as props}]
(let [add-color #(println "añadir color")]
[{:keys [library-id colors] :as props}]
(let [add-color
(fn [value opacity]
(st/emit! (dcol/create-color library-id value)))
add-color-clicked
(fn [event]
(modal/show! modal-edit-color
{:color-value "#406280"
:on-accept add-color}))]
[:div.asset-group
[:div.group-title
(tr "workspace.assets.colors")
[:span (str "\u00A0(") (count colors) ")"] ;; Unicode 00A0 is non-breaking space
[:div.group-button {:on-click add-color} i/plus]]
[:div.group-button {:on-click add-color-clicked} i/plus]]
[:div.group-list
(for [color (sort-by :name colors)]
[:div.group-list-item {:key (:name color)
:on-context-menu #(println "context")}
[:div.color-block {:style {:background-color (:content color)}}]
(:name color)
(when-not (= (:name color) (:content color))
[:span (:content color)])])]]))
[:& color-item {:key (:id color)
:color color
:library-id library-id}])]]))
(mf/defc library-toolbox
[{:keys [library-id
@ -141,11 +270,18 @@
i/arrow-slide]
[:span (tr "workspace.assets.file-library")]]
(when @open?
[:div.tool-window-content
(when (or (= box-filter :all) (= box-filter :graphics))
[:& graphics-box {:library-id library-id :images images}])
(when (or (= box-filter :all) (= box-filter :colors))
[:& colors-box {:colors colors}])])]))
(let [show-graphics (and (or (= box-filter :all) (= box-filter :graphics))
(or (> (count images) 0) (str/empty? search-term)))
show-colors (and (or (= box-filter :all) (= box-filter :colors))
(or (> (count colors) 0) (str/empty? search-term)))]
[:div.tool-window-content
(when show-graphics
[:& graphics-box {:library-id library-id :images images}])
(when show-colors
[:& colors-box {:library-id library-id :colors colors}])
(when (and (not show-graphics) (not show-colors))
[:div.asset-group
[:div.group-title (tr "workspace.assets.not-found")]])]))]))
(mf/defc assets-toolbox
[]
@ -160,7 +296,8 @@
filtered-images (filter #(matches-search (:name %) (:search-term @state))
(vals file-images))
filtered-colors (filter #(matches-search (:name %) (:search-term @state))
filtered-colors (filter #(or (matches-search (:name %) (:search-term @state))
(matches-search (:content %) (:search-term @state)))
(vals file-colors))
on-search-term-change (fn [event]
@ -168,6 +305,9 @@
(dom/get-value))]
(swap! state assoc :search-term value)))
on-search-clear-click (fn [event]
(swap! state assoc :search-term ""))
on-box-filter-change (fn [event]
(let [value (-> (dom/get-target event)
(dom/get-value)
@ -186,11 +326,18 @@
[:div.tool-window-content
[:div.assets-bar-title (tr "workspace.assets.assets")]
[:input.search-input
{:placeholder (tr "workspace.assets.search")
:type "text"
:value (:search-term @state)
:on-change on-search-term-change}]
[:div.search-block
[:input.search-input
{:placeholder (tr "workspace.assets.search")
:type "text"
:value (:search-term @state)
:on-change on-search-term-change}]
(if (str/empty? (:search-term @state))
[:div.search-icon
i/search]
[:div.search-icon.close
{:on-click on-search-clear-click}
i/close])]
[:select.input-select {:value (:box-filter @state)
:on-change on-box-filter-change}