diff --git a/CHANGES.md b/CHANGES.md index 8d9d3e7e60..caddcf7d7a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,39 +18,44 @@ ### :boom: Breaking changes - We've changed the behaviour of the border-radius so it works as CSS that [has some limits](https://www.w3.org/TR/css-backgrounds-3/#corner-overlap). +- Now exported text are SVG's native `text` tag instead of paths. This could break when opening the file depending on your engine. Some SVG's may require fonts to be installed at system level. ### :sparkles: New features - Group assets by drag and drop [Taiga #2831](https://tree.taiga.io/project/penpot/us/2831) - Search and filter layers [Taiga #2564](https://tree.taiga.io/project/penpot/us/2564) -- Constraints are not well assigned when default and multiselection [Taiga #3069](https://tree.taiga.io/project/penpot/issue/3069) - Exporting big files flow [Taiga #2218](https://tree.taiga.io/project/penpot/us/2218) - Multiexport from main menu [Taiga #520](https://tree.taiga.io/project/penpot/us/28541) - Multiexport assets (aka bulk export) [Taiga #520](https://tree.taiga.io/project/penpot/us/520) - Set the artboard layer fixed at the top side of the layers [Taiga #2636](https://tree.taiga.io/project/penpot/us/2636) - Set an artboard as the file thumbnail [Taiga #1526](https://tree.taiga.io/project/penpot/us/1526) - Social login redesign [Taiga #2974](https://tree.taiga.io/project/penpot/task/2974) -- Add border radius to our artboards [Taiga #2056](https://tree.taiga.io/project/penpot/us/2056) +- Add border radius to artboards [Taiga #2056](https://tree.taiga.io/project/penpot/us/2056) - Allow send multiple team invitations at once [Taiga #2798](https://tree.taiga.io/project/penpot/us/2798) - Persist color palette and color picker across refresh [Taiga #1660](https://tree.taiga.io/project/penpot/issue/1660) - Ability to add multiple strokes to a shape [Taiga #2778](https://tree.taiga.io/project/penpot/us/2778) - Scroll to selected size in font size selector [Taiga #2825](https://tree.taiga.io/project/penpot/us/2825) -- Duplicate artboards create new flows if needed [Taiga #2221](https://tree.taiga.io/project/penpot/issue/2221) - Add new invitations section [Taiga #2797](https://tree.taiga.io/project/penpot/us/2797) - Ability to add multiple fills to a shape [Taiga #1394](https://tree.taiga.io/project/penpot/us/1394) - Team members redesign [Taiga #2283](https://tree.taiga.io/project/penpot/us/2283) - New focus mode in workspace [Taiga #2748](https://tree.taiga.io/project/penpot/us/2748) - Changed text shapes to be displayed as natives SVG text elements [Taiga #2759](https://tree.taiga.io/project/penpot/us/2759) - Texts now can have strokes, multiple fills and can be used as masks -- Add the ability to specify the attr for retrieve the email on OIDC integration [#1460](https://github.com/penpot/penpot/issues/1460) +- Add the ability to specify the attribute for retrieve the email on OIDC integration [#1460](https://github.com/penpot/penpot/issues/1460) - Allow registration with invitation token when registration is disabled - Add the ability to disable standard, password login [Taiga #2999](https://tree.taiga.io/project/penpot/us/2999) - Don't stop SVG import when an image cannot be imported [#1531](https://github.com/penpot/penpot/issues/1531) -- Fix paste shapes while editing text [Taiga #2396](https://tree.taiga.io/project/penpot/issue/2396) - Show Penpot color in Safari tab bar [#1803](https://github.com/penpot/penpot/issues/1803) +- Added option to disable snap to pixel and improved behaviour for sub-pixel drawing [#2552](https://tree.taiga.io/project/penpot/us/2552) +- Delete guides while supr on hover [#2823](https://tree.taiga.io/project/penpot/us/2823) +- Opt-in subscription on on-premise instances [#2772](https://tree.taiga.io/project/penpot/us/2772) +- Optimizations in frame thumbnails [#3147](https://tree.taiga.io/project/penpot/us/3147) ### :bug: Bugs fixed +- Constraints are not well assigned when default and multiselection [Taiga #3069](https://tree.taiga.io/project/penpot/issue/3069) +- Duplicate artboards create new flows if needed [Taiga #2221](https://tree.taiga.io/project/penpot/issue/2221) +- Fix paste shapes while editing text [Taiga #2396](https://tree.taiga.io/project/penpot/issue/2396) - Round the size values on handoff to two decimals [Taiga #3227](https://tree.taiga.io/project/penpot/issue/3227) - Fix blend modes ignored in component updates [Taiga #2626](https://tree.taiga.io/project/penpot/issue/2626) - Fix internal error when hoverin over shape [Taiga #3237](https://tree.taiga.io/project/penpot/issue/3237) @@ -99,6 +104,11 @@ - Fix resize rotated shape with top&down constraints [Taiga #3167](https://tree.taiga.io/project/penpot/issue/3167) - Fix multi user not working [Taiga #3195](https://tree.taiga.io/project/penpot/issue/3195) - Fix guides are not duplicated with the artboard [Taiga #3072](https://tree.taiga.io/project/penpot/issue/3072) +- Fix problem when changing group size with decimal values [Taiga #3203](https://tree.taiga.io/project/penpot/issue/3203) +- Fix error when drawing curves with only one point [Taiga #3282](https://tree.taiga.io/project/penpot/issue/3282) +- Fix issue with paste ordering sometimes not being respected [Taiga #3268](https://tree.taiga.io/project/penpot/issue/3268) +- Fix problem when export/importing guides attached to frame [#1838](https://github.com/penpot/penpot/issues/1838) +- Fix problem when resizing a group with texts with auto-width/height [#3171](https://tree.taiga.io/project/penpot/issue/3171) ### :arrow_up: Deps updates ### :heart: Community contributions by (Thank you!) diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 4c404d8f12..5c295acef2 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -103,25 +103,25 @@ (defmethod constraint-modifier :scale [_ axis _ _ modifiers _] (let [{:keys [resize-vector resize-vector-2 displacement]} modifiers] - (cond-> {} - (and (some? resize-vector) - (not (mth/close? (axis resize-vector) 1))) - (assoc :resize-origin (:resize-origin modifiers) - :resize-vector (if (= :x axis) - (gpt/point (:x resize-vector) 1) - (gpt/point 1 (:y resize-vector)))) + (cond-> {} + (and (some? resize-vector) + (not= (axis resize-vector) 1)) + (assoc :resize-origin (:resize-origin modifiers) + :resize-vector (if (= :x axis) + (gpt/point (:x resize-vector) 1) + (gpt/point 1 (:y resize-vector)))) - (and (= :y axis) (some? resize-vector-2) - (not (mth/close? (:y resize-vector-2) 1))) - (assoc :resize-origin (:resize-origin-2 modifiers) - :resize-vector (gpt/point 1 (:y resize-vector-2))) + (and (= :y axis) (some? resize-vector-2) + (not (mth/close? (:y resize-vector-2) 1))) + (assoc :resize-origin (:resize-origin-2 modifiers) + :resize-vector (gpt/point 1 (:y resize-vector-2))) - (some? displacement) - (assoc :displacement - (get-displacement axis (-> (gpt/point 0 0) - (gpt/transform displacement) - (gpt/transform (:resize-transform-inverse modifiers (gmt/matrix))) - axis)))))) + (some? displacement) + (assoc :displacement + (get-displacement axis (-> (gpt/point 0 0) + (gpt/transform displacement) + (gpt/transform (:resize-transform-inverse modifiers (gmt/matrix))) + axis)))))) (defmethod constraint-modifier :default [_ _ _ _ _] {}) diff --git a/frontend/deps.edn b/frontend/deps.edn index 231b30c568..a1d592e326 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -9,7 +9,7 @@ funcool/beicon {:mvn/version "2021.07.05-1"} funcool/okulary {:mvn/version "2022.04.11-16"} - funcool/potok {:mvn/version "2021.09.20-0"} + funcool/potok {:mvn/version "2022.04.28-67"} funcool/rumext {:mvn/version "2022.04.19-148"} funcool/tubax {:mvn/version "2021.05.20-0"} diff --git a/frontend/resources/images/features/1.13-focus.gif b/frontend/resources/images/features/1.13-focus.gif new file mode 100644 index 0000000000..209cb0a351 Binary files /dev/null and b/frontend/resources/images/features/1.13-focus.gif differ diff --git a/frontend/resources/images/features/1.13-members.gif b/frontend/resources/images/features/1.13-members.gif new file mode 100644 index 0000000000..9745759dd0 Binary files /dev/null and b/frontend/resources/images/features/1.13-members.gif differ diff --git a/frontend/resources/images/features/1.13-multi-export.gif b/frontend/resources/images/features/1.13-multi-export.gif new file mode 100644 index 0000000000..47c7526663 Binary files /dev/null and b/frontend/resources/images/features/1.13-multi-export.gif differ diff --git a/frontend/resources/images/features/1.13-multiple-fills.gif b/frontend/resources/images/features/1.13-multiple-fills.gif new file mode 100644 index 0000000000..1f0283e6df Binary files /dev/null and b/frontend/resources/images/features/1.13-multiple-fills.gif differ diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 768ca5b2b7..5a491eaf26 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1482,12 +1482,11 @@ (let [set-index (fn [[result index] id] [(assoc result id index) (inc index)]) - map-ids (when index - (->> (vals paste-objects) - (filter #(not (selected (:parent-id %)))) - (map :id) - (reduce set-index [{} (inc index)]) - first))] + map-ids + (->> selected + (map #(get-in paste-objects [% :id])) + (reduce set-index [{} (inc index)]) + first)] (if (and (= :add-obj (:type change)) (contains? map-ids (:old-id change))) (assoc change :index (get map-ids (:old-id change))) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index d50b29c2d7..187ee5c44a 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -107,7 +107,8 @@ (update [_ state] (assoc-in state [:workspace-local :expanded id] true)))) -(def collapse-all +(defn collapse-all + [] (ptk/reify ::collapse-all ptk/UpdateEvent (update [_ state] diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index c333a7a293..cb75f95cf3 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -37,29 +37,29 @@ ptk/WatchEvent (watch [_ _ stream] - (let [stoper (rx/filter (ptk/type? ::clear-drawing) stream)] - (rx/merge - (when (= tool :path) - (rx/of (start-drawing :path))) + (rx/merge + (when (= tool :path) + (rx/of (start-drawing :path))) - (when (= tool :curve) - (let [stopper (->> stream (rx/filter dwc/interrupt?))] - (->> stream - (rx/filter (ptk/type? ::common/handle-finish-drawing)) - (rx/take 1) - (rx/observe-on :async) - (rx/map #(select-for-drawing tool data)) - (rx/take-until stopper)))) + (when (= tool :curve) + (let [stopper (->> stream (rx/filter dwc/interrupt?))] + (->> stream + (rx/filter (ptk/type? ::common/handle-finish-drawing)) + (rx/take 1) + (rx/observe-on :async) + (rx/map #(select-for-drawing tool data)) + (rx/take-until stopper)))) - ;; NOTE: comments are a special case and they manage they - ;; own interrupt cycle.q - (when (and (not= tool :comments) - (not= tool :path)) + ;; NOTE: comments are a special case and they manage they + ;; own interrupt cycle.q + (when (and (not= tool :comments) + (not= tool :path)) + (let [stopper (rx/filter (ptk/type? ::clear-drawing) stream)] (->> stream (rx/filter dwc/interrupt?) (rx/take 1) - (rx/map (constantly common/clear-drawing)) - (rx/take-until stoper))))))))) + (rx/map common/clear-drawing) + (rx/take-until stopper))))))))) ;; NOTE/TODO: when an exception is raised in some point of drawing the diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index 2218845f60..c2eeefc703 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -101,4 +101,4 @@ #(update-drawing % (cond-> point snap-pixel? gpt/round) shift?))) (rx/take-until stoper)) - (rx/of common/handle-finish-drawing)))))) + (rx/of (common/handle-finish-drawing))))))) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index 047f1c0ff6..3bd78df3ff 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -16,13 +16,15 @@ [beicon.core :as rx] [potok.core :as ptk])) -(def clear-drawing +(defn clear-drawing + [] (ptk/reify ::clear-drawing ptk/UpdateEvent (update [_ state] (update state :workspace-drawing dissoc :tool :object)))) -(def handle-finish-drawing +(defn handle-finish-drawing + [] (ptk/reify ::handle-finish-drawing ptk/WatchEvent (watch [_ state _] @@ -71,5 +73,6 @@ (rx/empty))))) ;; Delay so the mouse event can read the drawing state - (->> (rx/of clear-drawing) + (->> (rx/of (clear-drawing)) (rx/delay 0))))))) + diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index f221ff4f25..d60cc040c9 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -59,15 +59,22 @@ (dissoc :segments) (assoc :content content) (assoc :selrect selrect) - (assoc :points points)))) + (assoc :points points) -(defn finish-drawing-curve [state] - (update-in - state [:workspace-drawing :object] - (fn [shape] - (-> shape - (update :segments #(ups/simplify % simplify-tolerance)) - (curve-to-path))))) + (cond-> (or (empty? points) (nil? selrect) (<= (count content) 1)) + (assoc :initialized? false))))) + +(defn finish-drawing-curve + [] + (ptk/reify ::finish-drawing-curve + ptk/UpdateEvent + (update [_ state] + (letfn [(update-curve [shape] + (-> shape + (update :segments #(ups/simplify % simplify-tolerance)) + (curve-to-path)))] + (-> state + (update-in [:workspace-drawing :object] update-curve)))))) (defn handle-drawing-curve [] (ptk/reify ::handle-drawing-curve @@ -81,6 +88,6 @@ (rx/map (fn [pt] #(insert-point-segment % pt))) (rx/take-until stoper)) (rx/of (setup-frame-curve) - finish-drawing-curve - common/handle-finish-drawing)))))) + (finish-drawing-curve) + (common/handle-finish-drawing))))))) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index a6f0a41f51..5c46ecc456 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -275,7 +275,7 @@ ptk/WatchEvent (watch [_ _ _] (rx/of (setup-frame-path) - dwdc/handle-finish-drawing + (dwdc/handle-finish-drawing) (dwc/start-edition-mode shape-id) (change-edit-mode :draw))))) diff --git a/frontend/src/app/main/data/workspace/persistence.cljs b/frontend/src/app/main/data/workspace/persistence.cljs index 8bf0f2db45..788f31ca56 100644 --- a/frontend/src/app/main/data/workspace/persistence.cljs +++ b/frontend/src/app/main/data/workspace/persistence.cljs @@ -246,7 +246,7 @@ (ptk/reify ::fetch-bundle ptk/WatchEvent (watch [_ _ _] - (->> (rx/zip (rp/query :file {:id file-id}) + (->> (rx/zip (rp/query :file-raw {:id file-id}) (rp/query :team-users {:file-id file-id}) (rp/query :project {:id project-id}) (rp/query :file-libraries {:file-id file-id})) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index 1c403d0b23..6e564b1d30 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -124,7 +124,7 @@ (get-in shape [:svg-attrs :style :stroke-opacity]) (-> (update-in [:svg-attrs :style] dissoc :stroke-opacity) - (assoc-in [:fills 0 :stroke-opacity] (-> (get-in shape [:svg-attrs :style :stroke-opacity]) + (assoc-in [:strokes 0 :stroke-opacity] (-> (get-in shape [:svg-attrs :style :stroke-opacity]) (d/parse-double)))) (get-in shape [:svg-attrs :stroke-width]) @@ -395,14 +395,12 @@ :image (create-image-shape name frame-id svg-data element-data) #_other (create-raw-svg name frame-id svg-data element-data)))] (when (some? shape) - (let [shape (assoc shape :fills []) - shape (assoc shape :strokes []) - - shape (when (some? shape) - (-> shape - (assoc :svg-defs (select-keys (:defs svg-data) references)) - (setup-fill) - (setup-stroke))) + (let [shape (-> shape + (assoc :fills []) + (assoc :strokes []) + (assoc :svg-defs (select-keys (:defs svg-data) references)) + (setup-fill) + (setup-stroke)) children (cond->> (:content element-data) (or (= tag :g) (= tag :svg)) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 4b3cf805a6..0d46f915a4 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -384,6 +384,11 @@ (defn commit-position-data [] (ptk/reify ::commit-position-data + ptk/UpdateEvent + (update [_ state] + (let [ids (keys (::update-position-data state))] + (update state :workspace-text-modifiers #(apply dissoc % ids)))) + ptk/WatchEvent (watch [_ state _] (let [position-data (::update-position-data state)] @@ -404,9 +409,10 @@ (ptk/reify ::update-position-data ptk/UpdateEvent (update [_ state] - (if (nil? (::update-position-data-debounce state)) - (assoc state ::update-position-data-debounce start) - (assoc-in state [::update-position-data id] position-data))) + (let [state (assoc-in state [:workspace-text-modifier id :position-data] position-data)] + (if (nil? (::update-position-data-debounce state)) + (assoc state ::update-position-data-debounce start) + (assoc-in state [::update-position-data id] position-data)))) ptk/WatchEvent (watch [_ state stream] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 8d1be936f3..058f1b42c2 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -110,7 +110,7 @@ ;; geometric attributes of the shapes. (declare clear-local-transform) -(declare set-modifiers-recursive) +(declare set-objects-modifiers) (declare get-ignore-tree) (defn- set-modifiers @@ -139,7 +139,7 @@ (fn [state id] (let [shape (get objects id)] (update state :workspace-modifiers - #(set-modifiers-recursive % objects shape modifiers ignore-constraints snap-pixel?))))] + #(set-objects-modifiers % objects shape modifiers ignore-constraints snap-pixel?))))] (reduce setup-modifiers state ids)))))) @@ -166,6 +166,20 @@ (update state :workspace-modifiers #(reduce update-shape % shapes))))))) +(defn- update-grow-type + [shape old-shape] + (let [auto-width? (= :auto-width (:grow-type shape)) + auto-height? (= :auto-height (:grow-type shape)) + + changed-width? (not (mth/close? (:width shape) (:width old-shape))) + changed-height? (not (mth/close? (:height shape) (:height old-shape))) + + change-to-fixed? (or (and auto-width? (or changed-height? changed-width?)) + (and auto-height? changed-height?))] + (cond-> shape + change-to-fixed? + (assoc :grow-type :fixed)))) + (defn- apply-modifiers [ids] (us/verify (s/coll-of uuid?) ids) @@ -182,27 +196,33 @@ (rx/of (dwu/start-undo-transaction) (dwg/move-frame-guides ids-with-children) (dch/update-shapes - ids-with-children - (fn [shape] - (let [modif (get object-modifiers (:id shape))] - (gsh/transform-shape (merge shape modif)))) - {:reg-objects? true - :ignore-tree ignore-tree - ;; Attributes that can change in the transform. This way we don't have to check - ;; all the attributes - :attrs [:selrect - :points - :x - :y - :width - :height - :content - :transform - :transform-inverse - :rotation - :position-data - :flip-x - :flip-y]}) + ids-with-children + (fn [shape] + (let [modif (get object-modifiers (:id shape)) + text-shape? (cph/text-shape? shape)] + (-> shape + (merge modif) + (gsh/transform-shape) + (cond-> text-shape? + (update-grow-type shape))))) + {:reg-objects? true + :ignore-tree ignore-tree + ;; Attributes that can change in the transform. This way we don't have to check + ;; all the attributes + :attrs [:selrect + :points + :x + :y + :width + :height + :content + :transform + :transform-inverse + :rotation + :position-data + :flip-x + :flip-y + :grow-type]}) (clear-local-transform) (dwu/commit-undo-transaction)))))) @@ -330,25 +350,28 @@ (assoc :displacement (gmt/translate-matrix delta-v))))] modifiers))) -(defn- set-modifiers-recursive +(defn- set-objects-modifiers [modif-tree objects shape modifiers ignore-constraints snap-pixel?] + (letfn [(set-modifiers-rec + [modif-tree shape modifiers] - (let [children (map (d/getf objects) (:shapes shape)) - modifiers (cond-> modifiers snap-pixel? (set-pixel-precision shape)) - transformed-rect (gsh/transform-selrect (:selrect shape) modifiers) + (let [children (map (d/getf objects) (:shapes shape)) + modifiers (cond-> modifiers snap-pixel? (set-pixel-precision shape)) + transformed-rect (gsh/transform-selrect (:selrect shape) modifiers) - set-child - (fn [modif-tree child] - (let [child-modifiers (gsh/calc-child-modifiers shape child modifiers ignore-constraints transformed-rect)] - (cond-> modif-tree - (not (gsh/empty-modifiers? child-modifiers)) - (set-modifiers-recursive objects child child-modifiers ignore-constraints snap-pixel?)))) + set-child + (fn [modif-tree child] + (let [child-modifiers (gsh/calc-child-modifiers shape child modifiers ignore-constraints transformed-rect)] + (cond-> modif-tree + (not (gsh/empty-modifiers? child-modifiers)) + (set-modifiers-rec child child-modifiers)))) - modif-tree - (-> modif-tree - (assoc-in [(:id shape) :modifiers] modifiers))] + modif-tree + (-> modif-tree + (assoc-in [(:id shape) :modifiers] modifiers))] - (reduce set-child modif-tree children))) + (reduce set-child modif-tree children)))] + (set-modifiers-rec modif-tree shape modifiers))) (defn- get-ignore-tree "Retrieves a map with the flag `ignore-geometry?` given a tree of modifiers" @@ -480,12 +503,8 @@ focus (:workspace-focus-selected state) zoom (get-in state [:workspace-local :zoom] 1) objects (wsh/lookup-page-objects state page-id) - resizing-shapes (map #(get objects %) ids) - text-shapes-ids (->> resizing-shapes - (filter #(= :text (:type %))) - (map :id))] + resizing-shapes (map #(get objects %) ids)] (rx/concat - (rx/of (dch/update-shapes text-shapes-ids #(assoc % :grow-type :fixed))) (->> ms/mouse-position (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt) (rx/map normalize-proportion-lock) @@ -507,15 +526,17 @@ (ptk/reify ::update-dimensions ptk/UpdateEvent (update [_ state] - (let [page-id (:current-page-id state) - objects (get-in state [:workspace-data :pages-index page-id :objects]) + (let [objects (wsh/lookup-page-objects state) + layout (get state :workspace-layout) + snap-pixel? (contains? layout :snap-pixel-grid) update-modifiers (fn [state id] - (let [shape (get objects id) + (let [shape (get objects id) modifiers (gsh/resize-modifiers shape attr value)] - (update state :workspace-modifiers - #(set-modifiers-recursive % objects shape modifiers false false))))] + (-> state + (update :workspace-modifiers + #(set-objects-modifiers % objects shape modifiers false (and snap-pixel? (int? value)))))))] (reduce update-modifiers state ids))) ptk/WatchEvent diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index 907020c7ac..275b1ea106 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -82,9 +82,9 @@ [id params] (send-query! id params)) -(defmethod query :file - [id params] - (send-query! id params {:raw-transit? true})) +(defmethod query :file-raw + [_id params] + (send-query! :file params {:raw-transit? true})) (defmethod mutation :default [id params] diff --git a/frontend/src/app/main/ui/releases.cljs b/frontend/src/app/main/ui/releases.cljs index 8e56323206..a75dcfe3ad 100644 --- a/frontend/src/app/main/ui/releases.cljs +++ b/frontend/src/app/main/ui/releases.cljs @@ -13,6 +13,7 @@ [app.main.ui.releases.v1-10] [app.main.ui.releases.v1-11] [app.main.ui.releases.v1-12] + [app.main.ui.releases.v1-13] [app.main.ui.releases.v1-4] [app.main.ui.releases.v1-5] [app.main.ui.releases.v1-6] @@ -83,4 +84,4 @@ (defmethod rc/render-release-notes "0.0" [params] - (rc/render-release-notes (assoc params :version "1.12"))) + (rc/render-release-notes (assoc params :version "1.13"))) diff --git a/frontend/src/app/main/ui/releases/v1_13.cljs b/frontend/src/app/main/ui/releases/v1_13.cljs new file mode 100644 index 0000000000..4678e97821 --- /dev/null +++ b/frontend/src/app/main/ui/releases/v1_13.cljs @@ -0,0 +1,108 @@ +;; 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.releases.v1-13 + (:require + [app.main.ui.releases.common :as c] + [rumext.alpha :as mf])) + +(defmethod c/render-release-notes "1.13" + [{:keys [slide klass next finish navigate version]}] + (mf/html + (case @slide + :start + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/login-on.jpg" :border "0" :alt "What's new Beta release 1.13"}]] + [:div.modal-right + [:div.modal-title + [:h2 "What's new?"]] + [:span.release "Beta version " version] + [:div.modal-content + [:p "Penpot continues growing with new features that improve performance, user experience and visual design."] + [:p "We are happy to show you a sneak peak of the most important stuff that the Beta 1.13 version brings."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"]]] + [:img.deco {:src "images/deco-left.png" :border "0"}] + [:img.deco.right {:src "images/deco-right.png" :border "0"}]]]] + + 0 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/1.13-multi-export.gif" :border "0" :alt "Multiple exports"}]] + [:div.modal-right + [:div.modal-title + [:h2 "Multiple exports"]] + [:div.modal-content + [:p "Speed your workflow exporting multiple elements simultaneously."] + [:p "Use the export window to manage your multiple exports and be informed about the download progress. Big exports will happen in the background so you can continue designing in the meantime ;)"]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& c/navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 1 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/1.13-multiple-fills.gif" :border "0" :alt "Multiple fills and strokes"}]] + [:div.modal-right + [:div.modal-title + [:h2 "Multiple fills and strokes"]] + [:div.modal-content + [:p "Now you can add multiple color fills and strokes to a single element, including shapes and texts."] + [:p "This opens endless graphic possibilities such as combining gradients and blending modes in the same element to create visual effects."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& c/navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 2 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/1.13-members.gif" :border "0" :alt "Members area redesign"}]] + [:div.modal-right + [:div.modal-title + [:h2 "Members area redesign"]] + [:div.modal-content + [:p "Penpot is meant for teams, that’s why we decided to give some love to the members area."] + [:p "A refreshed interface and two new features: the Invitations section where you can check the state of the team invites and the ability to invite multiple members at the same time."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& c/navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 3 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/1.13-focus.gif" :border "0" :alt "Focus mode"}]] + [:div.modal-right + [:div.modal-title + [:h2 "Focus mode"]] + [:div.modal-content + [:p "Select the elements of a page you want to work with in a specific moment hiding the rest so they don’t get in the way of your attention."] + [:p "This option is also useful to improve the performance in cases where the page has a large number of elements."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click finish} "Start!"] + [:& c/navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]]))) diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index fa69ae097f..b124aca045 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.shapes.custom-stroke (:require + [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.shapes :as gsh] @@ -382,6 +383,14 @@ (some? style) (obj/set! "style" style))) + (some? (:svg-attrs shape)) + (let [style + (-> (obj/get props "style") + (obj/clone) + (obj/set! "fill" clr/black))] + (-> props + (obj/set! "style" style))) + (and (= :path (:type shape)) (empty? (:fills shape))) (let [style (-> (obj/get props "style") diff --git a/frontend/src/app/main/ui/shapes/svg_defs.cljs b/frontend/src/app/main/ui/shapes/svg_defs.cljs index e0d7bbc181..d127361cb3 100644 --- a/frontend/src/app/main/ui/shapes/svg_defs.cljs +++ b/frontend/src/app/main/ui/shapes/svg_defs.cljs @@ -72,11 +72,13 @@ [:> (name tag) (clj->js attrs) [:> wrapper wrapper-props - (for [node content] [:& svg-node {:type type - :node node - :prefix-id prefix-id - :transform transform - :bounds bounds}])]]))) + (for [[index node] (d/enumerate content)] + [:& svg-node {:key (dm/str "node-" index) + :type type + :node node + :prefix-id prefix-id + :transform transform + :bounds bounds}])]]))) (defn svg-def-bounds [svg-def shape transform] (let [{:keys [tag]} svg-def] @@ -107,10 +109,10 @@ (cond->> id (contains? svg-defs id) (str render-id "-")))] - ;; TODO: no key? (when (seq svg-defs) - (for [svg-def (vals svg-defs)] - [:& svg-node {:type (:type shape) + (for [[key svg-def] svg-defs] + [:& svg-node {:key (dm/str key) + :type (:type shape) :node svg-def :prefix-id prefix-id :transform transform diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index b2b9a8c978..22991ac905 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -117,6 +117,7 @@ thumb-renderer [:g.frame-thumbnail - [:> frame/frame-thumbnail {:shape (cond-> shape + [:> frame/frame-thumbnail {:key (dm/str (:id shape)) + :shape (cond-> shape (some? thumbnail-data) (assoc :thumbnail thumbnail-data))}]]])))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 5311132978..3624c041e9 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -38,15 +38,18 @@ (mf/use-layout-effect (mf/deps transforms) (fn [] - (when (and (empty? @prev-modifiers) (d/not-empty? modifiers)) - (utils/start-transform! node shapes)) + (let [is-prev-val? (d/not-empty? @prev-modifiers) + is-cur-val? (d/not-empty? modifiers)] - (when (d/not-empty? modifiers) - (utils/update-transform! node shapes transforms modifiers)) + (when (and (not is-prev-val?) is-cur-val?) + (utils/start-transform! node shapes)) - (when (and (d/not-empty? @prev-modifiers) (empty? modifiers)) - (utils/remove-transform! node @prev-shapes)) + (when is-cur-val? + (utils/update-transform! node shapes transforms modifiers)) - (reset! prev-modifiers modifiers) - (reset! prev-transforms transforms) - (reset! prev-shapes shapes))))) + (when (and is-prev-val? (not is-cur-val?)) + (utils/remove-transform! node @prev-shapes)) + + (reset! prev-modifiers modifiers) + (reset! prev-transforms transforms) + (reset! prev-shapes shapes)))))) 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 aea3696a0c..d0b9870332 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 @@ -48,11 +48,10 @@ (mf/use-callback (fn [] (let [canvas-node (mf/ref-val frame-canvas-ref) - img-node (mf/ref-val frame-image-ref)] - (ts/raf - #(let [thumb-data (draw-thumbnail-canvas canvas-node img-node)] - (st/emit! (dw/update-thumbnail id thumb-data)) - (reset! image-url nil)))))) + img-node (mf/ref-val frame-image-ref) + thumb-data (draw-thumbnail-canvas canvas-node img-node)] + (st/emit! (dw/update-thumbnail id thumb-data)) + (reset! image-url nil)))) on-change (mf/use-callback @@ -70,7 +69,6 @@ (dom/set-property! "height" height) (dom/set-property! "fill" "none") (obj/set! "innerHTML" frame-html)) - img-src (-> svg-node dom/node->xml dom/svg->data-uri)] (reset! image-url img-src))))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index f1efac1d8a..bec9538703 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -108,7 +108,7 @@ (fn [event] (dom/stop-propagation event) (if (and expanded? (kbd/shift? event)) - (st/emit! dwc/collapse-all) + (st/emit! (dwc/collapse-all)) (st/emit! (dwc/toggle-collapse id)))) toggle-blocking diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index f75698f58b..0e5c2ed638 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -158,9 +158,10 @@ show-outlines? (and (nil? transform) (not edition) (not drawing-obj) (not (#{:comments :path :curve} drawing-tool))) show-pixel-grid? (and (contains? layout :show-pixel-grid) (>= zoom 8)) + show-text-editor? (and editing-shape (= :text (:type editing-shape))) show-presence? page-id show-prototypes? (= options-mode :prototype) - show-selection-handlers? (and (seq selected) (not edition)) + show-selection-handlers? (and (seq selected) (not show-text-editor?)) show-snap-distance? (and (contains? layout :dynamic-alignment) (= transform :move) (seq selected)) @@ -172,7 +173,6 @@ show-artboard-names? (contains? layout :display-artboard-names) show-rules? (and (contains? layout :rules) (not (contains? layout :hide-ui))) - show-text-editor? (and editing-shape (= :text (:type editing-shape))) disabled-guides? (or drawing-tool transform)] diff --git a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs index a003b039e4..9aba15377c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs @@ -123,81 +123,75 @@ h-scrollbar-x) on-mouse-move - (mf/use-callback - (mf/deps zoom v-scrolling?) - (fn [event axis] - (when-let [_ (or @v-scrolling? @h-scrolling?)] - (let [viewport (mf/ref-val viewport-ref) - start-pt (mf/ref-val start-ref) - current-pt (dom/get-client-position event) - current-pt-viewport (utils/translate-point-to-viewport viewport zoom current-pt) - y-delta (/ (* (mf/ref-val height-factor-ref) (- (:y current-pt) (:y start-pt))) zoom) - x-delta (/ (* (mf/ref-val width-factor-ref) (- (:x current-pt) (:x start-pt))) zoom) - new-v-scrollbar-y (-> current-pt-viewport - (:y) - (+ (mf/ref-val v-scrollbar-y-padding-ref))) - new-h-scrollbar-x (-> current-pt-viewport - (:x) - (+ (mf/ref-val h-scrollbar-x-padding-ref))) - viewport-update (-> {} - (cond-> (= axis :y) (assoc :y #(+ % y-delta))) - (cond-> (= axis :x) (assoc :x #(+ % x-delta))))] - (mf/set-ref-val! vbox-y-ref vbox-y) - (mf/set-ref-val! vbox-x-ref vbox-x) - (st/emit! (dw/update-viewport-position viewport-update)) - (mf/set-ref-val! v-scrollbar-y-ref new-v-scrollbar-y) - (mf/set-ref-val! h-scrollbar-x-ref new-h-scrollbar-x) - (mf/set-ref-val! start-ref current-pt))))) + (fn [event axis] + (when-let [_ (or @v-scrolling? @h-scrolling?)] + (let [viewport (mf/ref-val viewport-ref) + start-pt (mf/ref-val start-ref) + current-pt (dom/get-client-position event) + current-pt-viewport (utils/translate-point-to-viewport viewport zoom current-pt) + y-delta (/ (* (mf/ref-val height-factor-ref) (- (:y current-pt) (:y start-pt))) zoom) + x-delta (/ (* (mf/ref-val width-factor-ref) (- (:x current-pt) (:x start-pt))) zoom) + new-v-scrollbar-y (-> current-pt-viewport + (:y) + (+ (mf/ref-val v-scrollbar-y-padding-ref))) + new-h-scrollbar-x (-> current-pt-viewport + (:x) + (+ (mf/ref-val h-scrollbar-x-padding-ref))) + viewport-update (-> {} + (cond-> (= axis :y) (assoc :y #(+ % y-delta))) + (cond-> (= axis :x) (assoc :x #(+ % x-delta))))] + (mf/set-ref-val! vbox-y-ref vbox-y) + (mf/set-ref-val! vbox-x-ref vbox-x) + (st/emit! (dw/update-viewport-position viewport-update)) + (mf/set-ref-val! v-scrollbar-y-ref new-v-scrollbar-y) + (mf/set-ref-val! h-scrollbar-x-ref new-h-scrollbar-x) + (mf/set-ref-val! start-ref current-pt)))) on-mouse-down - (mf/use-callback - (mf/deps v-scrollbar-y scrollbar-height) - (fn [event axis] - (let [viewport (mf/ref-val viewport-ref) - start-pt (dom/get-client-position event) - viewport-point (utils/translate-point-to-viewport viewport zoom start-pt) - new-h-scrollbar-x (:x viewport-point) - new-v-scrollbar-y (:y viewport-point) - v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y) - h-scrollbar-x-padding (- h-scrollbar-x new-h-scrollbar-x) - vbox-rect {:x vbox-x - :y vbox-y - :x1 vbox-x - :y1 vbox-y - :x2 (+ vbox-x (:width vbox)) - :y2 (+ vbox-y (:height vbox)) - :width (:width vbox) - :height (:height vbox)} - containing-rect (gsh/join-selrects [base-objects-rect vbox-rect]) - height-factor (/ (:height containing-rect) vbox-height) - width-factor (/ (:width containing-rect) vbox-width)] - (mf/set-ref-val! start-ref start-pt) - (mf/set-ref-val! v-scrollbar-y-padding-ref v-scrollbar-y-padding) - (mf/set-ref-val! h-scrollbar-x-padding v-scrollbar-y-padding) - (mf/set-ref-val! v-scrollbar-y-ref (+ new-v-scrollbar-y v-scrollbar-y-padding)) - (mf/set-ref-val! h-scrollbar-x-ref (+ new-h-scrollbar-x h-scrollbar-x-padding)) - (mf/set-ref-val! vbox-y-ref vbox-y) - (mf/set-ref-val! vbox-x-ref vbox-x) - (mf/set-ref-val! scrollbar-height-ref scrollbar-height) - (mf/set-ref-val! scrollbar-width-ref scrollbar-width) - (mf/set-ref-val! height-factor-ref height-factor) - (mf/set-ref-val! width-factor-ref width-factor) - (reset! v-scrolling? (= axis :y)) - (reset! h-scrolling? (= axis :x))))) + (fn [event axis] + (let [viewport (mf/ref-val viewport-ref) + start-pt (dom/get-client-position event) + viewport-point (utils/translate-point-to-viewport viewport zoom start-pt) + new-h-scrollbar-x (:x viewport-point) + new-v-scrollbar-y (:y viewport-point) + v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y) + h-scrollbar-x-padding (- h-scrollbar-x new-h-scrollbar-x) + vbox-rect {:x vbox-x + :y vbox-y + :x1 vbox-x + :y1 vbox-y + :x2 (+ vbox-x (:width vbox)) + :y2 (+ vbox-y (:height vbox)) + :width (:width vbox) + :height (:height vbox)} + containing-rect (gsh/join-selrects [base-objects-rect vbox-rect]) + height-factor (/ (:height containing-rect) vbox-height) + width-factor (/ (:width containing-rect) vbox-width)] + (mf/set-ref-val! start-ref start-pt) + (mf/set-ref-val! v-scrollbar-y-padding-ref v-scrollbar-y-padding) + (mf/set-ref-val! h-scrollbar-x-padding-ref h-scrollbar-x-padding) + (mf/set-ref-val! v-scrollbar-y-ref (+ new-v-scrollbar-y v-scrollbar-y-padding)) + (mf/set-ref-val! h-scrollbar-x-ref (+ new-h-scrollbar-x h-scrollbar-x-padding)) + (mf/set-ref-val! vbox-y-ref vbox-y) + (mf/set-ref-val! vbox-x-ref vbox-x) + (mf/set-ref-val! scrollbar-height-ref scrollbar-height) + (mf/set-ref-val! scrollbar-width-ref scrollbar-width) + (mf/set-ref-val! height-factor-ref height-factor) + (mf/set-ref-val! width-factor-ref width-factor) + (reset! v-scrolling? (= axis :y)) + (reset! h-scrolling? (= axis :x)))) on-mouse-up - (mf/use-callback - (mf/deps) - (fn [_] - (reset! v-scrolling? false) - (reset! h-scrolling? false)))] + (fn [] + (reset! v-scrolling? false) + (reset! h-scrolling? false))] [:* (when show-v-scroll? [:g.v-scroll [:rect {:on-mouse-move #(on-mouse-move % :y) :on-mouse-down #(on-mouse-down % :y) - :on-mouse-up #(on-mouse-up % :y) + :on-mouse-up on-mouse-up :width (* inv-zoom 7) :rx (* inv-zoom 3) :ry (* inv-zoom 3) @@ -211,7 +205,7 @@ [:g.h-scroll [:rect {:on-mouse-move #(on-mouse-move % :x) :on-mouse-down #(on-mouse-down % :x) - :on-mouse-up #(on-mouse-up % :x) + :on-mouse-up on-mouse-up :width scrollbar-width :rx (* inv-zoom 3) :ry (* inv-zoom 3) diff --git a/frontend/src/app/main/ui/workspace/viewport/utils.cljs b/frontend/src/app/main/ui/workspace/viewport/utils.cljs index 0c37143be9..69a53474fc 100644 --- a/frontend/src/app/main/ui/workspace/viewport/utils.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/utils.cljs @@ -91,7 +91,7 @@ (cond frame? [thumb-node - (dom/query shape-node ".frame-background") + (dom/get-parent (dom/query shape-node ".frame-background")) (dom/query shape-node ".frame-clip")] ;; For groups we don't want to transform the whole group but only @@ -223,8 +223,7 @@ :else (let [old-transform (dom/get-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 "data-old-transform") (dom/remove-attribute! node "transform"))))))))) (defn format-viewbox [vbox] diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index ad5fbfe403..9038d81815 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -344,7 +344,13 @@ (assoc :id (resolve page-id))) flows (->> (get-in page-data [:options :flows]) (mapv #(update % :starting-frame resolve))) - page-data (d/assoc-in-when page-data [:options :flows] flows) + + guides (-> (get-in page-data [:options :guides]) + (d/update-vals #(update % :frame-id resolve))) + + page-data (-> page-data + (d/assoc-in-when [:options :flows] flows) + (d/assoc-in-when [:options :guides] guides)) file (-> file (fb/add-page page-data)) ;; Preprocess nodes to parallel upload the images. Store the result in a table diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 66ac64dfb1..b27db88693 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -79,7 +79,7 @@ (let [objects (:objects page) frame (some->> page :thumbnail-frame-id (get objects)) element (if frame - (mf/element render/frame-svg #js {:objects objects :frame frame}) + (mf/element render/frame-svg #js {:objects objects :frame frame :show-thumbnails? true}) (mf/element render/page-svg #js {:data page :thumbnails? true}))] {:data (rds/renderToStaticMarkup element) :fonts @fonts/loaded