0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-15 17:21:17 -05:00

Merge remote-tracking branch 'origin/staging'

This commit is contained in:
Alejandro Alonso 2022-08-31 08:56:54 +02:00
commit 2cb8e7b986
12 changed files with 87 additions and 306 deletions

View file

@ -1,5 +1,12 @@
# CHANGELOG
## 1.15.2-beta
### :bug: Bugs fixed
- Fix problem with multi-user text editing [Taiga #3446](https://tree.taiga.io/project/penpot/issue/3446)
- Fix path tools blocking elements underneath [#2050](https://github.com/penpot/penpot/issues/2050)
- Fix frame titles deforming when resize [#2207](https://github.com/penpot/penpot/issues/2207)
## 1.15.1-beta
@ -11,6 +18,7 @@
- Fix validation error on text position [Taiga #4010](https://tree.taiga.io/project/penpot/issue/4010)
- Fix objects jitter while scrolling [Github #2167](https://github.com/penpot/penpot/issues/2167)
- Fix on color-picker, click+drag adds lots of recent colors [Taiga #4013](https://tree.taiga.io/project/penpot/issue/4013)
- Fix opening profile URL while signed out takes to "your account" section[Taiga #3976](https://tree.taiga.io/project/penpot/issue/3976)
## 1.15.0-beta

View file

@ -160,12 +160,12 @@
([shape]
(transform-str shape nil))
([{:keys [transform flip-x flip-y] :as shape} {:keys [no-flip]}]
([{:keys [transform flip-x flip-y] :as shape} {:keys [no-flip] :as params}]
(if (and (some? shape)
(or (some? transform)
(and (not no-flip) flip-x)
(and (not no-flip) flip-y)))
(dm/str (transform-matrix shape))
(dm/str (transform-matrix shape params))
"")))
(defn inverse-transform-matrix

View file

@ -352,9 +352,10 @@ $height-palette-max: 80px;
position: absolute;
width: 100%;
z-index: 12;
pointer-events: initial;
pointer-events: none;
.path-actions {
pointer-events: initial;
display: flex;
flex-direction: row;
background: white;

View file

@ -203,18 +203,24 @@
(fn [{:keys [type attr]}]
(and (= :set type) (= attr :position-data)))
remove-update-position-data
add-origin-session-id
(fn [{:keys [] :as op}]
(cond-> op
(position-data-operation? op)
(update :val with-meta {:session-id (:session-id msg)})))
update-position-data
(fn [change]
(cond-> change
(= :mod-obj (:type change))
(update :operations #(filterv (comp not position-data-operation?) %))))
(update :operations #(mapv add-origin-session-id %))))
process-page-changes
(fn [[page-id changes]]
(dch/update-indices page-id changes))
;; We remove `position-data` from the incomming message
changes (->> changes (mapv remove-update-position-data))
;; We update `position-data` from the incomming message
changes (->> changes (mapv update-position-data))
changes-by-pages (group-by :page-id changes)]
(rx/merge

View file

@ -7,14 +7,16 @@
(ns app.main.ui.settings
(:require
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.settings.change-email]
[app.main.ui.settings.delete-account]
[app.main.ui.settings.feedback :refer [feedback-page]]
[app.main.ui.settings.options :refer [options-page]]
[app.main.ui.settings.password :refer [password-page]]
[app.main.ui.settings.profile :refer [profile-page]]
[app.main.ui.settings.sidebar :refer [sidebar]]
[app.util.i18n :as i18n :refer [tr]]
[app.main.ui.settings.sidebar :refer [sidebar]]
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
[rumext.alpha :as mf]))
(mf/defc header
@ -29,6 +31,10 @@
(let [section (get-in route [:data :name])
profile (mf/deref refs/profile)
locale (mf/deref i18n/locale)]
(mf/use-effect
#(when (nil? profile)
(st/emit! (rt/nav :auth-login))))
[:section.dashboard-layout
[:& sidebar {:profile profile
:locale locale

View file

@ -11,6 +11,8 @@
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.main.store :as st]
[app.main.ui.workspace.viewport.utils :as vwu]
[app.util.dom :as dom]
[rumext.alpha :as mf]))
@ -202,6 +204,12 @@
(gsh/transform-matrix {:no-flip true}))]
(override-transform-att! node "transform" mtx))))
(dom/class? node "frame-title")
(let [shape (-> shape (assoc :modifiers modifiers) gsh/transform-shape)
zoom (get-in @st/state [:workspace-local :zoom] 1)
mtx (vwu/title-transform shape zoom)]
(override-transform-att! node "transform" mtx))
(or (= (dom/get-tag-name node) "mask")
(= (dom/get-tag-name node) "filter"))
(transform-region! node modifiers)

View file

@ -268,7 +268,11 @@
text-modifier
(mf/deref text-modifier-ref)
bounding-box (gsht/position-data-bounding-box (or text-modifier shape))
shape (cond-> shape
(some? text-modifier)
(dwt/apply-text-modifier text-modifier))
bounding-box (gsht/position-data-bounding-box shape)
x (min (:x bounding-box) (:x shape))
y (min (:y bounding-box) (:y shape))

View file

@ -1,258 +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.workspace.shapes.text.viewport-texts
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.text :as gsht]
[app.common.math :as mth]
[app.common.pages.helpers :as cph]
[app.common.text :as txt]
[app.main.data.workspace.texts :as dwt]
[app.main.fonts :as fonts]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.hooks :as hooks]
[app.main.ui.shapes.text.fo-text :as fo]
[app.util.dom :as dom]
[app.util.object :as obj]
[app.util.text-editor :as ted]
[app.util.text-svg-position :as tsp]
[app.util.timers :as ts]
[promesa.core :as p]
[rumext.alpha :as mf]))
(defn strip-position-data [shape]
(dissoc shape :position-data :transform :transform-inverse))
(defn strip-modifier
[modifier]
(if (or (some? (dm/get-in modifier [:modifiers :resize-vector]))
(some? (dm/get-in modifier [:modifiers :resize-vector-2])))
modifier
(d/update-when modifier :modifiers dissoc :displacement :rotation)))
(defn process-shape [modifiers {:keys [id] :as shape}]
(let [modifier (-> (get modifiers id) strip-modifier)
shape (cond-> shape
(not (gsh/empty-modifiers? (:modifiers modifier)))
(-> (assoc :grow-type :fixed)
(merge modifier) gsh/transform-shape))]
(-> shape
(cond-> (nil? (:position-data shape))
(assoc :migrate true))
strip-position-data)))
(defn- update-with-editor-state
"Updates the shape with the current state in the editor"
[shape editor-state]
(let [content (:content shape)
editor-content
(when editor-state
(-> editor-state
(ted/get-editor-current-content)
(ted/export-content)))]
(cond-> shape
(and (some? shape) (some? editor-content))
(assoc :content (d/txt-merge content editor-content)))))
(defn- update-text-shape
[{:keys [grow-type id migrate] :as shape} node]
;; Check if we need to update the size because it's auto-width or auto-height
;; Update the position-data of every text fragment
(p/let [position-data (tsp/calc-position-data id)]
;; At least one paragraph needs to be inside the bounding box
(when (gsht/overlaps-position-data? shape position-data)
(st/emit! (dwt/update-position-data id position-data)))
(when (contains? #{:auto-height :auto-width} grow-type)
(let [{:keys [width height]}
(-> (dom/query node ".paragraph-set")
(dom/get-client-size))
width (mth/ceil width)
height (mth/ceil height)]
(when (and (not (mth/almost-zero? width))
(not (mth/almost-zero? height))
(not migrate))
(st/emit! (dwt/resize-text id width height)))))
(st/emit! (dwt/clean-text-modifier id))))
(defn- update-text-modifier
[{:keys [grow-type id]} node]
(p/let [position-data (tsp/calc-position-data id)
props {:position-data position-data}
props
(if (contains? #{:auto-height :auto-width} grow-type)
(let [{:keys [width height]} (-> (dom/query node ".paragraph-set") (dom/get-client-size))
width (mth/ceil width)
height (mth/ceil height)]
(if (and (not (mth/almost-zero? width)) (not (mth/almost-zero? height)))
(assoc props :width width :height height)
props))
props)]
(st/emit! (dwt/update-text-modifier id props))))
(mf/defc text-container
{::mf/wrap-props false
::mf/wrap [mf/memo]}
[props]
(let [shape (obj/get props "shape")
on-update (obj/get props "on-update")
handle-update
(mf/use-callback
(mf/deps shape on-update)
(fn [node]
(when (some? node)
(on-update shape node))))]
[:& fo/text-shape {:key (str "shape-" (:id shape))
:ref handle-update
:shape shape
:grow-type (:grow-type shape)}]))
(mf/defc viewport-texts-wrapper
{::mf/wrap-props false
::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[props]
(let [text-shapes (obj/get props "text-shapes")
modifiers (obj/get props "modifiers")
prev-modifiers (hooks/use-previous modifiers)
prev-text-shapes (hooks/use-previous text-shapes)
;; A change in position-data won't be a "real" change
text-change?
(fn [id]
(let [old-shape (get prev-text-shapes id)
new-shape (get text-shapes id)
old-modifiers (-> (get prev-modifiers id) strip-modifier)
new-modifiers (-> (get modifiers id) strip-modifier)]
(or (and (not (identical? old-shape new-shape))
(not= (dissoc old-shape :migrate :position-data)
(dissoc new-shape :migrate :position-data)))
(not= new-modifiers old-modifiers)
;; When the position data is nil we force to recalculate
(:migrate new-shape))))
changed-texts
(mf/use-memo
(mf/deps text-shapes modifiers)
#(->> (keys text-shapes)
(filter text-change?)
(map (d/getf text-shapes))))
handle-update-modifier (mf/use-callback update-text-modifier)
handle-update-shape (mf/use-callback update-text-shape)]
[:*
(for [{:keys [id] :as shape} changed-texts]
[:& text-container {:shape (gsh/transform-shape shape)
:on-update (if (some? (get modifiers (:id shape)))
handle-update-modifier
handle-update-shape)
:key (str (dm/str "text-container-" id))}])]))
(mf/defc viewport-text-editing
{::mf/wrap-props false}
[props]
(let [shape (obj/get props "shape")
;; Join current objects with the state of the editor
editor-state
(-> (mf/deref refs/workspace-editor-state)
(get (:id shape)))
text-modifier-ref
(mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape)))
text-modifier
(mf/deref text-modifier-ref)
shape (cond-> shape
(some? editor-state)
(update-with-editor-state editor-state))
;; When we have a text with grow-type :auto-height we need to check the correct height
;; otherwise the center alignment will break
shape
(if (or (not= :auto-height (:grow-type shape)) (empty? text-modifier))
shape
(let [tr-shape (dwt/apply-text-modifier shape text-modifier)]
(cond-> shape
;; we only change the height otherwise could cause problems with the other fields
(some? text-modifier)
(assoc :height (:height tr-shape)))))
shape (hooks/use-equal-memo shape)
handle-update-shape (mf/use-callback update-text-modifier)]
(mf/use-effect
(mf/deps (:id shape))
(fn []
#(st/emit! (dwt/remove-text-modifier (:id shape)))))
[:& text-container {:shape shape
:on-update handle-update-shape}]))
(defn check-props
[new-props old-props]
(and (identical? (unchecked-get new-props "objects")
(unchecked-get old-props "objects"))
(identical? (unchecked-get new-props "modifiers")
(unchecked-get old-props "modifiers"))
(= (unchecked-get new-props "edition")
(unchecked-get old-props "edition"))))
(mf/defc viewport-texts
{::mf/wrap-props false
::mf/wrap [#(mf/memo' % check-props)]}
[props]
(let [objects (obj/get props "objects")
edition (obj/get props "edition")
modifiers (obj/get props "modifiers")
text-shapes
(mf/use-memo
(mf/deps objects)
#(into {} (filter (comp cph/text-shape? second)) objects))
text-shapes
(mf/use-memo
(mf/deps text-shapes modifiers)
#(d/update-vals text-shapes (partial process-shape modifiers)))
editing-shape (get text-shapes edition)
;; This memo is necesary so the viewport-text-wrapper memoize its props correctly
text-shapes-wrapper
(mf/use-memo
(mf/deps text-shapes edition)
(fn []
(dissoc text-shapes edition)))]
;; We only need the effect to run on "mount" because the next fonts will be changed when the texts are
;; edited
(mf/use-effect
(fn []
(let [text-nodes (->> text-shapes (vals)(mapcat #(txt/node-seq txt/is-text-node? (:content %))))
fonts (into #{} (keep :font-id) text-nodes)]
(run! fonts/ensure-loaded! fonts))))
[:*
(when editing-shape
[:& viewport-text-editing {:shape editing-shape}])
[:& viewport-texts-wrapper {:text-shapes text-shapes-wrapper
:modifiers modifiers}]]))

View file

@ -28,7 +28,10 @@
[rumext.alpha :as mf]))
(defn strip-position-data [shape]
(dissoc shape :position-data :transform :transform-inverse))
(-> shape
(cond-> (some? (meta (:position-data shape)))
(with-meta (meta (:position-data shape))))
(dissoc :position-data :transform :transform-inverse)))
(defn strip-modifier
[modifier]
@ -131,14 +134,17 @@
;; A change in position-data won't be a "real" change
text-change?
(fn [id]
(let [old-shape (get prev-text-shapes id)
new-shape (get text-shapes id)
(let [new-shape (get text-shapes id)
old-shape (get prev-text-shapes id)
old-modifiers (-> (get prev-modifiers id) strip-modifier)
new-modifiers (-> (get modifiers id) strip-modifier)]
new-modifiers (-> (get modifiers id) strip-modifier)
(or (and (not (identical? old-shape new-shape))
(not= (dissoc old-shape :migrate :position-data)
(dissoc new-shape :migrate :position-data)))
remote? (some? (-> new-shape meta :session-id)) ]
(or (and (not remote?)
(not (identical? old-shape new-shape))
(not= (dissoc old-shape :migrate)
(dissoc new-shape :migrate)))
(not= new-modifiers old-modifiers)
;; When the position data is nil we force to recalculate

View file

@ -9,6 +9,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.main.ui.cursors :as cur]
[app.main.ui.formats :refer [format-number]]
[app.util.dom :as dom]))
@ -45,3 +46,18 @@
:zoom-in cur/zoom-in
:zooom-out cur/zoom-out
cur/pointer-inner))
;; Ensure that the label has always the same font
;; size, regardless of zoom
;; https://css-tricks.com/transforms-on-svg-elements/
(defn text-transform
[{:keys [x y]} zoom]
(let [inv-zoom (/ 1 zoom)]
(str
"scale(" inv-zoom ", " inv-zoom ") "
"translate(" (* zoom x) ", " (* zoom y) ")")))
(defn title-transform [frame zoom]
(let [frame-transform (gsh/transform-str frame {:no-flip true})
label-pos (gpt/point (:x frame) (- (:y frame) (/ 10 zoom)))]
(dm/str frame-transform " " (text-transform label-pos zoom))))

View file

@ -20,6 +20,7 @@
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.workspace.viewport.path-actions :refer [path-actions]]
[app.main.ui.workspace.viewport.utils :as vwu]
[app.util.dom :as dom]
[rumext.alpha :as mf]))
@ -82,25 +83,11 @@
:stroke "rgb(49, 239, 184)"
:stroke-width (/ 1 zoom)}}]))
;; Ensure that the label has always the same font
;; size, regardless of zoom
;; https://css-tricks.com/transforms-on-svg-elements/
(defn text-transform
[{:keys [x y]} zoom]
(let [inv-zoom (/ 1 zoom)]
(str
"scale(" inv-zoom ", " inv-zoom ") "
"translate(" (* zoom x) ", " (* zoom y) ")")))
(mf/defc frame-title
{::mf/wrap [mf/memo]}
[{:keys [frame selected? zoom show-artboard-names? on-frame-enter on-frame-leave on-frame-select]}]
(let [{:keys [width x y]} frame
label-pos (gpt/point x (- y (/ 10 zoom)))
frame-transform (gsh/transform-str frame)
on-mouse-down
(let [on-mouse-down
(mf/use-callback
(mf/deps (:id frame) on-frame-select)
(fn [bevent]
@ -140,23 +127,22 @@
text-pos-x (if (:use-for-thumbnail? frame) 15 0)]
(when (not (:hidden frame))
[:g {:id (dm/str "frame-title-" (:id frame))}
[:g.frame-title {:id (dm/str "frame-title-" (:id frame)) :transform (vwu/title-transform frame zoom)}
(when (:use-for-thumbnail? frame)
[:g {:transform (dm/str frame-transform " " (text-transform label-pos zoom))}
[:svg {:x 0
:y -9
:width 12
:height 12
:class "workspace-frame-icon"
:style {:fill (when selected? "var(--color-primary-dark)")}
:visibility (if show-artboard-names? "visible" "hidden")}
[:use {:href "#icon-set-thumbnail"}]]])
[:svg {:x 0
:y -9
:width 12
:height 12
:class "workspace-frame-icon"
:style {:fill (when selected? "var(--color-primary-dark)")}
:visibility (if show-artboard-names? "visible" "hidden")}
[:use {:href "#icon-set-thumbnail"}]])
[:text {:x text-pos-x
:y 0
:width width
:width (:width frame)
:height 20
:class "workspace-frame-label"
:transform (dm/str frame-transform " " (text-transform label-pos zoom))
;:transform (dm/str frame-transform " " (text-transform label-pos zoom))
:style {:fill (when selected? "var(--color-primary-dark)")}
:visibility (if show-artboard-names? "visible" "hidden")
:on-mouse-down on-mouse-down
@ -172,7 +158,6 @@
[props]
(let [objects (unchecked-get props "objects")
zoom (unchecked-get props "zoom")
modifiers (unchecked-get props "modifiers")
selected (or (unchecked-get props "selected") #{})
show-artboard-names? (unchecked-get props "show-artboard-names?")
on-frame-enter (unchecked-get props "on-frame-enter")
@ -188,7 +173,6 @@
:selected? (contains? selected (:id frame))
:zoom zoom
:show-artboard-names? show-artboard-names?
:modifiers modifiers
:on-frame-enter on-frame-enter
:on-frame-leave on-frame-leave
:on-frame-select on-frame-select}]))]))
@ -231,7 +215,7 @@
:height 24
:transform (str (when (and selected? modifiers)
(str (:displacement modifiers) " " ))
(text-transform flow-pos zoom))}
(vwu/text-transform flow-pos zoom))}
[:div.flow-badge {:class (dom/classnames :selected selected?)}
[:div.content {:on-mouse-down on-mouse-down
:on-double-click on-double-click

View file

@ -1 +1 @@
1.15.1-beta
1.15.2-beta