♻️ Always set component-file-id, even in local file

This commit is contained in:
Andrés Moya 2020-12-04 15:31:03 +01:00 committed by Andrey Antukh
parent 53b5d78cdc
commit baec7838b4
24 changed files with 284 additions and 258 deletions

View file

@ -112,7 +112,7 @@
(create-file [conn owner-id project-id index]
(let [id (mk-uuid "file" project-id index)
name (str "file" index)
data (cp/make-file-data)]
data (cp/make-file-data id)]
(log/info "create file" id)
(db/insert! conn :file
{:id id
@ -186,7 +186,7 @@
id (mk-uuid "file" "draft" owner-id index)
name (str "file" index)
project-id (:default-project-id owner)
data (cp/make-file-data)]
data (cp/make-file-data id)]
(log/info "create draft file" id)
(db/insert! conn :file

View file

@ -63,7 +63,7 @@
:or {is-shared false}
:as params}]
(let [id (or id (uuid/next))
data (cp/make-file-data)
data (cp/make-file-data id)
file (db/insert! conn :file
{:id id
:project-id project-id
@ -276,6 +276,7 @@
changes (:changes params)
file (-> file
(update :data blob/decode)
(update :data assoc :id (:id file))
(update :data pmg/migrate-data)
(update :data cp/process-changes changes)
(update :data blob/encode)

View file

@ -67,6 +67,7 @@
(db/with-atomic [conn db/pool]
(let [mobjs (map :id (db/query conn :media-object {:file-id id}))
data (-> (blob/decode data)
(assoc :id id)
(pmg/migrate-data))
used (collect-used-media data)

View file

@ -18,8 +18,9 @@
[app.tests.helpers :as th]))
(t/deftest process-change-set-option
(let [page-id (uuid/custom 1 1)
data (cp/make-file-data page-id)]
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (cp/make-file-data file-id page-id)]
(t/testing "Sets option single"
(let [chg {:type :set-option
:page-id page-id
@ -83,8 +84,9 @@
))
(t/deftest process-change-add-obj
(let [page-id (uuid/custom 1 1)
data (cp/make-file-data page-id)
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (cp/make-file-data file-id page-id)
id-a (uuid/custom 2 1)
id-b (uuid/custom 2 2)
id-c (uuid/custom 2 3)]
@ -136,8 +138,9 @@
))
(t/deftest process-change-mod-obj
(let [page-id (uuid/custom 1 1)
data (cp/make-file-data page-id)]
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (cp/make-file-data file-id page-id)]
(t/testing "simple mod-obj"
(let [chg {:type :mod-obj
:page-id page-id
@ -161,9 +164,10 @@
(t/deftest process-change-del-obj
(let [page-id (uuid/custom 1 1)
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
id (uuid/custom 2 1)
data (cp/make-file-data page-id)
data (cp/make-file-data file-id page-id)
data (-> data
(assoc-in [:pages-index page-id :objects uuid/zero :shapes] [id])
(assoc-in [:pages-index page-id :objects id]
@ -205,8 +209,9 @@
rect-d-id (uuid/custom 0 8)
rect-e-id (uuid/custom 0 9)
file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (cp/make-file-data page-id)
data (cp/make-file-data file-id page-id)
data (update-in data [:pages-index page-id :objects]
#(-> %
@ -417,6 +422,7 @@
shape-2-id (uuid/custom 2 2)
shape-3-id (uuid/custom 2 3)
frame-id (uuid/custom 1 1)
file-id (uuid/custom 4 4)
page-id (uuid/custom 0 1)
changes [{:type :add-obj
@ -449,7 +455,7 @@
:obj {:type :rect
:name "Shape 3"}}
]
data (cp/make-file-data page-id)
data (cp/make-file-data file-id page-id)
data (cp/process-changes data changes)]
(t/testing "preserve order on multiple shape mov 1"
@ -513,6 +519,7 @@
shape-3-id (uuid/custom 1 3)
shape-4-id (uuid/custom 1 4)
group-1-id (uuid/custom 1 5)
file-id (uuid/custom 1 6)
page-id (uuid/custom 0 1)
changes [{:type :add-obj
@ -555,7 +562,7 @@
:parent-id group-1-id
:shapes [shape-1-id shape-2-id]}]
data (cp/make-file-data page-id)
data (cp/make-file-data file-id page-id)
data (cp/process-changes data changes)]
(t/testing "case 1"

View file

@ -80,3 +80,4 @@
(s/def ::recent-color ::spec/recent-color)
(s/def ::shape-attrs ::spec/shape-attrs)
(s/def ::typography ::spec/typography)

View file

@ -11,7 +11,7 @@
(:require
[app.common.uuid :as uuid]))
(def file-version 4)
(def file-version 5)
(def default-color "#b1b2b5") ;; $color-gray-20
(def root uuid/zero)

View file

@ -58,6 +58,7 @@
(defn get-container
[id type local-file]
(assert (some? type))
(-> (if (= type :page)
(get-in local-file [:pages-index id])
(get-in local-file [:components id]))
@ -68,10 +69,11 @@
(get-in container [:objects shape-id]))
(defn get-component
[component-id file-id local-library libraries]
(let [file (if (nil? file-id)
[component-id library-id local-library libraries]
(assert (some? (:id local-library)))
(let [file (if (= library-id (:id local-library))
local-library
(get-in libraries [file-id :data]))]
(get-in libraries [library-id :data]))]
(get-in file [:components component-id])))
(defn is-master-of

View file

@ -132,12 +132,13 @@
:height (:height selection-rect)})
(defn make-file-data
([] (make-file-data (uuid/next)))
([id]
([file-id] (make-file-data file-id(uuid/next)))
([file-id page-id]
(let [
pd (assoc empty-page-data
:id id
:id page-id
:name "Page-1")]
(-> empty-file-data
(update :pages conj id)
(update :pages-index assoc id pd)))))
(assoc :id file-id)
(update :pages conj page-id)
(update :pages-index assoc page-id pd)))))

View file

@ -35,7 +35,9 @@
(defn migrate-file
[file]
(update file :data migrate-data))
(-> file
(update :data assoc :id (:id file))
(update :data migrate-data)))
;; Default handler, noop
(defmethod migrate :default [data] data)
@ -120,3 +122,18 @@
;; We did rollback version 4 migration.
;; Keep this in order to remember the next version to be 5
(defmethod migrate 4 [data] data)
;; Put the id of the local file in :component-file in instances of local components
(defmethod migrate 5
[data]
(letfn [(update-object [_ object]
(if (and (some? (:component-id object))
(nil? (:component-file object)))
(assoc object :component-file (:id data))
object))
(update-page [_ page]
(update page :objects #(d/mapm update-object %)))]
(update data :pages-index #(d/mapm update-page %))))

View file

@ -69,7 +69,7 @@
(def platform (parse-platform))
(js/console.log
(str/format "Welcome to pentpot! Version: '%s'" (:full version)))
(str/format "Welcome to penpot! Version: '%s'" (:full version)))
;; --- Helper Functions

View file

@ -119,11 +119,11 @@
text-ids (filter is-text? ids)
shape-ids (filter (comp not is-text?) ids)
attrs (cond-> {:fill-color (:color color)
attrs {:fill-color (:color color)
:fill-color-ref-id (:id color)
:fill-color-ref-file (:file-id color)
:fill-color-gradient (:gradient color)
:fill-opacity (:opacity color)})
:fill-opacity (:opacity color)}
update-fn (fn [shape] (merge shape attrs))
editors (get-in state [:workspace-local :editors])

View file

@ -9,18 +9,22 @@
(ns app.main.data.workspace.common
(:require
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.set :as set]
[potok.core :as ptk]
[app.common.data :as d]
[app.common.geom.proportions :as gpr]
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp]
[app.common.spec :as us]
[app.common.uuid :as uuid]
[app.main.worker :as uw]
[app.util.logging :as log]
[app.util.timers :as ts]
[app.common.geom.proportions :as gpr]
[app.common.geom.shapes :as gsh]))
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[clojure.set :as set]
[potok.core :as ptk]))
;; Change this to :info :debug or :trace to debug this module
(log/set-level! :warn)
(s/def ::shape-attrs ::cp/shape-attrs)
(s/def ::set-of-string (s/every string? :kind set?))
@ -66,6 +70,9 @@
:as opts}]
(us/verify ::cp/changes changes)
;; (us/verify ::cp/changes undo-changes)
(log/debug :msg "commit-changes"
:js/changes changes
:js/undo-changes undo-changes)
(let [error (volatile! nil)]
(ptk/reify ::commit-changes

View file

@ -76,8 +76,9 @@
(assoc-in state [:workspace-local :color-for-rename] nil))))
(defn update-color
[{:keys [id] :as color}]
[{:keys [id] :as color} file-id]
(us/assert ::cp/color color)
(us/assert ::us/uuid file-id)
(ptk/reify ::update-color
ptk/WatchEvent
(watch [_ state stream]
@ -87,7 +88,7 @@
uchg {:type :mod-color
:color prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})
(sync-file nil))))))
(sync-file file-id))))))
(defn delete-color
[{:keys [id] :as params}]
@ -164,9 +165,9 @@
(assoc-in [:workspace-local :rename-typography] (:id typography))))))))))
(defn update-typography
[typography]
[typography file-id]
(us/assert ::cp/typography typography)
(us/assert ::us/uuid file-id)
(ptk/reify ::update-typography
ptk/WatchEvent
(watch [_ state stream]
@ -176,7 +177,7 @@
uchg {:type :mod-typography
:typography prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})
(sync-file nil))))))
(sync-file file-id))))))
(defn delete-typography
[id]
@ -196,7 +197,8 @@
(ptk/reify ::add-component
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
(let [file-id (:current-file-id state)
page-id (:current-page-id state)
objects (dwc/lookup-page-objects state page-id)
selected (get-in state [:workspace-local :selected])
shapes (dwg/shapes-for-grouping objects selected)]
@ -210,7 +212,7 @@
(dwg/prepare-create-group page-id shapes "Component-" true))
[new-shape new-shapes updated-shapes]
(dwlh/make-component-shape group objects)
(dwlh/make-component-shape group objects file-id)
rchanges (conj rchanges
{:type :add-component
@ -303,8 +305,8 @@
ptk/WatchEvent
(watch [_ state stream]
(let [component (cp/get-component id
nil
(get state :workspace-data)
(:current-file-id state)
(dwlh/get-local-library state)
nil)
all-components (vals (get-in state [:workspace-data :components]))
unames (set (map :name all-components))
@ -344,18 +346,18 @@
(defn instantiate-component
"Create a new shape in the current page, from the component with the given id
in the given file library (if file-id is nil, take it from the current file library)."
in the given file library / current file library."
[file-id component-id position]
(us/assert (s/nilable ::us/uuid) file-id)
(us/assert ::us/uuid file-id)
(us/assert ::us/uuid component-id)
(us/assert ::us/point position)
(ptk/reify ::instantiate-component
ptk/WatchEvent
(watch [_ state stream]
(let [component (if (nil? file-id)
(get-in state [:workspace-data :components component-id])
(get-in state [:workspace-libraries file-id :data :components component-id]))
component-shape (get-in component [:objects (:id component)])
(let [local-library (dwlh/get-local-library state)
libraries (get state :workspace-libraries)
component (cp/get-component component-id file-id local-library libraries)
component-shape (cp/get-shape component component-id)
orig-pos (gpt/point (:x component-shape) (:y component-shape))
delta (gpt/subtract position orig-pos)
@ -387,19 +389,9 @@
(nil? (:parent-id original-shape))
(assoc :component-id (:id original-shape)
:component-file file-id
:component-root? true)
(and (nil? (:parent-id original-shape)) (some? file-id))
(assoc :component-file file-id)
(and (nil? (:parent-id original-shape)) (nil? file-id))
(dissoc :component-file)
(and (some? (:component-id original-shape))
(nil? (:component-file original-shape))
(some? file-id))
(assoc :component-file file-id)
(some? (:parent-id original-shape))
(dissoc :component-root?))))
@ -514,15 +506,15 @@
ptk/WatchEvent
(watch [_ state stream]
(log/info :msg "RESET-COMPONENT of shape" :id (str id))
(let [local-file (get state :workspace-data)
libraries (get state :workspace-libraries)
(let [local-library (dwlh/get-local-library state)
libraries (dwlh/get-libraries state)
container (cp/get-container (get state :current-page-id)
:page
local-file)
local-library)
[rchanges uchanges]
(dwlh/generate-sync-shape-direct container
id
local-file
local-library
libraries
true)]
(log/debug :msg "RESET-COMPONENT finished" :js/rchanges rchanges)
@ -539,16 +531,11 @@
ptk/WatchEvent
(watch [_ state stream]
(log/info :msg "UPDATE-COMPONENT of shape" :id (str id))
(let [page-id (:current-page-id state)
objects (dwc/lookup-page-objects state page-id)
shape (get objects id)
file-id (get shape :component-file)
[rchanges uchanges]
(let [[rchanges uchanges]
(dwlh/generate-sync-shape-inverse (get state :current-page-id)
id
(get state :workspace-data)
(get state :workspace-libraries))]
(dwlh/get-local-library state)
(dwlh/get-libraries state))]
(log/debug :msg "UPDATE-COMPONENT finished" :js/rchanges rchanges)
@ -562,17 +549,17 @@
component of the library file, and copy the new values to the shapes.
Do it also for shapes inside components of the local file library."
[file-id]
(us/assert (s/nilable ::us/uuid) file-id)
(us/assert ::us/uuid file-id)
(ptk/reify ::sync-file
ptk/UpdateEvent
(update [_ state]
(if file-id
(if (not= file-id (:current-file-id state))
(assoc-in state [:workspace-libraries file-id :synced-at] (dt/now))
state))
ptk/WatchEvent
(watch [_ state stream]
(log/info :msg "SYNC-FILE" :file (str (or file-id "local")))
(log/info :msg "SYNC-FILE" :file (if (= file-id (:current-file-id state)) "local" (str file-id)))
(let [library-changes [(dwlh/generate-sync-library :components file-id state)
(dwlh/generate-sync-library :colors file-id state)
(dwlh/generate-sync-library :typographies file-id state)]
@ -590,7 +577,7 @@
(rx/of (dm/hide-tag :sync-dialog))
(when rchanges
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))
(when file-id
(when (not= file-id (:current-file-id state))
(rp/mutation :update-sync
{:file-id (get-in state [:workspace-file :id])
:library-id file-id}))
@ -607,12 +594,12 @@
;; implement updated-at at component level, to detect what components have
;; not changed, and then not to apply sync and terminate the loop.
[file-id]
(us/assert (s/nilable ::us/uuid) file-id)
(us/assert ::us/uuid file-id)
(ptk/reify ::sync-file-2nd-stage
ptk/WatchEvent
(watch [_ state stream]
(log/info :msg "SYNC-FILE (2nd stage)" :file (str (or file-id "local")))
(let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components nil state)
(log/info :msg "SYNC-FILE (2nd stage)" :file (if (= file-id (:current-file-id state)) "local" (str file-id)))
(let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components file-id state)
[rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state)
rchanges (d/concat rchanges1 rchanges2)
uchanges (d/concat uchanges1 uchanges2)]
@ -621,7 +608,7 @@
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))))
(def ignore-sync
(ptk/reify ::sync-file
(ptk/reify ::ignore-sync
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :ignore-sync-until] (dt/now)))

View file

@ -12,7 +12,6 @@
[cljs.spec.alpha :as s]
[app.common.spec :as us]
[app.common.data :as d]
[app.common.pages :as cph] ;; TODO: remove this namespace
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as geom]
[app.common.pages :as cp]
@ -44,7 +43,6 @@
(declare generate-sync-shape-inverse-recursive)
(declare compare-children)
(declare concat-changes)
(declare add-shape-to-instance)
(declare add-shape-to-master)
(declare remove-shape)
@ -53,6 +51,19 @@
(declare update-attrs)
(declare reposition-shape)
(defn concat-changes
[[rchanges1 uchanges1] [rchanges2 uchanges2]]
[(d/concat rchanges1 rchanges2)
(d/concat uchanges1 uchanges2)])
(defn get-local-library
[state]
(get state :workspace-data))
(defn get-libraries
[state]
(get state :workspace-libraries))
;; ---- Create a new component ----
@ -60,7 +71,7 @@
"Clone the shape and all children. Generate new ids and detach
from parent and frame. Update the original shapes to have links
to the new ones."
[shape objects]
[shape objects file-id]
(assert (nil? (:component-id shape)))
(assert (nil? (:component-file shape)))
(assert (nil? (:shape-ref shape)))
@ -88,20 +99,20 @@
(nil? (:parent-id new-shape))
(assoc :component-id (:id new-shape)
:component-file nil
:component-file file-id
:component-root? true)
(some? (:parent-id new-shape))
(dissoc :component-root?)))]
(cph/clone-object shape nil objects update-new-shape update-original-shape)))
(cp/clone-object shape nil objects update-new-shape update-original-shape)))
(defn duplicate-component
"Clone the root shape of the component and all children. Generate new
ids from all of them."
[component]
(let [component-root (cph/get-component-root component)]
(cph/clone-object component-root
(let [component-root (cp/get-component-root component)]
(cp/clone-object component-root
nil
(get component :objects)
identity)))
@ -114,14 +125,14 @@
with the given asset of the given library."
[asset-type library-id state]
(s/assert #{:colors :components :typographies} asset-type)
(s/assert (s/nilable ::us/uuid) library-id)
(s/assert ::us/uuid library-id)
(log/info :msg "Sync local file with library"
:asset-type asset-type
:library (str (or library-id "local")))
(let [library-items
(if (nil? library-id)
(if (= library-id (:current-file-id state))
(get-in state [:workspace-data asset-type])
(get-in state [:workspace-libraries library-id :data asset-type]))]
@ -136,7 +147,7 @@
(generate-sync-container asset-type
library-id
state
(cph/make-container page :page))]
(cp/make-container page :page))]
(recur (next pages)
(d/concat rchanges page-rchanges)
(d/concat uchanges page-uchanges)))
@ -149,10 +160,10 @@
(log/info :msg "Sync local components with library"
:asset-type asset-type
:library (str (or library-id "local")))
:library (str library-id))
(let [library-items
(if (nil? library-id)
(if (= library-id (:current-file-id state))
(get-in state [:workspace-data asset-type])
(get-in state [:workspace-libraries library-id :data asset-type]))]
(if (empty? library-items)
@ -166,7 +177,7 @@
(generate-sync-container asset-type
library-id
state
(cph/make-container local-component
(cp/make-container local-component
:component))]
(recur (next local-components)
(d/concat rchanges comp-rchanges)
@ -178,12 +189,12 @@
(a page or a component) that are linked to the given library."
[asset-type library-id state container]
(if (cph/page? container)
(if (cp/page? container)
(log/debug :msg "Sync page in local file" :page-id (:id container))
(log/debug :msg "Sync component in local library" :component-id (:id container)))
(let [has-asset-reference? (has-asset-reference-fn asset-type library-id)
linked-shapes (cph/select-objects has-asset-reference? container)]
linked-shapes (cp/select-objects has-asset-reference? container)]
(loop [shapes (seq linked-shapes)
rchanges []
uchanges []]
@ -209,7 +220,8 @@
(= (:component-file shape) library-id)))
:colors
(fn [shape] (if (= (:type shape) :text)
(fn [shape]
(if (= (:type shape) :text)
(->> shape
:content
;; Check if any node in the content has a reference for the library
@ -245,11 +257,12 @@
[_ library-id state container shape]
(generate-sync-shape-direct container
(:id shape)
(get state :workspace-data)
(get state :workspace-libraries)
(get-local-library state)
(get-libraries state)
false))
(defn- generate-sync-text-shape [shape container update-node]
(defn- generate-sync-text-shape
[shape container update-node]
(let [old-content (:content shape)
new-content (ut/map-node update-node old-content)
rchanges [(as-> {:type :mod-obj
@ -257,7 +270,7 @@
:operations [{:type :set
:attr :content
:val new-content}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
uchanges [(as-> {:type :mod-obj
@ -265,7 +278,7 @@
:operations [{:type :set
:attr :content
:val old-content}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
@ -275,6 +288,7 @@
(defmethod generate-sync-shape :colors
[_ library-id state container shape]
(log/debug :msg "Sync colors of shape" :shape (:name shape))
;; Synchronize a shape that uses some colors of the library. The value of the
;; color in the library is copied to the shape.
@ -298,13 +312,13 @@
(let [rchanges [(as-> {:type :mod-obj
:id (:id shape)
:operations roperations} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
uchanges [(as-> {:type :mod-obj
:id (:id shape)
:operations uoperations} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
[rchanges uchanges]))
@ -327,6 +341,7 @@
(defmethod generate-sync-shape :typographies
[_ library-id state container shape]
(log/debug :msg "Sync typographies of shape" :shape (:name shape))
;; Synchronize a shape that uses some typographies of the library. The attributes
;; of the typography are copied to the shape."
@ -342,7 +357,7 @@
(defn- get-assets
[library-id asset-type state]
(if (nil? library-id)
(if (= library-id (:current-file-id state))
(get-in state [:workspace-data asset-type])
(get-in state [:workspace-libraries library-id :data asset-type])))
@ -354,17 +369,17 @@
be copied to this one.
If reset? is true, all changed attributes will be copied and the 'touched'
flags in the instance shape will be cleared."
[container shape-id local-file libraries reset?]
[container shape-id local-library libraries reset?]
(log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?)
(let [shape-inst (cph/get-shape container shape-id)
component (cph/get-component (:component-id shape-inst)
(let [shape-inst (cp/get-shape container shape-id)
component (cp/get-component (:component-id shape-inst)
(:component-file shape-inst)
local-file
local-library
libraries)
shape-master (cph/get-shape component (:shape-ref shape-inst))
shape-master (cp/get-shape component (:shape-ref shape-inst))
root-inst shape-inst
root-master (cph/get-component-root component)]
root-master (cp/get-component-root component)]
(generate-sync-shape-direct-recursive container
shape-inst
@ -407,9 +422,9 @@
container
options))
children-inst (mapv #(cph/get-shape container %)
children-inst (mapv #(cp/get-shape container %)
(:shapes shape-inst))
children-master (mapv #(cph/get-shape component %)
children-master (mapv #(cp/get-shape component %)
(:shapes shape-master))
only-inst (fn [shape-inst]
@ -468,18 +483,18 @@
shapes.
And if the component shapes are, in turn, instances of a second component,
their 'touched' flags will be set accordingly."
[page-id shape-id local-file libraries]
[page-id shape-id local-library libraries]
(log/debug :msg "Sync shape inverse" :shape (str shape-id))
(let [container (cph/get-container page-id :page local-file)
shape-inst (cph/get-shape container shape-id)
component (cph/get-component (:component-id shape-inst)
(let [container (cp/get-container page-id :page local-library)
shape-inst (cp/get-shape container shape-id)
component (cp/get-component (:component-id shape-inst)
(:component-file shape-inst)
local-file
local-library
libraries)
shape-master (cph/get-shape component (:shape-ref shape-inst))
shape-master (cp/get-shape component (:shape-ref shape-inst))
root-inst shape-inst
root-master (cph/get-component-root component)]
root-master (cp/get-component-root component)]
(generate-sync-shape-inverse-recursive container
shape-inst
@ -509,7 +524,7 @@
shape-master
root-master)
component-container (cph/make-container component :component)
component-container (cp/make-container component :component)
[rchanges uchanges]
(concat-changes
@ -528,9 +543,9 @@
(change-touched shape-inst nil container {:reset-touched? true})
empty-changes)))
children-inst (mapv #(cph/get-shape container %)
children-inst (mapv #(cp/get-shape container %)
(:shapes shape-inst))
children-master (mapv #(cph/get-shape component %)
children-master (mapv #(cp/get-shape component %)
(:shapes shape-master))
only-inst (fn [shape-inst]
@ -607,15 +622,15 @@
children-inst)
:else
(if (cph/is-master-of child-master child-inst)
(if (cp/is-master-of child-master child-inst)
(recur (next children-inst)
(next children-master)
(concat-changes [rchanges uchanges]
(both-cb child-inst child-master)))
(let [child-inst' (d/seek #(cph/is-master-of child-master %)
(let [child-inst' (d/seek #(cp/is-master-of child-master %)
children-inst)
child-master' (d/seek #(cph/is-master-of % child-inst)
child-master' (d/seek #(cp/is-master-of % child-inst)
children-master)]
(cond
(nil? child-inst')
@ -643,20 +658,15 @@
(concat-changes (both-cb child-inst child-master'))
(concat-changes (moved-cb child-inst' child-master))))))))))))
(defn concat-changes
[[rchanges1 uchanges1] [rchanges2 uchanges2]]
[(d/concat rchanges1 rchanges2)
(d/concat uchanges1 uchanges2)])
(defn- add-shape-to-instance
[component-shape component container root-instance root-master omit-touched?]
(log/info :msg (str "ADD [P] " (:name component-shape)))
(let [component-parent-shape (cph/get-shape component (:parent-id component-shape))
parent-shape (d/seek #(cph/is-master-of component-parent-shape %)
(cph/get-object-with-children (:id root-instance)
(let [component-parent-shape (cp/get-shape component (:parent-id component-shape))
parent-shape (d/seek #(cp/is-master-of component-parent-shape %)
(cp/get-object-with-children (:id root-instance)
(:objects container)))
all-parents (vec (cons (:id parent-shape)
(cph/get-parents parent-shape (:objects container))))
(cp/get-parents parent-shape (:objects container))))
update-new-shape (fn [new-shape original-shape]
(let [new-shape (reposition-shape new-shape
@ -667,28 +677,13 @@
(assoc :frame-id (:frame-id parent-shape))
(nil? (:shape-ref original-shape))
(assoc :shape-ref (:id original-shape))
(some? (:shape-ref original-shape))
(assoc :shape-ref (:shape-ref original-shape))
(:component-id original-shape)
(assoc :component-id (:component-id original-shape))
(:component-file original-shape)
(assoc :component-file (:component-file original-shape))
(:component-root original-shape)
(assoc :component-root (:component-root original-shape))
(:touched original-shape)
(assoc :touched (:touched original-shape)))))
(assoc :shape-ref (:id original-shape)))))
update-original-shape (fn [original-shape new-shape]
original-shape)
[new-shape new-shapes _]
(cph/clone-object component-shape
(cp/clone-object component-shape
(:id parent-shape)
(get component :objects)
update-new-shape
@ -704,13 +699,13 @@
(cond-> $
(:frame-id shape')
(assoc :frame-id (:frame-id shape')))
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container)))))
new-shapes)
[(as-> {:type :reg-objects
:shapes all-parents} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))])
@ -719,24 +714,24 @@
(as-> {:type :del-obj
:id (:id shape')
:ignore-touched true} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container)))))
new-shapes))]
(if (and (cph/touched-group? parent-shape :shapes-group) omit-touched?)
(if (and (cp/touched-group? parent-shape :shapes-group) omit-touched?)
empty-changes
[rchanges uchanges])))
(defn- add-shape-to-master
[shape component page root-instance root-master]
(log/info :msg (str "ADD [C] " (:name shape)))
(let [parent-shape (cph/get-shape page (:parent-id shape))
component-parent-shape (d/seek #(cph/is-master-of % parent-shape)
(cph/get-object-with-children (:id root-master)
(let [parent-shape (cp/get-shape page (:parent-id shape))
component-parent-shape (d/seek #(cp/is-master-of % parent-shape)
(cp/get-object-with-children (:id root-master)
(:objects component)))
all-parents (vec (cons (:id component-parent-shape)
(cph/get-parents component-parent-shape (:objects component))))
(cp/get-parents component-parent-shape (:objects component))))
update-new-shape (fn [new-shape original-shape]
(reposition-shape new-shape
@ -750,7 +745,7 @@
original-shape))
[new-shape new-shapes updated-shapes]
(cph/clone-object shape
(cp/clone-object shape
(:id component-parent-shape)
(get page :objects)
update-new-shape
@ -802,17 +797,17 @@
(defn- remove-shape
[shape container omit-touched?]
(log/info :msg (str "REMOVE-SHAPE "
(if (cph/page? container) "[P] " "[C] ")
(if (cp/page? container) "[P] " "[C] ")
(:name shape)))
(let [objects (get container :objects)
parents (cph/get-parents (:id shape) objects)
parents (cp/get-parents (:id shape) objects)
parent (first parents)
children (cph/get-children (:id shape) objects)
children (cp/get-children (:id shape) objects)
rchanges [(as-> {:type :del-obj
:id (:id shape)
:ignore-touched true} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
@ -820,14 +815,14 @@
(let [shape' (get objects id)]
(as-> {:type :add-obj
:id id
:index (cph/position-on-parent id objects)
:index (cp/position-on-parent id objects)
:parent-id (:parent-id shape')
:ignore-touched true
:obj shape'} $
(cond-> $
(:frame-id shape')
(assoc :frame-id (:frame-id shape')))
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))))
@ -836,31 +831,31 @@
(map add-change children)
[(as-> {:type :reg-objects
:shapes (vec parents)} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))])]
(if (and (cph/touched-group? parent :shapes-group) omit-touched?)
(if (and (cp/touched-group? parent :shapes-group) omit-touched?)
empty-changes
[rchanges uchanges])))
(defn- move-shape
[shape index-before index-after container omit-touched?]
(log/info :msg (str "MOVE "
(if (cph/page? container) "[P] " "[C] ")
(if (cp/page? container) "[P] " "[C] ")
(:name shape)
" "
index-before
" -> "
index-after))
(let [parent (cph/get-shape container (:parent-id shape))
(let [parent (cp/get-shape container (:parent-id shape))
rchanges [(as-> {:type :mov-objects
:parent-id (:parent-id shape)
:shapes [(:id shape)]
:index index-after
:ignore-touched true} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
uchanges [(as-> {:type :mov-objects
@ -868,11 +863,11 @@
:shapes [(:id shape)]
:index index-before
:ignore-touched true} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
(if (and (cph/touched-group? parent :shapes-group) omit-touched?)
(if (and (cp/touched-group? parent :shapes-group) omit-touched?)
empty-changes
[rchanges uchanges])))
@ -886,7 +881,7 @@
empty-changes
(do
(log/info :msg (str "CHANGE-TOUCHED "
(if (cph/page? container) "[P] " "[C] ")
(if (cp/page? container) "[P] " "[C] ")
(:name dest-shape))
:options options)
(let [rchanges [(as-> {:type :mod-obj
@ -898,7 +893,7 @@
nil
copy-touched?
(:touched orig-shape))}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
@ -907,7 +902,7 @@
:operations
[{:type :set-touched
:touched (:touched dest-shape)}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
[rchanges uchanges]))))
@ -918,16 +913,16 @@
empty-changes
(do
(log/info :msg (str "SET-TOUCHED-SHAPES-GROUP "
(if (cph/page? container) "[P] " "[C] ")
(if (cp/page? container) "[P] " "[C] ")
(:name shape)))
(let [rchanges [(as-> {:type :mod-obj
:id (:id shape)
:operations
[{:type :set-touched
:touched (cph/set-touched-group
:touched (cp/set-touched-group
(:touched shape)
:shapes-group)}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
@ -936,7 +931,7 @@
:operations
[{:type :set-touched
:touched (:touched shape)}]} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
[rchanges uchanges]))))
@ -962,7 +957,7 @@
(log/info :msg (str "SYNC "
(:name origin-shape)
" -> "
(if (cph/page? container) "[P] " "[C] ")
(if (cp/page? container) "[P] " "[C] ")
(:name dest-shape)))
(let [; To synchronize geometry attributes we need to make a prior
@ -1002,13 +997,13 @@
rchanges [(as-> {:type :mod-obj
:id (:id dest-shape)
:operations roperations} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]
uchanges [(as-> {:type :mod-obj
:id (:id dest-shape)
:operations uoperations} $
(if (cph/page? container)
(if (cp/page? container)
(assoc $ :page-id (:id container))
(assoc $ :component-id (:id container))))]]
[rchanges uchanges])

View file

@ -112,7 +112,8 @@
(def workspace-local-library
(l/derived (fn [state]
(select-keys (get state :workspace-data)
[:colors
[:id
:colors
:media
:typographies
:components]))

View file

@ -122,7 +122,7 @@
(let [root-shape (cp/get-root-shape shape objects)
component-id (when root-shape (:component-id root-shape))
component-file-id (when root-shape (:component-file root-shape))
component-file (when component-file-id (get libraries component-file-id))
component-file (when component-file-id (get libraries component-file-id nil))
component (when component-id
(if component-file
(get-in component-file [:data :components component-id])
@ -141,7 +141,7 @@
""
(let [component-id (:component-id shape)
component-file-id (:component-file shape)
component-file (when component-file-id (get libraries component-file-id))
component-file (when component-file-id (get libraries component-file-id nil))
component (if component-file
(get-in component-file [:data :components component-id])
(get components component-id))]

View file

@ -36,7 +36,6 @@
(get-in state [:viewer-libraries file-id :data :typographies]))]
#(l/derived get-library st/state)))
(def properties [:fill-color
:fill-color-gradient
:font-family

View file

@ -80,9 +80,6 @@
(-> (js->clj fill-color-gradient :keywordize-keys true)
(update :type keyword)))
fill-color-ref-id (obj/get data "fill-color-ref-id")
fill-color-ref-file (obj/get data "fill-color-ref-file")
;; Uncomment this to allow to remove text colors. This could break the texts that already exist
;;[r g b a] (if (nil? fill-color)
;; [0 0 0 0] ;; Transparent color

View file

@ -16,6 +16,7 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.context :as ctx]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.hooks :refer [use-rxsub]]
[app.main.ui.icons :as i]
@ -50,6 +51,8 @@
{:keys [id] :as shape} (:shape mdata)
selected (:selected mdata)
current-file-id (mf/use-ctx ctx/current-file-id)
do-duplicate #(st/emit! dw/duplicate-selected)
do-delete #(st/emit! dw/delete-selected)
do-copy #(st/emit! dw/copy-selected)
@ -73,7 +76,7 @@
do-update-component #(do
(st/emit! (dwc/start-undo-transaction))
(st/emit! (dwl/update-component id))
(st/emit! (dwl/sync-file nil))
(st/emit! (dwl/sync-file current-file-id))
(st/emit! (dwc/commit-undo-transaction)))
do-show-component #(st/emit! (dw/go-to-layout :assets))
do-navigate-component-file #(st/emit! (dwl/nav-to-component-file
@ -154,7 +157,7 @@
;; WARNING: this menu is the same as the context menu at the sidebar.
;; If you change it, you must change equally the file
;; app/main/ui/workspace/sidebar/options/component.cljs
(if (nil? (:component-file shape))
(if (= (:component-file shape) current-file-id)
[:*
[:& menu-separator]
[:& menu-entry {:title (t locale "workspace.shape.menu.detach-instance")

View file

@ -51,6 +51,7 @@
:top nil
:left nil
:component-id nil})
on-duplicate
(mf/use-callback
(mf/deps state)
@ -61,7 +62,7 @@
(mf/deps state)
(fn []
(st/emit! (dwl/delete-component {:id (:component-id @state)}))
(st/emit! (dwl/sync-file nil))))
(st/emit! (dwl/sync-file file-id))))
on-rename
(mf/use-callback
@ -99,7 +100,7 @@
on-drag-start
(mf/use-callback
(fn [component event]
(dnd/set-data! event "app/component" {:file-id (if local? nil file-id)
(dnd/set-data! event "app/component" {:file-id file-id
:component component})
(dnd/set-allowed-effect! event "move")))]
@ -260,7 +261,7 @@
[(tr "workspace.assets.delete") on-delete]]}])])]))
(mf/defc color-item
[{:keys [color local? locale] :as props}]
[{:keys [color local? file-id locale] :as props}]
(let [rename? (= (:color-for-rename @refs/workspace-local) (:id color))
id (:id color)
input-ref (mf/use-ref)
@ -283,12 +284,12 @@
rename-color
(fn [name]
(st/emit! (dwl/update-color (assoc color :name name))))
(st/emit! (dwl/update-color (assoc color :name name) file-id)))
edit-color
(fn [new-color]
(let [updated-color (merge new-color (select-keys color [:id :file-id :name]))]
(st/emit! (dwl/update-color updated-color))))
(st/emit! (dwl/update-color updated-color file-id))))
delete-color
(fn []
@ -406,9 +407,10 @@
(let [color (cond-> color
(:value color) (assoc :color (:value color) :opacity 1)
(:value color) (dissoc :value)
true (assoc :file-id (when (not local?) file-id)))]
true (assoc :file-id file-id))]
[:& color-item {:key (:id color)
:color color
:file-id file-id
:local? local?
:locale locale}]))])]))
@ -433,12 +435,12 @@
(mf/use-callback
(mf/deps file-id)
(fn [typography changes]
(st/emit! (dwl/update-typography (merge typography changes)))))
(st/emit! (dwl/update-typography (merge typography changes) file-id))))
handle-typography-selection
(fn [typography]
(let [attrs (merge
{:typography-ref-file (when-not local? file-id)
{:typography-ref-file file-id
:typography-ref-id (:id typography)}
(d/without-keys typography [:id :name]))]
(run! #(st/emit! (dwt/update-text-attrs {:id % :editor (get-in local [:editors %]) :attrs attrs}))

View file

@ -13,6 +13,7 @@
[app.common.pages :as cp]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.data.workspace :as dw]
@ -25,7 +26,9 @@
(mf/defc component-menu
[{:keys [ids values] :as props}]
(let [id (first ids)
(let [current-file-id (mf/use-ctx ctx/current-file-id)
id (first ids)
locale (mf/deref i18n/locale)
local (mf/use-state {:menu-open false})
@ -51,7 +54,7 @@
do-update-component #(do
(st/emit! (dwc/start-undo-transaction))
(st/emit! (dwl/update-component id))
(st/emit! (dwl/sync-file nil))
(st/emit! (dwl/sync-file current-file-id))
(st/emit! (dwc/commit-undo-transaction)))
do-show-component #(st/emit! (dw/go-to-layout :assets))
do-navigate-component-file #(st/emit! (dwl/nav-to-component-file
@ -72,7 +75,7 @@
;; app/main/ui/workspace/context_menu.cljs
[:& context-menu {:on-close on-menu-close
:show (:menu-open @local)
:options (if (nil? (:component-file values))
:options (if (= (:component-file values) current-file-id)
[[(t locale "workspace.shape.menu.detach-instance") do-detach-component]
[(t locale "workspace.shape.menu.reset-overrides") do-reset-component]
[(t locale "workspace.shape.menu.update-master") do-update-component]

View file

@ -21,6 +21,7 @@
[app.main.refs :as refs]
[app.main.data.modal :as modal]
[app.main.ui.hooks :as h]
[app.main.ui.context :as ctx]
[app.main.ui.components.color-bullet :as cb]
[app.main.ui.components.numeric-input :refer [numeric-input]]))
@ -64,11 +65,14 @@
(mf/defc color-row
[{:keys [color disable-gradient disable-opacity on-change on-open on-close]}]
(let [file-colors (mf/deref refs/workspace-file-colors)
(let [current-file-id (mf/use-ctx ctx/current-file-id)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)
get-color-name (fn [{:keys [id file-id]}]
(let [src-colors (if file-id (get-in shared-libs [file-id :data :colors]) file-colors)]
(let [src-colors (if (= file-id current-file-id)
file-colors
(get-in shared-libs [file-id :data :colors]))]
(get-in src-colors [id :name])))
parse-color (fn [color]

View file

@ -12,6 +12,7 @@
[rumext.alpha :as mf]
[cuerdas.core :as str]
[okulary.core :as l]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.common.data :as d]
[app.common.uuid :as uuid]
@ -177,6 +178,7 @@
shapes] :as props}]
(let [locale (mf/deref i18n/locale)
current-file-id (mf/use-ctx ctx/current-file-id)
typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)
label (case type
@ -201,16 +203,16 @@
typography (cond
(and (:typography-ref-id values)
(not= (:typography-ref-id values) :multiple)
(:typography-ref-file values))
(not= (:typography-ref-file values) current-file-id))
(-> shared-libs
(get-in [(:typography-ref-file values) :data :typographies (:typography-ref-id values)])
(assoc :file-id (:typography-ref-file values)))
(and (:typography-ref-id values)
(not= (:typography-ref-id values) :multiple))
(not= (:typography-ref-id values) :multiple)
(= (:typography-ref-file values) current-file-id))
(get typographies (:typography-ref-id values)))
on-convert-to-typography
(mf/use-callback
(mf/deps values)
@ -234,7 +236,7 @@
handle-change-typography
(fn [changes]
(st/emit! (dwl/update-typography (merge typography changes))))
(st/emit! (dwl/update-typography (merge typography changes) current-file-id)))
opts #js {:editor editor
:ids ids
@ -253,7 +255,7 @@
(cond
typography
[:& typography-entry {:typography typography
:read-only? (some? (:typography-ref-file values))
:read-only? (not= (:typography-ref-file values) current-file-id)
:file (get shared-libs (:typography-ref-file values))
:on-deattach handle-deattach-typography
:on-change handle-change-typography}]

View file

@ -25,9 +25,7 @@
(defn format-fill-color [_ shape]
(let [color {:color (:fill-color shape)
:opacity (:fill-opacity shape)
:gradient (:fill-color-gradient shape)
:id (:fill-ref-id shape)
:file-id (:fill-ref-file-id shape)}]
:gradient (:fill-color-gradient shape)}]
(uc/color->background color)))
(defn format-stroke [_ shape]
@ -35,9 +33,7 @@
style (name (:stroke-style shape))
color {:color (:stroke-color shape)
:opacity (:stroke-opacity shape)
:gradient (:stroke-color-gradient shape)
:id (:stroke-ref-id shape)
:file-id (:stroke-ref-file-id shape)}]
:gradient (:stroke-color-gradient shape)}]
(str/format "%spx %s %s" width style (uc/color->background color))))
(def styles-data