mirror of
https://github.com/penpot/penpot.git
synced 2025-06-16 00:01:39 +02: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);
|
stroke: var(--button-tertiary-foreground-color-active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:global(.disabled),
|
&:global(.disabled),
|
||||||
&[disabled],
|
&[disabled],
|
||||||
&:disabled {
|
&:disabled {
|
||||||
|
|
|
@ -297,4 +297,13 @@
|
||||||
--tag-background-color: var(--color-accent-primary);
|
--tag-background-color: var(--color-accent-primary);
|
||||||
|
|
||||||
--link-foreground-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"))))))
|
(assoc :message (tr "errors.email-invalid"))))))
|
||||||
|
|
||||||
(mf/defc login-form
|
(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)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
initial (mf/use-memo (mf/deps params) (constantly params))
|
initial (mf/use-memo (mf/deps params) (constantly params))
|
||||||
|
|
||||||
error (mf/use-state false)
|
error (mf/use-state false)
|
||||||
form (fm/use-form :spec ::login-form
|
form (fm/use-form :spec ::login-form
|
||||||
:validators [handle-error-messages]
|
:validators [handle-error-messages]
|
||||||
|
@ -152,7 +151,12 @@
|
||||||
(let [params (:clean-data @form)]
|
(let [params (:clean-data @form)]
|
||||||
(login-with-ldap event (with-meta params
|
(login-with-ldap event (with-meta params
|
||||||
{:on-error on-error
|
{: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
|
(if new-css-system
|
||||||
[:*
|
[:*
|
||||||
(when-let [message @error]
|
(when-let [message @error]
|
||||||
|
@ -178,10 +182,11 @@
|
||||||
:label (tr "auth.password")
|
:label (tr "auth.password")
|
||||||
:class (stl/css :form-field)}]]
|
:class (stl/css :form-field)}]]
|
||||||
|
|
||||||
(when (or (contains? cf/flags :login)
|
(when (and (not= origin :viewer)
|
||||||
(contains? cf/flags :login-with-password))
|
(or (contains? cf/flags :login)
|
||||||
|
(contains? cf/flags :login-with-password)))
|
||||||
[:div {:class (stl/css :fields-row :forgot-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"}
|
:data-test "forgot-password"}
|
||||||
(tr "auth.forgot-password")]])
|
(tr "auth.forgot-password")]])
|
||||||
|
|
||||||
|
@ -198,6 +203,7 @@
|
||||||
{:label (tr "auth.login-with-ldap-submit")
|
{:label (tr "auth.login-with-ldap-submit")
|
||||||
:on-click on-submit-ldap}])]]]
|
:on-click on-submit-ldap}])]]]
|
||||||
|
|
||||||
|
|
||||||
;; OLD
|
;; OLD
|
||||||
[:*
|
[:*
|
||||||
(when-let [message @error]
|
(when-let [message @error]
|
||||||
|
@ -271,7 +277,7 @@
|
||||||
:icon i/brand-openid
|
:icon i/brand-openid
|
||||||
:label (tr "auth.login-with-oidc-submit")
|
:label (tr "auth.login-with-oidc-submit")
|
||||||
:class (stl/css :login-btn :btn-oidc-auth)}])]
|
:class (stl/css :login-btn :btn-oidc-auth)}])]
|
||||||
|
|
||||||
[:div.auth-buttons
|
[:div.auth-buttons
|
||||||
(when (contains? cf/flags :login-with-google)
|
(when (contains? cf/flags :login-with-google)
|
||||||
[:& bl/button-link {:on-click login-with-google
|
[:& bl/button-link {:on-click login-with-google
|
||||||
|
@ -299,28 +305,36 @@
|
||||||
|
|
||||||
(mf/defc login-button-oidc
|
(mf/defc login-button-oidc
|
||||||
[{:keys [params] :as props}]
|
[{: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
|
(if new-css-system
|
||||||
(when (contains? cf/flags :login-with-oidc)
|
(when (contains? cf/flags :login-with-oidc)
|
||||||
[:div {:class (stl/css :link-entry :link-oidc)}
|
[:div {:class (stl/css :link-entry :link-oidc)}
|
||||||
[:a {:tab-index "0"
|
[:a {:tab-index "0"
|
||||||
:on-key-down (fn [event]
|
:on-key-down handle-key-down
|
||||||
(when (k/enter? event)
|
:on-click login-oidc}
|
||||||
(login-with-oidc event :oidc params)))
|
|
||||||
:on-click #(login-with-oidc % :oidc params)}
|
|
||||||
(tr "auth.login-with-oidc-submit")]])
|
(tr "auth.login-with-oidc-submit")]])
|
||||||
|
|
||||||
|
;; OLD
|
||||||
(when (contains? cf/flags :login-with-oidc)
|
(when (contains? cf/flags :login-with-oidc)
|
||||||
[:div.link-entry.link-oidc
|
[:div.link-entry.link-oidc
|
||||||
[:a {:tab-index "0"
|
[:a {:tab-index "0"
|
||||||
:on-key-down (fn [event]
|
:on-key-down handle-key-down
|
||||||
(when (k/enter? event)
|
:on-click login-oidc}
|
||||||
(login-with-oidc event :oidc params)))
|
|
||||||
:on-click #(login-with-oidc % :oidc params)}
|
|
||||||
(tr "auth.login-with-oidc-submit")]]))))
|
(tr "auth.login-with-oidc-submit")]]))))
|
||||||
|
|
||||||
(mf/defc login-methods
|
(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)]
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
(if new-css-system
|
(if new-css-system
|
||||||
[:*
|
[:*
|
||||||
|
@ -336,7 +350,7 @@
|
||||||
(when (or (contains? cf/flags :login)
|
(when (or (contains? cf/flags :login)
|
||||||
(contains? cf/flags :login-with-password)
|
(contains? cf/flags :login-with-password)
|
||||||
(contains? cf/flags :login-with-ldap))
|
(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
|
;; OLD
|
||||||
[:*
|
[:*
|
||||||
|
@ -364,7 +378,19 @@
|
||||||
|
|
||||||
(mf/defc login-page
|
(mf/defc login-page
|
||||||
[{:keys [params] :as props}]
|
[{: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
|
(if new-css-system
|
||||||
[:div {:class (stl/css :auth-form)}
|
[:div {:class (stl/css :auth-form)}
|
||||||
[:h1 {:class (stl/css :auth-title)
|
[:h1 {:class (stl/css :auth-title)
|
||||||
|
@ -375,17 +401,24 @@
|
||||||
[:& login-methods {:params params}]
|
[:& login-methods {:params params}]
|
||||||
|
|
||||||
[:div {:class (stl/css :links)}
|
[: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)
|
(when (contains? cf/flags :registration)
|
||||||
[:div {:class (stl/css :link-entry :register)}
|
[:div {:class (stl/css :link-entry :register)}
|
||||||
[:span (tr "auth.register") " "]
|
[:span (tr "auth.register") " "]
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
|
[:& lk/link {:action go-register
|
||||||
:data-test "register-submit"}
|
:data-test "register-submit"}
|
||||||
(tr "auth.register-submit")]])]
|
(tr "auth.register-submit")]])]
|
||||||
|
|
||||||
(when (contains? cf/flags :demo-users)
|
(when (contains? cf/flags :demo-users)
|
||||||
[:div {:class (stl/css :link-entry :demo-account)}
|
[:div {:class (stl/css :link-entry :demo-account)}
|
||||||
[:span (tr "auth.create-demo-profile") " "]
|
[: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"}
|
:data-test "demo-account-link"}
|
||||||
(tr "auth.create-demo-account")]])]
|
(tr "auth.create-demo-account")]])]
|
||||||
|
|
||||||
|
@ -400,14 +433,14 @@
|
||||||
(when (or (contains? cf/flags :login)
|
(when (or (contains? cf/flags :login)
|
||||||
(contains? cf/flags :login-with-password))
|
(contains? cf/flags :login-with-password))
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
|
[:& lk/link {:action on-pass-recovery
|
||||||
:data-test "forgot-password"}
|
:data-test "forgot-password"}
|
||||||
(tr "auth.forgot-password")]])
|
(tr "auth.forgot-password")]])
|
||||||
|
|
||||||
(when (contains? cf/flags :registration)
|
(when (contains? cf/flags :registration)
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:span (tr "auth.register") " "]
|
[:span (tr "auth.register") " "]
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
|
[:& lk/link {:action go-register
|
||||||
:data-test "register-submit"}
|
:data-test "register-submit"}
|
||||||
(tr "auth.register-submit")]])]
|
(tr "auth.register-submit")]])]
|
||||||
|
|
||||||
|
@ -415,7 +448,7 @@
|
||||||
[:div.links.demo
|
[:div.links.demo
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:span (tr "auth.create-demo-profile") " "]
|
[: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"}
|
:data-test "demo-account-link"}
|
||||||
(tr "auth.create-demo-account")]]])]])))
|
(tr "auth.create-demo-account")]]])]])))
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,12 @@
|
||||||
:cmd cmd})))
|
:cmd cmd})))
|
||||||
|
|
||||||
on-toggle-enabled
|
on-toggle-enabled
|
||||||
(fn [index]
|
(mf/use-fn
|
||||||
(swap! exports update-in [index :enabled] not))
|
(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
|
change-all
|
||||||
(fn [_]
|
(fn [_]
|
||||||
|
@ -65,9 +69,8 @@
|
||||||
|
|
||||||
(if new-css-system
|
(if new-css-system
|
||||||
[:div {:class (stl/css :modal-overlay)}
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-container.export-multiple-dialog
|
[:div {:class (stl/css-case :modal-container true
|
||||||
{:class (stl/css-case :modal-container true
|
:empty (empty? all-exports))}
|
||||||
:empty (empty? all-exports))}
|
|
||||||
|
|
||||||
[:div {:class (stl/css :modal-header)}
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h2 {:class (stl/css :modal-title)} title]
|
[:h2 {:class (stl/css :modal-title)} title]
|
||||||
|
@ -84,55 +87,58 @@
|
||||||
:on-click change-all}
|
:on-click change-all}
|
||||||
[:span {:class (stl/css :checkbox-wrapper)}
|
[:span {:class (stl/css :checkbox-wrapper)}
|
||||||
(cond
|
(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]
|
: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)}]
|
: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])]]
|
:global/intermediate true)} i/remove-refactor])]]
|
||||||
[:div {:class (stl/css :selection-title)} (tr "dashboard.export-multiple.selected"
|
[:div {:class (stl/css :selection-title)}
|
||||||
(c (count enabled-exports))
|
(tr "dashboard.export-multiple.selected"
|
||||||
(c (count all-exports)))]]
|
(c (count enabled-exports))
|
||||||
|
(c (count all-exports)))]]
|
||||||
[:div {:class (stl/css :selection-wrapper)}
|
[:div {:class (stl/css :selection-wrapper)}
|
||||||
[:div {:class (stl/css-case :selection-list true
|
[:div {:class (stl/css-case :selection-list true
|
||||||
:selection-shadow (> (count all-exports) 8))}
|
:selection-shadow (> (count all-exports) 8))}
|
||||||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)]
|
(let [{:keys [x y width height]} (:selrect shape)]
|
||||||
[:div {:class (stl/css :selection-row)}
|
[:div {:class (stl/css :selection-row)
|
||||||
[:button {:class (stl/css :selection-btn)
|
:key (:id shape)}
|
||||||
:on-click #(on-toggle-enabled index)}
|
[:button {:class (stl/css :selection-btn)
|
||||||
[:span {:class (stl/css :checkbox-wrapper)}
|
:data-value index
|
||||||
(if (:enabled export)
|
:on-click on-toggle-enabled}
|
||||||
[:span {:class (stl/css-case :checkbox-icon2 true
|
[:span {:class (stl/css :checkbox-wrapper)}
|
||||||
:global/checked true)} i/tick-refactor]
|
(if (:enabled export)
|
||||||
[:span {:class (stl/css-case :checkbox-icon2 true
|
[:span {:class (stl/css-case :checkobox-tick true
|
||||||
:global/uncheked true)}])]
|
:global/checked true)} i/tick-refactor]
|
||||||
|
[:span {:class (stl/css-case :checkobox-tick true
|
||||||
|
:global/uncheked true)}])]
|
||||||
|
|
||||||
[:div {:class (stl/css :image-wrapper)}
|
[:div {:class (stl/css :image-wrapper)}
|
||||||
(if (some? (:thumbnail shape))
|
(if (some? (:thumbnail shape))
|
||||||
[:img {:src (:thumbnail shape)}]
|
[:img {:src (:thumbnail shape)}]
|
||||||
[:svg {:view-box (dm/str x " " y " " width " " height)
|
[:svg {:view-box (dm/str x " " y " " width " " height)
|
||||||
:width 24
|
:width 24
|
||||||
:height 20
|
:height 20
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
:xmlns "http://www.w3.org/2000/svg"
|
:xmlns "http://www.w3.org/2000/svg"
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
;; Fix Chromium bug about color of html texts
|
;; Fix Chromium bug about color of html texts
|
||||||
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
||||||
:style {:-webkit-print-color-adjust :exact}
|
:style {:-webkit-print-color-adjust :exact}
|
||||||
:fill "none"}
|
:fill "none"}
|
||||||
|
|
||||||
[:& shape-wrapper {:shape shape}]])]
|
[:& shape-wrapper {:shape shape}]])]
|
||||||
|
|
||||||
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
|
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
|
||||||
(when (:scale export)
|
(when (:scale export)
|
||||||
[:div {:class (stl/css :selection-scale)}
|
[:div {:class (stl/css :selection-scale)}
|
||||||
(dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
(dm/str (ust/format-precision (* width (:scale export)) 2) "px"
|
||||||
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
(ust/format-precision (* height (:scale export)) 2) "px")])
|
||||||
|
|
||||||
(when (:type export)
|
(when (:type export)
|
||||||
[:div {:class (stl/css :selection-extension)}
|
[:div {:class (stl/css :selection-extension)}
|
||||||
(-> export :type d/name str/upper)])]]))]]]
|
(-> export :type d/name str/upper)])]]))]]]
|
||||||
|
|
||||||
[:& no-selection])]
|
[:& no-selection])]
|
||||||
|
|
||||||
|
@ -187,7 +193,8 @@
|
||||||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)]
|
(let [{:keys [x y width height]} (:selrect shape)]
|
||||||
[:div.row
|
[: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)
|
(if (:enabled export)
|
||||||
[:span.checked i/checkbox-checked]
|
[:span.checked i/checkbox-checked]
|
||||||
[:span.unchecked i/checkbox-unchecked])]
|
[:span.unchecked i/checkbox-unchecked])]
|
||||||
|
@ -210,7 +217,7 @@
|
||||||
|
|
||||||
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
|
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
|
||||||
(when (:scale export)
|
(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 ")])
|
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
||||||
|
|
||||||
(when (:type export)
|
(when (:type export)
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
height: $s-24;
|
height: $s-24;
|
||||||
width: $s-24;
|
width: $s-24;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
.checkbox-icon2 {
|
.checkobox-tick {
|
||||||
@extend .checkbox-icon;
|
@extend .checkbox-icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -339,6 +339,7 @@
|
||||||
(def easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor))
|
(def easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor))
|
||||||
(def effects-refactor (icon-xref :effects-refactor))
|
(def effects-refactor (icon-xref :effects-refactor))
|
||||||
(def elipse-refactor (icon-xref :elipse-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 fill-content-refactor (icon-xref :fill-content-refactor))
|
||||||
(def filter-refactor (icon-xref :filter-refactor))
|
(def filter-refactor (icon-xref :filter-refactor))
|
||||||
(def fixed-width-refactor (icon-xref :fixed-width-refactor))
|
(def fixed-width-refactor (icon-xref :fixed-width-refactor))
|
||||||
|
@ -414,6 +415,7 @@
|
||||||
(def picker-refactor (icon-xref :picker-refactor))
|
(def picker-refactor (icon-xref :picker-refactor))
|
||||||
(def play-refactor (icon-xref :play-refactor))
|
(def play-refactor (icon-xref :play-refactor))
|
||||||
(def rectangle-refactor (icon-xref :rectangle-refactor))
|
(def rectangle-refactor (icon-xref :rectangle-refactor))
|
||||||
|
(def reload-refactor (icon-xref :reload-refactor))
|
||||||
(def remove-refactor (icon-xref :remove-refactor))
|
(def remove-refactor (icon-xref :remove-refactor))
|
||||||
(def rgba-refactor (icon-xref :rgba-refactor))
|
(def rgba-refactor (icon-xref :rgba-refactor))
|
||||||
(def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor))
|
(def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor))
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.ui.viewer
|
(ns app.main.ui.viewer
|
||||||
(:import goog.events.EventType)
|
(:import goog.events.EventType)
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -91,29 +92,57 @@
|
||||||
:vbox (str "0 0 " width " " height)})))
|
:vbox (str "0 0 " width " " height)})))
|
||||||
|
|
||||||
(mf/defc viewer-pagination
|
(mf/defc viewer-pagination
|
||||||
[{:keys [index num-frames left-bar right-bar] :as props}]
|
[{:keys [index num-frames left-bar right-bar comment-sidebar] :as props}]
|
||||||
[:*
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
(when (pos? index)
|
go-prev-frame (mf/use-fn #(st/emit! dv/select-prev-frame))
|
||||||
[:div.viewer-go-prev {:class (when left-bar "left-bar")}
|
go-next-frame (mf/use-fn #(st/emit! dv/select-next-frame))
|
||||||
[:div.arrow {:on-click #(st/emit! dv/select-prev-frame)} i/go-prev]])
|
go-first-frame (mf/use-fn #(st/emit! dv/select-first-frame))]
|
||||||
(when (< (+ index 1) num-frames)
|
(if new-css-system
|
||||||
[:div.viewer-go-next {:class (when right-bar "right-bar")}
|
[:*
|
||||||
[:div.arrow {:on-click #(st/emit! dv/select-next-frame)} i/go-next]])
|
(when (pos? index)
|
||||||
[:div.viewer-bottom {:class (when left-bar "left-bar")}
|
[:button {:class (stl/css-case :viewer-go-prev true
|
||||||
[:div.reset {:on-click #(st/emit! dv/select-first-frame)} i/reset]
|
:left-bar left-bar)
|
||||||
[:div.counter (str/join " / " [(+ index 1) num-frames])]
|
:on-click go-prev-frame}
|
||||||
[:span]]])
|
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/defc viewer-pagination-and-sidebar
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [section index users frame page]}]
|
[{:keys [section index users frame page]}]
|
||||||
(let [comments-local (mf/deref refs/comments-local)
|
(let [comments-local (mf/deref refs/comments-local)
|
||||||
show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))]
|
show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))]
|
||||||
[:*
|
[:*
|
||||||
[:& viewer-pagination
|
[:& viewer-pagination
|
||||||
{:index index
|
{:index index
|
||||||
:num-frames (count (:frames page))
|
:num-frames (count (:frames page))
|
||||||
:right-bar show-sidebar?}]
|
:comment-sidebar show-sidebar?}]
|
||||||
|
|
||||||
(when show-sidebar?
|
(when show-sidebar?
|
||||||
[:& comments-sidebar
|
[:& comments-sidebar
|
||||||
|
@ -172,72 +201,138 @@
|
||||||
:page page
|
:page page
|
||||||
:interactions-mode interactions-mode}]]]))
|
:interactions-mode interactions-mode}]]]))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc viewer-wrapper
|
(mf/defc viewer-wrapper
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
|
[{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
|
||||||
size frame interactions-mode overlays zoom section index]}]
|
size frame interactions-mode overlays zoom section index]}]
|
||||||
|
|
||||||
[:*
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:& viewer-pagination-and-sidebar
|
(if new-css-system
|
||||||
{:section section
|
[:*
|
||||||
:index index
|
[:& viewer-pagination-and-sidebar
|
||||||
:page page
|
{:section section
|
||||||
:users users
|
:index index
|
||||||
:frame frame
|
:page page
|
||||||
:interactions-mode interactions-mode}]
|
:users users
|
||||||
|
:frame frame
|
||||||
|
:interactions-mode interactions-mode}]
|
||||||
|
|
||||||
[:div.viewer-wrapper
|
[:div {:class (stl/css :viewer-wrapper)
|
||||||
{:style {:width (:width wrapper-size)
|
:style {:width (:width wrapper-size)
|
||||||
:height (:height wrapper-size)}}
|
:height (:height wrapper-size)}}
|
||||||
[:div.viewer-clipper
|
[:div {:class (stl/css :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
|
(when orig-frame
|
||||||
{:frame orig-frame
|
[:div {:class (stl/css :viewport-container)
|
||||||
:base-frame orig-frame
|
:ref orig-viewport-ref
|
||||||
:frame-offset (gpt/point 0 0)
|
:style {:width (:width orig-size)
|
||||||
:size orig-size
|
:height (:height orig-size)
|
||||||
:page page
|
:position "relative"}}
|
||||||
:users users
|
|
||||||
:interactions-mode interactions-mode}]])
|
|
||||||
|
|
||||||
[:div.viewport-container
|
[:& interactions/viewport
|
||||||
{:ref current-viewport-ref
|
{:frame orig-frame
|
||||||
:style {:width (:width size)
|
:base-frame orig-frame
|
||||||
:height (:height size)
|
:frame-offset (gpt/point 0 0)
|
||||||
:position "relative"}}
|
:size orig-size
|
||||||
|
:page page
|
||||||
|
:users users
|
||||||
|
:interactions-mode interactions-mode}]])
|
||||||
|
|
||||||
[:& interactions/viewport
|
[:div {:class (stl/css :viewport-container)
|
||||||
{:frame frame
|
:ref current-viewport-ref
|
||||||
:base-frame frame
|
:style {:width (:width size)
|
||||||
:frame-offset (gpt/point 0 0)
|
:height (:height size)
|
||||||
:size size
|
:position "relative"}}
|
||||||
:page page
|
|
||||||
:interactions-mode interactions-mode}]
|
|
||||||
|
|
||||||
(for [overlay overlays]
|
[:& interactions/viewport
|
||||||
[:& viewer-overlay
|
{:frame frame
|
||||||
{:overlay overlay
|
:base-frame frame
|
||||||
:key (dm/str (:id overlay))
|
:frame-offset (gpt/point 0 0)
|
||||||
:page page
|
:size size
|
||||||
:frame frame
|
:page page
|
||||||
:zoom zoom
|
:interactions-mode interactions-mode}]
|
||||||
:wrapper-size wrapper-size
|
|
||||||
: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)
|
(when (= section :comments)
|
||||||
[:& comments-layer {:file file
|
[:& comments-layer {:file file
|
||||||
:users users
|
:users users
|
||||||
:frame frame
|
:frame frame
|
||||||
:page page
|
:page page
|
||||||
:zoom zoom}])]])
|
: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
|
(mf/defc viewer
|
||||||
[{:keys [params data]}]
|
[{:keys [params data]}]
|
||||||
|
@ -245,6 +340,8 @@
|
||||||
(let [{:keys [page-id share-id section index interactions-mode]} params
|
(let [{:keys [page-id share-id section index interactions-mode]} params
|
||||||
{:keys [file users project permissions]} data
|
{:keys [file users project permissions]} data
|
||||||
|
|
||||||
|
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
|
||||||
allowed (or
|
allowed (or
|
||||||
(= section :interactions)
|
(= section :interactions)
|
||||||
(and (= section :comments)
|
(and (= section :comments)
|
||||||
|
@ -311,7 +408,7 @@
|
||||||
(calculate-wrapper size orig-size zoom))
|
(calculate-wrapper size orig-size zoom))
|
||||||
|
|
||||||
click-on-screen
|
click-on-screen
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [origin (dom/get-target event)
|
(let [origin (dom/get-target event)
|
||||||
over-section? (dom/class? origin "viewer-section")
|
over-section? (dom/class? origin "viewer-section")
|
||||||
|
@ -360,9 +457,13 @@
|
||||||
(if shift?
|
(if shift?
|
||||||
(dom/set-h-scroll-pos! section new-scroll-pos)
|
(dom/set-h-scroll-pos! section new-scroll-pos)
|
||||||
(dom/set-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
|
on-exit-fullscreen
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn []
|
(fn []
|
||||||
(when (not (dom/fullscreen?))
|
(when (not (dom/fullscreen?))
|
||||||
(st/emit! (dv/exit-fullscreen)))))]
|
(st/emit! (dv/exit-fullscreen)))))]
|
||||||
|
@ -441,7 +542,7 @@
|
||||||
nil)
|
nil)
|
||||||
;; Navigate animation needs to be started after navigation
|
;; Navigate animation needs to be started after navigation
|
||||||
;; is complete, and we have the next page index.
|
;; 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
|
(when nav-animation
|
||||||
(let [orig-viewport (mf/ref-val orig-viewport-ref)
|
(let [orig-viewport (mf/ref-val orig-viewport-ref)
|
||||||
current-viewport (mf/ref-val current-viewport-ref)]
|
current-viewport (mf/ref-val current-viewport-ref)]
|
||||||
|
@ -498,76 +599,153 @@
|
||||||
fonts (into #{} (keep :font-id) text-nodes)]
|
fonts (into #{} (keep :font-id) text-nodes)]
|
||||||
(run! fonts/ensure-loaded! fonts))))
|
(run! fonts/ensure-loaded! fonts))))
|
||||||
|
|
||||||
[:div#viewer-layout
|
(if new-css-system
|
||||||
{:class (dom/classnames
|
[:div#viewer-layout
|
||||||
:force-visible (:show-thumbnails local)
|
{:class (stl/css-case
|
||||||
:viewer-layout (not= section :inspect)
|
:force-visible (:show-thumbnails local)
|
||||||
:inspect-layout (= section :inspect)
|
:viewer-layout (not= section :inspect)
|
||||||
:fullscreen fullscreen?)}
|
:inspect-layout (= section :inspect)
|
||||||
|
:fullscreen fullscreen?)}
|
||||||
|
|
||||||
[:div.viewer-content
|
[:div {:class (stl/css :viewer-content)}
|
||||||
[:& header/header {:project project
|
[:& header/header {:project project
|
||||||
:index index
|
:index index
|
||||||
:file file
|
:file file
|
||||||
:page page
|
:page page
|
||||||
:frame frame
|
:frame frame
|
||||||
:permissions permissions
|
:permissions permissions
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:section section
|
:section section
|
||||||
:interactions-mode interactions-mode}]
|
: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")]]
|
|
||||||
|
|
||||||
(nil? frame)
|
[:button {:on-click on-thumbnails-close
|
||||||
[:section.empty-state
|
:class (stl/css-case :thumbnails-close true
|
||||||
(when (some? index)
|
:invisible (not (:show-thumbnails local false)))}]
|
||||||
[:span (tr "viewer.frame-not-found")])]
|
|
||||||
|
|
||||||
(some? frame)
|
[:& thumbnails-panel {:frames frames
|
||||||
(if (= :inspect section)
|
:show? (:show-thumbnails local false)
|
||||||
[:& inspect/viewport
|
:page page
|
||||||
{:frame frame
|
:index index
|
||||||
:page page
|
:thumbnail-data (:thumbnails file)}]
|
||||||
:file file
|
|
||||||
:section section
|
[:section {:id "viewer-section"
|
||||||
:local local
|
:ref viewer-section-ref
|
||||||
:size size
|
:class (stl/css-case :viewer-section true
|
||||||
:index index
|
:fulscreen fullscreen?)
|
||||||
:viewer-pagination viewer-pagination
|
:on-click click-on-screen}
|
||||||
:interactions-mode interactions-mode
|
(cond
|
||||||
:share-id share-id}]
|
(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}
|
[:& (mf/provider ctx/current-zoom) {:value zoom}
|
||||||
[:& viewer-wrapper
|
[:& viewer-wrapper
|
||||||
{:wrapper-size wrapper-size
|
{:wrapper-size wrapper-size
|
||||||
:orig-frame orig-frame
|
:orig-frame orig-frame
|
||||||
:orig-viewport-ref orig-viewport-ref
|
:orig-viewport-ref orig-viewport-ref
|
||||||
:orig-size orig-size
|
:orig-size orig-size
|
||||||
:page page
|
:page page
|
||||||
:file file
|
:file file
|
||||||
:users users
|
:users users
|
||||||
:current-viewport-ref current-viewport-ref
|
:current-viewport-ref current-viewport-ref
|
||||||
:size size
|
:size size
|
||||||
:frame frame
|
:frame frame
|
||||||
:interactions-mode interactions-mode
|
:interactions-mode interactions-mode
|
||||||
:overlays overlays
|
:overlays overlays
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:section section
|
:section section
|
||||||
:index index}]]))]]]))
|
:index index}]]))]]])))
|
||||||
|
|
||||||
;; --- Component: Viewer Page
|
;; --- 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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.comments
|
(ns app.main.ui.viewer.comments
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
|
@ -16,6 +18,7 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.comments :as cmt]
|
[app.main.ui.comments :as cmt]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.workspace.comments :as wc]
|
[app.main.ui.workspace.comments :as wc]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -28,55 +31,126 @@
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local)
|
(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)
|
show-dropdown? (mf/use-state false)
|
||||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||||
|
|
||||||
update-mode
|
update-mode
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [mode]
|
(fn [event]
|
||||||
(st/emit! (dcm/update-filters {:mode mode}))))
|
(let [mode (-> (dom/get-current-target event)
|
||||||
|
(dom/get-data "value")
|
||||||
|
(keyword))]
|
||||||
|
(st/emit! (dcm/update-filters {:mode mode})))))
|
||||||
|
|
||||||
update-show
|
update-show
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [mode]
|
(fn [event]
|
||||||
(st/emit! (dcm/update-filters {:show mode}))))
|
(let [mode (-> (dom/get-current-target event)
|
||||||
|
(dom/get-data "value")
|
||||||
|
(d/read-string))]
|
||||||
|
(st/emit! (dcm/update-filters {:show mode})))))
|
||||||
|
|
||||||
update-options
|
update-options
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [mode]
|
(fn [event]
|
||||||
(st/emit! (dcm/update-options {:show-sidebar? mode}))))]
|
(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}
|
(if new-css-system
|
||||||
[:span.label (tr "labels.comments")]
|
[:div {:class (stl/css :view-options)
|
||||||
[:span.icon i/arrow-down]
|
:on-click toggle-dropdown}
|
||||||
[:& dropdown {:show @show-dropdown?
|
[:span {:class (stl/css :dropdown-title)}
|
||||||
:on-close hide-dropdown}
|
(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
|
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
|
||||||
[:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode)))
|
(when (or (= :all cmode) (nil? cmode))
|
||||||
:on-click #(update-mode :all)}
|
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||||
[:span.icon i/tick]
|
|
||||||
[:span.label (tr "labels.show-all-comments")]]
|
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :yours cmode))
|
[:li {:class (stl/css-case :dropdown-element true
|
||||||
:on-click #(update-mode :yours)}
|
:selected (= :yours cmode))
|
||||||
[:span.icon i/tick]
|
:data-value :yours
|
||||||
[:span.label (tr "labels.show-your-comments")]]
|
:on-click update-mode}
|
||||||
|
|
||||||
[:hr]
|
[:span {:class (stl/css :label)}
|
||||||
|
(tr "labels.show-your-comments")]
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
(when (= :yours cmode)
|
||||||
:on-click #(update-show (if (= :pending cshow) :all :pending))}
|
[:span {:class (stl/css :icon)}
|
||||||
[:span.icon i/tick]
|
i/tick-refactor])]
|
||||||
[:span.label (tr "labels.hide-resolved-comments")]]
|
|
||||||
|
|
||||||
[:hr]
|
[:li {:class (stl/css :separator)}]
|
||||||
[:li {:class (dom/classnames :selected show-sidebar?)
|
|
||||||
:on-click #(update-options (not show-sidebar?))}
|
[:li {:class (stl/css-case :dropdown-element true
|
||||||
[:span.icon i/tick]
|
:selected (= :pending cshow))
|
||||||
[:span.label (tr "labels.show-comments-list")]]]]]))
|
: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}]
|
(defn- update-thread-position [positions {:keys [id] :as thread}]
|
||||||
|
@ -88,7 +162,8 @@
|
||||||
|
|
||||||
(mf/defc comments-layer
|
(mf/defc comments-layer
|
||||||
[{:keys [zoom file users frame page] :as props}]
|
[{:keys [zoom file users frame page] :as props}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
local (mf/deref refs/comments-local)
|
local (mf/deref refs/comments-local)
|
||||||
|
|
||||||
open-thread-id (:open local)
|
open-thread-id (:open local)
|
||||||
|
@ -159,43 +234,81 @@
|
||||||
(st/emit! (dcm/create-thread-on-viewer params)
|
(st/emit! (dcm/create-thread-on-viewer params)
|
||||||
(dcm/close-thread)))))]
|
(dcm/close-thread)))))]
|
||||||
|
|
||||||
[:div.comments-section {:on-click on-click}
|
(if new-css-system
|
||||||
[:div.viewer-comments-container
|
[:div {:class (stl/css :comments-section)
|
||||||
[:div.threads
|
:on-click on-click}
|
||||||
(for [item threads]
|
[:div {:class (stl/css :viewer-comments-container)}
|
||||||
[:& cmt/thread-bubble
|
[:div {:class (stl/css :threads)}
|
||||||
{:thread item
|
(for [item threads]
|
||||||
:position-modifier modifier1
|
[:& cmt/thread-bubble
|
||||||
:zoom zoom
|
{:thread item
|
||||||
:on-click on-bubble-click
|
:position-modifier modifier1
|
||||||
:open? (= (:id item) (:open local))
|
:zoom zoom
|
||||||
:key (:seqn item)
|
:on-click on-bubble-click
|
||||||
:origin :viewer}])
|
:open? (= (:id item) (:open local))
|
||||||
|
:key (:seqn item)
|
||||||
|
:origin :viewer}])
|
||||||
|
|
||||||
(when-let [thread (get threads-map open-thread-id)]
|
(when-let [thread (get threads-map open-thread-id)]
|
||||||
[:& cmt/thread-comments
|
[:& cmt/thread-comments
|
||||||
{:thread thread
|
{:thread thread
|
||||||
:position-modifier modifier1
|
:position-modifier modifier1
|
||||||
:users users
|
:users users
|
||||||
:zoom zoom}])
|
:zoom zoom}])
|
||||||
|
|
||||||
(when-let [draft (:draft local)]
|
(when-let [draft (:draft local)]
|
||||||
[:& cmt/draft-thread
|
[:& cmt/draft-thread
|
||||||
{:draft draft
|
{:draft draft
|
||||||
:position-modifier modifier1
|
:position-modifier modifier1
|
||||||
:on-cancel on-draft-cancel
|
:on-cancel on-draft-cancel
|
||||||
:on-submit on-draft-submit
|
:on-submit on-draft-submit
|
||||||
:zoom zoom}])]]]))
|
: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
|
(mf/defc comments-sidebar
|
||||||
[{:keys [users frame page]}]
|
[{: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)
|
local (mf/deref refs/comments-local)
|
||||||
threads-map (mf/deref refs/comment-threads)
|
threads-map (mf/deref refs/comment-threads)
|
||||||
threads (->> (vals threads-map)
|
threads (->> (vals threads-map)
|
||||||
(dcm/apply-filters local profile)
|
(dcm/apply-filters local profile)
|
||||||
(filter (fn [{:keys [position]}]
|
(filter (fn [{:keys [position]}]
|
||||||
(gsh/has-point? frame position))))]
|
(gsh/has-point? frame position))))]
|
||||||
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
(if new-css-system
|
||||||
[:div.settings-bar-inside
|
[:aside {:class (stl/css :comments-sidebar)}
|
||||||
[:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]]))
|
[: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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.header
|
(ns app.main.ui.viewer.header
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.shortcuts :as scd]
|
||||||
[app.main.data.viewer :as dv]
|
[app.main.data.viewer :as dv]
|
||||||
[app.main.data.viewer.shortcuts :as sc]
|
[app.main.data.viewer.shortcuts :as sc]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.export :refer [export-progress-widget]]
|
[app.main.ui.export :refer [export-progress-widget]]
|
||||||
[app.main.ui.formats :as fmt]
|
[app.main.ui.formats :as fmt]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -41,40 +44,120 @@
|
||||||
on-zoom-fit
|
on-zoom-fit
|
||||||
on-zoom-fill]
|
on-zoom-fill]
|
||||||
:as props}]
|
: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
|
(mf/defc header-options
|
||||||
[{:keys [section zoom page file index permissions interactions-mode]}]
|
[{: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
|
toggle-fullscreen
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
@ -91,49 +174,114 @@
|
||||||
(mf/deps page)
|
(mf/deps page)
|
||||||
(fn []
|
(fn []
|
||||||
(modal/show! :share-link {:page page :file file})
|
(modal/show! :share-link {:page page :file file})
|
||||||
(modal/allow-click-outside!)))]
|
(modal/allow-click-outside!)))
|
||||||
|
|
||||||
[:div.options-zone
|
handle-increase
|
||||||
(case section
|
(mf/use-fn
|
||||||
:interactions [:*
|
#(st/emit! dv/increase-zoom))
|
||||||
(when index
|
|
||||||
[:& flows-menu {:page page :index index}])
|
|
||||||
[:& interactions-menu {:interactions-mode interactions-mode}]]
|
|
||||||
:comments [:& comments-menu]
|
|
||||||
|
|
||||||
[:div.view-options])
|
handle-decrease
|
||||||
|
(mf/use-fn
|
||||||
|
#(st/emit! dv/decrease-zoom))
|
||||||
|
|
||||||
[:& export-progress-widget]
|
handle-zoom-reset
|
||||||
[:& zoom-widget
|
(mf/use-fn
|
||||||
{:zoom zoom
|
#(st/emit! dv/reset-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}]
|
|
||||||
|
|
||||||
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
|
handle-zoom-fill
|
||||||
{:alt (tr "viewer.header.fullscreen")
|
(mf/use-fn
|
||||||
:on-click toggle-fullscreen}
|
#(st/emit! dv/zoom-to-fill))
|
||||||
(if fullscreen?
|
|
||||||
i/full-screen-off
|
|
||||||
i/full-screen)]
|
|
||||||
|
|
||||||
(when (:is-admin permissions)
|
handle-zoom-fit
|
||||||
[:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]])
|
(mf/use-fn
|
||||||
|
#(st/emit! dv/zoom-to-fit))]
|
||||||
|
|
||||||
(when (:can-edit permissions)
|
(if new-css-system
|
||||||
[:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])
|
[: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)
|
[:& export-progress-widget]
|
||||||
[:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])]))
|
|
||||||
|
[:& 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
|
(mf/defc header-sitemap
|
||||||
[{:keys [project file page frame] :as props}]
|
[{: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)
|
file-name (:name file)
|
||||||
page-name (:name page)
|
page-name (:name page)
|
||||||
|
page-id (:id page)
|
||||||
frame-name (:name frame)
|
frame-name (:name frame)
|
||||||
show-dropdown? (mf/use-state false)
|
show-dropdown? (mf/use-state false)
|
||||||
|
|
||||||
|
@ -158,88 +306,181 @@
|
||||||
(st/emit! (dv/go-to-page page-id))
|
(st/emit! (dv/go-to-page page-id))
|
||||||
(reset! show-dropdown? false)))]
|
(reset! show-dropdown? false)))]
|
||||||
|
|
||||||
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
|
(if new-css-system
|
||||||
[:div.breadcrumb
|
[:div {:class (stl/css :sitemap-zone)
|
||||||
{:on-click open-dropdown}
|
:title (tr "viewer.header.sitemap")}
|
||||||
[:span.project-name project-name]
|
[:span {:class (stl/css :project-name)} project-name]
|
||||||
[:span "/"]
|
[:div {:class (stl/css :sitemap-text)}
|
||||||
[:span.file-name file-name]
|
[:div {:class (stl/css :breadcrumb)
|
||||||
[:span "/"]
|
:on-click open-dropdown}
|
||||||
|
[:span {:class (stl/css :breadcrumb-text)}
|
||||||
[:span.page-name page-name]
|
(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?
|
;; OLD
|
||||||
:on-close close-dropdown}
|
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
|
||||||
[:ul.dropdown
|
[:div.breadcrumb
|
||||||
(for [id (get-in file [:data :pages])]
|
{:on-click open-dropdown}
|
||||||
[:li {:id (str id)
|
[:span.project-name project-name]
|
||||||
:key (str id)
|
[:span "/"]
|
||||||
:on-click (partial navigate-to id)}
|
[:span.file-name file-name]
|
||||||
(get-in file [:data :pages-index id :name])])]]]
|
[:span "/"]
|
||||||
|
|
||||||
[:span.icon {:on-click open-dropdown} i/arrow-down]
|
[:span.page-name page-name]
|
||||||
[:div.current-frame
|
[:& dropdown {:show @show-dropdown?
|
||||||
{:on-click toggle-thumbnails}
|
:on-close close-dropdown}
|
||||||
[:span.label "/"]
|
[:ul.dropdown
|
||||||
[:span.label frame-name]]
|
(for [id (get-in file [:data :pages])]
|
||||||
[:span.icon {:on-click toggle-thumbnails} i/arrow-down]]))
|
[: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
|
(mf/defc header
|
||||||
[{:keys [project file page frame zoom section permissions index interactions-mode]}]
|
[{:keys [project file page frame zoom section permissions index interactions-mode]}]
|
||||||
(let [go-to-dashboard
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
#(st/emit! (dv/go-to-dashboard))
|
go-to-dashboard
|
||||||
|
(mf/use-fn
|
||||||
|
#(st/emit! (dv/go-to-dashboard)))
|
||||||
|
|
||||||
go-to-inspect
|
go-to-inspect
|
||||||
(fn[]
|
(mf/use-fn
|
||||||
(if (:is-logged permissions)
|
(mf/deps permissions)
|
||||||
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
|
(fn []
|
||||||
(open-login-dialog)))
|
(if (:is-logged permissions)
|
||||||
|
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
|
||||||
|
(open-login-dialog))))
|
||||||
|
|
||||||
navigate
|
navigate
|
||||||
(fn [section]
|
(mf/use-fn
|
||||||
(if (or (= section :interactions) (:is-logged permissions))
|
(mf/deps permissions)
|
||||||
(st/emit! (dv/go-to-section section))
|
(fn [event]
|
||||||
(open-login-dialog)))]
|
(let [section (-> (dom/get-current-target event)
|
||||||
|
(dom/get-data "value")
|
||||||
|
(keyword))]
|
||||||
|
|
||||||
[:header.viewer-header
|
(if (or (= section :interactions) (:is-logged permissions))
|
||||||
[:div.nav-zone
|
(st/emit! (dv/go-to-section section))
|
||||||
;; If the user doesn't have permission we disable the link
|
(open-login-dialog)))))]
|
||||||
[: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}]]
|
(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
|
[:& header-sitemap {:project project
|
||||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
:file file
|
||||||
{:on-click #(navigate :interactions)
|
:page page
|
||||||
:class (dom/classnames :active (= section :interactions))
|
:frame frame
|
||||||
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
:index index}]]
|
||||||
i/play]
|
|
||||||
|
|
||||||
(when (or (:can-edit permissions)
|
[:div {:class (stl/css :mode-zone)}
|
||||||
(= (:who-comment permissions) "all"))
|
[: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
|
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||||
{:on-click #(navigate :comments)
|
{:on-click navigate
|
||||||
:class (dom/classnames :active (= section :comments))
|
:data-value :interactions
|
||||||
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
:class (dom/classnames :active (= section :interactions))
|
||||||
i/chat])
|
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||||
|
i/play]
|
||||||
|
|
||||||
(when (or (= (:type permissions) :membership)
|
(when (or (:can-edit permissions)
|
||||||
(and (= (:type permissions) :share-link)
|
(= (:who-comment permissions) "all"))
|
||||||
(= (:who-inspect permissions) "all")))
|
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||||
[:button.mode-zone-button.tooltip.tooltip-bottom
|
{:on-click navigate
|
||||||
{:on-click go-to-inspect
|
:data-value :comments
|
||||||
:class (dom/classnames :active (= section :inspect))
|
:class (dom/classnames :active (= section :comments))
|
||||||
:alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
|
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
||||||
i/code])]
|
i/chat])
|
||||||
|
|
||||||
[:& header-options {:section section
|
(when (or (= (:type permissions) :membership)
|
||||||
:permissions permissions
|
(and (= (:type permissions) :share-link)
|
||||||
:page page
|
(= (:who-inspect permissions) "all")))
|
||||||
:file file
|
[:button.mode-zone-button.tooltip.tooltip-bottom
|
||||||
:index index
|
{:on-click go-to-inspect
|
||||||
:zoom zoom
|
:class (dom/classnames :active (= section :inspect))
|
||||||
:interactions-mode interactions-mode}]]))
|
: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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.inspect
|
(ns app.main.ui.viewer.inspect
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.viewer :as dv]
|
[app.main.data.viewer :as dv]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
||||||
[app.main.ui.viewer.inspect.left-sidebar :refer [left-sidebar]]
|
[app.main.ui.viewer.inspect.left-sidebar :refer [left-sidebar]]
|
||||||
[app.main.ui.viewer.inspect.render :refer [render-frame-svg]]
|
[app.main.ui.viewer.inspect.render :refer [render-frame-svg]]
|
||||||
|
@ -20,25 +23,27 @@
|
||||||
(:import goog.events.EventType))
|
(:import goog.events.EventType))
|
||||||
|
|
||||||
(defn handle-select-frame
|
(defn handle-select-frame
|
||||||
[frame]
|
[event]
|
||||||
(fn [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/prevent-default event)
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(st/emit! (dv/select-shape (:id frame)))
|
(st/emit! (dv/select-shape frame-id))
|
||||||
|
(when over-section?
|
||||||
(let [origin (dom/get-target event)
|
(if has-force?
|
||||||
over-section? (dom/class? origin "inspect-svg-container")
|
(dom/remove-class! layout "force-visible")
|
||||||
layout (dom/get-element "viewer-layout")
|
(dom/add-class! layout "force-visible")))))
|
||||||
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"))))))
|
|
||||||
|
|
||||||
(mf/defc viewport
|
(mf/defc viewport
|
||||||
[{:keys [local file page frame index viewer-pagination size share-id]}]
|
[{: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* (mf/use-state :info)
|
||||||
current-section (deref current-section*)
|
current-section (deref current-section*)
|
||||||
|
|
||||||
|
@ -77,7 +82,8 @@
|
||||||
handle-expand
|
handle-expand
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(mf/deps right-size)
|
(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)
|
(mf/use-effect on-mount)
|
||||||
|
|
||||||
|
@ -86,26 +92,60 @@
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dv/select-shape (:id frame)))))
|
(st/emit! (dv/select-shape (:id frame)))))
|
||||||
|
|
||||||
[:*
|
(if new-css-system
|
||||||
[:& left-sidebar {:frame frame
|
[:*
|
||||||
:local local
|
[:& left-sidebar {:frame frame
|
||||||
:page page}]
|
:local local
|
||||||
[:div.inspect-svg-wrapper {:on-click (handle-select-frame frame)}
|
:page page}]
|
||||||
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
|
[:div {:class (stl/css :inspect-svg-wrapper)
|
||||||
[:div.inspect-svg-container {:ref inspect-svg-container-ref}
|
:data-value (pr-str (:id frame))
|
||||||
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
|
: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
|
[:div {:class (stl/css-case :sidebar-container true
|
||||||
{:class (when (not can-be-expanded?) "not-expand")
|
:not-expand (not can-be-expanded?)
|
||||||
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
|
:expanded can-be-expanded?)
|
||||||
[:div.resize-area
|
|
||||||
{:on-pointer-down on-pointer-down
|
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
|
||||||
:on-lost-pointer-capture on-lost-pointer-capture
|
(when can-be-expanded?
|
||||||
:on-pointer-move on-pointer-move}]
|
[:div {:class (stl/css :resize-area)
|
||||||
[:& right-sidebar {:frame frame
|
:on-pointer-down on-pointer-down
|
||||||
:selected (:selected local)
|
:on-lost-pointer-capture on-lost-pointer-capture
|
||||||
:page page
|
:on-pointer-move on-pointer-move}])
|
||||||
:file file
|
[:& right-sidebar {:frame frame
|
||||||
:on-change-section handle-change-section
|
:selected (:selected local)
|
||||||
:on-expand handle-expand
|
:page page
|
||||||
:share-id share-id}]]]))
|
: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))))
|
(handle-change-tab :info))))
|
||||||
|
|
||||||
(if new-css-system
|
(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)
|
(if (seq shapes)
|
||||||
[:div {:class (stl/css :tool-windows)}
|
[:div {:class (stl/css :tool-windows)}
|
||||||
[:div {:class (stl/css :shape-row)}
|
[:div {:class (stl/css :shape-row)}
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
.settings-bar-right {
|
.settings-bar-right {
|
||||||
min-width: $s-252;
|
min-width: $s-252;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
position: relative;
|
position: relative;
|
||||||
left: unset;
|
left: unset;
|
||||||
right: unset;
|
right: unset;
|
||||||
grid-area: right-sidebar;
|
grid-area: right-sidebar;
|
||||||
|
padding-top: $s-8;
|
||||||
|
padding-left: $s-12;
|
||||||
.tool-windows {
|
.tool-windows {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -64,9 +66,11 @@
|
||||||
padding: $s-8 $s-24;
|
padding: $s-8 $s-24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspect-content {
|
.inspect-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
&.viewer-code {
|
||||||
|
height: calc(100vh - $s-48);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.interactions
|
(ns app.main.ui.viewer.interactions
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
[app.main.data.viewer :as dv]
|
[app.main.data.viewer :as dv]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.viewer.shapes :as shapes]
|
[app.main.ui.viewer.shapes :as shapes]
|
||||||
|
@ -191,77 +193,144 @@
|
||||||
(mf/defc flows-menu
|
(mf/defc flows-menu
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [page index]}]
|
[{: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)
|
frames (:frames page)
|
||||||
frame (get frames index)
|
frame (get frames index)
|
||||||
current-flow (mf/use-state
|
current-flow* (mf/use-state
|
||||||
(ctp/get-frame-flow flows (:id frame)))
|
#(ctp/get-frame-flow flows (:id frame)))
|
||||||
|
|
||||||
show-dropdown? (mf/use-state false)
|
current-flow (deref current-flow*)
|
||||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
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
|
select-flow
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [flow]
|
(fn [event]
|
||||||
(reset! current-flow flow)
|
(let [flow (-> (dom/get-current-target event)
|
||||||
(st/emit! (dv/go-to-frame (:starting-frame flow)))))]
|
(dom/get-data "value")
|
||||||
|
(d/read-string))]
|
||||||
|
(reset! current-flow* flow)
|
||||||
|
(st/emit! (dv/go-to-frame (:starting-frame flow))))))]
|
||||||
|
|
||||||
(when (seq flows)
|
(when (seq flows)
|
||||||
[:div.view-options {:on-click toggle-dropdown}
|
(if new-css-system
|
||||||
[:span.icon i/play]
|
[:div {:on-click toggle-dropdown
|
||||||
[:span.label (:name @current-flow)]
|
:class (stl/css :view-options)}
|
||||||
[:span.icon i/arrow-down]
|
[:span {:class (stl/css :icon)} i/play-refactor]
|
||||||
[:& dropdown {:show @show-dropdown?
|
[:span {:class (stl/css :dropdown-title)} (:name current-flow)]
|
||||||
:on-close hide-dropdown}
|
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
|
||||||
[:ul.dropdown.with-check
|
[:& dropdown {:show show-dropdown?
|
||||||
(for [[index flow] (d/enumerate flows)]
|
:on-close hide-dropdown}
|
||||||
[:li {:key (dm/str "flow-" (:id flow) "-" index)
|
[:ul {:class (stl/css :dropdown)}
|
||||||
:class (dom/classnames :selected (= (:id flow) (:id @current-flow)))
|
(for [[index flow] (d/enumerate flows)]
|
||||||
:on-click #(select-flow flow)}
|
[:li {:key (dm/str "flow-" (:id flow) "-" index)
|
||||||
[:span.icon i/tick]
|
:class (stl/css-case :dropdown-element true
|
||||||
[:span.label (:name flow)]])]]])))
|
: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
|
(mf/defc interactions-menu
|
||||||
[{:keys [interactions-mode]}]
|
[{: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))
|
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||||
|
|
||||||
select-mode
|
select-mode
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [mode (some-> (dom/get-current-target event)
|
(let [mode (some-> (dom/get-current-target event)
|
||||||
(dom/get-data "mode")
|
(dom/get-data "mode")
|
||||||
(keyword))]
|
(keyword))]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(st/emit! (dv/set-interactions-mode mode)))))]
|
(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 {:class (stl/css :label)} (tr "viewer.header.dont-show-interactions")]
|
||||||
[:span.label (tr "viewer.header.interactions")]
|
(when (= interactions-mode :hide)
|
||||||
[:span.icon i/arrow-down]
|
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||||
[:& 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))
|
[:li {:class (stl/css-case :dropdown-element true
|
||||||
:on-click select-mode
|
:selected (= interactions-mode :show))
|
||||||
:data-mode :show}
|
:on-click select-mode
|
||||||
[:span.icon i/tick]
|
:data-mode :show}
|
||||||
[:span.label (tr "viewer.header.show-interactions")]]
|
[: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
|
(defn animate-go-to-frame
|
||||||
[animation current-viewport orig-viewport current-size orig-size wrapper-size]
|
[animation current-viewport orig-viewport current-size orig-size wrapper-size]
|
||||||
(case (:animation-type animation)
|
(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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.login
|
(ns app.main.ui.viewer.login
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.logging :as log]
|
[app.common.logging :as log]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
[app.main.ui.auth.login :refer [login-methods]]
|
[app.main.ui.auth.login :refer [login-methods]]
|
||||||
[app.main.ui.auth.recovery-request :refer [recovery-request-page]]
|
[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.auth.register :refer [register-methods register-validate-form register-success-page]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -25,15 +27,31 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :login-register}
|
::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 "")
|
user-email (mf/use-state "")
|
||||||
register-token (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
|
main-section (or
|
||||||
(= @current-section :login)
|
(= current-section :login)
|
||||||
(= @current-section :register)
|
(= current-section :register)
|
||||||
(= @current-section :register-validate))
|
(= current-section :register-validate))
|
||||||
close
|
close
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
|
@ -49,57 +67,118 @@
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(reset! register-token (:token data))
|
(reset! register-token (:token data))
|
||||||
(set-current-section :register-validate))]
|
(set-current-section :register-validate))]
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(swap! storage assoc :redirect-url uri))
|
(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
|
[:div {:class (stl/css :modal-content)}
|
||||||
: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
|
(case current-section
|
||||||
[:div.form-container
|
:login
|
||||||
[:& register-methods {:on-success-callback success-register}]
|
[:div {:class (stl/css :form-container)}
|
||||||
[:div.links
|
[:& login-methods {:on-success-callback success-login :origin :viewer}]
|
||||||
[:div.link-entry
|
[:div {:class (stl/css :links)}
|
||||||
[:span (tr "auth.already-have-account") " "]
|
[:div {:class (stl/css :link-entry)}
|
||||||
[:a {:on-click #(set-current-section :login)}
|
[:a {:on-click set-section
|
||||||
(tr "auth.login-here")]]]]
|
: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
|
:register
|
||||||
[:div.form-container
|
[:div {:class (stl/css :form-container)}
|
||||||
[:& register-validate-form {:params {:token @register-token}
|
[:& 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}]
|
:on-success-callback success-email-sent}]
|
||||||
[:div.links
|
:email-sent
|
||||||
[:div.link-entry
|
[:div {:class (stl/css :form-container)}
|
||||||
[:a {:on-click #(set-current-section :register)}
|
[:& register-success-page {:params {:email @user-email}}]])
|
||||||
(tr "labels.go-back")]]]]
|
|
||||||
|
|
||||||
:recovery-request
|
(when main-section
|
||||||
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
|
[:div {:class (stl/css :links)}
|
||||||
:on-success-callback success-email-sent}]
|
[:& terms-login]])]]]
|
||||||
:email-sent
|
|
||||||
[:div.form-container
|
|
||||||
[:& register-success-page {:params {:email @user-email}}]])]
|
|
||||||
|
|
||||||
(when main-section
|
|
||||||
[:div.modal-footer.links
|
;;OLD
|
||||||
[:& terms-login]])]]))
|
[: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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.share-link
|
(ns app.main.ui.viewer.share-link
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -16,6 +17,8 @@
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[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.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -37,7 +40,8 @@
|
||||||
::mf/register-as :share-link
|
::mf/register-as :share-link
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[{:keys [file page]}]
|
[{: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)
|
current-page-id (:id page)
|
||||||
slinks (mf/deref refs/share-links)
|
slinks (mf/deref refs/share-links)
|
||||||
router (mf/deref refs/router)
|
router (mf/deref refs/router)
|
||||||
|
@ -151,135 +155,284 @@
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(swap! perms-visible* not))
|
(swap! perms-visible* not))
|
||||||
|
|
||||||
on-who-change
|
on-inspect-change
|
||||||
(fn [type event]
|
(fn [value]
|
||||||
(let [target (dom/get-target event)
|
(reset! confirm* false)
|
||||||
value (dom/get-value target)
|
(swap! options* assoc :who-inspect value))
|
||||||
value (keyword value)]
|
|
||||||
(reset! confirm* false)
|
on-comment-change
|
||||||
(if (= type :comment)
|
(fn [value]
|
||||||
(swap! options* assoc :who-comment (d/name value))
|
(reset! confirm* false)
|
||||||
(swap! options* assoc :who-inspect (d/name value)))))]
|
(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?)
|
(when (not ^boolean confirm?)
|
||||||
[:div.hint (tr "common.share-link.permissions-hint")])
|
[:div {:class (stl/css :permissions-section)}
|
||||||
(cond
|
[:button {:class (stl/css :manage-permissions)
|
||||||
(true? confirm?)
|
:on-click toggle-perms-visibility}
|
||||||
[:div.confirm-dialog
|
[:span {:class (stl/css-case :icon true
|
||||||
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
|
:rotated perms-visible?)}
|
||||||
[:div.actions
|
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
|
[:input.btn-secondary
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:on-click #(reset! confirm* false)
|
:class "primary"
|
||||||
:value (tr "labels.cancel")}]
|
:on-click try-delete-link
|
||||||
[:input.btn-danger
|
:value (tr "common.share-link.destroy-link")}]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:input.btn-primary
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:on-click delete-link
|
:class "primary"
|
||||||
:value (tr "common.share-link.destroy-link")}]]]
|
:on-click create-link
|
||||||
|
:value (tr "common.share-link.get-link")}])]]]
|
||||||
(some? current-link)
|
[:div.modal-content.ops-section
|
||||||
[:input.btn-secondary
|
[:div.manage-permissions
|
||||||
{:type "button"
|
{:on-click toggle-perms-visibility}
|
||||||
:class "primary"
|
[:span.icon i/picker-hsv]
|
||||||
:on-click try-delete-link
|
[:div.title (tr "common.share-link.manage-ops")]]
|
||||||
:value (tr "common.share-link.destroy-link")}]
|
(when ^boolean perms-visible?
|
||||||
|
[:*
|
||||||
:else
|
(let [all-selected? (:all-pages options)
|
||||||
[:input.btn-primary
|
pages (->> (get-in file [:data :pages])
|
||||||
{:type "button"
|
(map #(get-in file [:data :pages-index %])))
|
||||||
:class "primary"
|
selected (:pages options)]
|
||||||
:on-click create-link
|
[:*
|
||||||
:value (tr "common.share-link.get-link")}])]]]
|
[:div.view-mode
|
||||||
[:div.modal-content.ops-section
|
[:div.subtitle
|
||||||
[:div.manage-permissions
|
[:span.icon i/play]
|
||||||
{:on-click toggle-perms-visibility}
|
(tr "common.share-link.permissions-pages")]
|
||||||
[:span.icon i/picker-hsv]
|
[:div.items
|
||||||
[:div.title (tr "common.share-link.manage-ops")]]
|
(if (= 1 (count pages))
|
||||||
(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
|
|
||||||
[:div.input-checkbox.check-primary
|
[:div.input-checkbox.check-primary
|
||||||
[:input {:type "checkbox"
|
[:input {:type "checkbox"
|
||||||
:id "view-all"
|
:id (dm/str "page-" current-page-id)
|
||||||
:checked all-selected?
|
:data-page-id (dm/str current-page-id)
|
||||||
:name "pages-mode"
|
:on-change on-mark-checked-page
|
||||||
:on-change on-toggle-all}]
|
:checked true}]
|
||||||
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
|
[:label {:for (str "page-" current-page-id)} (:name current-page)]
|
||||||
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
[:span (str " " (tr "common.share-link.current-tag"))]]
|
||||||
|
|
||||||
[:ul.pages-selection
|
[:*
|
||||||
(for [{:keys [id name]} pages]
|
[:div.row
|
||||||
[:li.input-checkbox.check-primary {:key (dm/str id)}
|
[:div.input-checkbox.check-primary
|
||||||
[:input {:type "checkbox"
|
[:input {:type "checkbox"
|
||||||
:id (dm/str "page-" id)
|
:id "view-all"
|
||||||
:data-page-id (dm/str id)
|
:checked all-selected?
|
||||||
:on-change on-mark-checked-page
|
:name "pages-mode"
|
||||||
:checked (contains? selected id)}]
|
:on-change on-toggle-all}]
|
||||||
(if (= current-page-id id)
|
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
|
||||||
[:*
|
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
|
||||||
[:label {:for (dm/str "page-" id)} name]
|
|
||||||
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
|
[:ul.pages-selection
|
||||||
[:label {:for (dm/str "page-" id)} name])])]])]]])
|
(for [{:keys [id name]} pages]
|
||||||
[:div.access-mode
|
[:li.input-checkbox.check-primary {:key (dm/str id)}
|
||||||
[:div.subtitle
|
[:input {:type "checkbox"
|
||||||
[:span.icon i/chat]
|
:id (dm/str "page-" id)
|
||||||
(tr "common.share-link.permissions-can-comment")]
|
:data-page-id (dm/str id)
|
||||||
[:div.items
|
:on-change on-mark-checked-page
|
||||||
[:select.input-select {:on-change (partial on-who-change :comment)
|
:checked (contains? selected id)}]
|
||||||
:value (:who-comment options)}
|
(if (= current-page-id id)
|
||||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
[:*
|
||||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
|
[:label {:for (dm/str "page-" id)} name]
|
||||||
[:div.inspect-mode
|
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
|
||||||
[:div.subtitle
|
[:label {:for (dm/str "page-" id)} name])])]])]]])
|
||||||
[:span.icon i/code]
|
[:div.access-mode
|
||||||
(tr "common.share-link.permissions-can-inspect")]
|
[:div.subtitle
|
||||||
[:div.items
|
[:span.icon i/chat]
|
||||||
[:select.input-select {:on-change (partial on-who-change :inspect)
|
(tr "common.share-link.permissions-can-comment")]
|
||||||
:value (:who-inspect options)}
|
[:div.items
|
||||||
[:option {:value "team"} (tr "common.share-link.team-members")]
|
[:select.input-select {:on-change on-comment-change
|
||||||
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))
|
: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
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.viewer.thumbnails
|
(ns app.main.ui.viewer.thumbnails
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
[app.main.data.viewer :as dv]
|
[app.main.data.viewer :as dv]
|
||||||
[app.main.render :as render]
|
[app.main.render :as render]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -22,7 +24,8 @@
|
||||||
|
|
||||||
(mf/defc thumbnails-content
|
(mf/defc thumbnails-content
|
||||||
[{:keys [children expanded? total] :as props}]
|
[{: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))
|
width (mf/use-var (.. js/document -documentElement -clientWidth))
|
||||||
element-width (mf/use-var 152)
|
element-width (mf/use-var 152)
|
||||||
|
|
||||||
|
@ -56,45 +59,96 @@
|
||||||
(reset! width (obj/get dom "clientWidth"))))]
|
(reset! width (obj/get dom "clientWidth"))))]
|
||||||
|
|
||||||
(mf/use-effect on-mount)
|
(mf/use-effect on-mount)
|
||||||
(if expanded?
|
(if new-css-system
|
||||||
[:div.thumbnails-content
|
(if expanded?
|
||||||
[:div.thumbnails-list-expanded children]]
|
[:div {:class (stl/css :thumbnails-content)}
|
||||||
[:div.thumbnails-content
|
[:div {:class (stl/css :thumbnails-list-expanded)} children]]
|
||||||
[: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 {:class (stl/css :thumbnails-content)}
|
||||||
[:div.thumbnails-list {:ref container :on-wheel on-scroll}
|
[:button {:class (stl/css :left-scroll-handler)
|
||||||
[:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}}
|
:on-click on-left-arrow-click} i/arrow-refactor]
|
||||||
children]]])))
|
[: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
|
(mf/defc thumbnails-summary
|
||||||
[{:keys [on-toggle-expand on-close total] :as props}]
|
[{:keys [on-toggle-expand on-close total] :as props}]
|
||||||
[:div.thumbnails-summary
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:span.counter (tr "labels.num-of-frames" (i18n/c total))]
|
(if new-css-system
|
||||||
[:span.buttons
|
[:div {:class (stl/css :thumbnails-summary)}
|
||||||
[:span.btn-expand {:on-click on-toggle-expand} i/arrow-down]
|
[:span {:class (stl/css :counter)}
|
||||||
[:span.btn-close {:on-click on-close} i/close]]])
|
(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/defc thumbnail-item
|
||||||
{::mf/wrap [mf/memo
|
{::mf/wrap [mf/memo
|
||||||
#(mf/deferred % ts/idle-then-raf)]}
|
#(mf/deferred % ts/idle-then-raf)]}
|
||||||
[{:keys [selected? frame on-click index objects page-id thumbnail-data]}]
|
[{: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)))))]
|
children-bounds (gsh/shapes->rect (concat [frame] (->> children-ids (keep (d/getf objects)))))]
|
||||||
[:div.thumbnail-item {:on-click #(on-click % index)}
|
|
||||||
[:div.thumbnail-preview
|
(if new-css-system
|
||||||
{:class (dom/classnames :selected selected?)}
|
[:button {:class (stl/css :thumbnail-item)
|
||||||
[:& render/frame-svg {:frame (-> frame
|
:on-click #(on-click % index)}
|
||||||
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
[:div {:class (stl/css-case :thumbnail-preview true
|
||||||
(assoc :children-bounds children-bounds))
|
:selected selected?)}
|
||||||
:objects objects
|
[:& render/frame-svg {:frame (-> frame
|
||||||
:use-thumbnails true}]]
|
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
||||||
[:div.thumbnail-info
|
(assoc :children-bounds children-bounds))
|
||||||
[:span.name {:title (:name frame)} (:name frame)]]]))
|
: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
|
(mf/defc thumbnails-panel
|
||||||
[{:keys [frames page index show? thumbnail-data] :as props}]
|
[{: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)
|
container (mf/use-ref)
|
||||||
|
|
||||||
objects (:objects page)
|
objects (:objects page)
|
||||||
|
@ -109,24 +163,48 @@
|
||||||
(st/emit! (dv/go-to-frame-by-index index))
|
(st/emit! (dv/go-to-frame-by-index index))
|
||||||
(when @expanded?
|
(when @expanded?
|
||||||
(on-close))))]
|
(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
|
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
|
||||||
{;; This is better as an inline-style so it won't make a reflow of every frame inside
|
:on-close on-close
|
||||||
:style {:display (when (not show?) "none")}
|
:total (count frames)}]
|
||||||
:class (dom/classnames :expanded @expanded?)
|
[:& thumbnails-content {:expanded? @expanded?
|
||||||
:ref container}
|
: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)}]
|
[:section.viewer-thumbnails
|
||||||
[:& thumbnails-content {:expanded? @expanded?
|
{;; This is better as an inline-style so it won't make a reflow of every frame inside
|
||||||
:total (count frames)}
|
:style {:display (when (not show?) "none")}
|
||||||
(for [[i frame] (d/enumerate frames)]
|
:class (dom/classnames :expanded @expanded?)
|
||||||
[:& thumbnail-item {:index i
|
:ref container}
|
||||||
:key (dm/str (:id frame) "-" i)
|
|
||||||
:frame frame
|
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
|
||||||
:page-id (:id page)
|
:on-close on-close
|
||||||
:objects objects
|
:total (count frames)}]
|
||||||
:on-click on-item-click
|
[:& thumbnails-content {:expanded? @expanded?
|
||||||
:selected? (= i index)
|
:total (count frames)}
|
||||||
:thumbnail-data thumbnail-data}])]]))
|
(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))
|
[:li {:class (dom/classnames :selected (= :pending cshow))
|
||||||
:on-click update-show}
|
:on-click update-show}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.hide-resolved-comments")]]])
|
[:span.label (tr "labels.hide-resolved-comments")]]])))
|
||||||
|
|
||||||
))
|
|
||||||
|
|
||||||
(mf/defc comments-sidebar
|
(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)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
threads-map (mf/deref refs/threads-ref)
|
threads-map (mf/deref refs/threads-ref)
|
||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
|
@ -111,8 +109,11 @@
|
||||||
|
|
||||||
close-section
|
close-section
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps)
|
(mf/deps from-viewer)
|
||||||
#(st/emit! :interrupt (dw/deselect-all true)))
|
(fn []
|
||||||
|
(if from-viewer
|
||||||
|
(st/emit! (dcm/update-options {:show-sidebar? false}))
|
||||||
|
(st/emit! :interrupt (dw/deselect-all true)))))
|
||||||
|
|
||||||
tgroups (->> threads
|
tgroups (->> threads
|
||||||
(dcm/group-threads-by-page))
|
(dcm/group-threads-by-page))
|
||||||
|
@ -121,7 +122,6 @@
|
||||||
|
|
||||||
toggle-mode-selector
|
toggle-mode-selector
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps)
|
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(swap! state* not)))
|
(swap! state* not)))
|
||||||
|
@ -147,18 +147,17 @@
|
||||||
:on-click close-section}
|
:on-click close-section}
|
||||||
i/close-refactor]]
|
i/close-refactor]]
|
||||||
|
|
||||||
(when (seq tgroups)
|
[:button {:class (stl/css :mode-dropdown-wrapper)
|
||||||
[:button {:class (stl/css :mode-dropdown-wrapper)
|
:on-click toggle-mode-selector}
|
||||||
:on-click toggle-mode-selector}
|
|
||||||
|
|
||||||
[:span {:class (stl/css :mode-label)} (case (:mode local)
|
[:span {:class (stl/css :mode-label)} (case (:mode local)
|
||||||
(nil :all) (tr "labels.show-all-comments")
|
(nil :all) (tr "labels.show-all-comments")
|
||||||
:yours (tr "labels.show-your-comments"))]
|
:yours (tr "labels.show-your-comments"))]
|
||||||
[:div {:class (stl/css :icon)} i/arrow-refactor]]
|
[:div {:class (stl/css :icon)} i/arrow-refactor]]
|
||||||
|
|
||||||
[:& dropdown {:show options?
|
[:& dropdown {:show options?
|
||||||
:on-close #(reset! state* false)}
|
:on-close #(reset! state* false)}
|
||||||
[:& sidebar-options {:local local}]])
|
[:& sidebar-options {:local local}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :comments-section-content)}
|
[:div {:class (stl/css :comments-section-content)}
|
||||||
|
|
||||||
|
|
|
@ -126,14 +126,14 @@
|
||||||
(tr "workspace.header.zoom-fit-all")
|
(tr "workspace.header.zoom-fit-all")
|
||||||
[:span {:class (stl/css :shortcuts)}
|
[:span {:class (stl/css :shortcuts)}
|
||||||
(for [sc (scd/split-sc (sc/get-tooltip :fit-all))]
|
(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])]]
|
:key (str "zoom-fit-" sc)} sc])]]
|
||||||
[:li {:class (stl/css :zoom-option)
|
[:li {:class (stl/css :zoom-option)
|
||||||
:on-click on-zoom-selected}
|
:on-click on-zoom-selected}
|
||||||
(tr "workspace.header.zoom-selected")
|
(tr "workspace.header.zoom-selected")
|
||||||
[:span {:class (stl/css :shortcuts)}
|
[:span {:class (stl/css :shortcuts)}
|
||||||
(for [sc (scd/split-sc (sc/get-tooltip :zoom-selected))]
|
(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])]]]]]))
|
:key (str "zoom-selected-" sc)} sc])]]]]]))
|
||||||
|
|
||||||
;; --- Header Component
|
;; --- Header Component
|
||||||
|
|
|
@ -198,6 +198,7 @@
|
||||||
:checked (not hide-fill-on-export?)
|
:checked (not hide-fill-on-export?)
|
||||||
:on-change on-change-show-fill-on-export}]]])])]
|
:on-change on-change-show-fill-on-export}]]])])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
[:div.element-set
|
[:div.element-set
|
||||||
[:div.element-set-title
|
[:div.element-set-title
|
||||||
[:span label]
|
[:span label]
|
||||||
|
|
|
@ -1637,6 +1637,9 @@ msgstr "Settings"
|
||||||
msgid "labels.share-prototype"
|
msgid "labels.share-prototype"
|
||||||
msgstr "Share prototype"
|
msgstr "Share prototype"
|
||||||
|
|
||||||
|
msgid "labels.share"
|
||||||
|
msgstr "Share"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs
|
#: src/app/main/ui/dashboard/sidebar.cljs
|
||||||
msgid "labels.shared-libraries"
|
msgid "labels.shared-libraries"
|
||||||
msgstr "Libraries"
|
msgstr "Libraries"
|
||||||
|
|
|
@ -1673,6 +1673,9 @@ msgstr "Configuración"
|
||||||
msgid "labels.share-prototype"
|
msgid "labels.share-prototype"
|
||||||
msgstr "Compartir prototipo"
|
msgstr "Compartir prototipo"
|
||||||
|
|
||||||
|
msgid "labels.share"
|
||||||
|
msgstr "Compartir"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs
|
#: src/app/main/ui/dashboard/sidebar.cljs
|
||||||
msgid "labels.shared-libraries"
|
msgid "labels.shared-libraries"
|
||||||
msgstr "Bibliotecas"
|
msgstr "Bibliotecas"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue