diff --git a/CHANGES.md b/CHANGES.md index 9ff579c97..519a5ccdc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,10 +20,19 @@ ### :bug: Bugs fixed +- Fix unexpected exception related to default nudge value - Fix firefox changing layer color type is not applied [Taiga #4292](https://tree.taiga.io/project/penpot/issue/4292) - Fix justify alignes text left [Taiga #4322](https://tree.taiga.io/project/penpot/issue/4322) - Fix text out of borders with "auto width" and center align [Taiga #4308](https://tree.taiga.io/project/penpot/issue/4308) +- Fix wrong validation text after interaction with 2 and more files [Taiga #4276](https://tree.taiga.io/project/penpot/issue/4276) - Fix auto-width for texts can make text appear stretched [Github #2482](https://github.com/penpot/penpot/issues/2482) +- Fix boards name do not disappear in focus mode [#4272](https://tree.taiga.io/project/penpot/issue/4272) +- Fix wrong email in the info message at change email [Taiga #4274](https://tree.taiga.io/project/penpot/issue/4274) +- Fix transform to path RMB menu item is not relevant if shape is already path [Taiga #4302](https://tree.taiga.io/project/penpot/issue/4302) +- Fix join nodes icon is active when 2 already joined nodes are selected [Taiga #4370](https://tree.taiga.io/project/penpot/issue/4370) +- Fix path nodes panel. "To curve" and "To corner" icons are active if node is already curved/cornered [Taiga #4371](https://tree.taiga.io/project/penpot/issue/4371) +- Fix displaying comments settings are not applied via "Comments" menu drop-down on the top navbar on view mode [Taiga #4389](https://tree.taiga.io/project/penpot/issue/4389) +- Fix bad behaviour on hovering and click nested artboards[Taiga #4018](https://tree.taiga.io/project/penpot/issue/4018) and [Taiga #4269](https://tree.taiga.io/project/penpot/us/4269) ## 1.16.0-beta diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 6f7484e2b..110e0f139 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -288,7 +288,8 @@ props (-> (audit/extract-utm-params params) (merge (:props params)) (merge {:viewed-tutorial? false - :viewed-walkthrough? false}) + :viewed-walkthrough? false + :nudge {:big 10 :small 1}}) (db/tjson)) password (if-let [password (:password params)] diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 8d74c88cb..a680833d2 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -51,6 +51,10 @@ [{:keys [type]}] (= type :svg-raw)) +(defn path-shape? + [{:keys [type]}] + (= type :path)) + (defn unframed-shape? "Checks if it's a non-frame shape in the top level." [shape] diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index c732e87e0..e39869c98 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -183,11 +183,11 @@ (let [type-a (dm/get-in objects [id-a :type]) type-b (dm/get-in objects [id-b :type])] (cond - (and bottom-frames? (= :frame type-a) (not= :frame type-b)) - 1 + (and (= :frame type-a) (not= :frame type-b)) + (if bottom-frames? 1 -1) - (and bottom-frames? (not= :frame type-a) (= :frame type-b)) - -1 + (and (not= :frame type-a) (= :frame type-b)) + (if bottom-frames? -1 1) (= id-a id-b) 0 diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 84ba8d689..0842f1885 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -697,7 +697,7 @@ stopper (->> move-events (rx/debounce 100) (rx/take 1)) - scale (if shift? (gpt/point (:big nudge)) (gpt/point (:small nudge))) + scale (if shift? (gpt/point (or (:big nudge) 10)) (gpt/point (or (:small nudge) 1))) mov-vec (gpt/multiply (get-displacement direction) scale)] (rx/concat diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index a3a0229d0..70f068e06 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -82,12 +82,12 @@ on-duplicate (fn [_] (apply st/emit! (map dd/duplicate-file files)) - (st/emit! (dm/success (tr "dashboard.success-duplicate-file")))) + (st/emit! (dm/success (tr "dashboard.success-duplicate-file" (i18n/c (count files)))))) delete-fn (fn [_] (apply st/emit! (map dd/delete-file files)) - (st/emit! (dm/success (tr "dashboard.success-delete-file")))) + (st/emit! (dm/success (tr "dashboard.success-delete-file" (i18n/c (count files)))))) on-delete (fn [event] diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 14d69e1e5..468f18dde 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -52,20 +52,19 @@ (rx/throw error))) (defn- on-success - [form data] + [profile data] (if (:changed data) (st/emit! (du/fetch-profile) (modal/hide)) - (let [email (get-in @form [:clean-data :email-1]) - message (tr "notifications.validation-email-sent" email)] + (let [message (tr "notifications.validation-email-sent" (:email profile))] (st/emit! (dm/info message) (modal/hide))))) (defn- on-submit - [form _event] + [profile form _event] (let [params {:email (get-in @form [:clean-data :email-1])} mdata {:on-error (partial on-error form) - :on-success (partial on-success form)}] + :on-success (partial on-success profile)}] (st/emit! (du/request-email-change (with-meta params mdata))))) (mf/defc change-email-modal @@ -77,7 +76,12 @@ :validators [email-equality] :initial profile) on-close - (mf/use-callback #(st/emit! (modal/hide)))] + (mf/use-callback #(st/emit! (modal/hide))) + + on-submit + (mf/use-callback + (mf/deps profile) + (partial on-submit profile))] [:div.modal-overlay [:div.modal-container.change-email-modal.form-container @@ -86,7 +90,7 @@ [:div.modal-header [:div.modal-header-title - [:h2 {:data-test "change-email-title"} + [:h2 {:data-test "change-email-title"} (tr "modals.change-email.title")]] [:div.modal-close-button {:on-click on-close} i/close]] diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index b0fe50432..116b5dcce 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.viewer.comments (:require - [app.common.data :as d] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] @@ -27,21 +26,26 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [] - (let [local (mf/deref refs/comments-local) - owner-filter (:owner-filter local) - status-filter (:status-filter local) - show-sidebar? (:show-sidebar? local) + (let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local) show-dropdown? (mf/use-state false) toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) hide-dropdown (mf/use-fn #(reset! show-dropdown? false)) - update-option (mf/use-fn - (fn [event] - (let [target (dom/get-current-target event) - key (d/read-string (dom/get-attribute target "data-key")) - val (d/read-string (dom/get-attribute target "data-val"))] - (st/emit! (dcm/update-options {key val})))))] + update-mode + (mf/use-callback + (fn [mode] + (st/emit! (dcm/update-filters {:mode mode})))) + + update-show + (mf/use-callback + (fn [mode] + (st/emit! (dcm/update-filters {:show mode})))) + + update-options + (mf/use-callback + (fn [mode] + (st/emit! (dcm/update-options {:show-sidebar? mode}))))] [:div.view-options {:on-click toggle-dropdown} [:span.label (tr "labels.comments")] @@ -50,34 +54,26 @@ :on-close hide-dropdown} [:ul.dropdown.with-check - [:li {:class (dom/classnames :selected (= :all owner-filter)) - :data-key ":owner-filter" - :data-val ":all" - :on-click update-option} + [:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode))) + :on-click #(update-mode :all)} [:span.icon i/tick] [:span.label (tr "labels.show-all-comments")]] - [:li {:class (dom/classnames :selected (= :yours owner-filter)) - :data-key ":owner-filter" - :data-val ":yours" - :on-click update-option} + [:li {:class (dom/classnames :selected (= :yours cmode)) + :on-click #(update-mode :yours)} [:span.icon i/tick] [:span.label (tr "labels.show-your-comments")]] [:hr] - [:li {:class (dom/classnames :selected (= :pending status-filter)) - :data-key ":status-filter" - :data-val (if (= :pending status-filter) ":all" ":pending") - :on-click update-option} + [:li {:class (dom/classnames :selected (= :pending cshow)) + :on-click #(update-show (if (= :pending cshow) :all :pending))} [:span.icon i/tick] [:span.label (tr "labels.hide-resolved-comments")]] [:hr] [:li {:class (dom/classnames :selected show-sidebar?) - :data-key ":show-sidebar?" - :data-val (if show-sidebar? "false" "true") - :on-click update-option} + :on-click #(update-options (not show-sidebar?))} [:span.icon i/tick] [:span.label (tr "labels.show-comments-list")]]]]])) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 3e2f48771..39b8cfc10 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -265,18 +265,19 @@ (mf/defc context-menu-path [{:keys [shapes disable-flatten? disable-booleans?]}] - (let [multiple? (> (count shapes) 1) - single? (= (count shapes) 1) + (let [multiple? (> (count shapes) 1) + single? (= (count shapes) 1) - has-group? (->> shapes (d/seek cph/group-shape?)) - has-bool? (->> shapes (d/seek cph/bool-shape?)) - has-frame? (->> shapes (d/seek cph/frame-shape?)) + has-group? (->> shapes (d/seek cph/group-shape?)) + has-bool? (->> shapes (d/seek cph/bool-shape?)) + has-frame? (->> shapes (d/seek cph/frame-shape?)) + has-path? (->> shapes (d/seek cph/path-shape?)) - is-group? (and single? has-group?) - is-bool? (and single? has-bool?) - is-frame? (and single? has-frame?) + is-group? (and single? has-group?) + is-bool? (and single? has-bool?) + is-frame? (and single? has-frame?) - do-start-editing (fn [] (timers/schedule #(st/emit! (dw/start-editing-selected)))) + do-start-editing (fn [] (timers/schedule #(st/emit! (dw/start-editing-selected)))) do-transform-to-path #(st/emit! (dw/convert-selected-to-path)) make-do-bool @@ -296,7 +297,7 @@ :shortcut (sc/get-tooltip :start-editing) :on-click do-start-editing}]) - (when-not (or disable-flatten? has-frame?) + (when-not (or disable-flatten? has-frame? has-path?) [:& menu-entry {:title (tr "workspace.shape.menu.transform-to-path") :on-click do-transform-to-path}]) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index ee4110124..3cf07759b 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -330,7 +330,8 @@ :show-artboard-names? show-artboard-names? :on-frame-enter on-frame-enter :on-frame-leave on-frame-leave - :on-frame-select on-frame-select}] + :on-frame-select on-frame-select + :focus focus}] (when show-prototypes? [:& widgets/frame-flows diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index 0cf7db8a8..b66d01848 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -17,15 +17,22 @@ (defn check-enabled [content selected-points] (let [segments (upt/get-segments content selected-points) + num-segments (count segments) num-points (count selected-points) points-selected? (seq selected-points) - segments-selected? (seq segments)] - {:make-corner points-selected? - :make-curve points-selected? + segments-selected? (seq segments) + ;; max segments for n points is (n × (n -1)) / 2 + max-segments (-> num-points + (* (- num-points 1)) + (/ 2)) + is-curve? (some #(upt/is-curve? content %) selected-points)] + + {:make-corner (and points-selected? is-curve?) + :make-curve (and points-selected? (not is-curve?)) :add-node segments-selected? :remove-node points-selected? :merge-nodes segments-selected? - :join-nodes (and points-selected? (>= num-points 2)) + :join-nodes (and points-selected? (>= num-points 2) (< num-segments max-segments)) :separate-nodes segments-selected?})) (mf/defc path-actions [{:keys [shape]}] diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 1d85295f6..42596402e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -163,11 +163,15 @@ on-frame-enter (unchecked-get props "on-frame-enter") on-frame-leave (unchecked-get props "on-frame-leave") on-frame-select (unchecked-get props "on-frame-select") - frames (ctt/get-frames objects)] + frames (ctt/get-frames objects) + focus (unchecked-get props "focus")] [:g.frame-titles (for [frame frames] - (when (= (:parent-id frame) uuid/zero) + (when (and + (= (:parent-id frame) uuid/zero) + (or (empty? focus) + (contains? focus (:id frame)))) [:& frame-title {:key (dm/str "frame-title-" (:id frame)) :frame frame :selected? (contains? selected (:id frame)) diff --git a/frontend/src/app/util/path/tools.cljs b/frontend/src/app/util/path/tools.cljs index 9c420bd41..f6877b733 100644 --- a/frontend/src/app/util/path/tools.cljs +++ b/frontend/src/app/util/path/tools.cljs @@ -74,6 +74,13 @@ (assoc-in [:params :c2x] (:x h2)) (assoc-in [:params :c2y] (:y h2))))) +(defn is-curve? + [content point] + (let [handlers (-> (upc/content->handlers content) + (get point)) + handler-points (map #(upc/handler->point content (first %) (second %)) handlers)] + (some #(not= point %) handler-points))) + (defn make-curve-point "Changes the content to make the point a 'curve'. The handlers will be positioned in the same vector that results from the previous->next points but with fixed length." @@ -99,7 +106,6 @@ :next-p (upc/command->point next) :command cmd))))) - points (->> vectors (mapcat #(vector (:next-p %) (:prev-p %))) (remove nil?) (into #{}))] (cond @@ -124,8 +130,7 @@ next-correction (when (some? next-h) (gpt/scale (gpt/to-vec next-h point) (/ 1 3))) prev-h (when (some? prev-h) (gpt/add prev-h prev-correction)) - next-h (when (some? next-h) (gpt/add next-h next-correction)) - ] + next-h (when (some? next-h) (gpt/add next-h next-correction))] (cond-> content (and (= :line-to (:command cur-cmd)) (some? prev-p)) (update index upc/update-curve-to prev-p prev-h) @@ -147,7 +152,13 @@ (= :line-to (:command command)) (update index #(line->curve prev-p %)) + (= :curve-to (:command command)) + (update index #(line->curve prev-p %)) + (= :line-to (:command next-c)) + (update next-i #(line->curve point %)) + + (= :curve-to (:command next-c)) (update next-i #(line->curve point %))))] (->> vectors (reduce add-curve content)))))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index f5a489dd2..ef189c794 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -591,7 +591,9 @@ msgstr "Show all files" #: src/app/main/ui/dashboard/file_menu.cljs msgid "dashboard.success-delete-file" -msgstr "Your file has been deleted successfully" +msgid_plural "dashboard.success-delete-file" +msgstr[0] "Your file has been deleted successfully" +msgstr[1] "Your files have been deleted successfully" #: src/app/main/ui/dashboard/project_menu.cljs msgid "dashboard.success-delete-project" @@ -599,7 +601,9 @@ msgstr "Your project has been deleted successfully" #: src/app/main/ui/dashboard/file_menu.cljs msgid "dashboard.success-duplicate-file" -msgstr "Your file has been duplicated successfully" +msgid_plural "dashboard.success-delete-file" +msgstr[0] "Your file has been duplicated successfully" +msgstr[1] "Your files have been duplicated successfully" #: src/app/main/ui/dashboard/project_menu.cljs msgid "dashboard.success-duplicate-project" @@ -4287,4 +4291,16 @@ msgstr "There are updates in shared libraries" #: src/app/main/data/workspace/libraries.cljs msgid "workspace.updates.update" -msgstr "Update" \ No newline at end of file +msgstr "Update" + +msgid "workspace.viewport.click-to-close-path" +msgstr "Click to close the path" + +msgid "errors.profile-blocked" +msgstr "The profile is blocked" + +msgid "errors.bad-font" +msgstr "The font %s could not be loaded" + +msgid "errors.bad-font-plural" +msgstr "The fonts %s could not be loaded" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 0a72bbf05..17d8dc0b0 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -628,7 +628,9 @@ msgstr "Ver todos los archivos" #: src/app/main/ui/dashboard/file_menu.cljs msgid "dashboard.success-delete-file" -msgstr "Tu archivo ha sido borrado con éxito" +msgid_plural "dashboard.success-delete-file" +msgstr[0] "Tu archivo ha sido borrado con éxito" +msgstr[1] "Tus archivos han sido borrado con éxito" #: src/app/main/ui/dashboard/project_menu.cljs msgid "dashboard.success-delete-project" @@ -636,7 +638,9 @@ msgstr "Tu proyecto ha sido borrado con éxito" #: src/app/main/ui/dashboard/file_menu.cljs msgid "dashboard.success-duplicate-file" -msgstr "Tu archivo ha sido duplicado con éxito" +msgid_plural "dashboard.success-delete-file" +msgstr[0] "Tu archivo ha sido duplicado con éxito" +msgstr[1] "Tus archivos han sido duplicado con éxito" #: src/app/main/ui/dashboard/project_menu.cljs msgid "dashboard.success-duplicate-project"