mirror of
https://github.com/penpot/penpot.git
synced 2025-03-18 10:41:29 -05:00
💄 Add new UI to viewer area
This commit is contained in:
parent
15f81e557c
commit
f8dd86da34
31 changed files with 2841 additions and 723 deletions
3
frontend/resources/images/icons/expand-refactor.svg
Normal file
3
frontend/resources/images/icons/expand-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10.357 2.813h2.828v2.829m-10.37 4.713v2.829h2.828m7.071-9.9l-9.428 9.429z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 206 B |
3
frontend/resources/images/icons/reload-refactor.svg
Normal file
3
frontend/resources/images/icons/reload-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2.4 8a6 6 0 111.758 4.242M2.4 8l2.1-2zm0 0L1 5.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 182 B |
|
@ -148,6 +148,7 @@
|
|||
stroke: var(--button-tertiary-foreground-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
&:global(.disabled),
|
||||
&[disabled],
|
||||
&:disabled {
|
||||
|
|
|
@ -297,4 +297,13 @@
|
|||
--tag-background-color: var(--color-accent-primary);
|
||||
|
||||
--link-foreground-color: var(--color-accent-primary);
|
||||
|
||||
// VIEWER
|
||||
--viewer-background-color: var(--color-background-secondary);
|
||||
--viewer-paginator-background-color: var(--color-background-tertiary);
|
||||
--viewer-controls-background-color: var(--color-background-primary);
|
||||
--viewer-inspect-border-color: var(--color-background-tertiary);
|
||||
--viewer-thumbnails-control-foreground-color: var(--color-foreground-secondary);
|
||||
--viewer-thumbnail-border-color: var(--color-accent-primary);
|
||||
--viewer-thumbnail-background-color-selected: var(--color-accent-primary-muted);
|
||||
}
|
||||
|
|
|
@ -93,10 +93,9 @@
|
|||
(assoc :message (tr "errors.email-invalid"))))))
|
||||
|
||||
(mf/defc login-form
|
||||
[{:keys [params on-success-callback] :as props}]
|
||||
[{:keys [params on-success-callback origin] :as props}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
initial (mf/use-memo (mf/deps params) (constantly params))
|
||||
|
||||
error (mf/use-state false)
|
||||
form (fm/use-form :spec ::login-form
|
||||
:validators [handle-error-messages]
|
||||
|
@ -152,7 +151,12 @@
|
|||
(let [params (:clean-data @form)]
|
||||
(login-with-ldap event (with-meta params
|
||||
{:on-error on-error
|
||||
:on-success on-success})))))]
|
||||
:on-success on-success})))))
|
||||
|
||||
on-recovery-request
|
||||
(mf/use-fn
|
||||
#(st/emit! (rt/nav :auth-recovery-request)))]
|
||||
|
||||
(if new-css-system
|
||||
[:*
|
||||
(when-let [message @error]
|
||||
|
@ -178,10 +182,11 @@
|
|||
:label (tr "auth.password")
|
||||
:class (stl/css :form-field)}]]
|
||||
|
||||
(when (or (contains? cf/flags :login)
|
||||
(contains? cf/flags :login-with-password))
|
||||
(when (and (not= origin :viewer)
|
||||
(or (contains? cf/flags :login)
|
||||
(contains? cf/flags :login-with-password)))
|
||||
[:div {:class (stl/css :fields-row :forgot-password)}
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
|
||||
[:& lk/link {:action on-recovery-request
|
||||
:data-test "forgot-password"}
|
||||
(tr "auth.forgot-password")]])
|
||||
|
||||
|
@ -198,6 +203,7 @@
|
|||
{:label (tr "auth.login-with-ldap-submit")
|
||||
:on-click on-submit-ldap}])]]]
|
||||
|
||||
|
||||
;; OLD
|
||||
[:*
|
||||
(when-let [message @error]
|
||||
|
@ -271,7 +277,7 @@
|
|||
:icon i/brand-openid
|
||||
:label (tr "auth.login-with-oidc-submit")
|
||||
:class (stl/css :login-btn :btn-oidc-auth)}])]
|
||||
|
||||
|
||||
[:div.auth-buttons
|
||||
(when (contains? cf/flags :login-with-google)
|
||||
[:& bl/button-link {:on-click login-with-google
|
||||
|
@ -299,28 +305,36 @@
|
|||
|
||||
(mf/defc login-button-oidc
|
||||
[{:keys [params] :as props}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
login-oidc
|
||||
(mf/use-fn
|
||||
(mf/deps params)
|
||||
(fn [event]
|
||||
(login-with-oidc event :oidc params)))
|
||||
|
||||
handle-key-down
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(when (k/enter? event)
|
||||
(login-oidc event))))]
|
||||
(if new-css-system
|
||||
(when (contains? cf/flags :login-with-oidc)
|
||||
[:div {:class (stl/css :link-entry :link-oidc)}
|
||||
[:a {:tab-index "0"
|
||||
:on-key-down (fn [event]
|
||||
(when (k/enter? event)
|
||||
(login-with-oidc event :oidc params)))
|
||||
:on-click #(login-with-oidc % :oidc params)}
|
||||
:on-key-down handle-key-down
|
||||
:on-click login-oidc}
|
||||
(tr "auth.login-with-oidc-submit")]])
|
||||
|
||||
|
||||
;; OLD
|
||||
(when (contains? cf/flags :login-with-oidc)
|
||||
[:div.link-entry.link-oidc
|
||||
[:a {:tab-index "0"
|
||||
:on-key-down (fn [event]
|
||||
(when (k/enter? event)
|
||||
(login-with-oidc event :oidc params)))
|
||||
:on-click #(login-with-oidc % :oidc params)}
|
||||
:on-key-down handle-key-down
|
||||
:on-click login-oidc}
|
||||
(tr "auth.login-with-oidc-submit")]]))))
|
||||
|
||||
(mf/defc login-methods
|
||||
[{:keys [params on-success-callback] :as props}]
|
||||
[{:keys [params on-success-callback origin] :as props}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||
(if new-css-system
|
||||
[:*
|
||||
|
@ -336,7 +350,7 @@
|
|||
(when (or (contains? cf/flags :login)
|
||||
(contains? cf/flags :login-with-password)
|
||||
(contains? cf/flags :login-with-ldap))
|
||||
[:& login-form {:params params :on-success-callback on-success-callback}])]
|
||||
[:& login-form {:params params :on-success-callback on-success-callback :origin origin}])]
|
||||
|
||||
;; OLD
|
||||
[:*
|
||||
|
@ -364,7 +378,19 @@
|
|||
|
||||
(mf/defc login-page
|
||||
[{:keys [params] :as props}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
go-register
|
||||
(mf/use-fn
|
||||
#(st/emit! (rt/nav :auth-register {} params)))
|
||||
|
||||
on-pass-recovery
|
||||
(mf/use-fn
|
||||
#(st/emit! (rt/nav :auth-recovery-request)))
|
||||
|
||||
on-create-demo-profile
|
||||
(mf/use-fn
|
||||
#(st/emit! (du/create-demo-profile)))]
|
||||
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :auth-form)}
|
||||
[:h1 {:class (stl/css :auth-title)
|
||||
|
@ -375,17 +401,24 @@
|
|||
[:& login-methods {:params params}]
|
||||
|
||||
[:div {:class (stl/css :links)}
|
||||
(when (or (contains? cf/flags :login)
|
||||
(contains? cf/flags :login-with-password))
|
||||
[:div {:class (stl/css :link-entry :register)}
|
||||
[:& lk/link {:action on-pass-recovery
|
||||
:data-test "forgot-password"}
|
||||
(tr "auth.forgot-password")]])
|
||||
|
||||
(when (contains? cf/flags :registration)
|
||||
[:div {:class (stl/css :link-entry :register)}
|
||||
[:span (tr "auth.register") " "]
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
|
||||
[:& lk/link {:action go-register
|
||||
:data-test "register-submit"}
|
||||
(tr "auth.register-submit")]])]
|
||||
|
||||
(when (contains? cf/flags :demo-users)
|
||||
[:div {:class (stl/css :link-entry :demo-account)}
|
||||
[:span (tr "auth.create-demo-profile") " "]
|
||||
[:& lk/link {:action #(st/emit! (du/create-demo-profile))
|
||||
[:& lk/link {:action on-create-demo-profile
|
||||
:data-test "demo-account-link"}
|
||||
(tr "auth.create-demo-account")]])]
|
||||
|
||||
|
@ -400,14 +433,14 @@
|
|||
(when (or (contains? cf/flags :login)
|
||||
(contains? cf/flags :login-with-password))
|
||||
[:div.link-entry
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
|
||||
[:& lk/link {:action on-pass-recovery
|
||||
:data-test "forgot-password"}
|
||||
(tr "auth.forgot-password")]])
|
||||
|
||||
(when (contains? cf/flags :registration)
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.register") " "]
|
||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
|
||||
[:& lk/link {:action go-register
|
||||
:data-test "register-submit"}
|
||||
(tr "auth.register-submit")]])]
|
||||
|
||||
|
@ -415,7 +448,7 @@
|
|||
[:div.links.demo
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.create-demo-profile") " "]
|
||||
[:& lk/link {:action #(st/emit! (du/create-demo-profile))
|
||||
[:& lk/link {:action on-create-demo-profile
|
||||
:data-test "demo-account-link"}
|
||||
(tr "auth.create-demo-account")]]])]])))
|
||||
|
||||
|
|
|
@ -55,8 +55,12 @@
|
|||
:cmd cmd})))
|
||||
|
||||
on-toggle-enabled
|
||||
(fn [index]
|
||||
(swap! exports update-in [index :enabled] not))
|
||||
(mf/use-fn
|
||||
(mf/deps exports)
|
||||
(fn [event]
|
||||
(let [index (-> (dom/get-current-target event)
|
||||
(dom/get-data "value"))]
|
||||
(swap! exports update-in [index :enabled] not))))
|
||||
|
||||
change-all
|
||||
(fn [_]
|
||||
|
@ -65,9 +69,8 @@
|
|||
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div.modal-container.export-multiple-dialog
|
||||
{:class (stl/css-case :modal-container true
|
||||
:empty (empty? all-exports))}
|
||||
[:div {:class (stl/css-case :modal-container true
|
||||
:empty (empty? all-exports))}
|
||||
|
||||
[:div {:class (stl/css :modal-header)}
|
||||
[:h2 {:class (stl/css :modal-title)} title]
|
||||
|
@ -84,55 +87,58 @@
|
|||
:on-click change-all}
|
||||
[:span {:class (stl/css :checkbox-wrapper)}
|
||||
(cond
|
||||
all-checked? [:span {:class (stl/css-case :checkbox-icon2 true
|
||||
all-checked? [:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/checked true)} i/tick-refactor]
|
||||
all-unchecked? [:span {:class (stl/css-case :checkbox-icon2 true
|
||||
all-unchecked? [:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/uncheked true)}]
|
||||
:else [:span {:class (stl/css-case :checkbox-icon2 true
|
||||
:else [:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/intermediate true)} i/remove-refactor])]]
|
||||
[:div {:class (stl/css :selection-title)} (tr "dashboard.export-multiple.selected"
|
||||
(c (count enabled-exports))
|
||||
(c (count all-exports)))]]
|
||||
[:div {:class (stl/css :selection-title)}
|
||||
(tr "dashboard.export-multiple.selected"
|
||||
(c (count enabled-exports))
|
||||
(c (count all-exports)))]]
|
||||
[:div {:class (stl/css :selection-wrapper)}
|
||||
[:div {:class (stl/css-case :selection-list true
|
||||
:selection-shadow (> (count all-exports) 8))}
|
||||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||
(let [{:keys [x y width height]} (:selrect shape)]
|
||||
[:div {:class (stl/css :selection-row)}
|
||||
[:button {:class (stl/css :selection-btn)
|
||||
:on-click #(on-toggle-enabled index)}
|
||||
[:span {:class (stl/css :checkbox-wrapper)}
|
||||
(if (:enabled export)
|
||||
[:span {:class (stl/css-case :checkbox-icon2 true
|
||||
:global/checked true)} i/tick-refactor]
|
||||
[:span {:class (stl/css-case :checkbox-icon2 true
|
||||
:global/uncheked true)}])]
|
||||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||
(let [{:keys [x y width height]} (:selrect shape)]
|
||||
[:div {:class (stl/css :selection-row)
|
||||
:key (:id shape)}
|
||||
[:button {:class (stl/css :selection-btn)
|
||||
:data-value index
|
||||
:on-click on-toggle-enabled}
|
||||
[:span {:class (stl/css :checkbox-wrapper)}
|
||||
(if (:enabled export)
|
||||
[:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/checked true)} i/tick-refactor]
|
||||
[:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/uncheked true)}])]
|
||||
|
||||
[:div {:class (stl/css :image-wrapper)}
|
||||
(if (some? (:thumbnail shape))
|
||||
[:img {:src (:thumbnail shape)}]
|
||||
[:svg {:view-box (dm/str x " " y " " width " " height)
|
||||
:width 24
|
||||
:height 20
|
||||
:version "1.1"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
[:div {:class (stl/css :image-wrapper)}
|
||||
(if (some? (:thumbnail shape))
|
||||
[:img {:src (:thumbnail shape)}]
|
||||
[:svg {:view-box (dm/str x " " y " " width " " height)
|
||||
:width 24
|
||||
:height 20
|
||||
:version "1.1"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
;; Fix Chromium bug about color of html texts
|
||||
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
||||
:style {:-webkit-print-color-adjust :exact}
|
||||
:fill "none"}
|
||||
:style {:-webkit-print-color-adjust :exact}
|
||||
:fill "none"}
|
||||
|
||||
[:& shape-wrapper {:shape shape}]])]
|
||||
[:& shape-wrapper {:shape shape}]])]
|
||||
|
||||
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
|
||||
(when (:scale export)
|
||||
[:div {:class (stl/css :selection-scale)}
|
||||
(dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
||||
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
||||
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
|
||||
(when (:scale export)
|
||||
[:div {:class (stl/css :selection-scale)}
|
||||
(dm/str (ust/format-precision (* width (:scale export)) 2) "px"
|
||||
(ust/format-precision (* height (:scale export)) 2) "px")])
|
||||
|
||||
(when (:type export)
|
||||
[:div {:class (stl/css :selection-extension)}
|
||||
(-> export :type d/name str/upper)])]]))]]]
|
||||
(when (:type export)
|
||||
[:div {:class (stl/css :selection-extension)}
|
||||
(-> export :type d/name str/upper)])]]))]]]
|
||||
|
||||
[:& no-selection])]
|
||||
|
||||
|
@ -187,7 +193,8 @@
|
|||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||
(let [{:keys [x y width height]} (:selrect shape)]
|
||||
[:div.row
|
||||
[:div.field.check {:on-click #(on-toggle-enabled index)}
|
||||
[:div.field.check {:data-value index
|
||||
:on-click on-toggle-enabled}
|
||||
(if (:enabled export)
|
||||
[:span.checked i/checkbox-checked]
|
||||
[:span.unchecked i/checkbox-unchecked])]
|
||||
|
@ -210,7 +217,7 @@
|
|||
|
||||
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
|
||||
(when (:scale export)
|
||||
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
||||
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "px"
|
||||
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
||||
|
||||
(when (:type export)
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
height: $s-24;
|
||||
width: $s-24;
|
||||
padding: 0;
|
||||
.checkbox-icon2 {
|
||||
.checkobox-tick {
|
||||
@extend .checkbox-icon;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,6 +339,7 @@
|
|||
(def easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor))
|
||||
(def effects-refactor (icon-xref :effects-refactor))
|
||||
(def elipse-refactor (icon-xref :elipse-refactor))
|
||||
(def expand-refactor (icon-xref :expand-refactor))
|
||||
(def fill-content-refactor (icon-xref :fill-content-refactor))
|
||||
(def filter-refactor (icon-xref :filter-refactor))
|
||||
(def fixed-width-refactor (icon-xref :fixed-width-refactor))
|
||||
|
@ -414,6 +415,7 @@
|
|||
(def picker-refactor (icon-xref :picker-refactor))
|
||||
(def play-refactor (icon-xref :play-refactor))
|
||||
(def rectangle-refactor (icon-xref :rectangle-refactor))
|
||||
(def reload-refactor (icon-xref :reload-refactor))
|
||||
(def remove-refactor (icon-xref :remove-refactor))
|
||||
(def rgba-refactor (icon-xref :rgba-refactor))
|
||||
(def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.ui.viewer
|
||||
(:import goog.events.EventType)
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
|
@ -91,29 +92,57 @@
|
|||
:vbox (str "0 0 " width " " height)})))
|
||||
|
||||
(mf/defc viewer-pagination
|
||||
[{:keys [index num-frames left-bar right-bar] :as props}]
|
||||
[:*
|
||||
(when (pos? index)
|
||||
[:div.viewer-go-prev {:class (when left-bar "left-bar")}
|
||||
[:div.arrow {:on-click #(st/emit! dv/select-prev-frame)} i/go-prev]])
|
||||
(when (< (+ index 1) num-frames)
|
||||
[:div.viewer-go-next {:class (when right-bar "right-bar")}
|
||||
[:div.arrow {:on-click #(st/emit! dv/select-next-frame)} i/go-next]])
|
||||
[:div.viewer-bottom {:class (when left-bar "left-bar")}
|
||||
[:div.reset {:on-click #(st/emit! dv/select-first-frame)} i/reset]
|
||||
[:div.counter (str/join " / " [(+ index 1) num-frames])]
|
||||
[:span]]])
|
||||
[{:keys [index num-frames left-bar right-bar comment-sidebar] :as props}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
go-prev-frame (mf/use-fn #(st/emit! dv/select-prev-frame))
|
||||
go-next-frame (mf/use-fn #(st/emit! dv/select-next-frame))
|
||||
go-first-frame (mf/use-fn #(st/emit! dv/select-first-frame))]
|
||||
(if new-css-system
|
||||
[:*
|
||||
(when (pos? index)
|
||||
[:button {:class (stl/css-case :viewer-go-prev true
|
||||
:left-bar left-bar)
|
||||
:on-click go-prev-frame}
|
||||
i/arrow-refactor])
|
||||
(when (< (+ index 1) num-frames)
|
||||
[:button {:class (stl/css-case :viewer-go-next true
|
||||
:comment-sidebar comment-sidebar
|
||||
:right-bar right-bar)
|
||||
:on-click go-next-frame}
|
||||
i/arrow-refactor])
|
||||
[:div {:class (stl/css-case :viewer-bottom true
|
||||
:left-bar left-bar)}
|
||||
[:button {:on-click go-first-frame
|
||||
:class (stl/css :reset-button)}
|
||||
i/reload-refactor]
|
||||
[:span {:class (stl/css :counter)}
|
||||
(str/join " / " [(+ index 1) num-frames])]
|
||||
[:span]]]
|
||||
|
||||
|
||||
;; OLD
|
||||
[:*
|
||||
(when (pos? index)
|
||||
[:div.viewer-go-prev {:class (when left-bar "left-bar")}
|
||||
[:div.arrow {:on-click go-prev-frame} i/go-prev]])
|
||||
(when (< (+ index 1) num-frames)
|
||||
[:div.viewer-go-next {:class (when right-bar "right-bar")}
|
||||
[:div.arrow {:on-click go-next-frame} i/go-next]])
|
||||
[:div.viewer-bottom {:class (when left-bar "left-bar")}
|
||||
[:div.reset {:on-click go-first-frame} i/reset]
|
||||
[:div.counter (str/join " / " [(+ index 1) num-frames])]
|
||||
[:span]]])))
|
||||
|
||||
(mf/defc viewer-pagination-and-sidebar
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [section index users frame page]}]
|
||||
(let [comments-local (mf/deref refs/comments-local)
|
||||
show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))]
|
||||
[:*
|
||||
[:*
|
||||
[:& viewer-pagination
|
||||
{:index index
|
||||
:num-frames (count (:frames page))
|
||||
:right-bar show-sidebar?}]
|
||||
:comment-sidebar show-sidebar?}]
|
||||
|
||||
(when show-sidebar?
|
||||
[:& comments-sidebar
|
||||
|
@ -172,72 +201,138 @@
|
|||
:page page
|
||||
:interactions-mode interactions-mode}]]]))
|
||||
|
||||
|
||||
(mf/defc viewer-wrapper
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
|
||||
size frame interactions-mode overlays zoom section index]}]
|
||||
|
||||
[:*
|
||||
[:& viewer-pagination-and-sidebar
|
||||
{:section section
|
||||
:index index
|
||||
:page page
|
||||
:users users
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||
(if new-css-system
|
||||
[:*
|
||||
[:& viewer-pagination-and-sidebar
|
||||
{:section section
|
||||
:index index
|
||||
:page page
|
||||
:users users
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode}]
|
||||
|
||||
[:div.viewer-wrapper
|
||||
{:style {:width (:width wrapper-size)
|
||||
:height (:height wrapper-size)}}
|
||||
[:div.viewer-clipper
|
||||
(when orig-frame
|
||||
[:div.viewport-container
|
||||
{:ref orig-viewport-ref
|
||||
:style {:width (:width orig-size)
|
||||
:height (:height orig-size)
|
||||
:position "relative"}}
|
||||
[:div {:class (stl/css :viewer-wrapper)
|
||||
:style {:width (:width wrapper-size)
|
||||
:height (:height wrapper-size)}}
|
||||
[:div {:class (stl/css :viewer-clipper)}
|
||||
|
||||
[:& interactions/viewport
|
||||
{:frame orig-frame
|
||||
:base-frame orig-frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size orig-size
|
||||
:page page
|
||||
:users users
|
||||
:interactions-mode interactions-mode}]])
|
||||
(when orig-frame
|
||||
[:div {:class (stl/css :viewport-container)
|
||||
:ref orig-viewport-ref
|
||||
:style {:width (:width orig-size)
|
||||
:height (:height orig-size)
|
||||
:position "relative"}}
|
||||
|
||||
[:div.viewport-container
|
||||
{:ref current-viewport-ref
|
||||
:style {:width (:width size)
|
||||
:height (:height size)
|
||||
:position "relative"}}
|
||||
[:& interactions/viewport
|
||||
{:frame orig-frame
|
||||
:base-frame orig-frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size orig-size
|
||||
:page page
|
||||
:users users
|
||||
:interactions-mode interactions-mode}]])
|
||||
|
||||
[:& interactions/viewport
|
||||
{:frame frame
|
||||
:base-frame frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size size
|
||||
:page page
|
||||
:interactions-mode interactions-mode}]
|
||||
[:div {:class (stl/css :viewport-container)
|
||||
:ref current-viewport-ref
|
||||
:style {:width (:width size)
|
||||
:height (:height size)
|
||||
:position "relative"}}
|
||||
|
||||
(for [overlay overlays]
|
||||
[:& viewer-overlay
|
||||
{:overlay overlay
|
||||
:key (dm/str (:id overlay))
|
||||
:page page
|
||||
:frame frame
|
||||
:zoom zoom
|
||||
:wrapper-size wrapper-size
|
||||
:interactions-mode interactions-mode}])]]
|
||||
[:& interactions/viewport
|
||||
{:frame frame
|
||||
:base-frame frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size size
|
||||
:page page
|
||||
:interactions-mode interactions-mode}]
|
||||
|
||||
(for [overlay overlays]
|
||||
[:& viewer-overlay
|
||||
{:overlay overlay
|
||||
:key (dm/str (:id overlay))
|
||||
:page page
|
||||
:frame frame
|
||||
:zoom zoom
|
||||
:wrapper-size wrapper-size
|
||||
:interactions-mode interactions-mode}])]]
|
||||
|
||||
|
||||
(when (= section :comments)
|
||||
[:& comments-layer {:file file
|
||||
:users users
|
||||
:frame frame
|
||||
:page page
|
||||
:zoom zoom}])]])
|
||||
(when (= section :comments)
|
||||
[:& comments-layer {:file file
|
||||
:users users
|
||||
:frame frame
|
||||
:page page
|
||||
:zoom zoom}])]]
|
||||
|
||||
|
||||
|
||||
;; OLD
|
||||
[:*
|
||||
[:& viewer-pagination-and-sidebar
|
||||
{:section section
|
||||
:index index
|
||||
:page page
|
||||
:users users
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode}]
|
||||
|
||||
[:div.viewer-wrapper
|
||||
{:style {:width (:width wrapper-size)
|
||||
:height (:height wrapper-size)}}
|
||||
[:div.viewer-clipper
|
||||
(when orig-frame
|
||||
[:div.viewport-container
|
||||
{:ref orig-viewport-ref
|
||||
:style {:width (:width orig-size)
|
||||
:height (:height orig-size)
|
||||
:position "relative"}}
|
||||
|
||||
[:& interactions/viewport
|
||||
{:frame orig-frame
|
||||
:base-frame orig-frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size orig-size
|
||||
:page page
|
||||
:users users
|
||||
:interactions-mode interactions-mode}]])
|
||||
|
||||
[:div.viewport-container
|
||||
{:ref current-viewport-ref
|
||||
:style {:width (:width size)
|
||||
:height (:height size)
|
||||
:position "relative"}}
|
||||
|
||||
[:& interactions/viewport
|
||||
{:frame frame
|
||||
:base-frame frame
|
||||
:frame-offset (gpt/point 0 0)
|
||||
:size size
|
||||
:page page
|
||||
:interactions-mode interactions-mode}]
|
||||
|
||||
(for [overlay overlays]
|
||||
[:& viewer-overlay
|
||||
{:overlay overlay
|
||||
:key (dm/str (:id overlay))
|
||||
:page page
|
||||
:frame frame
|
||||
:zoom zoom
|
||||
:wrapper-size wrapper-size
|
||||
:interactions-mode interactions-mode}])]]
|
||||
|
||||
|
||||
(when (= section :comments)
|
||||
[:& comments-layer {:file file
|
||||
:users users
|
||||
:frame frame
|
||||
:page page
|
||||
:zoom zoom}])]])))
|
||||
|
||||
(mf/defc viewer
|
||||
[{:keys [params data]}]
|
||||
|
@ -245,6 +340,8 @@
|
|||
(let [{:keys [page-id share-id section index interactions-mode]} params
|
||||
{:keys [file users project permissions]} data
|
||||
|
||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
|
||||
allowed (or
|
||||
(= section :interactions)
|
||||
(and (= section :comments)
|
||||
|
@ -311,7 +408,7 @@
|
|||
(calculate-wrapper size orig-size zoom))
|
||||
|
||||
click-on-screen
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [origin (dom/get-target event)
|
||||
over-section? (dom/class? origin "viewer-section")
|
||||
|
@ -360,9 +457,13 @@
|
|||
(if shift?
|
||||
(dom/set-h-scroll-pos! section new-scroll-pos)
|
||||
(dom/set-scroll-pos! section new-scroll-pos)))))))))
|
||||
on-thumbnails-close
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/close-thumbnails-panel))
|
||||
|
||||
|
||||
on-exit-fullscreen
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(when (not (dom/fullscreen?))
|
||||
(st/emit! (dv/exit-fullscreen)))))]
|
||||
|
@ -441,7 +542,7 @@
|
|||
nil)
|
||||
;; Navigate animation needs to be started after navigation
|
||||
;; is complete, and we have the next page index.
|
||||
(let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))]
|
||||
(let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))]
|
||||
(when nav-animation
|
||||
(let [orig-viewport (mf/ref-val orig-viewport-ref)
|
||||
current-viewport (mf/ref-val current-viewport-ref)]
|
||||
|
@ -498,76 +599,153 @@
|
|||
fonts (into #{} (keep :font-id) text-nodes)]
|
||||
(run! fonts/ensure-loaded! fonts))))
|
||||
|
||||
[:div#viewer-layout
|
||||
{:class (dom/classnames
|
||||
:force-visible (:show-thumbnails local)
|
||||
:viewer-layout (not= section :inspect)
|
||||
:inspect-layout (= section :inspect)
|
||||
:fullscreen fullscreen?)}
|
||||
(if new-css-system
|
||||
[:div#viewer-layout
|
||||
{:class (stl/css-case
|
||||
:force-visible (:show-thumbnails local)
|
||||
:viewer-layout (not= section :inspect)
|
||||
:inspect-layout (= section :inspect)
|
||||
:fullscreen fullscreen?)}
|
||||
|
||||
[:div.viewer-content
|
||||
[:& header/header {:project project
|
||||
:index index
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:permissions permissions
|
||||
:zoom zoom
|
||||
:section section
|
||||
:interactions-mode interactions-mode}]
|
||||
[:div.thumbnail-close {:on-click #(st/emit! dv/close-thumbnails-panel)
|
||||
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
|
||||
[:& thumbnails-panel {:frames frames
|
||||
:show? (:show-thumbnails local false)
|
||||
:page page
|
||||
:index index
|
||||
:thumbnail-data (:thumbnails file)}]
|
||||
[:section.viewer-section {:id "viewer-section"
|
||||
:ref viewer-section-ref
|
||||
:class (if fullscreen? "fullscreen" "")
|
||||
:on-click click-on-screen}
|
||||
(cond
|
||||
(empty? frames)
|
||||
[:section.empty-state
|
||||
[:span (tr "viewer.empty-state")]]
|
||||
[:div {:class (stl/css :viewer-content)}
|
||||
[:& header/header {:project project
|
||||
:index index
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:permissions permissions
|
||||
:zoom zoom
|
||||
:section section
|
||||
:interactions-mode interactions-mode}]
|
||||
|
||||
(nil? frame)
|
||||
[:section.empty-state
|
||||
(when (some? index)
|
||||
[:span (tr "viewer.frame-not-found")])]
|
||||
[:button {:on-click on-thumbnails-close
|
||||
:class (stl/css-case :thumbnails-close true
|
||||
:invisible (not (:show-thumbnails local false)))}]
|
||||
|
||||
(some? frame)
|
||||
(if (= :inspect section)
|
||||
[:& inspect/viewport
|
||||
{:frame frame
|
||||
:page page
|
||||
:file file
|
||||
:section section
|
||||
:local local
|
||||
:size size
|
||||
:index index
|
||||
:viewer-pagination viewer-pagination
|
||||
:interactions-mode interactions-mode
|
||||
:share-id share-id}]
|
||||
[:& thumbnails-panel {:frames frames
|
||||
:show? (:show-thumbnails local false)
|
||||
:page page
|
||||
:index index
|
||||
:thumbnail-data (:thumbnails file)}]
|
||||
|
||||
[:section {:id "viewer-section"
|
||||
:ref viewer-section-ref
|
||||
:class (stl/css-case :viewer-section true
|
||||
:fulscreen fullscreen?)
|
||||
:on-click click-on-screen}
|
||||
(cond
|
||||
(empty? frames)
|
||||
[:section {:class (stl/css :empty-state)}
|
||||
[:span (tr "viewer.empty-state")]]
|
||||
|
||||
(nil? frame)
|
||||
[:section {:class (stl/css :empty-state)}
|
||||
(when (some? index)
|
||||
[:span (tr "viewer.frame-not-found")])]
|
||||
|
||||
(some? frame)
|
||||
(if (= :inspect section)
|
||||
[:& inspect/viewport
|
||||
{:frame frame
|
||||
:page page
|
||||
:file file
|
||||
:section section
|
||||
:local local
|
||||
:size size
|
||||
:index index
|
||||
:viewer-pagination viewer-pagination
|
||||
:interactions-mode interactions-mode
|
||||
:share-id share-id}]
|
||||
|
||||
[:& (mf/provider ctx/current-zoom) {:value zoom}
|
||||
[:& viewer-wrapper
|
||||
{:wrapper-size wrapper-size
|
||||
:orig-frame orig-frame
|
||||
:orig-viewport-ref orig-viewport-ref
|
||||
:orig-size orig-size
|
||||
:page page
|
||||
:file file
|
||||
:users users
|
||||
:current-viewport-ref current-viewport-ref
|
||||
:size size
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode
|
||||
:overlays overlays
|
||||
:zoom zoom
|
||||
:section section
|
||||
:index index}]]))]]]
|
||||
|
||||
;; OLD
|
||||
[:div#viewer-layout
|
||||
{:class (dom/classnames
|
||||
:force-visible (:show-thumbnails local)
|
||||
:viewer-layout (not= section :inspect)
|
||||
:inspect-layout (= section :inspect)
|
||||
:fullscreen fullscreen?)}
|
||||
|
||||
[:div.viewer-content
|
||||
[:& header/header {:project project
|
||||
:index index
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:permissions permissions
|
||||
:zoom zoom
|
||||
:section section
|
||||
:interactions-mode interactions-mode}]
|
||||
[:div.thumbnail-close {:on-click on-thumbnails-close
|
||||
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
|
||||
[:& thumbnails-panel {:frames frames
|
||||
:show? (:show-thumbnails local false)
|
||||
:page page
|
||||
:index index
|
||||
:thumbnail-data (:thumbnails file)}]
|
||||
[:section.viewer-section {:id "viewer-section"
|
||||
:ref viewer-section-ref
|
||||
:class (if fullscreen? "fullscreen" "")
|
||||
:on-click click-on-screen}
|
||||
(cond
|
||||
(empty? frames)
|
||||
[:section.empty-state
|
||||
[:span (tr "viewer.empty-state")]]
|
||||
|
||||
(nil? frame)
|
||||
[:section.empty-state
|
||||
(when (some? index)
|
||||
[:span (tr "viewer.frame-not-found")])]
|
||||
|
||||
(some? frame)
|
||||
(if (= :inspect section)
|
||||
[:& inspect/viewport
|
||||
{:frame frame
|
||||
:page page
|
||||
:file file
|
||||
:section section
|
||||
:local local
|
||||
:size size
|
||||
:index index
|
||||
:viewer-pagination viewer-pagination
|
||||
:interactions-mode interactions-mode
|
||||
:share-id share-id}]
|
||||
|
||||
|
||||
[:& (mf/provider ctx/current-zoom) {:value zoom}
|
||||
[:& viewer-wrapper
|
||||
{:wrapper-size wrapper-size
|
||||
:orig-frame orig-frame
|
||||
:orig-viewport-ref orig-viewport-ref
|
||||
:orig-size orig-size
|
||||
:page page
|
||||
:file file
|
||||
:users users
|
||||
:current-viewport-ref current-viewport-ref
|
||||
:size size
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode
|
||||
:overlays overlays
|
||||
:zoom zoom
|
||||
:section section
|
||||
:index index}]]))]]]))
|
||||
[:& (mf/provider ctx/current-zoom) {:value zoom}
|
||||
[:& viewer-wrapper
|
||||
{:wrapper-size wrapper-size
|
||||
:orig-frame orig-frame
|
||||
:orig-viewport-ref orig-viewport-ref
|
||||
:orig-size orig-size
|
||||
:page page
|
||||
:file file
|
||||
:users users
|
||||
:current-viewport-ref current-viewport-ref
|
||||
:size size
|
||||
:frame frame
|
||||
:interactions-mode interactions-mode
|
||||
:overlays overlays
|
||||
:zoom zoom
|
||||
:section section
|
||||
:index index}]]))]]])))
|
||||
|
||||
;; --- Component: Viewer Page
|
||||
|
||||
|
|
142
frontend/src/app/main/ui/viewer.scss
Normal file
142
frontend/src/app/main/ui/viewer.scss
Normal file
|
@ -0,0 +1,142 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
.viewer-layout {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: $s-48 auto;
|
||||
grid-template-columns: 1fr;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.viewer-content {
|
||||
grid-row: 2 / span 1;
|
||||
display: grid;
|
||||
grid-template-rows: $s-252 auto;
|
||||
grid-template-columns: 1fr;
|
||||
background-color: var(--viewer-background-color);
|
||||
}
|
||||
|
||||
.viewer-header {
|
||||
grid-row: 1 / span 1;
|
||||
}
|
||||
|
||||
.inspect-layout {
|
||||
display: grid;
|
||||
grid-template-rows: $s-48 auto;
|
||||
grid-template-columns: 1fr;
|
||||
height: 100vh;
|
||||
margin-top: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.thumbnails-close {
|
||||
@include buttonStyle;
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1 / span 1;
|
||||
z-index: $z-index-10;
|
||||
background-color: var(--overlay-color);
|
||||
}
|
||||
|
||||
.thumbnails-close.invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.viewer-section {
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1 / span 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
height: calc(100vh - $s-48);
|
||||
flex-flow: wrap;
|
||||
overflow: auto;
|
||||
}
|
||||
.inspect-layout .viewer-section {
|
||||
flex-wrap: nowrap;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.viewer-go-prev,
|
||||
.viewer-go-next {
|
||||
@extend .button-secondary;
|
||||
@include flexCenter;
|
||||
position: absolute;
|
||||
right: $s-8;
|
||||
height: $s-64;
|
||||
width: $s-32;
|
||||
top: calc(50vh - $s-32);
|
||||
z-index: $z-index-2;
|
||||
background-color: var(--viewer-controls-background-color);
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.viewer-go-next.comment-sidebar {
|
||||
right: $s-264;
|
||||
}
|
||||
|
||||
.viewer-go-prev {
|
||||
left: $s-8;
|
||||
right: unset;
|
||||
svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.viewer-bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: $s-40;
|
||||
padding-right: 0 $s-8 $s-40 $s-8;
|
||||
transition: bottom 400ms ease 300ms;
|
||||
z-index: $z-index-2;
|
||||
}
|
||||
|
||||
.reset-button {
|
||||
@extend .button-secondary;
|
||||
@include flexCenter;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
margin-left: $s-8;
|
||||
background-color: var(--viewer-controls-background-color);
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.counter {
|
||||
@include flexCenter;
|
||||
@include titleTipography;
|
||||
border-radius: $br-8;
|
||||
width: $s-64;
|
||||
height: $s-32;
|
||||
background-color: var(--viewer-controls-background-color);
|
||||
}
|
||||
|
||||
.viewer-wrapper {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.viewer-clipper {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: 1fr;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
|
@ -5,7 +5,9 @@
|
|||
;; 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.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
|
@ -16,6 +18,7 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.ui.comments :as cmt]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.comments :as wc]
|
||||
[app.util.dom :as dom]
|
||||
|
@ -28,55 +31,126 @@
|
|||
::mf/wrap-props false}
|
||||
[]
|
||||
(let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local)
|
||||
|
||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
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-callback
|
||||
(fn [mode]
|
||||
(st/emit! (dcm/update-filters {:mode mode}))))
|
||||
(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-callback
|
||||
(fn [mode]
|
||||
(st/emit! (dcm/update-filters {:show mode}))))
|
||||
(fn [event]
|
||||
(let [mode (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(d/read-string))]
|
||||
(st/emit! (dcm/update-filters {:show mode})))))
|
||||
|
||||
update-options
|
||||
(mf/use-callback
|
||||
(fn [mode]
|
||||
(st/emit! (dcm/update-options {:show-sidebar? mode}))))]
|
||||
(fn [event]
|
||||
(let [mode (-> (dom/get-target event)
|
||||
(dom/get-data "value")
|
||||
(boolean))]
|
||||
(st/emit! (dcm/update-options {:show-sidebar? mode})))))]
|
||||
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.label (tr "labels.comments")]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :view-options)
|
||||
:on-click toggle-dropdown}
|
||||
[:span {:class (stl/css :dropdown-title)}
|
||||
(tr "labels.comments")]
|
||||
[:span {:class (stl/css :icon-dropdown)}
|
||||
i/arrow-refactor]
|
||||
[:& 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}
|
||||
|
||||
[:ul.dropdown.with-check
|
||||
[:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode)))
|
||||
:on-click #(update-mode :all)}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-all-comments")]]
|
||||
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
|
||||
(when (or (= :all cmode) (nil? cmode))
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= :yours cmode))
|
||||
:on-click #(update-mode :yours)}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-your-comments")]]
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= :yours cmode))
|
||||
:data-value :yours
|
||||
:on-click update-mode}
|
||||
|
||||
[:hr]
|
||||
[:span {:class (stl/css :label)}
|
||||
(tr "labels.show-your-comments")]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
||||
:on-click #(update-show (if (= :pending cshow) :all :pending))}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.hide-resolved-comments")]]
|
||||
(when (= :yours cmode)
|
||||
[:span {:class (stl/css :icon)}
|
||||
i/tick-refactor])]
|
||||
|
||||
[:hr]
|
||||
[:li {:class (dom/classnames :selected show-sidebar?)
|
||||
:on-click #(update-options (not show-sidebar?))}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-comments-list")]]]]]))
|
||||
[:li {:class (stl/css :separator)}]
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= :pending cshow))
|
||||
:data-value (if (= :pending cshow) :all :pending)
|
||||
:on-click update-show}
|
||||
|
||||
[:span {:class (stl/css :label)}
|
||||
(tr "labels.hide-resolved-comments")]
|
||||
(when (= :pending cshow)
|
||||
[:span {:class (stl/css :icon)}
|
||||
i/tick-refactor])]
|
||||
|
||||
[:li {:class (stl/css :separator)}]
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected show-sidebar?)
|
||||
:data-value (not 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-refactor])]]]]
|
||||
|
||||
|
||||
|
||||
; OLD
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.label (tr "labels.comments")]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
|
||||
[:ul.dropdown.with-check
|
||||
[:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode)))
|
||||
:data-value :all
|
||||
:on-click update-mode}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-all-comments")]]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= :yours cmode))
|
||||
:data-value :yours
|
||||
:on-click update-mode}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-your-comments")]]
|
||||
|
||||
[:hr]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
||||
:data-value (if (= :pending cshow) :all :pending)
|
||||
:on-click update-show}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.hide-resolved-comments")]]
|
||||
|
||||
[:hr]
|
||||
[:li {:class (dom/classnames :selected show-sidebar?)
|
||||
:data-value (not show-sidebar?)
|
||||
:on-click update-options}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.show-comments-list")]]]]])))
|
||||
|
||||
|
||||
(defn- update-thread-position [positions {:keys [id] :as thread}]
|
||||
|
@ -88,7 +162,8 @@
|
|||
|
||||
(mf/defc comments-layer
|
||||
[{:keys [zoom file users frame page] :as props}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
profile (mf/deref refs/profile)
|
||||
local (mf/deref refs/comments-local)
|
||||
|
||||
open-thread-id (:open local)
|
||||
|
@ -159,43 +234,81 @@
|
|||
(st/emit! (dcm/create-thread-on-viewer params)
|
||||
(dcm/close-thread)))))]
|
||||
|
||||
[:div.comments-section {:on-click on-click}
|
||||
[:div.viewer-comments-container
|
||||
[:div.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}])
|
||||
(if new-css-system
|
||||
[: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
|
||||
:users users
|
||||
:zoom zoom}])
|
||||
(when-let [thread (get threads-map open-thread-id)]
|
||||
[:& cmt/thread-comments
|
||||
{:thread thread
|
||||
:position-modifier modifier1
|
||||
: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}])]]]))
|
||||
(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}])]]]
|
||||
|
||||
|
||||
[:div.comments-section {:on-click on-click}
|
||||
[:div.viewer-comments-container
|
||||
[:div.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
|
||||
: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)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
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.settings-bar.settings-bar-right.comments-right-sidebar
|
||||
[:div.settings-bar-inside
|
||||
[:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]]))
|
||||
(if new-css-system
|
||||
[: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)}]]]
|
||||
|
||||
|
||||
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
||||
[:div.settings-bar-inside
|
||||
[:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]])))
|
||||
|
|
119
frontend/src/app/main/ui/viewer/comments.scss
Normal file
119
frontend/src/app/main/ui/viewer/comments.scss
Normal file
|
@ -0,0 +1,119 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
// COMMENT DROPDOWN ON HEADER
|
||||
.view-options {
|
||||
@include titleTipography;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
gap: $s-4;
|
||||
height: $s-32;
|
||||
padding: $s-8;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--input-background-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
@extend .menu-dropdown;
|
||||
right: $s-2;
|
||||
top: calc($s-2 + $s-48);
|
||||
width: $s-272;
|
||||
padding: $s-6;
|
||||
}
|
||||
|
||||
.dropdown-title {
|
||||
@include titleTipography;
|
||||
flex-grow: 1;
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
|
||||
.label {
|
||||
flex-grow: 1;
|
||||
color: var(--input-foreground-color);
|
||||
}
|
||||
|
||||
.icon,
|
||||
.icon-dropdown {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-dropdown svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.dropdown-element {
|
||||
@extend .dropdown-element-base;
|
||||
.icon {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
&:hover .label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-element.selected {
|
||||
.label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
.icon svg {
|
||||
stroke: var(--input-foreground-color);
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: $s-8;
|
||||
}
|
||||
|
||||
// FLOATING COMMENT
|
||||
.viewer-comments-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: $z-index-1;
|
||||
}
|
||||
|
||||
.threads {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
//COMMENT SIDEBAR
|
||||
.comments-sidebar {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: $s-44;
|
||||
width: $s-256;
|
||||
height: calc(100vh - $s-48);
|
||||
z-index: $z-index-10;
|
||||
background-color: var(--panel-background-color);
|
||||
}
|
||||
|
||||
.settings-bar-inside {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.comments-section {
|
||||
background-color: var(--panel-background-color);
|
||||
}
|
|
@ -5,13 +5,16 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.viewer.header
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.shortcuts :as scd]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.data.viewer.shortcuts :as sc]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.export :refer [export-progress-widget]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.icons :as i]
|
||||
|
@ -41,40 +44,120 @@
|
|||
on-zoom-fit
|
||||
on-zoom-fill]
|
||||
:as props}]
|
||||
(let [show-dropdown? (mf/use-state false)]
|
||||
[:div.zoom-widget {:on-click
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(reset! show-dropdown? true))}
|
||||
[:span.label (fmt/format-percent zoom)]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close #(reset! show-dropdown? false)}
|
||||
[:ul.dropdown
|
||||
[:li.basic-zoom-bar
|
||||
[:span.zoom-btns
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-decrease))} "-"]
|
||||
[:p.zoom-size (fmt/format-percent zoom)]
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-increase))} "+"]]
|
||||
[:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]]
|
||||
[:li.separator]
|
||||
[:li {:on-click on-zoom-fit}
|
||||
(tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]]
|
||||
[:li {:on-click on-zoom-fill}
|
||||
(tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]]
|
||||
[:li {:on-click on-fullscreen}
|
||||
(tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]]))
|
||||
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
open* (mf/use-state false)
|
||||
open? (deref open*)
|
||||
open-dropdown
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(reset! open* true)))
|
||||
|
||||
close-dropdown
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(reset! open* false)))
|
||||
|
||||
on-increase
|
||||
(mf/use-fn
|
||||
(mf/deps on-increase)
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(on-increase)))
|
||||
|
||||
on-decrease
|
||||
(mf/use-fn
|
||||
(mf/deps on-decrease)
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(on-decrease)))
|
||||
|
||||
show-dropdown? (mf/use-state false)]
|
||||
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css-case :zoom-widget true
|
||||
:selected open?)
|
||||
:on-click open-dropdown
|
||||
:title (tr "workspace.header.zoom")}
|
||||
[:span {:class (stl/css :label)} (fmt/format-percent zoom)]
|
||||
[:& dropdown {:show open?
|
||||
:on-close close-dropdown}
|
||||
[:ul {:class (stl/css :dropdown)}
|
||||
[:li {:class (stl/css :basic-zoom-bar)}
|
||||
[:span {:class (stl/css :zoom-btns)}
|
||||
[:button {:class (stl/css :zoom-btn)
|
||||
:on-click on-decrease}
|
||||
[:span {:class (stl/css :zoom-icon)}
|
||||
i/remove-refactor]]
|
||||
[:p {:class (stl/css :zoom-text)}
|
||||
(fmt/format-percent zoom)]
|
||||
[:button {:class (stl/css :zoom-btn)
|
||||
:on-click on-increase}
|
||||
[:span {:class (stl/css :zoom-icon)}
|
||||
i/add-refactor]]]
|
||||
[:button {:class (stl/css :reset-btn)
|
||||
:on-click on-zoom-reset}
|
||||
(tr "workspace.header.reset-zoom")]]
|
||||
|
||||
[:li {:class (stl/css :zoom-option)
|
||||
:on-click on-zoom-fit}
|
||||
(tr "workspace.header.zoom-fit")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-fit-" sc)} sc])]]
|
||||
[:li {:class (stl/css :zoom-option)
|
||||
:on-click on-zoom-fill}
|
||||
(tr "workspace.header.zoom-fill")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-fill-" sc)} sc])]]
|
||||
[:li {:class (stl/css :zoom-option)
|
||||
:on-click on-fullscreen}
|
||||
(tr "workspace.header.zoom-full-screen")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))]
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-fullscreen-" sc)} sc])]]]]]
|
||||
|
||||
|
||||
;; OLD
|
||||
[:div.zoom-widget {:on-click
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(reset! show-dropdown? true))}
|
||||
[:span.label (fmt/format-percent zoom)]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close #(reset! show-dropdown? false)}
|
||||
[:ul.dropdown
|
||||
[:li.basic-zoom-bar
|
||||
[:span.zoom-btns
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-decrease))} "-"]
|
||||
[:p.zoom-size (fmt/format-percent zoom)]
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-increase))} "+"]]
|
||||
[:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]]
|
||||
[:li.separator]
|
||||
[:li {:on-click on-zoom-fit}
|
||||
(tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]]
|
||||
[:li {:on-click on-zoom-fill}
|
||||
(tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]]
|
||||
[:li {:on-click on-fullscreen}
|
||||
(tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]])))
|
||||
|
||||
(mf/defc header-options
|
||||
[{:keys [section zoom page file index permissions interactions-mode]}]
|
||||
(let [fullscreen? (mf/deref fullscreen-ref)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
fullscreen? (mf/deref fullscreen-ref)
|
||||
|
||||
toggle-fullscreen
|
||||
(mf/use-callback
|
||||
|
@ -91,49 +174,114 @@
|
|||
(mf/deps page)
|
||||
(fn []
|
||||
(modal/show! :share-link {:page page :file file})
|
||||
(modal/allow-click-outside!)))]
|
||||
(modal/allow-click-outside!)))
|
||||
|
||||
[:div.options-zone
|
||||
(case section
|
||||
:interactions [:*
|
||||
(when index
|
||||
[:& flows-menu {:page page :index index}])
|
||||
[:& interactions-menu {:interactions-mode interactions-mode}]]
|
||||
:comments [:& comments-menu]
|
||||
handle-increase
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/increase-zoom))
|
||||
|
||||
[:div.view-options])
|
||||
handle-decrease
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/decrease-zoom))
|
||||
|
||||
[:& export-progress-widget]
|
||||
[:& zoom-widget
|
||||
{:zoom zoom
|
||||
:on-increase #(st/emit! dv/increase-zoom)
|
||||
:on-decrease #(st/emit! dv/decrease-zoom)
|
||||
:on-zoom-reset #(st/emit! dv/reset-zoom)
|
||||
:on-zoom-fill #(st/emit! dv/zoom-to-fill)
|
||||
:on-zoom-fit #(st/emit! dv/zoom-to-fit)
|
||||
:on-fullscreen toggle-fullscreen}]
|
||||
handle-zoom-reset
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/reset-zoom))
|
||||
|
||||
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
|
||||
{:alt (tr "viewer.header.fullscreen")
|
||||
:on-click toggle-fullscreen}
|
||||
(if fullscreen?
|
||||
i/full-screen-off
|
||||
i/full-screen)]
|
||||
handle-zoom-fill
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/zoom-to-fill))
|
||||
|
||||
(when (:is-admin permissions)
|
||||
[:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]])
|
||||
handle-zoom-fit
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/zoom-to-fit))]
|
||||
|
||||
(when (:can-edit permissions)
|
||||
[:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :options-zone)}
|
||||
(case section
|
||||
:interactions [:*
|
||||
(when index
|
||||
[:& flows-menu {:page page :index index}])
|
||||
[:& interactions-menu {:interactions-mode interactions-mode}]]
|
||||
:comments [:& comments-menu]
|
||||
[:div {:class (stl/css :view-options)}])
|
||||
|
||||
(when-not (:is-logged permissions)
|
||||
[:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])]))
|
||||
[:& export-progress-widget]
|
||||
|
||||
[:& zoom-widget
|
||||
{:zoom zoom
|
||||
:on-increase handle-increase
|
||||
:on-decrease handle-decrease
|
||||
:on-zoom-reset handle-zoom-reset
|
||||
:on-zoom-fill handle-zoom-fill
|
||||
:on-zoom-fit handle-zoom-fit
|
||||
:on-fullscreen toggle-fullscreen}]
|
||||
|
||||
(when (:can-edit permissions)
|
||||
[:span {:on-click go-to-workspace
|
||||
:class (stl/css :edit-btn)}
|
||||
i/curve-refactor])
|
||||
|
||||
[:span {:title (tr "viewer.header.fullscreen")
|
||||
:class (stl/css-case :fullscreen-btn true
|
||||
:selected fullscreen?)
|
||||
:on-click toggle-fullscreen}
|
||||
i/expand-refactor]
|
||||
|
||||
(when (:is-admin permissions)
|
||||
[:button {:on-click open-share-dialog
|
||||
:class (stl/css :share-btn)}
|
||||
(tr "labels.share")])
|
||||
|
||||
(when-not (:is-logged permissions)
|
||||
[:span {:on-click open-login-dialog
|
||||
:class (stl/css :go-log-btn)} (tr "labels.log-or-sign")])]
|
||||
|
||||
|
||||
;; OLD
|
||||
[:div.options-zone
|
||||
(case section
|
||||
:interactions [:*
|
||||
(when index
|
||||
[:& flows-menu {:page page :index index}])
|
||||
[:& interactions-menu {:interactions-mode interactions-mode}]]
|
||||
:comments [:& comments-menu]
|
||||
|
||||
[:div.view-options])
|
||||
|
||||
[:& export-progress-widget]
|
||||
[:& zoom-widget
|
||||
{:zoom zoom
|
||||
:on-increase handle-increase
|
||||
:on-decrease handle-decrease
|
||||
:on-zoom-reset handle-zoom-reset
|
||||
:on-zoom-fill handle-zoom-fill
|
||||
:on-zoom-fit handle-zoom-fit
|
||||
:on-fullscreen toggle-fullscreen}]
|
||||
|
||||
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
|
||||
{:alt (tr "viewer.header.fullscreen")
|
||||
:on-click toggle-fullscreen}
|
||||
(if fullscreen?
|
||||
i/full-screen-off
|
||||
i/full-screen)]
|
||||
|
||||
(when (:is-admin permissions)
|
||||
[:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]])
|
||||
|
||||
(when (:can-edit permissions)
|
||||
[:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])
|
||||
|
||||
(when-not (:is-logged permissions)
|
||||
[:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])])))
|
||||
|
||||
(mf/defc header-sitemap
|
||||
[{:keys [project file page frame] :as props}]
|
||||
(let [project-name (:name project)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
project-name (:name project)
|
||||
file-name (:name file)
|
||||
page-name (:name page)
|
||||
page-id (:id page)
|
||||
frame-name (:name frame)
|
||||
show-dropdown? (mf/use-state false)
|
||||
|
||||
|
@ -158,88 +306,181 @@
|
|||
(st/emit! (dv/go-to-page page-id))
|
||||
(reset! show-dropdown? false)))]
|
||||
|
||||
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
|
||||
[:div.breadcrumb
|
||||
{:on-click open-dropdown}
|
||||
[:span.project-name project-name]
|
||||
[:span "/"]
|
||||
[:span.file-name file-name]
|
||||
[:span "/"]
|
||||
|
||||
[:span.page-name page-name]
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :sitemap-zone)
|
||||
:title (tr "viewer.header.sitemap")}
|
||||
[:span {:class (stl/css :project-name)} project-name]
|
||||
[:div {:class (stl/css :sitemap-text)}
|
||||
[:div {:class (stl/css :breadcrumb)
|
||||
:on-click open-dropdown}
|
||||
[:span {:class (stl/css :breadcrumb-text)}
|
||||
(dm/str file-name " / " page-name)]
|
||||
[:span {:class (stl/css :icon)} i/arrow-refactor]
|
||||
[:span "/"]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close close-dropdown}
|
||||
[:ul {:class (stl/css :dropdown-sitemap)}
|
||||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= page-id id))
|
||||
:id (str id)
|
||||
:key (str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
[:span {:class (stl/css :label)}
|
||||
(get-in file [:data :pages-index id :name])]
|
||||
(when (= page-id id)
|
||||
[:span {:class (stl/css :icon-check)} i/tick-refactor])])]]]
|
||||
[:div {:class (stl/css :current-frame)
|
||||
:on-click toggle-thumbnails}
|
||||
[:span {:class (stl/css :frame-name)} frame-name]
|
||||
[:span {:class (stl/css :icon)} i/arrow-refactor]]]]
|
||||
|
||||
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close close-dropdown}
|
||||
[:ul.dropdown
|
||||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:id (str id)
|
||||
:key (str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
(get-in file [:data :pages-index id :name])])]]]
|
||||
;; OLD
|
||||
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
|
||||
[:div.breadcrumb
|
||||
{:on-click open-dropdown}
|
||||
[:span.project-name project-name]
|
||||
[:span "/"]
|
||||
[:span.file-name file-name]
|
||||
[:span "/"]
|
||||
|
||||
[:span.icon {:on-click open-dropdown} i/arrow-down]
|
||||
[:div.current-frame
|
||||
{:on-click toggle-thumbnails}
|
||||
[:span.label "/"]
|
||||
[:span.label frame-name]]
|
||||
[:span.icon {:on-click toggle-thumbnails} i/arrow-down]]))
|
||||
[:span.page-name page-name]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close close-dropdown}
|
||||
[:ul.dropdown
|
||||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:id (str id)
|
||||
:key (str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
(get-in file [:data :pages-index id :name])])]]]
|
||||
|
||||
[:span.icon {:on-click open-dropdown} i/arrow-down]
|
||||
[:div.current-frame
|
||||
{:on-click toggle-thumbnails}
|
||||
[:span.label "/"]
|
||||
[:span.label frame-name]]
|
||||
[:span.icon {:on-click toggle-thumbnails} i/arrow-down]])))
|
||||
|
||||
(mf/defc header
|
||||
[{:keys [project file page frame zoom section permissions index interactions-mode]}]
|
||||
(let [go-to-dashboard
|
||||
#(st/emit! (dv/go-to-dashboard))
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
go-to-dashboard
|
||||
(mf/use-fn
|
||||
#(st/emit! (dv/go-to-dashboard)))
|
||||
|
||||
go-to-inspect
|
||||
(fn[]
|
||||
(if (:is-logged permissions)
|
||||
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
|
||||
(open-login-dialog)))
|
||||
(mf/use-fn
|
||||
(mf/deps permissions)
|
||||
(fn []
|
||||
(if (:is-logged permissions)
|
||||
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
|
||||
(open-login-dialog))))
|
||||
|
||||
navigate
|
||||
(fn [section]
|
||||
(if (or (= section :interactions) (:is-logged permissions))
|
||||
(st/emit! (dv/go-to-section section))
|
||||
(open-login-dialog)))]
|
||||
(mf/use-fn
|
||||
(mf/deps permissions)
|
||||
(fn [event]
|
||||
(let [section (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(keyword))]
|
||||
|
||||
[:header.viewer-header
|
||||
[:div.nav-zone
|
||||
;; If the user doesn't have permission we disable the link
|
||||
[:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}}
|
||||
[:a {:on-click go-to-dashboard
|
||||
:style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]]
|
||||
(if (or (= section :interactions) (:is-logged permissions))
|
||||
(st/emit! (dv/go-to-section section))
|
||||
(open-login-dialog)))))]
|
||||
|
||||
[:& header-sitemap {:project project :file file :page page :frame frame :index index}]]
|
||||
(if new-css-system
|
||||
[:header {:class (stl/css :viewer-header)}
|
||||
[:div {:class (stl/css :nav-zone)}
|
||||
;; If the user doesn't have permission we disable the link
|
||||
[:a {:class (stl/css :home-link)
|
||||
:on-click go-to-dashboard
|
||||
:style {:cursor (when-not (:can-edit permissions) "auto")
|
||||
:pointer-events (when-not (:can-edit permissions) "none")}}
|
||||
[:span {:class (stl/css :logo-icon)}
|
||||
i/logo-icon]]
|
||||
|
||||
[:div.mode-zone
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click #(navigate :interactions)
|
||||
:class (dom/classnames :active (= section :interactions))
|
||||
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||
i/play]
|
||||
[:& header-sitemap {:project project
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:index index}]]
|
||||
|
||||
(when (or (:can-edit permissions)
|
||||
(= (:who-comment permissions) "all"))
|
||||
[:div {:class (stl/css :mode-zone)}
|
||||
[:button {:on-click navigate
|
||||
:data-value :interactions
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :interactions))
|
||||
:title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||
i/play-refactor]
|
||||
|
||||
(when (or (:can-edit permissions)
|
||||
(= (:who-comment permissions) "all"))
|
||||
[:button {:on-click navigate
|
||||
:data-value :comments
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :comments))
|
||||
:title (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
||||
i/comments-refactor])
|
||||
|
||||
(when (or (= (:type permissions) :membership)
|
||||
(and (= (:type permissions) :share-link)
|
||||
(= (:who-inspect permissions) "all")))
|
||||
[:button {:on-click go-to-inspect
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :inspect))
|
||||
:title (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
|
||||
i/code-refactor])]
|
||||
|
||||
[:& header-options {:section section
|
||||
:permissions permissions
|
||||
:page page
|
||||
:file file
|
||||
:index index
|
||||
:zoom zoom
|
||||
:interactions-mode interactions-mode}]]
|
||||
|
||||
|
||||
;; OLD
|
||||
[:header.viewer-header
|
||||
[:div.nav-zone
|
||||
;; If the user doesn't have permission we disable the link
|
||||
[:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}}
|
||||
[:a {:on-click go-to-dashboard
|
||||
:style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]]
|
||||
|
||||
[:& header-sitemap {:project project :file file :page page :frame frame :index index}]]
|
||||
|
||||
[:div.mode-zone
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click #(navigate :comments)
|
||||
:class (dom/classnames :active (= section :comments))
|
||||
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
||||
i/chat])
|
||||
{:on-click navigate
|
||||
:data-value :interactions
|
||||
:class (dom/classnames :active (= section :interactions))
|
||||
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||
i/play]
|
||||
|
||||
(when (or (= (:type permissions) :membership)
|
||||
(and (= (:type permissions) :share-link)
|
||||
(= (:who-inspect permissions) "all")))
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click go-to-inspect
|
||||
:class (dom/classnames :active (= section :inspect))
|
||||
:alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
|
||||
i/code])]
|
||||
(when (or (:can-edit permissions)
|
||||
(= (:who-comment permissions) "all"))
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click navigate
|
||||
:data-value :comments
|
||||
:class (dom/classnames :active (= section :comments))
|
||||
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
||||
i/chat])
|
||||
|
||||
[:& header-options {:section section
|
||||
:permissions permissions
|
||||
:page page
|
||||
:file file
|
||||
:index index
|
||||
:zoom zoom
|
||||
:interactions-mode interactions-mode}]]))
|
||||
(when (or (= (:type permissions) :membership)
|
||||
(and (= (:type permissions) :share-link)
|
||||
(= (:who-inspect permissions) "all")))
|
||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||
{:on-click go-to-inspect
|
||||
:class (dom/classnames :active (= section :inspect))
|
||||
:alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
|
||||
i/code])]
|
||||
|
||||
[:& header-options {:section section
|
||||
:permissions permissions
|
||||
:page page
|
||||
:file file
|
||||
:index index
|
||||
:zoom zoom
|
||||
:interactions-mode interactions-mode}]])))
|
||||
|
|
301
frontend/src/app/main/ui/viewer/header.scss
Normal file
301
frontend/src/app/main/ui/viewer/header.scss
Normal file
|
@ -0,0 +1,301 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
.viewer-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
grid-column: 1 / span 1;
|
||||
grid-row: 1 / span 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr $s-92 1fr;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: $s-48;
|
||||
width: 100vw;
|
||||
padding: $s-8 $s-12;
|
||||
background-color: var(--panel-background-color);
|
||||
}
|
||||
|
||||
// FILE NAVIGATION
|
||||
|
||||
.nav-zone {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-basis: min-content;
|
||||
width: 100%;
|
||||
gap: $s-12;
|
||||
}
|
||||
|
||||
.home-link {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
@include flexCenter;
|
||||
width: $s-32;
|
||||
height: $s-32;
|
||||
svg {
|
||||
width: $s-28;
|
||||
fill: var(--icon-foreground-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.sitemap-zone {
|
||||
@include flexColumn;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.project-name {
|
||||
@include tabTitleTipography;
|
||||
}
|
||||
|
||||
.sitemap-text {
|
||||
@include flexRow;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
@include titleTipography;
|
||||
@include flexRow;
|
||||
color: var(--title-foreground-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.breadcrumb-text {
|
||||
@include textEllipsis;
|
||||
max-width: 12vw; // This is a fallback
|
||||
max-width: 12cqw; // This is a unit refered to container
|
||||
}
|
||||
|
||||
.icon {
|
||||
@include flexCenter;
|
||||
height: $s-16;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
transform: rotate(90deg);
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.dropdown-sitemap {
|
||||
@extend .menu-dropdown;
|
||||
left: 0;
|
||||
top: calc($s-2 + $s-48);
|
||||
width: $s-272;
|
||||
padding: $s-6;
|
||||
}
|
||||
|
||||
.dropdown-element {
|
||||
@extend .dropdown-element-base;
|
||||
.icon-check {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
&:hover .label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
.current-frame {
|
||||
@include titleTipography;
|
||||
@include flexRow;
|
||||
flex-grow: 1;
|
||||
color: var(--title-foreground-color-hover);
|
||||
cursor: pointer;
|
||||
.icon svg {
|
||||
stroke: var(--title-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.frame-name {
|
||||
@include textEllipsis;
|
||||
max-width: 17vw; // This is a fallback
|
||||
max-width: 17cqw; // This is a unit refered to container
|
||||
}
|
||||
|
||||
// SECTION BUTTONS
|
||||
.mode-zone {
|
||||
@include flexRow;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mode-zone-btn {
|
||||
@extend .button-tertiary;
|
||||
@include flexCenter;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
padding: 0;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
@extend .button-icon-selected;
|
||||
}
|
||||
|
||||
// OPTION AREA
|
||||
.options-zone {
|
||||
@include flexRow;
|
||||
position: relative;
|
||||
justify-content: flex-end;
|
||||
gap: $s-8;
|
||||
z-index: $z-index-10;
|
||||
}
|
||||
|
||||
.view-options {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
@extend .button-tertiary;
|
||||
@include flexCenter;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
@extend .button-primary;
|
||||
height: $s-32;
|
||||
min-width: $s-72;
|
||||
margin-left: $s-4;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
@extend .button-tertiary;
|
||||
@include flexCenter;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.go-log-btn {
|
||||
@extend .button-tertiary;
|
||||
@include titleTipography;
|
||||
height: $s-32;
|
||||
padding: 0 $s-8;
|
||||
border-radius: $br-8;
|
||||
color: var(--button-tertiary-foreground-color-rest);
|
||||
}
|
||||
|
||||
// ZOOM WIDGET
|
||||
.zoom-widget {
|
||||
@include buttonStyle;
|
||||
@include flexCenter;
|
||||
height: $s-28;
|
||||
min-width: $s-64;
|
||||
border-radius: $br-8;
|
||||
.label {
|
||||
@include titleTipography;
|
||||
color: var(--button-tertiary-foreground-color-rest);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.label {
|
||||
color: var(--button-tertiary-foreground-color-focus);
|
||||
}
|
||||
}
|
||||
&.selected {
|
||||
.label {
|
||||
color: var(--button-tertiary-foreground-color-focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
@extend .menu-dropdown;
|
||||
right: $s-2;
|
||||
top: calc($s-2 + $s-48);
|
||||
width: $s-272;
|
||||
}
|
||||
|
||||
.basic-zoom-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: $s-6;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.zoom-btns {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.zoom-btn {
|
||||
@extend .button-tertiary;
|
||||
height: $s-28;
|
||||
width: $s-28;
|
||||
border-radius: $br-8;
|
||||
.zoom-icon {
|
||||
@include flexCenter;
|
||||
width: $s-24;
|
||||
height: $s-32;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.zoom-icon svg {
|
||||
stroke: var(--button-tertiary-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-text {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
min-width: $s-64;
|
||||
padding: 0;
|
||||
margin: 0 $s-2;
|
||||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
@extend .button-tertiary;
|
||||
color: var(--button-tertiary-foreground-color-hover);
|
||||
height: $s-28;
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.zoom-option {
|
||||
@extend .menu-item;
|
||||
.shortcuts {
|
||||
@extend .shortcut;
|
||||
.shortcut-key {
|
||||
@extend .shortcut-key;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
.shortcuts {
|
||||
.shortcut-key {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,13 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.viewer.inspect
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
||||
[app.main.ui.viewer.inspect.left-sidebar :refer [left-sidebar]]
|
||||
[app.main.ui.viewer.inspect.render :refer [render-frame-svg]]
|
||||
|
@ -20,25 +23,27 @@
|
|||
(:import goog.events.EventType))
|
||||
|
||||
(defn handle-select-frame
|
||||
[frame]
|
||||
(fn [event]
|
||||
[event]
|
||||
(let [frame-id (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(d/read-string))
|
||||
origin (dom/get-target event)
|
||||
over-section? (dom/class? origin "inspect-svg-container")
|
||||
layout (dom/get-element "viewer-layout")
|
||||
has-force? (dom/class? layout "force-visible")]
|
||||
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dv/select-shape (:id frame)))
|
||||
|
||||
(let [origin (dom/get-target event)
|
||||
over-section? (dom/class? origin "inspect-svg-container")
|
||||
layout (dom/get-element "viewer-layout")
|
||||
has-force? (dom/class? layout "force-visible")]
|
||||
|
||||
(when over-section?
|
||||
(if has-force?
|
||||
(dom/remove-class! layout "force-visible")
|
||||
(dom/add-class! layout "force-visible"))))))
|
||||
(st/emit! (dv/select-shape frame-id))
|
||||
(when over-section?
|
||||
(if has-force?
|
||||
(dom/remove-class! layout "force-visible")
|
||||
(dom/add-class! layout "force-visible")))))
|
||||
|
||||
(mf/defc viewport
|
||||
[{:keys [local file page frame index viewer-pagination size share-id]}]
|
||||
(let [inspect-svg-container-ref (mf/use-ref nil)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
inspect-svg-container-ref (mf/use-ref nil)
|
||||
current-section* (mf/use-state :info)
|
||||
current-section (deref current-section*)
|
||||
|
||||
|
@ -77,7 +82,8 @@
|
|||
handle-expand
|
||||
(mf/use-callback
|
||||
(mf/deps right-size)
|
||||
#(set-right-size (if (> right-size 276) 276 768)))]
|
||||
(fn[]
|
||||
(set-right-size (if (> right-size 276) 276 768))))]
|
||||
|
||||
(mf/use-effect on-mount)
|
||||
|
||||
|
@ -86,26 +92,60 @@
|
|||
(fn []
|
||||
(st/emit! (dv/select-shape (:id frame)))))
|
||||
|
||||
[:*
|
||||
[:& left-sidebar {:frame frame
|
||||
:local local
|
||||
:page page}]
|
||||
[:div.inspect-svg-wrapper {:on-click (handle-select-frame frame)}
|
||||
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
|
||||
[:div.inspect-svg-container {:ref inspect-svg-container-ref}
|
||||
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
|
||||
(if new-css-system
|
||||
[:*
|
||||
[:& left-sidebar {:frame frame
|
||||
:local local
|
||||
:page page}]
|
||||
[:div {:class (stl/css :inspect-svg-wrapper)
|
||||
:data-value (pr-str (:id frame))
|
||||
:on-click handle-select-frame}
|
||||
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
|
||||
[:div {:class (stl/css :inspect-svg-container)
|
||||
:ref inspect-svg-container-ref}
|
||||
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
|
||||
|
||||
[:div.sidebar-container
|
||||
{:class (when (not can-be-expanded?) "not-expand")
|
||||
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
|
||||
[:div.resize-area
|
||||
{:on-pointer-down on-pointer-down
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
:on-pointer-move on-pointer-move}]
|
||||
[:& right-sidebar {:frame frame
|
||||
:selected (:selected local)
|
||||
:page page
|
||||
:file file
|
||||
:on-change-section handle-change-section
|
||||
:on-expand handle-expand
|
||||
:share-id share-id}]]]))
|
||||
[:div {:class (stl/css-case :sidebar-container true
|
||||
:not-expand (not can-be-expanded?)
|
||||
:expanded can-be-expanded?)
|
||||
|
||||
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
|
||||
(when can-be-expanded?
|
||||
[:div {:class (stl/css :resize-area)
|
||||
:on-pointer-down on-pointer-down
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
:on-pointer-move on-pointer-move}])
|
||||
[:& right-sidebar {:frame frame
|
||||
:selected (:selected local)
|
||||
:page page
|
||||
:file file
|
||||
:on-change-section handle-change-section
|
||||
:on-expand handle-expand
|
||||
:share-id share-id}]]]
|
||||
|
||||
|
||||
;;OLD
|
||||
[:*
|
||||
[:& left-sidebar {:frame frame
|
||||
:local local
|
||||
:page page}]
|
||||
[:div.inspect-svg-wrapper {:data-value (pr-str (:id frame))
|
||||
:on-click handle-select-frame}
|
||||
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
|
||||
[:div.inspect-svg-container {:ref inspect-svg-container-ref}
|
||||
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
|
||||
|
||||
[:div.sidebar-container
|
||||
{:class (when (not can-be-expanded?) "not-expand")
|
||||
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
|
||||
[:div.resize-area
|
||||
{:on-pointer-down on-pointer-down
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
:on-pointer-move on-pointer-move}]
|
||||
[:& right-sidebar {:frame frame
|
||||
:selected (:selected local)
|
||||
:page page
|
||||
:file file
|
||||
:on-change-section handle-change-section
|
||||
:on-expand handle-expand
|
||||
:share-id share-id}]]])))
|
||||
|
|
56
frontend/src/app/main/ui/viewer/inspect.scss
Normal file
56
frontend/src/app/main/ui/viewer/inspect.scss
Normal file
|
@ -0,0 +1,56 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
$width-settings-bar: $s-276;
|
||||
$width-settings-bar-max: $s-500;
|
||||
|
||||
.inspect-svg-wrapper {
|
||||
@include flexCenter;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.inspect-svg-container {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: safe center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
position: relative;
|
||||
align-self: flex-start;
|
||||
width: $width-settings-bar;
|
||||
|
||||
background-color: var(--panel-background-color);
|
||||
border-top: $s-1 solid var(--search-bar-input-border-color);
|
||||
}
|
||||
|
||||
.not-expand {
|
||||
max-width: $width-settings-bar;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
width: var(--width, $width-settings-bar);
|
||||
}
|
||||
|
||||
.resize-area {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: $s-8;
|
||||
height: 100%;
|
||||
z-index: $z-index-10;
|
||||
cursor: ew-resize;
|
||||
}
|
|
@ -87,8 +87,8 @@
|
|||
(handle-change-tab :info))))
|
||||
|
||||
(if new-css-system
|
||||
[:aside {:class (stl/css :settings-bar-right)}
|
||||
|
||||
[:aside {:class (stl/css-case :settings-bar-right true
|
||||
:viewer-code (= from :inspect))}
|
||||
(if (seq shapes)
|
||||
[:div {:class (stl/css :tool-windows)}
|
||||
[:div {:class (stl/css :shape-row)}
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
.settings-bar-right {
|
||||
min-width: $s-252;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
left: unset;
|
||||
right: unset;
|
||||
grid-area: right-sidebar;
|
||||
padding-top: $s-8;
|
||||
padding-left: $s-12;
|
||||
.tool-windows {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
@ -64,9 +66,11 @@
|
|||
padding: $s-8 $s-24;
|
||||
}
|
||||
}
|
||||
|
||||
.inspect-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
&.viewer-code {
|
||||
height: calc(100vh - $s-48);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.viewer.interactions
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
|
@ -18,6 +19,7 @@
|
|||
[app.main.data.viewer :as dv]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.viewer.shapes :as shapes]
|
||||
|
@ -191,77 +193,144 @@
|
|||
(mf/defc flows-menu
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [page index]}]
|
||||
(let [flows (dm/get-in page [:options :flows])
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
flows (dm/get-in page [:options :flows])
|
||||
frames (:frames page)
|
||||
frame (get frames index)
|
||||
current-flow (mf/use-state
|
||||
(ctp/get-frame-flow flows (:id frame)))
|
||||
current-flow* (mf/use-state
|
||||
#(ctp/get-frame-flow flows (:id frame)))
|
||||
|
||||
show-dropdown? (mf/use-state false)
|
||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||
current-flow (deref current-flow*)
|
||||
|
||||
show-dropdown?* (mf/use-state false)
|
||||
show-dropdown? (deref show-dropdown?*)
|
||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown?* not))
|
||||
hide-dropdown (mf/use-fn #(reset! show-dropdown?* false))
|
||||
|
||||
select-flow
|
||||
(mf/use-callback
|
||||
(fn [flow]
|
||||
(reset! current-flow flow)
|
||||
(st/emit! (dv/go-to-frame (:starting-frame flow)))))]
|
||||
(fn [event]
|
||||
(let [flow (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(d/read-string))]
|
||||
(reset! current-flow* flow)
|
||||
(st/emit! (dv/go-to-frame (:starting-frame flow))))))]
|
||||
|
||||
(when (seq flows)
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.icon i/play]
|
||||
[:span.label (:name @current-flow)]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul.dropdown.with-check
|
||||
(for [[index flow] (d/enumerate flows)]
|
||||
[:li {:key (dm/str "flow-" (:id flow) "-" index)
|
||||
:class (dom/classnames :selected (= (:id flow) (:id @current-flow)))
|
||||
:on-click #(select-flow flow)}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (:name flow)]])]]])))
|
||||
(if new-css-system
|
||||
[:div {:on-click toggle-dropdown
|
||||
:class (stl/css :view-options)}
|
||||
[:span {:class (stl/css :icon)} i/play-refactor]
|
||||
[:span {:class (stl/css :dropdown-title)} (:name current-flow)]
|
||||
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
|
||||
[:& dropdown {:show show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul {:class (stl/css :dropdown)}
|
||||
(for [[index flow] (d/enumerate flows)]
|
||||
[:li {:key (dm/str "flow-" (:id flow) "-" index)
|
||||
:class (stl/css-case :dropdown-element true
|
||||
:selected (= (:id flow) (:id current-flow)))
|
||||
;; This is not a best practise, is not very performant Do not reproduce
|
||||
:data-value (pr-str flow)
|
||||
:on-click select-flow}
|
||||
[:span {:class (stl/css :label)} (:name flow)]
|
||||
(when (= (:id flow) (:id current-flow))
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])])]]]
|
||||
|
||||
;; OLD
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.icon i/play]
|
||||
[:span.label (:name current-flow)]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul.dropdown.with-check
|
||||
(for [[index flow] (d/enumerate flows)]
|
||||
[:li {:key (dm/str "flow-" (:id flow) "-" index)
|
||||
:class (dom/classnames :selected (= (:id flow) (:id current-flow)))
|
||||
;; This is not a best practise, is not very performant Do not reproduce
|
||||
:data-value (pr-str flow)
|
||||
:on-click select-flow}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (:name flow)]])]]]))))
|
||||
|
||||
(mf/defc interactions-menu
|
||||
[{:keys [interactions-mode]}]
|
||||
(let [show-dropdown? (mf/use-state false)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
show-dropdown? (mf/use-state false)
|
||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||
|
||||
select-mode
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [mode (some-> (dom/get-current-target event)
|
||||
(dom/get-data "mode")
|
||||
(keyword))]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dv/set-interactions-mode mode)))))]
|
||||
(fn [event]
|
||||
(let [mode (some-> (dom/get-current-target event)
|
||||
(dom/get-data "mode")
|
||||
(keyword))]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dv/set-interactions-mode mode)))))]
|
||||
(if new-css-system
|
||||
[:div {:on-click toggle-dropdown
|
||||
:class (stl/css :view-options)}
|
||||
[:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")]
|
||||
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul {:class (stl/css :dropdown)}
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= interactions-mode :hide))
|
||||
:on-click select-mode
|
||||
:data-mode :hide}
|
||||
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.label (tr "viewer.header.interactions")]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul.dropdown.with-check
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :hide))
|
||||
:on-click select-mode
|
||||
:data-mode :hide}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.dont-show-interactions")]]
|
||||
[:span {:class (stl/css :label)} (tr "viewer.header.dont-show-interactions")]
|
||||
(when (= interactions-mode :hide)
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :show))
|
||||
:on-click select-mode
|
||||
:data-mode :show}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.show-interactions")]]
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= interactions-mode :show))
|
||||
:on-click select-mode
|
||||
:data-mode :show}
|
||||
[:span {:class (stl/css :label)} (tr "viewer.header.show-interactions")]
|
||||
(when (= interactions-mode :show)
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :show-on-click))
|
||||
:on-click select-mode
|
||||
:data-mode :show-on-click}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.show-interactions-on-click")]]]]]))
|
||||
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= interactions-mode :show-on-click))
|
||||
:on-click select-mode
|
||||
:data-mode :show-on-click}
|
||||
|
||||
[:span {:class (stl/css :label)} (tr "viewer.header.show-interactions-on-click")]
|
||||
(when (= interactions-mode :show-on-click)
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])]]]]
|
||||
|
||||
|
||||
|
||||
[:div.view-options {:on-click toggle-dropdown}
|
||||
[:span.label (tr "viewer.header.interactions")]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-dropdown}
|
||||
[:ul.dropdown.with-check
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :hide))
|
||||
:on-click select-mode
|
||||
:data-mode :hide}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.dont-show-interactions")]]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :show))
|
||||
:on-click select-mode
|
||||
:data-mode :show}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.show-interactions")]]
|
||||
|
||||
[:li {:class (dom/classnames :selected (= interactions-mode :show-on-click))
|
||||
:on-click select-mode
|
||||
:data-mode :show-on-click}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "viewer.header.show-interactions-on-click")]]]]])))
|
||||
|
||||
(defn animate-go-to-frame
|
||||
[animation current-viewport orig-viewport current-size orig-size wrapper-size]
|
||||
(case (:animation-type animation)
|
||||
|
|
80
frontend/src/app/main/ui/viewer/interactions.scss
Normal file
80
frontend/src/app/main/ui/viewer/interactions.scss
Normal file
|
@ -0,0 +1,80 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
.view-options {
|
||||
@include titleTipography;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
gap: $s-4;
|
||||
height: $s-32;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--input-background-color);
|
||||
padding: $s-8;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dropdown-title {
|
||||
@include titleTipography;
|
||||
flex-grow: 1;
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
|
||||
.label {
|
||||
flex-grow: 1;
|
||||
color: var(--input-foreground-color);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
@extend .menu-dropdown;
|
||||
right: $s-2;
|
||||
top: calc($s-2 + $s-48);
|
||||
width: $s-272;
|
||||
padding: $s-6;
|
||||
}
|
||||
|
||||
.dropdown-element {
|
||||
@extend .dropdown-element-base;
|
||||
.icon {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
&:hover .label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-element.selected {
|
||||
.label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
.icon svg {
|
||||
stroke: var(--input-foreground-color);
|
||||
}
|
||||
}
|
||||
|
||||
.icon,
|
||||
.icon-dropdown {
|
||||
@include flexCenter;
|
||||
height: 100%;
|
||||
width: $s-16;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-dropdown svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
// breakpoint 1013px
|
|
@ -5,6 +5,7 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.viewer.login
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.logging :as log]
|
||||
[app.main.data.modal :as modal]
|
||||
|
@ -13,6 +14,7 @@
|
|||
[app.main.ui.auth.login :refer [login-methods]]
|
||||
[app.main.ui.auth.recovery-request :refer [recovery-request-page]]
|
||||
[app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
@ -25,15 +27,31 @@
|
|||
{::mf/register modal/components
|
||||
::mf/register-as :login-register}
|
||||
[_]
|
||||
(let [uri (. (. js/document -location) -href)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
uri (. (. js/document -location) -href)
|
||||
user-email (mf/use-state "")
|
||||
register-token (mf/use-state "")
|
||||
current-section (mf/use-state :login)
|
||||
set-current-section (mf/use-fn #(reset! current-section %))
|
||||
|
||||
current-section* (mf/use-state :login)
|
||||
current-section (deref current-section*)
|
||||
|
||||
set-current-section
|
||||
(mf/use-fn #(reset! current-section* %))
|
||||
|
||||
set-section
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [section (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(keyword))]
|
||||
(set-current-section section))))
|
||||
|
||||
go-back-to-login (mf/use-fn #(set-current-section :login))
|
||||
|
||||
main-section (or
|
||||
(= @current-section :login)
|
||||
(= @current-section :register)
|
||||
(= @current-section :register-validate))
|
||||
(= current-section :login)
|
||||
(= current-section :register)
|
||||
(= current-section :register-validate))
|
||||
close
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
|
@ -49,57 +67,118 @@
|
|||
(fn [data]
|
||||
(reset! register-token (:token data))
|
||||
(set-current-section :register-validate))]
|
||||
|
||||
(mf/with-effect []
|
||||
(swap! storage assoc :redirect-url uri))
|
||||
[:div.modal-overlay
|
||||
[:div.modal-container.login-register
|
||||
[:div.title
|
||||
[:div.modal-close-button {:on-click close :title (tr "labels.close")}
|
||||
i/close]
|
||||
(when main-section
|
||||
[:h2 (tr "labels.continue-with-penpot")])]
|
||||
|
||||
[:div.modal-bottom.auth-content
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-container)}
|
||||
[:div {:class (stl/css :modal-header)}
|
||||
[:h2 {:class (stl/css :modal-title)} (tr "labels.continue-with-penpot")]
|
||||
[:button {:class (stl/css :modal-close-btn)
|
||||
:title (tr "labels.close")
|
||||
:on-click close} i/close-refactor]]
|
||||
|
||||
(case @current-section
|
||||
:login
|
||||
[:div.generic-form.login-form
|
||||
[:div.form-container
|
||||
[:& login-methods {:on-success-callback success-login}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:a {:on-click #(set-current-section :recovery-request)}
|
||||
(tr "auth.forgot-password")]]
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.register") " "]
|
||||
[:a {:on-click #(set-current-section :register)}
|
||||
(tr "auth.register-submit")]]]]]
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
|
||||
:register
|
||||
[:div.form-container
|
||||
[:& register-methods {:on-success-callback success-register}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.already-have-account") " "]
|
||||
[:a {:on-click #(set-current-section :login)}
|
||||
(tr "auth.login-here")]]]]
|
||||
(case current-section
|
||||
:login
|
||||
[:div {:class (stl/css :form-container)}
|
||||
[:& login-methods {:on-success-callback success-login :origin :viewer}]
|
||||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :link-entry)}
|
||||
[:a {:on-click set-section
|
||||
:data-value :recovery-request}
|
||||
(tr "auth.forgot-password")]]
|
||||
[:div {:class (stl/css :link-entry)}
|
||||
[:span (tr "auth.register") " "]
|
||||
[:a {:on-click set-section
|
||||
:data-value :register}
|
||||
(tr "auth.register-submit")]]]]
|
||||
|
||||
:register-validate
|
||||
[:div.form-container
|
||||
[:& register-validate-form {:params {:token @register-token}
|
||||
:register
|
||||
[:div {:class (stl/css :form-container)}
|
||||
[:& register-methods {:on-success-callback success-register}]
|
||||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :link-entry)}
|
||||
[:span (tr "auth.already-have-account") " "]
|
||||
[:a {:on-click set-section
|
||||
:data-value :login}
|
||||
(tr "auth.login-here")]]]]
|
||||
|
||||
:register-validate
|
||||
[:div {:class (stl/css :form-container)}
|
||||
[:& register-validate-form {:params {:token @register-token}
|
||||
:on-success-callback success-email-sent}]
|
||||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :link-entry)}
|
||||
[:a {:on-click set-section
|
||||
:data-value :register}
|
||||
(tr "labels.go-back")]]]]
|
||||
|
||||
:recovery-request
|
||||
[:& recovery-request-page {:go-back-callback go-back-to-login
|
||||
:on-success-callback success-email-sent}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:a {:on-click #(set-current-section :register)}
|
||||
(tr "labels.go-back")]]]]
|
||||
:email-sent
|
||||
[:div {:class (stl/css :form-container)}
|
||||
[:& register-success-page {:params {:email @user-email}}]])
|
||||
|
||||
:recovery-request
|
||||
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
|
||||
:on-success-callback success-email-sent}]
|
||||
:email-sent
|
||||
[:div.form-container
|
||||
[:& register-success-page {:params {:email @user-email}}]])]
|
||||
(when main-section
|
||||
[:div {:class (stl/css :links)}
|
||||
[:& terms-login]])]]]
|
||||
|
||||
(when main-section
|
||||
[:div.modal-footer.links
|
||||
[:& terms-login]])]]))
|
||||
|
||||
;;OLD
|
||||
[:div.modal-overlay
|
||||
[:div.modal-container.login-register
|
||||
[:div.title
|
||||
[:div.modal-close-button {:on-click close :title (tr "labels.close")}
|
||||
i/close]
|
||||
(when main-section
|
||||
[:h2 (tr "labels.continue-with-penpot")])]
|
||||
|
||||
[:div.modal-bottom.auth-content
|
||||
|
||||
(case current-section
|
||||
:login
|
||||
[:div.generic-form.login-form
|
||||
[:div.form-container
|
||||
[:& login-methods {:on-success-callback success-login}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:a {:on-click #(set-current-section :recovery-request)}
|
||||
(tr "auth.forgot-password")]]
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.register") " "]
|
||||
[:a {:on-click #(set-current-section :register)}
|
||||
(tr "auth.register-submit")]]]]]
|
||||
|
||||
:register
|
||||
[:div.form-container
|
||||
[:& register-methods {:on-success-callback success-register}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:span (tr "auth.already-have-account") " "]
|
||||
[:a {:on-click #(set-current-section :login)}
|
||||
(tr "auth.login-here")]]]]
|
||||
|
||||
:register-validate
|
||||
[:div.form-container
|
||||
[:& register-validate-form {:params {:token @register-token}
|
||||
:on-success-callback success-email-sent}]
|
||||
[:div.links
|
||||
[:div.link-entry
|
||||
[:a {:on-click #(set-current-section :register)}
|
||||
(tr "labels.go-back")]]]]
|
||||
|
||||
:recovery-request
|
||||
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
|
||||
:on-success-callback success-email-sent}]
|
||||
:email-sent
|
||||
[:div.form-container
|
||||
[:& register-success-page {:params {:email @user-email}}]])]
|
||||
|
||||
(when main-section
|
||||
[:div.modal-footer.links
|
||||
[:& terms-login]])]])))
|
||||
|
|
73
frontend/src/app/main/ui/viewer/login.scss
Normal file
73
frontend/src/app/main/ui/viewer/login.scss
Normal file
|
@ -0,0 +1,73 @@
|
|||
// 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
|
||||
|
||||
@import "refactor/common-refactor.scss";
|
||||
|
||||
.modal-overlay {
|
||||
@extend .modal-overlay-base;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@extend .modal-container-base;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
margin-bottom: $s-24;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@include tabTitleTipography;
|
||||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
.modal-close-btn {
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@include flexColumn;
|
||||
@include titleTipography;
|
||||
gap: $s-24;
|
||||
max-height: $s-400;
|
||||
width: $s-368;
|
||||
overflow: hidden auto;
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
max-width: $s-368;
|
||||
}
|
||||
|
||||
.links {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.link-entry {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-12;
|
||||
|
||||
span {
|
||||
text-align: center;
|
||||
font-size: $fs-14;
|
||||
color: var(--modal-text-foreground-color);
|
||||
margin-top: $s-12;
|
||||
}
|
||||
a {
|
||||
@extend .button-secondary;
|
||||
height: $s-40;
|
||||
text-transform: uppercase;
|
||||
font-size: $fs-11;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
;; 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]
|
||||
|
@ -16,6 +17,8 @@
|
|||
[app.main.data.modal :as modal]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.select :refer [select]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
@ -37,7 +40,8 @@
|
|||
::mf/register-as :share-link
|
||||
::mf/wrap-props false}
|
||||
[{:keys [file page]}]
|
||||
(let [current-page page
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
current-page page
|
||||
current-page-id (:id page)
|
||||
slinks (mf/deref refs/share-links)
|
||||
router (mf/deref refs/router)
|
||||
|
@ -151,135 +155,284 @@
|
|||
(fn [_]
|
||||
(swap! perms-visible* not))
|
||||
|
||||
on-who-change
|
||||
(fn [type event]
|
||||
(let [target (dom/get-target event)
|
||||
value (dom/get-value target)
|
||||
value (keyword value)]
|
||||
(reset! confirm* false)
|
||||
(if (= type :comment)
|
||||
(swap! options* assoc :who-comment (d/name value))
|
||||
(swap! options* assoc :who-inspect (d/name value)))))]
|
||||
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))]
|
||||
|
||||
(if new-css-system
|
||||
[: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-refactor]]
|
||||
[: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-refactor]])
|
||||
|
||||
[: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")}])]]
|
||||
|
||||
|
||||
[:div.modal-overlay.transparent.share-modal
|
||||
[:div.modal-container.share-link-dialog
|
||||
[:div.modal-content.initial
|
||||
[:div.title
|
||||
[:h2 (tr "common.share-link.title")]
|
||||
[:div.modal-close-button
|
||||
{:on-click on-close
|
||||
:title (tr "labels.close")}
|
||||
i/close]]]
|
||||
[:div.modal-content
|
||||
[:div.share-link-section
|
||||
(when (and (not confirm?) (some? current-link))
|
||||
[:div.custom-input.with-icon
|
||||
[:input {:type "text"
|
||||
:value (or current-link "")
|
||||
:placeholder (tr "common.share-link.placeholder")
|
||||
:read-only true}]
|
||||
[:div.help-icon {:title (tr "viewer.header.share.copy-link")
|
||||
:on-click copy-link}
|
||||
i/copy]])
|
||||
[:div.hint-wrapper
|
||||
(when (not ^boolean confirm?)
|
||||
[:div.hint (tr "common.share-link.permissions-hint")])
|
||||
(cond
|
||||
(true? confirm?)
|
||||
[:div.confirm-dialog
|
||||
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
|
||||
[:div.actions
|
||||
[: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-refactor]
|
||||
(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)}
|
||||
[: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}]
|
||||
[:label {:for (str "page-" current-page-id)} (:name current-page)]
|
||||
[:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/checked true)}
|
||||
i/status-tick-refactor]
|
||||
[: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-refactor)]
|
||||
(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-refactor)]
|
||||
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}]]]])])]]]
|
||||
|
||||
|
||||
;;OLD
|
||||
[:div.modal-overlay.transparent.share-modal
|
||||
[:div.modal-container.share-link-dialog
|
||||
[:div.modal-content.initial
|
||||
[:div.title
|
||||
[:h2 (tr "common.share-link.title")]
|
||||
[:div.modal-close-button
|
||||
{:on-click on-close
|
||||
:title (tr "labels.close")}
|
||||
i/close]]]
|
||||
[:div.modal-content
|
||||
[:div.share-link-section
|
||||
(when (and (not confirm?) (some? current-link))
|
||||
[:div.custom-input.with-icon
|
||||
[:input {:type "text"
|
||||
:value (or current-link "")
|
||||
:placeholder (tr "common.share-link.placeholder")
|
||||
:read-only true}]
|
||||
[:div.help-icon {:title (tr "viewer.header.share.copy-link")
|
||||
:on-click copy-link}
|
||||
i/copy]])
|
||||
[:div.hint-wrapper
|
||||
(when (not ^boolean confirm?)
|
||||
[:div.hint (tr "common.share-link.permissions-hint")])
|
||||
(cond
|
||||
(true? confirm?)
|
||||
[:div.confirm-dialog
|
||||
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
|
||||
[:div.actions
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:on-click #(reset! confirm* false)
|
||||
:value (tr "labels.cancel")}]
|
||||
[:input.btn-danger
|
||||
{:type "button"
|
||||
:on-click delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]]]
|
||||
|
||||
(some? current-link)
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:on-click #(reset! confirm* false)
|
||||
:value (tr "labels.cancel")}]
|
||||
[:input.btn-danger
|
||||
:class "primary"
|
||||
:on-click try-delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]
|
||||
|
||||
:else
|
||||
[:input.btn-primary
|
||||
{:type "button"
|
||||
:on-click delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]]]
|
||||
|
||||
(some? current-link)
|
||||
[:input.btn-secondary
|
||||
{:type "button"
|
||||
:class "primary"
|
||||
:on-click try-delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]
|
||||
|
||||
:else
|
||||
[:input.btn-primary
|
||||
{:type "button"
|
||||
:class "primary"
|
||||
:on-click create-link
|
||||
:value (tr "common.share-link.get-link")}])]]]
|
||||
[:div.modal-content.ops-section
|
||||
[:div.manage-permissions
|
||||
{:on-click toggle-perms-visibility}
|
||||
[:span.icon i/picker-hsv]
|
||||
[:div.title (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.view-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/play]
|
||||
(tr "common.share-link.permissions-pages")]
|
||||
[:div.items
|
||||
(if (= 1 (count pages))
|
||||
[:div.input-checkbox.check-primary
|
||||
[: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}]
|
||||
[:label {:for (str "page-" current-page-id)} (:name current-page)]
|
||||
[:span (str " " (tr "common.share-link.current-tag"))]]
|
||||
|
||||
[:*
|
||||
[:div.row
|
||||
:class "primary"
|
||||
:on-click create-link
|
||||
:value (tr "common.share-link.get-link")}])]]]
|
||||
[:div.modal-content.ops-section
|
||||
[:div.manage-permissions
|
||||
{:on-click toggle-perms-visibility}
|
||||
[:span.icon i/picker-hsv]
|
||||
[:div.title (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.view-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/play]
|
||||
(tr "common.share-link.permissions-pages")]
|
||||
[:div.items
|
||||
(if (= 1 (count pages))
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id "view-all"
|
||||
:checked all-selected?
|
||||
:name "pages-mode"
|
||||
:on-change on-toggle-all}]
|
||||
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
|
||||
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
||||
:id (dm/str "page-" current-page-id)
|
||||
:data-page-id (dm/str current-page-id)
|
||||
:on-change on-mark-checked-page
|
||||
:checked true}]
|
||||
[:label {:for (str "page-" current-page-id)} (:name current-page)]
|
||||
[:span (str " " (tr "common.share-link.current-tag"))]]
|
||||
|
||||
[:ul.pages-selection
|
||||
(for [{:keys [id name]} pages]
|
||||
[:li.input-checkbox.check-primary {:key (dm/str id)}
|
||||
[:*
|
||||
[:div.row
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (dm/str "page-" id)
|
||||
:data-page-id (dm/str id)
|
||||
:on-change on-mark-checked-page
|
||||
:checked (contains? selected id)}]
|
||||
(if (= current-page-id id)
|
||||
[:*
|
||||
[:label {:for (dm/str "page-" id)} name]
|
||||
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
|
||||
[:label {:for (dm/str "page-" id)} name])])]])]]])
|
||||
[:div.access-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/chat]
|
||||
(tr "common.share-link.permissions-can-comment")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change (partial on-who-change :comment)
|
||||
:value (:who-comment options)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
|
||||
[:div.inspect-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/code]
|
||||
(tr "common.share-link.permissions-can-inspect")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change (partial on-who-change :inspect)
|
||||
:value (:who-inspect options)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))
|
||||
:id "view-all"
|
||||
:checked all-selected?
|
||||
:name "pages-mode"
|
||||
:on-change on-toggle-all}]
|
||||
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
|
||||
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
||||
|
||||
[:ul.pages-selection
|
||||
(for [{:keys [id name]} pages]
|
||||
[:li.input-checkbox.check-primary {:key (dm/str id)}
|
||||
[:input {:type "checkbox"
|
||||
:id (dm/str "page-" id)
|
||||
:data-page-id (dm/str id)
|
||||
:on-change on-mark-checked-page
|
||||
:checked (contains? selected id)}]
|
||||
(if (= current-page-id id)
|
||||
[:*
|
||||
[:label {:for (dm/str "page-" id)} name]
|
||||
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
|
||||
[:label {:for (dm/str "page-" id)} name])])]])]]])
|
||||
[:div.access-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/chat]
|
||||
(tr "common.share-link.permissions-can-comment")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change on-comment-change
|
||||
:value (:who-comment options)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
|
||||
[:div.inspect-mode
|
||||
[:div.subtitle
|
||||
[:span.icon i/code]
|
||||
(tr "common.share-link.permissions-can-inspect")]
|
||||
[:div.items
|
||||
[:select.input-select {:on-change on-inspect-change
|
||||
:value (:who-inspect options)}
|
||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]])))
|
||||
|
||||
|
||||
|
||||
|
|
176
frontend/src/app/main/ui/viewer/share_link.scss
Normal file
176
frontend/src/app/main/ui/viewer/share_link.scss
Normal file
|
@ -0,0 +1,176 @@
|
|||
// 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
|
||||
|
||||
@import "refactor/common-refactor.scss";
|
||||
|
||||
.share-modal {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: $s-52;
|
||||
right: $s-12;
|
||||
left: calc(100vw - $s-512);
|
||||
z-index: $z-index-modal;
|
||||
}
|
||||
.share-link-dialog {
|
||||
@extend .modal-container-base;
|
||||
min-height: unset;
|
||||
}
|
||||
|
||||
.share-link-header {
|
||||
margin-bottom: $s-24;
|
||||
}
|
||||
|
||||
.share-link-title {
|
||||
@include tabTitleTipography;
|
||||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
.modal-close-button {
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@include titleTipography;
|
||||
@include flexColumn;
|
||||
gap: $s-24;
|
||||
}
|
||||
|
||||
.share-link-section {
|
||||
@include flexColumn;
|
||||
gap: $s-8;
|
||||
}
|
||||
|
||||
.hint-wrapper {
|
||||
@include flexRow;
|
||||
}
|
||||
.hint {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.custon-input-wrapper {
|
||||
@include flexRow;
|
||||
border-radius: $br-8;
|
||||
height: $s-32;
|
||||
width: 100%;
|
||||
background-color: var(--input-background-color);
|
||||
}
|
||||
|
||||
.input-text {
|
||||
@extend .input-element;
|
||||
color: var(--input-foreground-color-active);
|
||||
padding-left: $s-8;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: $s-1 solid var(--input-border-color-active);
|
||||
}
|
||||
}
|
||||
.copy-button {
|
||||
@extend .button-secondary;
|
||||
@include flexRow;
|
||||
gap: $s-8;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
@include titleTipography;
|
||||
margin-bottom: $s-24;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include flexRow;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.button-active {
|
||||
@extend .modal-accept-btn;
|
||||
}
|
||||
.button-cancel {
|
||||
@extend .modal-cancel-btn;
|
||||
}
|
||||
.button-danger {
|
||||
@extend .modal-danger-btn;
|
||||
}
|
||||
|
||||
.permissions-section {
|
||||
@include flexColumn;
|
||||
gap: $s-8;
|
||||
}
|
||||
|
||||
.manage-permissions {
|
||||
@include buttonStyle;
|
||||
@include tabTitleTipography;
|
||||
color: var(--menu-foreground-color-rest);
|
||||
height: $s-32;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@include flexCenter;
|
||||
margin-right: $s-6;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
&.rotated {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.view-mode,
|
||||
.access-mode,
|
||||
.inspect-mode {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.subtitle {
|
||||
color: var(--modal-text-foreground-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: $s-136;
|
||||
height: $s-32;
|
||||
}
|
||||
|
||||
.items {
|
||||
flex-grow: 1;
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
.select-all-row {
|
||||
@include flexRow;
|
||||
justify-content: space-between;
|
||||
height: $s-32;
|
||||
border-bottom: $s-1 solid var(--input-border-color-disabled);
|
||||
}
|
||||
.select-all-label {
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
.pages-selection {
|
||||
margin: 0;
|
||||
li {
|
||||
border-bottom: $s-1 solid var(--input-border-color-disabled);
|
||||
}
|
||||
li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.count-pages,
|
||||
.current-tag {
|
||||
@include titleTipography;
|
||||
color: var(--input-foreground-color);
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
@extend .input-checkbox;
|
||||
height: $s-32;
|
||||
padding: 0;
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.viewer.thumbnails
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
|
@ -13,6 +14,7 @@
|
|||
[app.main.data.viewer :as dv]
|
||||
[app.main.render :as render]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
@ -22,7 +24,8 @@
|
|||
|
||||
(mf/defc thumbnails-content
|
||||
[{:keys [children expanded? total] :as props}]
|
||||
(let [container (mf/use-ref)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
container (mf/use-ref)
|
||||
width (mf/use-var (.. js/document -documentElement -clientWidth))
|
||||
element-width (mf/use-var 152)
|
||||
|
||||
|
@ -56,45 +59,96 @@
|
|||
(reset! width (obj/get dom "clientWidth"))))]
|
||||
|
||||
(mf/use-effect on-mount)
|
||||
(if expanded?
|
||||
[:div.thumbnails-content
|
||||
[:div.thumbnails-list-expanded children]]
|
||||
[:div.thumbnails-content
|
||||
[:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide]
|
||||
[:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide]
|
||||
[:div.thumbnails-list {:ref container :on-wheel on-scroll}
|
||||
[:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}}
|
||||
children]]])))
|
||||
(if new-css-system
|
||||
(if expanded?
|
||||
[:div {:class (stl/css :thumbnails-content)}
|
||||
[:div {:class (stl/css :thumbnails-list-expanded)} children]]
|
||||
|
||||
[:div {:class (stl/css :thumbnails-content)}
|
||||
[:button {:class (stl/css :left-scroll-handler)
|
||||
:on-click on-left-arrow-click} i/arrow-refactor]
|
||||
[:button {:class (stl/css :right-scroll-handler)
|
||||
:on-click on-right-arrow-click} i/arrow-refactor]
|
||||
|
||||
[:div {:class (stl/css :thumbnails-list)
|
||||
:ref container
|
||||
:on-wheel on-scroll}
|
||||
[:div {:class (stl/css :thumbnails-list-inside)
|
||||
:style {:right (str (* @offset 152) "px")}}
|
||||
children]]])
|
||||
|
||||
|
||||
|
||||
(if expanded?
|
||||
[:div.thumbnails-content
|
||||
[:div.thumbnails-list-expanded children]]
|
||||
|
||||
[:div.thumbnails-content
|
||||
[:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide]
|
||||
[:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide]
|
||||
[:div.thumbnails-list {:ref container :on-wheel on-scroll}
|
||||
[:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}}
|
||||
children]]]))))
|
||||
|
||||
(mf/defc thumbnails-summary
|
||||
[{:keys [on-toggle-expand on-close total] :as props}]
|
||||
[:div.thumbnails-summary
|
||||
[:span.counter (tr "labels.num-of-frames" (i18n/c total))]
|
||||
[:span.buttons
|
||||
[:span.btn-expand {:on-click on-toggle-expand} i/arrow-down]
|
||||
[:span.btn-close {:on-click on-close} i/close]]])
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||
(if new-css-system
|
||||
[:div {:class (stl/css :thumbnails-summary)}
|
||||
[:span {:class (stl/css :counter)}
|
||||
(tr "labels.num-of-frames" (i18n/c total))]
|
||||
[:span {:class (stl/css :actions)}
|
||||
[:button {:class (stl/css :expand-btn)
|
||||
:on-click on-toggle-expand} i/arrow-refactor]
|
||||
[:button {:class (stl/css :close-btn)
|
||||
:on-click on-close} i/close-refactor]]]
|
||||
|
||||
|
||||
[:div.thumbnails-summary
|
||||
[:span.counter (tr "labels.num-of-frames" (i18n/c total))]
|
||||
[:span.buttons
|
||||
[:span.btn-expand {:on-click on-toggle-expand} i/arrow-down]
|
||||
[:span.btn-close {:on-click on-close} i/close]]])))
|
||||
|
||||
(mf/defc thumbnail-item
|
||||
{::mf/wrap [mf/memo
|
||||
#(mf/deferred % ts/idle-then-raf)]}
|
||||
[{:keys [selected? frame on-click index objects page-id thumbnail-data]}]
|
||||
|
||||
(let [children-ids (cfh/get-children-ids objects (:id frame))
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
children-ids (cfh/get-children-ids objects (:id frame))
|
||||
children-bounds (gsh/shapes->rect (concat [frame] (->> children-ids (keep (d/getf objects)))))]
|
||||
[:div.thumbnail-item {:on-click #(on-click % index)}
|
||||
[:div.thumbnail-preview
|
||||
{:class (dom/classnames :selected selected?)}
|
||||
[:& render/frame-svg {:frame (-> frame
|
||||
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
||||
(assoc :children-bounds children-bounds))
|
||||
:objects objects
|
||||
:use-thumbnails true}]]
|
||||
[:div.thumbnail-info
|
||||
[:span.name {:title (:name frame)} (:name frame)]]]))
|
||||
|
||||
(if new-css-system
|
||||
[:button {:class (stl/css :thumbnail-item)
|
||||
:on-click #(on-click % index)}
|
||||
[:div {:class (stl/css-case :thumbnail-preview true
|
||||
:selected selected?)}
|
||||
[:& render/frame-svg {:frame (-> frame
|
||||
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
||||
(assoc :children-bounds children-bounds))
|
||||
:objects objects
|
||||
:use-thumbnails true}]]
|
||||
[:div {:class (stl/css :thumbnail-info)
|
||||
:title (:name frame)}
|
||||
(:name frame)]]
|
||||
|
||||
|
||||
[:div.thumbnail-item {:on-click #(on-click % index)}
|
||||
[:div.thumbnail-preview
|
||||
{:class (dom/classnames :selected selected?)}
|
||||
[:& render/frame-svg {:frame (-> frame
|
||||
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
||||
(assoc :children-bounds children-bounds))
|
||||
:objects objects
|
||||
:use-thumbnails true}]]
|
||||
[:div.thumbnail-info
|
||||
[:span.name {:title (:name frame)} (:name frame)]]])))
|
||||
|
||||
(mf/defc thumbnails-panel
|
||||
[{:keys [frames page index show? thumbnail-data] :as props}]
|
||||
(let [expanded? (mf/use-state false)
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
expanded? (mf/use-state false)
|
||||
container (mf/use-ref)
|
||||
|
||||
objects (:objects page)
|
||||
|
@ -109,24 +163,48 @@
|
|||
(st/emit! (dv/go-to-frame-by-index index))
|
||||
(when @expanded?
|
||||
(on-close))))]
|
||||
(if new-css-system
|
||||
[:section
|
||||
{:class (stl/css-case :viewer-thumbnails true
|
||||
:expanded @expanded?)
|
||||
;; This is better as an inline-style so it won't make a reflow of every frame inside
|
||||
:style {:display (when (not show?) "none")}
|
||||
:ref container}
|
||||
|
||||
[:section.viewer-thumbnails
|
||||
{;; This is better as an inline-style so it won't make a reflow of every frame inside
|
||||
:style {:display (when (not show?) "none")}
|
||||
:class (dom/classnames :expanded @expanded?)
|
||||
:ref container}
|
||||
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
|
||||
:on-close on-close
|
||||
:total (count frames)}]
|
||||
[:& thumbnails-content {:expanded? @expanded?
|
||||
:total (count frames)}
|
||||
(for [[i frame] (d/enumerate frames)]
|
||||
[:& thumbnail-item {:index i
|
||||
:key (dm/str (:id frame) "-" i)
|
||||
:frame frame
|
||||
:page-id (:id page)
|
||||
:objects objects
|
||||
:on-click on-item-click
|
||||
:selected? (= i index)
|
||||
:thumbnail-data thumbnail-data}])]]
|
||||
|
||||
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
|
||||
:on-close on-close
|
||||
:total (count frames)}]
|
||||
[:& thumbnails-content {:expanded? @expanded?
|
||||
:total (count frames)}
|
||||
(for [[i frame] (d/enumerate frames)]
|
||||
[:& thumbnail-item {:index i
|
||||
:key (dm/str (:id frame) "-" i)
|
||||
:frame frame
|
||||
:page-id (:id page)
|
||||
:objects objects
|
||||
:on-click on-item-click
|
||||
:selected? (= i index)
|
||||
:thumbnail-data thumbnail-data}])]]))
|
||||
|
||||
|
||||
[:section.viewer-thumbnails
|
||||
{;; This is better as an inline-style so it won't make a reflow of every frame inside
|
||||
:style {:display (when (not show?) "none")}
|
||||
:class (dom/classnames :expanded @expanded?)
|
||||
:ref container}
|
||||
|
||||
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
|
||||
:on-close on-close
|
||||
:total (count frames)}]
|
||||
[:& thumbnails-content {:expanded? @expanded?
|
||||
:total (count frames)}
|
||||
(for [[i frame] (d/enumerate frames)]
|
||||
[:& thumbnail-item {:index i
|
||||
:key (dm/str (:id frame) "-" i)
|
||||
:frame frame
|
||||
:page-id (:id page)
|
||||
:objects objects
|
||||
:on-click on-item-click
|
||||
:selected? (= i index)
|
||||
:thumbnail-data thumbnail-data}])]])))
|
||||
|
|
152
frontend/src/app/main/ui/viewer/thumbnails.scss
Normal file
152
frontend/src/app/main/ui/viewer/thumbnails.scss
Normal file
|
@ -0,0 +1,152 @@
|
|||
// 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
|
||||
|
||||
@use "common/refactor/common-refactor.scss" as *;
|
||||
|
||||
.viewer-thumbnails {
|
||||
background-color: var(--viewer-background-color);
|
||||
grid-row: 1 / span 1;
|
||||
grid-column: 1 / span 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: $z-index-10;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
grid-row: 1 / span 2;
|
||||
|
||||
.expand-btn svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnails-summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: $s-32;
|
||||
margin: $s-24 $s-24 0 $s-24;
|
||||
}
|
||||
|
||||
.counter {
|
||||
@include titleTipography;
|
||||
color: var(--viewer-thumbnails-control-foreground-color);
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include flexRow;
|
||||
width: $s-60;
|
||||
}
|
||||
|
||||
.expand-btn,
|
||||
.close-btn {
|
||||
@extend .button-tertiary;
|
||||
height: $s-32;
|
||||
width: $s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
}
|
||||
}
|
||||
|
||||
.expand-btn svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.thumbnails-content {
|
||||
display: grid;
|
||||
grid-template-columns: $s-40 auto $s-40;
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
.thumbnails-list-expanded {
|
||||
grid-column: 1 / span 3;
|
||||
grid-row: 1 / span 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right-scroll-handler,
|
||||
.left-scroll-handler {
|
||||
@extend .button-tertiary;
|
||||
@include flexCenter;
|
||||
grid-column: 3 / span 1;
|
||||
grid-row: 1 / span 1;
|
||||
width: $s-32;
|
||||
height: $s-60;
|
||||
margin: auto 0;
|
||||
z-index: $z-index-10;
|
||||
opacity: 0;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.left-scroll-handler {
|
||||
grid-column: 1 / span 1;
|
||||
grid-row: 1 / span 1;
|
||||
svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnails-list {
|
||||
grid-column: 1 / span 3;
|
||||
grid-row: 1 / span 1;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.thumbnails-list-inside {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.thumbnail-item {
|
||||
@include buttonStyle;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: $s-16;
|
||||
}
|
||||
|
||||
.thumbnail-preview {
|
||||
@include flexCenter;
|
||||
width: $s-132;
|
||||
min-height: $s-132;
|
||||
height: $s-132;
|
||||
padding: $s-4;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--viewer-thumbnail-background-color-selected);
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: $s-1 solid var(--viewer-thumbnail-border-color);
|
||||
border-radius: $br-8;
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail-info {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
text-align: center;
|
||||
color: var(--viewer-thumbnails-control-foreground-color);
|
||||
padding: $s-8 0;
|
||||
width: 100%;
|
||||
max-width: $s-132;
|
||||
}
|
|
@ -86,12 +86,10 @@
|
|||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
||||
:on-click update-show}
|
||||
[:span.icon i/tick]
|
||||
[:span.label (tr "labels.hide-resolved-comments")]]])
|
||||
|
||||
))
|
||||
[:span.label (tr "labels.hide-resolved-comments")]]])))
|
||||
|
||||
(mf/defc comments-sidebar
|
||||
[{:keys [users threads page-id]}]
|
||||
[{:keys [users threads page-id from-viewer]}]
|
||||
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
threads-map (mf/deref refs/threads-ref)
|
||||
profile (mf/deref refs/profile)
|
||||
|
@ -111,8 +109,11 @@
|
|||
|
||||
close-section
|
||||
(mf/use-fn
|
||||
(mf/deps)
|
||||
#(st/emit! :interrupt (dw/deselect-all true)))
|
||||
(mf/deps from-viewer)
|
||||
(fn []
|
||||
(if from-viewer
|
||||
(st/emit! (dcm/update-options {:show-sidebar? false}))
|
||||
(st/emit! :interrupt (dw/deselect-all true)))))
|
||||
|
||||
tgroups (->> threads
|
||||
(dcm/group-threads-by-page))
|
||||
|
@ -121,7 +122,6 @@
|
|||
|
||||
toggle-mode-selector
|
||||
(mf/use-fn
|
||||
(mf/deps)
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! state* not)))
|
||||
|
@ -147,18 +147,17 @@
|
|||
:on-click close-section}
|
||||
i/close-refactor]]
|
||||
|
||||
(when (seq tgroups)
|
||||
[:button {:class (stl/css :mode-dropdown-wrapper)
|
||||
:on-click toggle-mode-selector}
|
||||
[:button {:class (stl/css :mode-dropdown-wrapper)
|
||||
:on-click toggle-mode-selector}
|
||||
|
||||
[:span {:class (stl/css :mode-label)} (case (:mode local)
|
||||
(nil :all) (tr "labels.show-all-comments")
|
||||
:yours (tr "labels.show-your-comments"))]
|
||||
[:div {:class (stl/css :icon)} i/arrow-refactor]]
|
||||
[:span {:class (stl/css :mode-label)} (case (:mode local)
|
||||
(nil :all) (tr "labels.show-all-comments")
|
||||
:yours (tr "labels.show-your-comments"))]
|
||||
[:div {:class (stl/css :icon)} i/arrow-refactor]]
|
||||
|
||||
[:& dropdown {:show options?
|
||||
:on-close #(reset! state* false)}
|
||||
[:& sidebar-options {:local local}]])
|
||||
[:& dropdown {:show options?
|
||||
:on-close #(reset! state* false)}
|
||||
[:& sidebar-options {:local local}]]
|
||||
|
||||
[:div {:class (stl/css :comments-section-content)}
|
||||
|
||||
|
|
|
@ -126,14 +126,14 @@
|
|||
(tr "workspace.header.zoom-fit-all")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :fit-all))]
|
||||
[:span {:class (dom/classnames (stl/css :shortcut-key) true)
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-fit-" sc)} sc])]]
|
||||
[:li {:class (stl/css :zoom-option)
|
||||
:on-click on-zoom-selected}
|
||||
(tr "workspace.header.zoom-selected")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :zoom-selected))]
|
||||
[:span {:class (dom/classnames (stl/css :shortcut-key) true)
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-selected-" sc)} sc])]]]]]))
|
||||
|
||||
;; --- Header Component
|
||||
|
|
|
@ -198,6 +198,7 @@
|
|||
:checked (not hide-fill-on-export?)
|
||||
:on-change on-change-show-fill-on-export}]]])])]
|
||||
|
||||
;; OLD
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
[:span label]
|
||||
|
|
|
@ -1637,6 +1637,9 @@ msgstr "Settings"
|
|||
msgid "labels.share-prototype"
|
||||
msgstr "Share prototype"
|
||||
|
||||
msgid "labels.share"
|
||||
msgstr "Share"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs
|
||||
msgid "labels.shared-libraries"
|
||||
msgstr "Libraries"
|
||||
|
|
|
@ -1673,6 +1673,9 @@ msgstr "Configuración"
|
|||
msgid "labels.share-prototype"
|
||||
msgstr "Compartir prototipo"
|
||||
|
||||
msgid "labels.share"
|
||||
msgstr "Compartir"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs
|
||||
msgid "labels.shared-libraries"
|
||||
msgstr "Bibliotecas"
|
||||
|
|
Loading…
Add table
Reference in a new issue