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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,6 +12,7 @@
[app.common.logging :as log] [app.common.logging :as log]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.helpers :as dsh]
[app.main.features :as features] [app.main.features :as features]
[app.main.worker :as uw] [app.main.worker :as uw]
[app.util.time :as dt] [app.util.time :as dt]
@ -76,32 +77,30 @@
(ptk/reify ::apply-changes-localy (ptk/reify ::apply-changes-localy
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [current-file-id (get state :current-file-id) (let [undo-changes
path (if (= file-id current-file-id) (if pending
[:workspace-data] (->> pending
[:libraries file-id :data]) (map :undo-changes)
(reverse)
(mapcat identity)
(vec))
nil)
undo-changes (if pending redo-changes
(->> pending (if pending
(map :undo-changes) (into redo-changes
(reverse) (mapcat :redo-changes)
(mapcat identity) pending)
(vec)) redo-changes)
nil)
redo-changes (if pending apply-changes
(into redo-changes (fn [fdata]
(mapcat :redo-changes) (let [fdata (cpc/process-changes fdata undo-changes false)
pending) fdata (cpc/process-changes fdata redo-changes false)
redo-changes)] pids (into #{} xf:map-page-id redo-changes)]
(reduce #(ctst/update-object-indices %1 %2) fdata pids)))]
(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)
pids (into #{} xf:map-page-id redo-changes)]
(reduce #(ctst/update-object-indices %1 %2) file pids))))))))
(update-in state [:files file-id :data] apply-changes)))))
(defn commit (defn commit
"Create a commit event instance" "Create a commit event instance"
@ -156,17 +155,11 @@
(defn- resolve-file-revn (defn- resolve-file-revn
[state file-id] [state file-id]
(let [file (:workspace-file state)] (:revn (dsh/lookup-file state file-id)))
(if (= (:id file) file-id)
(:revn file)
(dm/get-in state [:libraries file-id :revn]))))
(defn- resolve-file-vern (defn- resolve-file-vern
[state file-id] [state file-id]
(let [file (:workspace-file state)] (:vern (dsh/lookup-file state file-id)))
(if (= (:id file) file-id)
(:vern file)
(dm/get-in state [:libraries file-id :vern]))))
(defn commit-changes (defn commit-changes
"Schedules a list of changes to execute now, and add the corresponding undo changes to "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.types.shape-tree :as ctst]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.event :as ev] [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] [app.main.repo :as rp]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -25,8 +26,10 @@
[:file-id ::sm/uuid] [:file-id ::sm/uuid]
[:project-id ::sm/uuid] [:project-id ::sm/uuid]
[:owner-id ::sm/uuid] [:owner-id ::sm/uuid]
[:page-name {:optional true} :string] [:owner-fullname {:optional true} ::sm/text]
[:file-name :string] [:owner-email {:optional true} ::sm/email]
[:page-name {:optional true} ::sm/text]
[:file-name ::sm/text]
[:seqn :int] [:seqn :int]
[:content :string] [:content :string]
[:participants ::sm/set-of-uuid] [:participants ::sm/set-of-uuid]
@ -40,7 +43,10 @@
[:map {:title "Comment"} [:map {:title "Comment"}
[:id ::sm/uuid] [:id ::sm/uuid]
[:thread-id ::sm/uuid] [:thread-id ::sm/uuid]
[:file-id ::sm/uuid]
[:owner-id ::sm/uuid] [:owner-id ::sm/uuid]
[:owner-fullname {:optional true} ::sm/text]
[:owner-email {:optional true} ::sm/email]
[:created-at ::sm/inst] [:created-at ::sm/inst]
[:modified-at ::sm/inst] [:modified-at ::sm/inst]
[:content :string]]) [:content :string]])
@ -75,10 +81,11 @@
(ptk/reify ::created-thread-on-workspace (ptk/reify ::created-thread-on-workspace
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (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 (-> state
(update :comment-threads assoc id (dissoc thread :comment)) (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? (cond-> open?
(update :comments-local assoc :open id)) (update :comments-local assoc :open id))
(update :comments-local assoc :options nil) (update :comments-local assoc :options nil)
@ -94,8 +101,6 @@
:id id :id id
:content-size (count (:content comment))})))))) :content-size (count (:content comment))}))))))
(def ^:private (def ^:private
schema:create-thread-on-workspace schema:create-thread-on-workspace
[:map {:title "created-thread-on-workspace"} [:map {:title "created-thread-on-workspace"}
@ -114,7 +119,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [page-id (:current-page-id 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)) frame-id (ctst/get-frame-id-by-position objects (:position params))
params (-> params params (-> params
(update-mentions) (update-mentions)
@ -263,7 +268,7 @@
(rx/of (refresh-comment-thread thread))))))) (rx/of (refresh-comment-thread thread)))))))
(defn update-comment (defn update-comment
[{:keys [id content thread-id] :as comment}] [{:keys [id content thread-id file-id] :as comment}]
(dm/assert! (dm/assert!
"expected valid comment" "expected valid comment"
(check-comment! comment)) (check-comment! comment))
@ -277,15 +282,13 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (d/update-in-when state [:comments thread-id id] assoc :content content))
(d/update-in-when [:comments thread-id id] assoc :content content)))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [file-id (:current-file-id state) (let [share-id (-> state :viewer-local :share-id)
share-id (-> state :viewer-local :share-id) params {:id id :content content :share-id share-id}
params (-> {:id id :content content :share-id share-id} params (update-mentions params)]
(update-mentions))]
(->> (rp/cmd! :update-comment params) (->> (rp/cmd! :update-comment params)
(rx/catch #(rx/throw {:type :comment-error})) (rx/catch #(rx/throw {:type :comment-error}))
(rx/map #(retrieve-comment-threads file-id))))))) (rx/map #(retrieve-comment-threads file-id)))))))
@ -299,11 +302,10 @@
(ptk/reify ::delete-comment-thread-on-workspace (ptk/reify ::delete-comment-thread-on-workspace
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [page-id (:current-page-id state)] (-> state
(-> state (dsh/update-page #(update % :comment-thread-positions dissoc id))
(update-in [:workspace-data :pages-index page-id :comment-thread-positions] dissoc id) (update :comments dissoc id)
(update :comments dissoc id) (update :comment-threads dissoc id)))
(update :comment-threads dissoc id))))
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
@ -380,35 +382,37 @@
(rx/map #(partial fetched %)) (rx/map #(partial fetched %))
(rx/catch #(rx/throw {:type :comment-error})))))))) (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 (defn retrieve-comment-threads
[file-id] [file-id]
(dm/assert! (uuid? file-id)) (ptk/reify ::retrieve-comment-threads
(letfn [(set-comment-threds [state comment-thread] ptk/WatchEvent
(let [path [:workspace-data :pages-index (:page-id comment-thread) :comment-thread-positions (:id comment-thread)] (watch [_ state _]
thread-position (get-in state path)] (let [share-id (-> state :viewer-local :share-id)]
(cond-> state (rx/merge
(nil? thread-position) (->> (rp/cmd! :get-comment-threads {:file-id file-id :share-id share-id})
(-> (rx/map comment-threads-fetched))
(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 ;; Refresh team members
ptk/WatchEvent (rx/of (dtm/fetch-members)))))))
(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}))))))))
(defn retrieve-comments (defn retrieve-comments
[thread-id] [thread-id]
@ -423,6 +427,8 @@
(rx/map #(partial fetched %)) (rx/map #(partial fetched %))
(rx/catch #(rx/throw {:type :comment-error})))))))) (rx/catch #(rx/throw {:type :comment-error}))))))))
;; FIXME: revisit
(defn retrieve-unread-comment-threads (defn retrieve-unread-comment-threads
"A event used mainly in dashboard for retrieve all unread threads of a team." "A event used mainly in dashboard for retrieve all unread threads of a team."
[team-id] [team-id]
@ -544,6 +550,13 @@
;; Helpers ;; 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 (defn group-threads-by-page
[threads] [threads]
(letfn [(group-by-page [result thread] (letfn [(group-by-page [result thread]
@ -621,7 +634,7 @@
(ptk/reify ::detach-comment-thread (ptk/reify ::detach-comment-thread
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (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]))) is-frame? (fn [id] (= :frame (get-in objects [id :type])))
frame-ids? (into #{} (filter is-frame?) ids)] frame-ids? (into #{} (filter is-frame?) ids)]
@ -635,7 +648,7 @@
(defn fetch-profiles (defn fetch-profiles
"Fetch or refresh all profile data for comments of the current file" "Fetch or refresh all profile data for comments of the current file"
[] []
(ptk/reify ::fetch-comments-profiles (ptk/reify ::fetch-profiles
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [file-id (:current-file-id state) (let [file-id (:current-file-id state)

View file

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

View file

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

View file

@ -327,27 +327,23 @@
;; Workspace related events ;; 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 (defn add-recent-font
[font] [font]
(ptk/reify ::add-recent-font (ptk/reify ::add-recent-font
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [recent-fonts (get-in state [:workspace-data :recent-fonts]) (let [file-id (:current-file-id state)]
most-recent-fonts (into [font] (comp (remove #(= font %)) (take 3)) recent-fonts)] (update state :recent-fonts update-recent-font file-id font)))
(assoc-in state [:workspace-data :recent-fonts] most-recent-fonts)))
ptk/EffectEvent ptk/EffectEvent
(effect [_ state _] (effect [_ state _]
(let [most-recent-fonts (get-in state [:workspace-data :recent-fonts])] (let [recent-fonts (:recent-fonts state)]
;; FIXME: this should be prefixed by team (swap! storage/user assoc :recent-fonts recent-fonts)))))
(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)))))

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

View file

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

View file

@ -330,19 +330,6 @@
(rx/map (constantly (refresh-profile))) (rx/map (constantly (refresh-profile)))
(rx/catch on-error)))))) (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 (defn fetch-file-comments-users
[{:keys [team-id]}] [{:keys [team-id]}]
(dm/assert! (uuid? team-id)) (dm/assert! (uuid? team-id))

View file

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

View file

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

View file

@ -16,17 +16,17 @@
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.changes :as dch] [app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[cuerdas.core :as str] [cuerdas.core :as str]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
(defn selected-shapes-idx (defn selected-shapes-idx
[state] [state]
(let [objects (wsh/lookup-page-objects state)] (let [objects (dsh/lookup-page-objects state)]
(->> (wsh/lookup-selected state) (->> (dsh/lookup-selected state)
(cph/clean-loops objects)))) (cph/clean-loops objects))))
(defn create-bool-data (defn create-bool-data
@ -91,9 +91,9 @@
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id 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) 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)) (cph/clean-loops objects))
ordered-indexes (cph/order-by-indexed-shapes objects ids) ordered-indexes (cph/order-by-indexed-shapes objects ids)
shapes (->> ordered-indexes shapes (->> ordered-indexes
@ -121,7 +121,7 @@
(ptk/reify ::group-to-bool (ptk/reify ::group-to-bool
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
change-to-bool change-to-bool
(fn [shape] (group->bool shape bool-type objects))] (fn [shape] (group->bool shape bool-type objects))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) (when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
@ -132,7 +132,7 @@
(ptk/reify ::bool-to-group (ptk/reify ::bool-to-group
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
change-to-group change-to-group
(fn [shape] (bool->group shape objects))] (fn [shape] (bool->group shape objects))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) (when-not (ctn/has-any-copy-parent? objects (get objects shape-id))
@ -144,7 +144,7 @@
(ptk/reify ::change-bool-type (ptk/reify ::change-bool-type
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
change-type change-type
(fn [shape] (assoc shape :bool-type bool-type))] (fn [shape] (assoc shape :bool-type bool-type))]
(when-not (ctn/has-any-copy-parent? objects (get objects shape-id)) (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.common.types.shape.shadow :refer [check-shadow!]]
[app.main.broadcast :as mbc] [app.main.broadcast :as mbc]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as md] [app.main.data.modal :as md]
[app.main.data.workspace.layout :as layout] [app.main.data.workspace.layout :as layout]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shapes :as dwsh] [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.texts :as dwt]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.util.storage :as storage] [app.util.storage :as storage]
@ -84,8 +84,7 @@
(defn transform-fill (defn transform-fill
([state ids color transform] (transform-fill state ids color transform nil)) ([state ids color transform] (transform-fill state ids color transform nil))
([state ids color transform options] ([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 %))) is-text? #(= :text (:type (get objects %)))
text-ids (filter is-text? ids) text-ids (filter is-text? ids)
shape-ids (remove is-text? ids) shape-ids (remove is-text? ids)
@ -135,7 +134,7 @@
(ptk/reify ::reorder-fills (ptk/reify ::reorder-fills
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
is-text? #(= :text (:type (get objects %))) is-text? #(= :text (:type (get objects %)))
text-ids (filter is-text? ids) text-ids (filter is-text? ids)
@ -234,7 +233,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [page-id (:current-page-id 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 %))) is-text? #(= :text (:type (get objects %)))
shape-ids (filter (complement is-text?) ids) shape-ids (filter (complement is-text?) ids)
attrs {:hide-fill-on-export hide-fill-on-export}] attrs {:hide-fill-on-export hide-fill-on-export}]
@ -436,7 +435,7 @@
(ptk/reify ::picker-for-selected-shape (ptk/reify ::picker-for-selected-shape
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [ids (wsh/lookup-selected state) (let [ids (dsh/lookup-selected state)
stop? (rx/filter (ptk/type? ::stop-picker) stream) stop? (rx/filter (ptk/type? ::stop-picker) stream)
update-events update-events
@ -541,8 +540,8 @@
(ptk/reify ::apply-color-from-palette (ptk/reify ::apply-color-from-palette
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
selected (->> (wsh/lookup-selected state) selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects)) (cfh/clean-loops objects))
ids ids
@ -716,7 +715,7 @@
(ptk/reify ::update-colorpicker (ptk/reify ::update-colorpicker
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [shape-id (-> state wsh/lookup-selected first)] (let [shape-id (-> state dsh/lookup-selected first)]
(update state :colorpicker (update state :colorpicker
(fn [state] (fn [state]
(let [current-color (:current-color state)] (let [current-color (:current-color state)]
@ -978,8 +977,8 @@
(ptk/reify ::select-color (ptk/reify ::select-color
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [selected (wsh/lookup-selected state) (let [selected (dsh/lookup-selected state)
shapes (wsh/lookup-shapes state selected) shapes (dsh/lookup-shapes state selected)
shape (first shapes) shape (first shapes)
fills (if (cfh/text-shape? shape) fills (if (cfh/text-shape? shape)
(:fills (dwt/current-text-values (:fills (dwt/current-text-values

View file

@ -17,11 +17,11 @@
[app.main.data.comments :as dcmt] [app.main.data.comments :as dcmt]
[app.main.data.common :as dcm] [app.main.data.common :as dcm]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.common :as dwco] [app.main.data.workspace.common :as dwco]
[app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.viewport :as dwv] [app.main.data.workspace.viewport :as dwv]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.router :as rt] [app.main.router :as rt]
@ -35,26 +35,25 @@
(defn initialize-comments (defn initialize-comments
[file-id] [file-id]
(dm/assert! (uuid? file-id))
(ptk/reify ::initialize-comments (ptk/reify ::initialize-comments
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stopper (rx/filter #(= ::finalize %) stream)] (let [stopper-s (rx/filter #(= ::finalize %) stream)]
(rx/merge (->> (rx/merge
(rx/of (dcmt/retrieve-comment-threads file-id)) (rx/of (dcmt/retrieve-comment-threads file-id))
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-click-event?) (rx/filter mse/mouse-click-event?)
(rx/switch-map #(rx/take 1 ms/mouse-position)) (rx/switch-map #(rx/take 1 ms/mouse-position))
(rx/with-latest-from ms/keyboard-space) (rx/with-latest-from ms/keyboard-space)
(rx/filter (fn [[_ space]] (not space))) (rx/filter (fn [[_ space]] (not space)))
(rx/map first) (rx/map first)
(rx/map handle-comment-layer-click) (rx/map handle-comment-layer-click))
(rx/take-until stopper)) (->> stream
(->> stream (rx/filter dwco/interrupt?)
(rx/filter dwco/interrupt?) (rx/map handle-interrupt)))
(rx/map handle-interrupt)
(rx/take-until stopper))))))) (rx/take-until stopper-s))))))
(defn- handle-interrupt (defn- handle-interrupt
[] []
@ -65,10 +64,8 @@
(cond (cond
(:draft local) (rx/of (dcmt/close-thread)) (:draft local) (rx/of (dcmt/close-thread))
(:open local) (rx/of (dcmt/close-thread)) (:open local) (rx/of (dcmt/close-thread))
:else (rx/of (dwe/clear-edition-mode)
:else (dws/deselect-all true)))))))
(rx/of (dwe/clear-edition-mode)
(dws/deselect-all true)))))))
;; Event responsible of the what should be executed when user clicked ;; Event responsible of the what should be executed when user clicked
;; on the comments layer. An option can be create a new draft thread, ;; on the comments layer. An option can be create a new draft thread,
@ -139,9 +136,9 @@
(ptk/reify ::update-comment-thread-position (ptk/reify ::update-comment-thread-position
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page (wsh/lookup-page state) (let [page (dsh/lookup-page state)
page-id (:id page) 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) frame-id (if (nil? frame-id)
(ctst/get-frame-id-by-position objects (gpt/point new-x new-y)) (ctst/get-frame-id-by-position objects (gpt/point new-x new-y))
(:frame-id thread)) (:frame-id thread))
@ -172,7 +169,7 @@
(ptk/reify ::move-frame-comment-threads (ptk/reify ::move-frame-comment-threads
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [page (wsh/lookup-page state) (let [page (dsh/lookup-page state)
objects (get page :objects) objects (get page :objects)
is-frame? (fn [id] (= :frame (get-in objects [id :type]))) 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.types.shape.layout :as ctl]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.constants :refer [zoom-half-pixel-precision]] [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.drawing.common :as common]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.snap :as snap] [app.main.snap :as snap]
[app.main.streams :as ms] [app.main.streams :as ms]
[app.util.array :as array] [app.util.array :as array]
@ -87,7 +87,7 @@
initial (cond-> @ms/mouse-position snap-pixel? (gpt/round-step snap-prec)) initial (cond-> @ms/mouse-position snap-pixel? (gpt/round-step snap-prec))
page-id (:current-page-id state) 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) focus (:workspace-focus-selected state)
fid (->> (ctst/top-nested-frame objects initial) fid (->> (ctst/top-nested-frame objects initial)

View file

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

View file

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

View file

@ -7,8 +7,8 @@
(ns app.main.data.workspace.edition (ns app.main.data.workspace.edition
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.path.common :as dwpc] [app.main.data.workspace.path.common :as dwpc]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -22,7 +22,7 @@
(ptk/reify ::start-edition-mode (ptk/reify ::start-edition-mode
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [objects (wsh/lookup-page-objects state)] (let [objects (dsh/lookup-page-objects state)]
;; Can only edit objects that exist ;; Can only edit objects that exist
(if (contains? objects id) (if (contains? objects id)
(-> state (-> state
@ -38,7 +38,10 @@
(rx/take 1) (rx/take 1)
(rx/map clear-edition-mode))))) (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 (defn clear-edition-mode
[] []
(ptk/reify ::clear-edition-mode (ptk/reify ::clear-edition-mode

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,8 +7,8 @@
(ns app.main.data.workspace.specialized-panel (ns app.main.data.workspace.specialized-panel
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.common :as-alias dwc] [app.main.data.workspace.common :as-alias dwc]
[app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -28,8 +28,8 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id) objects (dsh/lookup-page-objects state page-id)
selected-ids (wsh/lookup-selected state) selected-ids (dsh/lookup-selected state)
selected-shapes (map (d/getf objects) selected-ids)] selected-shapes (map (d/getf objects) selected-ids)]
(assoc state :specialized-panel {:type type :shapes selected-shapes}))) (assoc state :specialized-panel {:type type :shapes selected-shapes})))
ptk/WatchEvent 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.types.shape-tree :as ctst]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.changes :as dch] [app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.util.webapi :as wapi] [app.util.webapi :as wapi]
@ -72,8 +72,8 @@
(try (try
(let [id (d/nilv id (uuid/next)) (let [id (d/nilv id (uuid/next))
page-id (:current-page-id state) page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id) objects (dsh/lookup-page-objects state page-id)
selected (if ignore-selection? #{} (wsh/lookup-selected state)) selected (if ignore-selection? #{} (dsh/lookup-selected state))
base (cfh/get-base-shape objects selected) base (cfh/get-base-shape objects selected)
selected-id (first selected) selected-id (first selected)

View file

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

View file

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

View file

@ -14,7 +14,7 @@
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.data.changes :as dch] [app.main.data.changes :as dch]
[app.main.data.common :as dcm] [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] [app.util.time :as dt]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -186,7 +186,7 @@
(ptk/reify ::undo-to-index (ptk/reify ::undo-to-index
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition]) edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)] drawing (get state :workspace-drawing)]
(when-not (and (or (some? edition) (some? (:object drawing))) (when-not (and (or (some? edition) (some? (:object drawing)))
@ -219,7 +219,7 @@
(ptk/reify ::undo (ptk/reify ::undo
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition]) edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)] drawing (get state :workspace-drawing)]
@ -257,7 +257,7 @@
(ptk/reify ::redo (ptk/reify ::redo
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [objects (wsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
edition (get-in state [:workspace-local :edition]) edition (get-in state [:workspace-local :edition])
drawing (get state :workspace-drawing)] drawing (get state :workspace-drawing)]
(when (and (or (nil? edition) (ctl/grid-layout? objects edition)) (when (and (or (nil? edition) (ctl/grid-layout? objects edition))
@ -291,7 +291,8 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [page-id (:current-page-id 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) (if (contains? pages page-id)
(rx/empty) (rx/empty)
(rx/of (dcm/go-to-workspace :page-id (first pages)))))))) (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.rect :as gpr]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.math :as mth] [app.common.math :as mth]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.helpers :as dsh]
[app.util.mouse :as mse] [app.util.mouse :as mse]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -38,7 +38,7 @@
(initialize [state local] (initialize [state local]
(let [page-id (:current-page-id 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) shapes (cfh/get-immediate-children objects)
srect (gsh/shapes->rect shapes) srect (gsh/shapes->rect shapes)
local (assoc local :vport size :zoom 1 :zoom-inverse 1 :hide-toolbar false)] 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.point :as gpt]
[app.common.geom.rect :as grc] [app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh] [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.main.streams :as ms]
[app.util.mouse :as mse] [app.util.mouse :as mse]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -83,7 +83,7 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [page-id (:current-page-id 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) shapes (cfh/get-immediate-children objects)
srect (gsh/shapes->rect shapes)] srect (gsh/shapes->rect shapes)]
(if (empty? shapes) (if (empty? shapes)
@ -101,11 +101,11 @@
(ptk/reify ::zoom-to-selected-shape (ptk/reify ::zoom-to-selected-shape
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [selected (wsh/lookup-selected state)] (let [selected (dsh/lookup-selected state)]
(if (empty? selected) (if (empty? selected)
state state
(let [page-id (:current-page-id 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 srect (->> selected
(map #(get objects %)) (map #(get objects %))
(gsh/shapes->rect))] (gsh/shapes->rect))]
@ -126,7 +126,7 @@
(if (empty? ids) (if (empty? ids)
state state
(let [page-id (:current-page-id 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 srect (->> ids
(map #(get objects %)) (map #(get objects %))
(gsh/shapes->rect))] (gsh/shapes->rect))]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,7 +20,7 @@
[okulary.core :as l] [okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def lens:background-color (def ^:private ref:background-color
(-> (l/key :background) (-> (l/key :background)
(l/derived refs/workspace-page))) (l/derived refs/workspace-page)))
@ -28,7 +28,7 @@
{::mf/wrap [mf/memo] {::mf/wrap [mf/memo]
::mf/wrap-props false} ::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-change (mf/use-fn #(st/emit! (dw/change-canvas-color %)))
on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options)))
on-close (mf/use-fn #(st/emit! (dwu/commit-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 :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.main.data.common :as dcm] [app.main.data.common :as dcm]
[app.main.data.helpers :as dsh]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -27,6 +28,29 @@
[okulary.core :as l] [okulary.core :as l]
[rumext.v2 :as mf])) [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 ;; --- Page Item
(mf/defc page-item (mf/defc page-item
@ -155,17 +179,11 @@
;; --- Page Item Wrapper ;; --- 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/defc page-item-wrapper
{::mf/wrap-props false} {::mf/wrap-props false}
[{:keys [page-id index deletable? selected? editing?]}] [{: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 (mf/deref page-ref)]
[:& page-item {:page page [:& page-item {:page page
:index index :index index
@ -198,7 +216,7 @@
(mf/defc sitemap (mf/defc sitemap
{::mf/wrap-props false} {::mf/wrap-props false}
[{:keys [size show-pages? toggle-pages]}] [{: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) file-id (get file :id)
project-id (get file :project-id) project-id (get file :project-id)
@ -207,6 +225,7 @@
(fn [event] (fn [event]
(st/emit! (dw/create-page {:file-id file-id :project-id project-id})) (st/emit! (dw/create-page {:file-id file-id :project-id project-id}))
(-> event dom/get-current-target dom/blur!))) (-> event dom/get-current-target dom/blur!)))
read-only? (mf/use-ctx ctx/workspace-read-only?) read-only? (mf/use-ctx ctx/workspace-read-only?)
permissions (mf/use-ctx ctx/permissions)] permissions (mf/use-ctx ctx/permissions)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,21 +11,20 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.container :as ctn] [app.common.types.container :as ctn]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.main.data.helpers :as dsh]
[app.main.store :as st] [app.main.store :as st]
[app.util.object :as obj])) [app.util.object :as obj]))
(defn locate-file (defn locate-file
[id] [id]
(assert (uuid? id) "File not valid uuid") (assert (uuid? id) "File not valid uuid")
(if (= id (:current-file-id @st/state)) (dsh/lookup-file @st/state id))
(-> (:workspace-file @st/state)
(assoc :data (:workspace-data @st/state)))
(dm/get-in @st/state [:libraries id])))
(defn locate-page (defn locate-page
[file-id id] [file-id id]
(assert (uuid? id) "Page not valid uuid") (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 (defn locate-objects
([] ([]
@ -62,13 +61,15 @@
(let [{:keys [profile-id]} (locate-presence session-id)] (let [{:keys [profile-id]} (locate-presence session-id)]
(dm/get-in @st/state [:users profile-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 (defn locate-component
[objects shape] [objects shape]
(let [current-file-id (:current-file-id @st/state) (let [state (deref st/state)
workspace-data (:workspace-data @st/state) file (dsh/lookup-file state)
libraries (:libraries @st/state) libraries (dsh/lookup-libraries state)
root (ctn/get-instance-root objects shape)] 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 (defn proxy->file
[proxy] [proxy]
@ -87,7 +88,7 @@
[proxy] [proxy]
(let [file-id (obj/get proxy "$file") (let [file-id (obj/get proxy "$file")
page-id (obj/get proxy "$page") page-id (obj/get proxy "$page")
id (obj/get proxy "$id")] id (obj/get proxy "$id")]
(when (and (some? file-id) (some? page-id) (some? id)) (when (and (some? file-id) (some? page-id) (some? id))
(locate-shape file-id page-id id)))) (locate-shape file-id page-id id))))
@ -167,9 +168,12 @@
(defn get-state (defn get-state
([self attr] ([self attr]
(let [id (get-data self :id) (let [id (get-data self :id)
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))] page-id (or (get-data self :page-id)
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr]))) (:current-page-id @st/state))]
(-> (dsh/lookup-page-objects @st/state page-id)
(dm/get-in [:objects id attr]))))
([self attr mapfn] ([self attr mapfn]
(-> (get-state self attr) (-> (get-state self attr)
(mapfn)))) (mapfn))))

View file

@ -18,6 +18,7 @@
[app.main.data.changes :as dwc] [app.main.data.changes :as dwc]
[app.main.data.common :as dcm] [app.main.data.common :as dcm]
[app.main.data.dashboard.shortcuts] [app.main.data.dashboard.shortcuts]
[app.main.data.helpers :as dsh]
[app.main.data.preview :as dp] [app.main.data.preview :as dp]
[app.main.data.viewer.shortcuts] [app.main.data.viewer.shortcuts]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
@ -149,8 +150,10 @@
nil) nil)
(defn ^:export dump-data [] (defn ^:export dump-data []
(logjs "workspace-data" (get @st/state :workspace-data)) (let [fdata (-> (dsh/lookup-file @st/state)
nil) (get :data))]
(logjs "file-data" fdata)
nil))
(defn ^:export dump-buffer [] (defn ^:export dump-buffer []
(logjs "last-events" @st/last-events) (logjs "last-events" @st/last-events)
@ -165,8 +168,7 @@
(defn dump-objects' (defn dump-objects'
[state] [state]
(let [page-id (get state :current-page-id) (let [objects (dsh/lookup-page-objects state)]
objects (get-in state [:workspace-data :pages-index page-id :objects])]
(logjs "objects" objects) (logjs "objects" objects)
nil)) nil))
@ -174,33 +176,25 @@
[] []
(dump-objects' @st/state)) (dump-objects' @st/state))
(defn dump-object' (defn get-object
[state name] [state name]
(let [page-id (get state :current-page-id) (let [objects (dsh/lookup-page-objects state)
objects (get-in state [:workspace-data :pages-index page-id :objects])
result (or (d/seek (fn [shape] (= name (:name shape))) (vals objects)) result (or (d/seek (fn [shape] (= name (:name shape))) (vals objects))
(get objects (uuid/uuid name)))] (get objects (uuid/uuid name)))]
#_(logjs name result) result))
result
#_nil))
(defn ^:export dump-object (defn ^:export dump-object
[name] [name]
(dump-object' @st/state name)) (get-object @st/state name))
(defn dump-selected' (defn get-selected
[state] [state]
(let [page-id (get state :current-page-id) (dsh/lookup-selected state))
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))
(defn ^:export dump-selected (defn ^:export dump-selected
[] []
(dump-selected' @st/state)) (logjs "selected" (get-selected @st/state))
nil)
(defn ^:export preview-selected (defn ^:export preview-selected
[] []
@ -208,26 +202,20 @@
(defn ^:export parent (defn ^:export parent
[] []
(let [state @st/state (let [objects (dsh/lookup-page-objects @st/state)
page-id (get state :current-page-id) selected-id (first (dsh/get-selected-ids @st/state))
objects (get-in state [:workspace-data :pages-index page-id :objects]) parent-id (dm/get-in objects [selected-id :parent-id])]
selected (first (get-in state [:workspace-local :selected])) (when-let [parent (get objects parent-id)]
parent-id (get-in objects [selected :parent-id]) (js/console.log (str (:name parent) " - " (:id parent))))
parent (get objects parent-id)]
(when parent
(prn (str (:name parent) " - " (:id parent))))
nil)) nil))
(defn ^:export frame (defn ^:export frame
[] []
(let [state @st/state (let [objects (dsh/lookup-page-objects @st/state)
page-id (get state :current-page-id) selected-id (first (dsh/get-selected-ids @st/state))
objects (get-in state [:workspace-data :pages-index page-id :objects]) frame-id (dm/get-in objects [selected-id :frame-id])]
selected (first (get-in state [:workspace-local :selected])) (when-let [frame (get objects frame-id)]
frame-id (get-in objects [selected :frame-id]) (js/console.log (str (:name frame) " - " (:id frame))))
frame (get objects frame-id)]
(when frame
(prn (str (:name frame) " - " (:id frame))))
nil)) nil))
(defn ^:export select-by-object-id (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] (dump-tree' state show-ids show-touched false))
([state show-ids show-touched show-modified] ([state show-ids show-touched show-modified]
(let [page-id (get state :current-page-id) (let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file) file (dsh/lookup-file state)
:data (get state :workspace-data)) libraries (get state :files)]
libraries (get state :libraries)]
(ctf/dump-tree file page-id libraries {:show-ids show-ids (ctf/dump-tree file page-id libraries {:show-ids show-ids
:show-touched show-touched :show-touched show-touched
:show-modified show-modified})))) :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] (dump-subtree' state shape-id show-ids show-touched false))
([state shape-id show-ids show-touched show-modified] ([state shape-id show-ids show-touched show-modified]
(let [page-id (get state :current-page-id) (let [page-id (get state :current-page-id)
file (assoc (get state :workspace-file) file (dsh/lookup-file state)
:data (get state :workspace-data)) libraries (get state :files)
libraries (get state :libraries)
shape-id (if (some? shape-id) shape-id (if (some? shape-id)
(uuid/uuid shape-id) (uuid/uuid shape-id)
(let [objects (get-in state [:workspace-data :pages-index page-id :objects]) (first (dsh/lookup-selected state)))]
selected (get-in state [:workspace-local :selected])]
(->> selected (map (d/getf objects)) first :id)))]
(if (some? shape-id) (if (some? shape-id)
(ctf/dump-subtree file page-id shape-id libraries {:show-ids show-ids (ctf/dump-subtree file page-id shape-id libraries {:show-ids show-ids
:show-touched show-touched :show-touched show-touched
@ -363,10 +347,10 @@
(defn ^:export dump-modifiers (defn ^:export dump-modifiers
[] []
(let [page-id (get @st/state :current-page-id) (let [objects (dsh/lookup-page-objects @st/state)
objects (get-in @st/state [:workspace-data :pages-index page-id :objects])] modifiers (:workspace-modifiers @st/state)]
(.log js/console (modif->js (:workspace-modifiers @st/state) objects))) (js/console.log (modif->js modifiers objects))
nil) nil))
(defn ^:export set-workspace-read-only (defn ^:export set-workspace-read-only
[read-only?] [read-only?]
@ -381,10 +365,8 @@
(defn ^:export validate (defn ^:export validate
([] (validate nil)) ([] (validate nil))
([shape-id] ([shape-id]
(let [file (assoc (get @st/state :workspace-file) (let [file (dsh/lookup-file @st/state)
:data (get @st/state :workspace-data)) libraries (get @st/state :files)]
libraries (get @st/state :libraries)]
(try (try
(->> (if-let [shape-id (some-> shape-id parse-uuid)] (->> (if-let [shape-id (some-> shape-id parse-uuid)]
(let [page (dm/get-in file [:data :pages-index (get @st/state :current-page-id)])] (let [page (dm/get-in file [:data :pages-index (get @st/state :current-page-id)])]
@ -398,9 +380,8 @@
(defn ^:export validate-schema (defn ^:export validate-schema
[] []
(try (try
(-> (get @st/state :workspace-file) (let [file (dsh/lookup-file @st/state)]
(assoc :data (get @st/state :workspace-data)) (cfv/validate-file-schema! file))
(cfv/validate-file-schema!))
(catch :default cause (catch :default cause
(errors/print-error! cause)))) (errors/print-error! cause))))
@ -413,11 +394,8 @@
(let [features (features/get-team-enabled-features state) (let [features (features/get-team-enabled-features state)
sid (:session-id state) sid (:session-id state)
file (get state :workspace-file) file (dsh/lookup-file state)
fdata (get state :workspace-data) libs (get state :files)
file (assoc file :data fdata)
libs (get state :libraries)
errors (cfv/validate-file file libs) errors (cfv/validate-file file libs)
_ (l/dbg :hint "repair current file" :errors (count errors)) _ (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.files :as cthf]
[app.common.test-helpers.ids-map :as cthi] [app.common.test-helpers.ids-map :as cthi]
[app.common.test-helpers.shapes :as cths] [app.common.test-helpers.shapes :as cths]
[app.main.data.helpers :as dsh]
[app.main.data.workspace.colors :as dc] [app.main.data.workspace.colors :as dc]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[cljs.test :as t :include-macros true] [cljs.test :as t :include-macros true]
@ -34,13 +35,10 @@
store done events store done events
(fn [new-state] (fn [new-state]
(let [;; ==== Get (let [;; ==== Get
shape1' (get-in new-state [:workspace-data objects (dsh/lookup-page-objects new-state)
:pages-index shape1' (get objects (cthi/id :shape1))
(cthi/id :page1) fills' (:fills shape1')
:objects fill' (first fills')]
(cthi/id :shape1)])
fills' (:fills shape1')
fill' (first fills')]
;; ==== Check ;; ==== Check
(t/is (some? shape1')) (t/is (some? shape1'))
@ -68,15 +66,11 @@
store done events store done events
(fn [new-state] (fn [new-state]
(let [;; ==== Get (let [;; ==== Get
shape1' (get-in new-state [:workspace-data objects (dsh/lookup-page-objects new-state)
:pages-index shape1' (get objects (cthi/id :shape1))
(cthi/id :page1) stroke' (first (:strokes shape1'))]
:objects
(cthi/id :shape1)])
stroke' (-> (:strokes shape1')
first)]
;; ==== Check ;; ==== Check
;; (println stroke') ;; (println stroke')
(t/is (some? shape1')) (t/is (some? shape1'))
(t/is (= (:stroke-alignment stroke') :inner)) (t/is (= (:stroke-alignment stroke') :inner))

View file

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

View file

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

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