mirror of
https://github.com/penpot/penpot.git
synced 2025-05-10 12:26:37 +02:00
✨ Add new zoom options in workspace and viewer mode
This commit is contained in:
parent
d33542c4dc
commit
4285972e41
14 changed files with 407 additions and 288 deletions
|
@ -33,15 +33,62 @@
|
|||
display: flex;
|
||||
padding: $size-2;
|
||||
|
||||
&.separator {
|
||||
border-top: 1px solid $color-gray-10;
|
||||
padding: 0px;
|
||||
margin: 2px;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&.basic-zoom-bar {
|
||||
cursor: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: $color-gray-20;
|
||||
font-size: $fs14;
|
||||
margin-left: auto;
|
||||
|
||||
&.zoom-btns {
|
||||
display: flex;
|
||||
margin-left: 2px;
|
||||
color: $color-gray-60;
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
font-size: $fs14;
|
||||
padding: 0 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-primary-lighter;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
background-color: $color-white;
|
||||
border: none;
|
||||
&:hover {
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
.reset-btn {
|
||||
color: $color-primary-dark;
|
||||
}
|
||||
.zoom-size {
|
||||
min-width: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
(def ^:private
|
||||
default-local-state
|
||||
{:zoom 1
|
||||
:fullscreen? false
|
||||
:interactions-mode :hide
|
||||
:interactions-show? false
|
||||
:comments-mode :all
|
||||
|
@ -209,17 +210,57 @@
|
|||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :zoom] 1))))
|
||||
|
||||
(def zoom-to-50
|
||||
(ptk/reify ::zoom-to-50
|
||||
(def zoom-to-fit
|
||||
(ptk/reify ::zoom-to-fit
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :zoom] 0.5))))
|
||||
(let [page-id (get-in state [:route :query-params :page-id])
|
||||
frame-idx (get-in state [:route :query-params :index])
|
||||
srect (get (nth (get-in state [:viewer :pages page-id :frames]) frame-idx) :selrect)
|
||||
original-size (get-in state [:viewer-local :viewport-size])
|
||||
wdiff (/ (:width original-size) (:width srect))
|
||||
hdiff (/ (:height original-size) (:height srect))
|
||||
minzoom (min wdiff hdiff)]
|
||||
(-> state
|
||||
(assoc-in [:viewer-local :zoom] minzoom)
|
||||
(assoc-in [:viewer-local :zoom-type] :fit))))))
|
||||
|
||||
(def zoom-to-200
|
||||
(ptk/reify ::zoom-to-200
|
||||
(def zoom-to-fill
|
||||
(ptk/reify ::zoom-to-fill
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :zoom] 2))))
|
||||
(let [page-id (get-in state [:route :query-params :page-id])
|
||||
frame-idx (get-in state [:route :query-params :index])
|
||||
srect (get (nth (get-in state [:viewer :pages page-id :frames]) frame-idx) :selrect)
|
||||
original-size (get-in state [:viewer-local :viewport-size])
|
||||
wdiff (/ (:width original-size) (:width srect))
|
||||
hdiff (/ (:height original-size) (:height srect))
|
||||
maxzoom (max wdiff hdiff)]
|
||||
(-> state
|
||||
(assoc-in [:viewer-local :zoom] maxzoom)
|
||||
(assoc-in [:viewer-local :zoom-type] :fill))))))
|
||||
|
||||
(def toggle-zoom-style
|
||||
(ptk/reify ::toggle-zoom-style
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [zoom-type (get-in state [:viewer-local :zoom-type])]
|
||||
(if (= zoom-type :fit)
|
||||
(rx/of zoom-to-fill)
|
||||
(rx/of zoom-to-fit))))))
|
||||
|
||||
(def toggle-fullscreen
|
||||
(ptk/reify ::toggle-fullscreen
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:viewer-local :fullscreen?] not))))
|
||||
|
||||
(defn set-viewport-size
|
||||
[{:keys [size]}]
|
||||
(ptk/reify ::set-viewport-size
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:viewer-local :viewport-size] size))))
|
||||
|
||||
;; --- Local State Management
|
||||
|
||||
|
@ -408,7 +449,7 @@
|
|||
[state frame position close-click-outside background-overlay animation]
|
||||
(cond-> state
|
||||
:always
|
||||
(update-in [:viewer-local :overlays] conj
|
||||
(update-in [:viewer-local :overlays] conj
|
||||
{:frame frame
|
||||
:position position
|
||||
:close-click-outside close-click-outside
|
||||
|
@ -588,14 +629,14 @@
|
|||
(assoc-in state [:viewer-local :overlays] []))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
pparams (:path-params route)
|
||||
qparams (-> (:query-params route)
|
||||
(assoc :index 0)
|
||||
(assoc :page-id page-id))
|
||||
rname (get-in route [:data :name])]
|
||||
(rx/of (rt/nav rname pparams qparams))))))
|
||||
(watch [_ state _]
|
||||
(let [route (:route state)
|
||||
pparams (:path-params route)
|
||||
qparams (-> (:query-params route)
|
||||
(assoc :index 0)
|
||||
(assoc :page-id page-id))
|
||||
rname (get-in route [:data :name])]
|
||||
(rx/of (rt/nav rname pparams qparams))))))
|
||||
|
||||
(defn go-to-workspace
|
||||
([] (go-to-workspace nil))
|
||||
|
|
|
@ -23,17 +23,17 @@
|
|||
:command (ds/c-mod "a")
|
||||
:fn (st/emitf (dv/select-all))}
|
||||
|
||||
:zoom-50 {:tooltip (ds/shift "0")
|
||||
:reset-zoom {:tooltip (ds/shift "0")
|
||||
:command "shift+0"
|
||||
:fn (st/emitf dv/zoom-to-50)}
|
||||
|
||||
:reset-zoom {:tooltip (ds/shift "1")
|
||||
:command "shift+1"
|
||||
:fn (st/emitf dv/reset-zoom)}
|
||||
|
||||
:zoom-200 {:tooltip (ds/shift "2")
|
||||
:command "shift+2"
|
||||
:fn (st/emitf dv/zoom-to-200)}
|
||||
:toggle-zoom-style {:tooltip "F"
|
||||
:command "f"
|
||||
:fn (st/emitf dv/toggle-zoom-style)}
|
||||
|
||||
:toogle-fullscreen {:tooltip (ds/shift "F")
|
||||
:command "shift+f"
|
||||
:fn (st/emitf dv/toggle-fullscreen)}
|
||||
|
||||
:next-frame {:tooltip ds/left-arrow
|
||||
:command "left"
|
||||
|
|
|
@ -263,7 +263,7 @@
|
|||
(when-not (contains? (get-in state [:workspace-data :pages-index]) page-id)
|
||||
(let [default-page-id (get-in state [:workspace-data :pages 0])]
|
||||
(rx/of (go-to-page default-page-id)))))
|
||||
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [;; we maintain a cache of page state for user convenience
|
||||
|
@ -455,7 +455,7 @@
|
|||
:y (+ (:y srect) (/ (- (:height srect) height) 2)))))))
|
||||
|
||||
(setup [state local]
|
||||
(if (and (:vport local) (:vbox local))
|
||||
(if (and (:vbox local) (:vport local))
|
||||
(update* local)
|
||||
(initialize state local)))]
|
||||
|
||||
|
@ -755,7 +755,7 @@
|
|||
:shapes [id]}))
|
||||
selected)
|
||||
|
||||
uchanges (mapv (fn [id]
|
||||
uchanges (mapv (fn [id]
|
||||
(let [obj (get objects id)]
|
||||
{:type :mov-objects
|
||||
:parent-id (:parent-id obj)
|
||||
|
@ -763,7 +763,7 @@
|
|||
:page-id page-id
|
||||
:shapes [id]
|
||||
:index (cp/position-on-parent id objects)}))
|
||||
selected)]
|
||||
selected)]
|
||||
;; TODO: maybe missing the :reg-objects event?
|
||||
(rx/of (dch/commit-changes {:redo-changes rchanges
|
||||
:undo-changes uchanges
|
||||
|
@ -1223,15 +1223,15 @@
|
|||
(ptk/reify ::toggle-propotion-lock
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
selected (wsh/lookup-selected state)
|
||||
selected-obj (-> (map #(get objects %) selected))
|
||||
multi (attrs/get-attrs-multi selected-obj [:proportion-lock])
|
||||
multi? (= :multiple (:proportion-lock multi))]
|
||||
(if multi?
|
||||
(rx/of (dch/update-shapes selected #(assoc % :proportion-lock true)))
|
||||
(rx/of (dch/update-shapes selected #(update % :proportion-lock not))))))))
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
selected (wsh/lookup-selected state)
|
||||
selected-obj (-> (map #(get objects %) selected))
|
||||
multi (attrs/get-attrs-multi selected-obj [:proportion-lock])
|
||||
multi? (= :multiple (:proportion-lock multi))]
|
||||
(if multi?
|
||||
(rx/of (dch/update-shapes selected #(assoc % :proportion-lock true)))
|
||||
(rx/of (dch/update-shapes selected #(update % :proportion-lock not))))))))
|
||||
|
||||
;; --- Update Shape Flags
|
||||
|
||||
|
@ -1256,8 +1256,8 @@
|
|||
(ptk/reify ::toggle-visibility-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(rx/of (dch/update-shapes selected #(update % :hidden not)))))))
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(rx/of (dch/update-shapes selected #(update % :hidden not)))))))
|
||||
|
||||
(defn toggle-lock-selected
|
||||
[]
|
||||
|
@ -1417,12 +1417,12 @@
|
|||
|
||||
(defn go-to-dashboard-fonts
|
||||
[]
|
||||
(ptk/reify ::go-to-dashboard-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of ::dwp/force-persist
|
||||
(rt/nav :dashboard-fonts {:team-id team-id}))))))
|
||||
(ptk/reify ::go-to-dashboard-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of ::dwp/force-persist
|
||||
(rt/nav :dashboard-fonts {:team-id team-id}))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Context Menu
|
||||
|
@ -1601,9 +1601,9 @@
|
|||
paste-image-str)
|
||||
(rx/first)
|
||||
(rx/catch
|
||||
(fn [err]
|
||||
(js/console.error "Clipboard error:" err)
|
||||
(rx/empty)))))
|
||||
(fn [err]
|
||||
(js/console.error "Clipboard error:" err)
|
||||
(rx/empty)))))
|
||||
(catch :default e
|
||||
(let [data (ex-data e)]
|
||||
(if (:not-implemented data)
|
||||
|
@ -1760,7 +1760,7 @@
|
|||
|
||||
(cond->
|
||||
;; if foreign instance, detach the shape
|
||||
(foreign-instance? shape paste-objects state)
|
||||
(foreign-instance? shape paste-objects state)
|
||||
(dissoc :component-id
|
||||
:component-file
|
||||
:component-root?
|
||||
|
@ -1933,10 +1933,10 @@
|
|||
(assoc :frame-id frame-id)
|
||||
(gsh/setup-selrect))]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction)
|
||||
(dwc/add-shape shape)
|
||||
(dwc/move-shapes-into-frame (:id shape) selected)
|
||||
(dwu/commit-undo-transaction))))))))
|
||||
(dwu/start-undo-transaction)
|
||||
(dwc/add-shape shape)
|
||||
(dwc/move-shapes-into-frame (:id shape) selected)
|
||||
(dwu/commit-undo-transaction))))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -322,3 +322,7 @@
|
|||
(def users
|
||||
(l/derived :users st/state))
|
||||
|
||||
(def fullscreen?
|
||||
(l/derived (fn [state]
|
||||
(get-in state [:viewer-local :fullscreen?] []))
|
||||
st/state))
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.ui.auth :refer [auth]]
|
||||
[app.main.ui.auth.verify-token :refer [verify-token]]
|
||||
[app.main.ui.components.fullscreen :as fs]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.cursors :as c]
|
||||
[app.main.ui.dashboard :refer [dashboard]]
|
||||
|
@ -62,8 +61,7 @@
|
|||
[:h1 "Cursors"]
|
||||
[:& c/debug-preview]
|
||||
[:h1 "Icons"]
|
||||
[:& i/debug-icons-preview]
|
||||
])
|
||||
[:& i/debug-icons-preview]])
|
||||
|
||||
(:dashboard-search
|
||||
:dashboard-projects
|
||||
|
@ -78,8 +76,7 @@
|
|||
#_[:div.modal-wrapper
|
||||
#_[:& app.main.ui.onboarding/onboarding-templates-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-modal]
|
||||
#_[:& app.main.ui.onboarding/onboarding-team-modal]
|
||||
]
|
||||
#_[:& app.main.ui.onboarding/onboarding-team-modal]]
|
||||
(when-let [props (some-> profile (get :props {}))]
|
||||
(cond
|
||||
(and cf/onboarding-form-id
|
||||
|
@ -104,14 +101,13 @@
|
|||
(let [{:keys [query-params path-params]} route
|
||||
{:keys [index share-id section page-id] :or {section :interactions}} query-params
|
||||
{:keys [file-id]} path-params]
|
||||
[:& fs/fullscreen-wrapper {}
|
||||
(if (:token query-params)
|
||||
[:& viewer/breaking-change-notice]
|
||||
[:& viewer/viewer-page {:page-id page-id
|
||||
:file-id file-id
|
||||
:section section
|
||||
:index index
|
||||
:share-id share-id}])])
|
||||
(if (:token query-params)
|
||||
[:& viewer/breaking-change-notice]
|
||||
[:& viewer/viewer-page {:page-id page-id
|
||||
:file-id file-id
|
||||
:section section
|
||||
:index index
|
||||
:share-id share-id}]))
|
||||
|
||||
:render-object
|
||||
(do
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
;; 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) UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.components.fullscreen
|
||||
(:require
|
||||
[app.util.dom :as dom]
|
||||
[app.util.webapi :as wapi]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(def fullscreen-context
|
||||
(mf/create-context))
|
||||
|
||||
(mf/defc fullscreen-wrapper
|
||||
[{:keys [children] :as props}]
|
||||
(let [container (mf/use-ref)
|
||||
state (mf/use-state (dom/fullscreen?))
|
||||
|
||||
change
|
||||
(mf/use-callback
|
||||
(fn [_]
|
||||
(let [val (dom/fullscreen?)]
|
||||
(reset! state val))))
|
||||
|
||||
manager
|
||||
(mf/use-memo
|
||||
(mf/deps @state)
|
||||
(fn []
|
||||
(specify! state
|
||||
cljs.core/IFn
|
||||
(-invoke
|
||||
([_ val]
|
||||
(if val
|
||||
(wapi/request-fullscreen (mf/ref-val container))
|
||||
(wapi/exit-fullscreen)))))))]
|
||||
|
||||
;; NOTE: the user interaction with F11 keyboard hot-key does not
|
||||
;; emits the `fullscreenchange` event; that event is emitted only
|
||||
;; when API is used. There are no way to detect the F11 behavior
|
||||
;; in a uniform cross browser way.
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
(.addEventListener js/document "fullscreenchange" change)
|
||||
(fn []
|
||||
(.removeEventListener js/document "fullscreenchange" change))))
|
||||
|
||||
[:div.fullscreen-wrapper {:ref container :class (dom/classnames :fullscreen @state)}
|
||||
[:& (mf/provider fullscreen-context) {:value manager}
|
||||
children]]))
|
||||
|
|
@ -91,9 +91,9 @@
|
|||
(fn []
|
||||
(some-> (:subscr @state) rx/unsub!)
|
||||
(swap! state (fn [state]
|
||||
(-> state
|
||||
(cancel-timer)
|
||||
(dissoc :over :subscr)))))
|
||||
(-> state
|
||||
(cancel-timer)
|
||||
(dissoc :over :subscr)))))
|
||||
|
||||
subscribe-to-drag-end
|
||||
(fn []
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
[app.main.ui.viewer.thumbnails :refer [thumbnails-panel]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.webapi :as wapi]
|
||||
[goog.events :as events]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
|
@ -72,7 +73,7 @@
|
|||
zoom (:zoom local)
|
||||
frames (:frames page)
|
||||
frame (get frames index)
|
||||
|
||||
fullscreen? (mf/deref refs/fullscreen?)
|
||||
overlays (:overlays local)
|
||||
|
||||
orig-frame
|
||||
|
@ -84,12 +85,12 @@
|
|||
(fn [] (calculate-size frame zoom)))
|
||||
|
||||
orig-size (mf/use-memo
|
||||
(mf/deps orig-frame zoom)
|
||||
(fn [] (when orig-frame (calculate-size orig-frame zoom))))
|
||||
(mf/deps orig-frame zoom)
|
||||
(fn [] (when orig-frame (calculate-size orig-frame zoom))))
|
||||
|
||||
wrapper-size (mf/use-memo
|
||||
(mf/deps size orig-size zoom)
|
||||
(fn [] (calculate-wrapper size orig-size zoom)))
|
||||
(mf/deps size orig-size zoom)
|
||||
(fn [] (calculate-wrapper size orig-size zoom)))
|
||||
|
||||
interactions-mode
|
||||
(:interactions-mode local)
|
||||
|
@ -103,8 +104,15 @@
|
|||
|
||||
close-overlay
|
||||
(mf/use-callback
|
||||
(fn [frame]
|
||||
(st/emit! (dv/close-overlay (:id frame)))))]
|
||||
(fn [frame]
|
||||
(st/emit! (dv/close-overlay (:id frame)))))
|
||||
|
||||
set-up-new-size
|
||||
(mf/use-callback
|
||||
(fn [_]
|
||||
(let [viewer-section (dom/get-element "viewer-section")
|
||||
size (dom/get-client-size viewer-section)]
|
||||
(st/emit! (dv/set-viewport-size {:size size})))))]
|
||||
|
||||
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
||||
|
||||
|
@ -125,73 +133,92 @@
|
|||
(events/unlistenByKey key1)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps nav-scroll)
|
||||
(fn []
|
||||
;; Set scroll position after navigate
|
||||
(when (number? nav-scroll)
|
||||
(let [viewer-section (dom/get-element "viewer-section")]
|
||||
(st/emit! (dv/reset-nav-scroll))
|
||||
(dom/set-scroll-pos! viewer-section nav-scroll)))))
|
||||
(fn []
|
||||
(set-up-new-size)
|
||||
(.addEventListener js/window "resize" set-up-new-size)
|
||||
(fn []
|
||||
(.removeEventListener js/window "resize" set-up-new-size))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps index)
|
||||
(fn []
|
||||
(mf/deps nav-scroll)
|
||||
(fn []
|
||||
;; Set scroll position after navigate
|
||||
(when (number? nav-scroll)
|
||||
(let [viewer-section (dom/get-element "viewer-section")]
|
||||
(st/emit! (dv/reset-nav-scroll))
|
||||
(dom/set-scroll-pos! viewer-section nav-scroll)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps fullscreen?)
|
||||
(fn []
|
||||
;; Trigger dom fullscreen depending on our state
|
||||
(let [wrapper (dom/get-element "viewer-layout")
|
||||
fullscreen-dom? (dom/fullscreen?)]
|
||||
(when (not= fullscreen? fullscreen-dom?)
|
||||
(if fullscreen?
|
||||
(wapi/request-fullscreen wrapper)
|
||||
(wapi/exit-fullscreen))))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps index)
|
||||
(fn []
|
||||
;; Navigate animation needs to be started after navigation
|
||||
;; is complete, and we have the next page index.
|
||||
(when (and current-animation
|
||||
(= (:kind current-animation) :go-to-frame))
|
||||
(let [orig-viewport (mf/ref-val orig-viewport-ref)
|
||||
current-viewport (mf/ref-val current-viewport-ref)]
|
||||
(interactions/animate-go-to-frame
|
||||
(:animation current-animation)
|
||||
current-viewport
|
||||
orig-viewport
|
||||
size
|
||||
orig-size
|
||||
wrapper-size)))))
|
||||
(when (and current-animation
|
||||
(= (:kind current-animation) :go-to-frame))
|
||||
(let [orig-viewport (mf/ref-val orig-viewport-ref)
|
||||
current-viewport (mf/ref-val current-viewport-ref)]
|
||||
(interactions/animate-go-to-frame
|
||||
(:animation current-animation)
|
||||
current-viewport
|
||||
orig-viewport
|
||||
size
|
||||
orig-size
|
||||
wrapper-size)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps current-animation)
|
||||
(fn []
|
||||
(mf/deps current-animation)
|
||||
(fn []
|
||||
;; Overlay animations may be started when needed.
|
||||
(when current-animation
|
||||
(case (:kind current-animation)
|
||||
(when current-animation
|
||||
(case (:kind current-animation)
|
||||
|
||||
:open-overlay
|
||||
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
|
||||
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
|
||||
overlays)
|
||||
overlay-size (calculate-size (:frame overlay) zoom)
|
||||
overlay-position {:x (* (:x (:position overlay)) zoom)
|
||||
:y (* (:y (:position overlay)) zoom)}]
|
||||
(interactions/animate-open-overlay
|
||||
(:animation current-animation)
|
||||
overlay-viewport
|
||||
wrapper-size
|
||||
overlay-size
|
||||
overlay-position))
|
||||
:open-overlay
|
||||
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
|
||||
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
|
||||
overlays)
|
||||
overlay-size (calculate-size (:frame overlay) zoom)
|
||||
overlay-position {:x (* (:x (:position overlay)) zoom)
|
||||
:y (* (:y (:position overlay)) zoom)}]
|
||||
(interactions/animate-open-overlay
|
||||
(:animation current-animation)
|
||||
overlay-viewport
|
||||
wrapper-size
|
||||
overlay-size
|
||||
overlay-position))
|
||||
|
||||
:close-overlay
|
||||
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
|
||||
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
|
||||
overlays)
|
||||
overlay-size (calculate-size (:frame overlay) zoom)
|
||||
overlay-position {:x (* (:x (:position overlay)) zoom)
|
||||
:y (* (:y (:position overlay)) zoom)}]
|
||||
(interactions/animate-close-overlay
|
||||
(:animation current-animation)
|
||||
overlay-viewport
|
||||
wrapper-size
|
||||
overlay-size
|
||||
overlay-position
|
||||
(:id (:frame overlay))))
|
||||
:close-overlay
|
||||
(let [overlay-viewport (dom/get-element (str "overlay-" (str (:overlay-id current-animation))))
|
||||
overlay (d/seek #(= (:id (:frame %)) (:overlay-id current-animation))
|
||||
overlays)
|
||||
overlay-size (calculate-size (:frame overlay) zoom)
|
||||
overlay-position {:x (* (:x (:position overlay)) zoom)
|
||||
:y (* (:y (:position overlay)) zoom)}]
|
||||
(interactions/animate-close-overlay
|
||||
(:animation current-animation)
|
||||
overlay-viewport
|
||||
wrapper-size
|
||||
overlay-size
|
||||
overlay-position
|
||||
(:id (:frame overlay))))
|
||||
|
||||
nil))))
|
||||
nil))))
|
||||
|
||||
[:div {:class (dom/classnames
|
||||
:force-visible (:show-thumbnails local)
|
||||
:viewer-layout (not= section :handoff)
|
||||
:handoff-layout (= section :handoff))}
|
||||
[:div#viewer-layout {:class (dom/classnames
|
||||
:force-visible (:show-thumbnails local)
|
||||
:viewer-layout (not= section :handoff)
|
||||
:handoff-layout (= section :handoff)
|
||||
:fullscreen fullscreen?)}
|
||||
|
||||
[:& header {:project project
|
||||
:index index
|
||||
|
@ -273,7 +300,7 @@
|
|||
(:background-overlay overlay))
|
||||
[:div.viewer-overlay-background
|
||||
{:class (dom/classnames
|
||||
:visible (:background-overlay overlay))
|
||||
:visible (:background-overlay overlay))
|
||||
:style {:width (:width wrapper-size)
|
||||
:height (:height wrapper-size)
|
||||
:position "absolute"
|
||||
|
|
|
@ -6,29 +6,65 @@
|
|||
|
||||
(ns app.main.ui.viewer.header
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.data.viewer.shortcuts :as sc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.components.fullscreen :as fs]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.viewer.comments :refer [comments-menu]]
|
||||
[app.main.ui.viewer.interactions :refer [flows-menu interactions-menu]]
|
||||
[app.main.ui.workspace.header :refer [zoom-widget]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc zoom-widget
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [zoom
|
||||
on-increase
|
||||
on-decrease
|
||||
on-zoom-reset
|
||||
on-fullscreen
|
||||
on-zoom-fit
|
||||
on-zoom-fill]
|
||||
:as props}]
|
||||
(let [show-dropdown? (mf/use-state false)]
|
||||
[:div.zoom-widget {:on-click #(reset! show-dropdown? true)}
|
||||
[:span.label {} (str (mth/round (* 100 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 {} (str (mth/round (* 100 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 :toogle-fullscreen)]]]]]))
|
||||
|
||||
|
||||
(mf/defc header-options
|
||||
[{:keys [section zoom page file index permissions]}]
|
||||
(let [fullscreen (mf/use-ctx fs/fullscreen-context)
|
||||
(let [fullscreen? (mf/deref refs/fullscreen?)
|
||||
|
||||
toggle-fullscreen
|
||||
(mf/use-callback
|
||||
(mf/deps fullscreen)
|
||||
(fn []
|
||||
(if @fullscreen (fullscreen false) (fullscreen true))))
|
||||
(fn [] (st/emit! dv/toggle-fullscreen)))
|
||||
|
||||
go-to-workspace
|
||||
(mf/use-callback
|
||||
|
@ -56,15 +92,15 @@
|
|||
{:zoom zoom
|
||||
:on-increase (st/emitf dv/increase-zoom)
|
||||
:on-decrease (st/emitf dv/decrease-zoom)
|
||||
:on-zoom-to-50 (st/emitf dv/zoom-to-50)
|
||||
:on-zoom-to-100 (st/emitf dv/reset-zoom)
|
||||
:on-zoom-to-200 (st/emitf dv/zoom-to-200)
|
||||
:on-zoom-reset (st/emitf dv/reset-zoom)
|
||||
:on-zoom-fill (st/emitf dv/zoom-to-fill)
|
||||
:on-zoom-fit (st/emitf dv/zoom-to-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
|
||||
(if fullscreen?
|
||||
i/full-screen-off
|
||||
i/full-screen)]
|
||||
|
||||
|
@ -104,31 +140,31 @@
|
|||
(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 "/"]
|
||||
[: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]
|
||||
[:span.icon i/arrow-down]
|
||||
[:span.page-name page-name]
|
||||
[:span.icon i/arrow-down]
|
||||
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close close-dropdown}
|
||||
[:ul.dropdown
|
||||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:id (str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
(get-in file [:data :pages-index id :name])])]]]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close close-dropdown}
|
||||
[:ul.dropdown
|
||||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:id (str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
(get-in file [:data :pages-index id :name])])]]]
|
||||
|
||||
[:div.current-frame
|
||||
{:on-click toggle-thumbnails}
|
||||
[:span.label "/"]
|
||||
[:span.label frame-name]
|
||||
[:span.icon i/arrow-down]
|
||||
[:span.counters (str (inc index) " / " total)]]]))
|
||||
[:div.current-frame
|
||||
{:on-click toggle-thumbnails}
|
||||
[:span.label "/"]
|
||||
[:span.label frame-name]
|
||||
[:span.icon i/arrow-down]
|
||||
[:span.counters (str (inc index) " / " total)]]]))
|
||||
|
||||
|
||||
(mf/defc header
|
||||
|
|
|
@ -57,16 +57,14 @@
|
|||
[:span.icon i/msg-warning]
|
||||
[:span.label (tr "workspace.header.save-error")]])]))
|
||||
|
||||
|
||||
(mf/defc zoom-widget
|
||||
(mf/defc zoom-widget-workspace
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [zoom
|
||||
on-increase
|
||||
on-decrease
|
||||
on-zoom-reset
|
||||
on-zoom-fit
|
||||
on-zoom-selected
|
||||
on-fullscreen]
|
||||
on-zoom-selected]
|
||||
:as props}]
|
||||
(let [show-dropdown? (mf/use-state false)]
|
||||
[:div.zoom-widget {:on-click #(reset! show-dropdown? true)}
|
||||
|
@ -75,19 +73,24 @@
|
|||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close #(reset! show-dropdown? false)}
|
||||
[:ul.dropdown
|
||||
[:li {:on-click on-increase}
|
||||
"Zoom in" [:span (sc/get-tooltip :increase-zoom)]]
|
||||
[:li {:on-click on-decrease}
|
||||
"Zoom out" [:span (sc/get-tooltip :decrease-zoom)]]
|
||||
[:li {:on-click on-zoom-reset}
|
||||
"Zoom to 100%" [:span (sc/get-tooltip :reset-zoom)]]
|
||||
[: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 {} (str (mth/round (* 100 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}
|
||||
"Zoom to fit all" [:span (sc/get-tooltip :fit-all)]]
|
||||
(tr "workspace.header.zoom-fit-all") [:span (sc/get-tooltip :fit-all)]]
|
||||
[:li {:on-click on-zoom-selected}
|
||||
"Zoom to selected" [:span (sc/get-tooltip :zoom-selected)]]
|
||||
(when on-fullscreen
|
||||
[:li {:on-click on-fullscreen}
|
||||
"Full screen"])]]]))
|
||||
(tr "workspace.header.zoom-selected") [:span (sc/get-tooltip :zoom-selected)]]]]]))
|
||||
|
||||
|
||||
|
||||
;; --- Header Users
|
||||
|
@ -166,24 +169,24 @@
|
|||
|
||||
on-export-frames
|
||||
(mf/use-callback
|
||||
(mf/deps file frames)
|
||||
(fn [_]
|
||||
(when (seq frames)
|
||||
(let [filename (str (:name file) ".pdf")
|
||||
frame-ids (mapv :id frames)]
|
||||
(st/emit! (dm/info (tr "workspace.options.exporting-object")
|
||||
{:timeout nil}))
|
||||
(->> (rp/query! :export-frames
|
||||
{:name (:name file)
|
||||
:file-id (:id file)
|
||||
:page-id page-id
|
||||
:frame-ids frame-ids})
|
||||
(rx/subs
|
||||
(fn [body]
|
||||
(dom/trigger-download filename body))
|
||||
(fn [_error]
|
||||
(st/emit! (dm/error (tr "errors.unexpected-error"))))
|
||||
(st/emitf dm/hide)))))))]
|
||||
(mf/deps file frames)
|
||||
(fn [_]
|
||||
(when (seq frames)
|
||||
(let [filename (str (:name file) ".pdf")
|
||||
frame-ids (mapv :id frames)]
|
||||
(st/emit! (dm/info (tr "workspace.options.exporting-object")
|
||||
{:timeout nil}))
|
||||
(->> (rp/query! :export-frames
|
||||
{:name (:name file)
|
||||
:file-id (:id file)
|
||||
:page-id page-id
|
||||
:frame-ids frame-ids})
|
||||
(rx/subs
|
||||
(fn [body]
|
||||
(dom/trigger-download filename body))
|
||||
(fn [_error]
|
||||
(st/emit! (dm/error (tr "errors.unexpected-error"))))
|
||||
(st/emitf dm/hide)))))))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps @editing?)
|
||||
|
@ -289,9 +292,7 @@
|
|||
|
||||
(when (contains? @cf/flags :user-feedback)
|
||||
[:li.feedback {:on-click (st/emitf (rt/nav :settings-feedback))}
|
||||
[:span (tr "labels.give-feedback")]])
|
||||
|
||||
]]]))
|
||||
[:span (tr "labels.give-feedback")]])]]]))
|
||||
|
||||
;; --- Header Component
|
||||
|
||||
|
@ -327,7 +328,7 @@
|
|||
[:div.options-section
|
||||
[:& persistence-state-widget]
|
||||
|
||||
[:& zoom-widget
|
||||
[:& zoom-widget-workspace
|
||||
{:zoom zoom
|
||||
:on-increase #(st/emit! (dw/increase-zoom nil))
|
||||
:on-decrease #(st/emit! (dw/decrease-zoom nil))
|
||||
|
|
|
@ -2087,6 +2087,30 @@ msgstr "Saving"
|
|||
msgid "workspace.header.unsaved"
|
||||
msgstr "Unsaved changes"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.reset-zoom"
|
||||
msgstr "Reset"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fit-all"
|
||||
msgstr "Zoom to fil all"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-selected"
|
||||
msgstr "Zoom to selected"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fit"
|
||||
msgstr "Fit - Scale down to fit"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fill"
|
||||
msgstr "Fill -Scale to fill"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-full-screen"
|
||||
msgstr "Full screen"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.viewer"
|
||||
msgstr "View mode (%s)"
|
||||
|
|
|
@ -2102,6 +2102,30 @@ msgstr "Guardando"
|
|||
msgid "workspace.header.unsaved"
|
||||
msgstr "Cambios sin guardar"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.reset-zoom"
|
||||
msgstr "Restablecer"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fit-all"
|
||||
msgstr "Zoom abarcar todo"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-selected"
|
||||
msgstr "Zoom a selección"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fit"
|
||||
msgstr "Escalar para ajustar"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-fill"
|
||||
msgstr "Escalar para rellenar"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.zoom-full-screen"
|
||||
msgstr "Pantalla completa"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs
|
||||
msgid "workspace.header.viewer"
|
||||
msgstr "Modo de visualización (%s)"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue