mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 23:49:45 -05:00
♻️ Refactor viewer comments related components
This commit is contained in:
parent
50d371c14b
commit
a37c1f7fca
2 changed files with 162 additions and 132 deletions
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.ui.comments
|
(ns app.main.ui.comments
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.main.data.comments :as dcm]
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
@ -110,8 +111,10 @@
|
||||||
[:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]])]))
|
[:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]])]))
|
||||||
|
|
||||||
(mf/defc draft-thread
|
(mf/defc draft-thread
|
||||||
[{:keys [draft zoom on-cancel on-submit] :as props}]
|
[{:keys [draft zoom on-cancel on-submit position-modifier]}]
|
||||||
(let [position (:position draft)
|
(let [position (cond-> (:position draft)
|
||||||
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
content (:content draft)
|
content (:content draft)
|
||||||
pos-x (* (:x position) zoom)
|
pos-x (* (:x position) zoom)
|
||||||
pos-y (* (:y position) zoom)
|
pos-y (* (:y position) zoom)
|
||||||
|
@ -281,9 +284,12 @@
|
||||||
(l/derived (l/in [:comments id]) st/state))
|
(l/derived (l/in [:comments id]) st/state))
|
||||||
|
|
||||||
(mf/defc thread-comments
|
(mf/defc thread-comments
|
||||||
[{:keys [thread zoom users origin]}]
|
{::mf/wrap [mf/memo]}
|
||||||
|
[{:keys [thread zoom users origin position-modifier]}]
|
||||||
(let [ref (mf/use-ref)
|
(let [ref (mf/use-ref)
|
||||||
pos (:position thread)
|
pos (cond-> (:position thread)
|
||||||
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
|
|
||||||
pos-x (+ (* (:x pos) zoom) 14)
|
pos-x (+ (* (:x pos) zoom) 14)
|
||||||
pos-y (- (* (:y pos) zoom) 14)
|
pos-y (- (* (:y pos) zoom) 14)
|
||||||
|
@ -384,9 +390,12 @@
|
||||||
|
|
||||||
(mf/defc thread-bubble
|
(mf/defc thread-bubble
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [thread zoom open? on-click origin]}]
|
[{:keys [thread zoom open? on-click origin position-modifier]}]
|
||||||
(let [pos (:position thread)
|
(let [pos (cond-> (:position thread)
|
||||||
drag? (mf/use-ref nil)
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
|
|
||||||
|
drag? (mf/use-ref nil)
|
||||||
was-open? (mf/use-ref nil)
|
was-open? (mf/use-ref nil)
|
||||||
|
|
||||||
{:keys [on-pointer-down
|
{:keys [on-pointer-down
|
||||||
|
@ -398,41 +407,45 @@
|
||||||
pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
|
pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
|
||||||
pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
|
pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
|
||||||
|
|
||||||
on-pointer-down* (mf/use-callback
|
on-pointer-down*
|
||||||
(mf/deps origin was-open? open? drag? on-pointer-down)
|
(mf/use-callback
|
||||||
(fn [event]
|
(mf/deps origin was-open? open? drag? on-pointer-down)
|
||||||
(when (not= origin :viewer)
|
(fn [event]
|
||||||
(mf/set-ref-val! was-open? open?)
|
(when (not= origin :viewer)
|
||||||
(when open? (st/emit! (dcm/close-thread)))
|
(mf/set-ref-val! was-open? open?)
|
||||||
(mf/set-ref-val! drag? false)
|
(when open? (st/emit! (dcm/close-thread)))
|
||||||
(dom/stop-propagation event)
|
(mf/set-ref-val! drag? false)
|
||||||
(on-pointer-down event))))
|
(dom/stop-propagation event)
|
||||||
|
(on-pointer-down event))))
|
||||||
|
|
||||||
on-pointer-up* (mf/use-callback
|
on-pointer-up*
|
||||||
(mf/deps origin thread was-open? drag? on-pointer-up)
|
(mf/use-callback
|
||||||
(fn [event]
|
(mf/deps origin thread was-open? drag? on-pointer-up)
|
||||||
(when (not= origin :viewer)
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(when (not= origin :viewer)
|
||||||
(on-pointer-up event thread)
|
(dom/stop-propagation event)
|
||||||
|
(on-pointer-up event thread)
|
||||||
|
|
||||||
(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?))))
|
||||||
(st/emit! (dcm/open-thread thread))))))
|
(st/emit! (dcm/open-thread thread))))))
|
||||||
|
|
||||||
on-mouse-move* (mf/use-callback
|
on-mouse-move*
|
||||||
(mf/deps origin drag? on-mouse-move)
|
(mf/use-callback
|
||||||
(fn [event]
|
(mf/deps origin drag? on-mouse-move)
|
||||||
(when (not= origin :viewer)
|
(fn [event]
|
||||||
(mf/set-ref-val! drag? true)
|
(when (not= origin :viewer)
|
||||||
(dom/stop-propagation event)
|
(mf/set-ref-val! drag? true)
|
||||||
(on-mouse-move event))))
|
(dom/stop-propagation event)
|
||||||
|
(on-mouse-move event))))
|
||||||
|
|
||||||
on-click* (mf/use-callback
|
on-click*
|
||||||
(mf/deps origin thread on-click)
|
(mf/use-callback
|
||||||
(fn [event]
|
(mf/deps origin thread on-click)
|
||||||
(dom/stop-propagation event)
|
(fn [event]
|
||||||
(when (= origin :viewer)
|
(dom/stop-propagation event)
|
||||||
(on-click thread))))]
|
(when (= origin :viewer)
|
||||||
|
(on-click thread))))]
|
||||||
|
|
||||||
[:div.thread-bubble
|
[:div.thread-bubble
|
||||||
{:style {:top (str pos-y "px")
|
{:style {:top (str pos-y "px")
|
||||||
|
@ -448,7 +461,7 @@
|
||||||
[:span (:seqn thread)]]))
|
[:span (:seqn thread)]]))
|
||||||
|
|
||||||
(mf/defc comment-thread
|
(mf/defc comment-thread
|
||||||
[{:keys [item users on-click] :as props}]
|
[{:keys [item users on-click]}]
|
||||||
(let [owner (get users (:owner-id item))
|
(let [owner (get users (:owner-id item))
|
||||||
on-click*
|
on-click*
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
(ns app.main.ui.viewer.comments
|
(ns app.main.ui.viewer.comments
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
@ -23,132 +25,145 @@
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(mf/defc comments-menu
|
(mf/defc comments-menu
|
||||||
|
{::mf/wrap [mf/memo]
|
||||||
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [{cmode :mode cshow :show clist :list} (mf/deref refs/comments-local)
|
(let [local (mf/deref refs/comments-local)
|
||||||
|
owner-filter (:owner-filter local)
|
||||||
|
status-filter (:status-filter local)
|
||||||
|
show-sidebar? (:show-sidebar? local)
|
||||||
|
|
||||||
show-dropdown? (mf/use-state false)
|
show-dropdown? (mf/use-state false)
|
||||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||||
|
|
||||||
update-mode
|
update-option (mf/use-fn
|
||||||
(mf/use-callback
|
(fn [event]
|
||||||
(fn [mode]
|
(let [target (dom/get-current-target event)
|
||||||
(st/emit! (dcm/update-filters {:mode mode}))))
|
key (d/read-string (dom/get-attribute target "data-key"))
|
||||||
|
val (d/read-string (dom/get-attribute target "data-val"))]
|
||||||
update-show
|
(st/emit! (dcm/update-options {key val})))))]
|
||||||
(mf/use-callback
|
|
||||||
(fn [mode]
|
|
||||||
(st/emit! (dcm/update-filters {:show mode}))))
|
|
||||||
|
|
||||||
update-list
|
|
||||||
(mf/use-callback
|
|
||||||
(fn [show-list]
|
|
||||||
(st/emit! (dcm/update-filters {:list show-list}))))]
|
|
||||||
|
|
||||||
[:div.view-options {:on-click toggle-dropdown}
|
[:div.view-options {:on-click toggle-dropdown}
|
||||||
[:span.label (tr "labels.comments")]
|
[:span.label (tr "labels.comments")]
|
||||||
[:span.icon i/arrow-down]
|
[:span.icon i/arrow-down]
|
||||||
[:& dropdown {:show @show-dropdown?
|
[:& dropdown {:show @show-dropdown?
|
||||||
:on-close hide-dropdown}
|
:on-close hide-dropdown}
|
||||||
|
|
||||||
[:ul.dropdown.with-check
|
[:ul.dropdown.with-check
|
||||||
[:li {:class (dom/classnames :selected (= :all cmode))
|
[:li {:class (dom/classnames :selected (= :all owner-filter))
|
||||||
:on-click #(update-mode :all)}
|
:data-key ":owner-filter"
|
||||||
|
:data-val ":all"
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-all-comments")]]
|
[:span.label (tr "labels.show-all-comments")]]
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :yours cmode))
|
[:li {:class (dom/classnames :selected (= :yours owner-filter))
|
||||||
:on-click #(update-mode :yours)}
|
:data-key ":owner-filter"
|
||||||
|
:data-val ":yours"
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-your-comments")]]
|
[:span.label (tr "labels.show-your-comments")]]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
[:li {:class (dom/classnames :selected (= :pending status-filter))
|
||||||
:on-click #(update-show (if (= :pending cshow) :all :pending))}
|
:data-key ":status-filter"
|
||||||
|
:data-val (if (= :pending status-filter) ":all" ":pending")
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.hide-resolved-comments")]]
|
[:span.label (tr "labels.hide-resolved-comments")]]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
[:li {:class (dom/classnames :selected show-sidebar?)
|
||||||
[:li {:class (dom/classnames :selected (= :show clist))
|
:data-key ":show-sidebar?"
|
||||||
:on-click #(update-list (if (= :show clist) :hide :show))}
|
:data-val (if show-sidebar? "false" "true")
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-comments-list")]]]]]))
|
[:span.label (tr "labels.show-comments-list")]]]]]))
|
||||||
|
|
||||||
|
|
||||||
(def threads-ref
|
(defn- update-thread-position [positions {:keys [id] :as thread}]
|
||||||
(l/derived :comment-threads st/state))
|
(if-let [data (get positions id)]
|
||||||
|
(-> thread
|
||||||
(def comments-local-ref
|
(assoc :position (:position data))
|
||||||
(l/derived :comments-local st/state))
|
(assoc :frame-id (:frame-id data)))
|
||||||
|
thread))
|
||||||
|
|
||||||
(mf/defc comments-layer
|
(mf/defc comments-layer
|
||||||
[{:keys [zoom file users frame page] :as props}]
|
[{:keys [zoom file users frame page] :as props}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(prn "comments-layer")
|
||||||
threads-position-ref (l/derived (l/in [:viewer :pages (:id page) :options :comment-threads-position]) st/state)
|
(let [profile (mf/deref refs/profile)
|
||||||
threads-position-map (mf/deref threads-position-ref)
|
local (mf/deref refs/comments-local)
|
||||||
threads-map (mf/deref threads-ref)
|
|
||||||
|
|
||||||
frame-corner (-> frame :points gsh/points->selrect gpt/point)
|
open-thread-id (:open local)
|
||||||
modifier1 (-> (gmt/matrix)
|
page-id (:id page)
|
||||||
(gmt/translate (gpt/negate frame-corner)))
|
file-id (:id file)
|
||||||
|
frame-id (:id frame)
|
||||||
|
|
||||||
modifier2 (-> (gpt/point frame-corner)
|
tpos-ref (mf/with-memo [page-id]
|
||||||
(gmt/translate-matrix))
|
(-> (l/in [:pages page-id :options :comment-threads-position])
|
||||||
|
(l/derived refs/viewer-data)))
|
||||||
|
|
||||||
cstate (mf/deref refs/comments-local)
|
positions (mf/deref tpos-ref)
|
||||||
|
threads-map (mf/deref refs/comment-threads)
|
||||||
|
|
||||||
update-thread-position (fn update-thread-position [thread]
|
frame-corner (mf/with-memo [frame]
|
||||||
(if (contains? threads-position-map (:id thread))
|
(-> frame :points gsh/points->selrect gpt/point))
|
||||||
(-> thread
|
|
||||||
(assoc :position (get-in threads-position-map [(:id thread) :position]))
|
modifier1 (mf/with-memo [frame-corner]
|
||||||
(assoc :frame-id (get-in threads-position-map [(:id thread) :frame-id])))
|
(-> (gmt/matrix)
|
||||||
thread))
|
(gmt/translate (gpt/negate frame-corner))))
|
||||||
|
modifier2 (mf/with-memo [frame-corner]
|
||||||
|
(-> (gpt/point frame-corner)
|
||||||
|
(gmt/translate-matrix)))
|
||||||
|
|
||||||
|
|
||||||
|
threads (mf/with-memo [threads-map positions]
|
||||||
|
(->> (vals threads-map)
|
||||||
|
(map (partial update-thread-position positions))
|
||||||
|
(filter #(= (:frame-id %) (:id frame)))
|
||||||
|
(dcm/apply-filters local profile)
|
||||||
|
(filter (fn [{:keys [position]}]
|
||||||
|
(gsh/has-point? frame position)))))
|
||||||
|
|
||||||
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))))
|
|
||||||
|
|
||||||
on-bubble-click
|
on-bubble-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps cstate)
|
(mf/deps open-thread-id)
|
||||||
(fn [thread]
|
(fn [{:keys [id] :as thread}]
|
||||||
(if (= (:open cstate) (:id thread))
|
(st/emit! (if (= open-thread-id id)
|
||||||
(st/emit! (dcm/close-thread))
|
(dcm/close-thread)
|
||||||
(st/emit! (-> (dcm/open-thread thread)
|
(-> (dcm/open-thread thread)
|
||||||
(with-meta {::ev/origin "viewer"}))))))
|
(with-meta {::ev/origin "viewer"}))))))
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps cstate frame page file zoom)
|
(mf/deps open-thread-id zoom page-id file-id modifier2)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(if (some? (:open cstate))
|
(if (some? open-thread-id)
|
||||||
(st/emit! (dcm/close-thread))
|
(st/emit! (dcm/close-thread))
|
||||||
(let [event (.-nativeEvent ^js event)
|
(let [event (dom/event->native-event event)
|
||||||
viewport-point (dom/get-offset-position event)
|
position (-> (dom/get-offset-position event)
|
||||||
viewport-point (-> viewport-point (update :x #(/ % zoom)) (update :y #(/ % zoom)))
|
(update :x #(/ % zoom))
|
||||||
position (gpt/transform viewport-point modifier2)
|
(update :y #(/ % zoom))
|
||||||
|
(gpt/transform modifier2))
|
||||||
params {:position position
|
params {:position position
|
||||||
:page-id (:id page)
|
:page-id (:id page)
|
||||||
:file-id (:id file)}]
|
:file-id (:id file)}]
|
||||||
(st/emit! (dcm/create-draft params))))))
|
(st/emit! (dcm/create-draft params))))))
|
||||||
|
|
||||||
on-draft-cancel
|
on-draft-cancel
|
||||||
(mf/use-callback
|
(mf/use-fn #(st/emit! (dcm/close-thread)))
|
||||||
(mf/deps cstate)
|
|
||||||
#(st/emit! (dcm/close-thread)))
|
|
||||||
|
|
||||||
on-draft-submit
|
on-draft-submit
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps frame)
|
(mf/deps frame-id modifier2)
|
||||||
(fn [draft]
|
(fn [draft]
|
||||||
(let [params (-> draft
|
(let [params (-> draft
|
||||||
(update :position gpt/transform modifier2)
|
(update :position gpt/transform modifier2)
|
||||||
(assoc :frame-id (:id frame)))]
|
(assoc :frame-id frame-id))]
|
||||||
(st/emit! (dcm/create-thread-on-viewer params)
|
(st/emit! (dcm/create-thread-on-viewer params)
|
||||||
(dcm/close-thread)))))]
|
(dcm/close-thread)))))]
|
||||||
|
|
||||||
|
@ -156,35 +171,37 @@
|
||||||
[:div.viewer-comments-container
|
[:div.viewer-comments-container
|
||||||
[:div.threads
|
[:div.threads
|
||||||
(for [item threads]
|
(for [item threads]
|
||||||
(let [item (update item :position gpt/transform modifier1)]
|
[:& cmt/thread-bubble
|
||||||
[:& cmt/thread-bubble {:thread item
|
{:thread item
|
||||||
:zoom zoom
|
:position-modifier modifier1
|
||||||
:on-click on-bubble-click
|
:zoom zoom
|
||||||
:open? (= (:id item) (:open cstate))
|
:on-click on-bubble-click
|
||||||
:key (:seqn item)
|
:open? (= (:id item) (:open local))
|
||||||
:origin :viewer}]))
|
:key (:seqn item)
|
||||||
|
:origin :viewer}])
|
||||||
|
|
||||||
(when-let [id (:open cstate)]
|
(when-let [thread (get threads-map open-thread-id)]
|
||||||
(when-let [thread (as-> (get threads-map id) $
|
[:& cmt/thread-comments
|
||||||
(when (some? $)
|
{:thread thread
|
||||||
(update $ :position gpt/transform modifier1)))]
|
:position-modifier modifier1
|
||||||
[:& cmt/thread-comments {:thread thread
|
:users users
|
||||||
:users users
|
:zoom zoom}])
|
||||||
:zoom zoom}]))
|
|
||||||
|
|
||||||
(when-let [draft (:draft cstate)]
|
(when-let [draft (:draft local)]
|
||||||
[:& cmt/draft-thread {:draft (update draft :position gpt/transform modifier1)
|
[:& cmt/draft-thread
|
||||||
:on-cancel on-draft-cancel
|
{:draft draft
|
||||||
:on-submit on-draft-submit
|
:position-modifier modifier1
|
||||||
:zoom zoom}])]]]))
|
:on-cancel on-draft-cancel
|
||||||
|
:on-submit on-draft-submit
|
||||||
|
:zoom zoom}])]]]))
|
||||||
|
|
||||||
(mf/defc comments-sidebar
|
(mf/defc comments-sidebar
|
||||||
[{:keys [users frame page]}]
|
[{:keys [users frame page]}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [profile (mf/deref refs/profile)
|
||||||
cstate (mf/deref refs/comments-local)
|
local (mf/deref refs/comments-local)
|
||||||
threads-map (mf/deref threads-ref)
|
threads-map (mf/deref refs/comment-threads)
|
||||||
threads (->> (vals threads-map)
|
threads (->> (vals threads-map)
|
||||||
(dcm/apply-filters cstate profile)
|
(dcm/apply-filters local profile)
|
||||||
(filter (fn [{:keys [position]}]
|
(filter (fn [{:keys [position]}]
|
||||||
(gsh/has-point? frame position))))]
|
(gsh/has-point? frame position))))]
|
||||||
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
||||||
|
|
Loading…
Add table
Reference in a new issue