0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-24 13:41:39 -05:00

Add new zoom options in workspace and viewer mode

This commit is contained in:
Eva 2022-01-12 14:45:58 +01:00 committed by Andrés Moya
parent d33542c4dc
commit 4285972e41
14 changed files with 407 additions and 288 deletions

View file

@ -3,8 +3,10 @@
## :rocket: Next
### :boom: Breaking changes
### :sparkles: New features
- Add new options for zoom widget in workspace and viewer mode [Taiga #896](https://tree.taiga.io/project/penpot/us/896).
- Allow decimals on stroke width and positions [Taiga #2035](https://tree.taiga.io/project/penpot/issue/2035).
- Ability to ignore background when exporting an artboard [Taiga #1395](https://tree.taiga.io/project/penpot/us/1395).
- Show color hex or name on hover [Taiga #2413](https://tree.taiga.io/project/penpot/us/2413).
@ -72,7 +74,6 @@
- Explain folders in components (by @candideu) [Penpot-docs #42](https://github.com/penpot/penpot-docs/pull/42).
- Readability improvements of user guide (by @PaulSchulz) [Penpot-docs #50](https://github.com/penpot/penpot-docs/pull/50).
# 1.10.4-beta
### :sparkles: Enhacements
@ -85,7 +86,6 @@
- Minor fix on how file changes log is persisted.
- Fix many issues on error reporting.
# 1.10.3-beta
### :sparkles: Enhacements
@ -120,14 +120,12 @@
- Update log4j2 dependency.
# 1.10.1-beta
### :bug: Bugs fixed
- Fix problems with team management [#1353](https://github.com/penpot/penpot/issues/1353)
## 1.10.0-beta
### :boom: Breaking changes
@ -232,8 +230,6 @@
- To the translation community for the hard work on making penpot
available on so many languages.
## 1.8.4-alpha
### :bug: Bugs fixed
@ -261,7 +257,6 @@
- Set proper environment variable on docker images for chrome executable.
- Fix internal metrics on websocket connections.
## 1.8.0-alpha
### :boom: Breaking changes
@ -303,12 +298,13 @@
- Fix problem while moving imported SVG's [#1199](https://github.com/penpot/penpot/issues/1199)
### :arrow_up: Deps updates
### :boom: Breaking changes
### :heart: Community contributions by (Thank you!)
- eduayme [#1129](https://github.com/penpot/penpot/pull/1129).
## 1.7.4-alpha
### :bug: Bugs fixed
@ -316,14 +312,12 @@
- Fix demo user creation (self-hosted only)
- Add better ldap response validation and reporting (self-hosted only)
## 1.7.3-alpha
### :bug: Bugs fixed
- Fix font uploading issue on Windows.
## 1.7.2-alpha
### :sparkles: New features
@ -347,7 +341,6 @@
- soultipsy [#1100](https://github.com/penpot/penpot/pull/1100)
## 1.7.1-alpha
### :bug: Bugs fixed
@ -357,7 +350,6 @@
- Fix issue on undo page deletion.
- Fix some issues related to constraints.
## 1.7.0-alpha
### :sparkles: New features
@ -392,7 +384,6 @@
- Fix header partially visible on fullscreen viewer mode [Taiga #1875](https://tree.taiga.io/project/penpot/issue/1875)
- Fix dynamic alignment enabled with hidden objects [#1063](https://github.com/penpot/penpot/issues/1063)
## 1.6.5-alpha
### :bug: Bugs fixed
@ -403,8 +394,8 @@
### :sparkles: Minor improvements
- Decrease default bulk buffers on storage tasks.
- Reduce file_change preserve interval to 24h.
- Decrease default bulk buffers on storage tasks.
- Reduce file_change preserve interval to 24h.
### :bug: Bugs fixed
@ -417,7 +408,6 @@
- Properly handle nil values on `update-shapes` function.
- Replace frame term usage by artboard on viewer app.
## 1.6.3-alpha
### :bug: Bugs fixed
@ -444,7 +434,6 @@
- Minor fix on previous commit.
- Minor improvements on svg uploading on libraries.
## 1.6.1-alpha
### :bug: Bugs fixed
@ -460,7 +449,6 @@
- Improve editor lifecycle management.
- Make the navigation async by default.
## 1.6.0-alpha
### :sparkles: New features
@ -475,7 +463,6 @@
- Use shift instead of ctrl/cmd to keep aspect ratio [Taiga 1697](https://tree.taiga.io/project/penpot/issue/1697).
- New translations: Portuguese (Brazil) and Romanias.
### :bug: Bugs fixed
- Remove interactions when the destination artboard is deleted [Taiga #1656](https://tree.taiga.io/project/penpot/issue/1656).
@ -493,7 +480,6 @@
- Update exporter dependencies (puppeteer), that fixes some unexpected exceptions.
- Update string manipulation library.
### :boom: Breaking changes
- The OIDC setting `PENPOT_OIDC_SCOPES` has changed the default semantics. Before this
@ -504,7 +490,6 @@
- Translations: Portuguese (Brazil) and Romanias.
## 1.5.4-alpha
### :bug: Bugs fixed
@ -512,7 +497,6 @@
- Fix issues on group rendering.
- Fix problem with text editing auto-height [Taiga #1683](https://tree.taiga.io/project/penpot/issue/1683)
## 1.5.3-alpha
### :bug: Bugs fixed
@ -536,7 +520,6 @@
- Increase default team invitation token expiration to 48h.
- Fix wrong error message when an expired token is used.
## 1.5.0-alpha
### :sparkles: New features
@ -582,7 +565,6 @@
- madmath03 (by [Monogramm](https://github.com/Monogramm)) [#807](https://github.com/penpot/penpot/pull/807)
- zzkt [#814](https://github.com/penpot/penpot/pull/814)
## 1.4.1-alpha
### :bug: Bugs fixed
@ -594,7 +576,6 @@
- Fix incorrect state management of user lang selection.
- Fix email validation usability issue on team invitation lightbox.
## 1.4.0-alpha
### :sparkles: New features
@ -617,7 +598,6 @@
- Replace Slate-Editor with DraftJS [Taiga #1346](https://tree.taiga.io/project/penpot/us/1346)
- Set proper page title [Taiga #1377](https://tree.taiga.io/project/penpot/us/1377)
### :bug: Bugs fixed
- Disable buttons in view mode for users without permissions [Taiga #1328](https://tree.taiga.io/project/penpot/issue/1328)
@ -660,13 +640,11 @@
(example `:username`) instead of `$`. The main reason is avoid
unnecessary conflict with bash interpolation.
### :arrow_up: Deps updates
- Update backend to JDK16.
- Update exporter nodejs to v14.16.0
### :heart: Community contributions by (Thank you!)
- iblueer [#726](https://github.com/penpot/penpot/pull/726)
@ -674,7 +652,6 @@
- girafic [#748](https://github.com/penpot/penpot/pull/748)
- mbrksntrk [#794](https://github.com/penpot/penpot/pull/794)
## 1.3.0-alpha
### :sparkles: New features
@ -690,7 +667,6 @@
- Disable groups interactions when holding "Ctrl" key (deep selection)
- New action in context menu to "edit" some shapes (bound to key "Enter")
### :bug: Bugs fixed
- Add more improvements to french translation strings [#591](https://github.com/penpot/penpot/pull/591)
@ -711,13 +687,11 @@
- Properly mark profile auth backend (on first register/ auth with 3rd party auth provider).
- Refactor LDAP auth backend.
### :heart: Community contributions by (Thank you!)
- girafic [#538](https://github.com/penpot/penpot/pull/654)
- arkhi [#591](https://github.com/penpot/penpot/pull/591)
## 1.2.0-alpha
### :sparkles: New features
@ -732,7 +706,6 @@
- Show a pixel grid when zoom greater than 800% [#519](https://github.com/penpot/penpot/discussions/519)
- Fix behavior of select all command when there are objects outside frames [Taiga #1209](https://tree.taiga.io/project/penpot/issue/1209)
### :bug: Bugs fixed
- Fix 404 when access shared link [#615](https://github.com/penpot/penpot/issues/615)
@ -768,7 +741,6 @@
- Improved MacOS shortcuts and helpers
- Small changes to shape creation
## 1.0.0-alpha
Initial release

View file

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

View file

@ -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))

View file

@ -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"

View file

@ -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))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -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))

View file

@ -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

View file

@ -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]]))

View file

@ -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 []

View file

@ -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"

View file

@ -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

View file

@ -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))

View file

@ -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)"

View file

@ -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)"