diff --git a/CHANGES.md b/CHANGES.md index 6f89fe950..7a01888b8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -111,6 +111,8 @@ - Fix 400 error when user changes password [Taiga #5643](https://tree.taiga.io/project/penpot/issue/5643) - Fix cannot undo layer styles [Taiga #5676](https://tree.taiga.io/project/penpot/issue/5676) - Fix unexpected exception on boolean shapes [Taiga #5685](https://tree.taiga.io/project/penpot/issue/5685) +- Fix ctrl+z on select not working [Taiga #5677](https://tree.taiga.io/project/penpot/issue/5677) +- Fix thubmnail rendering flashing [Taiga #5675](https://tree.taiga.io/project/penpot/issue/5675) ### :arrow_up: Deps updates diff --git a/backend/resources/app/onboarding.edn b/backend/resources/app/onboarding.edn index e9f6f063f..0438d25ba 100644 --- a/backend/resources/app/onboarding.edn +++ b/backend/resources/app/onboarding.edn @@ -1,36 +1,30 @@ [{:id "material-design-3" :name "Material Design 3" - :thumbnail-uri "https://penpot.app/images/libraries/cover-md3.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/main/Material%20Design%203.penpot"} {:id "tutorial-for-beginners" :name "Tutorial for beginners" - :thumbnail-uri "https://penpot.app/images/libraries/tutorial-for-beginners.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"} {:id "penpot-design-system" :name "Penpot Design System" - :thumbnail-uri "https://penpot.app/images/libraries/cover-ds-penpot.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"} + {:id "flex-layout-playground" + :name "Flex Layout Playground" + :file-uri "https://github.com/penpot/penpot-files/raw/main/Flex%20Layout%20Playground.penpot"} {:id "wireframing-kit" :name "Wireframing Kit" - :thumbnail-uri "https://penpot.app/images/libraries/cover-wireframes.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"} {:id "ant-design" :name "Ant Design UI Kit (lite)" - :thumbnail-uri "https://penpot.app/images/libraries/cover-ant-design.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Ant-Design-UI-Kit-Lite.penpot"} {:id "cocomaterial" :name "Cocomaterial" - :thumbnail-uri "https://penpot.app/images/libraries/cover-cocomaterial.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Cocomaterial.penpot"} {:id "circum-icons" :name "Circum Icons pack" - :thumbnail-uri "https://penpot.app/images/libraries/cover-circum.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/CircumIcons.penpot"} {:id "coreui" :name "CoreUI" - :thumbnail-uri "https://penpot.app/images/libraries/cover-coreui.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/main/CoreUI%20DesignSystem%20(DEMO).penpot"} {:id "whiteboarding-kit" :name "Whiteboarding Kit" - :thumbnail-uri "https://penpot.app/images/libraries/cover-whiteboards.jpg" :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Whiteboarding-mapping-kit.penpot"}] diff --git a/backend/src/app/rpc/commands/management.clj b/backend/src/app/rpc/commands/management.clj index 3de69a9dd..ead66317b 100644 --- a/backend/src/app/rpc/commands/management.clj +++ b/backend/src/app/rpc/commands/management.clj @@ -28,7 +28,8 @@ [app.util.services :as sv] [app.util.time :as dt] [clojure.spec.alpha :as s] - [clojure.walk :as walk])) + [clojure.walk :as walk] + [promesa.exec :as px])) ;; --- COMMAND: Duplicate File @@ -322,6 +323,18 @@ ;; delete possible broken relations on moved files (db/exec-one! conn [sql:delete-broken-relations pids]) + ;; Update the modification date of the all affected projects + ;; ensuring that the destination project is the most recent one. + (doseq [project-id (into (list project-id) source)] + + ;; NOTE: as this is executed on virtual thread, sleeping does + ;; not causes major issues, and allows an easy way to set a + ;; trully different modification date to each file. + (px/sleep 10) + (db/update! conn :project + {:modified-at (dt/now)} + {:id project-id})) + nil)) (s/def ::ids (s/every ::us/uuid :kind set?)) @@ -423,9 +436,9 @@ {::doc/added "1.10" ::doc/deprecated "1.19"} [cfg _params] - (mapv #(select-keys % [:id :name :thumbnail-uri]) (::setup/templates cfg))) + (mapv #(select-keys % [:id :name]) (::setup/templates cfg))) (sv/defmethod ::get-builtin-templates {::doc/added "1.19"} [cfg _params] - (mapv #(select-keys % [:id :name :thumbnail-uri]) (::setup/templates cfg))) + (mapv #(select-keys % [:id :name]) (::setup/templates cfg))) diff --git a/backend/src/app/setup/templates.clj b/backend/src/app/setup/templates.clj index 98afd340c..c51bc98c8 100644 --- a/backend/src/app/setup/templates.clj +++ b/backend/src/app/setup/templates.clj @@ -23,7 +23,6 @@ [:map {:title "Template"} [:id ::sm/word-string] [:name ::sm/word-string] - [:thumbnail-uri ::sm/word-string] [:file-uri ::sm/word-string]]) (def ^:private schema:templates diff --git a/frontend/resources/images/thumbnails/template-flex-layout-playground.jpg b/frontend/resources/images/thumbnails/template-flex-layout-playground.jpg new file mode 100644 index 000000000..0457dbfce Binary files /dev/null and b/frontend/resources/images/thumbnails/template-flex-layout-playground.jpg differ diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index 879810ff1..e377b1ab3 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -10,7 +10,6 @@ [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.schema :as sm] - [app.common.time :as dt] [app.common.uri :as u] [app.common.uuid :as uuid] [app.config :as cf] @@ -23,6 +22,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] + [app.util.time :as dt] [app.util.timers :as tm] [app.util.webapi :as wapi] [beicon.core :as rx] @@ -863,6 +863,7 @@ [{:keys [ids project-id] :as params}] (dm/assert! (sm/set-of-uuid? ids)) (dm/assert! (uuid? project-id)) + (ptk/reify ::move-files IDeref (-deref [_] @@ -872,13 +873,13 @@ ptk/UpdateEvent (update [_ state] (let [origin-project (get-in state [:dashboard-files (first ids) :project-id]) - update-project (fn [project] + update-project (fn [project delta] (-> project (update :count #(+ % (count ids))) - (assoc :modified-at (dt/now))))] + (assoc :modified-at (dt/plus (dt/now) {:milliseconds delta}))))] (-> state - (d/update-in-when [:dashboard-projects origin-project] update-project) - (d/update-in-when [:dashboard-projects project-id] update-project)))) + (d/update-in-when [:dashboard-projects origin-project] update-project 0) + (d/update-in-when [:dashboard-projects project-id] update-project 10)))) ptk/WatchEvent (watch [_ _ _] diff --git a/frontend/src/app/main/data/shortcuts_impl.js b/frontend/src/app/main/data/shortcuts_impl.js index d72137ed0..9be5beb05 100644 --- a/frontend/src/app/main/data/shortcuts_impl.js +++ b/frontend/src/app/main/data/shortcuts_impl.js @@ -17,17 +17,20 @@ if (Mousetrap.addKeycodes) { const target = Mousetrap.prototype || Mousetrap; target.stopCallback = function(e, element, combo) { - // if the element has the class "mousetrap" then no need to stop - if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { - return false; + // if the element has the data attribute "mousetrap-dont-stop" then no need + // to stop. It should be used like
...
+ // or :div {:data-mousetrap-dont-stop true} + if ('mousetrapDontStop' in element.dataset) { + return false } // stop for input, select, textarea and button - return element.tagName == 'INPUT' || - element.tagName == 'SELECT' || - element.tagName == 'TEXTAREA' || - (element.tagName == 'BUTTON' && combo.includes("tab")) || - (element.contentEditable && element.contentEditable == 'true'); + const shouldStop = element.tagName == "INPUT" || + element.tagName == "SELECT" || + element.tagName == "TEXTAREA" || + (element.tagName == "BUTTON" && combo.includes("tab")) || + (element.contentEditable && element.contentEditable == "true"); + return shouldStop; } export default Mousetrap; diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index d0f5f3f99..3c58700ae 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -296,10 +296,9 @@ :on-import on-import}] [:span.info (str (tr "labels.num-of-files" (i18n/c file-count)))] - (when (> file-count 0) - (let [time (-> (:modified-at project) - (dt/timeago {:locale locale}))] - [:span.recent-files-row-title-info (str ", " time)])) + (let [time (-> (:modified-at project) + (dt/timeago {:locale locale}))] + [:span.recent-files-row-title-info (str ", " time)]) [:div.project-actions (when-not (:is-default project) [:button.pin-icon.tooltip.tooltip-bottom diff --git a/frontend/src/app/main/ui/dashboard/templates.cljs b/frontend/src/app/main/ui/dashboard/templates.cljs index 9357faa8d..18bb1453f 100644 --- a/frontend/src/app/main/ui/dashboard/templates.cljs +++ b/frontend/src/app/main/ui/dashboard/templates.cljs @@ -150,8 +150,9 @@ (mf/defc templates-section {::mf/wrap-props false} [{:keys [default-project-id profile project-id team-id content-width]}] - (let [templates (->> (mf/deref builtin-templates) - (filter #(not= (:id %) "tutorial-for-beginners"))) + (let [templates (mf/deref builtin-templates) + templates (mf/with-memo [templates] + (filterv #(not= (:id %) "tutorial-for-beginners") templates)) route (mf/deref refs/route) route-name (get-in route [:data :name]) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index d5f76a4a3..ba6a8b28e 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -72,7 +72,9 @@ (reset! current-colors (into [] (filter check-valid-color?) colors))))) [:div.libraries - [:select {:on-change on-library-change :value (name @selected)} + [:select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change on-library-change + :value (name @selected)} [:option {:value "recent"} (tr "workspace.libraries.colors.recent-colors")] [:option {:value "file"} (tr "workspace.libraries.colors.file-library")] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs index a7c019bf8..5c7d535f3 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs @@ -103,7 +103,6 @@ render-frame* (mf/use-state (not thumbnail-uri)) debug? (debug? :thumbnails) - on-bitmap-load (mf/use-fn (fn [] @@ -171,6 +170,8 @@ (when (not= "false" (dom/get-data image-node "ready")) (dom/set-data! image-node "ready" "false"))) (when-not ^boolean @disable* + (reset! svg-uri* nil) + (reset! bitmap-uri* nil) (reset! render-frame* true) (reset! regenerate* true)))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index b4536f350..2a0970000 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -164,7 +164,7 @@ (if ^boolean new-css-system [:div {:class (css :assets-bar)} [:div {:class (css :assets-header)} - (when-not read-only? + (when-not ^boolean read-only? [:button {:class (css :libraries-button) :on-click #(modal/show! :libraries-dialog {})} [:span {:class (css :libraries-icon)} @@ -229,6 +229,7 @@ i/close])] [:select.input-select {:value (:section filters) + :data-mousetrap-dont-stop true :on-change on-section-filter-change} [:option {:value "all"} (tr "workspace.assets.box-filter-all")] [:option {:value "components"} (tr "workspace.assets.components")] diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 9fd49134f..781f1b3ad 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -189,7 +189,7 @@ ;; NOTE: Neither get-parent-at nor get-parent-with-selector ;; work if the component template changes, so we need to ;; seek for an alternate solution. Maybe use-context? - scroll-node (dom/get-parent-with-selector node ".tool-window-content") + scroll-node (dom/get-parent-with-data node "scrollContainer") parent-node (dom/get-parent-at node 2) subid diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 1fd8cef7d..e6ec213ff 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -538,6 +538,7 @@ (if (some? filtered-objects) [:* [:div {:class (stl/css new-css-system :tool-window-content) + :data-scroll-container true :ref on-render-container} [:& filters-tree {:objects filtered-objects :key (dm/str (:id page)) @@ -546,6 +547,7 @@ :style {:min-height 16}}]] [:div {:on-scroll on-scroll :class (stl/css new-css-system :tool-window-content) + :data-scroll-container true :style {:display (when (some? filtered-objects) "none")}} [:& layers-tree {:objects filtered-objects :key (dm/str (:id page)) @@ -554,6 +556,7 @@ [:div {:on-scroll on-scroll :class (stl/css new-css-system :tool-window-content) + :data-scroll-container true :style {:display (when (some? filtered-objects) "none")}} [:& layers-tree {:objects objects :key (dm/str (:id page)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index a65f6b125..94ebe5c78 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -147,7 +147,8 @@ [:div.constraints-form [:div.row-flex [:span.left-right i/full-screen] - [:select.input-select {:on-change (on-constraint-select-changed :constraints-h) + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change (on-constraint-select-changed :constraints-h) :value (d/name constraints-h "scale")} (when (= constraints-h :multiple) [:option {:value ""} (tr "settings.multiple")]) @@ -158,7 +159,8 @@ [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] [:div.row-flex [:span.top-bottom i/full-screen] - [:select.input-select {:on-change (on-constraint-select-changed :constraints-v) + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change (on-constraint-select-changed :constraints-v) :value (d/name constraints-v "scale")} (when (= constraints-v :multiple) [:option {:value ""} (tr "settings.multiple")]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index 879c49173..9fe6cad42 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -169,7 +169,8 @@ [:div.element-set-options-group {:key index} (when (scale-enabled? export) - [:select.input-select {:on-change (partial on-scale-change index) + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change (partial on-scale-change index) :value (:scale export)} [:option {:value "0.5"} "0.5x"] [:option {:value "0.75"} "0.75x"] @@ -182,7 +183,8 @@ :placeholder (tr "workspace.options.export.suffix") :on-change (partial on-suffix-change index) :on-key-down manage-key-down}] - [:select.input-select {:value (d/name (:type export)) + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :value (d/name (:type export)) :on-change (partial on-type-change index)} [:option {:value "png"} "PNG"] [:option {:value "jpeg"} "JPEG"] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index 5980469cd..f1f2ec21e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -139,7 +139,8 @@ i/actions] [:select.input-select - {:default-value shadow-style + {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value shadow-style :on-change (fn [event] (let [value (-> event dom/get-target dom/get-value d/read-string)] (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} @@ -165,7 +166,8 @@ {:on-click on-toggle-open-shadow} i/actions] [:select.input-select - {:default-value shadow-style + {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value shadow-style :on-change (fn [event] (let [value (-> event dom/get-target dom/get-value d/read-string)] (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index b1c4ae748..58c6d4d8c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -425,6 +425,7 @@ [:select.input-select.variant-option {:disabled (= font-id :multiple) + :data-mousetrap-dont-stop true :value (attr->string font-variant-id) :on-change on-font-variant-change :on-blur on-blur} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs index d834d4a6b..f0aca9d25 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs @@ -20,7 +20,8 @@ (case type :select - [:& select {:default-value value + [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value value :class "input-option" :options options :on-change on-change}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index 964f626b1..60bf0afb6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -106,7 +106,8 @@ :select-on-focus select-on-focus :on-blur on-blur}]] - [:select#style.input-select {:value (enum->string (:stroke-alignment stroke)) + [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :value (enum->string (:stroke-alignment stroke)) :on-change (on-stroke-alignment-change index)} (when (= (:stroke-alignment stroke) :multiple) [:option {:value ""} "--"]) @@ -115,7 +116,8 @@ [:option {:value ":outer"} (tr "workspace.options.stroke.outer")]] (when-not disable-stroke-style - [:select#style.input-select {:value (enum->string (:stroke-style stroke)) + [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :value (enum->string (:stroke-style stroke)) :on-change (on-stroke-style-change index)} (when (= (:stroke-style stroke) :multiple) [:option {:value ""} "--"]) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index dfe8769f6..a4db28c8b 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -166,6 +166,13 @@ current (recur (.-parentElement current) (dec current-count)))))) +(defn get-parent-with-data + [^js node name] + (loop [current node] + (if (or (nil? current) (obj/in? (.-dataset current) name)) + current + (recur (.-parentElement current))))) + (defn get-parent-with-selector [^js node selector] (loop [current node]