mirror of
https://github.com/penpot/penpot.git
synced 2025-04-10 14:01:29 -05:00
✨ New focus mode in workspace
This commit is contained in:
parent
dc18a6c3bc
commit
78d7fe3e10
26 changed files with 484 additions and 179 deletions
|
@ -12,6 +12,7 @@
|
|||
- Add new invitations section [Taiga #2797](https://tree.taiga.io/project/penpot/us/2797)
|
||||
- Ability to add multiple fills to a shape [Taiga #1394](https://tree.taiga.io/project/penpot/us/1394)
|
||||
- Team members redesign [Taiga #2283](https://tree.taiga.io/project/penpot/us/2283)
|
||||
- New focus mode in workspace [Taiga #2748](https://tree.taiga.io/project/penpot/us/2748)
|
||||
- Changed text shapes to be displayed as natives SVG text elements [Taiga #2759](https://tree.taiga.io/project/penpot/us/2759)
|
||||
- Texts now can have strokes, multiple fills and can be used as masks
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.pages.changes :as changes]
|
||||
[app.common.pages.common :as common]
|
||||
[app.common.pages.focus :as focus]
|
||||
[app.common.pages.indices :as indices]
|
||||
[app.common.pages.init :as init]))
|
||||
|
||||
|
@ -19,6 +20,11 @@
|
|||
(dm/export common/default-color)
|
||||
(dm/export common/component-sync-attrs)
|
||||
|
||||
;; Focus
|
||||
(dm/export focus/focus-objects)
|
||||
(dm/export focus/filter-not-focus)
|
||||
(dm/export focus/is-in-focus?)
|
||||
|
||||
;; Indices
|
||||
(dm/export indices/calculate-z-index)
|
||||
(dm/export indices/update-z-index)
|
||||
|
@ -36,3 +42,4 @@
|
|||
(dm/export init/make-minimal-shape)
|
||||
(dm/export init/make-minimal-group)
|
||||
(dm/export init/empty-file-data)
|
||||
|
||||
|
|
51
common/src/app/common/pages/focus.cljc
Normal file
51
common/src/app/common/pages/focus.cljc
Normal file
|
@ -0,0 +1,51 @@
|
|||
;; 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.common.pages.focus
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.pages.indices :as cpi]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(defn focus-objects
|
||||
[objects focus]
|
||||
(let [[ids-with-children z-index]
|
||||
(when (d/not-empty? focus)
|
||||
[(into (conj focus uuid/zero)
|
||||
(mapcat (partial cph/get-children-ids objects))
|
||||
focus)
|
||||
(cpi/calculate-z-index objects)])
|
||||
|
||||
sort-by-z-index
|
||||
(fn [coll]
|
||||
(->> coll (sort-by (fn [a b] (- (get z-index a) (get z-index b))))))]
|
||||
|
||||
(cond-> objects
|
||||
(some? ids-with-children)
|
||||
(-> (select-keys ids-with-children)
|
||||
(assoc-in [uuid/zero :shapes] (sort-by-z-index focus))))))
|
||||
|
||||
(defn filter-not-focus
|
||||
[objects focus ids]
|
||||
|
||||
(let [focused-ids
|
||||
(when (d/not-empty? focus)
|
||||
(into focus
|
||||
(mapcat (partial cph/get-children-ids objects))
|
||||
focus))]
|
||||
|
||||
(if (some? focused-ids)
|
||||
(into (d/ordered-set)
|
||||
(filter #(contains? focused-ids %))
|
||||
ids)
|
||||
ids)))
|
||||
|
||||
(defn is-in-focus?
|
||||
[objects focus id]
|
||||
(d/seek
|
||||
#(contains? focus %)
|
||||
(cph/get-parents-seq objects id)))
|
|
@ -74,6 +74,16 @@
|
|||
[objects id]
|
||||
(-> objects (get id) :parent-id))
|
||||
|
||||
(defn get-parents-seq
|
||||
[objects shape-id]
|
||||
|
||||
(cond
|
||||
(nil? shape-id)
|
||||
nil
|
||||
|
||||
:else
|
||||
(lazy-seq (cons shape-id (get-parents-seq objects (get-in objects [shape-id :parent-id]))))))
|
||||
|
||||
(defn get-parent-ids
|
||||
"Returns a vector of parents of the specified shape."
|
||||
[objects shape-id]
|
||||
|
@ -463,3 +473,4 @@
|
|||
[path name]
|
||||
(let [path-split (split-path path)]
|
||||
(merge-path-item (first path-split) name)))
|
||||
|
||||
|
|
|
@ -113,6 +113,43 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .focus-title {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-column-gap: 8px;
|
||||
|
||||
& .back-button {
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
transform: rotate(180deg);
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
fill: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
& svg {
|
||||
fill: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
& .focus-mode {
|
||||
color: $color-primary;
|
||||
border: 1px solid $color-primary;
|
||||
border-radius: 3px;
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.assets-bar .tool-window {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.align :as gal]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.proportions :as gpr]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
|
@ -44,6 +43,7 @@
|
|||
[app.main.data.workspace.svg-upload :as svg]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.worker :as uw]
|
||||
|
@ -294,7 +294,7 @@
|
|||
exit-workspace? (not= :workspace (get-in state [:route :data :name]))]
|
||||
(cond-> (assoc-in state [:workspace-cache page-id] local)
|
||||
:always
|
||||
(dissoc :current-page-id :workspace-local :trimmed-page)
|
||||
(dissoc :current-page-id :workspace-local :trimmed-page :workspace-focus-selected)
|
||||
exit-workspace?
|
||||
(dissoc :workspace-drawing))))))
|
||||
|
||||
|
@ -478,11 +478,6 @@
|
|||
|
||||
;; --- Viewport Sizing
|
||||
|
||||
(declare increase-zoom)
|
||||
(declare decrease-zoom)
|
||||
(declare set-zoom)
|
||||
(declare zoom-to-fit-all)
|
||||
|
||||
(defn initialize-viewport
|
||||
[{:keys [width height] :as size}]
|
||||
(letfn [(update* [{:keys [vport] :as local}]
|
||||
|
@ -612,114 +607,8 @@
|
|||
(-> state
|
||||
(update :workspace-local dissoc :panning)))))
|
||||
|
||||
(defn start-zooming [pt]
|
||||
(ptk/reify ::start-zooming
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? ::finish-zooming)))]
|
||||
(when-not (get-in state [:workspace-local :zooming])
|
||||
(rx/concat
|
||||
(rx/of #(-> % (assoc-in [:workspace-local :zooming] true)))
|
||||
(->> stream
|
||||
(rx/filter ms/pointer-event?)
|
||||
(rx/filter #(= :delta (:source %)))
|
||||
(rx/map :pt)
|
||||
(rx/take-until stopper)
|
||||
(rx/map (fn [delta]
|
||||
(let [scale (+ 1 (/ (:y delta) 100))] ;; this number may be adjusted after user testing
|
||||
(set-zoom pt scale)))))))))))
|
||||
|
||||
(defn finish-zooming []
|
||||
(ptk/reify ::finish-zooming
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :zooming)))))
|
||||
|
||||
;; --- Zoom Management
|
||||
|
||||
(defn- impl-update-zoom
|
||||
[{:keys [vbox] :as local} center zoom]
|
||||
(let [new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom)
|
||||
old-zoom (:zoom local)
|
||||
center (if center center (gsh/center-rect vbox))
|
||||
scale (/ old-zoom new-zoom)
|
||||
mtx (gmt/scale-matrix (gpt/point scale) center)
|
||||
vbox' (gsh/transform-rect vbox mtx)]
|
||||
(-> local
|
||||
(assoc :zoom new-zoom)
|
||||
(update :vbox merge (select-keys vbox' [:x :y :width :height])))))
|
||||
|
||||
(defn increase-zoom
|
||||
[center]
|
||||
(ptk/reify ::increase-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (min (* z 1.3) 200)))))))
|
||||
|
||||
(defn decrease-zoom
|
||||
[center]
|
||||
(ptk/reify ::decrease-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (max (/ z 1.3) 0.01)))))))
|
||||
|
||||
(defn set-zoom
|
||||
[center scale]
|
||||
(ptk/reify ::set-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (-> (* z scale)
|
||||
(max 0.01)
|
||||
(min 200))))))))
|
||||
|
||||
(def reset-zoom
|
||||
(ptk/reify ::reset-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % nil 1)))))
|
||||
|
||||
(def zoom-to-fit-all
|
||||
(ptk/reify ::zoom-to-fit-all
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shapes (cph/get-immediate-children objects)
|
||||
srect (gsh/selection-rect shapes)]
|
||||
(if (empty? shapes)
|
||||
state
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(let [srect (gal/adjust-to-viewport vport srect {:padding 40})
|
||||
zoom (/ (:width vport) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect))))))))))
|
||||
|
||||
(def zoom-to-selected-shape
|
||||
(ptk/reify ::zoom-to-selected-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(if (empty? selected)
|
||||
state
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
srect (->> selected
|
||||
(map #(get objects %))
|
||||
(gsh/selection-rect))]
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(let [srect (gal/adjust-to-viewport vport srect {:padding 40})
|
||||
zoom (/ (:width vport) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect)))))))))))
|
||||
|
||||
;; --- Update Shape Attrs
|
||||
|
||||
|
@ -1887,21 +1776,25 @@
|
|||
(dm/export dwp/clone-media-object)
|
||||
(dm/export dwc/image-uploaded)
|
||||
|
||||
;; Selection
|
||||
|
||||
(dm/export dws/select-shape)
|
||||
(dm/export dws/deselect-shape)
|
||||
(dm/export dws/select-all)
|
||||
(dm/export dws/deselect-all)
|
||||
;; Common
|
||||
(dm/export dwc/add-shape)
|
||||
(dm/export dwc/clear-edition-mode)
|
||||
(dm/export dwc/select-shapes)
|
||||
(dm/export dws/shift-select-shapes)
|
||||
(dm/export dwc/start-edition-mode)
|
||||
|
||||
;; Drawing
|
||||
(dm/export dwd/select-for-drawing)
|
||||
|
||||
;; Selection
|
||||
(dm/export dws/toggle-focus-mode)
|
||||
(dm/export dws/deselect-all)
|
||||
(dm/export dws/deselect-shape)
|
||||
(dm/export dws/duplicate-selected)
|
||||
(dm/export dws/handle-area-selection)
|
||||
(dm/export dws/select-all)
|
||||
(dm/export dws/select-inside-group)
|
||||
(dm/export dwd/select-for-drawing)
|
||||
(dm/export dwc/clear-edition-mode)
|
||||
(dm/export dwc/add-shape)
|
||||
(dm/export dwc/start-edition-mode)
|
||||
(dm/export dws/select-shape)
|
||||
(dm/export dws/shift-select-shapes)
|
||||
|
||||
;; Groups
|
||||
|
||||
|
@ -1924,3 +1817,11 @@
|
|||
(dm/export dwgu/remove-guide)
|
||||
(dm/export dwgu/set-hover-guide)
|
||||
|
||||
;; Zoom
|
||||
(dm/export dwz/reset-zoom)
|
||||
(dm/export dwz/zoom-to-selected-shape)
|
||||
(dm/export dwz/start-zooming)
|
||||
(dm/export dwz/finish-zooming)
|
||||
(dm/export dwz/zoom-to-fit-all)
|
||||
(dm/export dwz/decrease-zoom)
|
||||
(dm/export dwz/increase-zoom)
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
layout (get state :workspace-layout)
|
||||
focus (:workspace-focus-selected state)
|
||||
zoom (get-in state [:workspace-local :zoom] 1)
|
||||
|
||||
frames (cph/get-frames objects)
|
||||
|
@ -80,7 +81,7 @@
|
|||
(rx/of #(assoc-in state [:workspace-drawing :object] shape))
|
||||
|
||||
;; Initial SNAP
|
||||
(->> (snap/closest-snap-point page-id [shape] layout zoom initial)
|
||||
(->> (snap/closest-snap-point page-id [shape] objects layout zoom focus initial)
|
||||
(rx/map move-drawing))
|
||||
|
||||
(->> ms/mouse-position
|
||||
|
@ -88,7 +89,7 @@
|
|||
(rx/with-latest vector ms/mouse-position-shift)
|
||||
(rx/switch-map
|
||||
(fn [[point :as current]]
|
||||
(->> (snap/closest-snap-point page-id [shape] layout zoom point)
|
||||
(->> (snap/closest-snap-point page-id [shape] objects layout zoom focus point)
|
||||
(rx/map #(conj current %)))))
|
||||
(rx/map
|
||||
(fn [[_ shift? point]]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
|
@ -20,10 +21,13 @@
|
|||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.zoom :as dwz]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.worker :as uw]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.set :as set]
|
||||
[linked.set :as lks]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
|
@ -161,7 +165,12 @@
|
|||
(ptk/reify ::select-shapes
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:workspace-local :selected] ids))
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
focus (:workspace-focus-selected state)
|
||||
ids (if (d/not-empty? focus)
|
||||
(cp/filter-not-focus objects focus ids)
|
||||
ids)]
|
||||
(assoc-in state [:workspace-local :selected] ids)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -173,8 +182,9 @@
|
|||
(ptk/reify ::select-all
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
(let [focus (:workspace-focus-selected state)
|
||||
objects (-> (wsh/lookup-page-objects state)
|
||||
(cp/focus-objects focus))
|
||||
|
||||
selected (let [frame-ids (into #{} (comp
|
||||
(map (d/getf objects))
|
||||
|
@ -484,8 +494,8 @@
|
|||
|
||||
id-duplicated (when (= (count selected) 1) (first selected))]
|
||||
|
||||
(rx/of (select-shapes selected)
|
||||
(dch/commit-changes changes)
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(select-shapes selected)
|
||||
(memorize-duplicated id-original id-duplicated)))))))
|
||||
|
||||
(defn change-hover-state
|
||||
|
@ -495,3 +505,54 @@
|
|||
(update [_ state]
|
||||
(let [hover-value (if value #{id} #{})]
|
||||
(assoc-in state [:workspace-local :hover] hover-value)))))
|
||||
|
||||
(defn update-focus-shapes
|
||||
[added removed]
|
||||
(ptk/reify ::update-focus-shapes
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
|
||||
focus (-> (:workspace-focus-selected state)
|
||||
(set/union added)
|
||||
(set/difference removed))
|
||||
focus (cph/clean-loops objects focus)]
|
||||
|
||||
(-> state
|
||||
(assoc :workspace-focus-selected focus))))))
|
||||
|
||||
(defn toggle-focus-mode
|
||||
[]
|
||||
(ptk/reify ::toggle-focus-mode
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(cond-> state
|
||||
(and (empty? (:workspace-focus-selected state))
|
||||
(d/not-empty? selected))
|
||||
(assoc :workspace-focus-selected selected)
|
||||
|
||||
(d/not-empty? (:workspace-focus-selected state))
|
||||
(dissoc :workspace-focus-selected))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (rx/filter #(or (= ::toggle-focus-mode (ptk/type %))
|
||||
(= :app.main.data.workspace/finalize-page (ptk/type %))) stream)]
|
||||
(when (d/not-empty? (:workspace-focus-selected state))
|
||||
(rx/merge
|
||||
(rx/of dwz/zoom-to-selected-shape
|
||||
(deselect-all))
|
||||
(->> (rx/from-atom refs/workspace-page-objects {:emit-current-value? true})
|
||||
(rx/take-until stopper)
|
||||
(rx/map (comp set keys))
|
||||
(rx/buffer 2 1)
|
||||
(rx/merge-map
|
||||
(fn [[old-keys new-keys]]
|
||||
(let [removed (set/difference old-keys new-keys)
|
||||
added (set/difference new-keys old-keys)]
|
||||
|
||||
(if (or (d/not-empty? added) (d/not-empty? removed))
|
||||
(rx/of (update-focus-shapes added removed))
|
||||
(rx/empty))))))))))))
|
||||
|
|
|
@ -352,11 +352,13 @@
|
|||
:command (ds/c-mod "alt+g")
|
||||
:fn #(st/emit! (dw/create-artboard-from-selection))}
|
||||
|
||||
:hide-ui {:tooltip "\\"
|
||||
:command "\\"
|
||||
:fn #(st/emit! (dw/toggle-layout-flags :hide-ui))}
|
||||
:hide-ui {:tooltip "\\"
|
||||
:command "\\"
|
||||
:fn #(st/emit! (dw/toggle-layout-flags :hide-ui))}
|
||||
|
||||
})
|
||||
:toggle-focus-mode {:command "f"
|
||||
:tooltip "F"
|
||||
:fn #(st/emit! (dw/toggle-focus-mode))}})
|
||||
|
||||
(def opacity-shortcuts
|
||||
(into {} (->>
|
||||
|
|
|
@ -375,6 +375,7 @@
|
|||
stoper (rx/filter ms/mouse-up? stream)
|
||||
layout (:workspace-layout state)
|
||||
page-id (:current-page-id state)
|
||||
focus (:workspace-focus-selected state)
|
||||
zoom (get-in state [:workspace-local :zoom] 1)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
resizing-shapes (map #(get objects %) ids)
|
||||
|
@ -387,7 +388,7 @@
|
|||
(rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt)
|
||||
(rx/map normalize-proportion-lock)
|
||||
(rx/switch-map (fn [[point _ _ :as current]]
|
||||
(->> (snap/closest-snap-point page-id resizing-shapes layout zoom point)
|
||||
(->> (snap/closest-snap-point page-id resizing-shapes objects layout zoom focus point)
|
||||
(rx/map #(conj current %)))))
|
||||
(rx/mapcat (partial resize shape initial-position layout))
|
||||
(rx/take-until stoper))
|
||||
|
@ -509,7 +510,6 @@
|
|||
(rx/of (start-move initial selected)))))
|
||||
(rx/take-until stopper)))))))
|
||||
|
||||
|
||||
(defn- start-move-duplicate
|
||||
[from-position]
|
||||
(ptk/reify ::start-move-duplicate
|
||||
|
@ -544,6 +544,7 @@
|
|||
stopper (rx/filter ms/mouse-up? stream)
|
||||
layout (get state :workspace-layout)
|
||||
zoom (get-in state [:workspace-local :zoom] 1)
|
||||
focus (:workspace-focus-selected state)
|
||||
|
||||
fix-axis (fn [[position shift?]]
|
||||
(let [delta (gpt/to-vec from-position position)]
|
||||
|
@ -564,10 +565,10 @@
|
|||
(rx/throttle 20)
|
||||
(rx/switch-map
|
||||
(fn [pos]
|
||||
(->> (snap/closest-snap-move page-id shapes objects layout zoom pos)
|
||||
(->> (snap/closest-snap-move page-id shapes objects layout zoom focus pos)
|
||||
(rx/map #(vector pos %)))))))]
|
||||
(if (empty? shapes)
|
||||
(rx/empty)
|
||||
(rx/of (finish-transform))
|
||||
(rx/concat
|
||||
(->> position
|
||||
(rx/with-latest vector snap-delta)
|
||||
|
|
123
frontend/src/app/main/data/workspace/zoom.cljs
Normal file
123
frontend/src/app/main/data/workspace/zoom.cljs
Normal file
|
@ -0,0 +1,123 @@
|
|||
;; 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.data.workspace.zoom
|
||||
(:require
|
||||
[app.common.geom.align :as gal]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.streams :as ms]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]))
|
||||
|
||||
(defn- impl-update-zoom
|
||||
[{:keys [vbox] :as local} center zoom]
|
||||
(let [new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom)
|
||||
old-zoom (:zoom local)
|
||||
center (if center center (gsh/center-rect vbox))
|
||||
scale (/ old-zoom new-zoom)
|
||||
mtx (gmt/scale-matrix (gpt/point scale) center)
|
||||
vbox' (gsh/transform-rect vbox mtx)]
|
||||
(-> local
|
||||
(assoc :zoom new-zoom)
|
||||
(update :vbox merge (select-keys vbox' [:x :y :width :height])))))
|
||||
|
||||
(defn increase-zoom
|
||||
[center]
|
||||
(ptk/reify ::increase-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (min (* z 1.3) 200)))))))
|
||||
|
||||
(defn decrease-zoom
|
||||
[center]
|
||||
(ptk/reify ::decrease-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (max (/ z 1.3) 0.01)))))))
|
||||
|
||||
(defn set-zoom
|
||||
[center scale]
|
||||
(ptk/reify ::set-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % center (fn [z] (-> (* z scale)
|
||||
(max 0.01)
|
||||
(min 200))))))))
|
||||
|
||||
(def reset-zoom
|
||||
(ptk/reify ::reset-zoom
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace-local
|
||||
#(impl-update-zoom % nil 1)))))
|
||||
|
||||
(def zoom-to-fit-all
|
||||
(ptk/reify ::zoom-to-fit-all
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
shapes (cph/get-immediate-children objects)
|
||||
srect (gsh/selection-rect shapes)]
|
||||
(if (empty? shapes)
|
||||
state
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(let [srect (gal/adjust-to-viewport vport srect {:padding 40})
|
||||
zoom (/ (:width vport) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect))))))))))
|
||||
|
||||
(def zoom-to-selected-shape
|
||||
(ptk/reify ::zoom-to-selected-shape
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [selected (wsh/lookup-selected state)]
|
||||
(if (empty? selected)
|
||||
state
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
srect (->> selected
|
||||
(map #(get objects %))
|
||||
(gsh/selection-rect))]
|
||||
(update state :workspace-local
|
||||
(fn [{:keys [vport] :as local}]
|
||||
(let [srect (gal/adjust-to-viewport vport srect {:padding 40})
|
||||
zoom (/ (:width vport) (:width srect))]
|
||||
(-> local
|
||||
(assoc :zoom zoom)
|
||||
(update :vbox merge srect)))))))))))
|
||||
|
||||
(defn start-zooming [pt]
|
||||
(ptk/reify ::start-zooming
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? ::finish-zooming)))]
|
||||
(when-not (get-in state [:workspace-local :zooming])
|
||||
(rx/concat
|
||||
(rx/of #(-> % (assoc-in [:workspace-local :zooming] true)))
|
||||
(->> stream
|
||||
(rx/filter ms/pointer-event?)
|
||||
(rx/filter #(= :delta (:source %)))
|
||||
(rx/map :pt)
|
||||
(rx/take-until stopper)
|
||||
(rx/map (fn [delta]
|
||||
(let [scale (+ 1 (/ (:y delta) 100))] ;; this number may be adjusted after user testing
|
||||
(set-zoom pt scale)))))))))))
|
||||
|
||||
(defn finish-zooming []
|
||||
(ptk/reify ::finish-zooming
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :zooming)))))
|
|
@ -284,6 +284,9 @@
|
|||
(mapv (d/getf objects) shapes)))]
|
||||
(l/derived selector selected-data =)))
|
||||
|
||||
(def workspace-focus-selected
|
||||
(l/derived :workspace-focus-selected st/state))
|
||||
|
||||
;; ---- Viewer refs
|
||||
|
||||
(def viewer-file
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.uuid :refer [zero]]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -32,21 +33,27 @@
|
|||
|
||||
(defn make-remove-snap
|
||||
"Creates a filter for the snap data. Used to disable certain layouts"
|
||||
[layout filter-shapes]
|
||||
[layout filter-shapes objects focus]
|
||||
|
||||
(fn [{:keys [type id]}]
|
||||
(fn [{:keys [type id frame-id]}]
|
||||
(cond
|
||||
(= type :layout)
|
||||
(or (not (contains? layout :display-grid))
|
||||
(not (contains? layout :snap-grid)))
|
||||
(not (contains? layout :snap-grid))
|
||||
(and (d/not-empty? focus)
|
||||
(not (contains? focus id))))
|
||||
|
||||
(= type :guide)
|
||||
(or (not (contains? layout :rules))
|
||||
(not (contains? layout :snap-guides)))
|
||||
(not (contains? layout :snap-guides))
|
||||
(and (d/not-empty? focus)
|
||||
(not (contains? focus frame-id))))
|
||||
|
||||
:else
|
||||
(or (contains? filter-shapes id)
|
||||
(not (contains? layout :dynamic-alignment))))))
|
||||
(not (contains? layout :dynamic-alignment))
|
||||
(and (d/not-empty? focus)
|
||||
(not (cp/is-in-focus? objects focus id)))))))
|
||||
|
||||
(defn- flatten-to-points
|
||||
[query-result]
|
||||
|
@ -223,19 +230,19 @@
|
|||
(rx/map snap->vector))))
|
||||
|
||||
(defn closest-snap-point
|
||||
[page-id shapes layout zoom point]
|
||||
[page-id shapes objects layout zoom focus point]
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))
|
||||
remove-snap? (make-remove-snap layout filter-shapes)]
|
||||
remove-snap? (make-remove-snap layout filter-shapes objects focus)]
|
||||
(->> (closest-snap page-id frame-id [point] remove-snap? zoom)
|
||||
(rx/map #(or % (gpt/point 0 0)))
|
||||
(rx/map #(gpt/add point %)))))
|
||||
|
||||
(defn closest-snap-move
|
||||
[page-id shapes objects layout zoom movev]
|
||||
[page-id shapes objects layout zoom focus movev]
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))
|
||||
remove-snap? (make-remove-snap layout filter-shapes)
|
||||
remove-snap? (make-remove-snap layout filter-shapes objects focus)
|
||||
|
||||
shape (if (> (count shapes) 1)
|
||||
(->> shapes (map gsh/transform-shape) gsh/selection-rect (gsh/setup {:type :rect}))
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
(ns app.main.ui.hooks
|
||||
"A collection of general purpose react hooks."
|
||||
(:require
|
||||
[app.common.pages :as cp]
|
||||
[app.main.data.shortcuts :as dsc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.dom.dnd :as dnd]
|
||||
|
@ -235,3 +237,14 @@
|
|||
(let [ret (effect-fn)]
|
||||
(when (fn? ret) (ret)))
|
||||
(mf/use-effect deps effect-fn)))
|
||||
|
||||
(defn with-focus-objects
|
||||
([objects]
|
||||
(let [focus (mf/deref refs/workspace-focus-selected)]
|
||||
(with-focus-objects objects focus)))
|
||||
|
||||
([objects focus]
|
||||
(let [objects (mf/use-memo
|
||||
(mf/deps focus objects)
|
||||
#(cp/focus-objects objects focus))]
|
||||
objects)))
|
||||
|
|
|
@ -212,6 +212,17 @@
|
|||
:on-click do-create-artboard-from-selection}]
|
||||
[:& menu-separator]])]))
|
||||
|
||||
(mf/defc context-focus-mode-menu
|
||||
[{:keys []}]
|
||||
(let [focus (mf/deref refs/workspace-focus-selected)
|
||||
do-toggle-focus-mode #(st/emit! (dw/toggle-focus-mode))]
|
||||
|
||||
[:& menu-entry {:title (if (empty? focus)
|
||||
(tr "workspace.focus.focus-on")
|
||||
(tr "workspace.focus.focus-off"))
|
||||
:shortcut (sc/get-tooltip :toggle-focus-mode)
|
||||
:on-click do-toggle-focus-mode}]))
|
||||
|
||||
(mf/defc context-menu-path
|
||||
[{:keys [shapes disable-flatten? disable-booleans?]}]
|
||||
(let [multiple? (> (count shapes) 1)
|
||||
|
@ -426,6 +437,7 @@
|
|||
[:> context-menu-layer-position props]
|
||||
[:> context-menu-flip props]
|
||||
[:> context-menu-group props]
|
||||
[:> context-focus-mode-menu props]
|
||||
[:> context-menu-path props]
|
||||
[:> context-menu-layer-options props]
|
||||
[:> context-menu-prototype props]
|
||||
|
@ -434,15 +446,23 @@
|
|||
|
||||
(mf/defc viewport-context-menu
|
||||
[]
|
||||
(let [do-paste (st/emitf dw/paste)
|
||||
do-hide-ui (st/emitf (dw/toggle-layout-flags :hide-ui))]
|
||||
(let [focus (mf/deref refs/workspace-focus-selected)
|
||||
|
||||
do-paste (st/emitf dw/paste)
|
||||
do-hide-ui (st/emitf (dw/toggle-layout-flags :hide-ui))
|
||||
do-toggle-focus-mode #(st/emit! (dw/toggle-focus-mode))]
|
||||
[:*
|
||||
[:& menu-entry {:title (tr "workspace.shape.menu.paste")
|
||||
:shortcut (sc/get-tooltip :paste)
|
||||
:on-click do-paste}]
|
||||
[:& menu-entry {:title (tr "workspace.shape.menu.hide-ui")
|
||||
:shortcut (sc/get-tooltip :hide-ui)
|
||||
:on-click do-hide-ui}]]))
|
||||
:on-click do-hide-ui}]
|
||||
|
||||
(when (d/not-empty? focus)
|
||||
[:& menu-entry {:title (tr "workspace.focus.focus-off")
|
||||
:shortcut (sc/get-tooltip :toggle-focus-mode)
|
||||
:on-click do-toggle-focus-mode}])]))
|
||||
|
||||
(mf/defc context-menu
|
||||
[]
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.shapes.frame
|
||||
(:require
|
||||
[app.common.colors :as cc]
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
|
@ -41,7 +42,7 @@
|
|||
(let [{:keys [x y width height fill-color] :as shape} (obj/get props "shape")]
|
||||
(if (some? (:thumbnail shape))
|
||||
[:& frame/frame-thumbnail {:shape shape}]
|
||||
[:rect {:x x :y y :width width :height height :style {:fill (or fill-color "var(--color-white)")}}])))
|
||||
[:rect.frame-thumbnail {:x x :y y :width width :height height :style {:fill (or fill-color cc/white)}}])))
|
||||
|
||||
(defn custom-deferred
|
||||
[component]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[app.util.timers :as ts]
|
||||
|
@ -314,11 +315,23 @@
|
|||
(mf/defc layers-toolbox
|
||||
{:wrap [mf/memo]}
|
||||
[]
|
||||
(let [page (mf/deref refs/workspace-page)]
|
||||
(let [page (mf/deref refs/workspace-page)
|
||||
focus (mf/deref refs/workspace-focus-selected)
|
||||
objects (hooks/with-focus-objects (:objects page) focus)
|
||||
title (when (= 1 (count focus)) (get-in objects [(first focus) :name]))]
|
||||
[:div#layers.tool-window
|
||||
[:div.tool-window-bar
|
||||
[:div.tool-window-icon i/layers]
|
||||
[:span (:name page)]]
|
||||
(if (d/not-empty? focus)
|
||||
[:div.tool-window-bar
|
||||
[:div.focus-title
|
||||
[:button.back-button
|
||||
{:on-click #(st/emit! (dw/toggle-focus-mode))}
|
||||
i/arrow-slide ]
|
||||
[:span (or title (tr "workspace.focus.selection"))]
|
||||
[:div.focus-mode (tr "workspace.focus.focus-mode")]]]
|
||||
|
||||
[:div.tool-window-bar
|
||||
[:span (:name page)]])
|
||||
|
||||
[:div.tool-window-content
|
||||
[:& layers-tree-wrapper {:key (:id page)
|
||||
:objects (:objects page)}]]]))
|
||||
:objects objects}]]]))
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.hooks :as ui-hooks]
|
||||
[app.main.ui.measurements :as msr]
|
||||
[app.main.ui.shapes.embed :as embed]
|
||||
[app.main.ui.shapes.export :as use]
|
||||
|
@ -65,7 +66,9 @@
|
|||
;; DEREFS
|
||||
drawing (mf/deref refs/workspace-drawing)
|
||||
options (mf/deref refs/workspace-page-options)
|
||||
base-objects (mf/deref refs/workspace-page-objects)
|
||||
focus (mf/deref refs/workspace-focus-selected)
|
||||
base-objects (-> (mf/deref refs/workspace-page-objects)
|
||||
(ui-hooks/with-focus-objects focus))
|
||||
modifiers (mf/deref refs/workspace-modifiers)
|
||||
objects-modified (mf/with-memo [base-objects modifiers]
|
||||
(gsh/merge-modifiers base-objects modifiers))
|
||||
|
@ -169,7 +172,7 @@
|
|||
(hooks/setup-viewport-size viewport-ref)
|
||||
(hooks/setup-cursor cursor alt? ctrl? space? panning drawing-tool drawing-path? node-editing?)
|
||||
(hooks/setup-keyboard alt? ctrl? space?)
|
||||
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected ctrl? hover hover-ids @hover-disabled? zoom)
|
||||
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected ctrl? hover hover-ids @hover-disabled? focus zoom)
|
||||
(hooks/setup-viewport-modifiers modifiers base-objects)
|
||||
(hooks/setup-shortcuts node-editing? drawing-path?)
|
||||
(hooks/setup-active-frames base-objects vbox hover active-frames)
|
||||
|
@ -253,8 +256,12 @@
|
|||
[:& outline/shape-outlines
|
||||
{:objects base-objects
|
||||
:selected selected
|
||||
:hover (when (or @ctrl? (not= :frame (:type @hover)))
|
||||
#{(or @frame-hover (:id @hover))})
|
||||
:hover (cond
|
||||
(and @hover (or @ctrl? (not= :frame (:type @hover))))
|
||||
#{(:id @hover)}
|
||||
|
||||
@frame-hover
|
||||
#{@frame-hover})
|
||||
:edition edition
|
||||
:zoom zoom}])
|
||||
|
||||
|
@ -313,7 +320,8 @@
|
|||
[:& frame-grid/frame-grid
|
||||
{:zoom zoom
|
||||
:selected selected
|
||||
:transform transform}])
|
||||
:transform transform
|
||||
:focus focus}])
|
||||
|
||||
(when show-pixel-grid?
|
||||
[:& widgets/pixel-grid
|
||||
|
@ -329,6 +337,7 @@
|
|||
:page-id page-id
|
||||
:selected selected
|
||||
:objects base-objects
|
||||
:focus focus
|
||||
:modifiers modifiers}])
|
||||
|
||||
(when show-snap-distance?
|
||||
|
|
|
@ -80,13 +80,14 @@
|
|||
|
||||
(mf/defc frame-grid
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [zoom transform selected]}]
|
||||
[{:keys [zoom transform selected focus]}]
|
||||
(let [frames (mf/deref refs/workspace-frames)
|
||||
moving (when (= :move transform) selected)
|
||||
is-moving? #(contains? moving (:id %))]
|
||||
|
||||
[:g.grid-display {:style {:pointer-events "none"}}
|
||||
(for [frame (remove is-moving? frames)]
|
||||
[:& grid-display-frame {:key (str "grid-" (:id frame))
|
||||
:zoom zoom
|
||||
:frame (gsh/transform-shape frame)}])]))
|
||||
(when (or (empty? focus) (contains? focus (:id frame)))
|
||||
[:& grid-display-frame {:key (str "grid-" (:id frame))
|
||||
:zoom zoom
|
||||
:frame (gsh/transform-shape frame)}]))]))
|
||||
|
|
|
@ -428,6 +428,8 @@
|
|||
(vals)
|
||||
(filter (guide-inside-vbox? vbox))))
|
||||
|
||||
focus (mf/deref refs/workspace-focus-selected)
|
||||
|
||||
hover-frame-ref (mf/use-ref nil)
|
||||
|
||||
;; We use the ref to not redraw every guide everytime the hovering frame change
|
||||
|
@ -464,12 +466,15 @@
|
|||
:disabled-guides? disabled-guides?}]
|
||||
|
||||
(for [current guides]
|
||||
[:& guide {:key (str "guide-" (:id current))
|
||||
:guide current
|
||||
:vbox vbox
|
||||
:zoom zoom
|
||||
:frame-modifier (get modifiers (:frame-id current))
|
||||
:get-hover-frame get-hover-frame
|
||||
:on-guide-change on-guide-change
|
||||
:disabled-guides? disabled-guides?}])]))
|
||||
(when (or (nil? (:frame-id current))
|
||||
(empty? focus)
|
||||
(contains? focus (:frame-id current)))
|
||||
[:& guide {:key (str "guide-" (:id current))
|
||||
:guide current
|
||||
:vbox vbox
|
||||
:zoom zoom
|
||||
:frame-modifier (get modifiers (:frame-id current))
|
||||
:get-hover-frame get-hover-frame
|
||||
:on-guide-change on-guide-change
|
||||
:disabled-guides? disabled-guides?}]))]))
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.shortcuts :as dsc]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -97,13 +98,14 @@
|
|||
(some #(cph/is-parent? objects % group-id))
|
||||
(not))))
|
||||
|
||||
(defn setup-hover-shapes [page-id move-stream objects transform selected ctrl? hover hover-ids hover-disabled? zoom]
|
||||
(defn setup-hover-shapes [page-id move-stream objects transform selected ctrl? hover hover-ids hover-disabled? focus zoom]
|
||||
(let [;; We use ref so we don't recreate the stream on a change
|
||||
zoom-ref (mf/use-ref zoom)
|
||||
ctrl-ref (mf/use-ref @ctrl?)
|
||||
transform-ref (mf/use-ref nil)
|
||||
selected-ref (mf/use-ref selected)
|
||||
hover-disabled-ref (mf/use-ref hover-disabled?)
|
||||
focus-ref (mf/use-ref focus)
|
||||
|
||||
query-point
|
||||
(mf/use-callback
|
||||
|
@ -157,6 +159,10 @@
|
|||
(mf/deps hover-disabled?)
|
||||
#(mf/set-ref-val! hover-disabled-ref hover-disabled?))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps focus)
|
||||
#(mf/set-ref-val! focus-ref focus))
|
||||
|
||||
(hooks/use-stream
|
||||
over-shapes-stream
|
||||
(mf/deps page-id objects @ctrl?)
|
||||
|
@ -166,6 +172,7 @@
|
|||
(contains? #{:group :bool} (get-in objects [id :type])))
|
||||
|
||||
selected (mf/ref-val selected-ref)
|
||||
focus (mf/ref-val focus-ref)
|
||||
|
||||
remove-xfm (mapcat #(cph/get-parent-ids objects %))
|
||||
remove-id? (cond-> (into #{} remove-xfm selected)
|
||||
|
@ -177,6 +184,8 @@
|
|||
|
||||
hover-shape (->> ids
|
||||
(filter (comp not remove-id?))
|
||||
(filter #(or (empty? focus)
|
||||
(cp/is-in-focus? objects focus %)))
|
||||
(first)
|
||||
(get objects))]
|
||||
(reset! hover hover-shape)
|
||||
|
|
|
@ -151,15 +151,16 @@
|
|||
|
||||
(mf/defc snap-points
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [layout zoom objects selected page-id drawing transform modifiers] :as props}]
|
||||
[{:keys [layout zoom objects selected page-id drawing transform modifiers focus] :as props}]
|
||||
(us/assert set? selected)
|
||||
(let [shapes (into [] (keep (d/getf objects)) selected)
|
||||
|
||||
filter-shapes
|
||||
(into selected (mapcat #(cph/get-children-ids objects %)) selected)
|
||||
|
||||
remove-snap? (mf/with-memo [layout filter-shapes]
|
||||
(snap/make-remove-snap layout filter-shapes))
|
||||
remove-snap?
|
||||
(mf/with-memo [layout filter-shapes objects focus]
|
||||
(snap/make-remove-snap layout filter-shapes objects focus))
|
||||
|
||||
shapes (if drawing [drawing] shapes)]
|
||||
(when (or drawing transform)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.viewport.widgets
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
|
@ -165,7 +166,8 @@
|
|||
|
||||
[:g.frame-titles
|
||||
(for [frame frames]
|
||||
[:& frame-title {:frame frame
|
||||
[:& frame-title {:key (dm/str "frame-title-" (:id frame))
|
||||
:frame frame
|
||||
:selected? (contains? selected (:id frame))
|
||||
:zoom zoom
|
||||
:show-artboard-names? show-artboard-names?
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
(mapv #(array-map
|
||||
:type :guide
|
||||
:id (:id guide)
|
||||
:frame-id (:frame-id guide)
|
||||
:pt %)))]
|
||||
(if-let [frame-id (:frame-id guide)]
|
||||
;; Guide inside frame, we add the information only on that frame
|
||||
|
|
|
@ -3543,3 +3543,15 @@ msgstr "Update"
|
|||
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
msgstr "Click to close the path"
|
||||
|
||||
msgid "workspace.focus.selection"
|
||||
msgstr "Selection"
|
||||
|
||||
msgid "workspace.focus.focus-mode"
|
||||
msgstr "Focus mode"
|
||||
|
||||
msgid "workspace.focus.focus-on"
|
||||
msgstr "Focus on"
|
||||
|
||||
msgid "workspace.focus.focus-off"
|
||||
msgstr "Focus off"
|
||||
|
|
|
@ -3557,3 +3557,15 @@ msgstr "Actualizar"
|
|||
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
msgstr "Pulsar para cerrar la ruta"
|
||||
|
||||
msgid "workspace.focus.selection"
|
||||
msgstr "Selección"
|
||||
|
||||
msgid "workspace.focus.focus-mode"
|
||||
msgstr "Modo foco"
|
||||
|
||||
msgid "workspace.focus.focus-on"
|
||||
msgstr "Activar modo foco"
|
||||
|
||||
msgid "workspace.focus.focus-off"
|
||||
msgstr "Desactivar modo foco"
|
||||
|
|
Loading…
Add table
Reference in a new issue