🎉 Namespace workspace data with page id.

This commit is contained in:
Andrey Antukh 2020-03-16 23:43:14 +01:00 committed by Alonso Torres
parent 38f675d7f9
commit fc734328cb
13 changed files with 419 additions and 440 deletions

View file

@ -112,17 +112,20 @@
(s/def ::attr keyword?) (s/def ::attr keyword?)
(s/def ::val any?) (s/def ::val any?)
(s/def ::parent-id uuid?)
(s/def ::frame-id uuid?) (s/def ::frame-id uuid?)
(s/def ::loc #{:top :bottom :up :down})
(defmulti operation-spec-impl :type) (defmulti operation-spec-impl :type)
(defmethod operation-spec-impl :set [_] (defmethod operation-spec-impl :set [_]
(s/keys :req-un [::attr ::val])) (s/keys :req-un [::attr ::val]))
(defmethod operation-spec-impl :order [_] (defmethod operation-spec-impl :abs-order [_]
(s/keys :req-un [::id ::index])) (s/keys :req-un [::id ::index]))
(defmethod operation-spec-impl :rel-order [_]
(s/keys :req-un [::id ::loc]))
(s/def ::operation (s/multi-spec operation-spec-impl :type)) (s/def ::operation (s/multi-spec operation-spec-impl :type))
(s/def ::operations (s/coll-of ::operation)) (s/def ::operations (s/coll-of ::operation))
@ -226,7 +229,7 @@
(dissoc shape attr) (dissoc shape attr)
(assoc shape attr val)))) (assoc shape attr val))))
(defmethod process-operation :order (defmethod process-operation :abs-order
[obj {:keys [id index]}] [obj {:keys [id index]}]
(assert (vector? (:shapes obj)) ":shapes should be a vector") (assert (vector? (:shapes obj)) ":shapes should be a vector")
(update obj :shapes (fn [items] (update obj :shapes (fn [items]
@ -234,6 +237,24 @@
(split-at index))] (split-at index))]
(vec (concat b [id] a)))))) (vec (concat b [id] a))))))
(defmethod process-operation :rel-order
[obj {:keys [id loc] :as change}]
(assert (vector? (:shapes obj)) ":shapes should be a vector")
(let [shapes (:shapes obj)
cindex (d/index-of shapes id)
nindex (case loc
:top 0
:down (min (- (count shapes) 1) (inc cindex))
:up (max 0 (- cindex 1))
:bottom (- (count shapes) 1))]
(update obj :shapes
(fn [shapes]
(let [[fst snd] (->> (remove #(= % id) shapes)
(split-at nindex))]
(d/concat [] fst [id] snd))))))
(defmethod process-operation :default (defmethod process-operation :default
[shape op] [shape op]
(ex/raise :type :operation-not-implemented (ex/raise :type :operation-not-implemented

View file

@ -48,7 +48,7 @@ This is a potential list of persistent ops:
{:type :mov-obj {:type :mov-obj
:id <uuid> :id <uuid>
:dest <uuid>} :frame-id <uuid>}
{:type :del-obj {:type :del-obj
:id <uuid>} :id <uuid>}
@ -61,9 +61,13 @@ This is a potential list of operations:
:attr <any> :attr <any>
:val <any>} :val <any>}
{:type :mov {:type :abs-order
:id <uuid> :id <uuid>
:index <int>} :index <int>}
{:type :rel-order
:id <uuid>
:loc <one-of:up,down,top,bottom>}
``` ```

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,9 @@
(l/derive st/state))) (l/derive st/state)))
(def workspace-data (def workspace-data
(-> (l/key :workspace-data) (-> (l/lens (fn [state]
(let [page-id (get-in state [:workspace-page :id])]
(get-in state [:workspace-data page-id]))))
(l/derive st/state))) (l/derive st/state)))
(def selected-shapes (def selected-shapes
@ -68,14 +70,6 @@
(l/derive workspace-local))) (l/derive workspace-local)))
;; DEPRECATED ;; DEPRECATED
(def flags
(-> (l/key :flags)
(l/derive workspace-local)))
(def selected-flags
(-> (l/key :flags)
(l/derive workspace-local)))
(def selected-zoom (def selected-zoom
(-> (l/key :zoom) (-> (l/key :zoom)
(l/derive workspace-local))) (l/derive workspace-local)))

View file

