0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-24 07:46:13 -05:00

Improve page options handling.

This commit is contained in:
Andrey Antukh 2020-01-09 13:41:52 +01:00
parent 9c68877328
commit c8298c72ea
8 changed files with 269 additions and 283 deletions

View file

@ -81,7 +81,7 @@ CREATE TABLE IF NOT EXISTS project_page_snapshots (
label text NOT NULL DEFAULT '', label text NOT NULL DEFAULT '',
data bytea NOT NULL, data bytea NOT NULL,
operations bytea NULL DEFAULT NULL changes bytea NULL DEFAULT NULL
); );
-- Indexes -- Indexes

View file

@ -28,7 +28,6 @@
(s/def ::data ::cp/data) (s/def ::data ::cp/data)
(s/def ::user ::us/uuid) (s/def ::user ::us/uuid)
(s/def ::project-id ::us/uuid) (s/def ::project-id ::us/uuid)
(s/def ::metadata ::cp/metadata)
(s/def ::ordering ::us/number) (s/def ::ordering ::us/number)
;; --- Mutation: Create Page ;; --- Mutation: Create Page
@ -36,7 +35,7 @@
(declare create-page) (declare create-page)
(s/def ::create-project-page (s/def ::create-project-page
(s/keys :req-un [::user ::file-id ::name ::ordering ::metadata ::data] (s/keys :req-un [::user ::file-id ::name ::ordering ::data]
:opt-un [::id])) :opt-un [::id]))
(sm/defmutation ::create-project-page (sm/defmutation ::create-project-page
@ -46,15 +45,14 @@
(create-page conn params))) (create-page conn params)))
(defn create-page (defn create-page
[conn {:keys [id user file-id name ordering data metadata] :as params}] [conn {:keys [id user file-id name ordering data] :as params}]
(let [sql "insert into project_pages (id, user_id, file_id, name, (let [sql "insert into project_pages (id, user_id, file_id, name,
ordering, data, metadata, version) ordering, data, version)
values ($1, $2, $3, $4, $5, $6, $7, 0) values ($1, $2, $3, $4, $5, $6, 0)
returning *" returning *"
id (or id (uuid/next)) id (or id (uuid/next))
data (blob/encode data) data (blob/encode data)]
mdata (blob/encode metadata)] (-> (db/query-one conn [sql id user file-id name ordering data])
(-> (db/query-one conn [sql id user file-id name ordering data mdata])
(p/then' decode-row)))) (p/then' decode-row))))
;; --- Mutation: Update Page Data ;; --- Mutation: Update Page Data
@ -98,11 +96,11 @@
(p/then' su/constantly-nil)))) (p/then' su/constantly-nil))))
(defn- insert-page-snapshot (defn- insert-page-snapshot
[conn {:keys [user-id id version data operations]}] [conn {:keys [user-id id version data changes]}]
(let [sql "insert into project_page_snapshots (user_id, page_id, version, data, operations) (let [sql "insert into project_page_snapshots (user_id, page_id, version, data, changes)
values ($1, $2, $3, $4, $5) values ($1, $2, $3, $4, $5)
returning id, page_id, user_id, version, operations"] returning id, page_id, user_id, version, changes"]
(db/query-one conn [sql user-id id version data operations]))) (db/query-one conn [sql user-id id version data changes])))
;; --- Mutation: Rename Page ;; --- Mutation: Rename Page
@ -129,16 +127,16 @@
;; --- Mutation: Update Page ;; --- Mutation: Update Page
;; A generic, Ops based (granular) page update method. ;; A generic, Changes based (granular) page update method.
(s/def ::operations (s/def ::changes
(s/coll-of vector? :kind vector?)) (s/coll-of vector? :kind vector?))
(s/def ::update-project-page (s/def ::update-project-page
(s/keys :opt-un [::id ::user ::version ::operations])) (s/keys :opt-un [::id ::user ::version ::changes]))
(declare update-project-page) (declare update-project-page)
(declare retrieve-lagged-operations) (declare retrieve-lagged-changes)
(sm/defmutation ::update-project-page (sm/defmutation ::update-project-page
[{:keys [id user] :as params}] [{:keys [id user] :as params}]
@ -156,17 +154,17 @@
:hint "The incoming version is greater that stored version." :hint "The incoming version is greater that stored version."
:context {:incoming-version (:version params) :context {:incoming-version (:version params)
:stored-version (:version page)})) :stored-version (:version page)}))
(let [ops (:operations params) (let [changes (:changes params)
data (-> (:data page) data (-> (:data page)
(blob/decode) (blob/decode)
(cp/process-ops ops) (cp/process-changes changes)
(blob/encode)) (blob/encode))
page (assoc page page (assoc page
:user-id (:user params) :user-id (:user params)
:data data :data data
:version (inc (:version page)) :version (inc (:version page))
:operations (blob/encode ops))] :changes (blob/encode changes))]
(-> (update-page-data conn page) (-> (update-page-data conn page)
(p/then (fn [_] (insert-page-snapshot conn page))) (p/then (fn [_] (insert-page-snapshot conn page)))
@ -176,24 +174,24 @@
:user-id (:user-id s) :user-id (:user-id s)
:page-id (:page-id s) :page-id (:page-id s)
:version (:version s) :version (:version s)
:operations ops}) :changes changes})
(retrieve-lagged-operations conn s params)))))))) (retrieve-lagged-changes conn s params))))))))
(su/defstr sql:lagged-snapshots (su/defstr sql:lagged-snapshots
"select s.id, s.operations "select s.id, s.changes
from project_page_snapshots as s from project_page_snapshots as s
where s.page_id = $1 where s.page_id = $1
and s.version > $2") and s.version > $2")
(defn- retrieve-lagged-operations (defn- retrieve-lagged-changes
[conn snapshot params] [conn snapshot params]
(let [sql sql:lagged-snapshots] (let [sql sql:lagged-snapshots]
(-> (db/query conn [sql (:id params) (:version params) #_(:id snapshot)]) (-> (db/query conn [sql (:id params) (:version params) #_(:id snapshot)])
(p/then (fn [rows] (p/then (fn [rows]
{:page-id (:id params) {:page-id (:id params)
:version (:version snapshot) :version (:version snapshot)
:operations (into [] (comp (map decode-row) :changes (into [] (comp (map decode-row)
(map :operations) (map :changes)
(mapcat identity)) (mapcat identity))
rows)}))))) rows)})))))

View file

@ -120,9 +120,9 @@
;; --- Helpers ;; --- Helpers
(defn decode-row (defn decode-row
[{:keys [data metadata operations] :as row}] [{:keys [data metadata changes] :as row}]
(when row (when row
(cond-> row (cond-> row
data (assoc :data (blob/decode data)) data (assoc :data (blob/decode data))
metadata (assoc :metadata (blob/decode metadata)) metadata (assoc :metadata (blob/decode metadata))
operations (assoc :operations (blob/decode operations))))) changes (assoc :changes (blob/decode changes)))))

View file

@ -10,25 +10,83 @@
(s/def ::name string?) (s/def ::name string?)
(s/def ::type keyword?) (s/def ::type keyword?)
;; Metadata related ;; Page Options
(s/def ::grid-x-axis number?) (s/def ::grid-x number?)
(s/def ::grid-y-axis number?) (s/def ::grid-y number?)
(s/def ::grid-color string?) (s/def ::grid-color string?)
(s/def ::background string?)
(s/def ::background-opacity number?)
(s/def ::metadata (s/def ::options
(s/keys :opt-un [::grid-y-axis (s/keys :opt-un [::grid-y
::grid-x-axis ::grid-x
::grid-color ::grid-color]))
::background
::background-opacity]))
;; Page Data related ;; Page Data related
(s/def ::shape (s/def ::blocked boolean?)
(s/def ::collapsed boolean?)
(s/def ::content string?)
(s/def ::fill-color string?)
(s/def ::fill-opacity number?)
(s/def ::font-family string?)
(s/def ::font-size number?)
(s/def ::font-style string?)
(s/def ::font-weight string?)
(s/def ::hidden boolean?)
(s/def ::letter-spacing number?)
(s/def ::line-height number?)
(s/def ::locked boolean?)
(s/def ::page-id uuid?)
(s/def ::proportion number?)
(s/def ::proportion-lock boolean?)
(s/def ::rx number?)
(s/def ::ry number?)
(s/def ::stroke-color string?)
(s/def ::stroke-opacity number?)
(s/def ::stroke-style #{:none :solid :dotted :dashed :mixed})
(s/def ::stroke-width number?)
(s/def ::text-align #{"left" "right" "center" "justify"})
(s/def ::type #{:rect :path :circle :image :text :canvas})
(s/def ::x number?)
(s/def ::y number?)
(s/def ::cx number?)
(s/def ::cy number?)
(s/def ::width number?)
(s/def ::height number?)
(s/def ::shape-attrs
(s/keys :opt-un [::blocked
::collapsed
::content
::fill-color
::fill-opacity
::font-family
::font-size
::font-style
::font-weight
::hidden
;; ::page-id ??
::letter-spacing
::line-height
::locked
::proportion
::proportion-lock
::rx ::ry
::cx ::cy
::x ::y
::stroke-color
::stroke-opacity
::stroke-style
::stroke-width
::text-align
::width ::height]))
(s/def ::minimal-shape
(s/keys :req-un [::type ::name] (s/keys :req-un [::type ::name]
:opt-un [::id])) :opt-un [::id]))
(s/def ::shape
(s/and ::minimal-shape ::shape-attrs
(s/keys :opt-un [::id])))
(s/def ::shapes (s/coll-of uuid? :kind vector?)) (s/def ::shapes (s/coll-of uuid? :kind vector?))
(s/def ::canvas (s/coll-of uuid? :kind vector?)) (s/def ::canvas (s/coll-of uuid? :kind vector?))
@ -36,12 +94,16 @@
(s/map-of uuid? ::shape)) (s/map-of uuid? ::shape))
(s/def ::data (s/def ::data
(s/keys :req-un [::shapes ::canvas ::shapes-by-id])) (s/keys :req-un [::shapes
::canvas
::options
::shapes-by-id]))
;; Changes related
(s/def ::attr-change (s/def ::attr-change
(s/tuple #{:set} keyword? any?)) (s/tuple #{:set} keyword? any?))
(s/def ::operation (s/def ::change
(s/or :mod-shape (s/cat :name #(= % :mod-shape) (s/or :mod-shape (s/cat :name #(= % :mod-shape)
:id uuid? :id uuid?
:changes (s/* ::attr-change)) :changes (s/* ::attr-change))
@ -64,12 +126,12 @@
:del-canvas (s/cat :name #(= % :del-canvas) :del-canvas (s/cat :name #(= % :del-canvas)
:id uuid?))) :id uuid?)))
(s/def ::operations (s/def ::changes
(s/coll-of ::operation :kind vector?)) (s/coll-of ::change :kind vector?))
;; --- Operations Processing Impl ;; --- Changes Processing Impl
(declare process-operation) (declare process-change)
(declare process-mod-shape) (declare process-mod-shape)
(declare process-mod-opts) (declare process-mod-opts)
(declare process-mov-shape) (declare process-mov-shape)
@ -78,12 +140,12 @@
(declare process-del-shape) (declare process-del-shape)
(declare process-del-canvas) (declare process-del-canvas)
(defn process-ops (defn process-changes
[data operations] [data items]
(->> (s/assert ::operations operations) (->> (s/assert ::changes items)
(reduce process-operation data))) (reduce process-change data)))
(defn- process-operation (defn- process-change
[data [op & rest]] [data [op & rest]]
(case op (case op
:mod-shape (process-mod-shape data rest) :mod-shape (process-mod-shape data rest)

View file

@ -471,26 +471,3 @@
(assoc :workspace-page page) (assoc :workspace-page page)
(update :pages assoc id page) (update :pages assoc id page)
(update :pages-data assoc id data)))))) (update :pages-data assoc id data))))))
;; --- Update Page
;; TODO: deprecated, need refactor (this is used on page options)
(defn update-page-attrs
[{:keys [id] :as data}]
(s/assert ::page data)
(ptk/reify ::update-page-attrs
ptk/UpdateEvent
(update [_ state]
(update state :workspace-page merge (dissoc data :id :version)))))
;; --- Update Page Metadata
;; TODO: deprecated, need refactor (this is used on page options)
(defn update-metadata
[id metadata]
(s/assert ::id id)
(s/assert ::metadata metadata)
(reify
ptk/UpdateEvent
(update [this state]
(assoc-in state [:pages id :metadata] metadata))))

View file

@ -34,89 +34,24 @@
[uxbox.util.uuid :as uuid] [uxbox.util.uuid :as uuid]
[vendor.randomcolor])) [vendor.randomcolor]))
;; TODO: temporal workaround ;; TODO: temporal workaround
(def clear-ruler nil) (def clear-ruler nil)
(def start-ruler nil) (def start-ruler nil)
;; --- Specs ;; --- Specs
(s/def ::id ::us/uuid) (s/def ::shape-attrs ::cp/shape-attrs)
(s/def ::blocked boolean?)
(s/def ::collapsed boolean?)
(s/def ::content string?)
(s/def ::fill-color string?)
(s/def ::fill-opacity number?)
(s/def ::font-family string?)
(s/def ::font-size number?)
(s/def ::font-style string?)
(s/def ::font-weight string?)
(s/def ::hidden boolean?)
(s/def ::id uuid?)
(s/def ::letter-spacing number?)
(s/def ::line-height number?)
(s/def ::locked boolean?)
(s/def ::name string?)
(s/def ::page uuid?)
(s/def ::proportion number?)
(s/def ::proportion-lock boolean?)
(s/def ::rx number?)
(s/def ::ry number?)
(s/def ::stroke-color string?)
(s/def ::stroke-opacity number?)
(s/def ::stroke-style #{:none :solid :dotted :dashed :mixed})
(s/def ::stroke-width number?)
(s/def ::text-align #{"left" "right" "center" "justify"})
(s/def ::type #{:rect :path :circle :image :text :canvas})
(s/def ::x number?)
(s/def ::y number?)
(s/def ::cx number?)
(s/def ::cy number?)
(s/def ::width number?)
(s/def ::height number?)
(s/def ::attributes
(s/keys :opt-un [::blocked
::collapsed
::content
::fill-color
::fill-opacity
::font-family
::font-size
::font-style
::font-weight
::hidden
::letter-spacing
::line-height
::locked
::proportion
::proportion-lock
::rx ::ry
::cx ::cy
::x ::y
::stroke-color
::stroke-opacity
::stroke-style
::stroke-width
::text-align
::width ::height]))
(s/def ::minimal-shape
(s/keys :req-un [::id ::page ::type ::name]))
(s/def ::shape
(s/and ::minimal-shape ::attributes))
(s/def ::rect-like-shape
(s/keys :req-un [::x1 ::y1 ::x2 ::y2 ::type]))
(s/def ::set-of-uuid (s/def ::set-of-uuid
(s/every ::us/uuid :kind set?)) (s/every uuid? :kind set?))
;; --- Expose inner functions ;; --- Expose inner functions
(defn interrupt? [e] (= e :interrupt)) (defn interrupt? [e] (= e :interrupt))
;; --- Protocols
(defprotocol IAsyncChange)
;; --- Declarations ;; --- Declarations
(declare fetch-users) (declare fetch-users)
@ -125,8 +60,8 @@
(declare handle-pointer-send) (declare handle-pointer-send)
(declare handle-page-snapshot) (declare handle-page-snapshot)
(declare shapes-changes-commited) (declare shapes-changes-commited)
(declare commit-shapes-changes) (declare commit-changes)
(declare async-commit-shapes-changes) (declare commit-async-changes)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Websockets Events ;; Websockets Events
@ -320,19 +255,14 @@
(watch [_ state stream] (watch [_ state stream]
(let [stoper (rx/filter #(or (ptk/type? ::finalize %) (let [stoper (rx/filter #(or (ptk/type? ::finalize %)
(ptk/type? ::initialize-page %)) (ptk/type? ::initialize-page %))
stream) stream)]
notifier (->> stream
(rx/filter (ptk/type? ::async-commit-shapes-changes))
(rx/debounce 500))]
(->> stream (->> stream
(rx/filter (ptk/type? ::async-commit-shapes-changes)) (rx/filter #(satisfies? IAsyncChange %))
(rx/map deref) (rx/debounce 500)
(rx/mapcat identity) (rx/map (constantly commit-async-changes))
(rx/buffer-until notifier) (rx/finalize #(prn "FINALIZE" %))
(rx/map vec) (rx/take-until stoper))))))
(rx/map commit-shapes-changes)
(rx/take-until stoper)
(rx/finalize #(prn "FINALIZE" %)))))))
;; --- Fetch Workspace Users ;; --- Fetch Workspace Users
@ -612,7 +542,7 @@
(defn add-shape (defn add-shape
[data] [data]
(s/assert ::attributes data) (s/assert ::shape-attrs data)
(let [id (uuid/random)] (let [id (uuid/random)]
(ptk/reify ::add-shape (ptk/reify ::add-shape
ptk/UpdateEvent ptk/UpdateEvent
@ -626,7 +556,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [shape (get-in state [:workspace-data :shapes-by-id id])] (let [shape (get-in state [:workspace-data :shapes-by-id id])]
(rx/of (commit-shapes-changes [[:add-shape id shape]]) (rx/of (commit-changes [[:add-shape id shape]])
(select-shape id))))))) (select-shape id)))))))
(def canvas-default-attrs (def canvas-default-attrs
@ -637,7 +567,7 @@
(defn add-canvas (defn add-canvas
[data] [data]
(s/assert ::attributes data) (s/assert ::shape-attrs data)
(let [id (uuid/random)] (let [id (uuid/random)]
(ptk/reify ::add-canvas (ptk/reify ::add-canvas
ptk/UpdateEvent ptk/UpdateEvent
@ -651,7 +581,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [shape (get-in state [:workspace-data :shapes-by-id id])] (let [shape (get-in state [:workspace-data :shapes-by-id id])]
(rx/of (commit-shapes-changes [[:add-canvas id shape]]) (rx/of (commit-changes [[:add-canvas id shape]])
(select-shape id))))))) (select-shape id)))))))
@ -671,7 +601,7 @@
shapes (map duplicate selected)] shapes (map duplicate selected)]
(rx/merge (rx/merge
(rx/from (map (fn [s] #(impl-assoc-shape % s)) shapes)) (rx/from (map (fn [s] #(impl-assoc-shape % s)) shapes))
(rx/of (commit-shapes-changes (mapv #(vector :add-shape (:id %) %) shapes)))))))) (rx/of (commit-changes (mapv #(vector :add-shape (:id %) %) shapes))))))))
;; --- Toggle shape's selection status (selected or deselected) ;; --- Toggle shape's selection status (selected or deselected)
@ -740,8 +670,9 @@
(defn update-shape (defn update-shape
[id attrs] [id attrs]
(s/assert ::us/uuid id) (s/assert ::us/uuid id)
(s/assert ::attributes attrs) (s/assert ::shape-attrs attrs)
(ptk/reify ::update-shape (ptk/reify ::update-shape
IAsyncChange
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [shape-old (get-in state [:workspace-data :shapes-by-id id]) (let [shape-old (get-in state [:workspace-data :shapes-by-id id])
@ -749,13 +680,23 @@
diff (d/diff-maps shape-old shape-new)] diff (d/diff-maps shape-old shape-new)]
(-> state (-> state
(assoc-in [:workspace-data :shapes-by-id id] shape-new) (assoc-in [:workspace-data :shapes-by-id id] shape-new)
(assoc ::tmp-change (into [:mod-shape id] diff))))) (update ::async-changes (fnil conj []) (into [:mod-shape id] diff)))))))
ptk/WatchEvent ;; --- Update Page Options
(watch [_ state stream]
(let [change (::tmp-change state)] (defn update-options
(rx/of (async-commit-shapes-changes [change]) [opts]
#(dissoc state ::tmp-change)))))) (s/assert ::cp/options opts)
(ptk/reify ::update-options
IAsyncChange
ptk/UpdateEvent
(update [_ state]
(let [opts-old (get-in state [:workspace-data :options])
opts-new (merge opts-old opts)
diff (d/diff-maps opts-old opts-new)]
(-> state
(assoc-in [:workspace-data :options] opts-new)
(update ::async-changes (fnil conj []) (into [:mod-opts] diff)))))))
;; --- Update Selected Shapes attrs ;; --- Update Selected Shapes attrs
@ -844,7 +785,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])] (let [selected (get-in state [:workspace-local :selected])]
(rx/of (commit-shapes-changes (mapv #(vector :del-shape %) selected))))))) (rx/of (commit-changes (mapv #(vector :del-shape %) selected)))))))
;; --- Rename Shape ;; --- Rename Shape
@ -858,7 +799,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(rx/of (commit-shapes-changes [[:mod-shape id [:mod :name name]]]))))) (rx/of (commit-changes [[:mod-shape id [:mod :name name]]])))))
;; --- Shape Vertical Ordering ;; --- Shape Vertical Ordering
@ -897,7 +838,6 @@
[id index] [id index]
(s/assert ::us/uuid id) (s/assert ::us/uuid id)
(s/assert number? index) (s/assert number? index)
{:pre [(uuid? id) (number? index)]}
(ptk/reify ::change-shape-order (ptk/reify ::change-shape-order
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -905,18 +845,18 @@
shapes (into [] (remove #(= % id)) shapes) shapes (into [] (remove #(= % id)) shapes)
[before after] (split-at index shapes) [before after] (split-at index shapes)
shapes (d/concat [] before [id] after) shapes (d/concat [] before [id] after)
operation [:mov-shape id :after (last before)]] change [:mov-shape id :after (last before)]]
(-> state (-> state
(assoc-in [:workspace-data :shapes] shapes) (assoc-in [:workspace-data :shapes] shapes)
(assoc ::tmp-changes [operation])))))) (assoc ::tmp-shape-order-change change))))))
(def commit-shape-order-change (def commit-shape-order-change
(ptk/reify ::commit-shape-order-change (ptk/reify ::commit-shape-order-change
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [changes (::tmp-changes state)] (let [change (::tmp-shape-order-change state)]
(rx/of (commit-shapes-changes changes) (rx/of #(dissoc state ::tmp-changes)
#(dissoc state ::tmp-changes)))))) (commit-changes [change]))))))
;; --- Change Canvas Order (D&D Ordering) ;; --- Change Canvas Order (D&D Ordering)
@ -1001,50 +941,46 @@
diff (d/diff-maps shape-old shape-new)] diff (d/diff-maps shape-old shape-new)]
(-> state (-> state
(assoc-in [:workspace-data :shapes-by-id id] shape-new) (assoc-in [:workspace-data :shapes-by-id id] shape-new)
(update ::tmp-changes (fnil conj []) (into [:mod-shape id] diff)))))] (update ::async-changes (fnil conj []) (into [:mod-shape id] diff)))))]
(ptk/reify ::materialize-temporal-modifier-in-bulk (ptk/reify ::materialize-temporal-modifier-in-bulk
IAsyncChange
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(reduce process-shape state ids)) (reduce process-shape state ids)))))
ptk/WatchEvent (defn commit-changes
(watch [_ state stream] [changes]
(let [changes (::tmp-changes state)] (s/assert ::cp/changes changes)
(rx/of (commit-shapes-changes changes) (ptk/reify ::commit-changes
#(dissoc state ::tmp-changes)))))))
(defn commit-shapes-changes
[operations]
(s/assert ::cp/operations operations)
(ptk/reify ::commit-shapes-changes
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [pid (get-in state [:workspace-local :page-id]) (let [pid (get-in state [:workspace-local :page-id])
data (get-in state [:pages-data pid])] data (get-in state [:pages-data pid])]
(update-in state [:pages-data pid] cp/process-ops operations))) (update-in state [:pages-data pid] cp/process-changes changes)))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [page (:workspace-page state) (let [page (:workspace-page state)
params {:id (:id page) params {:id (:id page)
:version (:version page) :version (:version page)
:operations operations}] :changes changes}]
(->> (rp/mutation :update-project-page params) (->> (rp/mutation :update-project-page params)
(rx/map shapes-changes-commited)))))) (rx/map shapes-changes-commited))))))
(defn async-commit-shapes-changes (def commit-async-changes
[operations] (ptk/reify ::commit-async-changes
(s/assert ::cp/operations operations) ptk/WatchEvent
(ptk/reify ::async-commit-shapes-changes (watch [_ state stream]
cljs.core/IDeref (let [changes (::async-changes state)]
(-deref [_] operations))) (rx/of #(dissoc % ::async-changes)
(commit-changes changes))))))
(s/def ::shapes-changes-commited (s/def ::shapes-changes-commited
(s/keys :req-un [::page-id ::version ::cp/operations])) (s/keys :req-un [::page-id ::version ::cp/changes]))
(defn shapes-changes-commited (defn shapes-changes-commited
[{:keys [page-id version operations] :as params}] [{:keys [page-id version changes] :as params}]
(s/assert ::shapes-changes-commited params) (s/assert ::shapes-changes-commited params)
(ptk/reify ::shapes-changes-commited (ptk/reify ::shapes-changes-commited
ptk/UpdateEvent ptk/UpdateEvent
@ -1052,8 +988,8 @@
(-> state (-> state
(assoc-in [:workspace-page :version] version) (assoc-in [:workspace-page :version] version)
(assoc-in [:pages page-id :version] version) (assoc-in [:pages page-id :version] version)
(update-in [:pages-data page-id] cp/process-ops operations) (update-in [:pages-data page-id] cp/process-changes changes)
(update :workspace-data cp/process-ops operations))))) (update :workspace-data cp/process-changes changes)))))
;; --- Start shape "edition mode" ;; --- Start shape "edition mode"

View file

@ -10,6 +10,8 @@
(:require (:require
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[lentes.core :as l]
[uxbox.common.data :as d]
[uxbox.builtins.icons :as i] [uxbox.builtins.icons :as i]
[uxbox.main.constants :as c] [uxbox.main.constants :as c]
[uxbox.main.data.workspace :as udw] [uxbox.main.data.workspace :as udw]
@ -22,65 +24,83 @@
[uxbox.util.i18n :refer [tr]] [uxbox.util.i18n :refer [tr]]
[uxbox.util.spec :refer [color?]])) [uxbox.util.spec :refer [color?]]))
(mf/defc metadata-options ;; (mf/defc metadata-options
[{:keys [page] :as props}] ;; [{:keys [page] :as props}]
(let [metadata (:metadata page) ;; (let [metadata (:metadata page)
;; change-color
;; (fn [color]
;; #_(st/emit! (->> (assoc metadata :background color)
;; (udp/update-metadata (:id page)))))
;; on-color-change
;; (fn [event]
;; (let [value (dom/event->value event)]
;; (change-color value)))
;; show-color-picker
;; (fn [event]
;; (let [x (.-clientX event)
;; y (.-clientY event)
;; props {:x x :y y
;; :default "#ffffff"
;; :value (:background metadata)
;; :transparent? true
;; :on-change change-color}]
;; (modal/show! colorpicker-modal props)))]
;; [:div.element-set
;; [:div.element-set-title (tr "workspace.options.page-measures")]
;; [:div.element-set-content
;; [:span (tr "workspace.options.background-color")]
;; [:div.row-flex.color-data
;; [:span.color-th
;; {:style {:background-color (:background metadata "#ffffff")}
;; :on-click show-color-picker}]
;; [:div.color-info
;; [:input
;; {:on-change on-color-change
;; :value (:background metadata "#ffffff")}]]]]]))
(def default-options
"Default data for page metadata."
{:grid-x 10
:grid-y 10
:grid-color "#cccccc"})
(def options-iref
(-> (l/key :options)
(l/derive refs/workspace-data)))
(mf/defc grid-options
{:wrap [mf/wrap-memo]}
[props]
(let [options (->> (mf/deref options-iref)
(merge default-options))
on-x-change
(fn [event]
(let [value (-> (dom/get-target event)
(dom/get-value)
(d/parse-integer 0))]
(st/emit! (udw/update-options {:grid-x value}))))
on-y-change
(fn [event]
(let [value (-> (dom/get-target event)
(dom/get-value)
(d/parse-integer 0))]
(st/emit! (udw/update-options {:grid-y value}))))
change-color change-color
(fn [color] (fn [color]
#_(st/emit! (->> (assoc metadata :background color) (st/emit! (udw/update-options {:grid-color color})))
(udp/update-metadata (:id page)))))
on-color-change on-color-change
(fn [event] (fn [event]
(let [value (dom/event->value event)] (let [value (-> (dom/get-target event)
(dom/get-value))]
(change-color value))) (change-color value)))
show-color-picker show-color-picker
(fn [event] (fn [event]
(let [x (.-clientX event)
y (.-clientY event)
props {:x x :y y
:default "#ffffff"
:value (:background metadata)
:transparent? true
:on-change change-color}]
(modal/show! colorpicker-modal props)))]
[:div.element-set
[:div.element-set-title (tr "workspace.options.page-measures")]
[:div.element-set-content
[:span (tr "workspace.options.background-color")]
[:div.row-flex.color-data
[:span.color-th
{:style {:background-color (:background metadata "#ffffff")}
:on-click show-color-picker}]
[:div.color-info
[:input
{:on-change on-color-change
:value (:background metadata "#ffffff")}]]]]]))
(mf/defc grid-options
[{:keys [page] :as props}]
(let [metadata (:metadata page)
metadata (merge c/page-metadata metadata)]
(letfn [(on-x-change [event]
#_(let [value (-> (dom/event->value event)
(parse-int nil))]
(st/emit! (->> (assoc metadata :grid-x-axis value)
(udp/update-metadata (:id page))))))
(on-y-change [event]
#_(let [value (-> (dom/event->value event)
(parse-int nil))]
(st/emit! (->> (assoc metadata :grid-y-axis value)
(udp/update-metadata (:id page))))))
(change-color [color]
#_(st/emit! (->> (assoc metadata :grid-color color)
(udp/update-metadata (:id page)))))
(on-color-change [event]
(let [value (dom/event->value event)]
(change-color value)))
(show-color-picker [event]
(let [x (.-clientX event) (let [x (.-clientX event)
y (.-clientY event) y (.-clientY event)
props {:x x :y y props {:x x :y y
@ -95,30 +115,23 @@
[:span (tr "workspace.options.size")] [:span (tr "workspace.options.size")]
[:div.row-flex [:div.row-flex
[:div.input-element.pixels [:div.input-element.pixels
[:input.input-text [:input.input-text {:type "number"
{:type "number" :value (:grid-x options)
:value (:grid-x-axis metadata) :on-change on-x-change}]]
:on-change on-x-change
:placeholder "x"}]]
[:div.input-element.pixels [:div.input-element.pixels
[:input.input-text [:input.input-text {:type "number"
{:type "number" :value (:grid-y options)
:value (:grid-y-axis metadata) :on-change on-y-change}]]]
:on-change on-y-change
:placeholder "y"}]]]
[:span (tr "workspace.options.color")] [:span (tr "workspace.options.color")]
[:div.row-flex.color-data [:div.row-flex.color-data
[:span.color-th [:span.color-th {:style {:background-color (:grid-color options)}
{:style {:background-color (:grid-color metadata)}
:on-click show-color-picker}] :on-click show-color-picker}]
[:div.color-info [:div.color-info
[:input [:input {:on-change on-color-change
{:on-change on-color-change :value (:grid-color options)}]]]]]))
:value (:grid-color metadata "#cccccc")}]]]]])))
(mf/defc options (mf/defc options
[{:keys [page] :as props}] [{:keys [page] :as props}]
[:div [:div
#_[:& metadata-options {:page page}]
[:& grid-options {:page page}]]) [:& grid-options {:page page}]])

View file

@ -150,7 +150,7 @@
shapes-by-id (:shapes-by-id data) shapes-by-id (:shapes-by-id data)
shapes (map #(get shapes-by-id %) (:shapes data [])) shapes (map #(get shapes-by-id %) (:shapes data []))
canvas (map #(get shapes-by-id %) (:canvas data []))] canvas (map #(get shapes-by-id %) (:canvas data []))]
[:* [:g.shapes
(for [item canvas] (for [item canvas]
[:& shape-wrapper {:shape item :key (:id item)}]) [:& shape-wrapper {:shape item :key (:id item)}])
(for [item shapes] (for [item shapes]
@ -285,7 +285,7 @@
:modifiers (:modifiers local)}])] :modifiers (:modifiers local)}])]
(if (contains? flags :grid) (if (contains? flags :grid)
[:& grid {:page page}])] [:& grid])]
(when (contains? flags :ruler) (when (contains? flags :ruler)
[:& ruler {:zoom zoom :ruler (:ruler local)}]) [:& ruler {:zoom zoom :ruler (:ruler local)}])