0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-13 16:21:57 -05:00

Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
alonso.torres 2022-04-27 12:24:16 +02:00
commit f7dbb4f944
18 changed files with 190 additions and 100 deletions

View file

@ -7,6 +7,7 @@
(ns app.common.pages.helpers
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh]
[app.common.spec :as us]
[app.common.spec.page :as spec.page]
@ -92,7 +93,7 @@
"Returns a vector of parents of the specified shape."
[objects shape-id]
(loop [result [] id shape-id]
(if-let [parent-id (->> id (get objects) :parent-id)]
(if-let [parent-id (dm/get-in objects [id :parent-id])]
(recur (conj result parent-id) parent-id)
result)))

View file

@ -11,16 +11,17 @@
[app.common.uuid :as uuid]
[clojure.set :as set]))
(defn calculate-frame-z-index [z-index frame-id objects]
(defn calculate-frame-z-index
[z-index frame-id base-idx objects]
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
frame-shapes (->> objects (vals) (filterv #(= (:frame-id %) frame-id)))
children (or (get-in objects [frame-id :shapes]) [])]
(if (empty? children)
z-index
(loop [current (peek children)
pending (pop children)
current-idx (count frame-shapes)
current-idx base-idx
z-index z-index]
(let [children (get-in objects [current :shapes])
@ -46,10 +47,15 @@
[objects]
(let [frames (cph/get-frames objects)
z-index (calculate-frame-z-index {} uuid/zero objects)]
by-frame (cph/objects-by-frame objects)
frame-base-idx (d/update-vals by-frame count)
z-index (calculate-frame-z-index {} uuid/zero (get frame-base-idx uuid/zero) objects)]
(->> frames
(map :id)
(reduce #(calculate-frame-z-index %1 %2 objects) z-index))))
(reduce
(fn [z-index {:keys [id]}]
(calculate-frame-z-index z-index id (get frame-base-idx id) objects)) z-index))))
(defn update-z-index
"Updates the z-index given a set of ids to change and the old and new objects
@ -65,10 +71,13 @@
(map :id)
(filter #(contains? changed-frames %)))
z-index (calculate-frame-z-index z-index uuid/zero new-objects)]
by-frame (cph/objects-by-frame new-objects)
frame-base-idx (d/update-vals by-frame count)
z-index (calculate-frame-z-index z-index uuid/zero (get frame-base-idx uuid/zero) new-objects)]
(->> frames
(reduce #(calculate-frame-z-index %1 %2 new-objects) z-index))))
(reduce (fn [z-index id]
(calculate-frame-z-index z-index id (get frame-base-idx id) new-objects)) z-index))))
(defn generate-child-parent-index
[objects]
@ -84,10 +93,10 @@
(generate-child-all-parents-index objects (vals objects)))
([objects shapes]
(let [xf-parents (comp
(map :id)
(map #(vector % (cph/get-parent-ids objects %))))]
(into {} xf-parents shapes))))
(let [shape->entry
(fn [shape]
[(:id shape) (cph/get-parent-ids objects (:id shape))])]
(into {} (map shape->entry) shapes))))
(defn create-clip-index
"Retrieves the mask information for an object"

View file

@ -125,25 +125,34 @@
width: 100%;
height: 100%;
display: grid;
align-items: center;
grid-template-columns: auto 1fr auto;
grid-column-gap: 8px;
cursor: pointer;
& .back-button {
cursor: pointer;
background: none;
border: none;
transform: rotate(180deg);
padding: 0;
margin: 0;
& svg {
fill: $color-white;
transform: rotate(180deg);
margin-top: 3px;
}
&:hover {
svg {
fill: $color-primary;
}
}
}
& svg {
fill: $color-white;
}
& .focus-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
& .focus-mode {

View file

@ -115,17 +115,24 @@
(rx/filter (ptk/type? ::dwp/bundle-fetched))
(rx/take 1)
(rx/map deref)
(rx/mapcat (fn [bundle]
(let [team-id (-> bundle :project :team-id)]
(rx/merge
(rx/of (dwn/initialize team-id file-id)
(dwp/initialize-file-persistence file-id)
(dwc/initialize-indices bundle))
(rx/mapcat
(fn [bundle]
(rx/merge
(rx/of (dwc/initialize-indices bundle))
(->> stream
(rx/filter #(= ::dwc/index-initialized %))
(rx/take 1)
(rx/map #(file-initialized bundle))))))))))
(->> (rx/of bundle)
(rx/mapcat
(fn [bundle]
(let [bundle (assoc bundle :file (t/decode-str (:file-raw bundle)))
team-id (dm/get-in bundle [:project :team-id])]
(rx/merge
(rx/of (dwn/initialize team-id file-id)
(dwp/initialize-file-persistence file-id))
(->> stream
(rx/filter #(= ::dwc/index-initialized %))
(rx/take 1)
(rx/map #(file-initialized bundle))))))))))))))
ptk/EffectEvent
(effect [_ _ _]

View file

@ -48,13 +48,12 @@
;; --- Selection Index Handling
(defn initialize-indices
[{:keys [file] :as bundle}]
[{:keys [file-raw] :as bundle}]
(ptk/reify ::setup-selection-index
ptk/WatchEvent
(watch [_ _ _]
(let [msg {:cmd :initialize-indices
:file-id (:id file)
:data (:data file)}]
:file-raw file-raw}]
(->> (uw/ask! msg)
(rx/map (constantly ::index-initialized)))))))

View file

@ -251,8 +251,8 @@
(rp/query :project {:id project-id})
(rp/query :file-libraries {:file-id file-id}))
(rx/take 1)
(rx/map (fn [[file users project libraries]]
{:file file
(rx/map (fn [[file-raw users project libraries]]
{:file-raw file-raw
:users users
:project project
:libraries libraries}))

View file

@ -421,8 +421,11 @@
(assoc :position (if (= (:axis %) :x)
(+ (:position %) (- (:x new-frame) (:x frame)))
(+ (:position %) (- (:y new-frame) (:y frame))))))))]
(conj g
(into {} (map (juxt :id identity) new-guides)))))
(if-not (empty? new-guides)
(conj g
(into {} (map (juxt :id identity) new-guides)))
{})))
guides
frames)]
(-> (pcb/with-page changes page)

View file

@ -378,7 +378,7 @@
(update [_ state]
(-> state
(dissoc :workspace-modifiers)
(update :workspace-local dissoc :current-move-selected)))))
(dissoc ::current-move-selected)))))
;; -- Resize --------------------------------------------------------
@ -721,15 +721,15 @@
ptk/UpdateEvent
(update [_ state]
(if (nil? (get-in state [:workspace-local :current-move-selected]))
(if (nil? (get state ::current-move-selected))
(-> state
(assoc-in [:workspace-local :transform] :move)
(assoc-in [:workspace-local :current-move-selected] same-event))
(assoc ::current-move-selected same-event))
state))
ptk/WatchEvent
(watch [_ state stream]
(if (= same-event (get-in state [:workspace-local :current-move-selected]))
(if (= same-event (get state ::current-move-selected))
(let [selected (wsh/lookup-selected state {:omit-blocked? true})
nudge (get-in state [:profile :props :nudge] {:big 10 :small 1})
move-events (->> stream
@ -744,10 +744,10 @@
(rx/concat
(rx/merge
(->> move-events
(rx/take-until stopper)
(rx/scan #(gpt/add %1 mov-vec) (gpt/point 0 0))
(rx/map #(hash-map :displacement (gmt/translate-matrix %)))
(rx/map (partial set-modifiers selected)))
(rx/map (partial set-modifiers selected))
(rx/take-until stopper))
(rx/of (move-selected direction shift?)))
(rx/of (apply-modifiers selected)

View file

@ -35,8 +35,7 @@
(rx/throw {:type :validation
:code :request-body-too-large})
(and (>= status 400)
(map? body))
(and (>= status 400) (map? body))
(rx/throw body)
:else
@ -49,13 +48,19 @@
(defn- send-query!
"A simple helper for send and receive transit data on the penpot
query api."
[id params]
(->> (http/send! {:method :get
:uri (u/join base-uri "api/rpc/query/" (name id))
:credentials "include"
:query params})
(rx/map http/conditional-decode-transit)
(rx/mapcat handle-response)))
([id params]
(send-query! id params nil))
([id params {:keys [raw-transit?]}]
(let [decode-transit (if raw-transit?
identity
(partial rx/map http/conditional-decode-transit))]
(->> (http/send! {:method :get
:uri (u/join base-uri "api/rpc/query/" (name id))
:credentials "include"
:query params})
(decode-transit)
(rx/mapcat handle-response)))))
(defn- send-mutation!
"A simple helper for a common case of sending and receiving transit
@ -77,6 +82,10 @@
[id params]
(send-query! id params))
(defmethod query :file
[id params]
(send-query! id params {:raw-transit? true}))
(defmethod mutation :default
[id params]
(send-mutation! id params))

View file

@ -50,17 +50,17 @@
(let [mask (unchecked-get props "mask")
render-id (mf/use-ctx muc/render-ctx)
svg-text? (and (= :text (:type mask)) (some? (:position-data mask)))
;; This factory is generic, it's used for viewer, workspace and handoff.
;; These props are generated in viewer wrappers only, in the rest of the
;; cases these props will be nil, not affecting the code.
fixed? (unchecked-get props "fixed?")
delta (unchecked-get props "delta")
mask-for-bb (-> (gsh/transform-shape mask)
(cond-> fixed? (gsh/move delta)))
mask-bb (-> (gsh/transform-shape mask)
(cond-> fixed? (gsh/move delta))
(:points))
mask-bb (cond
svg-text? (gst/position-data-points mask-for-bb)
:else (:points mask-for-bb))]
mask-bb-rect (gsh/points->rect mask-bb)]
[:defs
[:filter {:id (filter-id render-id mask)}
[:feFlood {:flood-color "white"
@ -81,7 +81,12 @@
;; When te shape is a text we pass to the shape the info and disable the filter.
;; There is a bug in Firefox with filters and texts. We change the text to white at shape level
[:mask {:class "mask-shape"
:id (mask-id render-id mask)}
:id (mask-id render-id mask)
:x (:x mask-bb-rect)
:y (:y mask-bb-rect)
:width (:width mask-bb-rect)
:height (:height mask-bb-rect)
:mask-units "userSpaceOnUse"}
[:g {:filter (when-not svg-text? (filter-url render-id mask))}
[:& shape-wrapper {:shape (-> mask (dissoc :shadow :blur) (assoc :is-mask? true))}]]]])))

View file

@ -38,15 +38,13 @@
(mf/use-layout-effect
(mf/deps transforms)
(fn []
(when (and (nil? @prev-transforms)
(some? transforms))
(when (and (empty? @prev-modifiers) (d/not-empty? modifiers))
(utils/start-transform! node shapes))
(when (some? modifiers)
(when (d/not-empty? modifiers)
(utils/update-transform! node shapes transforms modifiers))
(when (and (some? @prev-modifiers)
(empty? modifiers))
(when (and (d/not-empty? @prev-modifiers) (empty? modifiers))
(utils/remove-transform! node @prev-shapes))
(reset! prev-modifiers modifiers)

View file

@ -498,11 +498,9 @@
[:div#layers.tool-window
(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-title {:on-click #(st/emit! (dw/toggle-focus-mode))}
[:button.back-button i/arrow-slide]
[:div.focus-name (or title (tr "workspace.focus.selection"))]
[:div.focus-mode (tr "workspace.focus.focus-mode")]]]
filter-component)

View file

@ -150,10 +150,14 @@
(when (or (= (dom/get-tag-name node) "mask")
(= (dom/get-tag-name node) "filter"))
(dom/set-attribute! node "data-old-x" (dom/get-attribute node "x"))
(dom/set-attribute! node "data-old-y" (dom/get-attribute node "y"))
(dom/set-attribute! node "data-old-width" (dom/get-attribute node "width"))
(dom/set-attribute! node "data-old-height" (dom/get-attribute node "height"))))))))
(let [old-x (dom/get-attribute node "x")
old-y (dom/get-attribute node "y")
old-width (dom/get-attribute node "width")
old-height (dom/get-attribute node "height")]
(dom/set-attribute! node "data-old-x" old-x)
(dom/set-attribute! node "data-old-y" old-y)
(dom/set-attribute! node "data-old-width" old-width)
(dom/set-attribute! node "data-old-height" old-height))))))))
(defn set-transform-att!
[node att value]
@ -208,10 +212,19 @@
;; The shape width/height will be automaticaly setup when the modifiers are applied
nil
(or (= (dom/get-tag-name node) "mask")
(= (dom/get-tag-name node) "filter"))
(do
(dom/remove-attribute! node "data-old-x")
(dom/remove-attribute! node "data-old-y")
(dom/remove-attribute! node "data-old-width")
(dom/remove-attribute! node "data-old-height"))
:else
(let [old-transform (dom/get-attribute node "data-old-transform")]
(when-not (some? old-transform)
(dom/remove-attribute! node "data-old-transform")
(if (some? old-transform)
(do (dom/remove-attribute! node "data-old-transform")
(dom/set-attribute! node "transform" old-transform))
(dom/remove-attribute! node "transform")))))))))
(defn format-viewbox [vbox]

View file

@ -7,10 +7,10 @@
(ns app.util.worker
"A lightweight layer on top of webworkers api."
(:require
[app.common.transit :as t]
[app.common.uuid :as uuid]
[app.util.globals :refer [global]]
[app.util.object :as obj]
[app.worker.messages :as wm]
[beicon.core :as rx]))
(declare handle-response)
@ -27,7 +27,7 @@
(rx/take-while #(not (:completed %)) ob)
(rx/take 1 ob)))
data (t/encode-str message)
data (wm/encode message)
instance (:instance worker)]
(if (some? instance)
@ -71,11 +71,10 @@
handle-message
(fn [event]
(let [data (.-data event)
data (t/decode-str data)]
(if (:error data)
(on-error (:error data))
(rx/push! bus data))))
(let [message (wm/decode (.-data event))]
(if (:error message)
(on-error (:error message))
(rx/push! bus message))))
handle-error
(fn [error]

View file

@ -8,10 +8,10 @@
(:require
[app.common.logging :as log]
[app.common.spec :as us]
[app.common.transit :as t]
[app.worker.export]
[app.worker.impl :as impl]
[app.worker.import]
[app.worker.messages :as wm]
[app.worker.selection]
[app.worker.snaps]
[app.worker.thumbnails]
@ -46,7 +46,7 @@
[{:keys [sender-id payload] :as message}]
(us/assert ::message message)
(letfn [(post [msg]
(let [msg (-> msg (assoc :reply-to sender-id) (t/encode-str))]
(let [msg (-> msg (assoc :reply-to sender-id) (wm/encode))]
(.postMessage js/self msg)))
(reply [result]
@ -91,8 +91,8 @@
"Sends to the client a notification that its messages have been dropped"
[{:keys [sender-id] :as message}]
(us/assert ::message message)
(.postMessage js/self (t/encode-str {:reply-to sender-id
:dropped true})))
(.postMessage js/self (wm/encode {:reply-to sender-id
:dropped true})))
(defn subscribe-buffer-messages
"Creates a subscription to process the buffer messages"
@ -150,7 +150,7 @@
[event]
(when (nil? (.-source event))
(let [message (.-data event)
message (t/decode-str message)]
message (wm/decode message)]
(if (:buffer? message)
(rx/push! buffer message)
(handle-message message)))))

View file

@ -7,6 +7,7 @@
(ns app.worker.impl
(:require
[app.common.pages.changes :as ch]
[app.common.transit :as t]
[app.util.globals :refer [global]]
[app.util.object :as obj]
[okulary.core :as l]))
@ -28,14 +29,15 @@
message)
(defmethod handler :initialize-indices
[{:keys [data] :as message}]
[{:keys [file-raw] :as message}]
(reset! state data)
(handler (-> message
(assoc :cmd :selection/initialize-index)))
(handler (-> message
(assoc :cmd :snaps/initialize-index))))
(let [data (-> (t/decode-str file-raw) :data)
message (assoc message :data data)]
(reset! state data)
(handler (-> message
(assoc :cmd :selection/initialize-index)))
(handler (-> message
(assoc :cmd :snaps/initialize-index)))))
(defmethod handler :update-page-indices
[{:keys [page-id changes] :as message}]

View file

@ -0,0 +1,36 @@
;; 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.worker.messages
"A lightweight layer on top of webworkers api."
(:require
[app.common.data :as d]
[app.common.transit :as t]
[app.util.object :as obj]))
(defn encode [{:keys [sender-id reply-to payload buffer?] :as message}]
#js {:cmd (d/name (:cmd payload))
:senderId (when sender-id (str sender-id))
:replyTo (when reply-to (str reply-to))
:payload (if (= :initialize-indices (:cmd payload))
(:file-raw payload)
(when (some? payload) (t/encode-str payload)))
:buffer (when (some? buffer?) buffer?)})
(defn decode [^js data]
(let [cmd (obj/get data "cmd")
sender-id (obj/get data "senderId")
reply-to (obj/get data "replyTo")
payload (obj/get data "payload")
buffer (obj/get data "buffer")]
(d/without-nils
{:sender-id (when sender-id (uuid sender-id))
:reply-to (when reply-to (uuid reply-to))
:payload (if (= cmd "initialize-indices")
{:cmd :initialize-indices
:file-raw payload}
(when (some? payload) (t/decode-str payload)))
:buffer? buffer})))

View file

@ -21,7 +21,7 @@
(defonce state (l/atom {}))
(defn index-shape
(defn make-index-shape
[objects parents-index clip-parents-index]
(fn [index shape]
(let [{:keys [x y width height]}
@ -77,13 +77,16 @@
(let [shapes (-> objects (dissoc uuid/zero) vals)
parents-index (cp/generate-child-all-parents-index objects)
clip-parents-index (cp/create-clip-index objects parents-index)
bounds (-> objects objects-bounds add-padding-bounds)
index (reduce (index-shape objects parents-index clip-parents-index)
(qdt/create (clj->js bounds))
shapes)
root-shapes (cph/get-immediate-children objects uuid/zero)
bounds (-> root-shapes gsh/selection-rect add-padding-bounds)
z-index (cp/calculate-z-index objects)]
index-shape (make-index-shape objects parents-index clip-parents-index)
initial-quadtree (qdt/create (clj->js bounds))
index (reduce index-shape initial-quadtree shapes)
z-index (cp/calculate-z-index objects)]
{:index index :z-index z-index :bounds bounds}))
@ -106,9 +109,8 @@
new-index (qdt/remove-all index changed-ids)
index (reduce (index-shape new-objects parents-index clip-parents-index)
new-index
shapes)
index-shape (make-index-shape new-objects parents-index clip-parents-index)
index (reduce index-shape new-index shapes)
z-index (cp/update-z-index z-index changed-ids old-objects new-objects)]