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