diff --git a/CHANGES.md b/CHANGES.md index 05c503720..3189658d0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,9 @@ - Fix shortcuts for zoom now take into account the mouse position [#2924](https://github.com/penpot/penpot/issues/2924) - Fix close colorpicker on Firefox when mouse-up is outside the picker [#2911](https://github.com/penpot/penpot/issues/2911) - Fix problems with touch devices and Wacom tablets [#2216](https://github.com/penpot/penpot/issues/2216) +- Fix problem with board titles misplaced [Taiga #4738](https://tree.taiga.io/project/penpot/issue/4738) +- Fix problem with alt getting stuck when alt+tab [Taiga #5013](https://tree.taiga.io/project/penpot/issue/5013) +- Fix problem with z positioning of elements [Taiga #5014](https://tree.taiga.io/project/penpot/issue/5014) ### :heart: Community contributions by (Thank you!) - To @ondrejkonec: for contributing to the code with: diff --git a/backend/src/app/http/websocket.clj b/backend/src/app/http/websocket.clj index f06fd1d7c..1db238d2e 100644 --- a/backend/src/app/http/websocket.clj +++ b/backend/src/app/http/websocket.clj @@ -204,7 +204,7 @@ (a/! output-ch message) (recur)))) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 94eed9c10..5f281a890 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -148,17 +148,17 @@ [base idx-a idx-b])) (defn is-shape-over-shape? - [objects base-shape-id over-shape-id] + [objects base-shape-id over-shape-id bottom-frames?] (let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)] (cond - ;; The base the base shape, so the other item is bellow + ;; The base the base shape, so the other item is bellow (if not bottom-frames) (= base base-shape-id) - false + (and bottom-frames? (cph/frame-shape? objects base)) - ;; The base is the testing over, so it's over + ;; The base is the testing over, so it's over (if not bottom-frames) (= base over-shape-id) - true + (or (not bottom-frames?) (not (cph/frame-shape? objects base))) ;; Check which index is lower :else @@ -177,29 +177,19 @@ ([objects ids] (sort-z-index objects ids nil)) - ([objects ids {:keys [bottom-frames?] :as options}] - (letfn [(comp [id-a id-b] - (let [frame-a? (= :frame (dm/get-in objects [id-a :type])) - frame-b? (= :frame (dm/get-in objects [id-b :type]))] - (cond - (= id-a id-b) - 0 + ([objects ids {:keys [bottom-frames?] :as options + :or {bottom-frames? false}}] + (letfn [ + (comp [id-a id-b] + (cond + (= id-a id-b) + 0 - (and (not frame-a?) frame-b?) - (if bottom-frames? -1 1) + (is-shape-over-shape? objects id-a id-b bottom-frames?) + 1 - (and frame-a? (not frame-b?)) - (if bottom-frames? 1 -1) - - ;; When comparing frames we invert the order if the flag `bottom-frames?` is on - (and frame-a? frame-b? bottom-frames?) - (if (is-shape-over-shape? objects id-b id-a) 1 -1) - - (is-shape-over-shape? objects id-b id-a) - -1 - - :else - 1)))] + :else + -1))] (sort comp ids)))) (defn frame-id-by-position diff --git a/frontend/resources/styles/main/partials/sidebar-layers.scss b/frontend/resources/styles/main/partials/sidebar-layers.scss index 15da99526..bd3d30a0d 100644 --- a/frontend/resources/styles/main/partials/sidebar-layers.scss +++ b/frontend/resources/styles/main/partials/sidebar-layers.scss @@ -433,6 +433,7 @@ span.element-name { background-color: $color-white; color: $color-gray-50; border-radius: $br4; + z-index: 1; span { padding: 10px 20px 10px 10px; border-radius: $br4; diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 18b5aa8f4..22de3463b 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1008,6 +1008,13 @@ ;; Navigation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defn workspace-focus-lost + [] + (ptk/reify ::workspace-focus-lost + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace-global :show-distances?] false)))) + (defn navigate-to-project [project-id] (ptk/reify ::navigate-to-project diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index 7002f8ea1..3a70a1b88 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -14,6 +14,8 @@ [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.persistence :as dwp] [app.main.streams :as ms] + [app.util.globals :refer [global]] + [app.util.object :as obj] [app.util.time :as dt] [beicon.core :as rx] [cljs.spec.alpha :as s] @@ -37,7 +39,8 @@ profile-id (:profile-id state) initmsg [{:type :subscribe-file - :file-id file-id} + :file-id file-id + :version (obj/get global "penpotVersion")} {:type :subscribe-team :team-id team-id}] @@ -130,7 +133,7 @@ }) (defn handle-presence - [{:keys [type session-id profile-id] :as message}] + [{:keys [type session-id profile-id version] :as message}] (letfn [(get-next-color [presence] (let [xfm (comp (map second) (map :color) @@ -149,6 +152,7 @@ (assoc :id session-id) (assoc :profile-id profile-id) (assoc :updated-at (dt/now)) + (assoc :version version) (update :color update-color presence) (assoc :text-color (if (contains? ["#00fa9a" "#ffd700" "#dda0dd" "#ffafda"] (update-color (:color presence) presence)) @@ -197,8 +201,9 @@ (-deref [_] {:changes changes}) ptk/WatchEvent - (watch [_ _ _] - (let [position-data-operation? + (watch [_ state _] + (let [page-id (:current-page-id state) + position-data-operation? (fn [{:keys [type attr]}] (and (= :set type) (= attr :position-data))) @@ -213,7 +218,8 @@ ;; Remove the position data from remote operations. Will be changed localy, otherwise ;; creates a strange "out-of-sync" behaviour. (cond-> change - (= :mod-obj (:type change)) + (and (= page-id (:page-id change)) + (= :mod-obj (:type change))) (update :operations #(d/removev position-data-operation? %)))) process-page-changes @@ -223,7 +229,10 @@ ;; We update `position-data` from the incoming message changes (->> changes (mapv update-position-data) - (d/removev :ignore-remote?)) + (d/removev (fn [change] + (and (= page-id (:page-id change)) + (:ignore-remote? change))))) + changes-by-pages (group-by :page-id changes)] (rx/merge diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index d9be83a3a..751ebdf8c 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace + (:import goog.events.EventType) (:require [app.common.colors :as clr] [app.common.data.macros :as dm] @@ -32,9 +33,11 @@ [app.main.ui.workspace.textpalette :refer [textpalette]] [app.main.ui.workspace.viewport :refer [viewport]] [app.util.dom :as dom] + [app.util.globals :as globals] [app.util.i18n :as i18n :refer [tr]] [app.util.object :as obj] [debug :refer [debug?]] + [goog.events :as events] [okulary.core :as l] [rumext.v2 :as mf])) @@ -136,7 +139,19 @@ components-v2 (features/use-feature :components-v2) - background-color (:background-color wglobal)] + background-color (:background-color wglobal) + + focus-out + (mf/use-callback + (fn [] + (st/emit! (dw/workspace-focus-lost))))] + + (mf/use-effect + (mf/deps focus-out) + (fn [] + (let [keys [(events/listen globals/document EventType.FOCUSOUT focus-out)]] + #(doseq [key keys] + (events/unlistenByKey key))))) ;; Setting the layout preset by its name (mf/with-effect [layout-name] diff --git a/frontend/src/app/main/ui/workspace/viewport/utils.cljs b/frontend/src/app/main/ui/workspace/viewport/utils.cljs index 750c79730..4768e0331 100644 --- a/frontend/src/app/main/ui/workspace/viewport/utils.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/utils.cljs @@ -8,7 +8,7 @@ (:require [app.common.data.macros :as dm] [app.common.geom.point :as gpt] - [app.common.geom.shapes :as gsh] + [app.common.math :as mth] [app.main.ui.cursors :as cur] [app.main.ui.formats :refer [format-number]])) @@ -42,7 +42,58 @@ (let [inv-zoom (/ 1 zoom)] (dm/fmt "scale(%, %) translate(%, %)" inv-zoom inv-zoom (* zoom x) (* zoom y)))) -(defn title-transform [{:keys [selrect] :as shape} zoom] - (let [transform (gsh/transform-str shape {:no-flip true}) - label-pos (gpt/point (:x selrect) (- (:y selrect) (/ 10 zoom)))] - (dm/str transform " " (text-transform label-pos zoom)))) +(defn left? + [cur cand] + (let [closex? (mth/close? (:x cand) (:x cur))] + (cond + (and closex? (< (:y cand) (:y cur))) cand + closex? cur + (< (:x cand) (:x cur)) cand + :else cur))) + +(defn top? + [cur cand] + (let [closey? (mth/close? (:y cand) (:y cur))] + (cond + (and closey? (< (:x cand) (:x cur))) cand + closey? cur + (< (:y cand) (:y cur)) cand + :else cur))) + +(defn right? + [cur cand] + (let [closex? (mth/close? (:x cand) (:x cur))] + (cond + (and closex? (< (:y cand) (:y cur))) cand + closex? cur + (> (:x cand) (:x cur)) cand + :else cur))) + +(defn title-transform [{:keys [points] :as shape} zoom] + (let [leftmost (->> points (reduce left?)) + topmost (->> points (remove #{leftmost}) (reduce top?)) + rightmost (->> points (remove #{leftmost topmost}) (reduce right?)) + + left-top (gpt/to-vec leftmost topmost) + left-top-angle (gpt/angle left-top) + + top-right (gpt/to-vec topmost rightmost) + top-right-angle (gpt/angle top-right) + + ;; Choose the position that creates the less angle between left-side and top-side + [label-pos angle v-pos] + (if (< (mth/abs left-top-angle) (mth/abs top-right-angle)) + [leftmost left-top-angle (gpt/perpendicular left-top)] + [topmost top-right-angle (gpt/perpendicular top-right)]) + + + label-pos + (gpt/subtract label-pos (gpt/scale (gpt/unit v-pos) (/ 10 zoom)))] + + (dm/fmt "rotate(% %,%) scale(%, %) translate(%, %)" + ;; rotate + angle (:x label-pos) (:y label-pos) + ;; scale + (/ 1 zoom) (/ 1 zoom) + ;; translate + (* zoom (:x label-pos)) (* zoom (:y label-pos)))))