mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 02:28:18 -05:00
Merge pull request #2084 from penpot/eva-alex-move-comments
❇️ Comments positioning
This commit is contained in:
commit
01306841a9
15 changed files with 596 additions and 212 deletions
|
@ -29,6 +29,7 @@
|
|||
- Improved share link options. Now you can allow non-team members to comment and/or inspect [Taiga #3056] (https://tree.taiga.io/project/penpot/us/3056)
|
||||
- Signin/Signup from shared link [Taiga #3472](https://tree.taiga.io/project/penpot/us/3472)
|
||||
- Support for import/export binary format [Taiga #2991](https://tree.taiga.io/project/penpot/us/2991)
|
||||
- Comments positioning [Taiga #https://2007](tree.taiga.io/project/penpot/us/2007)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
|
|
|
@ -238,6 +238,9 @@
|
|||
|
||||
{:name "0076-mod-storage-object-table"
|
||||
:fn (mg/resource "app/migrations/sql/0076-mod-storage-object-table.sql")}
|
||||
|
||||
{:name "0077-mod-comment-thread-table"
|
||||
:fn (mg/resource "app/migrations/sql/0077-mod-comment-thread-table.sql")}
|
||||
])
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
--- Add frame_id field.
|
||||
ALTER TABLE comment_thread
|
||||
ADD COLUMN frame_id uuid NULL DEFAULT '00000000-0000-0000-0000-000000000000';
|
|
@ -31,9 +31,10 @@
|
|||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::position ::gpt/point)
|
||||
(s/def ::content ::us/string)
|
||||
(s/def ::frame-id ::us/uuid)
|
||||
|
||||
(s/def ::create-comment-thread
|
||||
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id]
|
||||
(s/keys :req-un [::profile-id ::file-id ::position ::content ::page-id ::frame-id]
|
||||
:opt-un [::share-id]))
|
||||
|
||||
(sv/defmethod ::create-comment-thread
|
||||
|
@ -53,7 +54,7 @@
|
|||
(:next-seqn res)))
|
||||
|
||||
(defn- create-comment-thread
|
||||
[conn {:keys [profile-id file-id page-id position content] :as params}]
|
||||
[conn {:keys [profile-id file-id page-id position content frame-id] :as params}]
|
||||
(let [seqn (retrieve-next-seqn conn file-id)
|
||||
now (dt/now)
|
||||
pname (retrieve-page-name conn params)
|
||||
|
@ -66,7 +67,8 @@
|
|||
:created-at now
|
||||
:modified-at now
|
||||
:seqn seqn
|
||||
:position (db/pgpoint position)})]
|
||||
:position (db/pgpoint position)
|
||||
:frame-id frame-id})]
|
||||
|
||||
|
||||
;; Create a comment entry
|
||||
|
@ -281,3 +283,40 @@
|
|||
:code :not-allowed))
|
||||
|
||||
(db/delete! conn :comment {:id id}))))
|
||||
|
||||
;; --- Mutation: Update comment thread position
|
||||
|
||||
(s/def ::update-comment-thread-position
|
||||
(s/keys :req-un [::profile-id ::id ::position ::frame-id]))
|
||||
|
||||
(sv/defmethod ::update-comment-thread-position
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id position frame-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||
(when-not (= (:owner-id thread) profile-id)
|
||||
(ex/raise :type :validation
|
||||
:code :not-allowed))
|
||||
(db/update! conn :comment-thread
|
||||
{:modified-at (dt/now)
|
||||
:position (db/pgpoint position)
|
||||
:frame-id frame-id}
|
||||
{:id (:id thread)})
|
||||
nil)))
|
||||
|
||||
;; --- Mutation: Update comment frame
|
||||
|
||||
(s/def ::update-comment-thread-frame
|
||||
(s/keys :req-un [::profile-id ::id ::frame-id]))
|
||||
|
||||
(sv/defmethod ::update-comment-thread-frame
|
||||
[{:keys [pool] :as cfg} {:keys [profile-id id frame-id] :as params}]
|
||||
(db/with-atomic [conn pool]
|
||||
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||
(when-not (= (:owner-id thread) profile-id)
|
||||
(ex/raise :type :validation
|
||||
:code :not-allowed))
|
||||
(db/update! conn :comment-thread
|
||||
{:modified-at (dt/now)
|
||||
:frame-id frame-id}
|
||||
{:id (:id thread)})
|
||||
nil)))
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
&.unread {
|
||||
background-color: $color-primary;
|
||||
}
|
||||
span {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.thread-content {
|
||||
|
@ -77,7 +80,7 @@
|
|||
resize: none;
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
border: 1px solid $color-gray-10;
|
||||
border: 1px solid $color-gray-20;
|
||||
max-height: 4rem;
|
||||
}
|
||||
|
||||
|
@ -188,6 +191,7 @@
|
|||
margin: 0 $size-2 0 26px;
|
||||
white-space: pre-wrap;
|
||||
display: inline-block;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.repo :as rp]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
|
@ -59,29 +62,70 @@
|
|||
(declare retrieve-comment-threads)
|
||||
(declare refresh-comment-thread)
|
||||
|
||||
(s/def ::create-thread-params
|
||||
(s/def ::create-thread-on-workspace-params
|
||||
(s/keys :req-un [::page-id ::file-id ::position ::content]))
|
||||
|
||||
(defn create-thread
|
||||
[params]
|
||||
(us/assert ::create-thread-params params)
|
||||
(letfn [(created [{:keys [id comment] :as thread} state]
|
||||
(-> state
|
||||
(update :comment-threads assoc id (dissoc thread :comment))
|
||||
(update :comments-local assoc :open id)
|
||||
(update :comments-local dissoc :draft)
|
||||
(update :workspace-drawing dissoc :comment)
|
||||
(update-in [:comments id] assoc (:id comment) comment)))]
|
||||
(s/def ::create-thread-on-viewer-params
|
||||
(s/keys :req-un [::page-id ::file-id ::position ::content ::frame-id]))
|
||||
|
||||
(ptk/reify ::create-comment-thread
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)
|
||||
params (assoc params :share-id share-id)]
|
||||
(->> (rp/mutation :create-comment-thread params)
|
||||
(rx/mapcat #(rp/query :comment-thread {:file-id (:file-id %) :id (:id %) :share-id share-id}))
|
||||
(rx/map #(partial created %))
|
||||
(rx/catch #(rx/throw {:type :comment-error}))))))))
|
||||
(defn created-thread-on-workspace
|
||||
[{:keys [id comment page-id] :as thread}]
|
||||
|
||||
(ptk/reify ::created-thread-on-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :comment-threads assoc id (dissoc thread :comment))
|
||||
(update-in [:workspace-data :pages-index page-id :options :comment-threads-position] assoc id (select-keys thread [:position :frame-id]))
|
||||
(update :comments-local assoc :open id)
|
||||
(update :comments-local dissoc :draft)
|
||||
(update :workspace-drawing dissoc :comment)
|
||||
(update-in [:comments id] assoc (:id comment) comment)))))
|
||||
|
||||
(defn create-thread-on-workspace
|
||||
[params]
|
||||
(us/assert ::create-thread-on-workspace-params params)
|
||||
|
||||
(ptk/reify ::create-thread-on-workspace
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
frame-id (cph/frame-id-by-position objects (:position params))
|
||||
params (assoc params :frame-id frame-id)]
|
||||
(->> (rp/mutation :create-comment-thread params)
|
||||
(rx/mapcat #(rp/query :comment-thread {:file-id (:file-id %) :id (:id %)}))
|
||||
(rx/map created-thread-on-workspace)
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
|
||||
(defn created-thread-on-viewer
|
||||
[{:keys [id comment page-id] :as thread}]
|
||||
|
||||
(ptk/reify ::created-thread-on-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :comment-threads assoc id (dissoc thread :comment))
|
||||
(update-in [:viewer :pages page-id :options :comment-threads-position] assoc id (select-keys thread [:position :frame-id]))
|
||||
(update :comments-local assoc :open id)
|
||||
(update :comments-local dissoc :draft)
|
||||
(update :workspace-drawing dissoc :comment)
|
||||
(update-in [:comments id] assoc (:id comment) comment)))))
|
||||
|
||||
(defn create-thread-on-viewer
|
||||
[params]
|
||||
(us/assert ::create-thread-on-viewer-params params)
|
||||
|
||||
(ptk/reify ::create-thread-on-viewer
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)
|
||||
frame-id (:frame-id params)
|
||||
params (assoc params :share-id share-id :frame-id frame-id)]
|
||||
(->> (rp/mutation :create-comment-thread params)
|
||||
(rx/mapcat #(rp/query :comment-thread {:file-id (:file-id %) :id (:id %) :share-id share-id}))
|
||||
(rx/map created-thread-on-viewer)
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
|
||||
(defn update-comment-thread-status
|
||||
[{:keys [id] :as thread}]
|
||||
|
@ -95,7 +139,6 @@
|
|||
(rx/map (constantly done))
|
||||
(rx/catch #(rx/throw {:type :comment-error})))))))
|
||||
|
||||
|
||||
(defn update-comment-thread
|
||||
[{:keys [id is-resolved] :as thread}]
|
||||
(us/assert ::comment-thread thread)
|
||||
|
@ -114,7 +157,6 @@
|
|||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
|
||||
(defn add-comment
|
||||
[thread content]
|
||||
(us/assert ::comment-thread thread)
|
||||
|
@ -146,15 +188,35 @@
|
|||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))))))
|
||||
|
||||
(defn delete-comment-thread
|
||||
(defn delete-comment-thread-on-workspace
|
||||
[{:keys [id] :as thread}]
|
||||
(us/assert ::comment-thread thread)
|
||||
(ptk/reify ::delete-comment-thread
|
||||
(ptk/reify ::delete-comment-thread-on-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :comments dissoc id)
|
||||
(update :comment-threads dissoc id)))
|
||||
(let [page-id (:current-page-id state)]
|
||||
(-> state
|
||||
(update-in [:workspace-data :pages-index page-id :options :comment-threads-position] dissoc id)
|
||||
(update :comments dissoc id)
|
||||
(update :comment-threads dissoc id))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rp/mutation :delete-comment-thread {:id id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore)))))
|
||||
|
||||
(defn delete-comment-thread-on-viewer
|
||||
[{:keys [id] :as thread}]
|
||||
(us/assert ::comment-thread thread)
|
||||
(ptk/reify ::delete-comment-thread-on-viewer
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [page-id (:current-page-id state)]
|
||||
(-> state
|
||||
(update-in [:viewer :pages page-id :options :comment-threads-position] dissoc id)
|
||||
(update :comments dissoc id)
|
||||
(update :comment-threads dissoc id))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -194,8 +256,18 @@
|
|||
(defn retrieve-comment-threads
|
||||
[file-id]
|
||||
(us/assert ::us/uuid file-id)
|
||||
(letfn [(fetched [data state]
|
||||
(assoc state :comment-threads (d/index-by :id data)))]
|
||||
(letfn [(set-comment-threds [state comment-thread]
|
||||
(let [path [:workspace-data :pages-index (:page-id comment-thread) :options :comment-threads-position (:id comment-thread)]
|
||||
thread-position (get-in state path)]
|
||||
(cond-> state
|
||||
(nil? thread-position)
|
||||
(->
|
||||
(assoc-in (conj path :position) (:position comment-thread))
|
||||
(assoc-in (conj path :frame-id) (:frame-id comment-thread))))))
|
||||
(fetched [data state]
|
||||
(let [state (assoc state :comment-threads (d/index-by :id data))]
|
||||
(reduce set-comment-threds state data)))]
|
||||
|
||||
(ptk/reify ::retrieve-comment-threads
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -338,3 +410,41 @@
|
|||
|
||||
(= :yours mode)
|
||||
(filter #(contains? (:participants %) (:id profile))))))
|
||||
|
||||
(defn update-comment-thread-frame
|
||||
([thread ]
|
||||
(update-comment-thread-frame thread uuid/zero))
|
||||
|
||||
([thread frame-id]
|
||||
(us/assert ::comment-thread thread)
|
||||
(ptk/reify ::update-comment-thread-frame
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [thread-id (:id thread)]
|
||||
(assoc-in state [:comment-threads thread-id :frame-id] frame-id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [thread-id (:id thread)]
|
||||
(->> (rp/mutation :update-comment-thread-frame {:id thread-id :frame-id frame-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error :code :update-comment-thread-frame}))
|
||||
(rx/ignore)))))))
|
||||
|
||||
(defn detach-comment-thread
|
||||
"Detach comment threads that are inside a frame when that frame is deleted"
|
||||
[ids]
|
||||
(us/verify (s/coll-of uuid?) ids)
|
||||
|
||||
(ptk/reify ::detach-comment-thread
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
frame-ids? (into #{} (filter is-frame?) ids)]
|
||||
|
||||
(->> state
|
||||
:comment-threads
|
||||
(vals)
|
||||
(filter (fn [comment] (some #(= % (:frame-id comment)) frame-ids?)))
|
||||
(map update-comment-thread-frame)
|
||||
(rx/from))))))
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
|
@ -50,6 +49,7 @@
|
|||
[app.main.data.workspace.thumbnails :as dwth]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.data.workspace.viewport :as dwv]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.streams :as ms]
|
||||
|
@ -397,140 +397,6 @@
|
|||
(assoc-in state [:workspace-global :tooltip] content)
|
||||
(assoc-in state [:workspace-global :tooltip] nil)))))
|
||||
|
||||
;; --- Viewport Sizing
|
||||
|
||||
(defn initialize-viewport
|
||||
[{:keys [width height] :as size}]
|
||||
(letfn [(update* [{:keys [vport] :as local}]
|
||||
(let [wprop (/ (:width vport) width)
|
||||
hprop (/ (:height vport) height)]
|
||||
(-> local
|
||||
(assoc :vport size)
|
||||
(update :vbox (fn [vbox]
|
||||
(-> vbox
|
||||
(update :width #(/ % wprop))
|
||||
(update :height #(/ % hprop))))))))
|
||||
|
||||
(initialize [state local]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shapes (cph/get-immediate-children objects)
|
||||
srect (gsh/selection-rect shapes)
|
||||
local (assoc local :vport size :zoom 1)]
|
||||
(cond
|
||||
(or (not (d/num? (:width srect)))
|
||||
(not (d/num? (:height srect))))
|
||||
(assoc local :vbox (assoc size :x 0 :y 0))
|
||||
|
||||
(or (> (:width srect) width)
|
||||
(> (:height srect) height))
|
||||
(let [srect (gal/adjust-to-viewport size srect {:padding 40})
|
||||
zoom (/ (:width size) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect)))
|
||||
|
||||
:else
|
||||
(assoc local :vbox (assoc size
|
||||
:x (+ (:x srect) (/ (- (:width srect) width) 2))
|
||||
:y (+ (:y srect) (/ (- (:height srect) height) 2)))))))
|
||||
|
||||
(setup [state local]
|
||||
(if (and (:vbox local) (:vport local))
|
||||
(update* local)
|
||||
(initialize state local)))]
|
||||
|
||||
(ptk/reify ::initialize-viewport
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
(fn [local]
|
||||
(setup state local)))))))
|
||||
|
||||
(defn update-viewport-position
|
||||
[{:keys [x y] :or {x identity y identity}}]
|
||||
(us/assert fn? x)
|
||||
(us/assert fn? y)
|
||||
(ptk/reify ::update-viewport-position
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace-local :vbox]
|
||||
(fn [vbox]
|
||||
(-> vbox
|
||||
(update :x x)
|
||||
(update :y y)))))))
|
||||
|
||||
(defn update-viewport-size
|
||||
[resize-type {:keys [width height] :as size}]
|
||||
(ptk/reify ::update-viewport-size
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(if (or (nil? vport)
|
||||
(mth/almost-zero? width)
|
||||
(mth/almost-zero? height))
|
||||
;; If we have a resize to zero just keep the old value
|
||||
local
|
||||
(let [wprop (/ (:width vport) width)
|
||||
hprop (/ (:height vport) height)
|
||||
|
||||
vbox (:vbox local)
|
||||
vbox-x (:x vbox)
|
||||
vbox-y (:y vbox)
|
||||
vbox-width (:width vbox)
|
||||
vbox-height (:height vbox)
|
||||
|
||||
vbox-width' (/ vbox-width wprop)
|
||||
vbox-height' (/ vbox-height hprop)
|
||||
|
||||
vbox-x'
|
||||
(case resize-type
|
||||
:left (+ vbox-x (- vbox-width vbox-width'))
|
||||
:right vbox-x
|
||||
(+ vbox-x (/ (- vbox-width vbox-width') 2)))
|
||||
|
||||
vbox-y'
|
||||
(case resize-type
|
||||
:top (+ vbox-y (- vbox-height vbox-height'))
|
||||
:bottom vbox-y
|
||||
(+ vbox-y (/ (- vbox-height vbox-height') 2)))]
|
||||
(-> local
|
||||
(assoc :vport size)
|
||||
(assoc-in [:vbox :x] vbox-x')
|
||||
(assoc-in [:vbox :y] vbox-y')
|
||||
(assoc-in [:vbox :width] vbox-width')
|
||||
(assoc-in [:vbox :height] vbox-height')))))))))
|
||||
|
||||
(defn start-panning []
|
||||
(ptk/reify ::start-panning
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? ::finish-panning)))
|
||||
zoom (-> (get-in state [:workspace-local :zoom]) gpt/point)]
|
||||
(when-not (get-in state [:workspace-local :panning])
|
||||
(rx/concat
|
||||
(rx/of #(-> % (assoc-in [:workspace-local :panning] true)))
|
||||
(->> stream
|
||||
(rx/filter ms/pointer-event?)
|
||||
(rx/filter #(= :delta (:source %)))
|
||||
(rx/map :pt)
|
||||
(rx/take-until stopper)
|
||||
(rx/map (fn [delta]
|
||||
(let [delta (gpt/divide delta zoom)]
|
||||
(update-viewport-position {:x #(- % (:x delta))
|
||||
:y #(- % (:y delta))})))))))))))
|
||||
|
||||
(defn finish-panning []
|
||||
(ptk/reify ::finish-panning
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :panning)))))
|
||||
|
||||
|
||||
|
||||
|
||||
;; --- Update Shape Attrs
|
||||
|
||||
(defn update-shape
|
||||
|
@ -1762,3 +1628,10 @@
|
|||
|
||||
;; Thumbnails
|
||||
(dm/export dwth/update-thumbnail)
|
||||
|
||||
;; Viewport
|
||||
(dm/export dwv/initialize-viewport)
|
||||
(dm/export dwv/update-viewport-position)
|
||||
(dm/export dwv/update-viewport-size)
|
||||
(dm/export dwv/start-panning)
|
||||
(dm/export dwv/finish-panning)
|
||||
|
|
|
@ -6,13 +6,22 @@
|
|||
|
||||
(ns app.main.data.workspace.comments
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.changes :as dwc]
|
||||
[app.main.data.workspace.common :as dwco]
|
||||
[app.main.data.workspace.drawing :as dwd]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.viewport :as dwv]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.streams :as ms]
|
||||
[app.util.router :as rt]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(declare handle-interrupt)
|
||||
|
@ -33,7 +42,7 @@
|
|||
(rx/map handle-comment-layer-click)
|
||||
(rx/take-until stoper))
|
||||
(->> stream
|
||||
(rx/filter dwc/interrupt?)
|
||||
(rx/filter dwco/interrupt?)
|
||||
(rx/map handle-interrupt)
|
||||
(rx/take-until stoper)))))))
|
||||
|
||||
|
@ -95,8 +104,76 @@
|
|||
(rx/merge
|
||||
(rx/of (rt/nav :workspace pparams qparams))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dw/initialize-viewport))
|
||||
(rx/filter (ptk/type? ::dwv/initialize-viewport))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rx/of (center-to-comment-thread thread)
|
||||
(dw/select-for-drawing :comments)
|
||||
(dwd/select-for-drawing :comments)
|
||||
(dcm/open-thread thread)))))))))
|
||||
|
||||
(defn update-comment-thread-position
|
||||
([thread [new-x new-y]]
|
||||
(update-comment-thread-position thread [new-x new-y] nil))
|
||||
|
||||
([thread [new-x new-y] frame-id]
|
||||
(us/assert ::dcm/comment-thread thread)
|
||||
(ptk/reify ::update-comment-thread-position
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [thread-id (:id thread)
|
||||
page (wsh/lookup-page state)
|
||||
page-id (:id page)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
new-frame-id (if (nil? frame-id)
|
||||
(cph/frame-id-by-position objects {:x new-x :y new-y})
|
||||
(:frame-id thread))
|
||||
thread (assoc thread
|
||||
:position {:x new-x :y new-y}
|
||||
:frame-id new-frame-id)
|
||||
|
||||
changes
|
||||
(-> (pcb/empty-changes it)
|
||||
(pcb/with-page page)
|
||||
(pcb/update-page-option :comment-threads-position assoc thread-id (select-keys thread [:position :frame-id])))]
|
||||
|
||||
(rx/merge
|
||||
(rx/of (dwc/commit-changes changes))
|
||||
(->> (rp/mutation :update-comment-thread-position thread)
|
||||
(rx/catch #(rx/throw {:type :update-comment-thread-position}))
|
||||
(rx/ignore))))))))
|
||||
|
||||
(defn move-frame-comment-threads
|
||||
"Move comment threads that are inside a frame when that frame is moved"
|
||||
[ids]
|
||||
(us/verify (s/coll-of uuid?) ids)
|
||||
|
||||
(ptk/reify ::move-frame-comment-threads
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
|
||||
is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
frame-ids? (into #{} (filter is-frame?) ids)
|
||||
|
||||
object-modifiers (:workspace-modifiers state)
|
||||
|
||||
threads-position-map (:comment-threads-position (wsh/lookup-page-options state))
|
||||
|
||||
build-move-event
|
||||
(fn [comment-thread]
|
||||
(let [frame (get objects (:frame-id comment-thread))
|
||||
frame' (-> (merge frame (get object-modifiers (:frame-id comment-thread)))
|
||||
(gsh/transform-shape))
|
||||
moved (gpt/to-vec (gpt/point (:x frame) (:y frame))
|
||||
(gpt/point (:x frame') (:y frame')))
|
||||
position (get-in threads-position-map [(:id comment-thread) :position])
|
||||
new-x (+ (:x position) (:x moved))
|
||||
new-y (+ (:y position) (:y moved))]
|
||||
(update-comment-thread-position comment-thread [new-x new-y] (:id frame))))]
|
||||
|
||||
(->> (:comment-threads state)
|
||||
(vals)
|
||||
(map #(assoc % :position (get-in threads-position-map [(:id %) :position])))
|
||||
(map #(assoc % :frame-id (get-in threads-position-map [(:id %) :frame-id])))
|
||||
(filter (comp frame-ids? :frame-id))
|
||||
(map build-move-event)
|
||||
(rx/from))))))
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[app.common.types.shape :as spec.shape]
|
||||
[app.common.types.shape.interactions :as csi]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.comments :as dc]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
|
@ -237,7 +238,9 @@
|
|||
(->> (map :id starting-flows)
|
||||
(reduce csp/remove-flow flows))))))]
|
||||
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
(rx/of
|
||||
(dc/detach-comment-thread ids)
|
||||
(dch/commit-changes changes))))))
|
||||
|
||||
(defn- viewport-center
|
||||
[state]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
[app.common.spec :as us]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.collapse :as dwc]
|
||||
[app.main.data.workspace.comments :as dwcm]
|
||||
[app.main.data.workspace.guides :as dwg]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
|
@ -201,6 +202,7 @@
|
|||
(rx/of (dwu/start-undo-transaction))
|
||||
(rx/empty))
|
||||
(rx/of (dwg/move-frame-guides ids-with-children)
|
||||
(dwcm/move-frame-comment-threads ids-with-children)
|
||||
(dch/update-shapes
|
||||
ids-with-children
|
||||
(fn [shape]
|
||||
|
|
148
frontend/src/app/main/data/workspace/viewport.cljs
Normal file
148
frontend/src/app/main/data/workspace/viewport.cljs
Normal file
|
@ -0,0 +1,148 @@
|
|||
;; 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) UXBOX Labs SL
|
||||
|
||||
(ns app.main.data.workspace.viewport
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.align :as gal]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.streams :as ms]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn initialize-viewport
|
||||
[{:keys [width height] :as size}]
|
||||
(letfn [(update* [{:keys [vport] :as local}]
|
||||
(let [wprop (/ (:width vport) width)
|
||||
hprop (/ (:height vport) height)]
|
||||
(-> local
|
||||
(assoc :vport size)
|
||||
(update :vbox (fn [vbox]
|
||||
(-> vbox
|
||||
(update :width #(/ % wprop))
|
||||
(update :height #(/ % hprop))))))))
|
||||
|
||||
(initialize [state local]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shapes (cph/get-immediate-children objects)
|
||||
srect (gsh/selection-rect shapes)
|
||||
local (assoc local :vport size :zoom 1)]
|
||||
(cond
|
||||
(or (not (d/num? (:width srect)))
|
||||
(not (d/num? (:height srect))))
|
||||
(assoc local :vbox (assoc size :x 0 :y 0))
|
||||
|
||||
(or (> (:width srect) width)
|
||||
(> (:height srect) height))
|
||||
(let [srect (gal/adjust-to-viewport size srect {:padding 40})
|
||||
zoom (/ (:width size) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect)))
|
||||
|
||||
:else
|
||||
(assoc local :vbox (assoc size
|
||||
:x (+ (:x srect) (/ (- (:width srect) width) 2))
|
||||
:y (+ (:y srect) (/ (- (:height srect) height) 2)))))))
|
||||
|
||||
(setup [state local]
|
||||
(if (and (:vbox local) (:vport local))
|
||||
(update* local)
|
||||
(initialize state local)))]
|
||||
|
||||
(ptk/reify ::initialize-viewport
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
(fn [local]
|
||||
(setup state local)))))))
|
||||
|
||||
(defn update-viewport-position
|
||||
[{:keys [x y] :or {x identity y identity}}]
|
||||
(us/assert fn? x)
|
||||
(us/assert fn? y)
|
||||
(ptk/reify ::update-viewport-position
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:workspace-local :vbox]
|
||||
(fn [vbox]
|
||||
(-> vbox
|
||||
(update :x x)
|
||||
(update :y y)))))))
|
||||
|
||||
(defn update-viewport-size
|
||||
[resize-type {:keys [width height] :as size}]
|
||||
(ptk/reify ::update-viewport-size
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(if (or (nil? vport)
|
||||
(mth/almost-zero? width)
|
||||
(mth/almost-zero? height))
|
||||
;; If we have a resize to zero just keep the old value
|
||||
local
|
||||
(let [wprop (/ (:width vport) width)
|
||||
hprop (/ (:height vport) height)
|
||||
|
||||
vbox (:vbox local)
|
||||
vbox-x (:x vbox)
|
||||
vbox-y (:y vbox)
|
||||
vbox-width (:width vbox)
|
||||
vbox-height (:height vbox)
|
||||
|
||||
vbox-width' (/ vbox-width wprop)
|
||||
vbox-height' (/ vbox-height hprop)
|
||||
|
||||
vbox-x'
|
||||
(case resize-type
|
||||
:left (+ vbox-x (- vbox-width vbox-width'))
|
||||
:right vbox-x
|
||||
(+ vbox-x (/ (- vbox-width vbox-width') 2)))
|
||||
|
||||
vbox-y'
|
||||
(case resize-type
|
||||
:top (+ vbox-y (- vbox-height vbox-height'))
|
||||
:bottom vbox-y
|
||||
(+ vbox-y (/ (- vbox-height vbox-height') 2)))]
|
||||
(-> local
|
||||
(assoc :vport size)
|
||||
(assoc-in [:vbox :x] vbox-x')
|
||||
(assoc-in [:vbox :y] vbox-y')
|
||||
(assoc-in [:vbox :width] vbox-width')
|
||||
(assoc-in [:vbox :height] vbox-height')))))))))
|
||||
|
||||
(defn start-panning []
|
||||
(ptk/reify ::start-panning
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? ::finish-panning)))
|
||||
zoom (-> (get-in state [:workspace-local :zoom]) gpt/point)]
|
||||
(when-not (get-in state [:workspace-local :panning])
|
||||
(rx/concat
|
||||
(rx/of #(-> % (assoc-in [:workspace-local :panning] true)))
|
||||
(->> stream
|
||||
(rx/filter ms/pointer-event?)
|
||||
(rx/filter #(= :delta (:source %)))
|
||||
(rx/map :pt)
|
||||
(rx/take-until stopper)
|
||||
(rx/map (fn [delta]
|
||||
(let [delta (gpt/divide delta zoom)]
|
||||
(update-viewport-position {:x #(- % (:x delta))
|
||||
:y #(- % (:y delta))})))))))))))
|
||||
|
||||
(defn finish-panning []
|
||||
(ptk/reify ::finish-panning
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :panning)))))
|
|
@ -9,6 +9,7 @@
|
|||
[app.config :as cfg]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.comments :as dwcm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
|
@ -183,7 +184,7 @@
|
|||
[:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]]]))
|
||||
|
||||
(mf/defc comment-item
|
||||
[{:keys [comment thread users] :as props}]
|
||||
[{:keys [comment thread users origin] :as props}]
|
||||
(let [owner (get users (:owner-id comment))
|
||||
profile (mf/deref refs/profile)
|
||||
options (mf/use-state false)
|
||||
|
@ -210,7 +211,9 @@
|
|||
(mf/use-callback
|
||||
(mf/deps thread)
|
||||
#(st/emit! (dcm/close-thread)
|
||||
(dcm/delete-comment-thread thread)))
|
||||
(if (= origin :viewer)
|
||||
(dcm/delete-comment-thread-on-viewer thread)
|
||||
(dcm/delete-comment-thread-on-workspace thread))))
|
||||
|
||||
|
||||
on-delete-thread
|
||||
|
@ -278,9 +281,10 @@
|
|||
(l/derived (l/in [:comments id]) st/state))
|
||||
|
||||
(mf/defc thread-comments
|
||||
[{:keys [thread zoom users]}]
|
||||
[{:keys [thread zoom users origin]}]
|
||||
(let [ref (mf/use-ref)
|
||||
pos (:position thread)
|
||||
|
||||
pos-x (+ (* (:x pos) zoom) 14)
|
||||
pos-y (- (* (:y pos) zoom) 14)
|
||||
|
||||
|
@ -313,33 +317,134 @@
|
|||
[:div.comments
|
||||
[:& comment-item {:comment comment
|
||||
:users users
|
||||
:thread thread}]
|
||||
:thread thread
|
||||
:origin origin}]
|
||||
(for [item (rest comments)]
|
||||
[:*
|
||||
[:hr]
|
||||
[:& comment-item {:comment item :users users}]])
|
||||
[:& comment-item {:comment item
|
||||
:users users
|
||||
:origin origin}]])
|
||||
[:div {:ref ref}]]
|
||||
[:& reply-form {:thread thread}]])))
|
||||
|
||||
(defn use-buble
|
||||
[zoom {:keys [position frame-id]}]
|
||||
(let [dragging-ref (mf/use-ref false)
|
||||
start-ref (mf/use-ref nil)
|
||||
|
||||
state (mf/use-state {:hover false
|
||||
:new-position-x nil
|
||||
:new-position-y nil
|
||||
:new-frame-id frame-id})
|
||||
|
||||
on-pointer-down
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(dom/capture-pointer event)
|
||||
(mf/set-ref-val! dragging-ref true)
|
||||
(mf/set-ref-val! start-ref (dom/get-client-position event))))
|
||||
|
||||
on-pointer-up
|
||||
(mf/use-callback
|
||||
(mf/deps (select-keys @state [:new-position-x :new-position-y :new-frame-id]))
|
||||
(fn [_ thread]
|
||||
(when (and
|
||||
(some? (:new-position-x @state))
|
||||
(some? (:new-position-y @state)))
|
||||
(st/emit! (dwcm/update-comment-thread-position thread [(:new-position-x @state) (:new-position-y @state)])))))
|
||||
|
||||
on-lost-pointer-capture
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(dom/release-pointer event)
|
||||
(mf/set-ref-val! dragging-ref false)
|
||||
(mf/set-ref-val! start-ref nil)
|
||||
(swap! state assoc :new-position-x nil)
|
||||
(swap! state assoc :new-position-y nil)))
|
||||
|
||||
on-mouse-move
|
||||
(mf/use-callback
|
||||
(mf/deps position zoom)
|
||||
(fn [event]
|
||||
(when-let [_ (mf/ref-val dragging-ref)]
|
||||
(let [start-pt (mf/ref-val start-ref)
|
||||
current-pt (dom/get-client-position event)
|
||||
delta-x (/ (- (:x current-pt) (:x start-pt)) zoom)
|
||||
delta-y (/ (- (:y current-pt) (:y start-pt)) zoom)]
|
||||
(swap! state assoc
|
||||
:new-position-x (+ (:x position) delta-x)
|
||||
:new-position-y (+ (:y position) delta-y))))))]
|
||||
|
||||
{:on-pointer-down on-pointer-down
|
||||
:on-pointer-up on-pointer-up
|
||||
:on-mouse-move on-mouse-move
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
:state state}))
|
||||
|
||||
(mf/defc thread-bubble
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [thread zoom on-click] :as params}]
|
||||
[{:keys [thread zoom open? on-click origin]}]
|
||||
(let [pos (:position thread)
|
||||
pos-x (* (:x pos) zoom)
|
||||
pos-y (* (:y pos) zoom)
|
||||
on-click* (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(on-click thread))]
|
||||
drag? (mf/use-ref nil)
|
||||
was-open? (mf/use-ref nil)
|
||||
|
||||
{:keys [on-pointer-down
|
||||
on-pointer-up
|
||||
on-mouse-move
|
||||
state
|
||||
on-lost-pointer-capture]} (use-buble zoom thread)
|
||||
|
||||
pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
|
||||
pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
|
||||
|
||||
on-pointer-down* (mf/use-callback
|
||||
(mf/deps origin was-open? open? drag? on-pointer-down)
|
||||
(fn [event]
|
||||
(when (not= origin :viewer)
|
||||
(mf/set-ref-val! was-open? open?)
|
||||
(when open? (st/emit! (dcm/close-thread)))
|
||||
(mf/set-ref-val! drag? false)
|
||||
(dom/stop-propagation event)
|
||||
(on-pointer-down event))))
|
||||
|
||||
on-pointer-up* (mf/use-callback
|
||||
(mf/deps origin thread was-open? drag? on-pointer-up)
|
||||
(fn [event]
|
||||
(when (not= origin :viewer)
|
||||
(dom/stop-propagation event)
|
||||
(on-pointer-up event thread)
|
||||
|
||||
(when (or (and (mf/ref-val was-open?) (mf/ref-val drag?))
|
||||
(and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
|
||||
(st/emit! (dcm/open-thread thread))))))
|
||||
|
||||
on-mouse-move* (mf/use-callback
|
||||
(mf/deps origin drag? on-mouse-move)
|
||||
(fn [event]
|
||||
(when (not= origin :viewer)
|
||||
(mf/set-ref-val! drag? true)
|
||||
(dom/stop-propagation event)
|
||||
(on-mouse-move event))))
|
||||
|
||||
on-click* (mf/use-callback
|
||||
(mf/deps origin thread on-click)
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(when (= origin :viewer)
|
||||
(on-click thread))))]
|
||||
|
||||
[:div.thread-bubble
|
||||
{:style {:top (str pos-y "px")
|
||||
:left (str pos-x "px")}
|
||||
:on-mouse-down (fn [event]
|
||||
(dom/prevent-default event))
|
||||
:on-pointer-down on-pointer-down*
|
||||
:on-pointer-up on-pointer-up*
|
||||
:on-mouse-move on-mouse-move*
|
||||
:on-click on-click*
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
:class (dom/classnames
|
||||
:resolved (:is-resolved thread)
|
||||
:unread (pos? (:count-unread-comments thread)))
|
||||
:on-click on-click*}
|
||||
:unread (pos? (:count-unread-comments thread)))}
|
||||
[:span (:seqn thread)]]))
|
||||
|
||||
(mf/defc comment-thread
|
||||
|
|
|
@ -85,6 +85,8 @@
|
|||
(mf/defc comments-layer
|
||||
[{:keys [zoom file users frame page] :as props}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
threads-position-ref (l/derived (l/in [:viewer :pages (:id page) :options :comment-threads-position]) st/state)
|
||||
threads-position-map (mf/deref threads-position-ref)
|
||||
threads-map (mf/deref threads-ref)
|
||||
|
||||
frame-corner (-> frame :points gsh/points->selrect gpt/point)
|
||||
|
@ -96,7 +98,16 @@
|
|||
|
||||
cstate (mf/deref refs/comments-local)
|
||||
|
||||
update-thread-position (fn update-thread-position [thread]
|
||||
(if (contains? threads-position-map (:id thread))
|
||||
(-> thread
|
||||
(assoc :position (get-in threads-position-map [(:id thread) :position]))
|
||||
(assoc :frame-id (get-in threads-position-map [(:id thread) :frame-id])))
|
||||
thread))
|
||||
|
||||
threads (->> (vals threads-map)
|
||||
(map update-thread-position)
|
||||
(filter #(= (:frame-id %) (:id frame)))
|
||||
(dcm/apply-filters cstate profile)
|
||||
(filter (fn [{:keys [position]}]
|
||||
(gsh/has-point? frame position))))
|
||||
|
@ -135,8 +146,10 @@
|
|||
(mf/use-callback
|
||||
(mf/deps frame)
|
||||
(fn [draft]
|
||||
(let [params (update draft :position gpt/transform modifier2)]
|
||||
(st/emit! (dcm/create-thread params)
|
||||
(let [params (-> draft
|
||||
(update :position gpt/transform modifier2)
|
||||
(assoc :frame-id (:id frame)))]
|
||||
(st/emit! (dcm/create-thread-on-viewer params)
|
||||
(dcm/close-thread)))))]
|
||||
|
||||
[:div.comments-section {:on-click on-click}
|
||||
|
@ -148,7 +161,8 @@
|
|||
:zoom zoom
|
||||
:on-click on-bubble-click
|
||||
:open? (= (:id item) (:open cstate))
|
||||
:key (:seqn item)}]))
|
||||
:key (:seqn item)
|
||||
:origin :viewer}]))
|
||||
|
||||
(when-let [id (:open cstate)]
|
||||
(when-let [thread (as-> (get threads-map id) $
|
||||
|
|
|
@ -144,7 +144,7 @@
|
|||
on-pointer-move (actions/on-pointer-move viewport-ref zoom move-stream)
|
||||
on-pointer-up (actions/on-pointer-up)
|
||||
on-move-selected (actions/on-move-selected hover hover-ids selected space?)
|
||||
on-menu-selected (actions/on-menu-selected hover hover-ids selected)
|
||||
on-menu-selected (actions/on-menu-selected hover hover-ids selected)
|
||||
|
||||
on-frame-enter (actions/on-frame-enter frame-hover)
|
||||
on-frame-leave (actions/on-frame-leave frame-hover)
|
||||
|
|
|
@ -12,27 +12,32 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.ui.comments :as cmt]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc comments-layer
|
||||
[{:keys [vbox vport zoom file-id page-id drawing] :as props}]
|
||||
(let [pos-x (* (- (:x vbox)) zoom)
|
||||
pos-y (* (- (:y vbox)) zoom)
|
||||
(let [pos-x (* (- (:x vbox)) zoom)
|
||||
pos-y (* (- (:y vbox)) zoom)
|
||||
|
||||
profile (mf/deref refs/profile)
|
||||
users (mf/deref refs/current-file-comments-users)
|
||||
local (mf/deref refs/comments-local)
|
||||
threads-map (mf/deref refs/threads-ref)
|
||||
profile (mf/deref refs/profile)
|
||||
users (mf/deref refs/current-file-comments-users)
|
||||
local (mf/deref refs/comments-local)
|
||||
threads-position-ref (l/derived (l/in [:workspace-data :pages-index page-id :options :comment-threads-position]) st/state)
|
||||
threads-position-map (mf/deref threads-position-ref)
|
||||
threads-map (mf/deref refs/threads-ref)
|
||||
|
||||
threads (->> (vals threads-map)
|
||||
(filter #(= (:page-id %) page-id))
|
||||
(dcm/apply-filters local profile))
|
||||
update-thread-position (fn update-thread-position [thread]
|
||||
(if (contains? threads-position-map (:id thread))
|
||||
(-> thread
|
||||
(assoc :position (get-in threads-position-map [(:id thread) :position]))
|
||||
(assoc :frame-id (get-in threads-position-map [(:id thread) :frame-id])))
|
||||
thread))
|
||||
|
||||
on-bubble-click
|
||||
(fn [{:keys [id] :as thread}]
|
||||
(if (= (:open local) id)
|
||||
(st/emit! (dcm/close-thread))
|
||||
(st/emit! (dcm/open-thread thread))))
|
||||
threads (->> (vals threads-map)
|
||||
(filter #(= (:page-id %) page-id))
|
||||
(mapv update-thread-position)
|
||||
(dcm/apply-filters local profile))
|
||||
|
||||
on-draft-cancel
|
||||
(mf/use-callback
|
||||
|
@ -41,7 +46,7 @@
|
|||
on-draft-submit
|
||||
(mf/use-callback
|
||||
(fn [draft]
|
||||
(st/emit! (dcm/create-thread draft))))]
|
||||
(st/emit! (dcm/create-thread-on-workspace draft))))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps file-id)
|
||||
|
@ -58,13 +63,12 @@
|
|||
(for [item threads]
|
||||
[:& cmt/thread-bubble {:thread item
|
||||
:zoom zoom
|
||||
:on-click on-bubble-click
|
||||
:open? (= (:id item) (:open local))
|
||||
:key (:seqn item)}])
|
||||
|
||||
(when-let [id (:open local)]
|
||||
(when-let [thread (get threads-map id)]
|
||||
[:& cmt/thread-comments {:thread thread
|
||||
[:& cmt/thread-comments {:thread (update-thread-position thread)
|
||||
:users users
|
||||
:zoom zoom}]))
|
||||
|
||||
|
@ -73,5 +77,3 @@
|
|||
:on-cancel on-draft-cancel
|
||||
:on-submit on-draft-submit
|
||||
:zoom zoom}])]]]))
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue