diff --git a/frontend/src/uxbox/main.cljs b/frontend/src/uxbox/main.cljs index 552c10b8d..9ce3a2057 100644 --- a/frontend/src/uxbox/main.cljs +++ b/frontend/src/uxbox/main.cljs @@ -6,6 +6,7 @@ (ns ^:figwheel-hooks uxbox.main (:require + [cljs.spec.alpha :as s] [rumext.alpha :as mf] [uxbox.main.data.auth :refer [logout]] [uxbox.main.data.users :as udu] @@ -27,6 +28,7 @@ ;; --- i18n (declare reinit) +(s/check-asserts true) (i18n/update-locales! (fn [locales] (-> locales diff --git a/frontend/src/uxbox/main/data/icons.cljs b/frontend/src/uxbox/main/data/icons.cljs index 99c813f98..136a5c5e3 100644 --- a/frontend/src/uxbox/main/data/icons.cljs +++ b/frontend/src/uxbox/main/data/icons.cljs @@ -20,29 +20,23 @@ ;; --- Initialize -(defrecord Initialize [] - ptk/UpdateEvent - (update [_ state] - (assoc-in state [:dashboard :icons] {:selected #{}}))) - -(defn initialize - [] - (Initialize.)) +(def initialize + (ptk/reify ::initialize + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:dashboard :icons] {:selected #{}})))) ;; --- Select a Collection -(defrecord SelectCollection [type id] - ptk/WatchEvent - (watch [_ state stream] - (rx/of (r/navigate :dashboard/icons - {:type type :id id})))) - (defn select-collection ([type] (select-collection type nil)) ([type id] {:pre [(keyword? type)]} - (SelectCollection. type id))) + (ptk/reify ::select-collection + ptk/WatchEvent + (watch [_ state stream] + (rx/of (r/navigate :dashboard/icons {:type type :id id})))))) ;; --- Collections Fetched @@ -61,6 +55,10 @@ state items)))) +(defn collections-fetched? + [v] + (= ::collections-fetched (ptk/type v))) + ;; --- Fetch Collections (def fetch-collections @@ -72,48 +70,37 @@ ;; --- Collection Created -(defrecord CollectionCreated [item] - ptk/UpdateEvent - (update [_ state] - (let [{:keys [id] :as item} (assoc item :type :own)] - (update state :icons-collections assoc id item))) - - ptk/WatchEvent - (watch [_ state stream] - (rx/of (select-collection :own (:id item))))) - (defn collection-created [item] - (CollectionCreated. item)) + (ptk/reify ::collection-created + ptk/UpdateEvent + (update [_ state] + (let [{:keys [id] :as item} (assoc item :type :own)] + (update state :icons-collections assoc id item))) + + ptk/WatchEvent + (watch [_ state stream] + (rx/of (select-collection :own (:id item)))))) ;; --- Create Collection -(defrecord CreateCollection [] - ptk/WatchEvent - (watch [_ state s] - (let [name (tr "ds.default-library-title" (gensym "c")) - data {:name name}] - (->> (rp/mutation! :create-icons-collection data) - (rx/map collection-created))))) - -(defn create-collection - [] - (CreateCollection.)) - -(defn collections-fetched? - [v] - (= ::collections-fetched (ptk/type v))) +(def create-collection + (ptk/reify ::create-collection + ptk/WatchEvent + (watch [_ state s] + (let [name (tr "ds.default-library-title" (gensym "c")) + data {:name name}] + (->> (rp/mutation! :create-icons-collection data) + (rx/map collection-created)))))) ;; --- Collection Updated -(defrecord CollectionUpdated [item] - ptk/UpdateEvent - (update [_ state] - (update-in state [:icons-collections (:id item)] merge item))) - (defn collection-updated [item] - (CollectionUpdated. item)) + (ptk/reify ::collection-updated + ptk/UpdateEvent + (update [_ state] + (update-in state [:icons-collections (:id item)] merge item)))) ;; --- Update Collection diff --git a/frontend/src/uxbox/main/data/images.cljs b/frontend/src/uxbox/main/data/images.cljs index 42636a447..39181633b 100644 --- a/frontend/src/uxbox/main/data/images.cljs +++ b/frontend/src/uxbox/main/data/images.cljs @@ -245,31 +245,17 @@ {:pre [(or (uuid? id) (nil? id)) (fn? on-uploaded)]} (CreateImages. id files on-uploaded))) -;; --- Image Updated - -(defrecord ImagePersisted [id data] - ptk/UpdateEvent - (update [_ state] - (assoc-in state [:images id] data))) - -(defn image-persisted - [{:keys [id] :as data}] - {:pre [(map? data) (uuid? id)]} - (ImagePersisted. id data)) - ;; --- Update Image -(defrecord PersistImage [id] - ptk/WatchEvent - (watch [_ state stream] - (let [data (get-in state [:images id])] - (->> (rp/mutation! :update-image data) - (rx/map image-persisted))))) - (defn persist-image [id] {:pre [(uuid? id)]} - (PersistImage. id)) + (ptk/reify ::persist-image + ptk/WatchEvent + (watch [_ state stream] + (let [data (get-in state [:images id])] + (->> (rp/mutation! :update-image data) + (rx/ignore)))))) ;; --- Images Fetched diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index ed705d38a..849bb5b12 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -378,38 +378,38 @@ (reduce ds/dissoc-shape state (map #(get-in state [:shapes %]) ids))))) -(defrecord SelectShape [id] - ptk/UpdateEvent - (update [_ state] - (let [pid (get-in state [:workspace :current]) - selected (get-in state [:workspace pid :selected])] - (if (contains? selected id) - (update-in state [:workspace pid :selected] disj id) - (update-in state [:workspace pid :selected] conj id)))) - - ptk/WatchEvent - (watch [_ state s] - (rx/of (activate-flag :element-options)))) - (defn select-shape "Mark a shape selected for drawing." [id] - {:pre [(uuid? id)]} - (SelectShape. id)) + (s/assert ::us/uuid id) + (ptk/reify ::select-shape + ptk/UpdateEvent + (update [_ state] + (prn "select-shape$update" id) + (let [pid (get-in state [:workspace :current]) + selected (get-in state [:workspace pid :selected])] + (update-in state [:workspace pid :selected] + (fn [selected] + (if (contains? selected id) + (disj selected id) + (conj selected id)))))) -(defrecord DeselectAll [] - ptk/UpdateEvent - (update [_ state] - (let [pid (get-in state [:workspace :current])] - (update-in state [:workspace pid] #(-> % - (assoc :selected #{}) - (dissoc :selected-canvas)))))) + ptk/WatchEvent + (watch [_ state s] + (prn "select-shape$watch" id) + (rx/of (activate-flag :element-options))))) -(defn deselect-all +(def deselect-all "Clear all possible state of drawing, edition or any similar action taken by the user." - [] - (DeselectAll.)) + (ptk/reify ::deselect-all + ptk/UpdateEvent + (update [_ state] + (prn "deselect-all") + (let [pid (get-in state [:workspace :current])] + (update-in state [:workspace pid] #(-> % + (assoc :selected #{}) + (dissoc :selected-canvas))))))) ;; --- Select First Shape @@ -1030,7 +1030,7 @@ (rx/buffer-time 300) (rx/map #(into* #{} %)) (rx/filter (complement empty?)) - (rx/tap #(prn "changed" %)) + ;; (rx/tap #(prn "changed" %)) (rx/mapcat (fn [items] (rx/from-coll (map rehash-shape-relationship items)))) (rx/take-until stoper))))))) diff --git a/frontend/src/uxbox/main/ui/dashboard/icons.cljs b/frontend/src/uxbox/main/ui/dashboard/icons.cljs index 32d80e077..25f76195c 100644 --- a/frontend/src/uxbox/main/ui/dashboard/icons.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/icons.cljs @@ -425,7 +425,7 @@ :else (first colls)) id (:id selected-coll)] (mf/use-effect #(st/emit! di/fetch-collections)) - (mf/use-effect {:fn #(st/emit! (di/initialize) + (mf/use-effect {:fn #(st/emit! di/initialize (di/fetch-icons id)) :deps #js [id type]}) diff --git a/frontend/src/uxbox/main/ui/shapes/canvas.cljs b/frontend/src/uxbox/main/ui/shapes/canvas.cljs index 13c58f551..9f20c76e2 100644 --- a/frontend/src/uxbox/main/ui/shapes/canvas.cljs +++ b/frontend/src/uxbox/main/ui/shapes/canvas.cljs @@ -32,7 +32,7 @@ shape (merge canvas-default-props shape)] (letfn [(on-double-click [event] (dom/prevent-default event) - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape (:id shape))))] [:g.shape {:class (when selected? "selected") :on-double-click on-double-click diff --git a/frontend/src/uxbox/main/ui/shapes/common.cljs b/frontend/src/uxbox/main/ui/shapes/common.cljs index 7da6d3823..e43629017 100644 --- a/frontend/src/uxbox/main/ui/shapes/common.cljs +++ b/frontend/src/uxbox/main/ui/shapes/common.cljs @@ -4,6 +4,11 @@ ;; ;; Copyright (c) 2016-2019 Andrey Antukh +;; TODO: we need to consider moving this under uxbox.ui.workspace +;; namespace because this is logic only related to workspace +;; manipulation. Staying here causes a lot of confusion and finding +;; this code is also very difficult. + (ns uxbox.main.ui.shapes.common (:require [potok.core :as ptk] @@ -13,26 +18,29 @@ [uxbox.main.store :as st] [uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.workspace.streams :as uws] + [uxbox.main.workers :as uwrk] [uxbox.util.geom.matrix :as gmt] + [uxbox.util.geom.point :as gpt] [uxbox.util.dom :as dom])) ;; --- Shape Movement (by mouse) (def start-move-selected - (reify + (ptk/reify ::start-move-selected ptk/WatchEvent (watch [_ state stream] (let [pid (get-in state [:workspace :current]) flags (get-in state [:workspace pid :flags]) selected (get-in state [:workspace pid :selected]) - stoper (rx/filter uws/mouse-up? stream)] + stoper (rx/filter uws/mouse-up? stream) + position @uws/mouse-position] (rx/concat (when (refs/alignment-activated? flags) (rx/of (dw/initial-selection-align selected))) - (->> uws/mouse-position-deltas + (->> (uws/mouse-position-deltas position) (rx/map #(dw/apply-temporal-displacement-in-bulk selected %)) (rx/take-until stoper)) - (rx/of (dw/materialize-current-modifier-in-bulk selected))))))) + (rx/of (dw/materialize-current-modifier-in-bulk selected))))))) (defn on-mouse-down [event {:keys [id type] :as shape} selected] @@ -51,7 +59,7 @@ (and (not selected?) (empty? selected)) (do (dom/stop-propagation event) - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id) start-move-selected)) @@ -60,7 +68,7 @@ (dom/stop-propagation event) (if (kbd/shift? event) (st/emit! (dw/select-shape id)) - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id) start-move-selected))) :else diff --git a/frontend/src/uxbox/main/ui/workspace/selection.cljs b/frontend/src/uxbox/main/ui/workspace/selection.cljs index 85806b2c2..7856fefe8 100644 --- a/frontend/src/uxbox/main/ui/workspace/selection.cljs +++ b/frontend/src/uxbox/main/ui/workspace/selection.cljs @@ -154,10 +154,10 @@ [{:keys [shape modifiers zoom] :as props}] (letfn [(on-mouse-down [event index] (dom/stop-propagation event) - ;; TODO: this need code ux refactor (let [stoper (get-edition-stream-stoper) - stream (rx/take-until stoper ws/mouse-position-deltas)] + stream (->> (ws/mouse-position-deltas @ws/mouse-position) + (rx/take-until stoper))] (when @refs/selected-alignment (st/emit! (dw/initial-path-point-align (:id shape) index))) (rx/subscribe stream #(on-handler-move % index)))) diff --git a/frontend/src/uxbox/main/ui/workspace/shortcuts.cljs b/frontend/src/uxbox/main/ui/workspace/shortcuts.cljs index 71979e969..befba6acd 100644 --- a/frontend/src/uxbox/main/ui/workspace/shortcuts.cljs +++ b/frontend/src/uxbox/main/ui/workspace/shortcuts.cljs @@ -39,7 +39,7 @@ :ctrl+b #(st/emit! (dw/select-for-drawing :rect)) :ctrl+e #(st/emit! (dw/select-for-drawing :circle)) :ctrl+t #(st/emit! (dw/select-for-drawing :text)) - :esc #(st/emit! (dw/deselect-all)) + :esc #(st/emit! dw/deselect-all) :delete #(st/emit! dw/delete-selected) :ctrl+up #(st/emit! (dw/order-selected-shapes :up)) :ctrl+down #(st/emit! (dw/order-selected-shapes :down)) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs index 6dcb82d35..6747fb474 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/drawtools.cljs @@ -57,7 +57,7 @@ (dw/select-for-drawing tool))) (toggle-ruler [event] (st/emit! (dw/select-for-drawing nil) - (dw/deselect-all) + dw/deselect-all (dw/toggle-ruler)))] (let [selected (mf/deref refs/selected-drawing-tool) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs index ba1762288..dba0e52da 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/layers.cljs @@ -100,10 +100,10 @@ (st/emit! (dw/select-shape id)) (> (count selected) 1) - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id)) :else - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id))))) (on-drop [item monitor] @@ -161,10 +161,10 @@ (st/emit! (dw/select-shape id)) (> (count selected) 1) - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id)) :else - (st/emit! (dw/deselect-all) + (st/emit! dw/deselect-all (dw/select-shape id))))) (on-drop [item monitor] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs index 83480a100..438995fd2 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/sitemap.cljs @@ -92,7 +92,6 @@ (mf/defc sitemap-toolbox [{:keys [project-id current-page-id] :as props}] - (prn "sitemap-toolbox" props) (let [project-iref (mf/use-memo {:deps #js [project-id] :fn #(-> (l/in [:projects project-id]) (l/derive st/state))}) diff --git a/frontend/src/uxbox/main/ui/workspace/streams.cljs b/frontend/src/uxbox/main/ui/workspace/streams.cljs index 4717bcf3c..0f016a160 100644 --- a/frontend/src/uxbox/main/ui/workspace/streams.cljs +++ b/frontend/src/uxbox/main/ui/workspace/streams.cljs @@ -94,9 +94,11 @@ (rx/subscribe-with ob sub) sub)) -(defonce mouse-position-deltas - (->> mouse-position - (rx/sample 10) + +(defn mouse-position-deltas + [current] + (->> (rx/concat (rx/of current) + (rx/sample 10 mouse-position)) (rx/map #(gpt/divide % @refs/selected-zoom)) (rx/mapcat (fn [point] (if @refs/selected-alignment @@ -104,8 +106,7 @@ (rx/of point)))) (rx/buffer 2 1) (rx/map (fn [[old new]] - (gpt/subtract new old))) - (rx/share))) + (gpt/subtract new old))))) (defonce viewport-scroll (let [sub (rx/behavior-subject nil) diff --git a/frontend/src/uxbox/main/ui/workspace/viewport.cljs b/frontend/src/uxbox/main/ui/workspace/viewport.cljs index c9110b535..f5ed5a4ba 100644 --- a/frontend/src/uxbox/main/ui/workspace/viewport.cljs +++ b/frontend/src/uxbox/main/ui/workspace/viewport.cljs @@ -90,7 +90,7 @@ (watch [_ state stream] (let [stoper (rx/filter #(or (dw/interrupt? %) (uws/mouse-up? %)) stream)] (rx/concat - (rx/of (dw/deselect-all)) + (rx/of dw/deselect-all) (->> uws/mouse-position (rx/map (fn [pos] #(update-state % pos))) (rx/take-until stoper)) diff --git a/frontend/src/uxbox/util/spec.cljs b/frontend/src/uxbox/util/spec.cljs index 0a4e98eb8..60d35b574 100644 --- a/frontend/src/uxbox/util/spec.cljs +++ b/frontend/src/uxbox/util/spec.cljs @@ -50,7 +50,6 @@ (s/def ::email email?) (s/def ::color color?) (s/def ::string string?) -(s/def ::number number?) (s/def ::positive pos?) (s/def ::inst inst?) (s/def ::keyword keyword?) @@ -62,15 +61,18 @@ (s/and string? #(not (str/empty? %)))) -(defn- conform-number-str +(defn- conform-number [v] (cond - (re-matches number-rx v) (js/parseFloat v) (number? v) v + (re-matches number-rx v) (js/parseFloat v) :else ::s/invalid)) -(s/def ::number-str - (s/conformer conform-number-str str)) +(s/def ::number + (s/conformer conform-number str)) + +;; NOTE: backward compatibility (revisit the code and remove) +(s/def ::number-str ::number) (s/def ::color color?)