0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-18 10:41:29 -05:00

💄 Add new UI to viewer area

This commit is contained in:
Eva 2023-12-01 11:30:17 +01:00 committed by Alonso Torres
parent 15f81e557c
commit f8dd86da34
31 changed files with 2841 additions and 723 deletions

View 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

View 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

View file

@ -148,6 +148,7 @@
stroke: var(--button-tertiary-foreground-color-active);
}
}
&:global(.disabled),
&[disabled],
&:disabled {

View file

@ -297,4 +297,13 @@
--tag-background-color: var(--color-accent-primary);
--link-foreground-color: var(--color-accent-primary);
// VIEWER
--viewer-background-color: var(--color-background-secondary);
--viewer-paginator-background-color: var(--color-background-tertiary);
--viewer-controls-background-color: var(--color-background-primary);
--viewer-inspect-border-color: var(--color-background-tertiary);
--viewer-thumbnails-control-foreground-color: var(--color-foreground-secondary);
--viewer-thumbnail-border-color: var(--color-accent-primary);
--viewer-thumbnail-background-color-selected: var(--color-accent-primary-muted);
}

View file

@ -93,10 +93,9 @@
(assoc :message (tr "errors.email-invalid"))))))
(mf/defc login-form
[{:keys [params on-success-callback] :as props}]
[{:keys [params on-success-callback origin] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
initial (mf/use-memo (mf/deps params) (constantly params))
error (mf/use-state false)
form (fm/use-form :spec ::login-form
:validators [handle-error-messages]
@ -152,7 +151,12 @@
(let [params (:clean-data @form)]
(login-with-ldap event (with-meta params
{:on-error on-error
:on-success on-success})))))]
:on-success on-success})))))
on-recovery-request
(mf/use-fn
#(st/emit! (rt/nav :auth-recovery-request)))]
(if new-css-system
[:*
(when-let [message @error]
@ -178,10 +182,11 @@
:label (tr "auth.password")
:class (stl/css :form-field)}]]
(when (or (contains? cf/flags :login)
(contains? cf/flags :login-with-password))
(when (and (not= origin :viewer)
(or (contains? cf/flags :login)
(contains? cf/flags :login-with-password)))
[:div {:class (stl/css :fields-row :forgot-password)}
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
[:& lk/link {:action on-recovery-request
:data-test "forgot-password"}
(tr "auth.forgot-password")]])
@ -198,6 +203,7 @@
{:label (tr "auth.login-with-ldap-submit")
:on-click on-submit-ldap}])]]]
;; OLD
[:*
(when-let [message @error]
@ -271,7 +277,7 @@
:icon i/brand-openid
:label (tr "auth.login-with-oidc-submit")
:class (stl/css :login-btn :btn-oidc-auth)}])]
[:div.auth-buttons
(when (contains? cf/flags :login-with-google)
[:& bl/button-link {:on-click login-with-google
@ -299,28 +305,36 @@
(mf/defc login-button-oidc
[{:keys [params] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
login-oidc
(mf/use-fn
(mf/deps params)
(fn [event]
(login-with-oidc event :oidc params)))
handle-key-down
(mf/use-fn
(fn [event]
(when (k/enter? event)
(login-oidc event))))]
(if new-css-system
(when (contains? cf/flags :login-with-oidc)
[:div {:class (stl/css :link-entry :link-oidc)}
[:a {:tab-index "0"
:on-key-down (fn [event]
(when (k/enter? event)
(login-with-oidc event :oidc params)))
:on-click #(login-with-oidc % :oidc params)}
:on-key-down handle-key-down
:on-click login-oidc}
(tr "auth.login-with-oidc-submit")]])
;; OLD
(when (contains? cf/flags :login-with-oidc)
[:div.link-entry.link-oidc
[:a {:tab-index "0"
:on-key-down (fn [event]
(when (k/enter? event)
(login-with-oidc event :oidc params)))
:on-click #(login-with-oidc % :oidc params)}
:on-key-down handle-key-down
:on-click login-oidc}
(tr "auth.login-with-oidc-submit")]]))))
(mf/defc login-methods
[{:keys [params on-success-callback] :as props}]
[{:keys [params on-success-callback origin] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
(if new-css-system
[:*
@ -336,7 +350,7 @@
(when (or (contains? cf/flags :login)
(contains? cf/flags :login-with-password)
(contains? cf/flags :login-with-ldap))
[:& login-form {:params params :on-success-callback on-success-callback}])]
[:& login-form {:params params :on-success-callback on-success-callback :origin origin}])]
;; OLD
[:*
@ -364,7 +378,19 @@
(mf/defc login-page
[{:keys [params] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
go-register
(mf/use-fn
#(st/emit! (rt/nav :auth-register {} params)))
on-pass-recovery
(mf/use-fn
#(st/emit! (rt/nav :auth-recovery-request)))
on-create-demo-profile
(mf/use-fn
#(st/emit! (du/create-demo-profile)))]
(if new-css-system
[:div {:class (stl/css :auth-form)}
[:h1 {:class (stl/css :auth-title)
@ -375,17 +401,24 @@
[:& login-methods {:params params}]
[:div {:class (stl/css :links)}
(when (or (contains? cf/flags :login)
(contains? cf/flags :login-with-password))
[:div {:class (stl/css :link-entry :register)}
[:& lk/link {:action on-pass-recovery
:data-test "forgot-password"}
(tr "auth.forgot-password")]])
(when (contains? cf/flags :registration)
[:div {:class (stl/css :link-entry :register)}
[:span (tr "auth.register") " "]
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
[:& lk/link {:action go-register
:data-test "register-submit"}
(tr "auth.register-submit")]])]
(when (contains? cf/flags :demo-users)
[:div {:class (stl/css :link-entry :demo-account)}
[:span (tr "auth.create-demo-profile") " "]
[:& lk/link {:action #(st/emit! (du/create-demo-profile))
[:& lk/link {:action on-create-demo-profile
:data-test "demo-account-link"}
(tr "auth.create-demo-account")]])]
@ -400,14 +433,14 @@
(when (or (contains? cf/flags :login)
(contains? cf/flags :login-with-password))
[:div.link-entry
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
[:& lk/link {:action on-pass-recovery
:data-test "forgot-password"}
(tr "auth.forgot-password")]])
(when (contains? cf/flags :registration)
[:div.link-entry
[:span (tr "auth.register") " "]
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
[:& lk/link {:action go-register
:data-test "register-submit"}
(tr "auth.register-submit")]])]
@ -415,7 +448,7 @@
[:div.links.demo
[:div.link-entry
[:span (tr "auth.create-demo-profile") " "]
[:& lk/link {:action #(st/emit! (du/create-demo-profile))
[:& lk/link {:action on-create-demo-profile
:data-test "demo-account-link"}
(tr "auth.create-demo-account")]]])]])))

View file

@ -55,8 +55,12 @@
:cmd cmd})))
on-toggle-enabled
(fn [index]
(swap! exports update-in [index :enabled] not))
(mf/use-fn
(mf/deps exports)
(fn [event]
(let [index (-> (dom/get-current-target event)
(dom/get-data "value"))]
(swap! exports update-in [index :enabled] not))))
change-all
(fn [_]
@ -65,9 +69,8 @@
(if new-css-system
[:div {:class (stl/css :modal-overlay)}
[:div.modal-container.export-multiple-dialog
{:class (stl/css-case :modal-container true
:empty (empty? all-exports))}
[:div {:class (stl/css-case :modal-container true
:empty (empty? all-exports))}
[:div {:class (stl/css :modal-header)}
[:h2 {:class (stl/css :modal-title)} title]
@ -84,55 +87,58 @@
:on-click change-all}
[:span {:class (stl/css :checkbox-wrapper)}
(cond
all-checked? [:span {:class (stl/css-case :checkbox-icon2 true
all-checked? [:span {:class (stl/css-case :checkobox-tick true
:global/checked true)} i/tick-refactor]
all-unchecked? [:span {:class (stl/css-case :checkbox-icon2 true
all-unchecked? [:span {:class (stl/css-case :checkobox-tick true
:global/uncheked true)}]
:else [:span {:class (stl/css-case :checkbox-icon2 true
:else [:span {:class (stl/css-case :checkobox-tick true
:global/intermediate true)} i/remove-refactor])]]
[:div {:class (stl/css :selection-title)} (tr "dashboard.export-multiple.selected"
(c (count enabled-exports))
(c (count all-exports)))]]
[:div {:class (stl/css :selection-title)}
(tr "dashboard.export-multiple.selected"
(c (count enabled-exports))
(c (count all-exports)))]]
[:div {:class (stl/css :selection-wrapper)}
[:div {:class (stl/css-case :selection-list true
:selection-shadow (> (count all-exports) 8))}
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
(let [{:keys [x y width height]} (:selrect shape)]
[:div {:class (stl/css :selection-row)}
[:button {:class (stl/css :selection-btn)
:on-click #(on-toggle-enabled index)}
[:span {:class (stl/css :checkbox-wrapper)}
(if (:enabled export)
[:span {:class (stl/css-case :checkbox-icon2 true
:global/checked true)} i/tick-refactor]
[:span {:class (stl/css-case :checkbox-icon2 true
:global/uncheked true)}])]
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
(let [{:keys [x y width height]} (:selrect shape)]
[:div {:class (stl/css :selection-row)
:key (:id shape)}
[:button {:class (stl/css :selection-btn)
:data-value index
:on-click on-toggle-enabled}
[:span {:class (stl/css :checkbox-wrapper)}
(if (:enabled export)
[:span {:class (stl/css-case :checkobox-tick true
:global/checked true)} i/tick-refactor]
[:span {:class (stl/css-case :checkobox-tick true
:global/uncheked true)}])]
[:div {:class (stl/css :image-wrapper)}
(if (some? (:thumbnail shape))
[:img {:src (:thumbnail shape)}]
[:svg {:view-box (dm/str x " " y " " width " " height)
:width 24
:height 20
:version "1.1"
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
[:div {:class (stl/css :image-wrapper)}
(if (some? (:thumbnail shape))
[:img {:src (:thumbnail shape)}]
[:svg {:view-box (dm/str x " " y " " width " " height)
:width 24
:height 20
:version "1.1"
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
;; Fix Chromium bug about color of html texts
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
:style {:-webkit-print-color-adjust :exact}
:fill "none"}
:style {:-webkit-print-color-adjust :exact}
:fill "none"}
[:& shape-wrapper {:shape shape}]])]
[:& shape-wrapper {:shape shape}]])]
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
(when (:scale export)
[:div {:class (stl/css :selection-scale)}
(dm/str (ust/format-precision (* width (:scale export)) 2) "x"
(ust/format-precision (* height (:scale export)) 2) "px ")])
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
(when (:scale export)
[:div {:class (stl/css :selection-scale)}
(dm/str (ust/format-precision (* width (:scale export)) 2) "px"
(ust/format-precision (* height (:scale export)) 2) "px")])
(when (:type export)
[:div {:class (stl/css :selection-extension)}
(-> export :type d/name str/upper)])]]))]]]
(when (:type export)
[:div {:class (stl/css :selection-extension)}
(-> export :type d/name str/upper)])]]))]]]
[:& no-selection])]
@ -187,7 +193,8 @@
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
(let [{:keys [x y width height]} (:selrect shape)]
[:div.row
[:div.field.check {:on-click #(on-toggle-enabled index)}
[:div.field.check {:data-value index
:on-click on-toggle-enabled}
(if (:enabled export)
[:span.checked i/checkbox-checked]
[:span.unchecked i/checkbox-unchecked])]
@ -210,7 +217,7 @@
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
(when (:scale export)
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "x"
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "px"
(ust/format-precision (* height (:scale export)) 2) "px ")])
(when (:type export)

View file

@ -161,7 +161,7 @@
height: $s-24;
width: $s-24;
padding: 0;
.checkbox-icon2 {
.checkobox-tick {
@extend .checkbox-icon;
}
}

View file

@ -339,6 +339,7 @@
(def easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor))
(def effects-refactor (icon-xref :effects-refactor))
(def elipse-refactor (icon-xref :elipse-refactor))
(def expand-refactor (icon-xref :expand-refactor))
(def fill-content-refactor (icon-xref :fill-content-refactor))
(def filter-refactor (icon-xref :filter-refactor))
(def fixed-width-refactor (icon-xref :fixed-width-refactor))
@ -414,6 +415,7 @@
(def picker-refactor (icon-xref :picker-refactor))
(def play-refactor (icon-xref :play-refactor))
(def rectangle-refactor (icon-xref :rectangle-refactor))
(def reload-refactor (icon-xref :reload-refactor))
(def remove-refactor (icon-xref :remove-refactor))
(def rgba-refactor (icon-xref :rgba-refactor))
(def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor))

View file

@ -6,6 +6,7 @@
(ns app.main.ui.viewer
(:import goog.events.EventType)
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@ -91,29 +92,57 @@
:vbox (str "0 0 " width " " height)})))
(mf/defc viewer-pagination
[{:keys [index num-frames left-bar right-bar] :as props}]
[:*
(when (pos? index)
[:div.viewer-go-prev {:class (when left-bar "left-bar")}
[:div.arrow {:on-click #(st/emit! dv/select-prev-frame)} i/go-prev]])
(when (< (+ index 1) num-frames)
[:div.viewer-go-next {:class (when right-bar "right-bar")}
[:div.arrow {:on-click #(st/emit! dv/select-next-frame)} i/go-next]])
[:div.viewer-bottom {:class (when left-bar "left-bar")}
[:div.reset {:on-click #(st/emit! dv/select-first-frame)} i/reset]
[:div.counter (str/join " / " [(+ index 1) num-frames])]
[:span]]])
[{:keys [index num-frames left-bar right-bar comment-sidebar] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
go-prev-frame (mf/use-fn #(st/emit! dv/select-prev-frame))
go-next-frame (mf/use-fn #(st/emit! dv/select-next-frame))
go-first-frame (mf/use-fn #(st/emit! dv/select-first-frame))]
(if new-css-system
[:*
(when (pos? index)
[:button {:class (stl/css-case :viewer-go-prev true
:left-bar left-bar)
:on-click go-prev-frame}
i/arrow-refactor])
(when (< (+ index 1) num-frames)
[:button {:class (stl/css-case :viewer-go-next true
:comment-sidebar comment-sidebar
:right-bar right-bar)
:on-click go-next-frame}
i/arrow-refactor])
[:div {:class (stl/css-case :viewer-bottom true
:left-bar left-bar)}
[:button {:on-click go-first-frame
:class (stl/css :reset-button)}
i/reload-refactor]
[:span {:class (stl/css :counter)}
(str/join " / " [(+ index 1) num-frames])]
[:span]]]
;; OLD
[:*
(when (pos? index)
[:div.viewer-go-prev {:class (when left-bar "left-bar")}
[:div.arrow {:on-click go-prev-frame} i/go-prev]])
(when (< (+ index 1) num-frames)
[:div.viewer-go-next {:class (when right-bar "right-bar")}
[:div.arrow {:on-click go-next-frame} i/go-next]])
[:div.viewer-bottom {:class (when left-bar "left-bar")}
[:div.reset {:on-click go-first-frame} i/reset]
[:div.counter (str/join " / " [(+ index 1) num-frames])]
[:span]]])))
(mf/defc viewer-pagination-and-sidebar
{::mf/wrap [mf/memo]}
[{:keys [section index users frame page]}]
(let [comments-local (mf/deref refs/comments-local)
show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))]
[:*
[:*
[:& viewer-pagination
{:index index
:num-frames (count (:frames page))
:right-bar show-sidebar?}]
:comment-sidebar show-sidebar?}]
(when show-sidebar?
[:& comments-sidebar
@ -172,72 +201,138 @@
:page page
:interactions-mode interactions-mode}]]]))
(mf/defc viewer-wrapper
{::mf/wrap-props false}
[{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
size frame interactions-mode overlays zoom section index]}]
[:*
[:& viewer-pagination-and-sidebar
{:section section
:index index
:page page
:users users
:frame frame
:interactions-mode interactions-mode}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
(if new-css-system
[:*
[:& viewer-pagination-and-sidebar
{:section section
:index index
:page page
:users users
:frame frame
:interactions-mode interactions-mode}]
[:div.viewer-wrapper
{:style {:width (:width wrapper-size)
:height (:height wrapper-size)}}
[:div.viewer-clipper
(when orig-frame
[:div.viewport-container
{:ref orig-viewport-ref
:style {:width (:width orig-size)
:height (:height orig-size)
:position "relative"}}
[:div {:class (stl/css :viewer-wrapper)
:style {:width (:width wrapper-size)
:height (:height wrapper-size)}}
[:div {:class (stl/css :viewer-clipper)}
[:& interactions/viewport
{:frame orig-frame
:base-frame orig-frame
:frame-offset (gpt/point 0 0)
:size orig-size
:page page
:users users
:interactions-mode interactions-mode}]])
(when orig-frame
[:div {:class (stl/css :viewport-container)
:ref orig-viewport-ref
:style {:width (:width orig-size)
:height (:height orig-size)
:position "relative"}}
[:div.viewport-container
{:ref current-viewport-ref
:style {:width (:width size)
:height (:height size)
:position "relative"}}
[:& interactions/viewport
{:frame orig-frame
:base-frame orig-frame
:frame-offset (gpt/point 0 0)
:size orig-size
:page page
:users users
:interactions-mode interactions-mode}]])
[:& interactions/viewport
{:frame frame
:base-frame frame
:frame-offset (gpt/point 0 0)
:size size
:page page
:interactions-mode interactions-mode}]
[:div {:class (stl/css :viewport-container)
:ref current-viewport-ref
:style {:width (:width size)
:height (:height size)
:position "relative"}}
(for [overlay overlays]
[:& viewer-overlay
{:overlay overlay
:key (dm/str (:id overlay))
:page page
:frame frame
:zoom zoom
:wrapper-size wrapper-size
:interactions-mode interactions-mode}])]]
[:& interactions/viewport
{:frame frame
:base-frame frame
:frame-offset (gpt/point 0 0)
:size size
:page page
:interactions-mode interactions-mode}]
(for [overlay overlays]
[:& viewer-overlay
{:overlay overlay
:key (dm/str (:id overlay))
:page page
:frame frame
:zoom zoom
:wrapper-size wrapper-size
:interactions-mode interactions-mode}])]]
(when (= section :comments)
[:& comments-layer {:file file
:users users
:frame frame
:page page
:zoom zoom}])]])
(when (= section :comments)
[:& comments-layer {:file file
:users users
:frame frame
:page page
:zoom zoom}])]]
;; OLD
[:*
[:& viewer-pagination-and-sidebar
{:section section
:index index
:page page
:users users
:frame frame
:interactions-mode interactions-mode}]
[:div.viewer-wrapper
{:style {:width (:width wrapper-size)
:height (:height wrapper-size)}}
[:div.viewer-clipper
(when orig-frame
[:div.viewport-container
{:ref orig-viewport-ref
:style {:width (:width orig-size)
:height (:height orig-size)
:position "relative"}}
[:& interactions/viewport
{:frame orig-frame
:base-frame orig-frame
:frame-offset (gpt/point 0 0)
:size orig-size
:page page
:users users
:interactions-mode interactions-mode}]])
[:div.viewport-container
{:ref current-viewport-ref
:style {:width (:width size)
:height (:height size)
:position "relative"}}
[:& interactions/viewport
{:frame frame
:base-frame frame
:frame-offset (gpt/point 0 0)
:size size
:page page
:interactions-mode interactions-mode}]
(for [overlay overlays]
[:& viewer-overlay
{:overlay overlay
:key (dm/str (:id overlay))
:page page
:frame frame
:zoom zoom
:wrapper-size wrapper-size
:interactions-mode interactions-mode}])]]
(when (= section :comments)
[:& comments-layer {:file file
:users users
:frame frame
:page page
:zoom zoom}])]])))
(mf/defc viewer
[{:keys [params data]}]
@ -245,6 +340,8 @@
(let [{:keys [page-id share-id section index interactions-mode]} params
{:keys [file users project permissions]} data
new-css-system (mf/use-ctx ctx/new-css-system)
allowed (or
(= section :interactions)
(and (= section :comments)
@ -311,7 +408,7 @@
(calculate-wrapper size orig-size zoom))
click-on-screen
(mf/use-callback
(mf/use-fn
(fn [event]
(let [origin (dom/get-target event)
over-section? (dom/class? origin "viewer-section")
@ -360,9 +457,13 @@
(if shift?
(dom/set-h-scroll-pos! section new-scroll-pos)
(dom/set-scroll-pos! section new-scroll-pos)))))))))
on-thumbnails-close
(mf/use-fn
#(st/emit! dv/close-thumbnails-panel))
on-exit-fullscreen
(mf/use-callback
(mf/use-fn
(fn []
(when (not (dom/fullscreen?))
(st/emit! (dv/exit-fullscreen)))))]
@ -441,7 +542,7 @@
nil)
;; Navigate animation needs to be started after navigation
;; is complete, and we have the next page index.
(let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))]
(let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))]
(when nav-animation
(let [orig-viewport (mf/ref-val orig-viewport-ref)
current-viewport (mf/ref-val current-viewport-ref)]
@ -498,76 +599,153 @@
fonts (into #{} (keep :font-id) text-nodes)]
(run! fonts/ensure-loaded! fonts))))
[:div#viewer-layout
{:class (dom/classnames
:force-visible (:show-thumbnails local)
:viewer-layout (not= section :inspect)
:inspect-layout (= section :inspect)
:fullscreen fullscreen?)}
(if new-css-system
[:div#viewer-layout
{:class (stl/css-case
:force-visible (:show-thumbnails local)
:viewer-layout (not= section :inspect)
:inspect-layout (= section :inspect)
:fullscreen fullscreen?)}
[:div.viewer-content
[:& header/header {:project project
:index index
:file file
:page page
:frame frame
:permissions permissions
:zoom zoom
:section section
:interactions-mode interactions-mode}]
[:div.thumbnail-close {:on-click #(st/emit! dv/close-thumbnails-panel)
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
[:& thumbnails-panel {:frames frames
:show? (:show-thumbnails local false)
:page page
:index index
:thumbnail-data (:thumbnails file)}]
[:section.viewer-section {:id "viewer-section"
:ref viewer-section-ref
:class (if fullscreen? "fullscreen" "")
:on-click click-on-screen}
(cond
(empty? frames)
[:section.empty-state
[:span (tr "viewer.empty-state")]]
[:div {:class (stl/css :viewer-content)}
[:& header/header {:project project
:index index
:file file
:page page
:frame frame
:permissions permissions
:zoom zoom
:section section
:interactions-mode interactions-mode}]
(nil? frame)
[:section.empty-state
(when (some? index)
[:span (tr "viewer.frame-not-found")])]
[:button {:on-click on-thumbnails-close
:class (stl/css-case :thumbnails-close true
:invisible (not (:show-thumbnails local false)))}]
(some? frame)
(if (= :inspect section)
[:& inspect/viewport
{:frame frame
:page page
:file file
:section section
:local local
:size size
:index index
:viewer-pagination viewer-pagination
:interactions-mode interactions-mode
:share-id share-id}]
[:& thumbnails-panel {:frames frames
:show? (:show-thumbnails local false)
:page page
:index index
:thumbnail-data (:thumbnails file)}]
[:section {:id "viewer-section"
:ref viewer-section-ref
:class (stl/css-case :viewer-section true
:fulscreen fullscreen?)
:on-click click-on-screen}
(cond
(empty? frames)
[:section {:class (stl/css :empty-state)}
[:span (tr "viewer.empty-state")]]
(nil? frame)
[:section {:class (stl/css :empty-state)}
(when (some? index)
[:span (tr "viewer.frame-not-found")])]
(some? frame)
(if (= :inspect section)
[:& inspect/viewport
{:frame frame
:page page
:file file
:section section
:local local
:size size
:index index
:viewer-pagination viewer-pagination
:interactions-mode interactions-mode
:share-id share-id}]
[:& (mf/provider ctx/current-zoom) {:value zoom}
[:& viewer-wrapper
{:wrapper-size wrapper-size
:orig-frame orig-frame
:orig-viewport-ref orig-viewport-ref
:orig-size orig-size
:page page
:file file
:users users
:current-viewport-ref current-viewport-ref
:size size
:frame frame
:interactions-mode interactions-mode
:overlays overlays
:zoom zoom
:section section
:index index}]]))]]]
;; OLD
[:div#viewer-layout
{:class (dom/classnames
:force-visible (:show-thumbnails local)
:viewer-layout (not= section :inspect)
:inspect-layout (= section :inspect)
:fullscreen fullscreen?)}
[:div.viewer-content
[:& header/header {:project project
:index index
:file file
:page page
:frame frame
:permissions permissions
:zoom zoom
:section section
:interactions-mode interactions-mode}]
[:div.thumbnail-close {:on-click on-thumbnails-close
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
[:& thumbnails-panel {:frames frames
:show? (:show-thumbnails local false)
:page page
:index index
:thumbnail-data (:thumbnails file)}]
[:section.viewer-section {:id "viewer-section"
:ref viewer-section-ref
:class (if fullscreen? "fullscreen" "")
:on-click click-on-screen}
(cond
(empty? frames)
[:section.empty-state
[:span (tr "viewer.empty-state")]]
(nil? frame)
[:section.empty-state
(when (some? index)
[:span (tr "viewer.frame-not-found")])]
(some? frame)
(if (= :inspect section)
[:& inspect/viewport
{:frame frame
:page page
:file file
:section section
:local local
:size size
:index index
:viewer-pagination viewer-pagination
:interactions-mode interactions-mode
:share-id share-id}]
[:& (mf/provider ctx/current-zoom) {:value zoom}
[:& viewer-wrapper
{:wrapper-size wrapper-size
:orig-frame orig-frame
:orig-viewport-ref orig-viewport-ref
:orig-size orig-size
:page page
:file file
:users users
:current-viewport-ref current-viewport-ref
:size size
:frame frame
:interactions-mode interactions-mode
:overlays overlays
:zoom zoom
:section section
:index index}]]))]]]))
[:& (mf/provider ctx/current-zoom) {:value zoom}
[:& viewer-wrapper
{:wrapper-size wrapper-size
:orig-frame orig-frame
:orig-viewport-ref orig-viewport-ref
:orig-size orig-size
:page page
:file file
:users users
:current-viewport-ref current-viewport-ref
:size size
:frame frame
:interactions-mode interactions-mode
:overlays overlays
:zoom zoom
:section section
:index index}]]))]]])))
;; --- Component: Viewer Page

View 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;
}

View file

@ -5,7 +5,9 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.comments
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.rect :as grc]
@ -16,6 +18,7 @@
[app.main.store :as st]
[app.main.ui.comments :as cmt]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.workspace.comments :as wc]
[app.util.dom :as dom]
@ -28,55 +31,126 @@
::mf/wrap-props false}
[]
(let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local)
new-css-system (mf/use-ctx ctx/new-css-system)
show-dropdown? (mf/use-state false)
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
update-mode
(mf/use-callback
(fn [mode]
(st/emit! (dcm/update-filters {:mode mode}))))
(fn [event]
(let [mode (-> (dom/get-current-target event)
(dom/get-data "value")
(keyword))]
(st/emit! (dcm/update-filters {:mode mode})))))
update-show
(mf/use-callback
(fn [mode]
(st/emit! (dcm/update-filters {:show mode}))))
(fn [event]
(let [mode (-> (dom/get-current-target event)
(dom/get-data "value")
(d/read-string))]
(st/emit! (dcm/update-filters {:show mode})))))
update-options
(mf/use-callback
(fn [mode]
(st/emit! (dcm/update-options {:show-sidebar? mode}))))]
(fn [event]
(let [mode (-> (dom/get-target event)
(dom/get-data "value")
(boolean))]
(st/emit! (dcm/update-options {:show-sidebar? mode})))))]
[:div.view-options {:on-click toggle-dropdown}
[:span.label (tr "labels.comments")]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
(if new-css-system
[:div {:class (stl/css :view-options)
:on-click toggle-dropdown}
[:span {:class (stl/css :dropdown-title)}
(tr "labels.comments")]
[:span {:class (stl/css :icon-dropdown)}
i/arrow-refactor]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul {:class (stl/css :dropdown)}
[:li {:class (stl/css-case :dropdown-element true
:selected (or (= :all cmode) (nil? cmode)))
:data-value :all
:on-click update-mode}
[:ul.dropdown.with-check
[:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode)))
:on-click #(update-mode :all)}
[:span.icon i/tick]
[:span.label (tr "labels.show-all-comments")]]
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
(when (or (= :all cmode) (nil? cmode))
[:span {:class (stl/css :icon)} i/tick-refactor])]
[:li {:class (dom/classnames :selected (= :yours cmode))
:on-click #(update-mode :yours)}
[:span.icon i/tick]
[:span.label (tr "labels.show-your-comments")]]
[:li {:class (stl/css-case :dropdown-element true
:selected (= :yours cmode))
:data-value :yours
:on-click update-mode}
[:hr]
[:span {:class (stl/css :label)}
(tr "labels.show-your-comments")]
[:li {:class (dom/classnames :selected (= :pending cshow))
:on-click #(update-show (if (= :pending cshow) :all :pending))}
[:span.icon i/tick]
[:span.label (tr "labels.hide-resolved-comments")]]
(when (= :yours cmode)
[:span {:class (stl/css :icon)}
i/tick-refactor])]
[:hr]
[:li {:class (dom/classnames :selected show-sidebar?)
:on-click #(update-options (not show-sidebar?))}
[:span.icon i/tick]
[:span.label (tr "labels.show-comments-list")]]]]]))
[:li {:class (stl/css :separator)}]
[:li {:class (stl/css-case :dropdown-element true
:selected (= :pending cshow))
:data-value (if (= :pending cshow) :all :pending)
:on-click update-show}
[:span {:class (stl/css :label)}
(tr "labels.hide-resolved-comments")]
(when (= :pending cshow)
[:span {:class (stl/css :icon)}
i/tick-refactor])]
[:li {:class (stl/css :separator)}]
[:li {:class (stl/css-case :dropdown-element true
:selected show-sidebar?)
:data-value (not show-sidebar?)
:on-click update-options}
[:span {:class (stl/css :label)} (tr "labels.show-comments-list")]
(when show-sidebar?
[:span {:class (stl/css :icon)} i/tick-refactor])]]]]
; OLD
[:div.view-options {:on-click toggle-dropdown}
[:span.label (tr "labels.comments")]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul.dropdown.with-check
[:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode)))
:data-value :all
:on-click update-mode}
[:span.icon i/tick]
[:span.label (tr "labels.show-all-comments")]]
[:li {:class (dom/classnames :selected (= :yours cmode))
:data-value :yours
:on-click update-mode}
[:span.icon i/tick]
[:span.label (tr "labels.show-your-comments")]]
[:hr]
[:li {:class (dom/classnames :selected (= :pending cshow))
:data-value (if (= :pending cshow) :all :pending)
:on-click update-show}
[:span.icon i/tick]
[:span.label (tr "labels.hide-resolved-comments")]]
[:hr]
[:li {:class (dom/classnames :selected show-sidebar?)
:data-value (not show-sidebar?)
:on-click update-options}
[:span.icon i/tick]
[:span.label (tr "labels.show-comments-list")]]]]])))
(defn- update-thread-position [positions {:keys [id] :as thread}]
@ -88,7 +162,8 @@
(mf/defc comments-layer
[{:keys [zoom file users frame page] :as props}]
(let [profile (mf/deref refs/profile)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
profile (mf/deref refs/profile)
local (mf/deref refs/comments-local)
open-thread-id (:open local)
@ -159,43 +234,81 @@
(st/emit! (dcm/create-thread-on-viewer params)
(dcm/close-thread)))))]
[:div.comments-section {:on-click on-click}
[:div.viewer-comments-container
[:div.threads
(for [item threads]
[:& cmt/thread-bubble
{:thread item
:position-modifier modifier1
:zoom zoom
:on-click on-bubble-click
:open? (= (:id item) (:open local))
:key (:seqn item)
:origin :viewer}])
(if new-css-system
[:div {:class (stl/css :comments-section)
:on-click on-click}
[:div {:class (stl/css :viewer-comments-container)}
[:div {:class (stl/css :threads)}
(for [item threads]
[:& cmt/thread-bubble
{:thread item
:position-modifier modifier1
:zoom zoom
:on-click on-bubble-click
:open? (= (:id item) (:open local))
:key (:seqn item)
:origin :viewer}])
(when-let [thread (get threads-map open-thread-id)]
[:& cmt/thread-comments
{:thread thread
:position-modifier modifier1
:users users
:zoom zoom}])
(when-let [thread (get threads-map open-thread-id)]
[:& cmt/thread-comments
{:thread thread
:position-modifier modifier1
:users users
:zoom zoom}])
(when-let [draft (:draft local)]
[:& cmt/draft-thread
{:draft draft
:position-modifier modifier1
:on-cancel on-draft-cancel
:on-submit on-draft-submit
:zoom zoom}])]]]))
(when-let [draft (:draft local)]
[:& cmt/draft-thread
{:draft draft
:position-modifier modifier1
:on-cancel on-draft-cancel
:on-submit on-draft-submit
:zoom zoom}])]]]
[:div.comments-section {:on-click on-click}
[:div.viewer-comments-container
[:div.threads
(for [item threads]
[:& cmt/thread-bubble
{:thread item
:position-modifier modifier1
:zoom zoom
:on-click on-bubble-click
:open? (= (:id item) (:open local))
:key (:seqn item)
:origin :viewer}])
(when-let [thread (get threads-map open-thread-id)]
[:& cmt/thread-comments
{:thread thread
:position-modifier modifier1
:users users
:zoom zoom}])
(when-let [draft (:draft local)]
[:& cmt/draft-thread
{:draft draft
:position-modifier modifier1
:on-cancel on-draft-cancel
:on-submit on-draft-submit
:zoom zoom}])]]])))
(mf/defc comments-sidebar
[{:keys [users frame page]}]
(let [profile (mf/deref refs/profile)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
profile (mf/deref refs/profile)
local (mf/deref refs/comments-local)
threads-map (mf/deref refs/comment-threads)
threads (->> (vals threads-map)
(dcm/apply-filters local profile)
(filter (fn [{:keys [position]}]
(gsh/has-point? frame position))))]
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
[:div.settings-bar-inside
[:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]]))
(if new-css-system
[:aside {:class (stl/css :comments-sidebar)}
[:div {:class (stl/css :settings-bar-inside)}
[:& wc/comments-sidebar {:from-viewer true :users users :threads threads :page-id (:id page)}]]]
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
[:div.settings-bar-inside
[:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]])))

