mirror of
https://github.com/penpot/penpot.git
synced 2025-06-03 01:01:37 +02:00
245 lines
8.9 KiB
Clojure
245 lines
8.9 KiB
Clojure
;; 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.ui.viewer.comments
|
|
(:require-macros [app.main.style :as stl])
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.geom.matrix :as gmt]
|
|
[app.common.geom.point :as gpt]
|
|
[app.common.geom.rect :as grc]
|
|
[app.common.geom.shapes :as gsh]
|
|
[app.main.data.comments :as dcm]
|
|
[app.main.data.events :as ev]
|
|
[app.main.refs :as refs]
|
|
[app.main.store :as st]
|
|
[app.main.ui.comments :as cmt]
|
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
|
[app.main.ui.icons :as i]
|
|
[app.main.ui.workspace.comments :as wc]
|
|
[app.util.dom :as dom]
|
|
[app.util.i18n :as i18n :refer [tr]]
|
|
[okulary.core :as l]
|
|
[rumext.v2 :as mf]))
|
|
|
|
(mf/defc comments-menu
|
|
{::mf/props :obj
|
|
::mf/memo true}
|
|
[]
|
|
(let [state (mf/deref refs/comments-local)
|
|
cmode (:mode state)
|
|
cshow (:show state)
|
|
show-sidebar? (:show-sidebar? state false)
|
|
|
|
show-dropdown? (mf/use-state false)
|
|
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
|
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
|
|
|
update-mode
|
|
(mf/use-fn
|
|
(fn [event]
|
|
(let [mode (-> (dom/get-current-target event)
|
|
(dom/get-data "value")
|
|
(keyword))]
|
|
(st/emit! (dcm/update-filters {:mode mode})))))
|
|
|
|
update-show
|
|
(mf/use-fn
|
|
(fn [event]
|
|
(let [mode (-> (dom/get-current-target event)
|
|
(dom/get-data "value")
|
|
(keyword))
|
|
mode (if (= :pending mode) :all :pending)]
|
|
(st/emit! (dcm/update-filters {:show mode})))))
|
|
|
|
update-options
|
|
(mf/use-fn
|
|
(fn [event]
|
|
(let [mode (-> (dom/get-current-target event)
|
|
(dom/get-data "value")
|
|
(parse-boolean))]
|
|
(st/emit! (dcm/update-options {:show-sidebar? (not mode)})))))]
|
|
|
|
[:div {:class (stl/css :view-options)
|
|
:data-testid "viewer-comments-dropdown"
|
|
:on-click toggle-dropdown}
|
|
[:span {:class (stl/css :dropdown-title)} (tr "labels.comments")]
|
|
[:span {:class (stl/css :icon-dropdown)} i/arrow]
|
|
|
|
[:& dropdown {:show @show-dropdown?
|
|
:on-close hide-dropdown}
|
|
[:ul {:class (stl/css :dropdown)}
|
|
|
|
[:li {:class (stl/css-case
|
|
:dropdown-element true
|
|
:selected (or (= :all cmode) (nil? cmode)))
|
|
:data-value "all"
|
|
:on-click update-mode}
|
|
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
|
|
(when (or (= :all cmode) (nil? cmode))
|
|
[:span {:class (stl/css :icon)} i/tick])]
|
|
|
|
[:li {:class (stl/css-case
|
|
:dropdown-element true
|
|
:selected (= :yours cmode))
|
|
:data-value "yours"
|
|
:on-click update-mode}
|
|
[:span {:class (stl/css :label)} (tr "labels.show-your-comments")]
|
|
(when (= :yours cmode)
|
|
[:span {:class (stl/css :icon)}
|
|
i/tick])]
|
|
|
|
[:li {:class (stl/css :separator)}]
|
|
|
|
[:li {:class (stl/css-case
|
|
:dropdown-element true
|
|
:selected (= :pending cshow))
|
|
:data-value (d/name cshow)
|
|
:on-click update-show}
|
|
[:span {:class (stl/css :label)} (tr "labels.hide-resolved-comments")]
|
|
(when (= :pending cshow)
|
|
[:span {:class (stl/css :icon)}
|
|
i/tick])]
|
|
|
|
[:li {:class (stl/css :separator)}]
|
|
|
|
[:li {:class (stl/css-case
|
|
:dropdown-element true
|
|
:selected show-sidebar?)
|
|
:data-value (dm/str show-sidebar?)
|
|
:on-click update-options}
|
|
[:span {:class (stl/css :label)} (tr "labels.show-comments-list")]
|
|
(when show-sidebar?
|
|
[:span {:class (stl/css :icon)} i/tick])]]]]))
|
|
|
|
|
|
(defn- update-thread-position
|
|
[positions {:keys [id] :as thread}]
|
|
(if-let [data (get positions id)]
|
|
(-> thread
|
|
(assoc :position (:position data))
|
|
(assoc :frame-id (:frame-id data)))
|
|
thread))
|
|
|
|
(mf/defc comments-layer
|
|
{::mf/props :obj}
|
|
[{:keys [zoom file users frame page]}]
|
|
(let [profile (mf/deref refs/profile)
|
|
local (mf/deref refs/comments-local)
|
|
|
|
open-thread-id (:open local)
|
|
page-id (:id page)
|
|
file-id (:id file)
|
|
frame-id (:id frame)
|
|
vsize (-> (mf/deref refs/viewer-local)
|
|
:viewport-size)
|
|
|
|
tpos-ref (mf/with-memo [page-id]
|
|
(-> (l/in [:pages page-id :options :comment-threads-position])
|
|
(l/derived refs/viewer-data)))
|
|
|
|
positions (mf/deref tpos-ref)
|
|
threads-map (mf/deref refs/comment-threads)
|
|
|
|
frame-corner (mf/with-memo [frame]
|
|
(-> frame :points grc/points->rect gpt/point))
|
|
|
|
modifier1 (mf/with-memo [frame-corner]
|
|
(-> (gmt/matrix)
|
|
(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 frame local profile]
|
|
(->> (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)))))
|
|
|
|
on-bubble-click
|
|
(mf/use-fn
|
|
(mf/deps open-thread-id)
|
|
(fn [{:keys [id] :as thread}]
|
|
(st/emit! (if (= open-thread-id id)
|
|
(dcm/close-thread)
|
|
(-> (dcm/open-thread thread)
|
|
(with-meta {::ev/origin "viewer"}))))))
|
|
|
|
on-click
|
|
(mf/use-fn
|
|
(mf/deps open-thread-id zoom page-id file-id modifier2)
|
|
(fn [event]
|
|
(dom/stop-propagation event)
|
|
(if (some? open-thread-id)
|
|
(st/emit! (dcm/close-thread))
|
|
(let [event (dom/event->native-event event)
|
|
position (-> (dom/get-offset-position event)
|
|
(update :x #(/ % zoom))
|
|
(update :y #(/ % zoom))
|
|
(gpt/transform modifier2))
|
|
params {:position position
|
|
:page-id (:id page)
|
|
:file-id (:id file)}]
|
|
(st/emit! (dcm/create-draft params))))))
|
|
|
|
on-draft-cancel
|
|
(mf/use-fn #(st/emit! (dcm/close-thread)))
|
|
|
|
on-draft-submit
|
|
(mf/use-fn
|
|
(mf/deps frame-id modifier2)
|
|
(fn [draft]
|
|
(let [params (assoc draft :frame-id frame-id)]
|
|
(st/emit! (dcm/create-thread-on-viewer params)
|
|
(dcm/close-thread)))))]
|
|
|
|
[:div {:class (stl/css :comments-section)
|
|
:on-click on-click}
|
|
[:div {:class (stl/css :viewer-comments-container)}
|
|
[:div {:class (stl/css :threads)}
|
|
(for [item threads]
|
|
[:& cmt/thread-bubble
|
|
{:thread item
|
|
:position-modifier modifier1
|
|
:zoom zoom
|
|
:on-click on-bubble-click
|
|
:open? (= (:id item) (:open local))
|
|
:key (:seqn item)
|
|
:origin :viewer}])
|
|
|
|
(when-let [thread (get threads-map open-thread-id)]
|
|
[:& cmt/thread-comments
|
|
{:thread thread
|
|
:position-modifier modifier1
|
|
:viewport {:offset-x 0 :offset-y 0 :width (:width vsize) :height (:height vsize)}
|
|
:users users
|
|
:zoom zoom}])
|
|
|
|
(when-let [draft (:draft local)]
|
|
[:& cmt/draft-thread
|
|
{:draft draft
|
|
:position-modifier modifier1
|
|
:on-cancel on-draft-cancel
|
|
:on-submit on-draft-submit
|
|
:zoom zoom}])]]]))
|
|
|
|
(mf/defc comments-sidebar
|
|
[{:keys [users frame page]}]
|
|
(let [profile (mf/deref refs/profile)
|
|
local (mf/deref refs/comments-local)
|
|
threads-map (mf/deref refs/comment-threads)
|
|
threads (->> (vals threads-map)
|
|
(dcm/apply-filters local profile)
|
|
(filter (fn [{:keys [position]}]
|
|
(gsh/has-point? frame position))))]
|
|
[:aside {:class (stl/css :comments-sidebar)}
|
|
[:div {:class (stl/css :settings-bar-inside)}
|
|
[:& wc/comments-sidebar {:from-viewer true :users users :threads threads :page-id (:id page)}]]]))
|