@ -35,26 +35,30 @@
(let [flags (get-in state [:workspace-local :flags]) (let [flags (get-in state [:workspace-local :flags])
selected (get-in state [:workspace-local :selected]) selected (get-in state [:workspace-local :selected])
stoper (rx/filter uws/mouse-up? stream) stoper (rx/filter uws/mouse-up? stream)
position @uws/mouse-position] zero-point? #(= % (gpt/point 0 0))
position @uws/mouse-position
deltas (atom 0)]
(rx/concat (rx/concat
(->> (uws/mouse-position-deltas position) (->> (uws/mouse-position-deltas position)
(rx/filter (complement zero-point?))
(rx/tap #(swap! deltas inc))
(rx/map #(dw/apply-displacement-in-bulk selected %)) (rx/map #(dw/apply-displacement-in-bulk selected %))
(rx/take-until stoper)) (rx/take-until stoper))
(rx/of (dw/materialize-displacement-in-bulk selected) (rx/of (dw/materialize-displacement-in-bulk selected)))))))
::dw/page-data-update))))))
(def start-move-frame (def start-move-frame
(ptk/reify ::start-move-selected (ptk/reify ::start-move-frame
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [flags (get-in state [:workspace-local :flags]) (let [flags (get-in state [:workspace-local :flags])
selected (get-in state [:workspace-local :selected]) selected (get-in state [:workspace-local :selected])
stoper (rx/filter uws/mouse-up? stream) stoper (rx/filter uws/mouse-up? stream)
zero-point? #(= % (gpt/point 0 0))
frame-id (first selected) frame-id (first selected)
position @uws/mouse-position] position @uws/mouse-position]
(rx/concat (rx/concat
(->> (uws/mouse-position-deltas position) (->> (uws/mouse-position-deltas position)
(rx/filter (complement zero-point?))
(rx/map #(dw/apply-frame-displacement frame-id %)) (rx/map #(dw/apply-frame-displacement frame-id %))
(rx/take-until stoper)) (rx/take-until stoper))
(rx/of (dw/materialize-frame-displacement frame-id))))))) (rx/of (dw/materialize-frame-displacement frame-id)))))))

View file

