mirror of
https://github.com/penpot/penpot.git
synced 2026-05-23 00:43:41 +00:00
321 lines
13 KiB
Clojure
321 lines
13 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.share-link
|
|
(:require-macros [app.main.style :as stl])
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.logging :as log]
|
|
[app.common.uuid :as uuid]
|
|
[app.config :as cf]
|
|
[app.main.data.common :as dc]
|
|
[app.main.data.event :as ev]
|
|
[app.main.data.modal :as modal]
|
|
[app.main.data.notifications :as ntf]
|
|
[app.main.refs :as refs]
|
|
[app.main.router :as rt]
|
|
[app.main.store :as st]
|
|
[app.main.ui.components.select :refer [select]]
|
|
[app.main.ui.icons :as i]
|
|
[app.util.dom :as dom]
|
|
[app.util.i18n :as i18n :refer [tr]]
|
|
[app.util.webapi :as wapi]
|
|
[potok.v2.core :as ptk]
|
|
[rumext.v2 :as mf]))
|
|
|
|
(log/set-level! :warn)
|
|
|
|
(defn- prepare-params
|
|
[{:keys [pages who-comment who-inspect]}]
|
|
{:pages pages
|
|
:who-comment who-comment
|
|
:who-inspect who-inspect})
|
|
|
|
(mf/defc share-link-dialog
|
|
{::mf/register modal/components
|
|
::mf/register-as :share-link
|
|
::mf/wrap-props false}
|
|
[{:keys [file page]}]
|
|
(let [current-page page
|
|
current-page-id (:id page)
|
|
slinks (mf/deref refs/share-links)
|
|
router (mf/deref refs/router)
|
|
route (mf/deref refs/route)
|
|
zoom-type (mf/deref refs/viewer-zoom-type)
|
|
page-ids (dm/get-in file [:data :pages])
|
|
|
|
perms-visible* (mf/use-state false)
|
|
perms-visible? (deref perms-visible*)
|
|
|
|
confirm* (mf/use-state false)
|
|
confirm? (deref confirm*)
|
|
|
|
options* (mf/use-state
|
|
{:pages-mode "current"
|
|
:all-pages false
|
|
:pages #{(:id page)}
|
|
:who-comment "team"
|
|
:who-inspect "team"})
|
|
options (deref options*)
|
|
|
|
current-link
|
|
(mf/with-memo [slinks options page-ids]
|
|
(let [{:keys [pages who-comment who-inspect] :as params} (prepare-params options)
|
|
slink (d/seek #(and (= (:who-inspect %) who-inspect)
|
|
(= (:who-comment %) who-comment)
|
|
(= (:pages %) pages))
|
|
slinks)]
|
|
(when slink
|
|
(let [page-id (d/seek #(contains? (:pages slink) %) page-ids)
|
|
params (-> (:query-params route)
|
|
(assoc :share-id (:id slink))
|
|
(assoc :page-id page-id)
|
|
(assoc :index "0"))
|
|
params (if (nil? zoom-type)
|
|
(dissoc params :zoom)
|
|
(assoc params :zoom zoom-type))
|
|
|
|
href (rt/resolve router :viewer params)]
|
|
(dm/str (assoc cf/public-uri :fragment href))))))
|
|
|
|
on-close
|
|
(fn [event]
|
|
(dom/prevent-default event)
|
|
(st/emit! (modal/hide))
|
|
(modal/disallow-click-outside!))
|
|
|
|
on-toggle-all
|
|
(fn [_event]
|
|
(reset! confirm* false)
|
|
(swap! options*
|
|
(fn [state]
|
|
(if (true? (:all-pages state))
|
|
(-> state
|
|
(assoc :all-pages false)
|
|
(assoc :pages #{(:id page)}))
|
|
(-> state
|
|
(assoc :all-pages true)
|
|
(assoc :pages (into #{} (get-in file [:data :pages]))))))))
|
|
|
|
on-mark-checked-page
|
|
(fn [event]
|
|
(let [target (dom/get-target event)
|
|
checked? (dom/checked? target)
|
|
page-id (uuid/parse (dom/get-data target "page-id"))
|
|
dif-pages? (not= page-id (first (:pages options)))
|
|
no-one-page (< 1 (count (:pages options)))
|
|
should-change? (or ^boolean no-one-page
|
|
^boolean dif-pages?)]
|
|
(when ^boolean should-change?
|
|
(reset! confirm* false)
|
|
(swap! options*
|
|
(fn [{:keys [pages] :as state}]
|
|
(let [pages (if checked?
|
|
(conj pages page-id)
|
|
(disj pages page-id))]
|
|
(-> state
|
|
(assoc :pages pages)
|
|
(assoc :all-pages (= (count pages) (count page-ids))))))))))
|
|
|
|
create-link
|
|
(fn [_]
|
|
(let [params (prepare-params options)
|
|
params (assoc params :file-id (:id file))]
|
|
(st/emit! (dc/create-share-link params)
|
|
(ptk/event ::ev/event {::ev/name "create-share-link"
|
|
::ev/origin "viewer"
|
|
:can-comment (:who-comment params)
|
|
:can-inspect-code (:who-inspect params)}))))
|
|
|
|
copy-link
|
|
(fn [_]
|
|
(wapi/write-to-clipboard current-link)
|
|
(st/emit! (ntf/show {:level :info
|
|
:type :toast
|
|
:content (tr "common.share-link.link-copied-success")
|
|
:timeout 1000})
|
|
(ptk/event ::ev/event {::ev/name "copy-share-link"
|
|
::ev/origin "viewer"})))
|
|
|
|
try-delete-link
|
|
(fn [_]
|
|
(reset! confirm* true))
|
|
|
|
delete-link
|
|
(fn [_]
|
|
(let [params (prepare-params options)
|
|
slink (d/seek #(= (:flags %) (:flags params)) slinks)]
|
|
(reset! confirm* false)
|
|
(st/emit! (dc/delete-share-link slink))))
|
|
|
|
toggle-perms-visibility
|
|
(fn [_]
|
|
(swap! perms-visible* not))
|
|
|
|
on-inspect-change
|
|
(fn [value]
|
|
(reset! confirm* false)
|
|
(swap! options* assoc :who-inspect value))
|
|
|
|
on-comment-change
|
|
(fn [value]
|
|
(reset! confirm* false)
|
|
(swap! options* assoc :who-comment value))]
|
|
|
|
[:div {:class (stl/css :share-modal)}
|
|
[:div {:class (stl/css :share-link-dialog)}
|
|
[:div {:class (stl/css :share-link-header)}
|
|
[:h2 {:class (stl/css :share-link-title)}
|
|
(tr "common.share-link.title")]
|
|
[:button {:class (stl/css :modal-close-button)
|
|
:on-click on-close
|
|
:title (tr "labels.close")}
|
|
i/close]]
|
|
[:div {:class (stl/css :modal-content)}
|
|
[:div {:class (stl/css :share-link-section)}
|
|
(when (and (not confirm?) (some? current-link))
|
|
[:div {:class (stl/css :custon-input-wrapper)}
|
|
[:input {:class (stl/css :input-text)
|
|
:type "text"
|
|
:value (or current-link "")
|
|
:placeholder (tr "common.share-link.placeholder")
|
|
:read-only true}]
|
|
|
|
[:button {:class (stl/css :copy-button)
|
|
:title (tr "viewer.header.share.copy-link")
|
|
:on-click copy-link}
|
|
i/clipboard]])
|
|
|
|
[:div {:class (stl/css :hint-wrapper)}
|
|
(when (not ^boolean confirm?)
|
|
[:div {:class (stl/css :hint)} (tr "common.share-link.permissions-hint")])
|
|
(cond
|
|
(true? confirm?)
|
|
[:div {:class (stl/css :confirm-dialog)}
|
|
[:div {:class (stl/css :description)}
|
|
(tr "common.share-link.confirm-deletion-link-description")]
|
|
[:div {:class (stl/css :actions)}
|
|
[:input {:type "button"
|
|
:class (stl/css :button-cancel)
|
|
:on-click #(reset! confirm* false)
|
|
:value (tr "labels.cancel")}]
|
|
[:input {:type "button"
|
|
:class (stl/css :button-danger)
|
|
:on-click delete-link
|
|
:value (tr "common.share-link.destroy-link")}]]]
|
|
|
|
(some? current-link)
|
|
[:input
|
|
{:type "button"
|
|
:class (stl/css :button-danger)
|
|
:on-click try-delete-link
|
|
:value (tr "common.share-link.destroy-link")}]
|
|
|
|
:else
|
|
[:input
|
|
{:type "button"
|
|
:class (stl/css :button-active)
|
|
:on-click create-link
|
|
:value (tr "common.share-link.get-link")}])]]
|
|
|
|
|
|
(when (not ^boolean confirm?)
|
|
[:div {:class (stl/css :permissions-section)}
|
|
[:button {:class (stl/css :manage-permissions)
|
|
:on-click toggle-perms-visibility}
|
|
[:span {:class (stl/css-case :icon true
|
|
:rotated perms-visible?)}
|
|
i/arrow]
|
|
(tr "common.share-link.manage-ops")]
|
|
|
|
(when ^boolean perms-visible?
|
|
[:*
|
|
(let [all-selected? (:all-pages options)
|
|
pages (->> (get-in file [:data :pages])
|
|
(map #(get-in file [:data :pages-index %])))
|
|
selected (:pages options)]
|
|
[:div {:class (stl/css :view-mode)}
|
|
[:div {:class (stl/css :subtitle)}
|
|
(tr "common.share-link.permissions-pages")]
|
|
[:div {:class (stl/css :items)}
|
|
(if (= 1 (count pages))
|
|
[:div {:class (stl/css :checkbox-wrapper)}
|
|
|
|
[:label {:for (str "page-" current-page-id)
|
|
:class (stl/css-case :global/checked true)}
|
|
|
|
[:span {:class (stl/css :checked)}
|
|
i/status-tick]
|
|
|
|
(:name current-page)]
|
|
|
|
[:input {:type "checkbox"
|
|
:id (dm/str "page-" current-page-id)
|
|
:data-page-id (dm/str current-page-id)
|
|
:on-change on-mark-checked-page
|
|
:checked true}]
|
|
[:span (str " " (tr "common.share-link.current-tag"))]]
|
|
|
|
[:*
|
|
[:div {:class (stl/css :select-all-row)}
|
|
[:div {:class (stl/css :checkbox-wrapper)}
|
|
[:label {:for "view-all"
|
|
:class (stl/css :select-all-label)}
|
|
[:span {:class (stl/css-case :global/checked all-selected?)}
|
|
(when all-selected?
|
|
i/status-tick)]
|
|
(tr "common.share-link.view-all")
|
|
[:input {:type "checkbox"
|
|
:id "view-all"
|
|
:checked all-selected?
|
|
:name "pages-mode"
|
|
:on-change on-toggle-all}]]]
|
|
|
|
[:span {:class (stl/css :count-pages)}
|
|
(tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
|
|
|
[:ul {:class (stl/css :pages-selection)}
|
|
(for [{:keys [id name]} pages]
|
|
[:li {:class (stl/css :checkbox-wrapper)
|
|
:key (dm/str id)}
|
|
[:label {:for (dm/str "page-" id)}
|
|
[:span {:class (stl/css-case :global/checked (contains? selected id))}
|
|
(when (contains? selected id)
|
|
i/status-tick)]
|
|
name
|
|
(when (= current-page-id id)
|
|
[:div {:class (stl/css :current-tag)} (dm/str " " (tr "common.share-link.current-tag"))])
|
|
[:input {:type "checkbox"
|
|
:id (dm/str "page-" id)
|
|
:data-page-id (dm/str id)
|
|
:on-change on-mark-checked-page
|
|
:checked (contains? selected id)}]]])]])]])
|
|
|
|
[:div {:class (stl/css :access-mode)}
|
|
[:div {:class (stl/css :subtitle)}
|
|
(tr "common.share-link.permissions-can-comment")]
|
|
[:div {:class (stl/css :items)}
|
|
[:& select
|
|
{:class (stl/css :who-comment-select)
|
|
:default-value (dm/str (:who-comment options))
|
|
:options [{:value "team" :label (tr "common.share-link.team-members")}
|
|
{:value "all" :label (tr "common.share-link.all-users")}]
|
|
:on-change on-comment-change}]]]
|
|
[:div {:class (stl/css :inspect-mode)}
|
|
[:div {:class (stl/css :subtitle)}
|
|
(tr "common.share-link.permissions-can-inspect")]
|
|
[:div {:class (stl/css :items)}
|
|
[:& select
|
|
{:class (stl/css :who-inspect-select)
|
|
:default-value (dm/str (:who-inspect options))
|
|
:options [{:value "team" :label (tr "common.share-link.team-members")}
|
|
{:value "all" :label (tr "common.share-link.all-users")}]
|
|
:on-change on-inspect-change}]]]])])]]]))
|
|
|
|
|
|
|