♻️ Refactor state locality

The main purpose of this refactor is reduce
a custom state from different pages and unify
them under common access patterns
This commit is contained in:
Andrey Antukh 2025-01-16 11:00:14 +01:00
parent f62aecb383
commit 85746e7cb2
110 changed files with 2254 additions and 2125 deletions

View file

@ -47,31 +47,28 @@
(str/join "")))
(defn- format-comment-url
[thread {:keys [team-id file-id page-id]}]
[thread file]
(str/ffmt "%/#/workspace?%"
(cf/get :public-uri)
(uri/map->query-string
{:file-id file-id
:page-id page-id
:team-id team-id
{:file-id (:id file)
:page-id (:page-id file)
:team-id (:team-id file)
:comment-id (:id thread)})))
(defn- format-comment-ref
[{:keys [seqn]} {:keys [file-name page-name]}]
(str/ffmt "#%, %, %" seqn file-name page-name))
[thread file]
(str/ffmt "#%, %, %"
(:seqn thread)
(:name file)
(:page-name file)))
(defn get-team-users
(defn- get-team-users
[conn team-id]
(->> (teams/get-users+props conn team-id)
(map profile/decode-row)
(d/index-by :id)))
(defn- resolve-profile-name
[conn profile-id]
(-> (db/get conn :profile {:id profile-id}
{::sql/columns [:fullname]})
(get :fullname)))
(defn- notification-email?
[profile-id owner-id props]
(if (= profile-id owner-id)
@ -83,24 +80,22 @@
(not= :none (-> props :notifications :email-comments)))
(defn send-comment-emails!
[conn {:keys [profile-id team-id] :as params} comment thread]
(let [team-users (get-team-users conn team-id)
source-user (resolve-profile-name conn profile-id)
comment-reference (format-comment-ref thread params)
[conn profile comment thread file]
(let [team-users (get-team-users conn (:team-id file))
comment-reference (format-comment-ref thread file)
comment-content (format-comment comment)
comment-url (format-comment-url thread params)
comment-url (format-comment-url thread file)
profile-id (get profile :id)
;; Users mentioned in this comment
comment-mentions
(-> (:mentions comment)
(set/difference #{profile-id}))
(disj profile-id))
;; Users mentioned in this thread
thread-mentions
(-> (:mentions thread)
;; Remove the mentions in the thread because we're already sending a
;; Remove the mentions in the comment because we're already sending a
;; notification
(set/difference comment-mentions)
(disj profile-id))
@ -118,9 +113,10 @@
(eml/send!
{::eml/conn conn
::eml/factory eml/comment-mention
:public-uri (cf/get :public-uri)
:to email
:name fullname
:source-user source-user
:source-user (:fullname profile)
:comment-reference comment-reference
:comment-content comment-content
:comment-url comment-url}))))
@ -132,9 +128,10 @@
(eml/send!
{::eml/conn conn
::eml/factory eml/comment-thread
:public-uri (cf/get :public-uri)
:to email
:name fullname
:source-user source-user
:source-user (:fullname profile)
:comment-reference comment-reference
:comment-content comment-content
:comment-url comment-url}))))
@ -146,9 +143,10 @@
(eml/send!
{::eml/conn conn
::eml/factory eml/comment-notification
:public-uri (cf/get :public-uri)
:to email
:name fullname
:source-user source-user
:source-user (:fullname profile)
:comment-reference comment-reference
:comment-content comment-content
:comment-url comment-url}))))))
@ -165,12 +163,13 @@
(def ^:private
sql:get-file
"select f.id, f.modified_at, f.revn, f.features, f.name,
f.project_id, p.team_id, f.data
from file as f
join project as p on (p.id = f.project_id)
where f.id = ?
and f.deleted_at is null")
"SELECT f.id, f.modified_at, f.revn, f.features, f.name,
f.project_id, p.team_id, f.data,
f.data_ref_id, f.data_backend
FROM file as f
INNER JOIN project as p on (p.id = f.project_id)
WHERE f.id = ?
AND (f.deleted_at IS NULL OR f.deleted_at > now())")
(defn- get-file
"A specialized version of get-file for comments module."
@ -182,12 +181,16 @@
:hint "file not found"))
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)]
(let [{:keys [data] :as file} (files/decode-row file)]
(let [file (->> file
(files/decode-row)
(feat.fdata/resolve-file-data cfg))
data (get file :data)]
(-> file
(assoc :page-name (dm/get-in data [:pages-index page-id :name]))
(assoc :page-id page-id)
(dissoc :data))))))
;; FIXME: rename
(defn- get-comment-thread
[conn thread-id & {:as opts}]
(-> (db/get-by-id conn :comment-thread thread-id opts)
@ -249,6 +252,9 @@
(def ^:private sql:comment-threads
"SELECT DISTINCT ON (ct.id)
ct.*,
pf.fullname AS owner_fullname,
pf.email AS owner_email,
pf.photo_id AS owner_photo_id,
p.team_id AS team_id,
f.name AS file_name,
f.project_id AS project_id,
@ -265,6 +271,7 @@
INNER JOIN file AS f ON (f.id = ct.file_id)
INNER JOIN project AS p ON (p.id = f.project_id)
LEFT JOIN comment_thread_status AS cts ON (cts.thread_id = ct.id AND cts.profile_id = ?)
LEFT JOIN profile AS pf ON (ct.owner_id = pf.id)
WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)")
(def ^:private sql:comment-threads-by-file-id
@ -360,15 +367,25 @@
::sm/params schema:get-comments}
[cfg {:keys [::rpc/profile-id thread-id share-id]}]
(db/run! cfg (fn [{:keys [::db/conn]}]
(let [{:keys [file-id] :as thread} (get-comment-thread conn thread-id)]
(let [{:keys [file-id]} (get-comment-thread conn thread-id)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(get-comments conn thread-id)))))
(def sql:get-comments
"SELECT c.*,
ct.file_id AS file_id,
pf.fullname AS owner_fullname,
pf.email AS owner_email,
pf.photo_id AS owner_photo_id
FROM comment AS c
INNER JOIN comment_thread AS ct ON (ct.id = c.thread_id)
LEFT JOIN profile AS pf ON (c.owner_id = pf.id)
WHERE c.thread_id = ?
ORDER BY c.created_at ASC")
(defn- get-comments
[conn thread-id]
(->> (db/query conn :comment
{:thread-id thread-id}
{:order-by [[:created-at :asc]]})
(->> (db/exec! conn [sql:get-comments thread-id])
(into [] xf-decode-row)))
;; --- COMMAND: Get file comments users
@ -429,7 +446,21 @@
[:page-id ::sm/uuid]
[:frame-id ::sm/uuid]
[:share-id {:optional true} [:maybe ::sm/uuid]]
[:mentions {:optional true} [:vector ::sm/uuid]]])
[:mentions {:optional true} [::sm/set ::sm/uuid]]])
(defn- update-thread-seqn
[conn file-id seqn]
(db/update! conn :file
{:comment-thread-seqn seqn}
{:id file-id}
{::db/return-keys false}))
(defn add-owner
[thread-or-comment profile]
(-> thread-or-comment
(assoc :owner-fullname (:fullname profile))
(assoc :owner-email (:email profile))
(assoc :owner-photo-id (:photo-id profile))))
(sv/defmethod ::create-comment-thread
{::doc/added "1.15"
@ -437,10 +468,10 @@
::rtry/enabled true
::rtry/when rtry/conflict-exception?
::sm/params schema:create-comment-thread}
[cfg {:keys [::rpc/profile-id ::rpc/request-at file-id page-id share-id mentions position content frame-id]}]
[cfg {:keys [::rpc/profile-id file-id page-id share-id] :as params}]
(files/check-comment-permissions! cfg profile-id file-id share-id)
(let [{:keys [team-id project-id page-name name]} (get-file cfg file-id page-id)]
(let [{:keys [team-id project-id] :as file} (get-file cfg file-id page-id)]
(-> cfg
(assoc ::quotes/profile-id profile-id)
(assoc ::quotes/team-id team-id)
@ -449,26 +480,14 @@
(quotes/check! {::quotes/id ::quotes/comment-threads-per-file}
{::quotes/id ::quotes/comments-per-file}))
(let [params {:created-at request-at
:profile-id profile-id
:file-id file-id
:file-name name
:page-id page-id
:page-name page-name
:position position
:content content
:frame-id frame-id
:team-id team-id
:project-id project-id
:mentions mentions}
thread (-> (db/tx-run! cfg create-comment-thread params)
(decode-row))]
(let [params (assoc params ::file file)
thread (db/tx-run! cfg create-comment-thread params)]
(vary-meta thread assoc ::audit/props thread))))
(defn- create-comment-thread
[{:keys [::db/conn] :as cfg}
{:keys [profile-id file-id page-id page-name created-at position content mentions frame-id] :as params}]
{:keys [::rpc/profile-id ::rpc/request-at ::file position content mentions frame-id] :as params}]
(let [;; NOTE: we take the next seq number from a separate query
;; because we need to lock the file for avoid race conditions
@ -479,46 +498,47 @@
;; different storage (example: redis) for alivate the update
;; pression on the file table
seqn (get-next-seqn conn file-id)
profile (profile/get-profile conn profile-id)
seqn (get-next-seqn conn (:id file))
file-id (get file :id)
thread-id (uuid/next)
thread (-> (db/insert! conn :comment-thread
{:id thread-id
:file-id file-id
:page-name (:page-name file)
:page-id (:page-id file)
:owner-id profile-id
:participants (db/tjson #{profile-id})
:page-name page-name
:page-id page-id
:created-at created-at
:modified-at created-at
:created-at request-at
:modified-at request-at
:seqn seqn
:position (db/pgpoint position)
:frame-id frame-id
:position (db/pgpoint position)
:mentions (db/encode-pgarray mentions conn "uuid")})
(decode-row))
comment (-> (db/insert! conn :comment
{:id (uuid/next)
:thread-id thread-id
:owner-id profile-id
:created-at created-at
:modified-at created-at
:created-at request-at
:modified-at request-at
:mentions (db/encode-pgarray mentions conn "uuid")
:content content})
(decode-row))]
;; Make the current thread as read.
(upsert-comment-thread-status! conn profile-id thread-id created-at)
(upsert-comment-thread-status! conn profile-id thread-id request-at)
;; Optimistic update of current seq number on file.
(db/update! conn :file
{:comment-thread-seqn seqn}
{:id file-id}
{::db/return-keys false})
(update-thread-seqn conn file-id seqn)
;; Send mentions emails
(send-comment-emails! conn params comment thread)
(send-comment-emails! conn profile comment thread file)
(-> thread
(select-keys [:id :file-id :page-id :mentions])
(add-owner profile)
(assoc :comment-id (:id comment)))))
;; --- COMMAND: Update Comment Thread Status
@ -534,7 +554,7 @@
::sm/params schema:update-comment-thread-status
::db/transaction true}
[{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}]
(let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
(let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(upsert-comment-thread-status! conn profile-id id)))
@ -552,7 +572,7 @@
::sm/params schema:update-comment-thread
::db/transaction true}
[{:keys [::db/conn]} {:keys [::rpc/profile-id id is-resolved share-id]}]
(let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
(let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(db/update! conn :comment-thread
{:is-resolved is-resolved}
@ -561,15 +581,13 @@
;; --- COMMAND: Add Comment
(declare ^:private get-comment-thread)
(def ^:private
schema:create-comment
[:map {:title "create-comment"}
[:thread-id ::sm/uuid]
[:content [:string {:max 250}]]
[:share-id {:optional true} [:maybe ::sm/uuid]]
[:mentions {:optional true} [:vector ::sm/uuid]]])
[:mentions {:optional true} [::sm/set ::sm/uuid]]])
(sv/defmethod ::create-comment
{::doc/added "1.15"
@ -577,65 +595,58 @@
::sm/params schema:create-comment
::db/transaction true}
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content mentions]}]
(let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)
{file-name :name :keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)]
(let [{:keys [file-id page-id] :as thread}
(get-comment-thread conn thread-id ::sql/for-update true)
{:keys [team-id project-id] :as file}
(get-file cfg file-id page-id)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(quotes/check! cfg {::quotes/id ::quotes/comments-per-file
::quotes/profile-id profile-id
::quotes/team-id team-id
::quotes/project-id project-id
::quotes/file-id file-id})
;; Update the page-name cached attribute on comment thread table.
(when (not= page-name (:page-name thread))
(db/update! conn :comment-thread
{:page-name page-name}
{:id thread-id}))
(let [comment (-> (db/insert!
conn :comment
{:id (uuid/next)
(let [profile (profile/get-profile conn profile-id)
mentions (into #{} mentions)
params {:id (uuid/next)
:created-at request-at
:modified-at request-at
:thread-id thread-id
:owner-id profile-id
:content content
:mentions
(-> mentions
(set)
(db/encode-pgarray conn "uuid"))})
(decode-row))
props {:file-id file-id
:share-id nil}]
:mentions (db/encode-pgarray mentions conn "uuid")}
comment (-> (db/insert! conn :comment params)
(decode-row)
(add-owner profile))]
;; Update thread modified-at attribute and assoc the current
;; profile to the participant set.
(db/update! conn :comment-thread
{:modified-at request-at
:participants (-> (:participants thread #{})
(conj profile-id)
(db/tjson))
:mentions (-> (:mentions thread)
(set)
(into mentions)
(db/encode-pgarray conn "uuid"))}
{:id thread-id})
(let [mentions (into (:mentions thread) mentions)
participants (-> (:participants thread #{})
(conj profile-id))
params {:modified-at request-at
:participants (db/tjson participants)
:mentions (db/encode-pgarray mentions conn "uuid")}
;; Update the current profile status in relation to the
;; current thread.
;; Update the page-name cached attribute on comment thread table.
params (cond-> params
(not= (:page-name file) (:page-name thread))
(assoc :page-name (:page-name file)))]
(db/update! conn :comment-thread params
{:id thread-id}
{::db/return-keys false}))
;; Update the current profile status in relation to the current thread
(upsert-comment-thread-status! conn profile-id thread-id)
(let [params {:project-id project-id
:profile-id profile-id
:team-id team-id
:file-id (:file-id thread)
:page-id (:page-id thread)
:file-name file-name
:page-name page-name}]
(send-comment-emails! conn params comment thread))
(send-comment-emails! conn profile comment thread file)
(vary-meta comment assoc ::audit/props props))))
(vary-meta comment assoc ::audit/props comment))))
;; --- COMMAND: Update Comment
@ -645,16 +656,20 @@
[:id ::sm/uuid]
[:content [:string {:max 250}]]
[:share-id {:optional true} [:maybe ::sm/uuid]]
[:mentions {:optional true} [:vector ::sm/uuid]]])
[:mentions {:optional true} [::sm/set ::sm/uuid]]])
;; TODO: Check if there are new mentions, if there are send the new emails.
;; TODO Check if there are new mentions, if there are send the new emails.
(sv/defmethod ::update-comment
{::doc/added "1.15"
::sm/params schema:update-comment
::db/transaction true}
[{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at id share-id content mentions]}]
(let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::sql/for-update true)
{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)]
(let [{:keys [thread-id owner-id] :as comment}
(get-comment conn id ::sql/for-update true)
{:keys [file-id page-id] :as thread}
(get-comment-thread conn thread-id ::sql/for-update true)]
(files/check-comment-permissions! conn profile-id file-id share-id)
@ -675,10 +690,10 @@
:page-name page-name
:mentions
(-> (:mentions thread)
(set)
(into mentions)
(db/encode-pgarray conn "uuid"))}
{:id thread-id})
{:id thread-id}
{::db/return-keys false})
nil)))
;; --- COMMAND: Delete Comment Thread
@ -700,7 +715,8 @@
(ex/raise :type :validation
:code :not-allowed))
(db/delete! conn :comment-thread {:id id})
(db/delete! conn :comment-thread {:id id}
{::db/return-keys false})
nil))
;; --- COMMAND: Delete comment
@ -716,13 +732,19 @@
::sm/params schema:delete-comment
::db/transaction true}
[{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}]
(let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::sql/for-update true)
{:keys [file-id] :as thread} (get-comment-thread conn thread-id)]
(let [{:keys [owner-id thread-id] :as comment}
(get-comment conn id ::sql/for-update true)
{:keys [file-id]}
(get-comment-thread conn thread-id)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(when-not (= owner-id profile-id)
(ex/raise :type :validation
:code :not-allowed))
(db/delete! conn :comment {:id id})
(db/delete! conn :comment {:id id}
{::db/return-keys false})
nil))
;; --- COMMAND: Update comment thread position
@ -740,13 +762,14 @@
::sm/params schema:update-comment-thread-position
::db/transaction true}
[{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id position frame-id share-id]}]
(let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
(let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(db/update! conn :comment-thread
{:modified-at request-at
:position (db/pgpoint position)
:frame-id frame-id}
{:id (:id thread)})
{:id id}
{::db/return-keys false})
nil))
;; --- COMMAND: Update comment frame
@ -763,10 +786,11 @@
::sm/params schema:update-comment-thread-frame
::db/transaction true}
[{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id frame-id share-id]}]
(let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
(let [{:keys [file-id]} (get-comment-thread conn id ::sql/for-update true)]
(files/check-comment-permissions! conn profile-id file-id share-id)
(db/update! conn :comment-thread
{:modified-at request-at
:frame-id frame-id}
{:id id})
{:id id}
{::db/return-keys false})
nil))

View file

@ -614,7 +614,8 @@
l.name,
l.revn,
l.vern,
l.synced_at
l.synced_at,
l.is_shared
FROM libs AS l
WHERE l.deleted_at IS NULL OR l.deleted_at > now();")

View file