@ -58,9 +58,8 @@
(scroll/scroll-to-point dom mouse-point scroll-position)))) (scroll/scroll-to-point dom mouse-point scroll-position))))
(mf/defc workspace-content (mf/defc workspace-content
[{:keys [page file flags] :as params}] [{:keys [page file layout] :as params}]
(let [frame (mf/use-ref nil) (let [frame (mf/use-ref nil)
layout (mf/deref refs/workspace-layout)
left-sidebar? (not (empty? (keep layout [:layers :sitemap left-sidebar? (not (empty? (keep layout [:layers :sitemap
:document-history]))) :document-history])))
right-sidebar? (not (empty? (keep layout [:icons :drawtools right-sidebar? (not (empty? (keep layout [:icons :drawtools
@ -87,7 +86,7 @@
[:& vertical-rule]]) [:& vertical-rule]])
[:section.workspace-viewport {:id "workspace-viewport" :ref frame} [:section.workspace-viewport {:id "workspace-viewport" :ref frame}
[:& viewport {:page page}]]] [:& viewport {:page page :file file}]]]
;; Aside ;; Aside
(when left-sidebar? (when left-sidebar?
@ -95,6 +94,7 @@
(when right-sidebar? (when right-sidebar?
[:& right-sidebar {:page page :layout layout}])]])) [:& right-sidebar {:page page :layout layout}])]]))
(mf/defc workspace (mf/defc workspace
[{:keys [file-id page-id] :as props}] [{:keys [file-id page-id] :as props}]
(mf/use-effect (mf/use-effect
@ -109,6 +109,9 @@
(st/emit! (dw/initialize-ws file-id)) (st/emit! (dw/initialize-ws file-id))
#(st/emit! (dw/finalize-ws file-id)))}) #(st/emit! (dw/finalize-ws file-id)))})
(mf/use-effect
{:fn #(st/emit! dw/initialize-layout)})
(mf/use-effect (mf/use-effect
{:deps (mf/deps file-id page-id) {:deps (mf/deps file-id page-id)
:fn (fn [] :fn (fn []
@ -116,11 +119,15 @@
#(rx/cancel! sub)))}) #(rx/cancel! sub)))})
(let [file (mf/deref refs/workspace-file) (let [file (mf/deref refs/workspace-file)
page (mf/deref refs/workspace-page)] page (mf/deref refs/workspace-page)
layout (mf/deref refs/workspace-layout)]
[:> rdnd/provider {:backend rdnd/html5} [:> rdnd/provider {:backend rdnd/html5}
[:& messages-widget] [:& messages-widget]
[:& header {:page page}] [:& header {:page page
:file file
:layout layout}]
(when page (when page
[:& workspace-content {:file file [:& workspace-content {:file file
:page page}])])) :page page
:layout layout}])]))

View file

@ -53,7 +53,7 @@
:fill-opacity 0 :fill-opacity 0
:segments []} :segments []}
{:type :frame {:type :frame
:name "Canvas"} :name "Artboard"}
{:type :curve {:type :curve
:name "Path" :name "Path"
:stroke-style :solid :stroke-style :solid

View file

@ -63,19 +63,15 @@
;; --- Header Component ;; --- Header Component
(mf/defc header (mf/defc header
[{:keys [page] :as props}] [{:keys [page file layout] :as props}]
(let [toggle #(st/emit! (dw/toggle-flag %)) (let [toggle-layout #(st/emit! (dw/toggle-layout-flag %))
toggle-layout #(st/emit! (dw/toggle-layout-flag %)) on-undo #(st/emit! (udu/undo))
on-undo (constantly nil) on-redo #(st/emit! (udu/redo))
on-redo (constantly nil)
on-image #(modal/show! import-image-modal {}) on-image #(modal/show! import-image-modal {})
;;on-download #(udl/open! :download) ;;on-download #(udl/open! :download)
layout (mf/deref refs/workspace-layout)
flags (mf/deref refs/selected-flags)
file (mf/deref refs/workspace-file)
selected-drawtool (mf/deref refs/selected-drawing-tool) selected-drawtool (mf/deref refs/selected-drawing-tool)
select-drawtool #(st/emit! :interrupt select-drawtool #(st/emit! :interrupt
(dw/deactivate-ruler) #_(dw/deactivate-ruler)
(dw/select-for-drawing %))] (dw/select-for-drawing %))]
[:header#workspace-bar.workspace-bar [:header#workspace-bar.workspace-bar
@ -173,13 +169,13 @@
i/ruler] i/ruler]
[:li.tooltip.tooltip-bottom [:li.tooltip.tooltip-bottom
{:alt (tr "workspace.header.grid") {:alt (tr "workspace.header.grid")
:class (when (contains? flags :grid) "selected") :class (when (contains? layout :grid) "selected")
:on-click (partial toggle :grid)} :on-click (partial toggle-layout :grid)}
i/grid] i/grid]
[:li.tooltip.tooltip-bottom [:li.tooltip.tooltip-bottom
{:alt (tr "workspace.header.grid-snap") {:alt (tr "workspace.header.grid-snap")
:class (when (contains? flags :grid-snap) "selected") :class (when (contains? layout :grid-snap) "selected")
:on-click (partial toggle :grid-snap)} :on-click (partial toggle-layout :grid-snap)}
i/grid-snap]]] i/grid-snap]]]
;; [:li.tooltip.tooltip-bottom ;; [:li.tooltip.tooltip-bottom
;; {:alt (tr "header.align")} ;; {:alt (tr "header.align")}

View file

@ -39,10 +39,10 @@
:ctrl+t #(st/emit! (dw/select-for-drawing :text)) :ctrl+t #(st/emit! (dw/select-for-drawing :text))
:esc #(st/emit! :interrupt dw/deselect-all) :esc #(st/emit! :interrupt dw/deselect-all)
:delete #(st/emit! dw/delete-selected) :delete #(st/emit! dw/delete-selected)
:ctrl+up #(st/emit! (dw/order-selected-shapes :up)) :ctrl+up #(st/emit! (dw/vertical-order-selected :up))
:ctrl+down #(st/emit! (dw/order-selected-shapes :down)) :ctrl+down #(st/emit! (dw/vertical-order-selected :down))
:ctrl+shift+up #(st/emit! (dw/order-selected-shapes :top)) :ctrl+shift+up #(st/emit! (dw/vertical-order-selected :top))
:ctrl+shift+down #(st/emit! (dw/order-selected-shapes :bottom)) :ctrl+shift+down #(st/emit! (dw/vertical-order-selected :bottom))
:shift+up #(st/emit! (dw/move-selected :up true)) :shift+up #(st/emit! (dw/move-selected :up true))
:shift+down #(st/emit! (dw/move-selected :down true)) :shift+down #(st/emit! (dw/move-selected :down true))
:shift+right #(st/emit! (dw/move-selected :right true)) :shift+right #(st/emit! (dw/move-selected :right true))
@ -66,7 +66,7 @@
;; Initialize shortcut listener. ;; Initialize shortcut listener.
(let [event KeyboardShortcutHandler.EventType.SHORTCUT_TRIGGERED (let [event KeyboardShortcutHandler.EventType.SHORTCUT_TRIGGERED
callback #(sink (keyword (.-identifier %))) callback #(sink (keyword (.-identifier %)))
key (events/listen handler event callback)] key (events/listen handler event callback)]
(fn [] (fn []
(events/unlistenByKey key) (events/unlistenByKey key)

View file

@ -75,7 +75,8 @@
[props] [props]
(let [history (mf/deref refs/history) (let [history (mf/deref refs/history)
section (mf/use-state :main) section (mf/use-state :main)
close #(st/emit! (dw/toggle-flag :history)) ;; close #(st/emit! (dw/toggle-flag :history))
close (constantly nil)
main? (= @section :main) main? (= @section :main)
pinned? (= @section :pinned) pinned? (= @section :pinned)
show-main #(st/emit! (udh/select-section :main)) show-main #(st/emit! (udh/select-section :main))

View file

@ -118,14 +118,14 @@
(st/emit! dw/deselect-all (st/emit! dw/deselect-all
(dw/select-shape id))))) (dw/select-shape id)))))
on-drop
(fn [item monitor]
(st/emit! (dw/commit-shape-order-change (:obj-id item))))
on-hover on-hover
(fn [item monitor] (fn [item monitor]
(st/emit! (dw/shape-order-change (:obj-id item) index))) (st/emit! (dw/shape-order-change (:obj-id item) index)))
on-drop
(fn [item monitor]
(st/emit! (dw/commit-shape-order-change (:obj-id item))))
[dprops dnd-ref] (use-sortable [dprops dnd-ref] (use-sortable
{:type (str "layer-item" (:frame-id item)) {:type (str "layer-item" (:frame-id item))
:data {:obj-id (:id item) :data {:obj-id (:id item)

View file

@ -40,10 +40,10 @@
nil)]) nil)])
(mf/defc shape-options-wrapper (mf/defc shape-options-wrapper
[{:keys [shape-id] :as props}] [{:keys [shape-id page-id] :as props}]
(let [shape-iref (mf/use-memo (let [shape-iref (mf/use-memo
{:deps (mf/deps shape-id) {:deps (mf/deps shape-id page-id)
:fn #(-> (l/in [:workspace-data :objects shape-id]) :fn #(-> (l/in [:workspace-data page-id :objects shape-id])
(l/derive st/state))}) (l/derive st/state))})
shape (mf/deref shape-iref)] shape (mf/deref shape-iref)]
[:& shape-options {:shape shape}])) [:& shape-options {:shape shape}]))
@ -61,5 +61,6 @@
[:div.tool-window-content [:div.tool-window-content
[:div.element-options [:div.element-options
(if (= (count selected) 1) (if (= (count selected) 1)
[:& shape-options-wrapper {:shape-id (first selected)}] [:& shape-options-wrapper {:shape-id (first selected)
:page-id (:id page)}]
[:& page/options {:page page}])]]])) [:& page/options {:page page}])]]]))

View file

@ -9,7 +9,9 @@
(:require (:require
[beicon.core :as rx] [beicon.core :as rx]
[goog.events :as events] [goog.events :as events]
[goog.object :as gobj]
[potok.core :as ptk] [potok.core :as ptk]
[lentes.core :as l]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[uxbox.builtins.icons :as i] [uxbox.builtins.icons :as i]
[uxbox.main.constants :as c] [uxbox.main.constants :as c]
@ -141,12 +143,28 @@
;; --- Viewport ;; --- Viewport
(declare remote-user-cursors) (declare remote-user-cursors)
(declare frames)
(mf/defc frame-and-shapes (defn- build-workspace-data-iref
{:wrap [mf/wrap-memo]} [page-id]
(-> (l/in [:workspace-data page-id])
(l/derive st/state)))
(mf/defrc frames-wrapper
;; {:wrap [mf/wrap-memo]}
[props] [props]
(let [data (mf/deref refs/workspace-data) (let [page (gobj/get props "page")
objects (:objects data) page-id (:id page)
data-ref (mf/use-memo {:fn #(-> (l/in [:workspace-data page-id])
(l/derive st/state))
:deps (mf/deps page-id)})
data (mf/deref data-ref)]
[:& frames {:data data}]))
(mf/defc frames
{:wrap [mf/wrap-memo]}
[{:keys [data] :as props}]
(let [objects (:objects data)
root (get objects uuid/zero) root (get objects uuid/zero)
shapes (->> (:shapes root) shapes (->> (:shapes root)
(map #(get objects %)))] (map #(get objects %)))]
@ -298,7 +316,7 @@
;; {:id "foobar" ;; {:id "foobar"
;; :on-render (perf/react-on-profile)} ;; :on-render (perf/react-on-profile)}
;; [:& frame-and-shapes]] ;; [:& frame-and-shapes]]
[:& frame-and-shapes] [:& frames-wrapper {:page page}]
(when (seq selected) (when (seq selected)
[:& selection-handlers {:selected selected [:& selection-handlers {:selected selected