mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
✨ Simplify changes detection and commit.
With minor code cleaning.
This commit is contained in:
parent
8dd6c8457f
commit
1d726564df
4 changed files with 279 additions and 265 deletions
|
@ -23,7 +23,6 @@
|
|||
[uxbox.main.streams :as ms]
|
||||
[uxbox.main.websockets :as ws]
|
||||
[uxbox.main.workers :as uwrk]
|
||||
[uxbox.util.data :refer [dissoc-in index-of]]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.math :as mth]
|
||||
|
@ -234,6 +233,8 @@
|
|||
(let [file (get-in state [:files file-id])]
|
||||
(assoc state :workspace-file file)))))
|
||||
|
||||
(declare diff-and-commit-changes)
|
||||
|
||||
(defn initialize-page
|
||||
[page-id]
|
||||
(ptk/reify ::initialize-page
|
||||
|
@ -244,6 +245,7 @@
|
|||
(assoc state
|
||||
:workspace-local workspace-default
|
||||
:workspace-data data
|
||||
:workspace-data-prev data
|
||||
:workspace-page page)))
|
||||
|
||||
ptk/WatchEvent
|
||||
|
@ -254,7 +256,7 @@
|
|||
(->> stream
|
||||
(rx/filter #(satisfies? IBatchedChange %))
|
||||
(rx/debounce 500)
|
||||
(rx/map (constantly commit-batched-changes))
|
||||
(rx/map (constantly diff-and-commit-changes))
|
||||
(rx/take-until stoper))))))
|
||||
|
||||
(defn finalize
|
||||
|
@ -268,6 +270,29 @@
|
|||
:workspace-page
|
||||
:workspace-data))))
|
||||
|
||||
(def diff-and-commit-changes
|
||||
(ptk/reify ::diff-and-commit-changes
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [curr (get-in state [:workspace-data :shapes-by-id])
|
||||
prev (get-in state [:workspace-data-prev :shapes-by-id])
|
||||
|
||||
diff (d/diff-maps prev curr)
|
||||
changes (loop [scs (rest diff)
|
||||
sc (first diff)
|
||||
res []]
|
||||
(if (nil? sc)
|
||||
res
|
||||
(let [[_ id shape] sc]
|
||||
(recur (rest scs)
|
||||
(first scs)
|
||||
(conj res {:type :mod-shape
|
||||
:session-id (:session-id state)
|
||||
:operations (d/diff-maps (get prev id) shape)
|
||||
:id id})))))]
|
||||
(when-not (empty? changes)
|
||||
(rx/of (commit-changes changes)))))))
|
||||
|
||||
;; --- Fetch Workspace Users
|
||||
|
||||
(declare users-fetched)
|
||||
|
@ -465,7 +490,7 @@
|
|||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [increase #(nth c/zoom-levels
|
||||
(+ (index-of c/zoom-levels %) 1)
|
||||
(+ (d/index-of c/zoom-levels %) 1)
|
||||
(last c/zoom-levels))]
|
||||
(update-in state [:workspace-local :zoom] (fnil increase 1))))))
|
||||
|
||||
|
@ -474,7 +499,7 @@
|
|||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [decrease #(nth c/zoom-levels
|
||||
(- (index-of c/zoom-levels %) 1)
|
||||
(- (d/index-of c/zoom-levels %) 1)
|
||||
(first c/zoom-levels))]
|
||||
(update-in state [:workspace-local :zoom] (fnil decrease 1))))))
|
||||
|
||||
|
@ -632,11 +657,7 @@
|
|||
(fn [selected]
|
||||
(if (contains? selected id)
|
||||
(disj selected id)
|
||||
(conj selected id)))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (activate-flag :element-options)))))
|
||||
(conj selected id)))))))
|
||||
|
||||
(def deselect-all
|
||||
"Clear all possible state of drawing, edition
|
||||
|
@ -694,16 +715,7 @@
|
|||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [shape-old (get-in state [:workspace-data :shapes-by-id id])
|
||||
shape-new (merge shape-old attrs)
|
||||
operations (d/diff-maps shape-old shape-new)
|
||||
change {:type :mod-shape
|
||||
:session-id (:session-id state)
|
||||
:operations operations
|
||||
:id id}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :shapes-by-id id] shape-new)
|
||||
(update ::batched-changes (fnil conj []) change))))))
|
||||
(update-in state [:workspace-data :shapes-by-id id] merge attrs))))
|
||||
|
||||
;; --- Update Page Options
|
||||
|
||||
|
@ -714,15 +726,7 @@
|
|||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [opts-old (get-in state [:workspace-data :options])
|
||||
opts-new (merge opts-old opts)
|
||||
operations (d/diff-maps opts-old opts-new)
|
||||
change {:type :mod-opts
|
||||
:session-id (:session-id state)
|
||||
:operations operations}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :options] opts-new)
|
||||
(update ::batched-changes (fnil conj []) change))))))
|
||||
(update-in state [:workspace-data :options] merge opts))))
|
||||
|
||||
;; --- Update Selected Shapes attrs
|
||||
|
||||
|
@ -787,16 +791,15 @@
|
|||
;; --- Delete Selected
|
||||
|
||||
(defn impl-dissoc-shape
|
||||
"Given a shape, removes it from the state."
|
||||
[state id]
|
||||
(-> state
|
||||
(update-in [:workspace-data :canvas] (fn [items] (filterv #(not= % id) items)))
|
||||
(update-in [:workspace-data :shapes] (fn [items] (filterv #(not= % id) items)))
|
||||
(update-in [:workspace-data :shapes-by-id] dissoc id)))
|
||||
|
||||
(defn impl-lookup-shape
|
||||
[state id]
|
||||
(get-in state [:workspace-data :shapes-by-id id]))
|
||||
"Given a shape id, removes it from the state."
|
||||
[id]
|
||||
(ptk/reify ::impl-dissoc-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:workspace-data :canvas] (fn [items] (filterv #(not= % id) items)))
|
||||
(update-in [:workspace-data :shapes] (fn [items] (filterv #(not= % id) items)))
|
||||
(update-in [:workspace-data :shapes-by-id] dissoc id)))))
|
||||
|
||||
(def delete-selected
|
||||
"Deselect all and remove all selected shapes."
|
||||
|
@ -813,9 +816,9 @@
|
|||
{:type (if (= type :canvas) :del-canvas :del-shape)
|
||||
:session-id session-id
|
||||
:id id})))]
|
||||
(rx/merge
|
||||
(rx/concat
|
||||
(rx/of deselect-all)
|
||||
(rx/from (map (fn [id] #(impl-dissoc-shape % id)) selected))
|
||||
(rx/from (map impl-dissoc-shape selected))
|
||||
(rx/of (commit-changes changes)))))))
|
||||
|
||||
;; --- Rename Shape
|
||||
|
@ -846,6 +849,7 @@
|
|||
[loc]
|
||||
(us/assert ::direction loc)
|
||||
(ptk/reify ::move-selected-layer
|
||||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (first (get-in state [:workspace-local :selected]))
|
||||
|
@ -860,8 +864,8 @@
|
|||
(let [shapes (get-in state [:workspace-data :shapes])
|
||||
index (case opt
|
||||
:top 0
|
||||
:down (min (- (count shapes) 1) (inc (index-of shapes sid)))
|
||||
:up (max 0 (- (index-of shapes sid) 1))
|
||||
:down (min (- (count shapes) 1) (inc (d/index-of shapes sid)))
|
||||
:up (max 0 (- (d/index-of shapes sid) 1))
|
||||
:bottom (- (count shapes) 1))]
|
||||
(update-in state [:workspace-data :shapes]
|
||||
(fn [items]
|
||||
|
@ -977,16 +981,8 @@
|
|||
xfmt (or (:modifier-mtx shape) (gmt/matrix))
|
||||
shape-old (dissoc shape :modifier-mtx)
|
||||
shape-new (geom/transform shape-old xfmt)
|
||||
shape-new (recalculate-shape-canvas-relation state shape-new)
|
||||
operations (d/diff-maps shape-old shape-new)
|
||||
change {:type :mod-shape
|
||||
:session-id (:session-id state)
|
||||
:operations operations
|
||||
:id id}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :shapes-by-id id] shape-new)
|
||||
(update ::batched-changes (fnil conj []) change))))]
|
||||
|
||||
shape-new (recalculate-shape-canvas-relation state shape-new)]
|
||||
(assoc-in state [:workspace-data :shapes-by-id id] shape-new)))]
|
||||
(ptk/reify ::materialize-temporal-modifier-in-bulk
|
||||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
|
@ -1001,7 +997,9 @@
|
|||
(update [_ state]
|
||||
(let [pid (get-in state [:workspace-page :id])
|
||||
data (get-in state [:pages-data pid])]
|
||||
(update-in state [:pages-data pid] cp/process-changes changes)))
|
||||
(-> state
|
||||
(update-in [:pages-data pid] cp/process-changes changes)
|
||||
(assoc :workspace-data-prev (:workspace-data state)))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
|
@ -1059,7 +1057,7 @@
|
|||
(->> stream
|
||||
(rx/filter #(= % :interrupt))
|
||||
(rx/take 1)
|
||||
(rx/map (fn [_] #(dissoc-in % [:workspace-local :edition])))))))
|
||||
(rx/map (fn [_] #(d/dissoc-in % [:workspace-local :edition])))))))
|
||||
|
||||
;; --- Select for Drawing
|
||||
|
||||
|
@ -1106,16 +1104,7 @@
|
|||
IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [shape-old (get-in state [:workspace-data :shapes-by-id id])
|
||||
shape-new (geom/resize-dim shape-old dimensions)
|
||||
operations (d/diff-maps shape-old shape-new)
|
||||
change {:type :mod-shape
|
||||
:session-id (:session-id state)
|
||||
:operations operations
|
||||
:id id}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-data :shapes-by-id id] shape-new)
|
||||
(update ::batched-changes (fnil conj []) change))))))
|
||||
(update-in state [:workspace-data :shapes-by-id id] geom/resize-dim dimensions))))
|
||||
|
||||
;; --- Shape Proportions
|
||||
|
||||
|
@ -1143,21 +1132,20 @@
|
|||
|
||||
;; --- Path Modifications
|
||||
|
||||
;; TODO: revisit
|
||||
(deftype UpdatePath [id index delta]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace-data :shapes-by-id id :segments index] gpt/add delta)))
|
||||
|
||||
(defn update-path
|
||||
"Update a concrete point in the path shape."
|
||||
[id index delta]
|
||||
{:pre [(uuid? id) (number? index) (gpt/point? delta)]}
|
||||
(UpdatePath. id index delta))
|
||||
(us/assert ::us/uuid id)
|
||||
(us/assert ::us/integer index)
|
||||
(us/assert gpt/point? delta)
|
||||
(ptk/reify ::update-path
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace-data :shapes-by-id id :segments index] gpt/add delta))))
|
||||
|
||||
;; --- Initial Path Point Alignment
|
||||
|
||||
;; TODO: revisit
|
||||
;; TODO: revisit on alignemt refactor
|
||||
(deftype InitialPathPointAlign [id index]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
|
@ -1177,88 +1165,71 @@
|
|||
|
||||
;; --- Shape Visibility
|
||||
|
||||
;; TODO: revisit
|
||||
(defn set-hidden-attr
|
||||
[id value]
|
||||
(declare impl-update-shape-hidden)
|
||||
|
||||
(defn hide-shape
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(us/assert ::us/boolean value)
|
||||
(letfn [(impl-set-hidden [state id]
|
||||
(let [{:keys [type] :as shape} (get-in state [:shapes id])]
|
||||
(as-> state $
|
||||
(assoc-in $ [:shapes id :hidden] value)
|
||||
(if (= :canvas type)
|
||||
(let [shapes (get-in state [:pages (:page shape) :shapes])
|
||||
xform (comp (map #(get-in state [:shapes %]))
|
||||
(filter #(= id (:canvas %)))
|
||||
(map :id))]
|
||||
(reduce impl-set-hidden $ (sequence xform shapes)))
|
||||
$))))]
|
||||
(ptk/reify ::set-hidden-attr
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-set-hidden state id)))))
|
||||
(ptk/reify ::hide-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-update-shape-hidden state id true))))
|
||||
|
||||
(defn show-shape
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::hide-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-update-shape-hidden state id false))))
|
||||
|
||||
(defn- impl-update-shape-hidden
|
||||
[state id hidden?]
|
||||
(let [type (get-in state [:workspace-data :shapes-by-id id :type])
|
||||
state (update-in state [:workspace-data :shapes-by-id id] assoc :hidden hidden?)]
|
||||
(cond-> state
|
||||
(= type :canvas)
|
||||
(update-in [:workspace-data :shapes-by-id]
|
||||
(fn [shapes]
|
||||
(reduce-kv (fn [shapes key {:keys [canvas] :as val}]
|
||||
(cond-> shapes
|
||||
(= id canvas) (update key assoc :hidden hidden?)))
|
||||
shapes
|
||||
shapes))))))
|
||||
|
||||
;; --- Shape Blocking
|
||||
|
||||
;; TODO: revisit
|
||||
(defn set-blocked-attr
|
||||
[id value]
|
||||
(declare impl-update-shape-blocked)
|
||||
|
||||
(defn block-shape
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(us/assert ::us/boolean value)
|
||||
(letfn [(impl-set-blocked [state id]
|
||||
(let [{:keys [type] :as shape} (get-in state [:shapes id])]
|
||||
(as-> state $
|
||||
(assoc-in $ [:shapes id :blocked] value)
|
||||
(if (= :canvas type)
|
||||
(let [shapes (get-in state [:pages (:page shape) :shapes])
|
||||
xform (comp (map #(get-in state [:shapes %]))
|
||||
(filter #(= id (:canvas %)))
|
||||
(map :id))]
|
||||
(reduce impl-set-blocked $ (sequence xform shapes)))
|
||||
$))))]
|
||||
(ptk/reify ::set-blocked-attr
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-set-blocked state id)))))
|
||||
(ptk/reify ::hide-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-update-shape-blocked state id true))))
|
||||
|
||||
;; --- Shape Locking
|
||||
|
||||
;; TODO: revisit
|
||||
(deftype LockShape [id]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(letfn [(mark-locked [state id]
|
||||
(let [shape (get-in state [:shapes id])]
|
||||
(if (= :group (:type shape))
|
||||
(as-> state $
|
||||
(assoc-in $ [:shapes id :locked] true)
|
||||
(reduce mark-locked $ (:items shape)))
|
||||
(assoc-in state [:shapes id :locked] true))))]
|
||||
(mark-locked state id))))
|
||||
|
||||
;; TODO: revisit
|
||||
(defn lock-shape
|
||||
(defn unblock-shape
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(LockShape. id))
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::hide-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(impl-update-shape-blocked state id false))))
|
||||
|
||||
(deftype UnlockShape [id]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(letfn [(mark-unlocked [state id]
|
||||
(let [shape (get-in state [:shapes id])]
|
||||
(if (= :group (:type shape))
|
||||
(as-> state $
|
||||
(assoc-in $ [:shapes id :locked] false)
|
||||
(reduce mark-unlocked $ (:items shape)))
|
||||
(assoc-in state [:shapes id :locked] false))))]
|
||||
(mark-unlocked state id))))
|
||||
|
||||
;; TODO: revisit
|
||||
(defn unlock-shape
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(UnlockShape. id))
|
||||
(defn- impl-update-shape-blocked
|
||||
[state id hidden?]
|
||||
(let [type (get-in state [:workspace-data :shapes-by-id id :type])
|
||||
state (update-in state [:workspace-data :shapes-by-id id] assoc :blocked hidden?)]
|
||||
(cond-> state
|
||||
(= type :canvas)
|
||||
(update-in [:workspace-data :shapes-by-id]
|
||||
(fn [shapes]
|
||||
(reduce-kv (fn [shapes key {:keys [canvas] :as val}]
|
||||
(cond-> shapes
|
||||
(= id canvas) (update key assoc :blocked hidden?)))
|
||||
shapes
|
||||
shapes))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Canvas Interactions
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
(fn [own props]
|
||||
[]
|
||||
(letfn [(on-paste [item]
|
||||
(st/emit! (udw/paste-from-clipboard (:id item)))
|
||||
#_(st/emit! (udw/paste-from-clipboard (:id item)))
|
||||
(udl/close!))
|
||||
(on-close [event]
|
||||
(dom/prevent-default event)
|
||||
|
|
|
@ -2,13 +2,17 @@
|
|||
;; 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/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; Copyright (c) 2015-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.ui.workspace.sidebar.layers
|
||||
(:require
|
||||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
|
@ -16,7 +20,6 @@
|
|||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.main.ui.workspace.sortable :refer [use-sortable]]
|
||||
[uxbox.util.data :refer [classnames enumerate]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :as i18n :refer [t]]))
|
||||
|
||||
|
@ -77,138 +80,163 @@
|
|||
|
||||
(mf/defc layer-item
|
||||
[{:keys [shape selected index] :as props}]
|
||||
;; (prn "layer-item" index (:name shape))
|
||||
(letfn [(toggle-blocking [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [{:keys [id blocked]} shape]
|
||||
(st/emit! (dw/set-blocked-attr id (not blocked)))))
|
||||
(let [selected? (contains? selected (:id shape))
|
||||
|
||||
(toggle-visibility [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [{:keys [id hidden]} shape]
|
||||
(st/emit! (dw/set-hidden-attr id (not hidden)))))
|
||||
toggle-blocking
|
||||
(fn [event]
|
||||
(prn "toggle-blocking" (:blocked shape))
|
||||
(dom/stop-propagation event)
|
||||
(if (:blocked shape)
|
||||
(st/emit! (dw/unblock-shape (:id shape)))
|
||||
(st/emit! (dw/block-shape (:id shape)))))
|
||||
|
||||
(select-shape [event]
|
||||
(dom/prevent-default event)
|
||||
(let [id (:id shape)]
|
||||
(cond
|
||||
(or (:blocked shape)
|
||||
(:hidden shape))
|
||||
nil
|
||||
toggle-visibility
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(if (:hidden shape)
|
||||
(st/emit! (dw/show-shape (:id shape)))
|
||||
(st/emit! (dw/hide-shape (:id shape)))))
|
||||
|
||||
(.-ctrlKey event)
|
||||
(st/emit! (dw/select-shape id))
|
||||
select-shape
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(let [id (:id shape)]
|
||||
(cond
|
||||
(or (:blocked shape)
|
||||
(:hidden shape))
|
||||
nil
|
||||
|
||||
(> (count selected) 1)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id))
|
||||
:else
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id)))))
|
||||
(.-ctrlKey event)
|
||||
(st/emit! (dw/select-shape id))
|
||||
|
||||
(on-drop [item monitor]
|
||||
(st/emit! dw/commit-shape-order-change))
|
||||
(> (count selected) 1)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id))
|
||||
:else
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id)))))
|
||||
|
||||
(on-hover [item monitor]
|
||||
(st/emit! (dw/temporal-shape-order-change (:shape-id item) index)))]
|
||||
(let [selected? (contains? selected (:id shape))
|
||||
[dprops dnd-ref] (use-sortable
|
||||
{:type "layer-item"
|
||||
:data {:shape-id (:id shape)
|
||||
:page-id (:page shape)
|
||||
:index index}
|
||||
:on-hover on-hover
|
||||
:on-drop on-drop})]
|
||||
[:li {:ref dnd-ref
|
||||
:class (classnames
|
||||
:selected selected?
|
||||
:dragging-TODO (:dragging? dprops))}
|
||||
[:div.element-list-body {:class (classnames :selected selected?)
|
||||
:on-click select-shape
|
||||
:on-double-click #(dom/stop-propagation %)}
|
||||
[:div.element-actions
|
||||
[:div.toggle-element {:class (when-not (:hidden shape) "selected")
|
||||
:on-click toggle-visibility}
|
||||
i/eye]
|
||||
[:div.block-element {:class (when (:blocked shape) "selected")
|
||||
:on-click toggle-blocking}
|
||||
i/lock]]
|
||||
[:div.element-icon (element-icon shape)]
|
||||
[:& layer-name {:shape shape}]]])))
|
||||
on-drop
|
||||
(fn [item monitor]
|
||||
(st/emit! dw/commit-shape-order-change))
|
||||
|
||||
on-hover
|
||||
(fn [item monitor]
|
||||
(st/emit! (dw/temporal-shape-order-change (:shape-id item) index)))
|
||||
|
||||
[dprops dnd-ref] (use-sortable
|
||||
{:type "layer-item"
|
||||
:data {:shape-id (:id shape)
|
||||
:page-id (:page shape)
|
||||
:index index}
|
||||
:on-hover on-hover
|
||||
:on-drop on-drop})]
|
||||
[:li {:ref dnd-ref
|
||||
:class (dom/classnames
|
||||
:selected selected?
|
||||
:dragging-TODO (:dragging? dprops))}
|
||||
[:div.element-list-body {:class (dom/classnames :selected selected?)
|
||||
:on-click select-shape
|
||||
:on-double-click #(dom/stop-propagation %)}
|
||||
[:div.element-actions
|
||||
[:div.toggle-element {:class (when-not (:hidden shape) "selected")
|
||||
:on-click toggle-visibility}
|
||||
i/eye]
|
||||
[:div.block-element {:class (when (:blocked shape) "selected")
|
||||
:on-click toggle-blocking}
|
||||
i/lock]]
|
||||
[:div.element-icon (element-icon shape)]
|
||||
[:& layer-name {:shape shape}]]]))
|
||||
|
||||
(mf/defc canvas-item
|
||||
[{:keys [canvas shapes selected index] :as props}]
|
||||
(letfn [(toggle-blocking [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [{:keys [id blocked]} canvas]
|
||||
(st/emit! (dw/set-blocked-attr id (not blocked)))))
|
||||
(let [selected? (contains? selected (:id canvas))
|
||||
local (mf/use-state {:collapsed false})
|
||||
collapsed? (:collapsed @local)
|
||||
|
||||
(toggle-visibility [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [{:keys [id hidden]} canvas]
|
||||
(st/emit! (dw/set-hidden-attr id (not hidden)))))
|
||||
shapes (filter #(= (:canvas (second %)) (:id canvas)) shapes)
|
||||
|
||||
(select-shape [event]
|
||||
(dom/prevent-default event)
|
||||
(let [id (:id canvas)]
|
||||
(cond
|
||||
(or (:blocked canvas)
|
||||
(:hidden canvas))
|
||||
nil
|
||||
toggle-collapse
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! local update :collapsed not))
|
||||
|
||||
(.-ctrlKey event)
|
||||
(st/emit! (dw/select-shape id))
|
||||
toggle-blocking
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(if (:blocked canvas)
|
||||
(st/emit! (dw/unblock-shape (:id canvas)))
|
||||
(st/emit! (dw/block-shape (:id canvas)))))
|
||||
|
||||
(> (count selected) 1)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id))
|
||||
:else
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id)))))
|
||||
toggle-visibility
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(if (:hidden canvas)
|
||||
(st/emit! (dw/show-shape (:id canvas)))
|
||||
(st/emit! (dw/hide-shape (:id canvas)))))
|
||||
|
||||
(on-drop [item monitor]
|
||||
(st/emit! ::dw/page-data-update))
|
||||
select-shape
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(let [id (:id canvas)]
|
||||
(cond
|
||||
(or (:blocked canvas)
|
||||
(:hidden canvas))
|
||||
nil
|
||||
|
||||
(on-hover [item monitor]
|
||||
(st/emit! (dw/change-canvas-order {:id (:canvas-id item)
|
||||
:index index})))]
|
||||
(let [selected? (contains? selected (:id canvas))
|
||||
collapsed? (:collapsed canvas false)
|
||||
(.-ctrlKey event)
|
||||
(st/emit! (dw/select-shape id))
|
||||
|
||||
shapes (filter #(= (:canvas (second %)) (:id canvas)) shapes)
|
||||
[dprops dnd-ref] (use-sortable
|
||||
{:type "canvas-item"
|
||||
:data {:canvas-id (:id canvas)
|
||||
:page-id (:page canvas)
|
||||
:index index}
|
||||
:on-hover on-hover
|
||||
:on-drop on-drop})]
|
||||
[:li.group {:ref dnd-ref
|
||||
:class (classnames
|
||||
:selected selected?
|
||||
:dragging-TODO (:dragging? dprops))}
|
||||
[:div.element-list-body {:class (classnames :selected selected?)
|
||||
:on-click select-shape
|
||||
:on-double-click #(dom/stop-propagation %)}
|
||||
[:div.element-actions
|
||||
[:div.toggle-element {:class (when-not (:hidden canvas) "selected")
|
||||
:on-click toggle-visibility}
|
||||
i/eye]
|
||||
[:div.block-element {:class (when (:blocked canvas) "selected")
|
||||
:on-click toggle-blocking}
|
||||
(> (count selected) 1)
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id))
|
||||
:else
|
||||
(st/emit! dw/deselect-all
|
||||
(dw/select-shape id)))))
|
||||
|
||||
on-drop
|
||||
(fn [item monitor]
|
||||
(st/emit! ::dw/page-data-update))
|
||||
|
||||
on-hover
|
||||
(fn [item monitor]
|
||||
(st/emit! (dw/change-canvas-order {:id (:canvas-id item)
|
||||
:index index})))
|
||||
|
||||
[dprops dnd-ref] (use-sortable
|
||||
{:type "canvas-item"
|
||||
:data {:canvas-id (:id canvas)
|
||||
:page-id (:page canvas)
|
||||
:index index}
|
||||
:on-hover on-hover
|
||||
:on-drop on-drop})]
|
||||
[:li.group {:ref dnd-ref
|
||||
:class (dom/classnames
|
||||
:selected selected?
|
||||
:dragging-TODO (:dragging? dprops))}
|
||||
[:div.element-list-body {:class (dom/classnames :selected selected?)
|
||||
:on-click select-shape
|
||||
:on-double-click #(dom/stop-propagation %)}
|
||||
[:div.element-actions
|
||||
[:div.toggle-element {:class (when-not (:hidden canvas) "selected")
|
||||
:on-click toggle-visibility}
|
||||
i/eye]
|
||||
#_[:div.block-element {:class (when (:blocked canvas) "selected")
|
||||
:on-click toggle-blocking}
|
||||
i/lock]]
|
||||
[:div.element-icon i/folder]
|
||||
[:& layer-name {:shape canvas}]
|
||||
[:span.toggle-content
|
||||
{ ;; :on-click toggle-collapse
|
||||
:class (when-not collapsed? "inverse")}
|
||||
i/arrow-slide]]
|
||||
[:div.element-icon i/folder]
|
||||
[:& layer-name {:shape canvas}]
|
||||
[:span.toggle-content
|
||||
{:on-click toggle-collapse
|
||||
:class (when-not collapsed? "inverse")}
|
||||
i/arrow-slide]]
|
||||
(when-not collapsed?
|
||||
[:ul
|
||||
(for [[index shape] (reverse shapes)]
|
||||
[:& layer-item {:shape shape
|
||||
:selected selected
|
||||
:index index
|
||||
:key (:id shape)}])]])))
|
||||
:key (:id shape)}])])]))
|
||||
|
||||
;; --- Layers List
|
||||
|
||||
|
@ -245,15 +273,15 @@
|
|||
|
||||
canvas (->> (:canvas data)
|
||||
(map #(get shapes-by-id %))
|
||||
(enumerate))
|
||||
(d/enumerate))
|
||||
|
||||
shapes (->> (:shapes data)
|
||||
(map #(get shapes-by-id %)))
|
||||
|
||||
all-shapes (enumerate shapes)
|
||||
all-shapes (d/enumerate shapes)
|
||||
unc-shapes (->> shapes
|
||||
(filter #(nil? (:canvas %)))
|
||||
(enumerate))]
|
||||
(d/enumerate))]
|
||||
|
||||
[:div#layers.tool-window
|
||||
[:div.tool-window-bar
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
;; 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) 2015-2016 Andrey Antukh <niwi@niwi.nz>
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.util.dom
|
||||
(:require [goog.dom :as dom]))
|
||||
(:require
|
||||
[goog.dom :as dom]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
;; --- Deprecated methods
|
||||
|
||||
|
@ -22,6 +27,16 @@
|
|||
[e]
|
||||
(.-target e))
|
||||
|
||||
(defn classnames
|
||||
[& params]
|
||||
(assert (even? (count params)))
|
||||
(str/join " " (reduce (fn [acc [k v]]
|
||||
(if (true? v)
|
||||
(conj acc (name k))
|
||||
acc))
|
||||
[]
|
||||
(partition 2 params))))
|
||||
|
||||
;; --- New methods
|
||||
|
||||
(defn get-element-by-class
|
||||
|
|
Loading…
Add table
Reference in a new issue