View 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);
}

View file

@ -5,13 +5,16 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.header
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.main.data.modal :as modal]
[app.main.data.shortcuts :as scd]
[app.main.data.viewer :as dv]
[app.main.data.viewer.shortcuts :as sc]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.export :refer [export-progress-widget]]
[app.main.ui.formats :as fmt]
[app.main.ui.icons :as i]
@ -41,40 +44,120 @@
on-zoom-fit
on-zoom-fill]
:as props}]
(let [show-dropdown? (mf/use-state false)]
[:div.zoom-widget {:on-click
(fn [event]
(dom/stop-propagation event)
(reset! show-dropdown? true))}
[:span.label (fmt/format-percent zoom)]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close #(reset! show-dropdown? false)}
[:ul.dropdown
[:li.basic-zoom-bar
[:span.zoom-btns
[:button {:on-click (fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(on-decrease))} "-"]
[:p.zoom-size (fmt/format-percent zoom)]
[:button {:on-click (fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(on-increase))} "+"]]
[:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]]
[:li.separator]
[:li {:on-click on-zoom-fit}
(tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]]
[:li {:on-click on-zoom-fill}
(tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]]
[:li {:on-click on-fullscreen}
(tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]]))
(let [new-css-system (mf/use-ctx ctx/new-css-system)
open* (mf/use-state false)
open? (deref open*)
open-dropdown
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(reset! open* true)))
close-dropdown
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(reset! open* false)))
on-increase
(mf/use-fn
(mf/deps on-increase)
(fn [event]
(dom/stop-propagation event)
(on-increase)))
on-decrease
(mf/use-fn
(mf/deps on-decrease)
(fn [event]
(dom/stop-propagation event)
(on-decrease)))
show-dropdown? (mf/use-state false)]
(if new-css-system
[:div {:class (stl/css-case :zoom-widget true
:selected open?)
:on-click open-dropdown
:title (tr "workspace.header.zoom")}
[:span {:class (stl/css :label)} (fmt/format-percent zoom)]
[:& dropdown {:show open?
:on-close close-dropdown}
[:ul {:class (stl/css :dropdown)}
[:li {:class (stl/css :basic-zoom-bar)}
[:span {:class (stl/css :zoom-btns)}
[:button {:class (stl/css :zoom-btn)
:on-click on-decrease}
[:span {:class (stl/css :zoom-icon)}
i/remove-refactor]]
[:p {:class (stl/css :zoom-text)}
(fmt/format-percent zoom)]
[:button {:class (stl/css :zoom-btn)
:on-click on-increase}
[:span {:class (stl/css :zoom-icon)}
i/add-refactor]]]
[:button {:class (stl/css :reset-btn)
:on-click on-zoom-reset}
(tr "workspace.header.reset-zoom")]]
[:li {:class (stl/css :zoom-option)
:on-click on-zoom-fit}
(tr "workspace.header.zoom-fit")
[:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
[:span {:class (stl/css :shortcut-key)
:key (str "zoom-fit-" sc)} sc])]]
[:li {:class (stl/css :zoom-option)
:on-click on-zoom-fill}
(tr "workspace.header.zoom-fill")
[:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
[:span {:class (stl/css :shortcut-key)
:key (str "zoom-fill-" sc)} sc])]]
[:li {:class (stl/css :zoom-option)
:on-click on-fullscreen}
(tr "workspace.header.zoom-full-screen")
[:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))]
[:span {:class (stl/css :shortcut-key)
:key (str "zoom-fullscreen-" sc)} sc])]]]]]
;; OLD
[:div.zoom-widget {:on-click
(fn [event]
(dom/stop-propagation event)
(reset! show-dropdown? true))}
[:span.label (fmt/format-percent zoom)]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close #(reset! show-dropdown? false)}
[:ul.dropdown
[:li.basic-zoom-bar
[:span.zoom-btns
[:button {:on-click (fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(on-decrease))} "-"]
[:p.zoom-size (fmt/format-percent zoom)]
[:button {:on-click (fn [event]
(dom/stop-propagation event)
(dom/prevent-default event)
(on-increase))} "+"]]
[:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]]
[:li.separator]
[:li {:on-click on-zoom-fit}
(tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]]
[:li {:on-click on-zoom-fill}
(tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]]
[:li {:on-click on-fullscreen}
(tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]])))
(mf/defc header-options
[{:keys [section zoom page file index permissions interactions-mode]}]
(let [fullscreen? (mf/deref fullscreen-ref)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
fullscreen? (mf/deref fullscreen-ref)
toggle-fullscreen
(mf/use-callback
@ -91,49 +174,114 @@
(mf/deps page)
(fn []
(modal/show! :share-link {:page page :file file})
(modal/allow-click-outside!)))]
(modal/allow-click-outside!)))
[:div.options-zone
(case section
:interactions [:*
(when index
[:& flows-menu {:page page :index index}])
[:& interactions-menu {:interactions-mode interactions-mode}]]
:comments [:& comments-menu]
handle-increase
(mf/use-fn
#(st/emit! dv/increase-zoom))
[:div.view-options])
handle-decrease
(mf/use-fn
#(st/emit! dv/decrease-zoom))
[:& export-progress-widget]
[:& zoom-widget
{:zoom zoom
:on-increase #(st/emit! dv/increase-zoom)
:on-decrease #(st/emit! dv/decrease-zoom)
:on-zoom-reset #(st/emit! dv/reset-zoom)
:on-zoom-fill #(st/emit! dv/zoom-to-fill)
:on-zoom-fit #(st/emit! dv/zoom-to-fit)
:on-fullscreen toggle-fullscreen}]
handle-zoom-reset
(mf/use-fn
#(st/emit! dv/reset-zoom))
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (tr "viewer.header.fullscreen")
:on-click toggle-fullscreen}
(if fullscreen?
i/full-screen-off
i/full-screen)]
handle-zoom-fill
(mf/use-fn
#(st/emit! dv/zoom-to-fill))
(when (:is-admin permissions)
[:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]])
handle-zoom-fit
(mf/use-fn
#(st/emit! dv/zoom-to-fit))]
(when (:can-edit permissions)
[:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])
(if new-css-system
[:div {:class (stl/css :options-zone)}
(case section
:interactions [:*
(when index
[:& flows-menu {:page page :index index}])
[:& interactions-menu {:interactions-mode interactions-mode}]]
:comments [:& comments-menu]
[:div {:class (stl/css :view-options)}])
(when-not (:is-logged permissions)
[:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])]))
[:& export-progress-widget]
[:& zoom-widget
{:zoom zoom
:on-increase handle-increase
:on-decrease handle-decrease
:on-zoom-reset handle-zoom-reset
:on-zoom-fill handle-zoom-fill
:on-zoom-fit handle-zoom-fit
:on-fullscreen toggle-fullscreen}]
(when (:can-edit permissions)
[:span {:on-click go-to-workspace
:class (stl/css :edit-btn)}
i/curve-refactor])
[:span {:title (tr "viewer.header.fullscreen")
:class (stl/css-case :fullscreen-btn true
:selected fullscreen?)
:on-click toggle-fullscreen}
i/expand-refactor]
(when (:is-admin permissions)
[:button {:on-click open-share-dialog
:class (stl/css :share-btn)}
(tr "labels.share")])
(when-not (:is-logged permissions)
[:span {:on-click open-login-dialog
:class (stl/css :go-log-btn)} (tr "labels.log-or-sign")])]
;; OLD
[:div.options-zone
(case section
:interactions [:*
(when index
[:& flows-menu {:page page :index index}])
[:& interactions-menu {:interactions-mode interactions-mode}]]
:comments [:& comments-menu]
[:div.view-options])
[:& export-progress-widget]
[:& zoom-widget
{:zoom zoom
:on-increase handle-increase
:on-decrease handle-decrease
:on-zoom-reset handle-zoom-reset
:on-zoom-fill handle-zoom-fill
:on-zoom-fit handle-zoom-fit
:on-fullscreen toggle-fullscreen}]
[:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (tr "viewer.header.fullscreen")
:on-click toggle-fullscreen}
(if fullscreen?
i/full-screen-off
i/full-screen)]
(when (:is-admin permissions)
[:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]])
(when (:can-edit permissions)
[:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])
(when-not (:is-logged permissions)
[:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])])))
(mf/defc header-sitemap
[{:keys [project file page frame] :as props}]
(let [project-name (:name project)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
project-name (:name project)
file-name (:name file)
page-name (:name page)
page-id (:id page)
frame-name (:name frame)
show-dropdown? (mf/use-state false)
@ -158,88 +306,181 @@
(st/emit! (dv/go-to-page page-id))
(reset! show-dropdown? false)))]
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
[:div.breadcrumb
{:on-click open-dropdown}
[:span.project-name project-name]
[:span "/"]
[:span.file-name file-name]
[:span "/"]
[:span.page-name page-name]
(if new-css-system
[:div {:class (stl/css :sitemap-zone)
:title (tr "viewer.header.sitemap")}
[:span {:class (stl/css :project-name)} project-name]
[:div {:class (stl/css :sitemap-text)}
[:div {:class (stl/css :breadcrumb)
:on-click open-dropdown}
[:span {:class (stl/css :breadcrumb-text)}
(dm/str file-name " / " page-name)]
[:span {:class (stl/css :icon)} i/arrow-refactor]
[:span "/"]
[:& dropdown {:show @show-dropdown?
:on-close close-dropdown}
[:ul {:class (stl/css :dropdown-sitemap)}
(for [id (get-in file [:data :pages])]
[:li {:class (stl/css-case :dropdown-element true
:selected (= page-id id))
:id (str id)
:key (str id)
:on-click (partial navigate-to id)}
[:span {:class (stl/css :label)}
(get-in file [:data :pages-index id :name])]
(when (= page-id id)
[:span {:class (stl/css :icon-check)} i/tick-refactor])])]]]
[:div {:class (stl/css :current-frame)
:on-click toggle-thumbnails}
[:span {:class (stl/css :frame-name)} frame-name]
[:span {:class (stl/css :icon)} i/arrow-refactor]]]]
[:& dropdown {:show @show-dropdown?
:on-close close-dropdown}
[:ul.dropdown
(for [id (get-in file [:data :pages])]
[:li {:id (str id)
:key (str id)
:on-click (partial navigate-to id)}
(get-in file [:data :pages-index id :name])])]]]
;; OLD
[:div.sitemap-zone {:alt (tr "viewer.header.sitemap")}
[:div.breadcrumb
{:on-click open-dropdown}
[:span.project-name project-name]
[:span "/"]
[:span.file-name file-name]
[:span "/"]
[:span.icon {:on-click open-dropdown} i/arrow-down]
[:div.current-frame
{:on-click toggle-thumbnails}
[:span.label "/"]
[:span.label frame-name]]
[:span.icon {:on-click toggle-thumbnails} i/arrow-down]]))
[:span.page-name page-name]
[:& dropdown {:show @show-dropdown?
:on-close close-dropdown}
[:ul.dropdown
(for [id (get-in file [:data :pages])]
[:li {:id (str id)
:key (str id)
:on-click (partial navigate-to id)}
(get-in file [:data :pages-index id :name])])]]]
[:span.icon {:on-click open-dropdown} i/arrow-down]
[:div.current-frame
{:on-click toggle-thumbnails}
[:span.label "/"]
[:span.label frame-name]]
[:span.icon {:on-click toggle-thumbnails} i/arrow-down]])))
(mf/defc header
[{:keys [project file page frame zoom section permissions index interactions-mode]}]
(let [go-to-dashboard
#(st/emit! (dv/go-to-dashboard))
(let [new-css-system (mf/use-ctx ctx/new-css-system)
go-to-dashboard
(mf/use-fn
#(st/emit! (dv/go-to-dashboard)))
go-to-inspect
(fn[]
(if (:is-logged permissions)
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
(open-login-dialog)))
(mf/use-fn
(mf/deps permissions)
(fn []
(if (:is-logged permissions)
(st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect))
(open-login-dialog))))
navigate
(fn [section]
(if (or (= section :interactions) (:is-logged permissions))
(st/emit! (dv/go-to-section section))
(open-login-dialog)))]
(mf/use-fn
(mf/deps permissions)
(fn [event]
(let [section (-> (dom/get-current-target event)
(dom/get-data "value")
(keyword))]
[:header.viewer-header
[:div.nav-zone
;; If the user doesn't have permission we disable the link
[:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}}
[:a {:on-click go-to-dashboard
:style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]]
(if (or (= section :interactions) (:is-logged permissions))
(st/emit! (dv/go-to-section section))
(open-login-dialog)))))]
[:& header-sitemap {:project project :file file :page page :frame frame :index index}]]
(if new-css-system
[:header {:class (stl/css :viewer-header)}
[:div {:class (stl/css :nav-zone)}
;; If the user doesn't have permission we disable the link
[:a {:class (stl/css :home-link)
:on-click go-to-dashboard
:style {:cursor (when-not (:can-edit permissions) "auto")
:pointer-events (when-not (:can-edit permissions) "none")}}
[:span {:class (stl/css :logo-icon)}
i/logo-icon]]
[:div.mode-zone
[:button.mode-zone-button.tooltip.tooltip-bottom
{:on-click #(navigate :interactions)
:class (dom/classnames :active (= section :interactions))
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
i/play]
[:& header-sitemap {:project project
:file file
:page page
:frame frame
:index index}]]
(when (or (:can-edit permissions)
(= (:who-comment permissions) "all"))
[:div {:class (stl/css :mode-zone)}
[:button {:on-click navigate
:data-value :interactions
:class (stl/css-case :mode-zone-btn true
:selected (= section :interactions))
:title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
i/play-refactor]
(when (or (:can-edit permissions)
(= (:who-comment permissions) "all"))
[:button {:on-click navigate
:data-value :comments
:class (stl/css-case :mode-zone-btn true
:selected (= section :comments))
:title (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
i/comments-refactor])
(when (or (= (:type permissions) :membership)
(and (= (:type permissions) :share-link)
(= (:who-inspect permissions) "all")))
[:button {:on-click go-to-inspect
:class (stl/css-case :mode-zone-btn true
:selected (= section :inspect))
:title (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
i/code-refactor])]
[:& header-options {:section section
:permissions permissions
:page page
:file file
:index index
:zoom zoom
:interactions-mode interactions-mode}]]
;; OLD
[:header.viewer-header
[:div.nav-zone
;; If the user doesn't have permission we disable the link
[:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}}
[:a {:on-click go-to-dashboard
:style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]]
[:& header-sitemap {:project project :file file :page page :frame frame :index index}]]
[:div.mode-zone
[:button.mode-zone-button.tooltip.tooltip-bottom
{:on-click #(navigate :comments)
:class (dom/classnames :active (= section :comments))
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
i/chat])
{:on-click navigate
:data-value :interactions
:class (dom/classnames :active (= section :interactions))
:alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
i/play]
(when (or (= (:type permissions) :membership)
(and (= (:type permissions) :share-link)
(= (:who-inspect permissions) "all")))
[:button.mode-zone-button.tooltip.tooltip-bottom
{:on-click go-to-inspect
:class (dom/classnames :active (= section :inspect))
:alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
i/code])]
(when (or (:can-edit permissions)
(= (:who-comment permissions) "all"))
[:button.mode-zone-button.tooltip.tooltip-bottom
{:on-click navigate
:data-value :comments
:class (dom/classnames :active (= section :comments))
:alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
i/chat])
[:& header-options {:section section
:permissions permissions
:page page
:file file
:index index
:zoom zoom
:interactions-mode interactions-mode}]]))
(when (or (= (:type permissions) :membership)
(and (= (:type permissions) :share-link)
(= (:who-inspect permissions) "all")))
[:button.mode-zone-button.tooltip.tooltip-bottom
{:on-click go-to-inspect
:class (dom/classnames :active (= section :inspect))
:alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
i/code])]
[:& header-options {:section section
:permissions permissions
:page page
:file file
:index index
:zoom zoom
:interactions-mode interactions-mode}]])))

View 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);
}
}
}
}

View file

@ -5,10 +5,13 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.inspect
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.data.viewer :as dv]
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.viewer.inspect.left-sidebar :refer [left-sidebar]]
[app.main.ui.viewer.inspect.render :refer [render-frame-svg]]
@ -20,25 +23,27 @@
(:import goog.events.EventType))
(defn handle-select-frame
[frame]
(fn [event]
[event]
(let [frame-id (-> (dom/get-current-target event)
(dom/get-data "value")
(d/read-string))
origin (dom/get-target event)
over-section? (dom/class? origin "inspect-svg-container")
layout (dom/get-element "viewer-layout")
has-force? (dom/class? layout "force-visible")]
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dv/select-shape (:id frame)))
(let [origin (dom/get-target event)
over-section? (dom/class? origin "inspect-svg-container")
layout (dom/get-element "viewer-layout")
has-force? (dom/class? layout "force-visible")]
(when over-section?
(if has-force?
(dom/remove-class! layout "force-visible")
(dom/add-class! layout "force-visible"))))))
(st/emit! (dv/select-shape frame-id))
(when over-section?
(if has-force?
(dom/remove-class! layout "force-visible")
(dom/add-class! layout "force-visible")))))
(mf/defc viewport
[{:keys [local file page frame index viewer-pagination size share-id]}]
(let [inspect-svg-container-ref (mf/use-ref nil)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
inspect-svg-container-ref (mf/use-ref nil)
current-section* (mf/use-state :info)
current-section (deref current-section*)
@ -77,7 +82,8 @@
handle-expand
(mf/use-callback
(mf/deps right-size)
#(set-right-size (if (> right-size 276) 276 768)))]
(fn[]
(set-right-size (if (> right-size 276) 276 768))))]
(mf/use-effect on-mount)
@ -86,26 +92,60 @@
(fn []
(st/emit! (dv/select-shape (:id frame)))))
[:*
[:& left-sidebar {:frame frame
:local local
:page page}]
[:div.inspect-svg-wrapper {:on-click (handle-select-frame frame)}
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
[:div.inspect-svg-container {:ref inspect-svg-container-ref}
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
(if new-css-system
[:*
[:& left-sidebar {:frame frame
:local local
:page page}]
[:div {:class (stl/css :inspect-svg-wrapper)
:data-value (pr-str (:id frame))
:on-click handle-select-frame}
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
[:div {:class (stl/css :inspect-svg-container)
:ref inspect-svg-container-ref}
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
[:div.sidebar-container
{:class (when (not can-be-expanded?) "not-expand")
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
[:div.resize-area
{:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move}]
[:& right-sidebar {:frame frame
:selected (:selected local)
:page page
:file file
:on-change-section handle-change-section
:on-expand handle-expand
:share-id share-id}]]]))
[:div {:class (stl/css-case :sidebar-container true
:not-expand (not can-be-expanded?)
:expanded can-be-expanded?)
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
(when can-be-expanded?
[:div {:class (stl/css :resize-area)
:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move}])
[:& right-sidebar {:frame frame
:selected (:selected local)
:page page
:file file
:on-change-section handle-change-section
:on-expand handle-expand
:share-id share-id}]]]
;;OLD
[:*
[:& left-sidebar {:frame frame
:local local
:page page}]
[:div.inspect-svg-wrapper {:data-value (pr-str (:id frame))
:on-click handle-select-frame}
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
[:div.inspect-svg-container {:ref inspect-svg-container-ref}
[:& render-frame-svg {:frame frame :page page :local local :size size}]]]
[:div.sidebar-container
{:class (when (not can-be-expanded?) "not-expand")
:style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}}
[:div.resize-area
{:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move}]
[:& right-sidebar {:frame frame
:selected (:selected local)
:page page
:file file
:on-change-section handle-change-section
:on-expand handle-expand
:share-id share-id}]]])))

View 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;
}

View file

@ -87,8 +87,8 @@
(handle-change-tab :info))))
(if new-css-system
[:aside {:class (stl/css :settings-bar-right)}
[:aside {:class (stl/css-case :settings-bar-right true
:viewer-code (= from :inspect))}
(if (seq shapes)
[:div {:class (stl/css :tool-windows)}
[:div {:class (stl/css :shape-row)}

View file

@ -9,11 +9,13 @@
.settings-bar-right {
min-width: $s-252;
width: 100%;
height: 100%;
height: 100vh;
position: relative;
left: unset;
right: unset;
grid-area: right-sidebar;
padding-top: $s-8;
padding-left: $s-12;
.tool-windows {
height: 100%;
display: flex;
@ -64,9 +66,11 @@
padding: $s-8 $s-24;
}
}
.inspect-content {
flex: 1;
overflow: hidden;
}
&.viewer-code {
height: calc(100vh - $s-48);
}
}

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.interactions
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@ -18,6 +19,7 @@
[app.main.data.viewer :as dv]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
[app.main.ui.viewer.shapes :as shapes]
@ -191,77 +193,144 @@
(mf/defc flows-menu
{::mf/wrap [mf/memo]}
[{:keys [page index]}]
(let [flows (dm/get-in page [:options :flows])
(let [new-css-system (mf/use-ctx ctx/new-css-system)
flows (dm/get-in page [:options :flows])
frames (:frames page)
frame (get frames index)
current-flow (mf/use-state
(ctp/get-frame-flow flows (:id frame)))
current-flow* (mf/use-state
#(ctp/get-frame-flow flows (:id frame)))
show-dropdown? (mf/use-state false)
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
current-flow (deref current-flow*)
show-dropdown?* (mf/use-state false)
show-dropdown? (deref show-dropdown?*)
toggle-dropdown (mf/use-fn #(swap! show-dropdown?* not))
hide-dropdown (mf/use-fn #(reset! show-dropdown?* false))
select-flow
(mf/use-callback
(fn [flow]
(reset! current-flow flow)
(st/emit! (dv/go-to-frame (:starting-frame flow)))))]
(fn [event]
(let [flow (-> (dom/get-current-target event)
(dom/get-data "value")
(d/read-string))]
(reset! current-flow* flow)
(st/emit! (dv/go-to-frame (:starting-frame flow))))))]
(when (seq flows)
[:div.view-options {:on-click toggle-dropdown}
[:span.icon i/play]
[:span.label (:name @current-flow)]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul.dropdown.with-check
(for [[index flow] (d/enumerate flows)]
[:li {:key (dm/str "flow-" (:id flow) "-" index)
:class (dom/classnames :selected (= (:id flow) (:id @current-flow)))
:on-click #(select-flow flow)}
[:span.icon i/tick]
[:span.label (:name flow)]])]]])))
(if new-css-system
[:div {:on-click toggle-dropdown
:class (stl/css :view-options)}
[:span {:class (stl/css :icon)} i/play-refactor]
[:span {:class (stl/css :dropdown-title)} (:name current-flow)]
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
[:& dropdown {:show show-dropdown?
:on-close hide-dropdown}
[:ul {:class (stl/css :dropdown)}
(for [[index flow] (d/enumerate flows)]
[:li {:key (dm/str "flow-" (:id flow) "-" index)
:class (stl/css-case :dropdown-element true
:selected (= (:id flow) (:id current-flow)))
;; This is not a best practise, is not very performant Do not reproduce
:data-value (pr-str flow)
:on-click select-flow}
[:span {:class (stl/css :label)} (:name flow)]
(when (= (:id flow) (:id current-flow))
[:span {:class (stl/css :icon)} i/tick-refactor])])]]]
;; OLD
[:div.view-options {:on-click toggle-dropdown}
[:span.icon i/play]
[:span.label (:name current-flow)]
[:span.icon i/arrow-down]
[:& dropdown {:show show-dropdown?
:on-close hide-dropdown}
[:ul.dropdown.with-check
(for [[index flow] (d/enumerate flows)]
[:li {:key (dm/str "flow-" (:id flow) "-" index)
:class (dom/classnames :selected (= (:id flow) (:id current-flow)))
;; This is not a best practise, is not very performant Do not reproduce
:data-value (pr-str flow)
:on-click select-flow}
[:span.icon i/tick]
[:span.label (:name flow)]])]]]))))
(mf/defc interactions-menu
[{:keys [interactions-mode]}]
(let [show-dropdown? (mf/use-state false)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
show-dropdown? (mf/use-state false)
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
select-mode
(mf/use-fn
(fn [event]
(let [mode (some-> (dom/get-current-target event)
(dom/get-data "mode")
(keyword))]
(dom/stop-propagation event)
(st/emit! (dv/set-interactions-mode mode)))))]
(fn [event]
(let [mode (some-> (dom/get-current-target event)
(dom/get-data "mode")
(keyword))]
(dom/stop-propagation event)
(st/emit! (dv/set-interactions-mode mode)))))]
(if new-css-system
[:div {:on-click toggle-dropdown
:class (stl/css :view-options)}
[:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")]
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul {:class (stl/css :dropdown)}
[:li {:class (stl/css-case :dropdown-element true
:selected (= interactions-mode :hide))
:on-click select-mode
:data-mode :hide}
[:div.view-options {:on-click toggle-dropdown}
[:span.label (tr "viewer.header.interactions")]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul.dropdown.with-check
[:li {:class (dom/classnames :selected (= interactions-mode :hide))
:on-click select-mode
:data-mode :hide}
[:span.icon i/tick]
[:span.label (tr "viewer.header.dont-show-interactions")]]
[:span {:class (stl/css :label)} (tr "viewer.header.dont-show-interactions")]
(when (= interactions-mode :hide)
[:span {:class (stl/css :icon)} i/tick-refactor])]
[:li {:class (dom/classnames :selected (= interactions-mode :show))
:on-click select-mode
:data-mode :show}
[:span.icon i/tick]
[:span.label (tr "viewer.header.show-interactions")]]
[:li {:class (stl/css-case :dropdown-element true
:selected (= interactions-mode :show))
:on-click select-mode
:data-mode :show}
[:span {:class (stl/css :label)} (tr "viewer.header.show-interactions")]
(when (= interactions-mode :show)
[:span {:class (stl/css :icon)} i/tick-refactor])]
[:li {:class (dom/classnames :selected (= interactions-mode :show-on-click))
:on-click select-mode
:data-mode :show-on-click}
[:span.icon i/tick]
[:span.label (tr "viewer.header.show-interactions-on-click")]]]]]))
[:li {:class (stl/css-case :dropdown-element true
:selected (= interactions-mode :show-on-click))
:on-click select-mode
:data-mode :show-on-click}
[:span {:class (stl/css :label)} (tr "viewer.header.show-interactions-on-click")]
(when (= interactions-mode :show-on-click)
[:span {:class (stl/css :icon)} i/tick-refactor])]]]]
[:div.view-options {:on-click toggle-dropdown}
[:span.label (tr "viewer.header.interactions")]
[:span.icon i/arrow-down]
[:& dropdown {:show @show-dropdown?
:on-close hide-dropdown}
[:ul.dropdown.with-check
[:li {:class (dom/classnames :selected (= interactions-mode :hide))
:on-click select-mode
:data-mode :hide}
[:span.icon i/tick]
[:span.label (tr "viewer.header.dont-show-interactions")]]
[:li {:class (dom/classnames :selected (= interactions-mode :show))
:on-click select-mode
:data-mode :show}
[:span.icon i/tick]
[:span.label (tr "viewer.header.show-interactions")]]
[:li {:class (dom/classnames :selected (= interactions-mode :show-on-click))
:on-click select-mode
:data-mode :show-on-click}
[:span.icon i/tick]
[:span.label (tr "viewer.header.show-interactions-on-click")]]]]])))
(defn animate-go-to-frame
[animation current-viewport orig-viewport current-size orig-size wrapper-size]
(case (:animation-type animation)

View 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

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.login
(:require-macros [app.main.style :as stl])
(:require
[app.common.logging :as log]
[app.main.data.modal :as modal]
@ -13,6 +14,7 @@
[app.main.ui.auth.login :refer [login-methods]]
[app.main.ui.auth.recovery-request :refer [recovery-request-page]]
[app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -25,15 +27,31 @@
{::mf/register modal/components
::mf/register-as :login-register}
[_]
(let [uri (. (. js/document -location) -href)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
uri (. (. js/document -location) -href)
user-email (mf/use-state "")
register-token (mf/use-state "")
current-section (mf/use-state :login)
set-current-section (mf/use-fn #(reset! current-section %))
current-section* (mf/use-state :login)
current-section (deref current-section*)
set-current-section
(mf/use-fn #(reset! current-section* %))
set-section
(mf/use-fn
(fn [event]
(let [section (-> (dom/get-current-target event)
(dom/get-data "value")
(keyword))]
(set-current-section section))))
go-back-to-login (mf/use-fn #(set-current-section :login))
main-section (or
(= @current-section :login)
(= @current-section :register)
(= @current-section :register-validate))
(= current-section :login)
(= current-section :register)
(= current-section :register-validate))
close
(fn [event]
(dom/prevent-default event)
@ -49,57 +67,118 @@
(fn [data]
(reset! register-token (:token data))
(set-current-section :register-validate))]
(mf/with-effect []
(swap! storage assoc :redirect-url uri))
[:div.modal-overlay
[:div.modal-container.login-register
[:div.title
[:div.modal-close-button {:on-click close :title (tr "labels.close")}
i/close]
(when main-section
[:h2 (tr "labels.continue-with-penpot")])]
[:div.modal-bottom.auth-content
(if new-css-system
[:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)}
[:div {:class (stl/css :modal-header)}
[:h2 {:class (stl/css :modal-title)} (tr "labels.continue-with-penpot")]
[:button {:class (stl/css :modal-close-btn)
:title (tr "labels.close")
:on-click close} i/close-refactor]]
(case @current-section
:login
[:div.generic-form.login-form
[:div.form-container
[:& login-methods {:on-success-callback success-login}]
[:div.links
[:div.link-entry
[:a {:on-click #(set-current-section :recovery-request)}
(tr "auth.forgot-password")]]
[:div.link-entry
[:span (tr "auth.register") " "]
[:a {:on-click #(set-current-section :register)}
(tr "auth.register-submit")]]]]]
[:div {:class (stl/css :modal-content)}
:register
[:div.form-container
[:& register-methods {:on-success-callback success-register}]
[:div.links
[:div.link-entry
[:span (tr "auth.already-have-account") " "]
[:a {:on-click #(set-current-section :login)}
(tr "auth.login-here")]]]]
(case current-section
:login
[:div {:class (stl/css :form-container)}
[:& login-methods {:on-success-callback success-login :origin :viewer}]
[:div {:class (stl/css :links)}
[:div {:class (stl/css :link-entry)}
[:a {:on-click set-section
:data-value :recovery-request}
(tr "auth.forgot-password")]]
[:div {:class (stl/css :link-entry)}
[:span (tr "auth.register") " "]
[:a {:on-click set-section
:data-value :register}
(tr "auth.register-submit")]]]]
:register-validate
[:div.form-container
[:& register-validate-form {:params {:token @register-token}
:register
[:div {:class (stl/css :form-container)}
[:& register-methods {:on-success-callback success-register}]
[:div {:class (stl/css :links)}
[:div {:class (stl/css :link-entry)}
[:span (tr "auth.already-have-account") " "]
[:a {:on-click set-section
:data-value :login}
(tr "auth.login-here")]]]]
:register-validate
[:div {:class (stl/css :form-container)}
[:& register-validate-form {:params {:token @register-token}
:on-success-callback success-email-sent}]
[:div {:class (stl/css :links)}
[:div {:class (stl/css :link-entry)}
[:a {:on-click set-section
:data-value :register}
(tr "labels.go-back")]]]]
:recovery-request
[:& recovery-request-page {:go-back-callback go-back-to-login
:on-success-callback success-email-sent}]
[:div.links
[:div.link-entry
[:a {:on-click #(set-current-section :register)}
(tr "labels.go-back")]]]]
:email-sent
[:div {:class (stl/css :form-container)}
[:& register-success-page {:params {:email @user-email}}]])
:recovery-request
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
:on-success-callback success-email-sent}]
:email-sent
[:div.form-container
[:& register-success-page {:params {:email @user-email}}]])]
(when main-section
[:div {:class (stl/css :links)}
[:& terms-login]])]]]
(when main-section
[:div.modal-footer.links
[:& terms-login]])]]))
;;OLD
[:div.modal-overlay
[:div.modal-container.login-register
[:div.title
[:div.modal-close-button {:on-click close :title (tr "labels.close")}
i/close]
(when main-section
[:h2 (tr "labels.continue-with-penpot")])]
[:div.modal-bottom.auth-content
(case current-section
:login
[:div.generic-form.login-form
[:div.form-container
[:& login-methods {:on-success-callback success-login}]
[:div.links
[:div.link-entry
[:a {:on-click #(set-current-section :recovery-request)}
(tr "auth.forgot-password")]]
[:div.link-entry
[:span (tr "auth.register") " "]
[:a {:on-click #(set-current-section :register)}
(tr "auth.register-submit")]]]]]
:register
[:div.form-container
[:& register-methods {:on-success-callback success-register}]
[:div.links
[:div.link-entry
[:span (tr "auth.already-have-account") " "]
[:a {:on-click #(set-current-section :login)}
(tr "auth.login-here")]]]]
:register-validate
[:div.form-container
[:& register-validate-form {:params {:token @register-token}
:on-success-callback success-email-sent}]
[:div.links
[:div.link-entry
[:a {:on-click #(set-current-section :register)}
(tr "labels.go-back")]]]]
:recovery-request
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
:on-success-callback success-email-sent}]
:email-sent
[:div.form-container
[:& register-success-page {:params {:email @user-email}}]])]
(when main-section
[:div.modal-footer.links
[:& terms-login]])]])))

View 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;
}
}

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.share-link
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@ -16,6 +17,8 @@
[app.main.data.modal :as modal]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.select :refer [select]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -37,7 +40,8 @@
::mf/register-as :share-link
::mf/wrap-props false}
[{:keys [file page]}]
(let [current-page page
(let [new-css-system (mf/use-ctx ctx/new-css-system)
current-page page
current-page-id (:id page)
slinks (mf/deref refs/share-links)
router (mf/deref refs/router)
@ -151,135 +155,284 @@
(fn [_]
(swap! perms-visible* not))
on-who-change
(fn [type event]
(let [target (dom/get-target event)
value (dom/get-value target)
value (keyword value)]
(reset! confirm* false)
(if (= type :comment)
(swap! options* assoc :who-comment (d/name value))
(swap! options* assoc :who-inspect (d/name value)))))]
on-inspect-change
(fn [value]
(reset! confirm* false)
(swap! options* assoc :who-inspect value))
on-comment-change
(fn [value]
(reset! confirm* false)
(swap! options* assoc :who-comment value))]
(if new-css-system
[:div {:class (stl/css :share-modal)}
[:div {:class (stl/css :share-link-dialog)}
[:div {:class (stl/css :share-link-header)}
[:h2 {:class (stl/css :share-link-title)}
(tr "common.share-link.title")]
[:button {:class (stl/css :modal-close-button)
:on-click on-close
:title (tr "labels.close")}
i/close-refactor]]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :share-link-section)}
(when (and (not confirm?) (some? current-link))
[:div {:class (stl/css :custon-input-wrapper)}
[:input {:class (stl/css :input-text)
:type "text"
:value (or current-link "")
:placeholder (tr "common.share-link.placeholder")
:read-only true}]
[:button {:class (stl/css :copy-button)
:title (tr "viewer.header.share.copy-link")
:on-click copy-link}
i/clipboard-refactor]])
[:div {:class (stl/css :hint-wrapper)}
(when (not ^boolean confirm?)
[:div {:class (stl/css :hint)} (tr "common.share-link.permissions-hint")])
(cond
(true? confirm?)
[:div {:class (stl/css :confirm-dialog)}
[:div {:class (stl/css :description)}
(tr "common.share-link.confirm-deletion-link-description")]
[:div {:class (stl/css :actions)}
[:input {:type "button"
:class (stl/css :button-cancel)
:on-click #(reset! confirm* false)
:value (tr "labels.cancel")}]
[:input {:type "button"
:class (stl/css :button-danger)
:on-click delete-link
:value (tr "common.share-link.destroy-link")}]]]
(some? current-link)
[:input
{:type "button"
:class (stl/css :button-danger)
:on-click try-delete-link
:value (tr "common.share-link.destroy-link")}]
:else
[:input
{:type "button"
:class (stl/css :button-active)
:on-click create-link
:value (tr "common.share-link.get-link")}])]]
[:div.modal-overlay.transparent.share-modal
[:div.modal-container.share-link-dialog
[:div.modal-content.initial
[:div.title
[:h2 (tr "common.share-link.title")]
[:div.modal-close-button
{:on-click on-close
:title (tr "labels.close")}
i/close]]]
[:div.modal-content
[:div.share-link-section
(when (and (not confirm?) (some? current-link))
[:div.custom-input.with-icon
[:input {:type "text"
:value (or current-link "")
:placeholder (tr "common.share-link.placeholder")
:read-only true}]
[:div.help-icon {:title (tr "viewer.header.share.copy-link")
:on-click copy-link}
i/copy]])
[:div.hint-wrapper
(when (not ^boolean confirm?)
[:div.hint (tr "common.share-link.permissions-hint")])
(cond
(true? confirm?)
[:div.confirm-dialog
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
[:div.actions
[:div {:class (stl/css :permissions-section)}
[:button {:class (stl/css :manage-permissions)
:on-click toggle-perms-visibility}
[:span {:class (stl/css-case :icon true
:rotated perms-visible?)}
i/arrow-refactor]
(tr "common.share-link.manage-ops")]
(when ^boolean perms-visible?
[:*
(let [all-selected? (:all-pages options)
pages (->> (get-in file [:data :pages])
(map #(get-in file [:data :pages-index %])))
selected (:pages options)]
[:div {:class (stl/css :view-mode)}
[:div {:class (stl/css :subtitle)}
(tr "common.share-link.permissions-pages")]
[:div {:class (stl/css :items)}
(if (= 1 (count pages))
[:div {:class (stl/css :checkbox-wrapper)}
[:input {:type "checkbox"
:id (dm/str "page-" current-page-id)
:data-page-id (dm/str current-page-id)
:on-change on-mark-checked-page
:checked true}]
[:label {:for (str "page-" current-page-id)} (:name current-page)]
[:span {:class (stl/css-case :checkobox-tick true
:global/checked true)}
i/status-tick-refactor]
[:span (str " " (tr "common.share-link.current-tag"))]]
[:*
[:div {:class (stl/css :select-all-row)}
[:div {:class (stl/css :checkbox-wrapper)}
[:label {:for "view-all"
:class (stl/css :select-all-label)}
[:span {:class (stl/css-case :global/checked all-selected?)}
(when all-selected?
i/status-tick-refactor)]
(tr "common.share-link.view-all")
[:input {:type "checkbox"
:id "view-all"
:checked all-selected?
:name "pages-mode"
:on-change on-toggle-all}]]]
[:span {:class (stl/css :count-pages)}
(tr "common.share-link.page-shared" (i18n/c (count selected)))]]
[:ul {:class (stl/css :pages-selection)}
(for [{:keys [id name]} pages]
[:li {:class (stl/css :checkbox-wrapper)
:key (dm/str id)}
[:label {:for (dm/str "page-" id)}
[:span {:class (stl/css-case :global/checked (contains? selected id))}
(when (contains? selected id)
i/status-tick-refactor)]
name
(when (= current-page-id id)
[:div {:class (stl/css :current-tag)} (dm/str " " (tr "common.share-link.current-tag"))])
[:input {:type "checkbox"
:id (dm/str "page-" id)
:data-page-id (dm/str id)
:on-change on-mark-checked-page
:checked (contains? selected id)}]]])]])]])
[:div {:class (stl/css :access-mode)}
[:div {:class (stl/css :subtitle)}
(tr "common.share-link.permissions-can-comment")]
[:div {:class (stl/css :items)}
[:& select
{:class (stl/css :who-comment-select)
:default-value (dm/str (:who-comment options))
:options [{:value "team" :label (tr "common.share-link.team-members")}
{:value "all" :label (tr "common.share-link.all-users")}]
:on-change on-comment-change}]]]
[:div {:class (stl/css :inspect-mode)}
[:div {:class (stl/css :subtitle)}
(tr "common.share-link.permissions-can-inspect")]
[:div {:class (stl/css :items)}
[:& select
{:class (stl/css :who-inspect-select)
:default-value (dm/str (:who-inspect options))
:options [{:value "team" :label (tr "common.share-link.team-members")}
{:value "all" :label (tr "common.share-link.all-users")}]
:on-change on-inspect-change}]]]])])]]]
;;OLD
[:div.modal-overlay.transparent.share-modal
[:div.modal-container.share-link-dialog
[:div.modal-content.initial
[:div.title
[:h2 (tr "common.share-link.title")]
[:div.modal-close-button
{:on-click on-close
:title (tr "labels.close")}
i/close]]]
[:div.modal-content
[:div.share-link-section
(when (and (not confirm?) (some? current-link))
[:div.custom-input.with-icon
[:input {:type "text"
:value (or current-link "")
:placeholder (tr "common.share-link.placeholder")
:read-only true}]
[:div.help-icon {:title (tr "viewer.header.share.copy-link")
:on-click copy-link}
i/copy]])
[:div.hint-wrapper
(when (not ^boolean confirm?)
[:div.hint (tr "common.share-link.permissions-hint")])
(cond
(true? confirm?)
[:div.confirm-dialog
[:div.description (tr "common.share-link.confirm-deletion-link-description")]
[:div.actions
[:input.btn-secondary
{:type "button"
:on-click #(reset! confirm* false)
:value (tr "labels.cancel")}]
[:input.btn-danger
{:type "button"
:on-click delete-link
:value (tr "common.share-link.destroy-link")}]]]
(some? current-link)
[:input.btn-secondary
{:type "button"
:on-click #(reset! confirm* false)
:value (tr "labels.cancel")}]
[:input.btn-danger
:class "primary"
:on-click try-delete-link
:value (tr "common.share-link.destroy-link")}]
:else
[:input.btn-primary
{:type "button"
:on-click delete-link
:value (tr "common.share-link.destroy-link")}]]]
(some? current-link)
[:input.btn-secondary
{:type "button"
:class "primary"
:on-click try-delete-link
:value (tr "common.share-link.destroy-link")}]
:else
[:input.btn-primary
{:type "button"
:class "primary"
:on-click create-link
:value (tr "common.share-link.get-link")}])]]]
[:div.modal-content.ops-section
[:div.manage-permissions
{:on-click toggle-perms-visibility}
[:span.icon i/picker-hsv]
[:div.title (tr "common.share-link.manage-ops")]]
(when ^boolean perms-visible?
[:*
(let [all-selected? (:all-pages options)
pages (->> (get-in file [:data :pages])
(map #(get-in file [:data :pages-index %])))
selected (:pages options)]
[:*
[:div.view-mode
[:div.subtitle
[:span.icon i/play]
(tr "common.share-link.permissions-pages")]
[:div.items
(if (= 1 (count pages))
[:div.input-checkbox.check-primary
[:input {:type "checkbox"
:id (dm/str "page-" current-page-id)
:data-page-id (dm/str current-page-id)
:on-change on-mark-checked-page
:checked true}]
[:label {:for (str "page-" current-page-id)} (:name current-page)]
[:span (str " " (tr "common.share-link.current-tag"))]]
[:*
[:div.row
:class "primary"
:on-click create-link
:value (tr "common.share-link.get-link")}])]]]
[:div.modal-content.ops-section
[:div.manage-permissions
{:on-click toggle-perms-visibility}
[:span.icon i/picker-hsv]
[:div.title (tr "common.share-link.manage-ops")]]
(when ^boolean perms-visible?
[:*
(let [all-selected? (:all-pages options)
pages (->> (get-in file [:data :pages])
(map #(get-in file [:data :pages-index %])))
selected (:pages options)]
[:*
[:div.view-mode
[:div.subtitle
[:span.icon i/play]
(tr "common.share-link.permissions-pages")]
[:div.items
(if (= 1 (count pages))
[:div.input-checkbox.check-primary
[:input {:type "checkbox"
:id "view-all"
:checked all-selected?
:name "pages-mode"
:on-change on-toggle-all}]
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
:id (dm/str "page-" current-page-id)
:data-page-id (dm/str current-page-id)
:on-change on-mark-checked-page
:checked true}]
[:label {:for (str "page-" current-page-id)} (:name current-page)]
[:span (str " " (tr "common.share-link.current-tag"))]]
[:ul.pages-selection
(for [{:keys [id name]} pages]
[:li.input-checkbox.check-primary {:key (dm/str id)}
[:*
[:div.row
[:div.input-checkbox.check-primary
[:input {:type "checkbox"
:id (dm/str "page-" id)
:data-page-id (dm/str id)
:on-change on-mark-checked-page
:checked (contains? selected id)}]
(if (= current-page-id id)
[:*
[:label {:for (dm/str "page-" id)} name]
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
[:label {:for (dm/str "page-" id)} name])])]])]]])
[:div.access-mode
[:div.subtitle
[:span.icon i/chat]
(tr "common.share-link.permissions-can-comment")]
[:div.items
[:select.input-select {:on-change (partial on-who-change :comment)
:value (:who-comment options)}
[:option {:value "team"} (tr "common.share-link.team-members")]
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
[:div.inspect-mode
[:div.subtitle
[:span.icon i/code]
(tr "common.share-link.permissions-can-inspect")]
[:div.items
[:select.input-select {:on-change (partial on-who-change :inspect)
:value (:who-inspect options)}
[:option {:value "team"} (tr "common.share-link.team-members")]
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))
:id "view-all"
:checked all-selected?
:name "pages-mode"
:on-change on-toggle-all}]
[:label {:for "view-all"} (tr "common.share-link.view-all")]]
[:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]]
[:ul.pages-selection
(for [{:keys [id name]} pages]
[:li.input-checkbox.check-primary {:key (dm/str id)}
[:input {:type "checkbox"
:id (dm/str "page-" id)
:data-page-id (dm/str id)
:on-change on-mark-checked-page
:checked (contains? selected id)}]
(if (= current-page-id id)
[:*
[:label {:for (dm/str "page-" id)} name]
[:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]]
[:label {:for (dm/str "page-" id)} name])])]])]]])
[:div.access-mode
[:div.subtitle
[:span.icon i/chat]
(tr "common.share-link.permissions-can-comment")]
[:div.items
[:select.input-select {:on-change on-comment-change
:value (:who-comment options)}
[:option {:value "team"} (tr "common.share-link.team-members")]
[:option {:value "all"} (tr "common.share-link.all-users")]]]]
[:div.inspect-mode
[:div.subtitle
[:span.icon i/code]
(tr "common.share-link.permissions-can-inspect")]
[:div.items
[:select.input-select {:on-change on-inspect-change
:value (:who-inspect options)}
[:option {:value "team"} (tr "common.share-link.team-members")]
[:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]])))

View 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;
}

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.thumbnails
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@ -13,6 +14,7 @@
[app.main.data.viewer :as dv]
[app.main.render :as render]
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -22,7 +24,8 @@
(mf/defc thumbnails-content
[{:keys [children expanded? total] :as props}]
(let [container (mf/use-ref)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
container (mf/use-ref)
width (mf/use-var (.. js/document -documentElement -clientWidth))
element-width (mf/use-var 152)
@ -56,45 +59,96 @@
(reset! width (obj/get dom "clientWidth"))))]
(mf/use-effect on-mount)
(if expanded?
[:div.thumbnails-content
[:div.thumbnails-list-expanded children]]
[:div.thumbnails-content
[:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide]
[:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide]
[:div.thumbnails-list {:ref container :on-wheel on-scroll}
[:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}}
children]]])))
(if new-css-system
(if expanded?
[:div {:class (stl/css :thumbnails-content)}
[:div {:class (stl/css :thumbnails-list-expanded)} children]]
[:div {:class (stl/css :thumbnails-content)}
[:button {:class (stl/css :left-scroll-handler)
:on-click on-left-arrow-click} i/arrow-refactor]
[:button {:class (stl/css :right-scroll-handler)
:on-click on-right-arrow-click} i/arrow-refactor]
[:div {:class (stl/css :thumbnails-list)
:ref container
:on-wheel on-scroll}
[:div {:class (stl/css :thumbnails-list-inside)
:style {:right (str (* @offset 152) "px")}}
children]]])
(if expanded?
[:div.thumbnails-content
[:div.thumbnails-list-expanded children]]
[:div.thumbnails-content
[:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide]
[:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide]
[:div.thumbnails-list {:ref container :on-wheel on-scroll}
[:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}}
children]]]))))
(mf/defc thumbnails-summary
[{:keys [on-toggle-expand on-close total] :as props}]
[:div.thumbnails-summary
[:span.counter (tr "labels.num-of-frames" (i18n/c total))]
[:span.buttons
[:span.btn-expand {:on-click on-toggle-expand} i/arrow-down]
[:span.btn-close {:on-click on-close} i/close]]])
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
(if new-css-system
[:div {:class (stl/css :thumbnails-summary)}
[:span {:class (stl/css :counter)}
(tr "labels.num-of-frames" (i18n/c total))]
[:span {:class (stl/css :actions)}
[:button {:class (stl/css :expand-btn)
:on-click on-toggle-expand} i/arrow-refactor]
[:button {:class (stl/css :close-btn)
:on-click on-close} i/close-refactor]]]
[:div.thumbnails-summary
[:span.counter (tr "labels.num-of-frames" (i18n/c total))]
[:span.buttons
[:span.btn-expand {:on-click on-toggle-expand} i/arrow-down]
[:span.btn-close {:on-click on-close} i/close]]])))
(mf/defc thumbnail-item
{::mf/wrap [mf/memo
#(mf/deferred % ts/idle-then-raf)]}
[{:keys [selected? frame on-click index objects page-id thumbnail-data]}]
(let [children-ids (cfh/get-children-ids objects (:id frame))
(let [new-css-system (mf/use-ctx ctx/new-css-system)
children-ids (cfh/get-children-ids objects (:id frame))
children-bounds (gsh/shapes->rect (concat [frame] (->> children-ids (keep (d/getf objects)))))]
[:div.thumbnail-item {:on-click #(on-click % index)}
[:div.thumbnail-preview
{:class (dom/classnames :selected selected?)}
[:& render/frame-svg {:frame (-> frame
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
(assoc :children-bounds children-bounds))
:objects objects
:use-thumbnails true}]]
[:div.thumbnail-info
[:span.name {:title (:name frame)} (:name frame)]]]))
(if new-css-system
[:button {:class (stl/css :thumbnail-item)
:on-click #(on-click % index)}
[:div {:class (stl/css-case :thumbnail-preview true
:selected selected?)}
[:& render/frame-svg {:frame (-> frame
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
(assoc :children-bounds children-bounds))
:objects objects
:use-thumbnails true}]]
[:div {:class (stl/css :thumbnail-info)
:title (:name frame)}
(:name frame)]]
[:div.thumbnail-item {:on-click #(on-click % index)}
[:div.thumbnail-preview
{:class (dom/classnames :selected selected?)}
[:& render/frame-svg {:frame (-> frame
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
(assoc :children-bounds children-bounds))
:objects objects
:use-thumbnails true}]]
[:div.thumbnail-info
[:span.name {:title (:name frame)} (:name frame)]]])))
(mf/defc thumbnails-panel
[{:keys [frames page index show? thumbnail-data] :as props}]
(let [expanded? (mf/use-state false)
(let [new-css-system (mf/use-ctx ctx/new-css-system)
expanded? (mf/use-state false)
container (mf/use-ref)
objects (:objects page)
@ -109,24 +163,48 @@
(st/emit! (dv/go-to-frame-by-index index))
(when @expanded?
(on-close))))]
(if new-css-system
[:section
{:class (stl/css-case :viewer-thumbnails true
:expanded @expanded?)
;; This is better as an inline-style so it won't make a reflow of every frame inside
:style {:display (when (not show?) "none")}
:ref container}
[:section.viewer-thumbnails
{;; This is better as an inline-style so it won't make a reflow of every frame inside
:style {:display (when (not show?) "none")}
:class (dom/classnames :expanded @expanded?)
:ref container}
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
:on-close on-close
:total (count frames)}]
[:& thumbnails-content {:expanded? @expanded?
:total (count frames)}
(for [[i frame] (d/enumerate frames)]
[:& thumbnail-item {:index i
:key (dm/str (:id frame) "-" i)
:frame frame
:page-id (:id page)
:objects objects
:on-click on-item-click
:selected? (= i index)
:thumbnail-data thumbnail-data}])]]
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
:on-close on-close
:total (count frames)}]
[:& thumbnails-content {:expanded? @expanded?
:total (count frames)}
(for [[i frame] (d/enumerate frames)]
[:& thumbnail-item {:index i
:key (dm/str (:id frame) "-" i)
:frame frame
:page-id (:id page)
:objects objects
:on-click on-item-click
:selected? (= i index)
:thumbnail-data thumbnail-data}])]]))
[:section.viewer-thumbnails
{;; This is better as an inline-style so it won't make a reflow of every frame inside
:style {:display (when (not show?) "none")}
:class (dom/classnames :expanded @expanded?)
:ref container}
[:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not)
:on-close on-close
:total (count frames)}]
[:& thumbnails-content {:expanded? @expanded?
:total (count frames)}
(for [[i frame] (d/enumerate frames)]
[:& thumbnail-item {:index i
:key (dm/str (:id frame) "-" i)
:frame frame
:page-id (:id page)
:objects objects
:on-click on-item-click
:selected? (= i index)
:thumbnail-data thumbnail-data}])]])))

View 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;
}

View file

@ -86,12 +86,10 @@
[:li {:class (dom/classnames :selected (= :pending cshow))
:on-click update-show}
[:span.icon i/tick]
[:span.label (tr "labels.hide-resolved-comments")]]])
))
[:span.label (tr "labels.hide-resolved-comments")]]])))
(mf/defc comments-sidebar
[{:keys [users threads page-id]}]
[{:keys [users threads page-id from-viewer]}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
threads-map (mf/deref refs/threads-ref)
profile (mf/deref refs/profile)
@ -111,8 +109,11 @@
close-section
(mf/use-fn
(mf/deps)
#(st/emit! :interrupt (dw/deselect-all true)))
(mf/deps from-viewer)
(fn []
(if from-viewer
(st/emit! (dcm/update-options {:show-sidebar? false}))
(st/emit! :interrupt (dw/deselect-all true)))))
tgroups (->> threads
(dcm/group-threads-by-page))
@ -121,7 +122,6 @@
toggle-mode-selector
(mf/use-fn
(mf/deps)
(fn [event]
(dom/stop-propagation event)
(swap! state* not)))
@ -147,18 +147,17 @@
:on-click close-section}
i/close-refactor]]
(when (seq tgroups)
[:button {:class (stl/css :mode-dropdown-wrapper)
:on-click toggle-mode-selector}
[:button {:class (stl/css :mode-dropdown-wrapper)
:on-click toggle-mode-selector}
[:span {:class (stl/css :mode-label)} (case (:mode local)
(nil :all) (tr "labels.show-all-comments")
:yours (tr "labels.show-your-comments"))]
[:div {:class (stl/css :icon)} i/arrow-refactor]]
[:span {:class (stl/css :mode-label)} (case (:mode local)
(nil :all) (tr "labels.show-all-comments")
:yours (tr "labels.show-your-comments"))]
[:div {:class (stl/css :icon)} i/arrow-refactor]]
[:& dropdown {:show options?
:on-close #(reset! state* false)}
[:& sidebar-options {:local local}]])
[:& dropdown {:show options?
:on-close #(reset! state* false)}
[:& sidebar-options {:local local}]]
[:div {:class (stl/css :comments-section-content)}

View file

@ -126,14 +126,14 @@
(tr "workspace.header.zoom-fit-all")
[:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :fit-all))]
[:span {:class (dom/classnames (stl/css :shortcut-key) true)
[:span {:class (stl/css :shortcut-key)
:key (str "zoom-fit-" sc)} sc])]]
[:li {:class (stl/css :zoom-option)
:on-click on-zoom-selected}
(tr "workspace.header.zoom-selected")
[:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :zoom-selected))]
[:span {:class (dom/classnames (stl/css :shortcut-key) true)
[:span {:class (stl/css :shortcut-key)
:key (str "zoom-selected-" sc)} sc])]]]]]))
;; --- Header Component

View file

@ -198,6 +198,7 @@
:checked (not hide-fill-on-export?)
:on-change on-change-show-fill-on-export}]]])])]
;; OLD
[:div.element-set
[:div.element-set-title
[:span label]

View file

@ -1637,6 +1637,9 @@ msgstr "Settings"
msgid "labels.share-prototype"
msgstr "Share prototype"
msgid "labels.share"
msgstr "Share"
#: src/app/main/ui/dashboard/sidebar.cljs
msgid "labels.shared-libraries"
msgstr "Libraries"

View file

@ -1673,6 +1673,9 @@ msgstr "Configuración"
msgid "labels.share-prototype"
msgstr "Compartir prototipo"
msgid "labels.share"
msgstr "Compartir"
#: src/app/main/ui/dashboard/sidebar.cljs
msgid "labels.shared-libraries"
msgstr "Bibliotecas"