@ -70,6 +70,7 @@
:deleted-at nil})]
{:users members
:profiles members
:fonts fonts
:project project
:share-links links

View file

@ -13,7 +13,6 @@
[app.common.types.color :as ctc]
[app.common.types.colors-list :as ctcl]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.pages-list :as ctpl]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
@ -43,8 +42,7 @@
frame-id (if (cfh/frame-shape? parent)
(:id parent)
(:frame-id parent))]
(ctf/update-file-data
file
(update file :data
(fn [file-data]
(ctpl/update-page file-data
(:id page)
@ -60,8 +58,9 @@
[file label & {:keys [page-label]}]
(let [page (if page-label
(thf/get-page file page-label)
(thf/current-page file))]
(ctst/get-shape page (thi/id label))))
(thf/current-page file))
shape-id (thi/id label)]
(ctst/get-shape page shape-id)))
(defn get-shape-by-id
[file id & {:keys [page-label]}]
@ -76,8 +75,7 @@
(thf/get-page file page-label)
(thf/current-page file))
shape (ctst/get-shape page (thi/id shape-label))]
(ctf/update-file-data
file
(update file :data
(fn [file-data]
(ctpl/update-page file-data
(:id page)
@ -104,7 +102,7 @@
(defn add-sample-library-color
[file label & {:keys [] :as params}]
(let [color (sample-color label params)]
(ctf/update-file-data file #(ctcl/add-color % color))))
(update file :data ctcl/add-color color)))
(defn sample-typography
[label & {:keys [] :as params}]
@ -113,7 +111,7 @@
(defn add-sample-typography
[file label & {:keys [] :as params}]
(let [typography (sample-typography label params)]
(ctf/update-file-data file #(cttl/add-typography % typography))))
(update file :data cttl/add-typography typography)))
(defn add-interaction
[file origin-label dest-label]
@ -124,8 +122,7 @@
(ctsi/set-destination (:id dest))
(assoc :position-relative-to (:id origin)))
interactions (ctsi/add-interaction (:interactions origin) interaction)]
(ctf/update-file-data
file
(update file :data
(fn [file-data]
(ctpl/update-page file-data
(:id page)

View file

@ -143,6 +143,7 @@
;; --- fill
;; FIXME: revisit, this generates invalid colors
(defn fill->shape-color
[fill]
(d/without-nils
@ -153,6 +154,16 @@
:ref-id (:fill-color-ref-id fill)
:ref-file (:fill-color-ref-file fill)}))
(defn fill->color
[fill]
(d/without-nils
{:color (:fill-color fill)
:opacity (:fill-opacity fill)
:gradient (:fill-color-gradient fill)
:image (:fill-image fill)
:id (:fill-color-ref-id fill)
:file-id (:fill-color-ref-file fill)}))
(defn set-fill-color
[shape position color opacity gradient image]
(update-in shape [:fills position]

View file

@ -103,4 +103,3 @@
(txt/transform-nodes #(not= (:typography-ref-file %) file-id)
remove-ref-file
content)))))

View file

@ -12,6 +12,7 @@
[app.common.logging :as log]
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
[app.main.data.helpers :as dsh]
[app.main.features :as features]
[app.main.worker :as uw]
[app.util.time :as dt]
@ -76,12 +77,8 @@
(ptk/reify ::apply-changes-localy
ptk/UpdateEvent
(update [_ state]
(let [current-file-id (get state :current-file-id)
path (if (= file-id current-file-id)
[:workspace-data]
[:libraries file-id :data])
undo-changes (if pending
(let [undo-changes
(if pending
(->> pending
(map :undo-changes)
(reverse)
@ -89,19 +86,21 @@
(vec))
nil)
redo-changes (if pending
redo-changes
(if pending
(into redo-changes
(mapcat :redo-changes)
pending)
redo-changes)]
redo-changes)
(d/update-in-when state path
(fn [file]
(let [file (cpc/process-changes file undo-changes false)
file (cpc/process-changes file redo-changes false)
apply-changes
(fn [fdata]
(let [fdata (cpc/process-changes fdata undo-changes false)
fdata (cpc/process-changes fdata redo-changes false)
pids (into #{} xf:map-page-id redo-changes)]
(reduce #(ctst/update-object-indices %1 %2) file pids))))))))
(reduce #(ctst/update-object-indices %1 %2) fdata pids)))]
(update-in state [:files file-id :data] apply-changes)))))
(defn commit
"Create a commit event instance"
@ -156,17 +155,11 @@
(defn- resolve-file-revn
[state file-id]
(let [file (:workspace-file state)]
(if (= (:id file) file-id)
(:revn file)
(dm/get-in state [:libraries file-id :revn]))))
(:revn (dsh/lookup-file state file-id)))
(defn- resolve-file-vern
[state file-id]
(let [file (:workspace-file state)]
(if (= (:id file) file-id)
(:vern file)
(dm/get-in state [:libraries file-id :vern]))))
(:vern (dsh/lookup-file state file-id)))
(defn commit-changes
"Schedules a list of changes to execute now, and add the corresponding undo changes to

View file

@ -13,7 +13,8 @@
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
[app.main.data.event :as ev]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.data.team :as dtm]
[app.main.repo :as rp]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -25,8 +26,10 @@
[:file-id ::sm/uuid]
[:project-id ::sm/uuid]
[:owner-id ::sm/uuid]
[:page-name {:optional true} :string]
[:file-name :string]
[:owner-fullname {:optional true} ::sm/text]
[:owner-email {:optional true} ::sm/email]
[:page-name {:optional true} ::sm/text]
[:file-name ::sm/text]
[:seqn :int]
[:content :string]
[:participants ::sm/set-of-uuid]
@ -40,7 +43,10 @@
[:map {:title "Comment"}
[:id ::sm/uuid]
[:thread-id ::sm/uuid]
[:file-id ::sm/uuid]
[:owner-id ::sm/uuid]
[:owner-fullname {:optional true} ::sm/text]
[:owner-email {:optional true} ::sm/email]
[:created-at ::sm/inst]
[:modified-at ::sm/inst]
[:content :string]])
@ -75,10 +81,11 @@
(ptk/reify ::created-thread-on-workspace
ptk/UpdateEvent
(update [_ state]
(let [position (select-keys thread [:position :frame-id])]
(let [position (select-keys thread [:position :frame-id])
page-id (or page-id (:current-page-id state))]
(-> state
(update :comment-threads assoc id (dissoc thread :comment))
(update-in [:workspace-data :pages-index page-id :comment-thread-positions] assoc id position)
(dsh/update-page page-id #(update % :comment-thread-positions assoc id position))
(cond-> open?
(update :comments-local assoc :open id))
(update :comments-local assoc :options nil)
@ -94,8 +101,6 @@
:id id
:content-size (count (:content comment))}))))))
(def ^:private
schema:create-thread-on-workspace
[:map {:title "created-thread-on-workspace"}
@ -114,7 +119,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
frame-id (ctst/get-frame-id-by-position objects (:position params))
params (-> params
(update-mentions)
@ -263,7 +268,7 @@
(rx/of (refresh-comment-thread thread)))))))
(defn update-comment
[{:keys [id content thread-id] :as comment}]
[{:keys [id content thread-id file-id] :as comment}]
(dm/assert!
"expected valid comment"
(check-comment! comment))
@ -277,15 +282,13 @@
ptk/UpdateEvent
(update [_ state]
(-> state
(d/update-in-when [:comments thread-id id] assoc :content content)))
(d/update-in-when state [:comments thread-id id] assoc :content content))
ptk/WatchEvent
(watch [_ state _]
(let [file-id (:current-file-id state)
share-id (-> state :viewer-local :share-id)
params (-> {:id id :content content :share-id share-id}
(update-mentions))]
(let [share-id (-> state :viewer-local :share-id)
params {:id id :content content :share-id share-id}
params (update-mentions params)]
(->> (rp/cmd! :update-comment params)
(rx/catch #(rx/throw {:type :comment-error}))
(rx/map #(retrieve-comment-threads file-id)))))))
@ -299,11 +302,10 @@
(ptk/reify ::delete-comment-thread-on-workspace
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)]
(-> state
(update-in [:workspace-data :pages-index page-id :comment-thread-positions] dissoc id)
(dsh/update-page #(update % :comment-thread-positions dissoc id))
(update :comments dissoc id)
(update :comment-threads dissoc id))))
(update :comment-threads dissoc id)))
ptk/WatchEvent
(watch [_ _ _]
@ -380,35 +382,37 @@
(rx/map #(partial fetched %))
(rx/catch #(rx/throw {:type :comment-error}))))))))
(defn- comment-threads-fetched
[threads]
(ptk/reify ::comment-threads-fetched
ptk/UpdateEvent
(update [_ state]
(reduce (fn [state {:keys [id file-id page-id] :as thread}]
(-> state
(update :comment-threads assoc id thread)
(dsh/update-page file-id page-id
(fn [page]
(update-in page [:comment-thread-positions id]
(fn [state]
(-> state
(assoc :position (:position thread))
(assoc :frame-id (:frame-id thread)))))))))
state
threads))))
(defn retrieve-comment-threads
[file-id]
(dm/assert! (uuid? file-id))
(letfn [(set-comment-threds [state comment-thread]
(let [path [:workspace-data :pages-index (:page-id comment-thread) :comment-thread-positions (:id comment-thread)]
thread-position (get-in state path)]
(cond-> state
(nil? thread-position)
(->
(assoc-in (conj path :position) (:position comment-thread))
(assoc-in (conj path :frame-id) (:frame-id comment-thread))))))
(fetched [[users comments] state]
(let [pages (-> (get-in state [:workspace-data :pages])
set)
comments (filter #(contains? pages (:page-id %)) comments)
state (-> state
(assoc :comment-threads (d/index-by :id comments))
(update :current-file-comments-users merge (d/index-by :id users)))]
(reduce set-comment-threds state comments)))]
(ptk/reify ::retrieve-comment-threads
ptk/WatchEvent
(watch [_ state _]
(let [share-id (-> state :viewer-local :share-id)]
(->> (rx/zip (rp/cmd! :get-team-users {:file-id file-id})
(rp/cmd! :get-comment-threads {:file-id file-id :share-id share-id}))
(rx/take 1)
(rx/map #(partial fetched %))
(rx/catch #(rx/throw {:type :comment-error}))))))))
(rx/merge
(->> (rp/cmd! :get-comment-threads {:file-id file-id :share-id share-id})
(rx/map comment-threads-fetched))
;; Refresh team members
(rx/of (dtm/fetch-members)))))))
(defn retrieve-comments
[thread-id]
@ -423,6 +427,8 @@
(rx/map #(partial fetched %))
(rx/catch #(rx/throw {:type :comment-error}))))))))
;; FIXME: revisit
(defn retrieve-unread-comment-threads
"A event used mainly in dashboard for retrieve all unread threads of a team."
[team-id]
@ -544,6 +550,13 @@
;; Helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-owner
[thread-or-comment]
{:id (:owner-id thread-or-comment)
:fullname (:owner-fullname thread-or-comment)
:email (:owner-email thread-or-comment)
:photo-id (:owner-photo-id thread-or-comment)})
(defn group-threads-by-page
[threads]
(letfn [(group-by-page [result thread]
@ -621,7 +634,7 @@
(ptk/reify ::detach-comment-thread
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
is-frame? (fn [id] (= :frame (get-in objects [id :type])))
frame-ids? (into #{} (filter is-frame?) ids)]
@ -635,7 +648,7 @@
(defn fetch-profiles
"Fetch or refresh all profile data for comments of the current file"
[]
(ptk/reify ::fetch-comments-profiles
(ptk/reify ::fetch-profiles
ptk/WatchEvent
(watch [_ state _]
(let [file-id (:current-file-id state)

View file

@ -12,6 +12,7 @@
[app.common.schema :as sm]
[app.common.types.components-list :as ctkl]
[app.common.types.team :as ctt]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.persistence :as-alias dps]
@ -111,8 +112,9 @@
ptk/WatchEvent
(watch [_ state _]
(let [features (features/get-team-enabled-features state)
data (:workspace-data state)
file (:workspace-file state)]
file (dsh/lookup-file state)
data (get file :data)]
(->> (if (and data file)
(rx/of {:name (:name file)
:components-count (count (ctkl/components-seq data))
@ -368,7 +370,9 @@
(let [team-id (or team-id (:current-team-id state))
file-id (or file-id (:current-file-id state))
page-id (or page-id (:current-page-id state)
(dm/get-in state [:workspace-data :pages 0]))
(-> (dsh/lookup-file-data state file-id)
(get :pages)
(first)))
params (-> (rt/get-params state)
(assoc :team-id team-id)

View file

@ -8,9 +8,9 @@
(:require
[app.common.uuid :as uuid]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.persistence :as dwp]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
@ -56,11 +56,11 @@
(watch [_ state _]
(let [file-id (:current-file-id state)
page-id (:current-page-id state)
selected (or selected (wsh/lookup-selected state page-id {}))
selected (or selected (dsh/lookup-selected state page-id {}))
shapes (if (seq selected)
(wsh/lookup-shapes state selected)
(reverse (wsh/filter-shapes state #(pos? (count (:exports %))))))
(dsh/lookup-shapes state selected)
(reverse (dsh/filter-shapes state #(pos? (count (:exports %))))))
exports (for [shape shapes
export (:exports shape)]

View file

@ -327,27 +327,23 @@
;; Workspace related events
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- update-recent-font
"Moves the font/font to the top of the list of recents and then truncates up to 4"
[state file-id font]
(let [xform (comp
(remove #(= font %))
(take 3))]
(update state file-id #(into [font] xform %))))
(defn add-recent-font
[font]
(ptk/reify ::add-recent-font
ptk/UpdateEvent
(update [_ state]
(let [recent-fonts (get-in state [:workspace-data :recent-fonts])
most-recent-fonts (into [font] (comp (remove #(= font %)) (take 3)) recent-fonts)]
(assoc-in state [:workspace-data :recent-fonts] most-recent-fonts)))
(let [file-id (:current-file-id state)]
(update state :recent-fonts update-recent-font file-id font)))
ptk/EffectEvent
(effect [_ state _]
(let [most-recent-fonts (get-in state [:workspace-data :recent-fonts])]
;; FIXME: this should be prefixed by team
(swap! storage/user assoc ::recent-fonts most-recent-fonts)))))
(defn load-recent-fonts
[fonts]
(ptk/reify ::load-recent-fonts
ptk/UpdateEvent
(update [_ state]
(let [fonts-map (d/index-by :id fonts)
saved-recent-fonts (->> (::recent-fonts storage/user)
(keep #(get fonts-map (:id %)))
(into #{}))]
(assoc-in state [:workspace-data :recent-fonts] saved-recent-fonts)))))
(let [recent-fonts (:recent-fonts state)]
(swap! storage/user assoc :recent-fonts recent-fonts)))))

View file

@ -0,0 +1,170 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.helpers
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.svg.path.command :as upc]))
(defn lookup-profile
([state]
(:profile state))
([state profile-id]
(dm/get-in state [:profiles profile-id])))
(defn lookup-libraries
"Retrieve all libraries, including the local file."
[state]
(:files state))
(defn lookup-file
([state]
(lookup-file state (:current-file-id state)))
([state file-id]
(dm/get-in state [:files file-id])))
(defn lookup-file-data
([state]
(lookup-file-data state (:current-file-id state)))
([state file-id]
(dm/get-in state [:files file-id :data])))
(defn get-page
[fdata page-id]
(dm/get-in fdata [:pages-index page-id]))
(defn lookup-page
([state]
(let [file-id (:current-file-id state)
page-id (:current-page-id state)]
(lookup-page state file-id page-id)))
([state page-id]
(let [file-id (:current-file-id state)]
(lookup-page state file-id page-id)))
([state file-id page-id]
(dm/get-in state [:files file-id :data :pages-index page-id])))
(defn lookup-page-objects
([state]
(lookup-page-objects state
(:current-file-id state)
(:current-page-id state)))
([state page-id]
(lookup-page-objects state
(:current-file-id state)
page-id))
([state file-id page-id]
(-> (lookup-page state file-id page-id)
(get :objects))))
(defn process-selected-shapes
([objects selected]
(process-selected-shapes objects selected nil))
([objects selected {:keys [omit-blocked?] :or {omit-blocked? false}}]
(letfn [(selectable? [id]
(and (contains? objects id)
(or (not omit-blocked?)
(not (get-in objects [id :blocked] false)))))]
(let [selected (->> selected (cfh/clean-loops objects))]
(into (d/ordered-set)
(filter selectable?)
selected)))))
;; DEPRECATED
(defn lookup-selected-raw
[state]
(dm/get-in state [:workspace-local :selected]))
(defn get-selected-ids
[state]
(dm/get-in state [:workspace-local :selected]))
(defn lookup-selected
([state]
(lookup-selected state (:current-page-id state) nil))
([state options]
(lookup-selected state (:current-page-id state) options))
([state page-id options]
(let [objects (lookup-page-objects state page-id)
selected (dm/get-in state [:workspace-local :selected])]
(process-selected-shapes objects selected options))))
(defn lookup-shape
([state id]
(lookup-shape state (:current-page-id state) id))
([state page-id id]
(let [objects (lookup-page-objects state page-id)]
(get objects id))))
(defn lookup-shapes
([state ids]
(lookup-shapes state (:current-page-id state) ids))
([state page-id ids]
(let [objects (lookup-page-objects state page-id)]
(into [] (keep (d/getf objects)) ids))))
(defn update-file
([state f]
(update-file state (:current-file-id state) f))
([state file-id f]
(d/update-in-when state [:files file-id] f)))
(defn update-page
([state f]
(update-page state
(:current-file-id state)
(:current-page-id state)
f))
([state page-id f]
(update-page state
(:current-file-id state)
page-id
f))
([state file-id page-id f]
(d/update-in-when state [:files file-id :data :pages-index page-id] f)))
(defn filter-shapes
([state filter-fn]
(filter-shapes state (:current-page-id state) filter-fn))
([state page-id filter-fn]
(let [objects (lookup-page-objects state page-id)]
(into [] (filter filter-fn) (vals objects)))))
(defn select-bool-children
[state parent-id]
(let [objects (lookup-page-objects state)
shape-modifiers
(:workspace-modifiers state)
content-modifiers
(dm/get-in state [:workspace-local :edit-path])]
(reduce (fn [result id]
(if-let [shape (get objects id)]
(let [modifiers (dm/get-in shape-modifiers [id :modifiers])
shape (if (some? modifiers)
(gsh/transform-shape shape modifiers)
shape)
modifiers (dm/get-in content-modifiers [id :content-modifiers])
shape (if (some? modifiers)
(update shape :content upc/apply-content-modifiers modifiers)
shape)]
(assoc result id shape))
result))
{}
(cfh/get-children-ids objects parent-id))))
(defn get-viewport-center
[state]
(when-let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])]
(gpt/point (+ x (/ width 2)) (+ y (/ height 2)))))

View file

@ -11,6 +11,7 @@
[app.common.logging :as log]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.repo :as rp]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -49,11 +50,7 @@
ptk/UpdateEvent
(update [_ state]
(log/dbg :hint "update-file-revn" :file-id (dm/str file-id) :revn revn)
(if-let [current-file-id (:current-file-id state)]
(if (= file-id current-file-id)
(update-in state [:workspace-file :revn] max revn)
(d/update-in-when state [:libraries file-id :revn] max revn))
state))
(dsh/update-file state file-id #(update % :revn max revn)))
ptk/EffectEvent
(effect [_ _ _]

View file

@ -10,7 +10,7 @@
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.types.shape-tree :as ctst]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.fonts :as fonts]
[app.main.refs :as refs]
[app.util.code-beautify :as cb]
@ -57,7 +57,7 @@
(ptk/reify ::update-preview
ptk/EffectEvent
(effect [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects shape-id)
all-children
@ -94,7 +94,7 @@
(ptk/reify ::open-preview-selected
ptk/WatchEvent
(watch [_ state _]
(let [shape-id (first (wsh/lookup-selected state))
(let [shape-id (first (dsh/lookup-selected state))
closed-preview (rx/subject)
preview (.open js/window "/#/frame-preview")
listener-fn #(rx/push! closed-preview true)]

View file

@ -330,19 +330,6 @@
(rx/map (constantly (refresh-profile)))
(rx/catch on-error))))))
(defn fetch-users
[]
(letfn [(fetched [users state]
(->> users
(d/index-by :id)
(assoc state :users)))]
(ptk/reify ::fetch-team-users
ptk/WatchEvent
(watch [_ state _]
(let [team-id (:current-team-id state)]
(->> (rp/cmd! :get-team-users {:team-id team-id})
(rx/map #(partial fetched %))))))))
(defn fetch-file-comments-users
[{:keys [team-id]}]
(dm/assert! (uuid? team-id))

View file

@ -13,8 +13,8 @@
[app.common.types.shape :as cts]
[app.common.types.tokens-lib :as ctob]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.refs :as refs]
[app.main.ui.workspace.tokens.token-set :as wtts]
[app.main.ui.workspace.tokens.update :as wtu]
[beicon.v2.core :as rx]
@ -42,18 +42,15 @@
;; TOKENS Getters
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-tokens-lib [state]
(get-in state [:workspace-data :tokens-lib]))
(defn get-tokens-lib
[state]
(-> (dsh/lookup-file-data state)
(get :tokens-lib)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TOKENS Actions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn get-token-data-from-token-id
[id]
(let [workspace-data (deref refs/workspace-data)]
(get (:tokens workspace-data) id)))
(defn set-selected-token-set-path
[full-path]
(ptk/reify ::set-selected-token-set-path
@ -112,7 +109,8 @@
(ptk/reify ::delete-token-theme
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-token-theme group name))]
@ -178,7 +176,7 @@
(ptk/reify ::import-tokens-lib
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
update-token-set-change (some-> lib
(ctob/get-sets)
(first)
@ -196,7 +194,7 @@
(ptk/reify ::delete-token-set-path
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-token-set-path prefixed-full-set-path))]
@ -259,7 +257,7 @@
(ptk/reify ::delete-token
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-token set-name token-name))]

View file

@ -40,6 +40,7 @@
[app.main.data.common :as dcm]
[app.main.data.event :as ev]
[app.main.data.fonts :as df]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.plugins :as dp]
@ -67,7 +68,6 @@
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.texts :as dwtxt]
[app.main.data.workspace.thumbnails :as dwth]
[app.main.data.workspace.transforms :as dwt]
@ -174,16 +174,21 @@
(ptk/reify ::libraries-fetched
ptk/UpdateEvent
(update [_ state]
(assoc state :libraries (d/index-by :id libraries)))
(let [libraries (d/index-by :id libraries)]
(update state :files merge libraries)))
ptk/WatchEvent
(watch [_ state _]
(let [file-id (dm/get-in state [:workspace-file :id])
ignore-until (dm/get-in state [:workspace-file :ignore-sync-until])
needs-check? (some #(and (> (:modified-at %) (:synced-at %))
(let [file (dsh/lookup-file state)
file-id (get file :id)
ignore-until (get file :ignore-sync-until)
needs-check?
(some #(and (> (:modified-at %) (:synced-at %))
(or (not ignore-until)
(> (:modified-at %) ignore-until)))
libraries)]
(when needs-check?
(rx/concat (rx/timer 1000)
(rx/of (dwl/notify-sync-file file-id))))))))
@ -213,21 +218,17 @@
(rx/map dwl/library-thumbnails-fetched))))))))))
(defn- workspace-initialized
[]
[file-id]
(ptk/reify ::workspace-initialized
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc :workspace-undo {})
(assoc :workspace-ready true)))
(assoc :workspace-ready file-id)))
ptk/WatchEvent
(watch [_ state _]
(rx/of
(when (and (not (boolean (-> state :profile :props :v2-info-shown)))
(features/active-feature? state "components/v2"))
(modal/show :v2-info {}))
(dp/check-open-plugin)
(watch [_ _ _]
(rx/of (dp/check-open-plugin)
(fdf/fix-deleted-fonts)
(fbs/fix-broken-shapes)))))
@ -242,10 +243,10 @@
ptk/UpdateEvent
(update [_ state]
(let [file-id (:id file)]
(-> state
(assoc :thumbnails thumbnails)
(assoc :workspace-file (dissoc file :data))
(assoc :workspace-data (:data file))))
(update :files assoc file-id file))))
ptk/WatchEvent
(watch [_ state _]
@ -317,11 +318,13 @@
(ptk/reify ::initialize-workspace
ptk/UpdateEvent
(update [_ state]
(assoc state
:recent-colors (:recent-colors storage/user)
:workspace-ready false
:current-file-id file-id
:workspace-presence {}))
(-> state
(dissoc :files)
(dissoc :workspace-ready)
(assoc :recent-colors (:recent-colors storage/user))
(assoc :recent-fonts (:recent-fonts storage/user))
(assoc :current-file-id file-id)
(assoc :workspace-presence {})))
ptk/WatchEvent
(watch [_ state stream]
@ -341,7 +344,7 @@
(rx/map deref)
(rx/mapcat (fn [{:keys [file]}]
(rx/of (dpj/initialize-project (:project-id file))
(-> (workspace-initialized)
(-> (workspace-initialized file-id)
(with-meta {:file-id file-id}))))))
(when-let [component-id (some-> rparams :component-id parse-uuid)]
@ -388,12 +391,11 @@
ptk/UpdateEvent
(update [_ state]
(-> state
;; FIXME: revisit
(dissoc
:current-file-id
:workspace-data
:workspace-editor-state
:workspace-file
:libraries
:files
:workspace-media-objects
:workspace-persistence
:workspace-presence
@ -431,7 +433,7 @@
(ptk/reify ::initialize-page
ptk/UpdateEvent
(update [_ state]
(if-let [{:keys [id] :as page} (dm/get-in state [:workspace-data :pages-index page-id])]
(if-let [{:keys [id] :as page} (dsh/lookup-page state page-id)]
;; we maintain a cache of page state for user convenience with the exception of the
;; selection; when user abandon the current page, the selection is lost
(let [local (dm/get-in state [:workspace-cache id] default-workspace-local)]
@ -483,7 +485,7 @@
(cond
(some? metadata) (cf/resolve-file-media metadata)
(some? fill-image) (cf/resolve-file-media fill-image)))))
uris (into #{} xform (wsh/lookup-page-objects state page-id))]
uris (into #{} xform (dsh/lookup-page-objects state page-id))]
(->> (rx/from uris)
(rx/subs! #(http/fetch-data-uri % false)))))))
@ -503,7 +505,9 @@
ptk/WatchEvent
(watch [it state _]
(let [pages (get-in state [:workspace-data :pages-index])
(let [pages (-> (dsh/lookup-file-data state)
(get :pages-index))
unames (cfh/get-used-names pages)
name (cfh/generate-unique-name unames "Page 1")
@ -518,14 +522,14 @@
ptk/WatchEvent
(watch [it state _]
(let [id (uuid/next)
pages (get-in state [:workspace-data :pages-index])
fdata (dsh/lookup-file-data state)
pages (get fdata :pages-index)
page (get pages page-id)
unames (cfh/get-used-names pages)
page (get-in state [:workspace-data :pages-index page-id])
name (cfh/generate-unique-name unames (:name page))
fdata (:workspace-data state)
components-v2 (dm/get-in fdata [:options :components-v2])
objects (->> (:objects page)
(d/mapm (fn [_ val] (dissoc val :use-for-thumbnail))))
objects (update-vals (:objects page) #(dissoc % :use-for-thumbnail))
main-instances-ids (set (keep #(when (ctk/main-instance? (val %)) (key %)) objects))
ids-to-remove (set (apply concat (map #(cfh/get-children-ids objects %) main-instances-ids)))
@ -537,7 +541,7 @@
component
fdata
(gpt/point (:x shape) (:y shape))
components-v2
true
{:keep-ids? true})
children (into {} (map (fn [shape] [(:id shape) shape]) new-shapes))
objs (assoc objs id new-shape)]
@ -576,10 +580,9 @@
(ptk/reify ::rename-page
ptk/WatchEvent
(watch [it state _]
(let [page (get-in state [:workspace-data :pages-index id])
(let [page (dsh/lookup-page state id)
changes (-> (pcb/empty-changes it)
(pcb/mod-page page {:name name}))]
(rx/of (dch/commit-changes changes))))))
(defn set-plugin-data
@ -599,20 +602,14 @@
(ptk/reify ::set-file-plugin-data
ptk/WatchEvent
(watch [it state _]
(let [file-data
(if (= file-id (:current-file-id state))
(:workspace-data state)
(get-in state [:libraries file-id :data]))
changes
(-> (pcb/empty-changes it)
(let [file-data (dm/get-in state [:files file-id :data])
changes (-> (pcb/empty-changes it)
(pcb/with-file-data file-data)
(assoc :file-id file-id)
(pcb/set-plugin-data type id page-id namespace key value))]
(rx/of (dch/commit-changes changes)))))))
(declare purge-page)
(declare go-to-file)
(defn- delete-page-components
[changes page]
@ -633,30 +630,29 @@
(ptk/reify ::delete-page
ptk/WatchEvent
(watch [it state _]
(let [components-v2 (features/active-feature? state "components/v2")
file-id (:current-file-id state)
file (wsh/get-file state file-id)
pages (get-in state [:workspace-data :pages])
(let [file-id (:current-file-id state)
fdata (dsh/lookup-file-data state file-id)
pindex (:pages-index fdata)
pages (:pages fdata)
index (d/index-of pages id)
page (get-in state [:workspace-data :pages-index id])
page (get pindex id)
page (assoc page :index index)
changes (cond-> (pcb/empty-changes it)
components-v2
(pcb/with-library-data file)
components-v2
changes (-> (pcb/empty-changes it)
(pcb/with-library-data fdata)
(delete-page-components page)
:always
(pcb/del-page page))]
(rx/of (dch/commit-changes changes)
(when (= id (:current-page-id state))
(go-to-file)))))))
(dcm/go-to-workspace)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; WORKSPACE File Actions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FIXME: move to common
(defn rename-file
[id name]
{:pre [(uuid? id) (string? name)]}
@ -668,7 +664,8 @@
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :name] name))
(let [file-id (:current-file-id state)]
(assoc-in state [:files file-id :name] name)))
ptk/WatchEvent
(watch [_ _ _]
@ -752,7 +749,7 @@
ptk/WatchEvent
(watch [_ state _]
(when-let [shape-id (d/nilv shape-id (dm/get-in state [:workspace-local :shape-for-rename]))]
(let [shape (wsh/lookup-shape state shape-id)
(let [shape (dsh/lookup-shape state shape-id)
name (str/trim name)
clean-name (cfh/clean-path name)
valid? (and (not (str/ends-with? name "/"))
@ -782,7 +779,7 @@
(ptk/reify ::update-selected-shapes
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/from (map #(update-shape % attrs) selected))))))
;; --- Delete Selected
@ -793,7 +790,7 @@
(ptk/reify ::delete-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
(let [selected (dsh/lookup-selected state)
hover-guides (get-in state [:workspace-guides :hover])]
(cond
(d/not-empty? selected)
@ -812,7 +809,7 @@
(ptk/reify ::start-rename-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
(let [selected (dsh/lookup-selected state)
id (first selected)]
(when (= (count selected) 1)
(rx/of (dcm/go-to-workspace :layout :layers)
@ -832,8 +829,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected-ids (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected-ids (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected-ids)
undo-id (js/Symbol)
@ -876,7 +873,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
;; Ignore any shape whose parent is also intended to be moved
ids (cfh/clean-loops objects ids)
@ -906,7 +903,7 @@
(ptk/reify ::relocate-selected-shapes
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (relocate-shapes selected parent-id to-index))))))
(defn start-editing-selected
@ -914,8 +911,8 @@
(ptk/reify ::start-editing-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)]
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)]
(if (> (count selected) 1)
(let [shapes-to-select
@ -950,8 +947,8 @@
(ptk/reify ::select-parent-layer
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
shapes-to-select
(->> selected
(reduce
@ -970,7 +967,8 @@
(ptk/reify ::relocate-page
ptk/WatchEvent
(watch [it state _]
(let [prev-index (-> (get-in state [:workspace-data :pages])
(let [prev-index (-> (dsh/lookup-file-data state)
(get :pages)
(d/index-of id))
changes (-> (pcb/empty-changes it)
(pcb/move-page id index prev-index))]
@ -1009,8 +1007,8 @@
(ptk/reify ::align-objects
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (or selected (wsh/lookup-selected state))
(let [objects (dsh/lookup-page-objects state)
selected (or selected (dsh/lookup-selected state))
moved (if (= 1 (count selected))
(align-object-to-parent objects (first selected) axis)
(align-objects-list objects selected axis))
@ -1039,8 +1037,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (or ids (wsh/lookup-selected state))
objects (dsh/lookup-page-objects state page-id)
selected (or ids (dsh/lookup-selected state))
moved (-> (map #(get objects %) selected)
(gal/distribute-space axis))
undo-id (js/Symbol)]
@ -1070,8 +1068,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected (dsh/lookup-selected state)
selected-obj (-> (map #(get objects %) selected))
multi (attrs/get-attrs-multi selected-obj [:proportion-lock])
multi? (= :multiple (:proportion-lock multi))]
@ -1157,9 +1155,12 @@
(ptk/reify ::show-component-in-assets
ptk/WatchEvent
(watch [_ state _]
(let [component-path (cfh/split-path (get-in state [:workspace-data :components component-id :path]))
paths (map (fn [i] (cfh/join-path (take (inc i) component-path))) (range (count component-path)))
file-id (:current-file-id state)]
(let [file-id (:current-file-id state)
fdata (dsh/lookup-file-data state file-id)
cpath (dm/get-in fdata [:components component-id :path])
cpath (cfh/split-path cpath)
paths (map (fn [i] (cfh/join-path (take (inc i) cpath)))
(range (count cpath)))]
(rx/concat
(rx/from (map #(set-assets-group-open file-id :components % true) paths))
(rx/of (dcm/go-to-workspace :layout :assets)
@ -1189,8 +1190,8 @@
(ptk/reify ::show-shape-context-menu
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
all-selected (into [] (mapcat #(cfh/get-children-with-self objects %)) selected)
head (get objects (first selected))
@ -1236,7 +1237,7 @@
(ptk/reify ::show-grid-cell-context-menu
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
grid (get objects grid-id)
cells (->> (get-in state [:workspace-grid-edition grid-id :selected])
(map #(get-in grid [:layout-grid-cells %])))]
@ -1260,8 +1261,8 @@
(defn copy-selected
[]
(letfn [(sort-selected [state data]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
;; Narrow the objects map so it contains only relevant data for
;; selected and its parents
@ -1325,9 +1326,10 @@
;; When copying an instance that is nested inside another one, we need to
;; advance the shape refs to one or more levels of remote mains.
(advance-copies [state selected data]
(let [file (wsh/get-local-file-full state)
libraries (wsh/get-libraries state)
page (wsh/lookup-page state)
(let [file (dsh/lookup-file state)
libraries (:files state)
;; FIXME
page (dsh/lookup-page state)
heads (mapcat #(ctn/get-child-heads (:objects data) %) selected)]
(update data :objects
#(reduce (partial advance-copy file libraries page)
@ -1364,15 +1366,16 @@
(catch :default e
(on-copy-error e)))
(let [objects (wsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state)
(let [objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects))
features (-> (features/get-team-enabled-features state)
(set/difference cfeat/frontend-only-features))
file-id (:current-file-id state)
frame-id (cfh/common-parent-frame objects selected)
version (dm/get-in state [:workspace-file :version])
file (dsh/lookup-file state file-id)
version (get file :version)
initial {:type :copied-shapes
:features features
@ -1478,7 +1481,7 @@
(ptk/reify ::paste-from-event
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
edit-id (dm/get-in state [:workspace-local :edition])
is-editing? (and edit-id (= :text (get-in objects [edit-id :type])))]
@ -1516,8 +1519,8 @@
(ptk/reify ::copy-selected-css
ptk/EffectEvent
(effect [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state) (mapv (d/getf objects)))
(let [objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state) (mapv (d/getf objects)))
css (css/generate-style objects selected selected {:with-prelude? false})]
(wapi/write-to-clipboard css)))))
@ -1526,8 +1529,8 @@
(ptk/reify ::copy-selected-css-nested
ptk/EffectEvent
(effect [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state)
(let [objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state)
(cfh/selected-with-children objects)
(mapv (d/getf objects)))
css (css/generate-style objects selected selected {:with-prelude? false})]
@ -1564,14 +1567,14 @@
(js/console.error "clipboard blocked:" error)
(rx/empty))]
(let [selected (->> (wsh/lookup-selected state) first)
objects (wsh/lookup-page-objects state)]
(let [selected (->> (dsh/lookup-selected state) first)
objects (dsh/lookup-page-objects state)]
(when-let [shape (get objects selected)]
(let [props (cts/extract-props shape)
features (-> (features/get-team-enabled-features state)
(set/difference cfeat/frontend-only-features))
version (dm/get-in state [:workspace-file :version])
version (-> (dsh/lookup-file state) :version)
copy-data {:type :copied-props
:features features
@ -1628,8 +1631,8 @@
(rx/catch on-error))))))
(defn selected-frame? [state]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)]
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)]
(and (= 1 (count selected))
(= :frame (get-in objects [(first selected) :type])))))
@ -1643,7 +1646,7 @@
(filter #(contains? parent-ids %)))))
(defn any-same-frame-from-selected? [state frame-ids]
(let [selected (first (wsh/lookup-selected state))]
(let [selected (first (dsh/lookup-selected state))]
(< 0 (count (filter #(= % selected) frame-ids)))))
(defn frame-same-size?
@ -1777,7 +1780,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [features (features/get-team-enabled-features state)
selected (wsh/lookup-selected state)]
selected (dsh/lookup-selected state)]
(when (paste-data-valid? pdata)
(cfeat/check-paste-features! features (:features pdata))
@ -1841,10 +1844,10 @@
change)))
(calculate-paste-position [state pobjects selected position]
(let [page-objects (wsh/lookup-page-objects state)
(let [page-objects (dsh/lookup-page-objects state)
selected-objs (map (d/getf pobjects) selected)
first-selected-obj (first selected-objs)
page-selected (wsh/lookup-selected state)
page-selected (dsh/lookup-selected state)
wrapper (gsh/shapes->rect selected-objs)
orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper))
frame-id (first page-selected)
@ -1954,7 +1957,7 @@
ptk/WatchEvent
(watch [it state _]
(let [file-id (:current-file-id state)
page (wsh/lookup-page state)
page (dsh/lookup-page state)
media-idx (->> (:images pdata)
(d/index-by :prev-id))
@ -1972,10 +1975,12 @@
page-objects (:objects page)
libraries (wsh/get-libraries state)
ldata (wsh/get-local-file state)
libraries (dsh/lookup-libraries state)
ldata (dsh/lookup-file-data state file-id)
full-libs (assoc-in libraries [(:id ldata) :data] ldata)
;; full-libs (assoc-in libraries [(:id ldata) :data] ldata)
full-libs libraries
[parent-id
frame-id] (ctn/find-valid-parent-and-frame-ids candidate-parent-id page-objects (vals objects) true full-libs)
@ -2053,8 +2058,8 @@
(cond
;; Pasting inside a frame
(selected-frame? state)
(let [page-selected (wsh/lookup-selected state)
page-objects (wsh/lookup-page-objects state)
(let [page-selected (dsh/lookup-selected state)
page-objects (dsh/lookup-page-objects state)
frame-id (first page-selected)
frame-object (get page-objects frame-id)]
(gsh/shape->center frame-object))
@ -2133,7 +2138,7 @@
(ptk/reify ::paste-image
ptk/WatchEvent
(watch [_ state _]
(let [file-id (dm/get-in state [:workspace-file :id])
(let [file-id (:current-file-id state)
position (calculate-paste-position state)
params {:file-id file-id
:blobs [image]
@ -2177,7 +2182,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (or page-id (:current-page-id state))
page (wsh/lookup-page state page-id)
page (dsh/lookup-page state page-id)
changes (-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/mod-page {:background (:color color)}))]
@ -2214,12 +2219,24 @@
;; Orphan Shapes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- find-orphan-shapes
([state]
(find-orphan-shapes state (:current-page-id state)))
([state page-id]
(let [objects (dsh/lookup-page-objects state page-id)
objects (filter (fn [item]
(and
(not= (key item) uuid/zero)
(not (contains? objects (:parent-id (val item))))))
objects)]
objects)))
(defn fix-orphan-shapes
[]
(ptk/reify ::fix-orphan-shapes
ptk/WatchEvent
(watch [_ state _]
(let [orphans (set (into [] (keys (wsh/find-orphan-shapes state))))]
(let [orphans (set (into [] (keys (find-orphan-shapes state))))]
(rx/of (relocate-shapes orphans uuid/zero 0 true))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2254,7 +2271,9 @@
(ptk/reify ::update-component-annotation
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data
(dsh/lookup-file-data state)
update-fn
(fn [component]
;; NOTE: we need to ensure the component exists,
@ -2265,7 +2284,8 @@
(dissoc component :annotation)
(assoc component :annotation annotation))))
changes (-> (pcb/empty-changes it)
changes
(-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/update-component id update-fn))]
@ -2323,7 +2343,7 @@
(ptk/reify ::find-components-norefs
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
copies (->> objects
vals
(filter #(and (ctk/instance-head? %) (not (ctk/main-instance? %)))))

View file

@ -16,17 +16,17 @@
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
[potok.v2.core :as ptk]))
(defn selected-shapes-idx
[state]
(let [objects (wsh/lookup-page-objects state)]
(->> (wsh/lookup-selected state)
(let [objects (dsh/lookup-page-objects state)]
(->> (dsh/lookup-selected state)
(cph/clean-loops objects))))
(defn create-bool-data
@ -91,9 +91,9 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
name (-> bool-type d/name str/capital)
ids (->> (or ids (wsh/lookup-selected state))
ids (->> (or ids (dsh/lookup-selected state))
(cph/clean-loops objects))
ordered-indexes (cph/order-by-indexed-shapes objects ids)
shapes (->> ordered-indexes
@ -121,7 +121,7 @@
(ptk/reify ::group-to-bool
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
change-to-bool
(fn [shape] (group->bool shape bool-type objects))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
@ -132,7 +132,7 @@
(ptk/reify ::bool-to-group
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
change-to-group
(fn [shape] (bool->group shape objects))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
@ -144,7 +144,7 @@
(ptk/reify ::change-bool-type
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
change-type
(fn [shape] (assoc shape :bool-type bool-type))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id))

View file

@ -17,11 +17,11 @@
[app.common.types.shape.shadow :refer [check-shadow!]]
[app.main.broadcast :as mbc]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as md]
[app.main.data.workspace.layout :as layout]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.undo :as dwu]
[app.util.storage :as storage]
@ -84,8 +84,7 @@
(defn transform-fill
([state ids color transform] (transform-fill state ids color transform nil))
([state ids color transform options]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
is-text? #(= :text (:type (get objects %)))
text-ids (filter is-text? ids)
shape-ids (remove is-text? ids)
@ -135,7 +134,7 @@
(ptk/reify ::reorder-fills
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
is-text? #(= :text (:type (get objects %)))
text-ids (filter is-text? ids)
@ -234,7 +233,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
is-text? #(= :text (:type (get objects %)))
shape-ids (filter (complement is-text?) ids)
attrs {:hide-fill-on-export hide-fill-on-export}]
@ -436,7 +435,7 @@
(ptk/reify ::picker-for-selected-shape
ptk/WatchEvent
(watch [_ state stream]
(let [ids (wsh/lookup-selected state)
(let [ids (dsh/lookup-selected state)
stop? (rx/filter (ptk/type? ::stop-picker) stream)
update-events
@ -541,8 +540,8 @@
(ptk/reify ::apply-color-from-palette
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state)
(let [objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects))
ids
@ -716,7 +715,7 @@
(ptk/reify ::update-colorpicker
ptk/UpdateEvent
(update [_ state]
(let [shape-id (-> state wsh/lookup-selected first)]
(let [shape-id (-> state dsh/lookup-selected first)]
(update state :colorpicker
(fn [state]
(let [current-color (:current-color state)]
@ -978,8 +977,8 @@
(ptk/reify ::select-color
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
shapes (wsh/lookup-shapes state selected)
(let [selected (dsh/lookup-selected state)
shapes (dsh/lookup-shapes state selected)
shape (first shapes)
fills (if (cfh/text-shape? shape)
(:fills (dwt/current-text-values

View file

@ -17,11 +17,11 @@
[app.main.data.comments :as dcmt]
[app.main.data.common :as dcm]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.common :as dwco]
[app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.viewport :as dwv]
[app.main.repo :as rp]
[app.main.router :as rt]
@ -35,12 +35,11 @@
(defn initialize-comments
[file-id]
(dm/assert! (uuid? file-id))
(ptk/reify ::initialize-comments
ptk/WatchEvent
(watch [_ _ stream]
(let [stopper (rx/filter #(= ::finalize %) stream)]
(rx/merge
(let [stopper-s (rx/filter #(= ::finalize %) stream)]
(->> (rx/merge
(rx/of (dcmt/retrieve-comment-threads file-id))
(->> stream
(rx/filter mse/mouse-event?)
@ -49,12 +48,12 @@
(rx/with-latest-from ms/keyboard-space)
(rx/filter (fn [[_ space]] (not space)))
(rx/map first)
(rx/map handle-comment-layer-click)
(rx/take-until stopper))
(rx/map handle-comment-layer-click))
(->> stream
(rx/filter dwco/interrupt?)
(rx/map handle-interrupt)
(rx/take-until stopper)))))))
(rx/map handle-interrupt)))
(rx/take-until stopper-s))))))
(defn- handle-interrupt
[]
@ -65,9 +64,7 @@
(cond
(:draft local) (rx/of (dcmt/close-thread))
(:open local) (rx/of (dcmt/close-thread))
:else
(rx/of (dwe/clear-edition-mode)
:else (rx/of (dwe/clear-edition-mode)
(dws/deselect-all true)))))))
;; Event responsible of the what should be executed when user clicked
@ -139,9 +136,9 @@
(ptk/reify ::update-comment-thread-position
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
(let [page (dsh/lookup-page state)
page-id (:id page)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
frame-id (if (nil? frame-id)
(ctst/get-frame-id-by-position objects (gpt/point new-x new-y))
(:frame-id thread))
@ -172,7 +169,7 @@
(ptk/reify ::move-frame-comment-threads
ptk/WatchEvent
(watch [_ state _]
(let [page (wsh/lookup-page state)
(let [page (dsh/lookup-page state)
objects (get page :objects)
is-frame? (fn [id] (= :frame (get-in objects [id :type])))

View file

@ -20,8 +20,8 @@
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.constants :refer [zoom-half-pixel-precision]]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.drawing.common :as common]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.snap :as snap]
[app.main.streams :as ms]
[app.util.array :as array]
@ -87,7 +87,7 @@
initial (cond-> @ms/mouse-position snap-pixel? (gpt/round-step snap-prec))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
focus (:workspace-focus-selected state)
fid (->> (ctst/top-nested-frame objects initial)

View file

@ -12,8 +12,8 @@
[app.common.math :as mth]
[app.common.types.modifiers :as ctm]
[app.common.types.shape :as cts]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.worker :as uw]
[beicon.v2.core :as rx]
@ -33,7 +33,7 @@
(watch [_ state _]
(let [tool (dm/get-in state [:workspace-drawing :tool])
shape (dm/get-in state [:workspace-drawing :object])
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
page-id (:current-page-id state)]
(rx/concat

View file

@ -18,8 +18,8 @@
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.drawing.common :as common]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.streams :as ms]
[app.util.mouse :as mse]
[app.util.path.simplify-curve :as ups]
@ -51,7 +51,7 @@
(ptk/reify ::setup-frame
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
content (dm/get-in state [:workspace-drawing :object :content] [])
start (dm/get-in content [0 :params] nil)
position (when start (gpt/point start))

View file

@ -7,8 +7,8 @@
(ns app.main.data.workspace.edition
(:require
[app.common.data.macros :as dm]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.path.common :as dwpc]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -22,7 +22,7 @@
(ptk/reify ::start-edition-mode
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)]
(let [objects (dsh/lookup-page-objects state)]
;; Can only edit objects that exist
(if (contains? objects id)
(-> state
@ -38,7 +38,10 @@
(rx/take 1)
(rx/map clear-edition-mode)))))
;; If these event change modules review /src/app/main/data/workspace/path/undo.cljs
;; IMPORTANT: If this event is moved from this namespace to other,
;; update namespace reference in the
;; app/main/data/workspace/path/undo.cljs file.
(defn clear-edition-mode
[]
(ptk/reify ::clear-edition-mode

View file

@ -7,6 +7,7 @@
(ns app.main.data.workspace.fix-broken-shapes
(:require
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -39,12 +40,12 @@
(ptk/reify ::fix-broken-shapes
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [fdata (dsh/lookup-file-data state)
changes (concat
(mapcat (partial generate-broken-link-changes :page-id)
(vals (:pages-index data)))
(vals (:pages-index fdata)))
(mapcat (partial generate-broken-link-changes :component-id)
(vals (:components data))))]
(vals (:components fdata))))]
(if (seq changes)
(rx/of (dch/commit-changes

View file

@ -9,7 +9,7 @@
[app.common.files.helpers :as cfh]
[app.common.text :as txt]
[app.main.data.changes :as dwc]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.fonts :as fonts]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -91,7 +91,7 @@
objects))
(defn- generate-deleted-font-components-changes
[state]
[fdata]
(sequence
(comp (map val)
(filter should-fix-deleted-font-component?)
@ -99,27 +99,29 @@
{:type :mod-component
:id (:id component)
:objects (-> (fix-deleted-font-component component) :objects)})))
(wsh/lookup-local-components state)))
(:components fdata)))
(defn- generate-deleted-font-typography-changes
[state]
[fdata]
(sequence
(comp (map val)
(filter has-invalid-font-family?)
(map (fn [typography]
{:type :mod-typography
:typography (fix-deleted-font-typography typography)})))
(get-in state [:workspace-data :typographies])))
(:typographies fdata)))
(defn fix-deleted-fonts
[]
(ptk/reify ::fix-deleted-fonts
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
shape-changes (mapcat generate-deleted-font-shape-changes (vals (:pages-index data)))
components-changes (generate-deleted-font-components-changes state)
typography-changes (generate-deleted-font-typography-changes state)
(let [fdata (dsh/lookup-file-data state)
pages (:pages-index fdata)
shape-changes (mapcat generate-deleted-font-shape-changes (vals pages))
components-changes (generate-deleted-font-components-changes fdata)
typography-changes (generate-deleted-font-typography-changes fdata)
changes (concat shape-changes
components-changes
typography-changes)]

View file

@ -11,8 +11,8 @@
[app.common.files.changes-builder :as pcb]
[app.common.types.grid :as ctg]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -26,8 +26,7 @@
(ptk/reify ::add-frame-grid
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
page (dm/get-in state [:workspace-data :pages-index page-id])
(let [page (dsh/lookup-page state)
params (or (dm/get-in page [:default-grids :square])
(:square ctg/default-grid-params))
grid {:type :square
@ -56,7 +55,7 @@
(ptk/reify ::set-default-grid
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)]
(let [page (dsh/lookup-page state)]
(rx/of (dch/commit-changes
(-> (pcb/empty-changes it)
(pcb/with-page page)

View file

@ -9,7 +9,7 @@
[app.common.data.macros :as dm]
[app.common.geom.rect :as grc]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[potok.v2.core :as ptk]))
(defn hover-grid-cell
@ -34,7 +34,7 @@
ptk/UpdateEvent
(update [_ state]
(if shift?
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
grid (get objects grid-id)
selected (or (dm/get-in state [:workspace-grid-edition grid-id :selected]) #{})
selected (into selected [cell-id])
@ -74,7 +74,7 @@
(ptk/reify ::clean-selection
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects grid-id)]
(update-in state [:workspace-grid-edition grid-id :selected]
(fn [selected]
@ -94,7 +94,7 @@
(ptk/reify ::locate-board
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
srect (get-in objects [grid-id :selrect])]
(-> state
(update :workspace-local
@ -111,7 +111,7 @@
(ptk/reify ::select-track-cells
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
parent (get objects grid-id)
cells

View file

@ -17,8 +17,8 @@
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -182,7 +182,7 @@
(watch [it state _]
(let [id (d/nilv id (uuid/next))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes
(->> ids
@ -203,7 +203,7 @@
(ptk/reify ::group-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (group-shapes nil selected :change-selection? true))))))
(defn ungroup-shapes
@ -212,7 +212,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
prepare
(fn [shape-id]
@ -264,7 +264,7 @@
(ptk/reify ::ungroup-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (ungroup-shapes selected :change-selection? true))))))
(defn mask-group
@ -275,8 +275,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (->> (or ids (wsh/lookup-selected state))
objects (dsh/lookup-page-objects state page-id)
selected (->> (or ids (dsh/lookup-selected state))
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
shapes (shapes-for-grouping objects selected)
@ -323,9 +323,9 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
masked-groups (->> (d/nilv ids (wsh/lookup-selected state))
masked-groups (->> (d/nilv ids (dsh/lookup-selected state))
(map #(get objects %))
(filter #(or (= :bool (:type %)) (= :group (:type %)))))

View file

@ -13,7 +13,7 @@
[app.common.types.page :as ctp]
[app.main.data.changes :as dwc]
[app.main.data.event :as ev]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -31,7 +31,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
(let [page (dsh/lookup-page state)
changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
@ -56,7 +56,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
(let [page (dsh/lookup-page state)
changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
@ -73,7 +73,7 @@
(ptk/reify ::remove-guides
ptk/WatchEvent
(watch [_ state _]
(let [{:keys [guides] :as page} (wsh/lookup-page state)
(let [{:keys [guides] :as page} (dsh/lookup-page state)
guides (-> (select-keys guides ids) (vals))]
(rx/from (mapv remove-guide guides))))))
@ -88,7 +88,7 @@
(let [ids (:ids args)
object-modifiers (:modifiers args)
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
is-frame? (fn [id] (= :frame (get-in objects [id :type])))
frame-ids? (into #{} (filter is-frame?) ids)
@ -104,7 +104,7 @@
guide (update guide :position + (get moved (:axis guide)))]
(update-guides guide)))
guides (-> state wsh/lookup-page :guides vals)]
guides (-> state dsh/lookup-page :guides vals)]
(->> guides
(filter (comp frame-ids? :frame-id))

View file

@ -18,8 +18,8 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.streams :as ms]
[app.util.mouse :as mse]
@ -41,8 +41,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page (if page-id
(wsh/lookup-page state page-id)
(wsh/lookup-page state))
(dsh/lookup-page state page-id)
(dsh/lookup-page state))
flows (get page :flows)
unames (cfh/get-used-names (vals flows))
@ -64,7 +64,7 @@
(ptk/reify ::add-flow-selected-frame
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (add-flow (first selected)))))))
(defn remove-flow
@ -77,8 +77,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page (if page-id
(wsh/lookup-page state page-id)
(wsh/lookup-page state))]
(dsh/lookup-page state page-id)
(dsh/lookup-page state))]
(rx/of (dch/commit-changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
@ -94,8 +94,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page (if page-id
(wsh/lookup-page state page-id)
(wsh/lookup-page state))
(dsh/lookup-page state page-id)
(dsh/lookup-page state))
flow (dm/get-in page [:flows flow-id])
flow (some-> flow update-fn)]
@ -114,7 +114,7 @@
(ptk/reify ::rename-flow
ptk/WatchEvent
(watch [_ state _]
(let [page (wsh/lookup-page state)]
(let [page (dsh/lookup-page state)]
(rx/of (update-flow (:id page) flow-id #(assoc % :name name)))))))
(defn start-rename-flow
@ -165,7 +165,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
page (wsh/lookup-page state page-id)
page (dsh/lookup-page state page-id)
objects (get page :objects)
frame (cfh/get-root-frame objects (:id shape))
@ -229,7 +229,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
remove-interactions-shape
(fn [shape]
@ -258,7 +258,7 @@
ptk/WatchEvent
(watch [_ state stream]
(let [initial-pos @ms/mouse-position
selected (wsh/lookup-selected state)
selected (dsh/lookup-selected state)
stopper (mse/drag-stopper stream)]
(when (= 1 (count selected))
(rx/concat
@ -270,9 +270,9 @@
(defn- get-target-frame
[state position]
(let [objects (wsh/lookup-page-objects state)
from-id (-> state wsh/lookup-selected first)
from-shape (wsh/lookup-shape state from-id)
(let [objects (dsh/lookup-page-objects state)
from-id (-> state dsh/lookup-selected first)
from-shape (dsh/lookup-shape state from-id)
from-frame-id (if (cfh/frame-shape? from-shape)
from-id (:frame-id from-shape))
@ -309,8 +309,8 @@
(watch [_ state _]
(let [position @ms/mouse-position
target-frame (get-target-frame state position)
shape-id (-> state wsh/lookup-selected first)
shape (wsh/lookup-shape state shape-id)
shape-id (-> state dsh/lookup-selected first)
shape (dsh/lookup-shape state shape-id)
change-interaction
(fn [interaction]
@ -368,13 +368,13 @@
ptk/WatchEvent
(watch [_ state stream]
(let [initial-pos @ms/mouse-position
selected (wsh/lookup-selected state)
selected (dsh/lookup-selected state)
stopper (mse/drag-stopper stream)]
(when (= 1 (count selected))
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shape (->> state
wsh/lookup-selected
dsh/lookup-selected
first
(get objects))
overlay-pos (-> shape
@ -418,9 +418,9 @@
(gpt/subtract offset))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shape (->> state
wsh/lookup-selected
dsh/lookup-selected
first
(get objects))

View file

@ -9,8 +9,8 @@
(:require
[app.common.data :as d]
[app.common.math :as mth]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
[potok.v2.core :as ptk]))
@ -43,8 +43,8 @@
(ptk/reify ::set-opacity
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state {:omit-blocked? true})
(let [objects (dsh/lookup-page-objects state)
selected (dsh/lookup-selected state {:omit-blocked? true})
shapes (map #(get objects %) selected)
shapes-ids (->> shapes
(map :id))]

View file

@ -29,6 +29,7 @@
[app.main.data.comments :as dc]
[app.main.data.common :as dcm]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.notifications :as ntf]
[app.main.data.workspace :as-alias dw]
@ -37,7 +38,6 @@
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.specialized-panel :as dwsp]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.data.workspace.transforms :as dwtr]
[app.main.data.workspace.undo :as dwu]
@ -63,7 +63,7 @@
[file-id state]
(if (= file-id (:current-file-id state))
"<local>"
(str "<" (get-in state [:libraries file-id :name]) ">")))
(str "<" (get-in state [:files file-id :name]) ">")))
(defn- log-changes
[changes file]
@ -164,7 +164,7 @@
(defn- update-color*
[it state color file-id]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
[path name] (cfh/parse-path-name (:name color))
color (assoc color :path path :name name)
changes (-> (pcb/empty-changes it)
@ -173,7 +173,7 @@
undo-id (js/Symbol)]
(rx/of (dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(sync-file (:current-file-id state) file-id :colors (:id color))
(sync-file (:id data) file-id :colors (:id color))
(dwu/commit-undo-transaction undo-id))))
(defn update-color
@ -212,6 +212,7 @@
(let [color (assoc color :name (dm/str (:path color) "/" (:name color)))]
(update-color* it state color file-id))))))
;; FIXME: revisit why file-id is passed on the event
(defn rename-color
[file-id id new-name]
(dm/assert!
@ -232,7 +233,7 @@
(let [new-name (str/trim new-name)]
(if (str/empty? new-name)
(rx/empty)
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
color (get-in data [:colors id])
color (assoc color :name new-name)
color (d/without-nils color)]
@ -247,7 +248,7 @@
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-color id))]
@ -288,7 +289,7 @@
(if (str/empty? new-name)
(rx/empty)
(let [[path name] (cfh/parse-path-name new-name)
data (get state :workspace-data)
data (dsh/lookup-file-data state)
object (get-in data [:media id])
new-object (assoc object :path path :name name)
changes (-> (pcb/empty-changes it)
@ -308,7 +309,7 @@
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-media id))]
@ -337,7 +338,7 @@
(defn- do-update-tipography
[it state typography file-id]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
typography (extract-path-if-missing typography)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
@ -373,7 +374,7 @@
ptk/WatchEvent
(watch [it state _]
(when (and (some? new-name) (not= "" new-name))
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
[path name] (cfh/parse-path-name new-name)
object (get-in data [:typographies id])
new-object (assoc object :path path :name name)]
@ -388,7 +389,7 @@
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-typography id))]
@ -409,7 +410,7 @@
(watch [it state _]
(let [file-id (:current-file-id state)
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (dwg/shapes-for-grouping objects selected)
parents (into #{} (map :parent-id) shapes)]
(when-not (empty? shapes)
@ -436,8 +437,8 @@
(ptk/reify ::add-component
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (->> (d/nilv ids (wsh/lookup-selected state))
(let [objects (dsh/lookup-page-objects state)
selected (->> (d/nilv ids (dsh/lookup-selected state))
(cfh/clean-loops objects))
selected-objects (map #(get objects %) selected)
components-v2 (features/active-feature? state "components/v2")
@ -454,8 +455,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [components-v2 (features/active-feature? state "components/v2")
objects (wsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects))
selected-objects (map #(get objects %) selected)
;; We don't want to change the structure of component copies
@ -488,11 +489,9 @@
(let [new-name (str/trim new-name)]
(if (str/empty? new-name)
(rx/empty)
(let [library-data (get state :workspace-data)
components-v2 (features/active-feature? state "components/v2")
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(cll/generate-rename-component id new-name library-data components-v2))]
(cll/generate-rename-component id new-name data true))]
(rx/of (dch/commit-changes changes))))))))
(defn rename-component-and-main-instance
@ -505,10 +504,13 @@
valid? (and (not (str/ends-with? name "/"))
(string? clean-name)
(not (str/blank? clean-name)))
component (dm/get-in state [:workspace-data :components component-id])]
data (dsh/lookup-file-data state)
component (dm/get-in data [:components component-id])]
(when (and valid? component)
(let [shape-id (:main-instance-id component)
page-id (:main-instance-page component)]
(rx/concat
(rx/of (rename-component component-id clean-name))
@ -522,7 +524,7 @@
(ptk/reify ::duplicate-component
ptk/WatchEvent
(watch [it state _]
(let [libraries (wsh/get-libraries state)
(let [libraries (dsh/lookup-libraries state)
library (get libraries library-id)
components-v2 (features/active-feature? state "components/v2")
changes (-> (pcb/empty-changes it nil)
@ -540,22 +542,22 @@
(ptk/reify ::delete-component
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)]
(if (features/active-feature? state "components/v2")
(let [component (ctkl/get-component data id)
(let [file-id (:current-file-id state)
fdata (dsh/lookup-file-data state file-id)
component (ctkl/get-component fdata id)
page-id (:main-instance-page component)
root-id (:main-instance-id component)
file-id (:current-file-id state)
file (wsh/get-file state file-id)
page (wsh/lookup-page state page-id)
objects (wsh/lookup-page-objects state page-id)
components-v2 (features/active-feature? state "components/v2")
page (dsh/get-page fdata page-id)
objects (:objects page)
undo-group (uuid/next)
undo-id (js/Symbol)
[all-parents changes]
(-> (pcb/empty-changes it page-id)
;; Deleting main root triggers component delete
(cls/generate-delete-shapes file page objects #{root-id} {:components-v2 components-v2
(cls/generate-delete-shapes fdata page objects #{root-id} {:components-v2 true
:undo-group undo-group
:undo-id undo-id}))]
(rx/of
@ -564,13 +566,7 @@
(dc/detach-comment-thread #{root-id})
(dch/commit-changes changes)
(ptk/data-event :layout/update {:ids all-parents :undo-group undo-group})
(dwu/commit-undo-transaction undo-id)))
(let [page-id (:current-page-id state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/delete-component id page-id))]
(rx/of (dch/commit-changes changes))))))))
(dwu/commit-undo-transaction undo-id))))))
(defn restore-component
"Restore a deleted component, with the given id, in the given file library."
@ -581,11 +577,13 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
current-page (dm/get-in state [:workspace-data :pages-index page-id])
library-data (wsh/get-file state library-id)
objects (wsh/lookup-page-objects state page-id)
page (dsh/lookup-page state page-id)
objects (:objects page)
ldata (dsh/lookup-file-data state library-id)
changes (-> (pcb/empty-changes it)
(cll/generate-restore-component library-data component-id library-id current-page objects))]
(cll/generate-restore-component ldata component-id library-id page objects))]
(rx/of (dch/commit-changes changes))))))
@ -614,8 +612,8 @@
(ptk/reify ::instantiate-component
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
libraries (wsh/get-libraries state)
(let [page (dsh/lookup-page state)
libraries (dsh/lookup-libraries state)
objects (:objects page)
changes (-> (pcb/empty-changes it (:id page))
@ -637,8 +635,7 @@
(when id-ref
(reset! id-ref (:id new-shape)))
(rx/of (ptk/event
::ev/event
(rx/of (ptk/event ::ev/event
{::ev/name "use-library-component"
::ev/origin origin
:external-library (not= file-id current-file-id)})
@ -658,12 +655,14 @@
(ptk/reify ::detach-component
ptk/WatchEvent
(watch [it state _]
(let [file (wsh/get-local-file state)
page-id (get state :current-page-id)
libraries (wsh/get-libraries state)
(let [page-id (:current-page-id state)
file-id (:current-file-id state)
fdata (dsh/lookup-file-data state file-id)
libraries (dsh/lookup-libraries state)
changes (-> (pcb/empty-changes it)
(cll/generate-detach-component id file page-id libraries))]
(cll/generate-detach-component id fdata page-id libraries))]
(rx/of (dch/commit-changes changes))))))
@ -685,20 +684,27 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
file (wsh/get-local-file state)
libraries (wsh/get-libraries state)
file-id (:current-file-id state)
;; FIXME: revisit, innefficient access
objects (dsh/lookup-page-objects state page-id)
libraries (dsh/lookup-libraries state)
fdata (dsh/lookup-file-data state file-id)
selected (->> state
(wsh/lookup-selected)
(dsh/lookup-selected)
(cfh/clean-loops objects))
selected-objects (map #(get objects %) selected)
copies (filter ctk/in-component-copy? selected-objects)
can-detach? (and (seq copies)
(every? #(not (ctn/has-any-copy-parent? objects %)) selected-objects))
changes (when can-detach?
(reduce
(fn [changes id]
(cll/generate-detach-component changes id file page-id libraries))
(cll/generate-detach-component changes id fdata page-id libraries))
(pcb/empty-changes it)
selected))]
@ -725,6 +731,7 @@
ptk/WatchEvent
(watch [_ state stream]
(let [current-page-id (:current-page-id state)
data (dsh/lookup-file-data state)
select-and-zoom
(fn [shape-id]
@ -741,7 +748,7 @@
(rx/observe-on :async)
(rx/mapcat (fn [_] (select-and-zoom shape-id))))))]
(when-let [component (dm/get-in state [:workspace-data :components id])]
(when-let [component (dm/get-in data [:components id])]
(let [page-id (:main-instance-page component)
shape-id (:main-instance-id component)]
(when (some? page-id)
@ -779,9 +786,9 @@
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:libraries library-id]
(update-in [:files library-id]
assoc :modified-at modified-at :revn revn)
(d/update-in-when [:libraries library-id :data]
(d/update-in-when [:files library-id :data]
ch/process-changes changes)))
ptk/WatchEvent
@ -805,28 +812,23 @@
ptk/WatchEvent
(watch [it state _]
(log/info :msg "RESET-COMPONENT of shape" :id (str id))
(let [file (wsh/get-local-file state)
file-full (wsh/get-local-file-full state)
libraries (wsh/get-libraries state)
(let [libraries (:files state)
page-id (:current-page-id state)
container (ctn/get-container file :page page-id)
components-v2
(features/active-feature? state "components/v2")
file (dsh/lookup-file state)
data (:data file)
container (ctn/get-container data :page page-id)
undo-id (js/Symbol)
changes
(-> (pcb/empty-changes it)
(cll/generate-reset-component file-full libraries container id components-v2))]
(cll/generate-reset-component file libraries container id true))]
(log/debug :msg "RESET-COMPONENT finished" :js/rchanges (log-changes
(:redo-changes changes)
file))
(rx/of
(dwu/start-undo-transaction undo-id)
(rx/of (dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(dwu/commit-undo-transaction undo-id))))))
@ -859,24 +861,24 @@
ptk/WatchEvent
(watch [it state _]
(log/info :msg "UPDATE-COMPONENT of shape" :id (str id) :undo-group undo-group)
(let [page-id (get state :current-page-id)
local-file (wsh/get-local-file state)
full-file (wsh/get-local-file-full state)
container (ctn/get-container local-file :page page-id)
shape (ctn/get-shape container id)
components-v2 (features/active-feature? state "components/v2")]
(let [page-id (:current-page-id state)
libraries (dsh/lookup-libraries state)
file (dsh/lookup-file state)
fdata (:data file)
container (ctn/get-container fdata :page page-id)
shape (ctn/get-shape container id)]
(when (ctk/instance-head? shape)
(let [libraries (wsh/get-libraries state)
changes
(let [changes
(-> (pcb/empty-changes it)
(pcb/set-undo-group undo-group)
(pcb/with-container container)
(cll/generate-sync-shape-inverse full-file libraries container id components-v2))
(cll/generate-sync-shape-inverse fdata libraries container id true))
file-id (:component-file shape)
file (wsh/get-file state file-id)
ldata (->> (:component-file shape)
(dsh/lookup-file-data state))
xf-filter (comp
(filter :local-change?)
@ -897,26 +899,22 @@
(log/debug :msg "UPDATE-COMPONENT finished"
:js/local-changes (log-changes
(:redo-changes local-changes)
file)
fdata)
:js/nonlocal-changes (log-changes
(:redo-changes nonlocal-changes)
file))
fdata))
(rx/of
(when (seq (:redo-changes local-changes))
(dch/commit-changes (assoc local-changes
:file-id (:id local-file))))
:file-id (:id file))))
(when (seq (:redo-changes nonlocal-changes))
(dch/commit-changes (assoc nonlocal-changes
:file-id file-id)))))))))))
:file-id (:id ldata))))))))))))
(defn- update-component-thumbnail-sync
[state component-id file-id tag]
(let [current-file-id (:current-file-id state)
current-file? (= current-file-id file-id)
data (if current-file?
(get state :workspace-data)
(get-in state [:libraries file-id :data]))
(let [data (dsh/lookup-file-data state file-id)
component (ctkl/get-component data component-id)
page-id (:main-instance-page component)
root-id (:main-instance-id component)]
@ -930,7 +928,8 @@
(watch [_ state _]
(let [current-file-id (:current-file-id state)
current-file? (= current-file-id file-id)
page (wsh/lookup-page state)
page (dsh/lookup-page state)
shape (ctn/get-shape page shape-id)
component-id (:component-id shape)
undo-id (js/Symbol)]
@ -995,12 +994,13 @@
(watch [it state _]
;; First delete shapes so we have space in the layout otherwise we can have problems
;; in the grid creating new rows/columns to make space
(let [file (wsh/get-file state file-id)
libraries (wsh/get-libraries state)
page (wsh/lookup-page state)
objects (wsh/lookup-page-objects state)
(let [libraries (dsh/lookup-libraries state)
page (dsh/lookup-page state)
objects (:objects page)
parent (get objects (:parent-id shape))
ldata (dsh/lookup-file-data state file-id)
;; If the target parent is a grid layout we need to pass the target cell
target-cell (when (ctl/grid-layout? parent)
(ctl/get-cell-by-shape-id parent (:id shape)))
@ -1016,7 +1016,7 @@
[new-shape all-parents changes]
(-> (pcb/empty-changes it (:id page))
(pcb/set-undo-group undo-group)
(cll/generate-component-swap objects shape file page libraries id-new-component index target-cell keep-props-values))]
(cll/generate-component-swap objects shape ldata page libraries id-new-component index target-cell keep-props-values))]
(rx/of
(dwu/start-undo-transaction undo-id)
@ -1086,7 +1086,7 @@
(update [_ state]
(if (and (not= library-id (:current-file-id state))
(nil? asset-id))
(d/assoc-in-when state [:libraries library-id :synced-at] (dt/now))
(d/assoc-in-when state [:files library-id :synced-at] (dt/now))
state))
ptk/WatchEvent
@ -1098,8 +1098,8 @@
:asset-type asset-type
:asset-id asset-id
:undo-group undo-group)
(let [file (wsh/get-file state file-id)
libraries (wsh/get-libraries state)
(let [ldata (dsh/lookup-file-data state file-id)
libraries (dsh/lookup-libraries state)
current-file-id (:current-file-id state)
changes (cll/generate-sync-file-changes
@ -1113,7 +1113,7 @@
current-file-id)
find-frames (fn [change]
(->> (ch/frames-changed file change)
(->> (ch/frames-changed ldata change)
(map #(assoc %1 :page-id (:page-id change)))))
updated-frames (->> changes
@ -1123,7 +1123,7 @@
(log/debug :msg "SYNC-FILE finished" :js/rchanges (log-changes
(:redo-changes changes)
file))
ldata))
(rx/concat
(rx/of (set-updating-library false)
(ntf/hide {:tag :sync-dialog}))
@ -1161,7 +1161,8 @@
(ptk/reify ::ignore-sync
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :ignore-sync-until] (dt/now)))
(let [file-id (:current-file-id state)]
(assoc-in state [:files file-id :ignore-sync-until] (dt/now))))
ptk/WatchEvent
(watch [_ state _]
@ -1175,11 +1176,13 @@
"Get a lazy sequence of all the assets of each type in the library that have
been modified after the last sync of the library. The sync date may be
overriden by providing a ignore-until parameter."
([library file-data] (assets-need-sync library file-data nil))
([library file-data]
(assets-need-sync library file-data nil))
([library file-data ignore-until]
(when (not= (:id library) (:id file-data))
(let [sync-date (max (:synced-at library) (or ignore-until 0))]
(when (> (:modified-at library) sync-date)
(ctf/used-assets-changed-since file-data library sync-date)))))
(ctf/used-assets-changed-since file-data library sync-date))))))
(defn notify-sync-file
[file-id]
@ -1187,17 +1190,28 @@
(ptk/reify ::notify-sync-file
ptk/WatchEvent
(watch [_ state _]
(let [file-data (:workspace-data state)
ignore-until (dm/get-in state [:workspace-file :ignore-sync-until])
libraries-need-sync (filter #(seq (assets-need-sync % file-data ignore-until))
(vals (get state :libraries)))
do-more-info #(modal/show! :libraries-dialog {:starting-tab "updates"})
do-update #(do (apply st/emit! (map (fn [library]
(let [file (dm/get-in state [:files file-id])
file-data (get file :data)
ignore-until (get file :ignore-sync-until)
;; FIXME: syntax of this can be improved
libraries-need-sync
(filter #(seq (assets-need-sync % file-data ignore-until))
(vals (get state :files)))
do-more-info
#(modal/show! :libraries-dialog {:starting-tab "updates"})
do-update
#(do (apply st/emit! (map (fn [library]
(sync-file (:current-file-id state)
(:id library)))
libraries-need-sync))
(st/emit! (ntf/hide)))
do-dismiss #(do (st/emit! ignore-sync)
do-dismiss
#(do (st/emit! ignore-sync)
(st/emit! (ntf/hide)))]
(when (seq libraries-need-sync)
@ -1227,7 +1241,7 @@
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
(let [data (dsh/lookup-file-data state)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/update-component id #(assoc % :modified-at (dt/now))))]
@ -1351,7 +1365,7 @@
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :is-shared] is-shared))
(update-in state [:files id] assoc :is-shared is-shared))
ptk/WatchEvent
(watch [_ _ _]
@ -1377,7 +1391,7 @@
(let [libraries (:workspace-shared-files state)
library (d/seek #(= (:id %) library-id) libraries)]
(if library
(update state :libraries assoc library-id (dissoc library :library-summary))
(update state :files assoc library-id (dissoc library :library-summary))
state)))
ptk/WatchEvent
@ -1389,9 +1403,10 @@
(rx/ignore))
(->> (rp/cmd! :get-file {:id library-id :features features})
(rx/merge-map fpmap/resolve-file)
;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event
(rx/map (fn [file]
(fn [state]
(assoc-in state [:libraries library-id] file)))))
(assoc-in state [:files library-id] file)))))
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
(rx/map (fn [thumbnails]
(fn [state]
@ -1409,7 +1424,7 @@
ptk/UpdateEvent
(update [_ state]
(d/dissoc-in state [:libraries library-id]))
(update state :files dissoc library-id))
ptk/WatchEvent
(watch [_ _ _]

View file

@ -21,11 +21,11 @@
[app.common.uuid :as uuid]
[app.config :as cf]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.media :as dmm]
[app.main.data.notifications :as ntf]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.svg-upload :as svg]
[app.main.repo :as rp]
[app.main.store :as st]
@ -266,9 +266,11 @@
(on-success image)
(dmm/notify-finished-loading))
file-id (:current-file-id state)
prepare
(fn [content]
{:file-id (get-in state [:workspace-file :id])
{:file-id file-id
:name (if (dmm/file? content) (.-name content) (tr "media.image"))
:is-local false
:content content})]
@ -399,22 +401,31 @@
(ptk/reify ::process-img-component
ptk/WatchEvent
(watch [it state _]
(let [file-data (wsh/get-local-file state)
page (wsh/lookup-page state)
pos (wsh/viewport-center state)]
(let [file-id (:current-file-id state)
page-id (:current-page-id state)
fdata (dsh/lookup-file-data state file-id)
page (dsh/get-page fdata page-id)
pos (dsh/get-viewport-center state)]
(->> (create-shapes-img pos media-obj)
(rx/map (partial add-shapes-and-component it file-data page (:name media-obj))))))))
(rx/map (partial add-shapes-and-component it fdata page (:name media-obj))))))))
(defn- process-svg-component
[svg-data]
(ptk/reify ::process-svg-component
ptk/WatchEvent
(watch [it state _]
(let [file-data (wsh/get-local-file state)
page (wsh/lookup-page state)
pos (wsh/viewport-center state)]
(->> (create-shapes-svg (:id file-data) (:objects page) pos svg-data)
(rx/map (partial add-shapes-and-component it file-data page (:name svg-data))))))))
(let [file-id (:current-file-id state)
page-id (:current-page-id state)
fdata (dsh/lookup-file-data state file-id)
page (dsh/get-page fdata page-id)
pos (dsh/get-viewport-center state)]
(->> (create-shapes-svg file-id (:objects page) pos svg-data)
(rx/map (partial add-shapes-and-component it fdata page (:name svg-data))))))))
(defn upload-media-components
[params]

View file

@ -23,10 +23,10 @@
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]
[app.main.constants :refer [zoom-half-pixel-precision]]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.comments :as-alias dwcm]
[app.main.data.workspace.guides :as-alias dwg]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -335,7 +335,7 @@
([state ignore-constraints ignore-snap-pixel modif-tree params]
(let [objects
(wsh/lookup-page-objects state)
(dsh/lookup-page-objects state)
snap-pixel?
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))
@ -355,7 +355,7 @@
(defn- calculate-update-modifiers
[old-modif-tree state ignore-constraints ignore-snap-pixel modif-tree]
(let [objects
(wsh/lookup-page-objects state)
(dsh/lookup-page-objects state)
snap-pixel?
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))
@ -421,7 +421,7 @@
(ptk/reify ::set-rotation-modifiers
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
ids (sequence xf-rotation-shape shapes)
get-modifier
@ -442,7 +442,7 @@
(ptk/reify ::set-delta-rotation-modifiers
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
ids
(->> shapes
(remove #(get % :blocked false))
@ -473,7 +473,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [text-modifiers (get state :workspace-text-modifier)
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
object-modifiers
(if (some? modifiers)

View file

@ -13,6 +13,7 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.common :as dc]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.plugins :as dpl]
[app.main.data.websocket :as dws]
@ -273,7 +274,7 @@
[:file-id ::sm/uuid]
[:vern :int]])
(def ^:private check-file-restore-params!
(def ^:private check-file-restore-params
(sm/check-fn schema:handle-file-restore))
(defn handle-file-restore
@ -281,15 +282,17 @@
(dm/assert!
"expected valid parameters"
(check-file-restore-params! msg))
(check-file-restore-params msg))
(ptk/reify ::handle-file-restore
ptk/WatchEvent
(watch [_ state _]
(let [curr-file-id (:current-file-id state)
curr-vern (dm/get-in state [:workspace-file :vern])
reload? (and (= file-id curr-file-id) (not= vern curr-vern))]
(when reload?
file (dsh/lookup-file state curr-file-id)
curr-vern (:vern file)]
(when (and (= file-id curr-file-id)
(not= vern curr-vern))
(rx/of (ptk/event ::dw/reload-current-file)))))))
(def ^:private schema:handle-library-change

View file

@ -9,10 +9,10 @@
[app.common.data.macros :as dm]
[app.common.files.changes-builder :as pcb]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.path.common :refer [check-path-content!]]
[app.main.data.workspace.path.helpers :as helpers]
[app.main.data.workspace.path.state :as st]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -83,7 +83,7 @@
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
page-id (:current-page-id state)
id (get-in state [:workspace-local :edition])
old-content (get-in state [:workspace-local :edit-path id :old-content])

View file

@ -15,6 +15,7 @@
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.drawing.common :as dwdc]
[app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.path.changes :as changes]
@ -24,7 +25,6 @@
[app.main.data.workspace.path.streams :as streams]
[app.main.data.workspace.path.undo :as undo]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.util.mouse :as mse]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -252,7 +252,7 @@
(ptk/reify ::setup-frame
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
content (get-in state [:workspace-drawing :object :content] [])
position (gpt/point (get-in content [0 :params] nil))
frame-id (->> (ctst/top-nested-frame objects position)
@ -321,11 +321,10 @@
(ptk/reify ::start-draw-mode
ptk/UpdateEvent
(update [_ state]
(let [id (get-in state [:workspace-local :edition])
page-id (:current-page-id state)
old-content (get-in state [:workspace-data :pages-index page-id :objects id :content])]
(-> state
(assoc-in [:workspace-local :edit-path id :old-content] old-content))))
(let [id (dm/get-in state [:workspace-local :edition])
objects (dsh/lookup-page-objects state)
content (dm/get-in objects [id :content])]
(update-in state [:workspace-local :edit-path id] assoc :old-content content)))
ptk/WatchEvent
(watch [_ state stream]

View file

@ -15,6 +15,7 @@
[app.common.svg.path.shapes-to-path :as upsp]
[app.common.svg.path.subpath :as ups]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.drawing :as drawing]
@ -24,7 +25,6 @@
[app.main.data.workspace.path.streams :as streams]
[app.main.data.workspace.path.undo :as undo]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.streams :as ms]
[app.util.mouse :as mse]
[app.util.path.tools :as upt]
@ -50,7 +50,7 @@
(ptk/reify ::apply-content-modifiers
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
id (st/get-path-id state)
page-id (:current-page-id state)
@ -294,7 +294,7 @@
(ptk/reify ::start-path-edit
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
edit-path (dm/get-in state [:workspace-local :edit-path id])
content (st/get-path state :content)
state (cond-> state

View file

@ -11,7 +11,7 @@
[app.common.svg.path.shapes-to-path :as upsp]
[app.common.types.container :as ctn]
[app.main.data.changes :as dch]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -23,8 +23,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state)
selected (->> (or ids (wsh/lookup-selected state))
objects (dsh/lookup-page-objects state)
selected (->> (or ids (dsh/lookup-selected state))
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
children-ids

View file

@ -51,12 +51,11 @@
(defn get-path-location
[state & ks]
(let [edit-id (get-in state [:workspace-local :edition])
page-id (:current-page-id state)]
(into (if edit-id
[:workspace-data :pages-index page-id :objects edit-id]
[:workspace-drawing :object])
ks)))
(if-let [edit-id (dm/get-in state [:workspace-local :edition])]
(let [page-id (:current-page-id state)
file-id (:current-file-id state)]
(into [:files file-id :data :pages-index page-id :objects edit-id] ks))
(into [:workspace-drawing :object] ks)))
(defn get-path
"Retrieves the location of the path object and additionally can pass
@ -66,7 +65,6 @@
shape (-> (get-in state path-loc)
;; Empty map because we know the current shape will not have children
(upsp/convert-to-path {}))]
(if (empty? ks)
shape
(get-in shape ks))))
@ -74,5 +72,4 @@
(defn set-content
[state content]
(let [path-loc (get-path-location state :content)]
(-> state
(assoc-in path-loc content))))
(assoc-in state path-loc content)))

View file

@ -9,11 +9,11 @@
[app.common.svg.path.shapes-to-path :as upsp]
[app.common.svg.path.subpath :as ups]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.state :as st]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.util.path.tools :as upt]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -26,7 +26,7 @@
(ptk/reify ::process-path-tool
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
id (st/get-path-id state)
page-id (:current-page-id state)
shape (st/get-path state)

View file

@ -132,8 +132,9 @@
dissoc :undo-lock :undo-stack)))))
(defn- stop-undo? [event]
(or (= :app.main.data.workspace.common/clear-edition-mode (ptk/type event))
(= :app.main.data.workspace/finalize-page (ptk/type event))))
(let [type (ptk/type event)]
(or (= :app.main.data.workspace.edition/clear-edition-mode type)
(= :app.main.data.workspace/finalize-page type))))
(def path-content-ref
(letfn [(selector [state]

View file

@ -19,10 +19,10 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as md]
[app.main.data.workspace.collapse :as dwc]
[app.main.data.workspace.specialized-panel :as-alias dwsp]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.zoom :as dwz]
[app.main.refs :as refs]
@ -140,9 +140,9 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected-id (wsh/lookup-selected state)
selected (wsh/lookup-shapes state selected-id)
objects (dsh/lookup-page-objects state page-id)
selected-id (dsh/lookup-selected state)
selected (dsh/lookup-shapes state selected-id)
frame-ids (map (fn [item] (let [parent (cfh/get-frame objects (:id item))]
(:id parent))) selected)
params-without-board (-> (rt/get-params state)
@ -162,11 +162,11 @@
(ptk/reify ::select-prev-shape
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
(let [selected (dsh/lookup-selected state)
count-selected (count selected)
first-selected (first selected)
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
current (get objects first-selected)
parent (get objects (:parent-id current))
sibling-ids (:shapes parent)
@ -187,11 +187,11 @@
(ptk/reify ::select-next-shape
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
(let [selected (dsh/lookup-selected state)
count-selected (count selected)
first-selected (first selected)
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
current (get objects first-selected)
parent (get objects (:parent-id current))
sibling-ids (:shapes parent)
@ -230,10 +230,10 @@
(rx/of ::dwsp/interrupt))
ptk/UpdateEvent
(update [_ state]
(let [objects (or objects (wsh/lookup-page-objects state))
(let [objects (or objects (dsh/lookup-page-objects state))
append-to-selection (cfh/expand-region-selection objects (into #{} [(get-in state [:workspace-local :last-selected]) id]))
selection (-> state
wsh/lookup-selected
dsh/lookup-selected
(conj id))]
(-> state
(assoc-in [:workspace-local :selected]
@ -250,7 +250,7 @@
(ptk/reify ::select-shapes
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
focus (:workspace-focus-selected state)
ids (if (d/not-empty? focus)
(cpf/filter-not-focus objects focus ids)
@ -259,7 +259,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)]
(let [objects (dsh/lookup-page-objects state)]
(rx/of
(dwc/expand-all-parents ids objects)
::dwsp/interrupt)))))
@ -273,11 +273,11 @@
;; case delimit the objects to the focused shapes if focus
;; mode is active
focus (:workspace-focus-selected state)
objects (-> (wsh/lookup-page-objects state)
objects (-> (dsh/lookup-page-objects state)
(cpf/focus-objects focus))
lookup (d/getf objects)
parents (->> (wsh/lookup-selected state)
parents (->> (dsh/lookup-selected state)
(into #{} (comp (keep lookup) (map :parent-id))))
;; If we have a only unique parent, then use it as main
@ -307,6 +307,7 @@
(dissoc :board-id))]
(rx/of ::dwsp/interrupt)
(rx/of (rt/nav :workspace params-without-board {::rt/replace true}))))
ptk/UpdateEvent
(update [_ state]
@ -329,8 +330,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
selected (dsh/lookup-selected state)
initial-set (if preserve?
selected
lks/empty-linked-set)
@ -363,7 +364,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
group (get objects group-id)
children (map #(get objects %) (:shapes group))
@ -435,7 +436,7 @@
(ptk/reify ::duplicate-shapes
ptk/WatchEvent
(watch [it state _]
(let [page (wsh/lookup-page state)
(let [page (dsh/lookup-page state)
objects (:objects page)
ids (into #{}
(comp (map (d/getf objects))
@ -449,8 +450,9 @@
(gpt/point 0 0))
file-id (:current-file-id state)
libraries (wsh/get-libraries state)
library-data (wsh/get-file state file-id)
libraries (dsh/lookup-libraries state)
library-data (dsh/lookup-file-data state file-id)
changes (-> (pcb/empty-changes it)
(cll/generate-duplicate-changes objects page ids delta libraries library-data file-id)
@ -504,7 +506,7 @@
ptk/WatchEvent
(watch [_ state _]
(when (or (not move-delta?) (nil? (get-in state [:workspace-local :transform])))
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (duplicate-shapes selected
:move-delta? move-delta?
:alt-duplication? alt-duplication?))))))))
@ -523,7 +525,7 @@
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
focus (-> (:workspace-focus-selected state)
(set/union added)
@ -541,7 +543,7 @@
ptk/UpdateEvent
(update [_ state]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(cond-> state
(and (empty? (:workspace-focus-selected state))
(d/not-empty? selected))

View file

@ -22,12 +22,12 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.colors :as cl]
[app.main.data.workspace.grid-layout.editor :as dwge]
[app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.selection :as dwse]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -101,7 +101,7 @@
(ptk/reify ::update-layout-positions
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
ids (->> ids (filter #(contains? objects %)))]
(if (d/not-empty? ids)
(let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))]
@ -144,7 +144,7 @@
(ptk/reify ::create-layout-from-id
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
parent (get objects id)
undo-id (js/Symbol)
layout-initializer (get-layout-initializer type from-frame? calculate-params?)]
@ -162,8 +162,8 @@
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected)
single? (= (count selected-shapes) 1)
has-group? (->> selected-shapes (d/seek cfh/group-shape?))
@ -229,8 +229,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected)
single? (= (count selected-shapes) 1)
is-frame? (= :frame (:type (first selected-shapes)))
@ -248,8 +248,8 @@
(ptk/reify ::toggle-shape-layout
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state)
(let [objects (dsh/lookup-page-objects state)
selected (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected)
single? (= (count selected-shapes) 1)
has-layout? (and single?
@ -300,7 +300,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [undo-id (js/Symbol)]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shapes-to-delete
(when with-shapes?
@ -334,10 +334,10 @@
ptk/WatchEvent
(watch [it state _]
(let [file-id (:current-file-id state)
page (wsh/lookup-page state)
page (dsh/lookup-page state)
objects (:objects page)
libraries (wsh/get-libraries state)
library-data (wsh/get-file state file-id)
libraries (dsh/lookup-libraries state)
library-data (dsh/lookup-file state file-id)
shape-id (first ids)
base-shape (get objects shape-id)
@ -406,7 +406,7 @@
(ptk/reify ::hover-layout-track
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects (first ids))
highlighted
@ -524,7 +524,7 @@
(ptk/reify ::update-layout-child
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
children-ids (->> ids (mapcat #(cfh/get-children-ids objects %)))
parent-ids (->> ids (map #(cfh/get-parent-id objects %)))
undo-id (js/Symbol)]
@ -694,7 +694,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
frame-id (uuid/next)
undo-id (js/Symbol)

View file

@ -19,9 +19,9 @@
[app.main.data.changes :as dch]
[app.main.data.comments :as dc]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.features :as features]
[beicon.v2.core :as rx]
@ -60,7 +60,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (or page-id (:current-page-id state))
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
ids (into [] (filter some?) ids)
update-layout-ids
@ -107,7 +107,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
[shape changes]
(-> (pcb/empty-changes it page-id)
@ -140,7 +140,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (->> shapes
(remove #(dm/get-in objects [% :blocked]))
(cfh/order-by-indexed-shapes objects))
@ -169,13 +169,16 @@
(watch [it state _]
(let [file-id (:current-file-id state)
page-id (or page-id (:current-page-id state))
file (wsh/get-file state file-id)
page (wsh/lookup-page state page-id)
objects (wsh/lookup-page-objects state page-id)
fdata (dsh/lookup-file-data state file-id)
page (dsh/get-page fdata page-id)
objects (:objects page)
components-v2 (features/active-feature? state "components/v2")
undo-id (or (:undo-id options) (js/Symbol))
[all-parents changes] (-> (pcb/empty-changes it (:id page))
(cls/generate-delete-shapes file page objects ids {:components-v2 components-v2
(cls/generate-delete-shapes fdata page objects ids
{:components-v2 components-v2
:ignore-touched (:component-swap options)
:undo-group (:undo-group options)
:undo-id undo-id}))]
@ -191,15 +194,15 @@
(ptk/reify ::create-and-add-shape
ptk/WatchEvent
(watch [_ state _]
(let [vbc (wsh/viewport-center state)
(let [vbc (dsh/get-viewport-center state)
x (:x attrs (- (:x vbc) (/ width 2)))
y (:y attrs (- (:y vbc) (/ height 2)))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
frame-id (-> (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
frame-id (-> (dsh/lookup-page-objects state page-id)
(ctst/top-nested-frame {:x frame-x :y frame-y}))
selected (wsh/lookup-selected state)
selected (dsh/lookup-selected state)
base (cfh/get-base-shape objects selected)
parent-id (if (or (and (= 1 (count selected))
@ -241,8 +244,8 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (->> (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
@ -291,7 +294,7 @@
(cond-> obj
(boolean? blocked) (assoc :blocked blocked)
(boolean? hidden) (assoc :hidden hidden)))
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
;; We have change only the hidden behaviour, to hide only the
;; selected shape, block behaviour remains the same.
ids (if (boolean? blocked)
@ -304,7 +307,7 @@
(ptk/reify ::toggle-visibility-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (update-shapes selected #(update % :hidden not)))))))
(defn toggle-lock-selected
@ -312,7 +315,7 @@
(ptk/reify ::toggle-lock-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(rx/of (update-shapes selected #(update % :blocked not)))))))
@ -323,8 +326,9 @@
(ptk/reify ::toggle-file-thumbnail-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
pages (-> state :workspace-data :pages-index vals)
(let [selected (dsh/lookup-selected state)
fdata (dsh/lookup-file-data state)
pages (-> fdata :pages-index vals)
undo-id (js/Symbol)]
(rx/concat

View file

@ -7,8 +7,8 @@
(ns app.main.data.workspace.specialized-panel
(:require
[app.common.data :as d]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.common :as-alias dwc]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -28,8 +28,8 @@
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected-ids (wsh/lookup-selected state)
objects (dsh/lookup-page-objects state page-id)
selected-ids (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected-ids)]
(assoc state :specialized-panel {:type type :shapes selected-shapes})))
ptk/WatchEvent

View file

@ -1,168 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.workspace.state-helpers
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.svg.path.command :as upc]
[app.common.uuid :as uuid]))
(defn lookup-page
([state]
(lookup-page state (:current-page-id state)))
([state page-id]
(get-in state [:workspace-data :pages-index page-id])))
(defn lookup-page-objects
([state]
(lookup-page-objects state (:current-page-id state)))
([state page-id]
(-> (lookup-page state page-id)
(get :objects))))
(defn lookup-library-objects
[state file-id page-id]
(dm/get-in state [:libraries file-id :data :pages-index page-id :objects]))
(defn lookup-objects
[state file-id page-id]
(let [current-file? (= file-id (:current-file-id state))]
(if ^boolean current-file?
(lookup-page-objects state page-id)
(lookup-library-objects state file-id page-id))))
(defn lookup-local-components
([state]
(dm/get-in state [:workspace-data :components])))
(defn process-selected-shapes
([objects selected]
(process-selected-shapes objects selected nil))
([objects selected {:keys [omit-blocked?] :or {omit-blocked? false}}]
(letfn [(selectable? [id]
(and (contains? objects id)
(or (not omit-blocked?)
(not (get-in objects [id :blocked] false)))))]
(let [selected (->> selected (cfh/clean-loops objects))]
(into (d/ordered-set)
(filter selectable?)
selected)))))
(defn lookup-selected-raw
[state]
(dm/get-in state [:workspace-local :selected]))
(defn lookup-selected
([state]
(lookup-selected state nil))
([state options]
(lookup-selected state (:current-page-id state) options))
([state page-id options]
(let [objects (lookup-page-objects state page-id)
selected (dm/get-in state [:workspace-local :selected])]
(process-selected-shapes objects selected options))))
(defn lookup-shape
([state id]
(lookup-shape state (:current-page-id state) id))
([state page-id id]
(let [objects (lookup-page-objects state page-id)]
(get objects id))))
(defn lookup-shapes
([state ids]
(lookup-shapes state (:current-page-id state) ids))
([state page-id ids]
(let [objects (lookup-page-objects state page-id)]
(into [] (keep (d/getf objects)) ids))))
(defn filter-shapes
([state filter-fn]
(filter-shapes state (:current-page-id state) filter-fn))
([state page-id filter-fn]
(let [objects (lookup-page-objects state page-id)]
(into [] (filter filter-fn) (vals objects)))))
(defn get-local-file
"Get the data content of the file you are currently working with."
[state]
(get state :workspace-data))
(defn get-local-file-full
[state]
(-> (get state :workspace-file)
(assoc :data (get state :workspace-data))))
(defn get-file
"Get the data content of the given file (it may be the current file
or one library)."
[state file-id]
(if (= file-id (:current-file-id state))
(get state :workspace-data)
(dm/get-in state [:libraries file-id :data])))
(defn get-file-full
"Get the data content of the given file (it may be the current file
or one library)."
[state file-id]
(if (= file-id (:current-file-id state))
(-> (get state :workspace-file)
(assoc :data (get state :workspace-data)))
(dm/get-in state [:libraries file-id :data])))
(defn get-libraries
"Retrieve all libraries, including the local file."
[state]
(let [{:keys [id] :as local} (:workspace-data state)]
(-> (:libraries state)
(assoc id {:id id
:data local}))))
(defn- set-content-modifiers [state]
(fn [id shape]
(let [content-modifiers (dm/get-in state [:workspace-local :edit-path id :content-modifiers])]
(if (some? content-modifiers)
(update shape :content upc/apply-content-modifiers content-modifiers)
shape))))
(defn select-bool-children
[parent-id state]
(let [objects (lookup-page-objects state)
modifiers (:workspace-modifiers state)
children-ids (cfh/get-children-ids objects parent-id)
children
(-> (select-keys objects children-ids)
(update-vals
(fn [child]
(cond-> child
(contains? modifiers (:id child))
(gsh/transform-shape (get-in modifiers [(:id child) :modifiers]))))))]
(as-> children $
(d/mapm (set-content-modifiers state) $))))
(defn viewport-center
[state]
(let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])]
(gpt/point (+ x (/ width 2)) (+ y (/ height 2)))))
(defn find-orphan-shapes
([state]
(find-orphan-shapes state (:current-page-id state)))
([state page-id]
(let [objects (lookup-page-objects state page-id)
objects (filter (fn [item]
(and
(not= (key item) uuid/zero)
(not (contains? objects (:parent-id (val item))))))
objects)]
objects)))

View file

@ -15,8 +15,8 @@
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.repo :as rp]
[app.util.webapi :as wapi]
@ -72,8 +72,8 @@
(try
(let [id (d/nilv id (uuid/next))
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (if ignore-selection? #{} (wsh/lookup-selected state))
objects (dsh/lookup-page-objects state page-id)
selected (if ignore-selection? #{} (dsh/lookup-selected state))
base (cfh/get-base-shape objects selected)
selected-id (first selected)

View file

@ -18,12 +18,12 @@
[app.common.types.modifiers :as ctm]
[app.common.uuid :as uuid]
[app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.features :as features]
[app.main.fonts :as fonts]
@ -89,7 +89,7 @@
ptk/WatchEvent
(watch [_ state _]
(when (dwc/initialized? state)
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
editor-state (get-in state [:workspace-editor-state id])
content (-> editor-state
@ -321,7 +321,7 @@
(ptk/reify ::update-text-range
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
update-fn
@ -347,7 +347,7 @@
(ptk/reify ::update-root-attrs
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
update-fn
@ -372,7 +372,7 @@
ptk/WatchEvent
(watch [_ state _]
(when-not (some? (get-in state [:workspace-editor-state id]))
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
merge-fn (fn [node attrs]
@ -398,7 +398,7 @@
ptk/WatchEvent
(watch [_ state _]
(when-not (some? (get-in state [:workspace-editor-state id]))
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
update-node? (fn [node]
(or (txt/is-text-node? node)
@ -446,9 +446,8 @@
(when (or
(and (features/active-feature? state "text-editor/v2") (nil? (:workspace-editor state)))
(and (not (features/active-feature? state "text-editor/v2")) (nil? (get-in state [:workspace-editor-state id]))))
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
update-node? (some-fn txt/is-text-node? txt/is-paragraph-node?)
shape-ids
@ -485,8 +484,8 @@
(ptk/reify ::start-edit-if-selected
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
selected (->> state wsh/lookup-selected (mapv #(get objects %)))]
(let [objects (dsh/lookup-page-objects state)
selected (->> state dsh/lookup-selected (mapv #(get objects %)))]
(cond-> state
(and (= 1 (count selected))
(= (-> selected first :type) :text))
@ -501,7 +500,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [props (::resize-text-debounce-props state)
objects (wsh/lookup-page-objects state)
objects (dsh/lookup-page-objects state)
undo-id (js/Symbol)]
(letfn [(changed-text? [id]
@ -765,7 +764,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [editor-state (:workspace-editor-state state)
ids (d/nilv ids (wsh/lookup-selected state))
ids (d/nilv ids (dsh/lookup-selected state))
attrs (-> typography
(assoc :typography-ref-file file-id)
(assoc :typography-ref-id (:id typography))
@ -794,8 +793,8 @@
(ptk/reify ::add-typography
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
(let [selected (dsh/lookup-selected state)
objects (dsh/lookup-page-objects state)
xform (comp (keep (d/getf objects))
(filter cfh/text-shape?))
@ -863,7 +862,7 @@
(ptk/reify ::v2-update-text-shape-content
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)
modifiers (get-in state [:workspace-text-modifier id])
new-shape? (nil? (:content shape))]

View file

@ -12,9 +12,9 @@
[app.common.thumbnails :as thc]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.persistence :as-alias dps]
[app.main.data.workspace.notifications :as-alias wnt]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.rasterizer :as thr]
[app.main.refs :as refs]
[app.main.render :as render]
@ -65,7 +65,9 @@
[state file-id page-id frame-id tag]
(let [object-id (thc/fmt-object-id file-id page-id frame-id tag)
tp (tp/tpoint-ms)
objects (wsh/lookup-objects state file-id page-id)
objects (-> (dsh/lookup-file state file-id)
(dsh/get-page page-id)
:objects)
shape (get objects frame-id)]
(->> (render/render-frame objects shape object-id)

View file

@ -26,10 +26,10 @@
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.collapse :as dwc]
[app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.snap :as snap]
[app.main.streams :as ms]
@ -262,7 +262,7 @@
page-id (:current-page-id state)
focus (:workspace-focus-selected state)
zoom (dm/get-in state [:workspace-local :zoom] 1)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (map (d/getf objects) ids)]
(rx/concat
@ -313,10 +313,9 @@
(ptk/reify ::update-dimensions
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
get-modifier
(fn [shape] (ctm/change-dimensions-modifiers shape attr value))
modif-tree
(-> (dwm/build-modif-tree ids objects get-modifier)
(gm/set-objects-modifiers objects))]
@ -341,7 +340,7 @@
(ptk/reify ::change-orientation
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
get-modifier
(fn [shape] (ctm/change-orientation-modifiers shape orientation))
@ -408,7 +407,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (->> ids (map #(get objects %)))]
(rx/concat
(rx/of (dwm/set-delta-rotation-modifiers rotation shapes params))
@ -438,7 +437,7 @@
;; We toggle the selection so we don't have to wait for the event
selected
(cond-> (wsh/lookup-selected state {:omit-blocked? true})
(cond-> (dsh/lookup-selected state {:omit-blocked? true})
(some? id)
(d/toggle-selection id shift?))]
@ -502,8 +501,8 @@
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state {:omit-blocked? true})
objects (dsh/lookup-page-objects state page-id)
selected (dsh/lookup-selected state {:omit-blocked? true})
ids (if (nil? ids) selected ids)
shapes (into []
(comp (map (d/getf objects))
@ -625,8 +624,8 @@
(ptk/reify ::reorder-layout-child
ptk/WatchEvent
(watch [it state _]
(let [selected (wsh/lookup-selected state {:omit-blocked? true})
objects (wsh/lookup-page-objects state)
(let [selected (dsh/lookup-selected state {:omit-blocked? true})
objects (dsh/lookup-page-objects state)
page-id (:current-page-id state)
get-move-to-index
@ -734,7 +733,7 @@
ptk/WatchEvent
(watch [_ state stream]
(if (= same-event (get state ::current-move-selected))
(let [selected (wsh/lookup-selected state {:omit-blocked? true})
(let [selected (dsh/lookup-selected state {:omit-blocked? true})
nudge (get-in state [:profile :props :nudge] {:big 10 :small 1})
move-events (->> stream
(rx/filter (ptk/type? ::nudge-selected-shapes))
@ -776,8 +775,8 @@
(ptk/reify ::move-selected
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state {:omit-blocked? true})
(let [objects (dsh/lookup-page-objects state)
selected (dsh/lookup-selected state {:omit-blocked? true})
selected-shapes (->> selected (map (d/getf objects)))]
(if (every? #(and (ctl/any-layout-immediate-child? objects %)
(not (ctl/position-absolute? %)))
@ -794,7 +793,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shape (get objects id)
;; FIXME: performance rect
@ -817,7 +816,7 @@
(ptk/reify ::position-shapes
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
shapes (d/index-by :id shapes)
modif-tree
@ -864,7 +863,7 @@
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
ids (cleanup-invalid-moving-shapes ids objects frame-id)
changes (cls/generate-relocate (pcb/empty-changes it)
objects
@ -898,8 +897,8 @@
(ptk/reify ::flip-horizontal-selected
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (or ids (wsh/lookup-selected state {:omit-blocked? true}))
(let [objects (dsh/lookup-page-objects state)
selected (or ids (dsh/lookup-selected state {:omit-blocked? true}))
shapes (map #(get objects %) selected)
selrect (gsh/shapes->rect shapes)
center (grc/rect->center selrect)
@ -913,8 +912,8 @@
(ptk/reify ::flip-vertical-selected
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
selected (or ids (wsh/lookup-selected state {:omit-blocked? true}))
(let [objects (dsh/lookup-page-objects state)
selected (or ids (dsh/lookup-selected state {:omit-blocked? true}))
shapes (map #(get objects %) selected)
selrect (gsh/shapes->rect shapes)
center (grc/rect->center selrect)

View file

@ -14,7 +14,7 @@
[app.common.types.shape.layout :as ctl]
[app.main.data.changes :as dch]
[app.main.data.common :as dcm]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.util.time :as dt]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -186,7 +186,7 @@
(ptk/reify ::undo-to-index
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)]
(when-not (and (or (some? edition) (some? (:object drawing)))
@ -219,7 +219,7 @@
(ptk/reify ::undo
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)]
@ -257,7 +257,7 @@
(ptk/reify ::redo
ptk/WatchEvent
(watch [it state _]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)]
(when (and (or (nil? edition) (ctl/grid-layout? objects edition))
@ -291,7 +291,8 @@
ptk/WatchEvent
(watch [_ state _]
(let [page-id (:current-page-id state)
pages (dm/get-in state [:workspace-data :pages])]
pages (-> (dsh/lookup-file-data state)
(get :pages))]
(if (contains? pages page-id)
(rx/empty)
(rx/of (dcm/go-to-workspace :page-id (first pages))))))))

View file

@ -13,7 +13,7 @@
[app.common.geom.rect :as gpr]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.util.mouse :as mse]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -38,7 +38,7 @@
(initialize [state local]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (cfh/get-immediate-children objects)
srect (gsh/shapes->rect shapes)
local (assoc local :vport size :zoom 1 :zoom-inverse 1 :hide-toolbar false)]

View file

@ -14,7 +14,7 @@
[app.common.geom.point :as gpt]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.streams :as ms]
[app.util.mouse :as mse]
[beicon.v2.core :as rx]
@ -83,7 +83,7 @@
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
shapes (cfh/get-immediate-children objects)
srect (gsh/shapes->rect shapes)]
(if (empty? shapes)
@ -101,11 +101,11 @@
(ptk/reify ::zoom-to-selected-shape
ptk/UpdateEvent
(update [_ state]
(let [selected (wsh/lookup-selected state)]
(let [selected (dsh/lookup-selected state)]
(if (empty? selected)
state
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
srect (->> selected
(map #(get objects %))
(gsh/shapes->rect))]
@ -126,7 +126,7 @@
(if (empty? ids)
state
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
objects (dsh/lookup-page-objects state page-id)
srect (->> ids
(map #(get objects %))
(gsh/shapes->rect))]

View file

@ -14,7 +14,7 @@
[app.common.types.shape.layout :as ctl]
[app.common.types.tokens-lib :as ctob]
[app.config :as cf]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.store :as st]
[app.main.ui.workspace.tokens.token-set :as wtts]
[okulary.core :as l]))
@ -53,7 +53,7 @@
(def exception
(l/derived :exception st/state))
(def threads-ref
(def threads
(l/derived :comment-threads st/state))
(def share-links
@ -71,13 +71,22 @@
(def files
(l/derived :files st/state))
(def file
(l/derived (fn [state]
(let [file-id (:current-file-id state)
files (:files state)]
(get files file-id)))
st/state))
(def shared-files
"A derived state that points to the current list of shared
files (without the content, only summary)"
(l/derived :shared-files st/state))
(def libraries
(l/derived :libraries st/state))
"A derived state that contanins the currently loaded shared libraries
with all its content; including the current file"
(l/derived :files st/state))
(defn extract-selected-files
[files selected]
@ -121,7 +130,7 @@
(def ^:private selected-shapes-data
(l/derived
(fn [state]
(let [objects (wsh/lookup-page-objects state)
(let [objects (dsh/lookup-page-objects state)
selected (dm/get-in state [:workspace-local :selected])]
{:objects objects :selected selected}))
st/state (fn [v1 v2]
@ -131,7 +140,7 @@
(def selected-shapes
(l/derived
(fn [{:keys [objects selected]}]
(wsh/process-selected-shapes objects selected))
(dsh/process-selected-shapes objects selected))
selected-shapes-data))
(defn make-selected-ref
@ -217,20 +226,10 @@
(def rulers?
(l/derived #(contains? % :rulers) workspace-layout))
(def workspace-file
"A ref to a striped vision of file (without data)."
(l/derived (fn [state]
(let [file (:workspace-file state)
data (:workspace-data state)]
(-> file
(dissoc :data)
;; FIXME: still used in sitemaps but sitemaps
;; should declare its own lense for it
(assoc :pages (:pages data)))))
st/state =))
;; FIXME: rename to current-file-data
(def workspace-data
(l/derived :workspace-data st/state))
"Currently working file data on workspace"
(l/derived dsh/lookup-file-data st/state))
(def workspace-file-colors
(l/derived (fn [{:keys [id] :as data}]
@ -238,18 +237,19 @@
workspace-data
=))
(def workspace-recent-colors
(def recent-colors
"Recent colors for the currently selected file"
(l/derived (fn [state]
(when-let [file-id (:current-file-id state)]
(dm/get-in state [:recent-colors file-id])))
st/state))
;; FIXME: fonts are not prefixed, so the recent font list is shared
;; across all teams. This may not be expected behavior
(def workspace-recent-fonts
(l/derived (fn [data]
(get data :recent-fonts []))
workspace-data))
(def recent-fonts
"Recent fonts for the currently selected file"
(l/derived (fn [state]
(when-let [file-id (:current-file-id state)]
(dm/get-in state [:recent-fonts file-id])))
st/state))
(def workspace-file-typography
(l/derived :typographies workspace-data))
@ -258,23 +258,20 @@
(l/derived :workspace-presence st/state))
(def workspace-page
(l/derived (fn [state]
(let [page-id (:current-page-id state)
data (:workspace-data state)]
(dm/get-in data [:pages-index page-id])))
st/state))
"Ref to currently active page on workspace"
(l/derived dsh/lookup-page st/state))
(def workspace-page-flows
(l/derived #(-> % :flows not-empty) workspace-page))
(defn workspace-page-object-by-id
[page-id shape-id]
(l/derived #(wsh/lookup-shape % page-id shape-id) st/state =))
(l/derived #(dsh/lookup-shape % page-id shape-id) st/state =))
;; TODO: Looks like using the `=` comparator can be pretty expensive
;; on large pages, we are using this for some reason?
(def workspace-page-objects
(l/derived wsh/lookup-page-objects st/state =))
(l/derived dsh/lookup-page-objects st/state =))
(def workspace-read-only?
(l/derived :read-only? workspace-global))
@ -348,7 +345,7 @@
(l/derived
(fn [state]
{:modifiers (:workspace-modifiers state)
:objects (wsh/lookup-page-objects state)})
:objects (dsh/lookup-page-objects state)})
st/state
(fn [a b]
(and (= (:modifiers a) (:modifiers b))
@ -379,11 +376,11 @@
(l/derived #(get % frame-id) workspace-frame-modifiers =))
(defn select-bool-children [id]
(l/derived (partial wsh/select-bool-children id) st/state =))
(l/derived #(dsh/select-bool-children % id) st/state =))
(def selected-data
(l/derived #(let [selected (wsh/lookup-selected %)
objects (wsh/lookup-page-objects %)]
(l/derived #(let [selected (dsh/lookup-selected %)
objects (dsh/lookup-page-objects %)]
(hash-map :selected selected
:objects objects))
st/state =))
@ -415,7 +412,7 @@
[ids]
(l/derived
(fn [state]
(let [objects (wsh/lookup-page-objects state)]
(let [objects (dsh/lookup-page-objects state)]
(into []
(comp (map (d/getf objects))
(filter (partial ctl/flex-layout-immediate-child? objects)))

View file

@ -28,7 +28,8 @@
(r/map->Match data))
(defn resolve
([router id] (resolve router id {}))
([router id]
(resolve router id {}))
([router id params]
(when router
(when-let [match (r/match-by-name router id)]

View file

@ -37,14 +37,13 @@
[okulary.core :as l]
[rumext.v2 :as mf]))
(def comments-local-options (l/derived :options refs/comments-local))
(def ^:private ref:comments-local-options
(l/derived :options refs/comments-local))
(def mentions-context (mf/create-context nil))
(def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)")
(def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)")
(defn- parse-comment
"Parse a comment into its elements (texts and mentions)"
[comment]
@ -58,7 +57,7 @@
:content user
:data {:id id}})))))
(defn parse-nodes
(defn- parse-nodes
"Parse the nodes to format a comment"
[node]
(->> (dom/get-children node)
@ -72,8 +71,7 @@
(.-textContent node))))
(str/join "")))
(defn create-text-node
(defn- create-text-node
"Creates a text-only node"
([]
(create-text-node ""))
@ -82,7 +80,7 @@
(dom/set-data! "type" "text")
(dom/set-html! (if (empty? text) "&#8203;" text)))))
(defn create-mention-node
(defn- create-mention-node
"Creates a mention node"
[id fullname]
(-> (dom/create-element "span")
@ -91,7 +89,7 @@
(dom/set-data! "fullname" fullname)
(obj/set! "textContent" fullname)))
(defn current-text-node
(defn- current-text-node
"Retrieves the text node and the offset that the cursor is positioned on"
[node]
@ -108,7 +106,7 @@
(when (= node container)
[span-node anchor-offset])))))
(defn absolute-offset
(defn- absolute-offset
[node child offset]
(loop [nodes (seq (dom/get-children node))
acc 0]
@ -118,7 +116,7 @@
(recur (rest nodes) (+ acc (.-length (.-textContent head)))))
nil)))
(defn get-prev-node
(defn- get-prev-node
[parent node]
(->> (d/with-prev (dom/get-children parent))
(d/seek (fn [[it _]] (= node it)))
@ -126,8 +124,7 @@
;; Component that renders the component content
(mf/defc comment-content*
{::mf/props :obj
::mf/private true}
{::mf/private true}
[{:keys [content]}]
(let [comment-elements (mf/use-memo (mf/deps content) #(parse-comment content))]
(for [[idx {:keys [type content]}] (d/enumerate comment-elements)]
@ -141,22 +138,20 @@
;; Input text for comments with mentions
(mf/defc comment-input*
{::mf/props :obj
::mf/private true
::mf/wrap-props false}
[{:keys [value placeholder max-length autofocus? on-focus on-blur on-change on-esc on-ctrl-enter]}]
{::mf/private true}
[{:keys [value placeholder max-length autofocus on-focus on-blur on-change on-esc on-ctrl-enter]}]
(let [value (d/nilv value "")
prev-value (h/use-previous value)
local-ref (mf/use-ref nil)
mentions-str (mf/use-ctx mentions-context)
mentions-s (mf/use-ctx mentions-context)
cur-mention (mf/use-var nil)
prev-selection (mf/use-var nil)
init-input
(mf/use-callback
(mf/use-fn
(fn [node]
(mf/set-ref-val! local-ref node)
(when node
@ -167,13 +162,13 @@
nil)))))
handle-input
(mf/use-callback
(mf/use-fn
(mf/deps on-change)
(fn []
(let [node (mf/ref-val local-ref)
children (dom/get-children node)]
(doseq [child-node children]
(doseq [^js child-node children]
;; Remove nodes that are not span. This can happen if the user copy/pastes
(when (not= (.-tagName child-node) "SPAN")
(.remove child-node))
@ -198,7 +193,7 @@
(on-change new-input))))))
handle-select
(mf/use-callback
(mf/use-fn
(fn []
(let [node (mf/ref-val local-ref)
selection (wapi/get-selection)
@ -240,16 +235,16 @@
(if (re-matches #"@\w*" mention-text)
(do
(reset! cur-mention mention-text)
(rx/push! mentions-str {:type :display-mentions})
(rx/push! mentions-s {:type :display-mentions})
(let [mention (subs mention-text 1)]
(when (d/not-empty? mention)
(rx/push! mentions-str {:type :filter-mentions :data mention}))))
(rx/push! mentions-s {:type :filter-mentions :data mention}))))
(do
(reset! cur-mention nil)
(rx/push! mentions-str {:type :hide-mentions}))))))))
(rx/push! mentions-s {:type :hide-mentions}))))))))
handle-focus
(mf/use-callback
(mf/use-fn
(fn [event]
(dom/prevent-default event)
(dom/set-css-property! (mf/ref-val local-ref) "--placeholder" "")
@ -257,7 +252,7 @@
(on-focus event))))
handle-blur
(mf/use-callback
(mf/use-fn
(mf/deps value)
(fn [event]
(when (empty? value)
@ -268,6 +263,8 @@
(on-blur event))))
handle-insert-mention
(mf/use-fn
(mf/deps on-change)
(fn [data]
(let [node (mf/ref-val local-ref)
[span-node offset] (current-text-node node)]
@ -298,8 +295,8 @@
(wapi/set-cursor-after! after-span)
(wapi/collapse-end! sel)
(when on-change
(on-change (parse-nodes node)))))))
(when (fn? on-change)
(on-change (parse-nodes node))))))))
handle-key-down
(mf/use-fn
@ -314,22 +311,22 @@
(and @cur-mention (kbd/enter? event))
(do (dom/prevent-default event)
(dom/stop-propagation event)
(rx/push! mentions-str {:type :insert-selected-mention}))
(rx/push! mentions-s {:type :insert-selected-mention}))
(and @cur-mention (kbd/down-arrow? event))
(do (dom/prevent-default event)
(dom/stop-propagation event)
(rx/push! mentions-str {:type :insert-next-mention}))
(rx/push! mentions-s {:type :insert-next-mention}))
(and @cur-mention (kbd/up-arrow? event))
(do (dom/prevent-default event)
(dom/stop-propagation event)
(rx/push! mentions-str {:type :insert-prev-mention}))
(rx/push! mentions-s {:type :insert-prev-mention}))
(and @cur-mention (kbd/esc? event))
(do (dom/prevent-default event)
(dom/stop-propagation event)
(rx/push! mentions-str {:type :hide-mentions}))
(rx/push! mentions-s {:type :hide-mentions}))
(and (kbd/esc? event) (fn? on-esc))
(on-esc event)
@ -362,43 +359,36 @@
(.remove prev-node)))))))]
(mf/use-layout-effect
(mf/deps autofocus?)
(mf/deps autofocus)
(fn []
(when autofocus?
(when autofocus
(dom/focus! (mf/ref-val local-ref)))))
;; Creates the handlers for selection
(mf/use-effect
(mf/deps handle-select)
(fn []
(mf/with-effect [handle-select]
(let [handle-select* handle-select]
(js/document.addEventListener "selectionchange" handle-select*)
#(js/document.removeEventListener "selectionchange" handle-select*))))
#(js/document.removeEventListener "selectionchange" handle-select*)))
;; Effect to communicate with the mentions panel
(mf/use-effect
(fn []
(when mentions-str
(->> mentions-str
(mf/with-effect []
(when mentions-s
(->> mentions-s
(rx/subs!
(fn [{:keys [type data]}]
(case type
:insert-mention
(handle-insert-mention data)
nil)))))))
nil))))))
;; Auto resize input to display the comment
(mf/use-layout-effect
nil
(fn []
(let [node (mf/ref-val local-ref)]
(mf/with-layout-effect nil
(let [^js node (mf/ref-val local-ref)]
(set! (.-height (.-style node)) "0")
(set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px")))))
(set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px"))))
(mf/use-effect
(mf/deps value prev-value)
(fn []
(mf/with-effect [value prev-value]
(let [node (mf/ref-val local-ref)]
(cond
(and (d/not-empty? prev-value) (empty? value))
@ -411,7 +401,7 @@
(dom/set-css-property! node "--placeholder" (dm/str "\"" placeholder "\""))
(some? node)
(dom/set-css-property! node "--placeholder" "")))))
(dom/set-css-property! node "--placeholder" ""))))
[:div
{:role "textbox"
@ -425,27 +415,26 @@
:on-blur handle-blur}]))
(mf/defc mentions-panel*
{::mf/props :obj
::mf/private true}
[{:keys [profiles]}]
(let [mentions-str (mf/use-ctx mentions-context)
[]
(let [mentions-s (mf/use-ctx mentions-context)
profile (mf/deref refs/profile)
profiles (mf/deref refs/profiles)
mention-state
(mf/use-state {:display? false
state*
(mf/use-state
#(do {:display false
:mention-filter ""
:selected 0})
:selected 0}))
{:keys [display? mention-filter selected]} @mention-state
{:keys [display mention-filter selected]}
(deref state*)
mentions-users
(mf/use-memo
(mf/deps mention-filter)
#(->> (vals profiles)
(filter
(fn [{:keys [id fullname email]}]
(mf/with-memo [mention-filter]
(->> (vals profiles)
(filter (fn [{:keys [id fullname email]}]
(and
(not= id (:id profile))
(or (not mention-filter)
@ -455,54 +444,53 @@
(take 4)
(into [])))
selected (mth/clamp selected 0 (dec (count mentions-users)))
selected
(mth/clamp selected 0 (dec (count mentions-users)))
handle-click-mention
(mf/use-callback
(mf/use-fn
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(let [id (-> (dom/get-current-target event)
(dom/get-data "user-id")
(uuid/uuid))]
(rx/push! mentions-str {:type :insert-mention
(rx/push! mentions-s {:type :insert-mention
:data {:user (get profiles id)}}))))]
(mf/use-effect
(mf/deps mentions-users selected)
(fn []
(mf/with-effect [mentions-users selected]
(let [sub
(->> mentions-str
(->> mentions-s
(rx/subs!
(fn [{:keys [type data]}]
(case type
;; Display the mentions dialog
:display-mentions
(swap! mention-state assoc :display? true)
(swap! state* assoc :display true)
;; Hide mentions
:hide-mentions
(swap! mention-state assoc :display? false :mention-filter "")
(swap! state* assoc :display false :mention-filter "")
;; Filter the metions by some characters
:filter-mentions
(swap! mention-state assoc :mention-filter data)
(swap! state* assoc :mention-filter data)
:insert-selected-mention
(rx/push! mentions-str {:type :insert-mention
(rx/push! mentions-s {:type :insert-mention
:data {:user (get mentions-users selected)}})
:insert-next-mention
(swap! mention-state update :selected #(mth/clamp (inc %) 0 (dec (count mentions-users))))
(swap! state* update :selected #(mth/clamp (inc %) 0 (dec (count mentions-users))))
:insert-prev-mention
(swap! mention-state update :selected #(mth/clamp (dec %) 0 (dec (count mentions-users))))
(swap! state* update :selected #(mth/clamp (dec %) 0 (dec (count mentions-users))))
;;
nil))))]
#(rx/dispose! sub))))
#(rx/dispose! sub)))
(when display?
(when ^boolean display
[:div {:class (stl/css :comments-mentions-choice)}
(if (empty? mentions-users)
[:div {:class (stl/css :comments-mentions-empty)}
@ -523,15 +511,15 @@
{::mf/props :obj
::mf/private true}
[]
(let [mentions-str (mf/use-ctx mentions-context)
(let [mentions-s (mf/use-ctx mentions-context)
display-mentions* (mf/use-state false)
handle-mouse-down
(mf/use-callback
(mf/use-fn
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(rx/push! mentions-str {:type :display-mentions})))]
(rx/push! mentions-s {:type :display-mentions})))]
(mf/use-effect
(fn []
@ -542,7 +530,7 @@
:display-mentions (reset! display-mentions* true)
:hide-mentions (reset! display-mentions* false)
nil))
mentions-str)]
mentions-s)]
#(rx/dispose! sub))))
[:> icon-button*
@ -561,8 +549,7 @@
[:maybe [:enum "read" "unread" "solved"]]]])
(mf/defc comment-avatar*
{::mf/props :obj
::mf/schema schema:comment-avatar}
{::mf/schema schema:comment-avatar}
[{:keys [image variant class] :rest props}]
(let [variant (or variant "read")
class (dm/str class " " (stl/css-case :avatar true
@ -577,8 +564,7 @@
:avatar-darken (= variant "solved"))}]]))
(mf/defc comment-info*
{::mf/props :obj
::mf/private true}
{::mf/private true}
[{:keys [item profile]}]
[:*
[:div {:class (stl/css :author)}
@ -642,11 +628,12 @@
(fn []
(st/emit! (dcm/add-comment thread @content))
(on-cancel)))]
[:div {:class (stl/css :form)}
[:> comment-input*
{:value @content
:placeholder (tr "labels.reply.thread")
:autofocus? true
:autofocus true
:on-blur on-blur
:on-focus on-focus
:on-ctrl-enter on-submit
@ -664,8 +651,7 @@
(tr "labels.post")]])]))
(mf/defc comment-edit-form*
{::mf/props :obj
::mf/private true}
{::mf/private true}
[{:keys [content on-submit on-cancel]}]
(let [content (mf/use-state content)
@ -684,7 +670,7 @@
[:div {:class (stl/css :form)}
[:> comment-input*
{:value @content
:autofocus? true
:autofocus true
:on-ctrl-enter on-submit*
:on-change on-change
:max-length 750}]
@ -699,11 +685,10 @@
(tr "labels.post")]]]))
(mf/defc comment-floating-thread-draft*
{::mf/props :obj}
[{:keys [draft zoom on-cancel on-submit position-modifier profiles]}]
[{:keys [draft zoom on-cancel on-submit position-modifier]}]
(let [profile (mf/deref refs/profile)
mentions-str (mf/use-memo #(rx/subject))
mentions-s (mf/use-memo #(rx/subject))
position (cond-> (:position draft)
(some? position-modifier)
@ -736,7 +721,7 @@
(mf/deps draft)
(partial on-submit draft))]
[:> (mf/provider mentions-context) {:value mentions-str}
[:> (mf/provider mentions-context) {:value mentions-s}
[:div
{:class (stl/css :floating-preview-wrapper)
:data-testid "floating-thread-bubble"
@ -753,7 +738,7 @@
[:> comment-input*
{:placeholder (tr "labels.write-new-comment")
:value (or content "")
:autofocus? true
:autofocus true
:on-esc on-esc
:on-change on-change
:on-ctrl-enter on-submit
@ -769,15 +754,14 @@
:disabled disabled?}
(tr "labels.post")]]]
[:> mentions-panel* {:profiles profiles}]]]))
[:> mentions-panel*]]]))
(mf/defc comment-floating-thread-header*
{::mf/props :obj
::mf/private true}
[{:keys [profiles thread origin]}]
(let [owner (get profiles (:owner-id thread))
{::mf/private true}
[{:keys [thread origin]}]
(let [owner (dcm/get-owner thread)
profile (mf/deref refs/profile)
options (mf/deref comments-local-options)
options (mf/deref ref:comments-local-options)
toggle-resolved
(mf/use-fn
@ -842,12 +826,11 @@
(tr "labels.delete-comment-thread")]]]]))
(mf/defc comment-floating-thread-item*
{::mf/props :obj
::mf/private true}
[{:keys [comment thread profiles]}]
(let [owner (get profiles (:owner-id comment))
{::mf/private true}
[{:keys [comment thread]}]
(let [owner (dcm/get-owner comment)
profile (mf/deref refs/profile)
options (mf/deref comments-local-options)
options (mf/deref ref:comments-local-options)
edition? (mf/use-state false)
on-toggle-options
@ -945,11 +928,10 @@
{:x x :y y :h-dir h-dir :v-dir v-dir}))
(mf/defc comment-floating-thread*
{::mf/props :obj
::mf/wrap [mf/memo]}
[{:keys [thread zoom profiles origin position-modifier viewport]}]
{::mf/wrap [mf/memo]}
[{:keys [thread zoom origin position-modifier viewport]}]
(let [ref (mf/use-ref)
mentions-str (mf/use-memo #(rx/subject))
mentions-s (mf/use-memo #(rx/subject))
thread-id (:id thread)
thread-pos (:position thread)
@ -960,7 +942,7 @@
max-height (when (some? viewport) (int (* (:height viewport) 0.5)))
;; We should probably look for a better way of doing this.
bubble-margin {:x 24 :y 24}
bubble-margin (gpt/point 24 24)
pos (offset-position base-pos viewport zoom bubble-margin)
margin-x (* (:x bubble-margin) (if (= (:h-dir pos) :left) -1 1))
@ -988,7 +970,7 @@
(when-let [node (mf/ref-val ref)]
(dom/scroll-into-view-if-needed! node)))
[:& (mf/provider mentions-context) {:value mentions-str}
[:> (mf/provider mentions-context) {:value mentions-s}
(when (some? first-comment)
[:div {:class (stl/css-case :floating-thread-wrapper true
:left (= (:h-dir pos) :left)
@ -1000,29 +982,25 @@
:on-click dom/stop-propagation}
[:div {:class (stl/css :floating-thread-header)}
[:> comment-floating-thread-header* {:profiles profiles
:thread thread
[:> comment-floating-thread-header* {:thread thread
:origin origin}]]
[:div {:class (stl/css :floating-thread-main)}
[:> comment-floating-thread-item* {:comment first-comment
:profiles profiles
:thread thread}]
(for [item (rest comments)]
[:* {:key (dm/str (:id item))}
[:> comment-floating-thread-item* {:comment item
:profiles profiles}]])]
[:> comment-floating-thread-item* {:comment item}]])]
[:> comment-reply-form* {:thread thread}]
[:> mentions-panel* {:profiles profiles}]])]))
[:> mentions-panel*]])]))
(mf/defc comment-floating-bubble*
{::mf/props :obj
::mf/wrap [mf/memo]}
[{:keys [thread profiles zoom is-open on-click origin position-modifier]}]
(let [owner (get profiles (:owner-id thread))
{::mf/wrap [mf/memo]}
[{:keys [thread zoom is-open on-click origin position-modifier]}]
(let [owner (mf/with-memo [thread]
(dcm/get-owner thread))
base-pos (cond-> (:position thread)
(some? position-modifier)
(gpt/transform position-modifier))
@ -1036,11 +1014,12 @@
position (:position thread)
frame-id (:frame-id thread)
state (mf/use-state {:hover? false
:grabbing? false
state (mf/use-state
#(do {:is-hover false
:is-grabbing false
:new-position-x nil
:new-position-y nil
:new-frame-id frame-id})
:new-frame-id frame-id}))
pos-x (floor (* (or (:new-position-x @state) (:x base-pos)) zoom))
pos-y (floor (* (or (:new-position-y @state) (:y base-pos)) zoom))
@ -1050,7 +1029,7 @@
(mf/deps origin was-open? is-open drag?)
(fn [event]
(when (not= origin :viewer)
(swap! state assoc :grabbing? true)
(swap! state assoc :is-grabbing true)
(mf/set-ref-val! was-open? is-open)
(when is-open (st/emit! (dcm/close-thread)))
(mf/set-ref-val! drag? false)
@ -1064,7 +1043,7 @@
(mf/deps origin thread (select-keys @state [:new-position-x :new-position-y :new-frame-id]))
(fn [event]
(when (not= origin :viewer)
(swap! state assoc :grabbing? false)
(swap! state assoc :is-grabbing false)
(dom/stop-propagation event)
(dom/release-pointer event)
(mf/set-ref-val! dragging-ref false)
@ -1100,28 +1079,28 @@
(fn [event]
(dom/stop-propagation event)
(when (false? is-open)
(swap! state assoc :hover? true))))
(swap! state assoc :is-hover true))))
on-pointer-leave
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(swap! state assoc :hover? false)))
(swap! state assoc :is-hover false)))
on-click*
(mf/use-fn
(mf/deps origin thread on-click was-open? drag? (select-keys @state [:hover?]))
(mf/deps origin thread on-click was-open? drag? (select-keys @state [:is-hover]))
(fn [event]
(dom/stop-propagation event)
(when (or (and (mf/ref-val was-open?) (mf/ref-val drag?))
(and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
(swap! state assoc :hover? false)
(swap! state assoc :is-hover false)
(st/emit! (dcm/open-thread thread)))
(when (= origin :viewer)
(on-click thread))))]
[:div {:style {:top (str pos-y "px")
:left (str pos-x "px")}
[:div {:style {:top (dm/str pos-y "px")
:left (dm/str pos-x "px")}
:on-pointer-down on-pointer-down
:on-pointer-up on-pointer-up
:on-pointer-move on-pointer-move
@ -1129,29 +1108,30 @@
:on-pointer-leave on-pointer-leave
:on-click on-click*
:class (stl/css-case :floating-preview-wrapper true
:floating-preview-bubble (false? (:hover? @state))
:grabbing (true? (:grabbing? @state)))}
:floating-preview-bubble (false? (:is-hover @state))
:grabbing (true? (:is-grabbing @state)))}
(if (:hover? @state)
(if (:is-hover @state)
[:div {:class (stl/css :floating-thread-wrapper :floating-preview-displacement)}
[:div {:class (stl/css :floating-thread-item-wrapper)}
[:div {:class (stl/css :floating-thread-item)}
[:> comment-info* {:item thread
:profile owner}]]]]
[:> comment-avatar* {:image (cfg/resolve-profile-photo-url owner)
[:> comment-avatar*
{:image (cfg/resolve-profile-photo-url owner)
:class (stl/css :avatar-lg)
:data-testid (str "floating-thread-bubble-" (:seqn thread))
:variant (cond (:is-resolved thread) "solved"
:data-testid (dm/str "floating-thread-bubble-" (:seqn thread))
:variant (cond
(:is-resolved thread) "solved"
(pos? (:count-unread-comments thread)) "unread"
:else "read")}])]))
(mf/defc comment-sidebar-thread-item*
{::mf/props :obj
::mf/private true}
[{:keys [item profiles on-click]}]
(let [owner (get profiles (:owner-id item))
{::mf/private true}
[{:keys [item on-click]}]
(let [owner (dcm/get-owner item)
;; FIXME
frame (mf/deref (refs/workspace-page-object-by-id (:page-id item) (:frame-id item)))
on-click*
@ -1176,21 +1156,18 @@
:profile owner}]]))
(mf/defc comment-sidebar-thread-group*
{::mf/props :obj}
[{:keys [group profiles on-thread-click]}]
[{:keys [group on-thread-click]}]
[:div
(for [item (:items group)]
[:> comment-sidebar-thread-item*
{:item item
:on-click on-thread-click
:profiles profiles
:key (:id item)}])])
(mf/defc comment-dashboard-thread-item*
{::mf/props :obj
::mf/private true}
[{:keys [item profiles on-click]}]
(let [owner (get profiles (:owner-id item))
{::mf/private true}
[{:keys [item on-click]}]
(let [owner (dcm/get-owner item)
on-click*
(mf/use-fn
@ -1215,12 +1192,10 @@
:profile owner}]]))
(mf/defc comment-dashboard-thread-group*
{::mf/props :obj}
[{:keys [group profiles on-thread-click]}]
[{:keys [group on-thread-click]}]
[:div
(for [item (:items group)]
[:> comment-dashboard-thread-item*
{:item item
:on-click on-thread-click
:profiles profiles
:key (:id item)}])])

View file

@ -50,9 +50,9 @@
(mf/defc comments-section
[{:keys [profile team show? on-hide-comments]}]
(let [threads-map (mf/deref refs/comment-threads)
profiles (mf/deref refs/profiles)
team-id (:id team)
;; FIXME: with-memo
team-id (:id team)
tgroups (->> (vals threads-map)
(sort-by :modified-at)
(reverse)
@ -93,14 +93,12 @@
[:> cmt/comment-dashboard-thread-group*
{:group (first tgroups)
:on-thread-click on-navigate
:show-file-name true
:profiles profiles}]
:show-file-name true}]
(for [tgroup (rest tgroups)]
[:> cmt/comment-dashboard-thread-group*
{:group tgroup
:on-thread-click on-navigate
:show-file-name true
:profiles profiles
:key (:page-id tgroup)}])]
[:div {:class (stl/css :thread-groups-placeholder)}

View file

@ -14,8 +14,8 @@
[app.common.geom.shapes.points :as gpo]
[app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.css-cursors :as cur]
@ -135,7 +135,7 @@
negate {:column-gap (if flip-x true false)
:row-gap (if flip-y true false)}
objects (wsh/lookup-page-objects @st/state)
objects (dsh/lookup-page-objects @st/state)
children (->> (cfh/get-immediate-children objects frame-id)
(remove ctl/position-absolute?))

View file

@ -127,7 +127,7 @@
(mf/defc comments-layer
{::mf/props :obj}
[{:keys [zoom file users frame page]}]
[{:keys [zoom file frame page]}]
(let [profile (mf/deref refs/profile)
local (mf/deref refs/comments-local)
@ -208,7 +208,6 @@
(for [item threads]
[:> cmt/comment-floating-bubble*
{:thread item
:profiles users
:position-modifier modifier1
:zoom zoom
:on-click on-bubble-click
@ -219,7 +218,6 @@
(when-let [thread (get threads-map open-thread-id)]
[:> cmt/comment-floating-thread*
{:thread thread
:profiles users
:position-modifier modifier1
:viewport {:offset-x 0 :offset-y 0 :width (:width vsize) :height (:height vsize)}
:zoom zoom}])
@ -227,7 +225,6 @@
(when-let [draft (:draft local)]
[:> cmt/comment-floating-thread-draft*
{:draft draft
:profiles users
:position-modifier modifier1
:on-cancel on-draft-cancel
:on-submit on-draft-submit

View file

@ -9,11 +9,13 @@
(:require
[app.common.data.macros :as dm]
[app.main.data.common :as dcm]
[app.main.data.helpers :as dsh]
[app.main.data.persistence :as dps]
[app.main.data.plugins :as dpl]
[app.main.data.workspace :as dw]
[app.main.features :as features]
[app.main.refs :as refs]
[app.main.router :as-alias rt]
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.ds.product.loader :refer [loader*]]
@ -21,7 +23,7 @@
[app.main.ui.hooks.resize :refer [use-resize-observer]]
[app.main.ui.modal :refer [modal-container*]]
[app.main.ui.workspace.colorpicker]
[app.main.ui.workspace.context-menu :refer [context-menu]]
[app.main.ui.workspace.context-menu :refer [context-menu*]]
[app.main.ui.workspace.coordinates :as coordinates]
[app.main.ui.workspace.libraries]
[app.main.ui.workspace.nudge]
@ -32,7 +34,7 @@
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.tokens.modals]
[app.main.ui.workspace.tokens.modals.themes]
[app.main.ui.workspace.viewport :refer [viewport]]
[app.main.ui.workspace.viewport :refer [viewport*]]
[app.util.debug :as dbg]
[app.util.dom :as dom]
[app.util.globals :as globals]
@ -41,27 +43,19 @@
[okulary.core :as l]
[rumext.v2 :as mf]))
(defn- make-file-ready-ref
(defn- make-workspace-ready-ref
[file-id]
(l/derived (fn [state]
(let [data (:workspace-data state)]
(and (:workspace-ready state)
(= file-id (:current-file-id state))
(= file-id (:id data)))))
(and (= file-id (:workspace-ready state))
(some? (dsh/lookup-file-data state file-id))))
st/state))
(defn- make-page-ready-ref
[page-id]
(l/derived (fn [state]
(and (some? page-id)
(= page-id (:current-page-id state))))
st/state))
(mf/defc workspace-content
{::mf/wrap-props false}
[{:keys [file layout page-id wglobal]}]
(mf/defc workspace-content*
{::mf/private true}
[{:keys [file layout page wglobal]}]
(let [palete-size (mf/use-state nil)
selected (mf/deref refs/selected-shapes)
page-id (:id page)
{:keys [vport] :as wlocal} (mf/deref refs/workspace-local)
{:keys [options-mode]} wglobal
@ -102,7 +96,9 @@
[:button {:on-click #(st/emit! dw/reinitialize-undo)} "CLEAR"]
[:> history-toolbox*]])
[:& viewport {:file file
[:> viewport*
{:file file
:page page
:wlocal wlocal
:wglobal wglobal
:selected selected
@ -125,21 +121,17 @@
:page-id page-id}]])]))
(mf/defc workspace-loader*
{::mf/props :obj
::mf/private true}
{::mf/private true}
[]
[:> loader* {:title (tr "labels.loading")
:class (stl/css :workspace-loader)
:overlay true}])
(mf/defc workspace-page*
{::mf/props :obj
::mf/private true}
{::mf/private true}
[{:keys [page-id file layout wglobal]}]
(let [page-id (hooks/use-equal-memo page-id)
page-ready* (mf/with-memo [page-id]
(make-page-ready-ref page-id))
page-ready? (mf/deref page-ready*)]
page (mf/deref refs/workspace-page)]
(mf/with-effect []
(let [focus-out #(st/emit! (dw/workspace-focus-lost))
@ -149,29 +141,39 @@
(mf/with-effect [page-id]
(if (some? page-id)
(st/emit! (dw/initialize-page page-id))
(st/emit! (dcm/go-to-workspace)))
(st/emit! (dcm/go-to-workspace ::rt/replace true)))
(fn []
(when (some? page-id)
(st/emit! (dw/finalize-page page-id)))))
(if ^boolean page-ready?
[:& workspace-content {:page-id page-id
:file file
(if (some? page)
[:> workspace-content* {:file file
:page page
:wglobal wglobal
:layout layout}]
[:& workspace-loader*])))
(def ^:private ref:file-without-data
(l/derived (fn [file]
(dissoc file :data))
refs/file
=))
(mf/defc workspace*
{::mf/props :obj
::mf/wrap [mf/memo]}
[{:keys [project-id file-id page-id layout-name]}]
(let [layout (mf/deref refs/workspace-layout)
(let [file-id (hooks/use-equal-memo file-id)
page-id (hooks/use-equal-memo page-id)
layout (mf/deref refs/workspace-layout)
wglobal (mf/deref refs/workspace-global)
team (mf/deref refs/team)
file (mf/deref refs/workspace-file)
file (mf/deref ref:file-without-data)
file-name (:name file)
permissions (:permissions team)
@ -179,11 +181,10 @@
read-only? (mf/deref refs/workspace-read-only?)
read-only? (or read-only? (not (:can-edit permissions)))
file-ready* (mf/with-memo [file-id]
(make-file-ready-ref file-id))
file-ready? (mf/deref file-ready*)
ready* (mf/with-memo [file-id]
(make-workspace-ready-ref file-id))
ready? (mf/deref ready*)
components-v2? (features/use-feature "components/v2")
design-tokens? (features/use-feature "design-tokens/v1")
background-color (:background-color wglobal)]
@ -206,21 +207,21 @@
(st/emit! ::dps/force-persist
(dw/finalize-workspace file-id))))
[:& (mf/provider ctx/current-project-id) {:value project-id}
[:& (mf/provider ctx/current-file-id) {:value file-id}
[:& (mf/provider ctx/current-page-id) {:value page-id}
[:& (mf/provider ctx/components-v2) {:value components-v2?}
[:& (mf/provider ctx/design-tokens) {:value design-tokens?}
[:& (mf/provider ctx/workspace-read-only?) {:value read-only?}
[:> (mf/provider ctx/current-project-id) {:value project-id}
[:> (mf/provider ctx/current-file-id) {:value file-id}
[:> (mf/provider ctx/current-page-id) {:value page-id}
[:> (mf/provider ctx/components-v2) {:value true}
[:> (mf/provider ctx/design-tokens) {:value design-tokens?}
[:> (mf/provider ctx/workspace-read-only?) {:value read-only?}
[:> modal-container*]
[:section {:class (stl/css :workspace)
:style {:background-color background-color
:touch-action "none"}}
[:& context-menu]
[:> context-menu*]
(if ^boolean file-ready?
(if ^boolean ready?
[:> workspace-page* {:page-id page-id
:file file
:wglobal wglobal
:layout layout}]
[:> workspace-loader* {}])]]]]]]]))
[:> workspace-loader*])]]]]]]]))

View file

@ -24,20 +24,22 @@
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(mf/defc palette-item
(mf/defc palette-item*
{::mf/wrap [mf/memo]}
[{:keys [color size selected]}]
(letfn [(select-color [event]
(st/emit!
(dwl/add-recent-color color)
(let [select-color
(mf/use-fn
(mf/deps color selected)
(fn [event]
(st/emit! (dwl/add-recent-color color)
(mdc/apply-color-from-palette color (kbd/alt? event))
(when (not= selected :recent)
(ptk/event
::ev/event
(ptk/data-event ::ev/event
{::ev/name "use-library-color"
::ev/origin "color-palette"
:external-library (not= selected :file)}))))]
[:div {:class (stl/css-case :color-cell true
:external-library (not= selected :file)})))))]
[:div {:class (stl/css-case
:color-cell true
:is-not-library-color (nil? (:id color))
:no-text (<= size 64))
:title (uc/get-color-name color)
@ -45,8 +47,7 @@
[:& cb/color-bullet {:color color}]
[:& cb/color-name {:color color :size size :origin :palette}]]))
(mf/defc palette
(mf/defc palette*
[{:keys [current-colors size width selected]}]
(let [;; We had to do this due to a bug that leave some bugged colors
current-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) current-colors))
@ -140,7 +141,7 @@
:max-width (str width "px")
:right (str (* offset-step offset) "px")}}
(for [[idx item] (map-indexed vector current-colors)]
[:& palette-item {:color item :key idx :size size :selected selected}])])]
[:> palette-item* {:color item :key idx :size size :selected selected}])])]
(when show-arrows?
[:button {:class (stl/css :right-arrow)
:disabled (= offset max-offset)
@ -155,7 +156,7 @@
(mf/defc color-palette
{::mf/wrap [mf/memo]}
[{:keys [size width selected] :as props}]
(let [recent-colors (mf/deref refs/workspace-recent-colors)
(let [recent-colors (mf/deref refs/recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/libraries)
colors (mf/use-state [])]
@ -176,7 +177,7 @@
(reset! colors (into [] (->> (vals file-colors)
(sort-by :name))))))
[:& palette {:current-colors @colors
[:> palette* {:current-colors @colors
:size size
:width width
:selected selected}]))

View file

@ -17,7 +17,7 @@
(mf/defc color-palette-ctx-menu
[{:keys [show-menu? close-menu on-select-palette selected]}]
(let [recent-colors (mf/deref refs/workspace-recent-colors)
(let [recent-colors (mf/deref refs/recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/libraries)]
[:& dropdown {:show show-menu?

View file

@ -32,7 +32,7 @@
shared-libs (mf/deref refs/libraries)
file-colors (mf/deref refs/workspace-file-colors)
recent-colors (mf/deref refs/workspace-recent-colors)
recent-colors (mf/deref refs/recent-colors)
recent-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) recent-colors))
on-library-change

View file

@ -73,9 +73,8 @@
[:span {:class (stl/css :icon)} i/tick]]]))
(mf/defc comments-sidebar*
{::mf/props :obj}
[{:keys [profiles threads page-id from-viewer]}]
(let [threads-map (mf/deref refs/threads-ref)
(let [threads-map (mf/deref refs/threads)
profile (mf/deref refs/profile)
profiles' (mf/deref refs/profiles)
profiles (or profiles profiles')

View file

@ -748,7 +748,7 @@
;; FIXME: optimize because it is rendered always
(mf/defc context-menu
(mf/defc context-menu*
[]
(let [mdata (mf/deref menu-ref)
top (- (get-in mdata [:position :y]) 20)

View file

@ -29,6 +29,7 @@
[app.main.ui.components.link-button :as lb]
[app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
@ -38,7 +39,6 @@
[app.util.strings :refer [matches-search]]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.v2 :as mf]))
(def ^:private close-icon
@ -53,25 +53,47 @@
(def ^:private library-icon
(i/icon-xref :library (stl/css :library-icon)))
(def ref:workspace-file
(l/derived :workspace-file st/state))
(defn- get-library-summary
"Given a library data return a summary representation of this library"
[data]
(let [colors (count (:colors data))
graphics 0
typographies (count (:typographies data))
components (count (ctkl/components-seq data))
empty? (and (zero? components)
(zero? graphics)
(zero? colors)
(zero? typographies))]
(defn create-file-library-ref
[library-id]
(letfn [(getter-fn [state]
(let [fdata (let [{:keys [id] :as wfile} (:workspace-data state)]
(if (= id library-id)
wfile
(dm/get-in state [:libraries library-id :data])))]
{:colors (-> fdata :colors vals)
:media (-> fdata :media vals)
:components (ctkl/components-seq fdata)
:typographies (-> fdata :typographies vals)}))]
(l/derived getter-fn st/state =)))
{:is-empty empty?
:colors colors
:graphics graphics
:typographies typographies
:components components}))
(defn- adapt-backend-summary
[summary]
(let [components (or (-> summary :components :count) 0)
graphics (or (-> summary :media :count) 0)
typographies (or (-> summary :typographies :count) 0)
colors (or (-> summary :colors :count) 0)
empty? (and (zero? components)
(zero? graphics)
(zero? colors)
(zero? typographies))]
{:is-empty empty?
:components components
:graphics graphics
:typographies typographies
:colors colors}))
(defn- describe-library
[components-count graphics-count colors-count typography-count]
(let [all-zero? (and (zero? components-count) (zero? graphics-count) (zero? colors-count) (zero? typography-count))]
(let [all-zero? (and (zero? components-count)
(zero? graphics-count)
(zero? colors-count)
(zero? typography-count))]
(str
(str/join " · "
(cond-> []
@ -88,10 +110,15 @@
(conj (tr "workspace.libraries.typography" typography-count))))
"\u00A0")))
(mf/defc describe-library-blocks*
(mf/defc library-description*
{::mf/props :obj
::mf/private true}
[{:keys [components-count graphics-count colors-count typography-count]}]
[{:keys [summary]}]
(let [components-count (get summary :components)
graphics-count (get summary :graphics)
typography-count (get summary :typographies)
colors-count (get summary :colors)]
[:*
(when (pos? components-count)
[:li {:class (stl/css :element-count)}
@ -107,7 +134,7 @@
(when (pos? typography-count)
[:li {:class (stl/css :element-count)}
(tr "workspace.libraries.typography" typography-count)])])
(tr "workspace.libraries.typography" typography-count)])]))
(mf/defc sample-library-entry*
{::mf/props :obj
@ -146,26 +173,35 @@
:value (if (= importing? id) (tr "labels.adding") (tr "labels.add"))
:on-click import-library}]]))
(defn- empty-library?
"Check if currentt library summary has elements or not"
[summary]
(let [colors (or (-> summary :colors :count) 0)
components (or (-> summary :components :count) 0)
media (or (-> summary :media :count) 0)
typographies (or (-> summary :typographies :count) 0)]
(and (zero? colors)
(zero? components)
(zero? media)
(zero? typographies))))
(mf/defc libraries-tab*
{::mf/props :obj
::mf/private true}
[{:keys [file-id is-shared linked-libraries shared-libraries]}]
(let [search-term* (mf/use-state "")
[{:keys [is-shared linked-libraries shared-libraries]}]
(let [file-id (mf/use-ctx ctx/current-file-id)
search-term* (mf/use-state "")
search-term (deref search-term*)
library-ref (mf/with-memo [file-id]
(create-file-library-ref file-id))
library (deref library-ref)
colors (:colors library)
components (:components library)
media (:media library)
typographies (:typographies library)
;; The summary of the current/local library
;; NOTE: we only need a snapshot of current library
local-library (deref refs/workspace-data)
summary (get-library-summary local-library)
empty-library? (empty-library? summary)
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
empty-library? (and
(zero? (count colors))
(zero? (count components))
(zero? (count media))
(zero? (count typographies)))
shared-libraries
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
@ -263,10 +299,8 @@
[:div {:class (stl/css :item-content)}
[:div {:class (stl/css :item-name)} (tr "workspace.libraries.file-library")]
[:ul {:class (stl/css :item-contents)}
[:> describe-library-blocks* {:components-count (count components)
:graphics-count (count media)
:colors-count (count colors)
:typography-count (count typographies)}]]]
[:> library-description* {:summary summary}]]]
(if ^boolean is-shared
[:input {:class (stl/css :item-unpublish)
:type "button"
@ -277,21 +311,15 @@
:value (tr "common.publish")
:on-click publish}])]
(for [{:keys [id name] :as library} linked-libraries]
(for [{:keys [id name data] :as library} linked-libraries]
[:div {:class (stl/css :section-list-item)
:key (dm/str id)
:data-testid "library-item"}
[:div {:class (stl/css :item-content)}
[:div {:class (stl/css :item-name)} name]
[:ul {:class (stl/css :item-contents)}
(let [components-count (count (or (ctkl/components-seq (:data library)) []))
graphics-count (count (dm/get-in library [:data :media] []))
colors-count (count (dm/get-in library [:data :colors] []))
typography-count (count (dm/get-in library [:data :typographies] []))]
[:> describe-library-blocks* {:components-count components-count
:graphics-count graphics-count
:colors-count colors-count
:typography-count typography-count}])]]
(let [summary (get-library-summary data)]
[:> library-description* {:summary summary}])]]
[:button {:class (stl/css :item-button)
:type "button"
@ -318,14 +346,10 @@
[:div {:class (stl/css :item-content)}
[:div {:class (stl/css :item-name)} name]
[:ul {:class (stl/css :item-contents)}
(let [components-count (dm/get-in library [:library-summary :components :count] 0)
graphics-count (dm/get-in library [:library-summary :media :count] 0)
colors-count (dm/get-in library [:library-summary :colors :count] 0)
typography-count (dm/get-in library [:library-summary :typographies :count] 0)]
[:> describe-library-blocks* {:components-count components-count
:graphics-count graphics-count
:colors-count colors-count
:typography-count typography-count}])]]
(let [summary (-> (:library-summary library)
(adapt-backend-summary))]
[:> library-description* {:summary summary}])]]
[:button {:class (stl/css :item-button-shared)
:data-library-id (dm/str id)
:title (tr "workspace.libraries.shared-library-btn")
@ -414,11 +438,16 @@
(mf/defc updates-tab*
{::mf/props :obj
::mf/private true}
[{:keys [file-id file-data libraries]}]
[{:keys [file-id libraries]}]
;; FIXME: naming
(let [summary?* (mf/use-state true)
summary? (deref summary?*)
updating? (mf/deref refs/updating-library)
;; NOTE: we don't want to react on file changes, we just want
;; a snapshot of file on the momento of open the dialog
file-data (deref refs/workspace-data)
see-all-assets
(mf/use-fn
(fn []
@ -544,22 +573,31 @@
(when (or (pos? (:components exceeded))
(pos? (:colors exceeded))
(pos? (:typographies exceeded)))
[:& lb/link-button {:on-click see-all-assets
[:& lb/link-button
{:on-click see-all-assets
:class (stl/css :libraries-updates-see-all)
:value (str "(" (tr "workspace.libraries.update.see-all-changes") ")")}])])]])]]))
(mf/defc libraries-dialog
{::mf/register modal/components
::mf/register-as :libraries-dialog}
[{:keys [starting-tab] :as props :or {starting-tab :libraries}}]
(let [file-data (mf/deref refs/workspace-data)
file (mf/deref ref:workspace-file)
(let [;; NOTE: we don't want to react on file changes, we just want
;; a snapshot of file on the momento of open the dialog
file (deref refs/file)
file-id (:id file)
shared? (:is-shared file)
libraries (mf/deref refs/libraries)
libraries (mf/with-memo [libraries]
(d/removem (fn [[_ val]] (:is-indirect val)) libraries))
linked-libraries
(mf/deref refs/files)
linked-libraries
(mf/with-memo [linked-libraries file-id]
(d/removem (fn [[_ lib]]
(or (:is-indirect lib)
(= (:id lib) file-id)))
linked-libraries))
shared-libraries
(mf/deref refs/shared-files)
@ -578,16 +616,14 @@
libraries-tab
(mf/html [:> libraries-tab*
{:file-id file-id
:is-shared shared?
:linked-libraries libraries
{:is-shared shared?
:linked-libraries linked-libraries
:shared-libraries shared-libraries}])
updates-tab
(mf/html [:> updates-tab*
{:file-id file-id
:file-data file-data
:libraries libraries}])
:libraries linked-libraries}])
tabs
#js [#js {:label (tr "workspace.libraries.libraries")
@ -600,7 +636,9 @@
(mf/with-effect []
(st/emit! (dtm/fetch-shared-files)))
[:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside :data-testid "libraries-modal"}
[:div {:class (stl/css :modal-overlay)
:on-click close-dialog-outside
:data-testid "libraries-modal"}
[:div {:class (stl/css :modal-dialog)}
[:button {:class (stl/css :close-btn)
:on-click close-dialog

View file

@ -11,7 +11,7 @@
[app.common.geom.shapes.bounds :as gsb]
[app.common.math :as mth]
[app.common.thumbnails :as thc]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.refs :as refs]
[app.main.store :as st]
@ -70,7 +70,7 @@
::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
objects (wsh/lookup-page-objects @st/state)
objects (dsh/lookup-page-objects @st/state)
frame-id (dm/get-prop shape :id)

View file

@ -20,10 +20,11 @@
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.main.ui.workspace.sidebar.assets.file-library :refer [file-library]]
[app.main.ui.workspace.sidebar.assets.file-library :refer [file-library*]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.v2 :as mf]))
(mf/defc assets-libraries*
@ -31,38 +32,39 @@
::mf/props :obj
::mf/private true}
[{:keys [filters]}]
(let [libraries (mf/deref refs/libraries)
libraries (mf/with-memo [libraries]
(let [file-id (mf/use-ctx ctx/current-file-id)
libraries (mf/deref refs/libraries)
libraries (mf/with-memo [libraries file-id]
(->> (vals libraries)
(remove :is-indirect)
(remove #(= file-id (:id %)))
(map (fn [file]
(update file :data dissoc :pages-index)))
(sort-by #(str/lower (:name %)))))]
(for [file libraries]
[:& file-library
[:> file-library*
{:key (dm/str (:id file))
:file file
:local? false
:default-open? false
:is-local false
:is-default-open false
:filters filters}])))
(def ^:private ref:local-library
(l/derived (fn [file]
(update file :data dissoc :pages-index))
refs/file))
(mf/defc assets-local-library
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[{:keys [filters]}]
;; NOTE: as workspace-file is an incomplete view of file (it do not
;; contain :data), we need to reconstruct it using workspace-data
(let [file (mf/deref refs/workspace-file)
data (mf/deref refs/workspace-data)
data (mf/with-memo [data]
(dissoc data :pages-index))
file (mf/with-memo [file data]
(assoc file :data data))]
[:& file-library
(let [file (mf/deref ref:local-library)]
[:> file-library*
{:file file
:local? true
:default-open? true
:is-local true
:is-default-open true
:filters filters}]))
(defn- toggle-values

View file

@ -15,6 +15,7 @@
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.config :as cf]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl]
@ -58,7 +59,10 @@
(if reverse? "z" "a")
path)]
(str/lower (cfh/merge-path-item path name))))
(if ^boolean reverse? > <)))))
(if ^boolean reverse? > <))
:always
(vec))))
(defn add-group
[asset group-name]
@ -315,10 +319,13 @@
copies (filter ctk/in-component-copy? shapes)
current-file-id (mf/use-ctx ctx/current-file-id)
objects (deref refs/workspace-page-objects)
workspace-data (deref refs/workspace-data)
current-page-id (mf/use-ctx ctx/current-page-id)
libraries (deref refs/libraries)
current-file {:id current-file-id :data workspace-data}
current-file (get libraries current-file-id)
objects (-> (dsh/get-page (:data current-file) current-page-id)
(get :objects))
find-component (fn [shape include-deleted?]
(ctf/resolve-component

View file

@ -37,31 +37,23 @@
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(def drag-data* (atom {:local? false}))
(def drag-data* (atom {:is-local false}))
(defn set-drag-data! [data]
(reset! drag-data* data))
(defn- get-component-root-and-container
[file-id component components-v2]
(if (= file-id (:id @refs/workspace-file))
(let [data @refs/workspace-data]
[(ctf/get-component-root data component)
(if components-v2
(ctf/get-component-page data component)
component)])
[file-id component]
(let [data (dm/get-in @refs/libraries [file-id :data])
root-shape (ctf/get-component-root data component)
container (if components-v2
(ctf/get-component-page data component)
component)]
[root-shape container])))
container (ctf/get-component-page data component)]
[root-shape container]))
(mf/defc components-item
{::mf/wrap-props false}
[{:keys [component renaming listing-thumbs? selected
file-id on-asset-click on-context-menu on-drag-start do-rename
cancel-rename selected-full selected-paths local]}]
cancel-rename selected-full selected-paths is-local]}]
(let [item-ref (mf/use-ref)
@ -69,7 +61,6 @@
dragging? (deref dragging*)
read-only? (mf/use-ctx ctx/workspace-read-only?)
components-v2 (mf/use-ctx ctx/components-v2)
component-id (:id component)
visible? (h/use-visible item-ref :once? true)
@ -78,7 +69,7 @@
;; really need rerender on any change on the file change. If
;; the component changes, it will trigger rerender anyway.
[root-shape container]
(get-component-root-and-container file-id component components-v2)
(get-component-root-and-container file-id component)
unselect-all
(mf/use-fn
@ -94,38 +85,38 @@
on-component-double-click
(mf/use-fn
(mf/deps file-id component local)
(mf/deps file-id component is-local)
(fn [event]
(dom/stop-propagation event)
(if local
(if is-local
(st/emit! (dwl/go-to-local-component component-id))
(st/emit! (dwl/go-to-component-file file-id component)))))
on-drop
(mf/use-fn
(mf/deps component dragging* selected selected-full selected-paths local drag-data*)
(mf/deps component dragging* selected selected-full selected-paths is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drop-asset event component dragging* selected selected-full
selected-paths dwl/rename-component-and-main-instance))))
on-drag-enter
(mf/use-fn
(mf/deps component dragging* selected selected-paths local drag-data*)
(mf/deps component dragging* selected selected-paths is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drag-enter-asset event component dragging* selected selected-paths))))
on-drag-leave
(mf/use-fn
(mf/deps dragging* local drag-data*)
(mf/deps dragging* is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drag-leave-asset event dragging*))))
on-component-drag-start
(mf/use-fn
(mf/deps file-id component selected item-ref on-drag-start read-only? local)
(mf/deps file-id component selected item-ref on-drag-start read-only? is-local)
(fn [event]
(if read-only?
(dom/prevent-default event)
@ -183,7 +174,7 @@
{::mf/wrap-props false}
[{:keys [file-id prefix groups open-groups force-open? renaming listing-thumbs? selected on-asset-click
on-drag-start do-rename cancel-rename on-rename-group on-group on-ungroup on-context-menu
selected-full local]}]
selected-full is-local]}]
(let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
false
@ -199,23 +190,23 @@
selected-full))
on-drag-enter
(mf/use-fn
(mf/deps dragging* prefix selected-paths local drag-data*)
(mf/deps dragging* prefix selected-paths is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drag-enter-asset-group event dragging* prefix selected-paths))))
on-drag-leave
(mf/use-fn
(mf/deps dragging* local drag-data*)
(mf/deps dragging* is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drag-leave-asset event dragging*))))
on-drop
(mf/use-fn
(mf/deps dragging* prefix selected-paths selected-full local drag-data*)
(mf/deps dragging* prefix selected-paths selected-full is-local drag-data*)
(fn [event]
(when (and local (:local? @drag-data*))
(when (and is-local (:is-local @drag-data*))
(cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-component-and-main-instance))))]
[:div {:class (stl/css :component-group)
@ -248,7 +239,7 @@
(when (and (empty? components)
(some? groups)
local)
is-local)
[:div {:class (stl/css-case :drop-space true
:drop-space-small (not dragging?))}])
@ -268,7 +259,7 @@
:on-group on-group
:do-rename do-rename
:cancel-rename cancel-rename
:local local}])])
:is-local is-local}])])
(for [[path-item content] groups]
(when-not (empty? path-item)
@ -289,11 +280,11 @@
:on-ungroup on-ungroup
:on-context-menu on-context-menu
:selected-full selected-full
:local local}]))])]))
:is-local is-local}]))])]))
(mf/defc components-section
{::mf/wrap-props false}
[{:keys [file-id local? components listing-thumbs? open? force-open?
[{:keys [file-id is-local components listing-thumbs? open? force-open?
reverse-sort? selected on-asset-click on-assets-delete
on-clear-selection open-status-ref]}]
@ -466,7 +457,7 @@
(fn [component event]
(let [file-data
(d/nilv (dm/get-in @refs/libraries [file-id :data]) @refs/workspace-data)
(dm/get-in @refs/libraries [file-id :data])
shape-main
(ctf/get-component-root file-data component)]
@ -476,7 +467,7 @@
(set-drag-data! {:file-id file-id
:component component
:shape shape-main
:local? local?})
:is-local is-local})
(dnd/set-data! event "penpot/component" true)
@ -487,10 +478,10 @@
on-show-main
(mf/use-fn
(mf/deps current-component-id file-id local?)
(mf/deps current-component-id file-id is-local)
(fn [event]
(dom/stop-propagation event)
(if local?
(if is-local
(st/emit! (dwl/go-to-local-component :id current-component-id))
(let [component (d/seek #(= (:id %) current-component-id) components)]
(st/emit! (dwl/go-to-component-file file-id component))))))
@ -518,7 +509,7 @@
:title (tr "workspace.assets.grid-view")
:id "opt-grid"}]]])
(when (and components-v2 (not read-only?) local?)
(when (and components-v2 (not read-only?) is-local)
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.assets.components.add-component")
:on-click add-component
@ -547,27 +538,27 @@
:on-ungroup on-ungroup
:on-context-menu on-context-menu
:selected-full selected-full
:local ^boolean local?}])
:local ^boolean is-local}])
[:& cmm/assets-context-menu
{:on-close on-close-menu
:state @menu-state
:options [(when (and local? (not (or multi-components? multi-assets? read-only?)))
:options [(when (and is-local (not (or multi-components? multi-assets? read-only?)))
{:name (tr "workspace.assets.rename")
:id "assets-rename-component"
:handler on-rename})
(when (and local? (not (or multi-assets? read-only?)))
(when (and is-local (not (or multi-assets? read-only?)))
{:name (if components-v2
(tr "workspace.assets.duplicate-main")
(tr "workspace.assets.duplicate"))
:id "assets-duplicate-component"
:handler on-duplicate})
(when (and local? (not read-only?))
(when (and is-local (not read-only?))
{:name (tr "workspace.assets.delete")
:id "assets-delete-component"
:handler on-delete})
(when (and local? (not (or multi-assets? read-only?)))
(when (and is-local (not (or multi-assets? read-only?)))
{:name (tr "workspace.assets.group")
:id "assets-group-component"
:handler on-group})

View file

@ -9,6 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.components-list :as ctkl]
[app.main.data.event :as ev]
[app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl]
@ -19,7 +20,6 @@
[app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.workspace.libraries :refer [create-file-library-ref]]
[app.main.ui.workspace.sidebar.assets.colors :refer [colors-section]]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.main.ui.workspace.sidebar.assets.components :refer [components-section]]
@ -33,6 +33,10 @@
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; REFS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:private ref:open-status
(l/derived (l/in [:workspace-assets :open-status]) st/state))
@ -40,8 +44,37 @@
(-> (l/in [:workspace-assets :selected])
(l/derived st/state)))
(defn- create-file-ref
[library-id]
(l/derived (fn [state]
(dm/get-in state [:files library-id :data]))
st/state))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LOCAL HELPER HOOKS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- use-library-ref
[file-id]
(let [library-ref (mf/with-memo [file-id]
(create-file-ref file-id))]
(mf/deref library-ref)))
(defn- use-selected
"Returns the currently selected assets set on the library"
[file-id]
(let [selected-ref
(mf/with-memo [file-id]
(-> (l/key file-id)
(l/derived ref:selected)))]
(mf/deref selected-ref)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COMPONENTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(mf/defc file-library-title*
{::mf/props :obj}
{::mf/private true}
[{:keys [is-open is-local file-id page-id file-name]}]
(let [router (mf/deref refs/router)
team-id (mf/use-ctx ctx/current-team-id)
@ -61,7 +94,8 @@
(dom/stop-propagation ev)
(st/emit! (ptk/data-event ::ev/event {::ev/name "navigate-to-library-file"}))))]
[:div {:class (stl/css-case :library-title true
[:div {:class (stl/css-case
:library-title true
:open is-open)}
[:& title-bar {:collapsable true
:collapsed (not is-open)
@ -71,10 +105,9 @@
(mf/html [:div {:class (stl/css :special-title)}
(tr "workspace.assets.local-library")])
;; Do we need to add shared info here?
(mf/html [:div {:class (stl/css :special-title)}
file-name]))}
(when-not is-local
(when-not ^boolean is-local
[:span {:title (tr "workspace.assets.open-library")}
[:a {:class (stl/css :file-link)
:href (str "#" url)
@ -82,74 +115,8 @@
:on-click on-click}
i/open-link]])]]))
(mf/defc file-library-content
{::mf/wrap-props false}
[{:keys [file local? open-status-ref on-clear-selection filters]}]
(let [components-v2 (mf/use-ctx ctx/components-v2)
open-status (mf/deref open-status-ref)
file-id (:id file)
project-id (:project-id file)
filters-section (:section filters)
filters-term (:term filters)
filters-ordering (:ordering filters)
filters-list-style (:list-style filters)
reverse-sort? (= :desc filters-ordering)
listing-thumbs? (= :thumbs filters-list-style)
library-ref (mf/with-memo [file-id]
(create-file-library-ref file-id))
library (mf/deref library-ref)
colors (:colors library)
components (:components library)
media (:media library)
typographies (:typographies library)
colors (mf/with-memo [filters colors]
(cmm/apply-filters colors filters))
components (mf/with-memo [filters components]
(cmm/apply-filters components filters))
media (mf/with-memo [filters media]
(cmm/apply-filters media filters))
typographies (mf/with-memo [filters typographies]
(cmm/apply-filters typographies filters))
show-components? (and (or (= filters-section "all")
(= filters-section "components"))
(or (pos? (count components))
(str/empty? filters-term)))
show-graphics? (and (or (= filters-section "all")
(= filters-section "graphics"))
(or (pos? (count media))
(and (str/empty? filters-term)
(not components-v2))))
show-colors? (and (or (= filters-section "all")
(= filters-section "colors"))
(or (> (count colors) 0)
(str/empty? filters-term)))
show-typography? (and (or (= filters-section "all")
(= filters-section "typographies"))
(or (pos? (count typographies))
(str/empty? filters-term)))
selected-lens (mf/with-memo [file-id]
(-> (l/key file-id)
(l/derived ref:selected)))
selected (mf/deref selected-lens)
has-term? (not ^boolean (str/empty? filters-term))
force-open-components? (when ^boolean has-term? (> 60 (count components)))
force-open-colors? (when ^boolean has-term? (> 60 (count colors)))
force-open-graphics? (when ^boolean has-term? (> 60 (count media)))
force-open-typographies? (when ^boolean has-term? (> 60 (count typographies)))
extend-selected
(fn [type asset-groups asset-id]
(defn- extend-selected
[selected type asset-groups asset-id file-id]
(letfn [(flatten-groups [groups]
(reduce concat [(get groups "" [])
(into []
@ -175,9 +142,60 @@
(st/emit! (dw/select-assets file-id ids type)))))))
(mf/defc file-library-content*
{::mf/private true}
[{:keys [file is-local open-status-ref on-clear-selection filters colors media typographies components]}]
(let [open-status (mf/deref open-status-ref)
file-id (:id file)
project-id (:project-id file)
filters-section (:section filters)
has-filters-term? (not ^boolean (str/empty? (:term filters)))
reverse-sort? (= :desc (:ordering filters))
listing-thumbs? (= :thumbs (:list-style filters))
selected (use-selected file-id)
show-components?
(and (or (= filters-section "all")
(= filters-section "components"))
(or (pos? (count components))
(not has-filters-term?)))
show-graphics?
(and (or (= filters-section "all")
(= filters-section "graphics"))
(pos? (count media)))
show-colors?
(and (or (= filters-section "all")
(= filters-section "colors"))
(or (> (count colors) 0)
(not has-filters-term?)))
show-typography?
(and (or (= filters-section "all")
(= filters-section "typographies"))
(or (pos? (count typographies))
(not has-filters-term?)))
force-open-components?
(when ^boolean has-filters-term? (> 60 (count components)))
force-open-colors?
(when ^boolean has-filters-term? (> 60 (count colors)))
force-open-graphics?
(when ^boolean has-filters-term? (> 60 (count media)))
force-open-typographies?
(when ^boolean has-filters-term? (> 60 (count typographies)))
on-asset-click
(mf/use-fn
(mf/deps file-id extend-selected)
(mf/deps file-id selected)
(fn [asset-type asset-groups asset-id default-click event]
(cond
(kbd/mod? event)
@ -188,7 +206,7 @@
(kbd/shift? event)
(do
(dom/stop-propagation event)
(extend-selected asset-type asset-groups asset-id))
(extend-selected selected asset-type asset-groups asset-id file-id))
:else
(when default-click
@ -232,7 +250,7 @@
(when ^boolean show-components?
[:& components-section
{:file-id file-id
:local? local?
:local? is-local
:components components
:listing-thumbs? listing-thumbs?
:open? (or ^boolean force-open-components?
@ -249,7 +267,7 @@
[:& graphics-section
{:file-id file-id
:project-id project-id
:local? local?
:local? is-local
:objects media
:listing-thumbs? listing-thumbs?
:open? (or ^boolean force-open-graphics?
@ -265,7 +283,7 @@
(when ^boolean show-colors?
[:& colors-section
{:file-id file-id
:local? local?
:local? is-local
:colors colors
:open? (or ^boolean force-open-colors?
^boolean (get open-status :colors false))
@ -281,7 +299,7 @@
[:& typographies-section
{:file file
:file-id (:id file)
:local? local?
:local? is-local
:typographies typographies
:open? (or ^boolean force-open-typographies?
^boolean (get open-status :typographies false))
@ -303,67 +321,90 @@
[:span {:class (stl/css :no-found-text)}
(tr "workspace.assets.not-found")]])]))
(defn- force-lib-open? [file-id filters]
(let [library-ref (mf/with-memo [file-id]
(create-file-library-ref file-id))
library (mf/deref library-ref)
colors (:colors library)
components (:components library)
media (:media library)
typographies (:typographies library)
filtered-colors (mf/with-memo [filters colors]
(cmm/apply-filters colors filters))
filtered-components (mf/with-memo [filters components]
(cmm/apply-filters components filters))
filtered-media (mf/with-memo [filters media]
(cmm/apply-filters media filters))
filtered-typographies (mf/with-memo [filters typographies]
(cmm/apply-filters typographies filters))
filters-term (:term filters)
has-term? (not (str/blank? filters-term))]
(and has-term?
(some pos? (map count [filtered-components filtered-colors filtered-media filtered-typographies]))
(some #(> 60 (count %)) [filtered-components filtered-colors filtered-media filtered-typographies]))))
(mf/defc file-library
{::mf/props :obj}
[{:keys [file local? default-open? filters]}]
(mf/defc file-library*
[{:keys [file is-local is-default-open? filters]}]
(let [file-id (:id file)
file-name (:name file)
page-id (dm/get-in file [:data :pages 0])
open-status-ref (mf/with-memo [file-id]
library (use-library-ref file-id)
colors (:colors library)
media (:media library)
typographies (:typographies library)
filters-term (:term filters)
;; FIXME: maybe unused
;; has-term? (not (str/blank? filters-term))
filtered-colors
(mf/with-memo [filters colors]
(-> (vals colors)
(cmm/apply-filters filters)))
filtered-components
(mf/with-memo [filters library]
(-> (into [] (ctkl/components-seq library))
(cmm/apply-filters filters)))
filtered-media
(mf/with-memo [filters media]
(-> (vals media)
(cmm/apply-filters filters)))
filtered-typographies
(mf/with-memo [filters typographies]
(-> (vals typographies)
(cmm/apply-filters filters)))
open-status-ref
(mf/with-memo [file-id]
(-> (l/key file-id)
(l/derived ref:open-status)))
open-status (mf/deref open-status-ref)
force-open-lib? (force-lib-open? file-id filters)
open? (if (false? (:library open-status)) ;; if the user has closed it specifically, respect that
open-status
(mf/deref open-status-ref)
force-lib-open?
(and (not (str/blank? filters-term))
(or (> 60 (count filtered-colors))
(> 60 (count filtered-components))
(> 60 (count filtered-media))
(> 60 (count filtered-typographies))))
open?
(if (false? (:library open-status))
;; if the user has closed it specifically, respect that
false
(or force-open-lib?
(d/nilv (:library open-status) default-open?)))
(or force-lib-open?
(d/nilv (:library open-status) is-default-open?)))
unselect-all
(mf/use-fn
(mf/deps file-id)
(fn []
(st/emit! (dw/unselect-all-assets file-id))))]
[:div {:class (stl/css :tool-window)
:on-context-menu dom/prevent-default
:on-click unselect-all}
[:> file-library-title*
{:file-id file-id
:page-id page-id
:file-name file-name
:is-open open?
:is-local local?}]
:is-local is-local}]
(when ^boolean open?
[:& file-library-content
[:> file-library-content*
{:file file
:local? local?
:is-local is-local
:filters filters
:colors filtered-colors
:components filtered-components
:media filtered-media
:typographies filtered-typographies
:on-clear-selection unselect-all
:open-status-ref open-status-ref}])]))

View file

@ -249,6 +249,7 @@
read-only? (mf/use-ctx ctx/workspace-read-only?)
menu-state (mf/use-state cmm/initial-context-menu-state)
typographies (mf/with-memo [typographies]
(mapv dwl/extract-path-if-missing typographies))

View file

@ -169,11 +169,12 @@
(defn use-search
[page objects]
(let [state* (mf/use-state
{:show-search false
#(do {:show-search false
:show-menu false
:search-text ""
:filters #{}
:num-items 100})
:num-items 100}))
state (deref state*)
current-filters (:filters state)
current-items (:num-items state)

View file

@ -268,15 +268,6 @@
[:span {:class (stl/css :arrow-icon)}
i/arrow]]))
(def ^:private ref:swap-libraries
(letfn [(get-libraries [state]
(let [file (:workspace-file state)
data (:workspace-data state)
libs (:libraries state)]
(assoc libs (:id file)
(assoc file :data data))))]
(l/derived get-libraries st/state)))
(defn- find-common-path
([components]
(let [paths (map (comp cfh/split-path :path) components)]
@ -298,14 +289,13 @@
(= (:component-id shape-a)
(:component-id shape-b)))
(mf/defc component-swap
{::mf/props :obj}
[{:keys [shapes]}]
(let [single? (= 1 (count shapes))
shape (first shapes)
current-file-id (mf/use-ctx ctx/current-file-id)
libraries (mf/deref ref:swap-libraries)
libraries (mf/deref refs/files)
objects (mf/deref refs/workspace-page-objects)
^boolean
@ -522,12 +512,13 @@
{::mf/props :obj}
[{:keys [shapes swap-opened?]}]
(let [current-file-id (mf/use-ctx ctx/current-file-id)
components-v2 (mf/use-ctx ctx/components-v2)
workspace-data (deref refs/workspace-data)
libraries (deref refs/libraries)
state* (mf/use-state {:show-content true
:menu-open false})
libraries (deref refs/libraries)
current-file (get libraries current-file-id)
state* (mf/use-state
#(do {:show-content true
:menu-open false}))
state (deref state*)
open? (:show-content state)
menu-open? (:menu-open state)
@ -535,18 +526,18 @@
shapes (filter ctk/instance-head? shapes)
multi (> (count shapes) 1)
copies (filter ctk/in-component-copy? shapes)
can-swap? (and components-v2 (seq copies))
can-swap? (boolean (seq copies))
;; For when it's only one shape
shape (first shapes)
id (:id shape)
shape-name (:name shape)
component (ctf/resolve-component shape
{:id current-file-id
:data workspace-data}
current-file
libraries
{:include-deleted? true})
main-instance? (if components-v2 (ctk/main-instance? shape) true)
main-instance? (ctk/main-instance? shape)
toggle-content
(mf/use-fn #(swap! state* update :show-content not))
@ -585,7 +576,7 @@
(fn []
(swap! state* update :render inc)))
menu-entries (cmm/generate-components-menu-entries shapes components-v2)
menu-entries (cmm/generate-components-menu-entries shapes true)
show-menu? (seq menu-entries)
path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))]
@ -650,7 +641,7 @@
(when swap-opened?
[:& component-swap {:shapes copies}])
(when (and (not swap-opened?) (not multi) components-v2)
(when (and (not swap-opened?) (not multi))
[:& component-annotation {:id id :shape shape :component component :rerender-fn rerender-fn}])
(when (dbg/enabled? :display-touched)
[:div ":touched " (str (:touched shape))])])])))

View file

@ -9,8 +9,8 @@
(:require
[app.common.data :as d]
[app.main.data.exports.assets :as de]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.select :refer [select]]
@ -40,7 +40,7 @@
state (mf/deref refs/export)
in-progress? (:in-progress state)
shapes-with-exports (->> (wsh/lookup-shapes @st/state ids)
shapes-with-exports (->> (dsh/lookup-shapes @st/state ids)
(filter #(pos? (count (:exports %)))))
sname (when (seqable? exports)

View file

@ -9,6 +9,7 @@
(:require
[app.common.colors :as clr]
[app.common.data :as d]
[app.common.types.color :as ctc]
[app.common.types.shape.attrs :refer [default-color]]
[app.main.data.workspace.colors :as dc]
[app.main.store :as st]
@ -167,12 +168,7 @@
(seq fills)
[:& h/sortable-container {}
(for [[index value] (d/enumerate (:fills values []))]
[:& color-row {:color {:color (:fill-color value)
:opacity (:fill-opacity value)
:id (:fill-color-ref-id value)
:file-id (:fill-color-ref-file value)
:gradient (:fill-color-gradient value)
:image (:fill-image value)}
[:& color-row {:color (ctc/fill->color value)
:key index
:index index
:title (tr "workspace.options.fill")

View file

@ -9,9 +9,9 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.data.helpers :as dsh]
[app.main.data.workspace :as dw]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.features :as features]
[app.main.store :as st]
[app.main.ui.components.numeric-input :refer [numeric-input*]]
@ -56,7 +56,7 @@
wasm-renderer-enabled? (features/use-feature "render-wasm/v1")
shapes (->
(wsh/lookup-page-objects @st/state)
(dsh/lookup-page-objects @st/state)
(select-keys ids)
vals)

View file

@ -57,16 +57,16 @@
(or next (peek fonts)))
current))
(mf/defc font-item
(mf/defc font-item*
{::mf/wrap [mf/memo]}
[{:keys [font current? on-click style]}]
[{:keys [font is-current on-click style]}]
(let [item-ref (mf/use-ref)
on-click (mf/use-fn (mf/deps font) #(on-click font))]
(mf/use-effect
(mf/deps current?)
(mf/deps is-current)
(fn []
(when current?
(when is-current
(let [element (mf/ref-val item-ref)]
(when-not (dom/is-in-viewport? element)
(dom/scroll-into-view! element))))))
@ -76,9 +76,9 @@
:ref item-ref
:on-click on-click}
[:div {:class (stl/css-case :font-item true
:selected current?)}
:selected is-current)}
[:span {:class (stl/css :label)} (:name font)]
[:span {:class (stl/css :icon)} (when current? i/tick)]]]))
[:span {:class (stl/css :icon)} (when is-current i/tick)]]]))
(declare row-renderer)
@ -93,16 +93,21 @@
(comp (filter #(contains? backends (:backend %)))))]
(into [] xform fonts)))
(mf/defc font-selector
[{:keys [on-select on-close current-font show-recent full-size] :as props}]
(mf/defc font-selector*
[{:keys [on-select on-close current-font show-recent full-size]}]
(let [selected (mf/use-state current-font)
state (mf/use-state {:term "" :backends #{}})
state* (mf/use-state
#(do {:term "" :backends #{}}))
state (deref state*)
flist (mf/use-ref)
input (mf/use-ref)
fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
recent-fonts (mf/deref refs/workspace-recent-fonts)
fonts (mf/deref fonts/fonts)
fonts (mf/with-memo [state fonts]
(filter-fonts state fonts))
recent-fonts (mf/deref refs/recent-fonts)
full-size? (boolean (and full-size show-recent))
@ -136,7 +141,7 @@
on-filter-change
(mf/use-fn
(fn [event]
(swap! state assoc :term event)))
(swap! state* assoc :term event)))
on-select-and-close
(mf/use-fn
@ -145,9 +150,6 @@
(on-select font)
(on-close)))]
(mf/with-effect [fonts]
(st/emit! (fts/load-recent-fonts fonts)))
(mf/with-effect [fonts]
(let [key (events/listen js/document "keydown" on-key-down)]
#(events/unlistenByKey key)))
@ -176,18 +178,18 @@
[:div {:class (stl/css-case :font-selector-dropdown true :font-selector-dropdown-full-size full-size?)}
[:div {:class (stl/css :header)}
[:& search-bar {:on-change on-filter-change
:value (:term @state)
:value (:term state)
:auto-focus true
:placeholder (tr "workspace.options.search-font")}]
(when (and recent-fonts show-recent)
[:section {:class (stl/css :show-recent)}
[:p {:class (stl/css :title)} (tr "workspace.options.recent-fonts")]
(for [[idx font] (d/enumerate recent-fonts)]
[:& font-item {:key (dm/str "font-" idx)
[:> font-item* {:key (dm/str "font-" idx)
:font font
:style {}
:on-click on-select-and-close
:current? (= (:id font) (:id @selected))}])])]
:is-current (= (:id font) (:id @selected))}])])]
[:div {:class (stl/css-case :fonts-list true
:fonts-list-full-size full-size?)}
@ -211,11 +213,11 @@
style (unchecked-get props "style")
font (nth fonts index)]
(mf/html
[:& font-item {:key key
[:> font-item* {:key key
:font font
:style style
:on-click on-select
:current? (= (:id font) (:id selected))}])))
:is-current (= (:id font) (:id selected))}])))
(mf/defc font-options
{::mf/wrap-props false}
@ -228,14 +230,14 @@
fonts (mf/deref fonts/fontsdb)
font (get fonts font-id)
recent-fonts (mf/deref refs/workspace-recent-fonts)
last-font (mf/use-ref nil)
open-selector? (mf/use-state false)
change-font
(mf/use-fn
(mf/deps on-change fonts recent-fonts)
(mf/deps on-change fonts)
(fn [new-font-id]
(let [{:keys [family] :as font} (get fonts new-font-id)
{:keys [id name weight style]} (fonts/get-default-variant font)]
@ -286,7 +288,7 @@
[:*
(when @open-selector?
[:& font-selector
[:> font-selector*
{:current-font font
:on-close on-font-selector-close
:on-select on-font-select

View file

@ -20,7 +20,7 @@
[okulary.core :as l]
[rumext.v2 :as mf]))
(def lens:background-color
(def ^:private ref:background-color
(-> (l/key :background)
(l/derived refs/workspace-page)))
@ -28,7 +28,7 @@
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[]
(let [background (mf/deref lens:background-color)
(let [background (mf/deref ref:background-color)
on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %)))
on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options)))
on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))]

View file

@ -10,6 +10,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.data.common :as dcm]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
@ -27,6 +28,29 @@
[okulary.core :as l]
[rumext.v2 :as mf]))
;; FIXME: can we unify this two refs in one?
(def ^:private ref:file-with-pages
"A derived state of the current file, without data with the
exception of list of pages"
(l/derived (fn [{:keys [data] :as file}]
(-> file
(dissoc :data)
(assoc :pages (:pages data))))
refs/file
=))
(defn- make-page-ref
"Create a derived state that poins to a page identified by `page-id`
without including the page objects (mainly for avoid rerender on
each object change)"
[page-id]
(l/derived (fn [fdata]
(-> (dsh/get-page fdata page-id)
(dissoc :objects)))
refs/workspace-data
=))
;; --- Page Item
(mf/defc page-item
@ -155,17 +179,11 @@
;; --- Page Item Wrapper
(defn- make-page-ref
[page-id]
(l/derived (fn [state]
(let [page (get-in state [:workspace-data :pages-index page-id])]
(select-keys page [:id :name])))
st/state =))
(mf/defc page-item-wrapper
{::mf/wrap-props false}
[{:keys [page-id index deletable? selected? editing?]}]
(let [page-ref (mf/use-memo (mf/deps page-id) #(make-page-ref page-id))
(let [page-ref (mf/with-memo [page-id]
(make-page-ref page-id))
page (mf/deref page-ref)]
[:& page-item {:page page
:index index
@ -198,7 +216,7 @@
(mf/defc sitemap
{::mf/wrap-props false}
[{:keys [size show-pages? toggle-pages]}]
(let [file (mf/deref refs/workspace-file)
(let [file (mf/deref ref:file-with-pages)
file-id (get file :id)
project-id (get file :project-id)
@ -207,6 +225,7 @@
(fn [event]
(st/emit! (dw/create-page {:file-id file-id :project-id project-id}))
(-> event dom/get-current-target dom/blur!)))
read-only? (mf/use-ctx ctx/workspace-read-only?)
permissions (mf/use-ctx ctx/permissions)]

View file

@ -9,11 +9,11 @@
[app.common.types.shape.radius :as ctsr]
[app.common.types.token :as ctt]
[app.common.types.tokens-lib :as ctob]
[app.main.data.helpers :as dsh]
[app.main.data.workspace :as udw]
[app.main.data.workspace.colors :as wdc]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.undo :as dwu]
[app.main.store :as st]
@ -36,7 +36,8 @@
(ptk/reify ::apply-token
ptk/WatchEvent
(watch [_ state _]
(when-let [tokens (some-> (get-in state [:workspace-data :tokens-lib])
(when-let [tokens (some-> (dsh/lookup-file-data state)
(get :tokens-lib)
(ctob/get-active-themes-set-tokens))]
(->> (rx/from (sd/resolve-tokens+ tokens))
(rx/mapcat
@ -179,7 +180,7 @@
(ptk/reify ::update-layout-spacing
ptk/WatchEvent
(watch [_ state _]
(let [layout-shape-ids (->> (wsh/lookup-shapes state shape-ids)
(let [layout-shape-ids (->> (dsh/lookup-shapes state shape-ids)
(eduction
(filter :layout)
(map :id)))

View file

@ -1,17 +1,24 @@
(ns app.main.ui.workspace.tokens.token-set
(:require
[app.common.types.tokens-lib :as ctob]))
[app.common.types.tokens-lib :as ctob]
[app.main.data.helpers :as dsh]))
(defn get-workspace-tokens-lib [state]
(get-in state [:workspace-data :tokens-lib]))
(defn get-workspace-tokens-lib
[state]
(-> (dsh/lookup-file-data state)
(get :tokens-lib)))
;; Themes ----------------------------------------------------------------------
(defn get-active-theme-ids [state]
(get-in state [:workspace-data :token-active-themes] #{}))
(defn get-active-theme-ids
[state]
(-> (dsh/lookup-file-data state)
(get :token-active-themes #{})))
(defn get-temp-theme-id [state]
(get-in state [:workspace-data :token-theme-temporary-id]))
(defn get-temp-theme-id
[state]
(-> (dsh/lookup-file-data state)
(get :token-theme-temporary-id)))
(defn update-theme-id
[state]
@ -22,8 +29,11 @@
(= 1 (count active-themes)) (first active-themes)
:else temporary-theme-id)))
(defn get-workspace-token-theme [id state]
(get-in state [:workspace-data :token-themes-index id]))
(defn get-workspace-token-theme
[id state]
(-> (dsh/lookup-file-data state)
(get :token-themes-index)
(get id)))
(defn add-token-set-to-token-theme [token-set-id token-theme]
(update token-theme :sets conj token-set-id))

View file

@ -1,8 +1,8 @@
(ns app.main.ui.workspace.tokens.update
(:require
[app.common.types.token :as ctt]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu]
[app.main.ui.workspace.tokens.changes :as wtch]
[app.main.ui.workspace.tokens.style-dictionary :as wtsd]
@ -107,7 +107,7 @@
shapes-update-info))
(defn update-tokens [state resolved-tokens]
(->> (wsh/lookup-page-objects state)
(->> (dsh/lookup-page-objects state)
(collect-shapes-update-info resolved-tokens)
(actionize-shapes-update-info)))

View file

@ -74,8 +74,8 @@
objects
selected))
(mf/defc viewport-classic
[{:keys [selected wglobal wlocal layout file palete-size] :as props}]
(mf/defc viewport-classic*
[{:keys [selected wglobal wlocal layout file page palete-size]}]
(let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check
;; that the new parameter is sent
{:keys [edit-path
@ -100,13 +100,12 @@
read-only? (mf/use-ctx ctx/workspace-read-only?)
;; DEREFS
drawing (mf/deref refs/workspace-drawing)
focus (mf/deref refs/workspace-focus-selected)
page (mf/deref refs/workspace-page)
objects (get page :objects)
file-id (get file :id)
page-id (get page :id)
objects (get page :objects)
background (get page :background clr/canvas)
base-objects (ui-hooks/with-focus-objects objects focus)
@ -158,7 +157,6 @@
drawing-tool (:tool drawing)
drawing-obj (:object drawing)
selected-frames (into #{} (map :frame-id) selected-shapes)
;; Only when we have all the selected shapes in one frame
@ -302,12 +300,12 @@
:edition edition}])]]]
(when show-comments?
[:& comments/comments-layer {:vbox vbox
[:> comments/comments-layer* {:vbox vbox
:page-id page-id
:file-id file-id
:vport vport
:zoom zoom
:drawing drawing
:page-id page-id
:file-id (:id file)}])
:drawing drawing}])
(when picking-color?
[:& pixel-overlay/pixel-overlay {:vport vport
@ -568,6 +566,7 @@
[:> guides/viewport-guides*
{:zoom zoom
:vbox vbox
:guides (:guides page)
:hover-frame guide-frame
:disabled-guides disabled-guides?
:modifiers modifiers}])
@ -648,6 +647,7 @@
:modifiers modifiers
:shape frame
:view-only true}]))]
[:g.scrollbar-wrapper {:clipPath "url(#clip-handlers)"}
[:& scroll-bars/viewport-scrollbars
{:objects base-objects
@ -655,9 +655,9 @@
:vbox vbox
:bottom-padding (when palete-size (+ palete-size 8))}]]]]]))
(mf/defc viewport
(mf/defc viewport*
[props]
(let [wasm-renderer-enabled? (features/use-feature "render-wasm/v1")]
(if ^boolean wasm-renderer-enabled?
[:& viewport.wasm/viewport props]
[:& viewport-classic props])))
[:> viewport.wasm/viewport* props]
[:> viewport-classic* props])))

View file

@ -9,6 +9,7 @@
(:require
[app.common.data.macros :as dm]
[app.main.data.comments :as dcm]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.comments :as dwcm]
[app.main.refs :as refs]
[app.main.store :as st]
@ -24,9 +25,14 @@
(assoc :frame-id (dm/get-in positions [id :frame-id])))
thread))
(mf/defc comments-layer
{::mf/props :obj}
[{:keys [vbox vport zoom file-id page-id drawing] :as props}]
(def ^:private ref:thread-positions
(l/derived (fn [state]
(-> (dsh/lookup-page state)
(get :comment-thread-positions)))
st/state))
(mf/defc comments-layer*
[{:keys [vbox vport zoom drawing file-id page-id]}]
(let [vbox-x (dm/get-prop vbox :x)
vbox-y (dm/get-prop vbox :y)
vport-w (dm/get-prop vport :width)
@ -36,26 +42,26 @@
pos-y (* (- vbox-y) zoom)
profile (mf/deref refs/profile)
profiles (mf/deref refs/profiles)
local (mf/deref refs/comments-local)
positions-ref
(mf/with-memo [page-id]
;; FIXME: use lookup helpers here
(-> (l/in [:workspace-data :pages-index page-id :comment-thread-positions])
(l/derived st/state)))
positions (mf/deref ref:thread-positions)
positions (mf/deref positions-ref)
threads-map (mf/deref refs/threads-ref)
threads-map (mf/deref refs/threads)
threads-map (mf/with-memo [threads-map page-id positions]
(reduce-kv (fn [threads id thread]
(if (= (:page-id thread) page-id)
(assoc threads id (update-position positions thread))
threads))
{}
threads-map))
threads
(mf/with-memo [threads-map positions local profile]
(mf/with-memo [threads-map local profile]
(->> (vals threads-map)
(filter #(= (:page-id %) page-id))
(mapv (partial update-position positions))
(dcm/apply-filters local profile)))
viewport (assoc vport :offset-x pos-x :offset-y pos-y)
viewport
(assoc vport :offset-x pos-x :offset-y pos-y)
on-draft-cancel
(mf/use-fn #(st/emit! :interrupt))
@ -78,7 +84,6 @@
:style {:transform (dm/fmt "translate(%px, %px)" pos-x pos-y)}}
(for [item threads]
[:> cmt/comment-floating-bubble* {:thread item
:profiles profiles
:zoom zoom
:is-open (= (:id item) (:open local))
:key (:seqn item)}])
@ -86,15 +91,14 @@
(when-let [id (:open local)]
(when-let [thread (get threads-map id)]
(when (seq (dcm/apply-filters local profile [thread]))
[:> cmt/comment-floating-thread* {:thread (update-position positions thread)
:profiles profiles
[:> cmt/comment-floating-thread*
{:thread (update-position positions thread)
:viewport viewport
:zoom zoom}])))
(when-let [draft (:comment drawing)]
[:> cmt/comment-floating-thread-draft* {:draft draft
:profiles profiles
[:> cmt/comment-floating-thread-draft*
{:draft draft
:on-cancel on-draft-cancel
:on-submit on-draft-submit
:zoom zoom}])]]]))

View file

@ -23,7 +23,6 @@
[app.main.ui.formats :as fmt]
[app.main.ui.workspace.viewport.rulers :as rulers]
[app.util.dom :as dom]
[okulary.core :as l]
[rumext.v2 :as mf]))
(def guide-width 1)
@ -448,16 +447,12 @@
:is-hover true
:hover-frame frame}])]))
(def ^:private lens:workspace-guides
(-> (l/key :guides)
(l/derived refs/workspace-page)))
(mf/defc viewport-guides*
{::mf/wrap [mf/memo]
::mf/props :obj}
[{:keys [zoom vbox hover-frame disabled-guides modifiers]}]
(let [guides (mf/deref lens:workspace-guides)
guides (mf/with-memo [guides vbox]
[{:keys [zoom vbox hover-frame disabled-guides modifiers guides]}]
(let [guides
(mf/with-memo [guides vbox]
(->> (vals guides)
(filter (partial guide-inside-vbox? zoom vbox))))

View file

@ -74,8 +74,8 @@
objects
selected))
(mf/defc viewport
[{:keys [selected wglobal wlocal layout file palete-size] :as props}]
(mf/defc viewport*
[{:keys [selected wglobal wlocal layout file page palete-size]}]
(let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check
;; that the new parameter is sent
{:keys [edit-path
@ -102,7 +102,6 @@
drawing (mf/deref refs/workspace-drawing)
focus (mf/deref refs/workspace-focus-selected)
page (mf/deref refs/workspace-page)
objects (get page :objects)
page-id (get page :id)
background (get page :background clr/canvas)
@ -341,12 +340,11 @@
:edition edition}])]]]
(when show-comments?
[:& comments/comments-layer {:vbox vbox
[:> comments/comments-layer* {:vbox vbox
:page-id page-id
:vport vport
:zoom zoom
:drawing drawing
:page-id page-id
:file-id (:id file)}])
:drawing drawing}])
(when picking-color?
[:& pixel-overlay/pixel-overlay {:vport vport
@ -571,6 +569,7 @@
[:> guides/viewport-guides*
{:zoom zoom
:vbox vbox
:guides (:guides page)
:hover-frame guide-frame
:disabled-guides disabled-guides?
:modifiers modifiers}])

View file

@ -8,7 +8,6 @@
"RPC for plugins runtime."
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.changes-builder :as cb]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
@ -19,6 +18,7 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as ch]
[app.main.data.common :as dcm]
[app.main.data.helpers :as dsh]
[app.main.data.workspace :as dw]
[app.main.data.workspace.bool :as dwb]
[app.main.data.workspace.colors :as dwc]
@ -48,15 +48,17 @@
;;
(defn create-shape
[plugin-id type]
(let [page-id (:current-page-id @st/state)
page (dm/get-in @st/state [:workspace-data :pages-index page-id])
(let [page (dsh/lookup-page @st/state)
shape (cts/setup-shape {:type type
:x 0 :y 0 :width 100 :height 100})
:x 0 :y 0
:width 100
:height 100})
changes
(-> (cb/empty-changes)
(cb/with-page page)
(cb/with-objects (:objects page))
(cb/add-object shape))]
(st/emit! (ch/commit-changes changes))
(shape/shape-proxy plugin-id (:id shape))))
@ -160,7 +162,7 @@
(map #(obj/get % "$id"))
(mapcat #(cfh/get-children-with-self objects %)))
file-id (:current-file-id @st/state)
shared-libs (:libraries @st/state)]
shared-libs (:files @st/state)]
(->> (ctc/extract-all-colors shapes file-id shared-libs)
(group-by :attrs)
@ -182,7 +184,7 @@
:else
(let [file-id (:current-file-id @st/state)
shared-libs (:libraries @st/state)
shared-libs (:files @st/state)
objects (u/locate-objects)
shapes
(->> shapes
@ -295,8 +297,7 @@
:createPath
(fn []
(let [page-id (:current-page-id @st/state)
page (dm/get-in @st/state [:workspace-data :pages-index page-id])
(let [page (dsh/lookup-page @st/state)
shape (cts/setup-shape
{:type :path
:content [{:command :move-to :params {:x 0 :y 0}}
@ -306,6 +307,7 @@
(cb/with-page page)
(cb/with-objects (:objects page))
(cb/add-object shape))]
(st/emit! (ch/commit-changes changes))
(shape/shape-proxy plugin-id (:id shape))))
@ -316,9 +318,7 @@
(u/display-not-valid :createText text)
:else
(let [file-id (:current-file-id @st/state)
page-id (:current-page-id @st/state)
page (dm/get-in @st/state [:workspace-data :pages-index page-id])
(let [page (dsh/lookup-page @st/state)
shape (-> (cts/setup-shape {:type :text :x 0 :y 0 :grow-type :auto-width})
(txt/change-text text)
(assoc :position-data nil))
@ -327,8 +327,9 @@
(cb/with-page page)
(cb/with-objects (:objects page))
(cb/add-object shape))]
(st/emit! (ch/commit-changes changes))
(shape/shape-proxy plugin-id file-id page-id (:id shape)))))
(shape/shape-proxy plugin-id (:id shape)))))
:createShapeFromSvg
(fn [svg-string]

View file

@ -9,6 +9,7 @@
[app.common.geom.point :as gpt]
[app.common.spec :as us]
[app.main.data.comments :as dc]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.comments :as dwc]
[app.main.repo :as rp]
[app.main.store :as st]
@ -25,7 +26,7 @@
(obj/type-of? p "CommentProxy"))
(defn comment-proxy
[plugin-id file-id page-id thread-id users data]
[plugin-id file-id page-id thread-id data]
(let [data* (atom data)]
(obj/reify {:name "CommentProxy"}
;; Private properties
@ -36,9 +37,15 @@
:$id {:enumerable false :get (fn [] (:id data))}
;; Public properties
;; FIXME: inconsistent with comment-thread: owner
:user
{:get
(fn [] (user/user-proxy plugin-id (get users (:owner-id data))))}
{:get #(->> (dc/get-owner data)
(user/user-proxy plugin-id))}
:owner
{:get #(->> (dc/get-owner data)
(user/user-proxy plugin-id))}
:date
{:get
@ -86,20 +93,22 @@
(obj/type-of? p "CommentThreadProxy"))
(defn comment-thread-proxy
[plugin-id file-id page-id users data]
[plugin-id file-id page-id data]
(let [data* (atom data)]
(obj/reify {:name "CommentThreadProxy"}
:$plugin {:enumerable false :get (fn [] plugin-id)}
:$file {:enumerable false :get (fn [] file-id)}
:$page {:enumerable false :get (fn [] page-id)}
:$id {:enumerable false :get (fn [] (:id data))}
:$users {:enumerable false :get (fn [] users)}
:page {:enumerable false :get #(u/locate-page file-id page-id)}
:seqNumber {:get #(:seqn data)}
:owner {:get #(user/user-proxy plugin-id (get users (:owner-id data)))}
:board {:get #(shape/shape-proxy plugin-id file-id page-id (:frame-id data))}
:owner
{:get #(->> (dc/get-owner data)
(user/user-proxy plugin-id))}
:position
{:get
(fn []
@ -152,7 +161,7 @@
(fn [comments]
(resolve
(format/format-array
#(comment-proxy plugin-id file-id page-id (:id data) users %) comments)))
#(comment-proxy plugin-id file-id page-id (:id data) %) comments)))
reject))))))
:reply
@ -168,12 +177,12 @@
(js/Promise.
(fn [resolve reject]
(->> (rp/cmd! :create-comment {:thread-id (:id data) :content content})
(rx/subs! #(resolve (comment-proxy plugin-id file-id page-id (:id data) users %)) reject))))))
(rx/subs! #(resolve (comment-proxy plugin-id file-id page-id (:id data) %)) reject))))))
:remove
(fn []
(let [profile (:profile @st/state)
owner (get users (:owner-id data))]
owner (dsh/lookup-profile @st/state (:owner-id data))]
(cond
(not (r/check-permission plugin-id "comment:write"))
(u/display-not-valid :remove "Plugin doesn't have 'comment:write' permission")

View file

@ -7,7 +7,7 @@
(ns app.plugins.events
(:require
[app.common.data.macros :as dm]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[app.main.store :as st]
[app.plugins.file :as file]
[app.plugins.page :as page]
@ -63,8 +63,8 @@
(defmethod handle-state-change "shapechange"
[_ plugin-id old-val new-val props]
(if-let [shape-id (-> (obj/get props "shapeId") parser/parse-id)]
(let [old-shape (wsh/lookup-shape old-val shape-id)
new-shape (wsh/lookup-shape new-val shape-id)
(let [old-shape (dsh/lookup-shape old-val shape-id)
new-shape (dsh/lookup-shape new-val shape-id)
file-id (:current-file-id new-val)
page-id (:current-page-id new-val)]

View file

@ -929,7 +929,7 @@
:connected
{:get
(fn []
(let [libraries (get @st/state :libraries)]
(let [libraries (get @st/state :files)]
(apply array (->> libraries keys (map (partial library-proxy plugin-id))))))}
:availableLibraries
@ -937,7 +937,7 @@
(let [team-id (:current-team-id @st/state)]
(js/Promise.
(fn [resolve reject]
(let [current-libs (into #{} (map first) (get @st/state :libraries))]
(let [current-libs (into #{} (map first) (get @st/state :files))]
(->> (rp/cmd! :get-team-shared-files {:team-id team-id})
(rx/map (fn [result]
(->> result

View file

@ -369,11 +369,7 @@
:content content}
(fn [data]
(->> (rp/cmd! :get-team-users {:file-id file-id})
(rx/subs!
(fn [users]
(let [users (d/index-by :id users)]
(resolve (pc/comment-thread-proxy plugin-id file-id id users data)))))))
(resolve (pc/comment-thread-proxy plugin-id file-id id data)))
false))))))))
:removeCommentThread
@ -396,7 +392,7 @@
(fn [criteria]
(let [only-yours (boolean (obj/get criteria "onlyYours" false))
show-resolved (boolean (obj/get criteria "showResolved" true))
user-id (-> @st/state :profile :id)]
user-id (:profile-id @st/state)]
(js/Promise.
(fn [resolve reject]
(cond
@ -406,14 +402,11 @@
(reject "Plugin doesn't have 'comment:read' permission"))
:else
(->> (rx/zip (rp/cmd! :get-team-users {:file-id file-id})
(rp/cmd! :get-comment-threads {:file-id file-id}))
(rx/take 1)
(->> (rp/cmd! :get-comment-threads {:file-id file-id})
(rx/subs!
(fn [[users comments]]
(let [users (d/index-by :id users)
comments
(cond->> comments
(fn [threads]
(let [threads
(cond->> threads
(not show-resolved)
(filter (comp not :is-resolved))
@ -421,5 +414,5 @@
(filter #(contains? (:participants %) user-id)))]
(resolve
(format/format-array
#(pc/comment-thread-proxy plugin-id file-id id users %) comments))))
#(pc/comment-thread-proxy plugin-id file-id id %) threads))))
reject)))))))))

View file

@ -11,21 +11,20 @@
[app.common.data.macros :as dm]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.main.data.helpers :as dsh]
[app.main.store :as st]
[app.util.object :as obj]))
(defn locate-file
[id]
(assert (uuid? id) "File not valid uuid")
(if (= id (:current-file-id @st/state))
(-> (:workspace-file @st/state)
(assoc :data (:workspace-data @st/state)))
(dm/get-in @st/state [:libraries id])))
(dsh/lookup-file @st/state id))
(defn locate-page
[file-id id]
(assert (uuid? id) "Page not valid uuid")
(dm/get-in (locate-file file-id) [:data :pages-index id]))
(-> (dsh/lookup-file-data @st/state file-id)
(dsh/get-page id)))
(defn locate-objects
([]
@ -62,13 +61,15 @@
(let [{:keys [profile-id]} (locate-presence session-id)]
(dm/get-in @st/state [:users profile-id])))
;; FIXME: the impl looks strange: objects is passed by parameters but
;; then the rest of the file is looked up directly from state.... (?)
(defn locate-component
[objects shape]
(let [current-file-id (:current-file-id @st/state)
workspace-data (:workspace-data @st/state)
libraries (:libraries @st/state)
(let [state (deref st/state)
file (dsh/lookup-file state)
libraries (dsh/lookup-libraries state)
root (ctn/get-instance-root objects shape)]
[root (ctf/resolve-component root {:id current-file-id :data workspace-data} libraries {:include-deleted? true})]))
[root (ctf/resolve-component root file libraries {:include-deleted? true})]))
(defn proxy->file
[proxy]
@ -168,8 +169,11 @@
(defn get-state
([self attr]
(let [id (get-data self :id)
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))]
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr])))
page-id (or (get-data self :page-id)
(:current-page-id @st/state))]
(-> (dsh/lookup-page-objects @st/state page-id)
(dm/get-in [:objects id attr]))))
([self attr mapfn]
(-> (get-state self attr)
(mapfn))))

View file

@ -18,6 +18,7 @@
[app.main.data.changes :as dwc]
[app.main.data.common :as dcm]
[app.main.data.dashboard.shortcuts]
[app.main.data.helpers :as dsh]
[app.main.data.preview :as dp]
[app.main.data.viewer.shortcuts]
[app.main.data.workspace :as dw]
@ -149,8 +150,10 @@
nil)
(defn ^:export dump-data []
(logjs "workspace-data" (get @st/state :workspace-data))
nil)
(let [fdata (-> (dsh/lookup-file @st/state)
(get :data))]
(logjs "file-data" fdata)
nil))
(defn ^:export dump-buffer []
(logjs "last-events" @st/last-events)
@ -165,8 +168,7 @@
(defn dump-objects'
[state]
(let [page-id (get state :current-page-id)
objects (get-in state [:workspace-data :pages-index page-id :objects])]
(let [objects (dsh/lookup-page-objects state)]
(logjs "objects" objects)
nil))
@ -174,33 +176,25 @@
[]
(dump-objects' @st/state))
(defn dump-object'
(defn get-object
[state name]
(let [page-id (get state :current-page-id)
objects (get-in state [:workspace-data :pages-index page-id :objects])
(let [objects (dsh/lookup-page-objects state)
result (or (d/seek (fn [shape] (= name (:name shape))) (vals objects))
(get objects (uuid/uuid name)))]
#_(logjs name result)
result
#_nil))
result))
(defn ^:export dump-object
[name]
(dump-object' @st/state name))
(get-object @st/state name))
(defn dump-selected'
(defn get-selected
[state]
(let [page-id (get state :current-page-id)
objects (get-in state [:workspace-data :pages-index page-id :objects])
selected (get-in state [:workspace-local :selected])
result (->> selected (map (d/getf objects)))]
(logjs "selected" result)
nil))
(dsh/lookup-selected state))
(defn ^:export dump-selected
[]
(dump-selected' @st/state))
(logjs "selected" (get-selected @st/state))
nil)
(defn ^:export preview-selected
[]
@ -208,26 +202,20 @@
(defn ^:export parent
[]
(let [state @st/state
page-id (get state :current-page-id)
objects (get-in state [:workspace-data :pages-index page-id :objects])
selected (first (get-in state [:workspace-local :selected]))
parent-id (get-in objects [selected :parent-id])
parent (get objects parent-id)]
(when parent
(prn (str (:name parent) " - " (:id parent))))
(let [objects (dsh/lookup-page-objects @st/state)
selected-id (first (dsh/get-selected-ids @st/state))
parent-id (dm/get-in objects [selected-id :parent-id])]
(when-let [parent (get objects parent-id)]
(js/console.log (str (:name parent) " - " (:id parent))))
nil))
(defn ^:export frame
[]
(let [state @st/state
page-id (get state :current-page-id)
objects (get-in state [:workspace-data :pages-index page-id :objects])
selected (first (get-in state [:workspace-local :selected]))
frame-id (get-in objects [selected :frame-id])
frame (get objects frame-id)]
(when frame
(prn (str (:name frame) " - " (:id frame))))
(let [objects (dsh/lookup-page-objects @st/state)
selected-id (first (dsh/get-selected-ids @st/state))
frame-id (dm/get-in objects [selected-id :frame-id])]
(when-let [frame (get objects frame-id)]
(js/console.log (str (:name frame) " - " (:id frame))))
nil))
(defn ^:export select-by-object-id
@ -246,9 +234,8 @@
([state show-ids show-touched] (dump-tree' state show-ids show-touched false))
([state show-ids show-touched show-modified]
(let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file)
:data (get state :workspace-data))
libraries (get state :libraries)]
file (dsh/lookup-file state)
libraries (get state :files)]
(ctf/dump-tree file page-id libraries {:show-ids show-ids
:show-touched show-touched
:show-modified show-modified}))))
@ -264,14 +251,11 @@
([state shape-id show-ids show-touched] (dump-subtree' state shape-id show-ids show-touched false))
([state shape-id show-ids show-touched show-modified]
(let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file)
:data (get state :workspace-data))
libraries (get state :libraries)
file (dsh/lookup-file state)
libraries (get state :files)
shape-id (if (some? shape-id)
(uuid/uuid shape-id)
(let [objects (get-in state [:workspace-data :pages-index page-id :objects])
selected (get-in state [:workspace-local :selected])]
(->> selected (map (d/getf objects)) first :id)))]
(first (dsh/lookup-selected state)))]
(if (some? shape-id)
(ctf/dump-subtree file page-id shape-id libraries {:show-ids show-ids
:show-touched show-touched
@ -363,10 +347,10 @@
(defn ^:export dump-modifiers
[]
(let [page-id (get @st/state :current-page-id)
objects (get-in @st/state [:workspace-data :pages-index page-id :objects])]
(.log js/console (modif->js (:workspace-modifiers @st/state) objects)))
nil)
(let [objects (dsh/lookup-page-objects @st/state)
modifiers (:workspace-modifiers @st/state)]
(js/console.log (modif->js modifiers objects))
nil))
(defn ^:export set-workspace-read-only
[read-only?]
@ -381,10 +365,8 @@
(defn ^:export validate
([] (validate nil))
([shape-id]
(let [file (assoc (get @st/state :workspace-file)
:data (get @st/state :workspace-data))
libraries (get @st/state :libraries)]
(let [file (dsh/lookup-file @st/state)
libraries (get @st/state :files)]
(try
(->> (if-let [shape-id (some-> shape-id parse-uuid)]
(let [page (dm/get-in file [:data :pages-index (get @st/state :current-page-id)])]
@ -398,9 +380,8 @@
(defn ^:export validate-schema
[]
(try
(-> (get @st/state :workspace-file)
(assoc :data (get @st/state :workspace-data))
(cfv/validate-file-schema!))
(let [file (dsh/lookup-file @st/state)]
(cfv/validate-file-schema! file))
(catch :default cause
(errors/print-error! cause))))
@ -413,11 +394,8 @@
(let [features (features/get-team-enabled-features state)
sid (:session-id state)
file (get state :workspace-file)
fdata (get state :workspace-data)
file (assoc file :data fdata)
libs (get state :libraries)
file (dsh/lookup-file state)
libs (get state :files)
errors (cfv/validate-file file libs)
_ (l/dbg :hint "repair current file" :errors (count errors))

View file

@ -9,6 +9,7 @@
[app.common.test-helpers.files :as cthf]
[app.common.test-helpers.ids-map :as cthi]
[app.common.test-helpers.shapes :as cths]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.colors :as dc]
[app.main.data.workspace.shapes :as dwsh]
[cljs.test :as t :include-macros true]
@ -34,11 +35,8 @@
store done events
(fn [new-state]
(let [;; ==== Get
shape1' (get-in new-state [:workspace-data
:pages-index
(cthi/id :page1)
:objects
(cthi/id :shape1)])
objects (dsh/lookup-page-objects new-state)
shape1' (get objects (cthi/id :shape1))
fills' (:fills shape1')
fill' (first fills')]
@ -68,13 +66,9 @@
store done events
(fn [new-state]
(let [;; ==== Get
shape1' (get-in new-state [:workspace-data
:pages-index
(cthi/id :page1)
:objects
(cthi/id :shape1)])
stroke' (-> (:strokes shape1')
first)]
objects (dsh/lookup-page-objects new-state)
shape1' (get objects (cthi/id :shape1))
stroke' (first (:strokes shape1'))]
;; ==== Check
;; (println stroke')

View file

@ -9,7 +9,7 @@
[app.common.files.helpers :as cfh]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.helpers :as dsh]
[cljs.test :as t :include-macros true]
[frontend-tests.helpers.pages :as thp]))
@ -111,7 +111,7 @@
root-inst (ctn/get-shape page root-inst-id)
main-instance? (:main-instance root-inst)
libs (wsh/get-libraries state)
libs (dsh/lookup-libraries state)
component (ctf/get-component libs (:component-file root-inst) (:component-id root-inst))
library (ctf/get-component-library libs root-inst)
@ -151,7 +151,7 @@
(let [page (thp/current-page state)
root-inst (ctn/get-shape page root-inst-id)
libs (wsh/get-libraries state)
libs (dsh/lookup-libraries state)
component (ctf/get-component libs (:component-file root-inst) (:component-id root-inst))
library (ctf/get-component-library libs root-inst)
@ -166,7 +166,7 @@
(defn resolve-component
"Get the component with the given id and all its shapes."
[state component-file component-id]
(let [libs (wsh/get-libraries state)
(let [libs (dsh/lookup-libraries state)
component (ctf/get-component libs component-file component-id)
library (ctf/get-component-library libs component)
shapes-main (ctf/get-component-shapes (:data library) component)]

View file

@ -20,9 +20,9 @@
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.groups :as dwg]
[app.main.data.workspace.layout :as layout]
[app.main.data.workspace.state-helpers :as wsh]))
[app.main.data.workspace.layout :as layout]))
;; ---- Helpers to manage pages and objects
@ -33,12 +33,15 @@
:current-page-id nil
:workspace-layout layout/default-layout
:workspace-global layout/default-global
:workspace-data {:id current-file-id
:files
{current-file-id
{:id current-file-id
:data {:id current-file-id
:options {:components-v2 true}
:components {}
:pages []
:pages-index {}}
:workspace-libraries {}
:pages-index {}}}}
:features-team #{"components/v2"}})
(def ^:private idmap (atom {}))
@ -48,8 +51,9 @@
(defn current-page
[state]
(let [page-id (:current-page-id state)]
(get-in state [:workspace-data :pages-index page-id])))
(let [page-id (:current-page-id state)
file-id (:current-file-id state)]
(get-in state [:files file-id :data :pages-index page-id])))
(defn id
[label]
@ -65,18 +69,20 @@
(let [page (current-page state)]
(cfh/get-children (:objects page) (id label))))
(defn apply-changes
[state changes]
(let [file-id (:current-file-id state)]
(update-in state [:files file-id :data] cp/process-changes changes)))
(defn sample-page
([state] (sample-page state {}))
([state {:keys [id name] :as props
:or {id (uuid/next)
name "page1"}}]
(swap! idmap assoc :page id)
(-> state
(assoc :current-page-id id)
(update :workspace-data
cp/process-changes
[{:type :add-page
(apply-changes [{:type :add-page
:id id
:name name}]))))
@ -87,8 +93,7 @@
frame (cfh/get-frame (:objects page))
shape (cts/setup-shape (merge {:type type :x 0 :y 0 :width 1 :height 1} props))]
(swap! idmap assoc label (:id shape))
(update state :workspace-data
cp/process-changes
(apply-changes state
[{:type :add-obj
:id (:id shape)
:page-id (:id page)
@ -106,8 +111,7 @@
(dwg/prepare-create-group (pcb/empty-changes) nil (:objects page) (:id page) shapes prefix true)]
(swap! idmap assoc label (:id group))
(update state :workspace-data
cp/process-changes (:redo-changes changes)))))))
(apply-changes state (:redo-changes changes)))))))
(defn frame-shapes
([state label ids] (frame-shapes state label ids "Board"))
@ -128,13 +132,12 @@
true)]
(swap! idmap assoc label (:id frame))
(update state :workspace-data
cp/process-changes (:redo-changes changes)))))))
(apply-changes state (:redo-changes changes)))))))
(defn make-component
[state instance-label component-label shape-ids]
(let [page (current-page state)
objects (wsh/lookup-page-objects state (:id page))
objects (dsh/lookup-page-objects state (:id page))
shapes (dwg/shapes-for-grouping objects shape-ids)
[group component-id changes]
@ -149,15 +152,14 @@
(swap! idmap assoc instance-label (:id group)
component-label component-id)
(update state :workspace-data
cp/process-changes (:redo-changes changes))))
(apply-changes state (:redo-changes changes))))
(defn instantiate-component
([state label component-id]
(instantiate-component state label component-id current-file-id))
([state label component-id file-id]
(let [page (current-page state)
libraries (wsh/get-libraries state)
libraries (dsh/lookup-libraries state)
objects (:objects page)
changes (-> (pcb/empty-changes nil (:id page))
@ -173,26 +175,27 @@
libraries)]
(swap! idmap assoc label (:id new-shape))
(update state :workspace-data
cp/process-changes (:redo-changes changes)))))
(apply-changes state (:redo-changes changes)))))
(defn move-to-library
[state label name]
(let [library-id (uuid/next)
data (get state :workspace-data)]
file-id (:current-file-id state)
data (get-in state [:files file-id :data])]
(swap! idmap assoc label library-id)
(-> state
(update :workspace-libraries
assoc library-id {:id library-id
(update :files assoc library-id
{:id library-id
:name name
:data {:id library-id
:options (:options data)
:pages (:pages data)
:pages-index (:pages-index data)
:components (:components data)}})
(update :workspace-data
assoc :components {} :pages [] :pages-index {}))))
(update-in [:files file-id :data] assoc
:components {}
:pages []
:pages-index {}))))
(defn simulate-copy-shape
[selected objects libraries page file features version]

View file

@ -18,8 +18,6 @@
:workspace-global layout/default-global
:current-file-id nil
:current-page-id nil
:workspace-data nil
:workspace-libraries {}
:features-team #{"components/v2"}})
(defn- on-error
@ -34,8 +32,7 @@
(assoc :current-file-id (:id file)
:current-page-id (cthf/current-page-id file)
:permissions {:can-edit true}
:workspace-file (dissoc file :data)
:workspace-data (:data file)))
:files {(:id file) file}))
store (ptk/store {:state state :on-error on-error})]
store))
@ -64,7 +61,7 @@
(ptk/emit! store :the/end))))
(defn get-file-from-store
[store]
(-> (:workspace-file store)
(assoc :data (:workspace-data store))))
(defn get-file-from-state
[state]
(let [file-id (:current-file-id state)]
(get-in state [:files file-id])))

Some files were not shown because too many files have changed in this diff Show more