diff --git a/frontend/src/app/main/ui/render.cljs b/frontend/src/app/main/ui/render.cljs index f7de7b8628..c6853ecd2e 100644 --- a/frontend/src/app/main/ui/render.cljs +++ b/frontend/src/app/main/ui/render.cljs @@ -78,7 +78,8 @@ :height height :version "1.1" :xmlnsXlink "http://www.w3.org/1999/xlink" - :xmlns "http://www.w3.org/2000/svg"} + :xmlns "http://www.w3.org/2000/svg" + :xmlns:penpot "https://penpot.app/xmlns"} (case (:type object) :frame [:& frame-wrapper {:shape object :view-box vbox}] :group [:> shape-container {:shape object} diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index f3759ce0c2..1e19f219fd 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -6,11 +6,13 @@ (ns app.main.ui.shapes.custom-stroke (:require - [rumext.alpha :as mf] - [app.common.uuid :as uuid] + [app.common.data :as d] [app.common.geom.shapes :as geom] + [app.common.uuid :as uuid] + [app.main.ui.context :as muc] [app.util.object :as obj] - [app.main.ui.context :as muc])) + [cuerdas.core :as str] + [rumext.alpha :as mf])) (defn add-props [props new-props] @@ -71,13 +73,22 @@ shape (obj/get props "shape") stroke-width (:stroke-width shape 0) stroke-mask-id (str "outer-stroke-" render-id) - shape-id (str "stroke-shape-" render-id)] + shape-id (str "stroke-shape-" render-id) + + style-str (->> (obj/get base-props "style") + (js->clj) + (mapv (fn [[k v]] + (-> (d/name k) + (str/kebab) + (str ":" v)))) + (str/join ";"))] [:g.outer-stroke-shape [:symbol [:> elem-name (-> (obj/clone base-props) (obj/set! "id" shape-id) - (obj/without ["style"]))]] + (obj/set! "data-style" style-str) + (obj/without ["style"]))]] [:use {:href (str "#" shape-id) :mask (str "url(#" stroke-mask-id ")") diff --git a/frontend/src/app/main/ui/shapes/shape.cljs b/frontend/src/app/main/ui/shapes/shape.cljs index cd05e9d11b..5a8d4fecdf 100644 --- a/frontend/src/app/main/ui/shapes/shape.cljs +++ b/frontend/src/app/main/ui/shapes/shape.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.uuid :as uuid] + [app.common.geom.matrix :as gmt] [app.main.ui.context :as muc] [app.main.ui.shapes.custom-stroke :as cs] [app.main.ui.shapes.fill-image :as fim] @@ -17,6 +18,36 @@ [app.util.object :as obj] [rumext.alpha :as mf])) +(defn add-metadata + "Adds as metadata properties that we cannot deduce from the exported SVG" + [props shape] + (let [add! + (fn [props attr val] + (let [ns-attr (str "penpot:" (-> attr d/name))] + (-> props + (obj/set! ns-attr val)))) + frame? (= :frame type)] + (-> props + (add! :name (-> shape :name)) + (add! :blocked (-> shape (:blocked false) str)) + (add! :hidden (-> shape (:hidden false) str)) + (add! :type (-> shape :type d/name)) + + (add! :stroke-style (-> shape (:stroke-style :none) d/name)) + (add! :stroke-alignment (-> shape (:stroke-alignment :center) d/name)) + + (add! :transform (-> shape (:transform (gmt/matrix)) str)) + (add! :transform-inverse (-> shape (:transform-inverse (gmt/matrix)) str)) + + (cond-> (some? (:r1 shape)) + (-> (add! :r1 (-> shape (:r1 0) str)) + (add! :r2 (-> shape (:r2 0) str)) + (add! :r3 (-> shape (:r3 0) str)) + (add! :r4 (-> shape (:r4 0) str)))) + + (cond-> frame? + (obj/set! "xmlns:penpot" "https://penpot.app/xmlns"))))) + (mf/defc shape-container {::mf/forward-ref true ::mf/wrap-props false} @@ -34,24 +65,29 @@ {:keys [x y width height type]} shape frame? (= :frame type) - group-props (-> (obj/clone props) - (obj/without ["shape" "children"]) - (obj/set! "ref" ref) - (obj/set! "id" (str "shape-" (:id shape))) - (obj/set! "filter" (filters/filter-str filter-id shape)) - (obj/set! "style" styles) - (cond-> frame? - (-> (obj/set! "x" x) - (obj/set! "y" y) - (obj/set! "width" width) - (obj/set! "height" height) - (obj/set! "xmlnsXlink" "http://www.w3.org/1999/xlink") - (obj/set! "xmlns" "http://www.w3.org/2000/svg")))) + wrapper-props + (-> (obj/clone props) + (obj/without ["shape" "children"]) + (obj/set! "ref" ref) + (obj/set! "id" (str "shape-" (:id shape))) + (obj/set! "filter" (filters/filter-str filter-id shape)) + (obj/set! "style" styles) + + (cond-> frame? + (-> (obj/set! "x" x) + (obj/set! "y" y) + (obj/set! "width" width) + (obj/set! "height" height) + (obj/set! "xmlnsXlink" "http://www.w3.org/1999/xlink") + (obj/set! "xmlns" "http://www.w3.org/2000/svg"))) + + (add-metadata shape)) wrapper-tag (if frame? "svg" "g")] + [:& (mf/provider muc/render-ctx) {:value render-id} - [:> wrapper-tag group-props + [:> wrapper-tag wrapper-props [:defs [:& defs/svg-defs {:shape shape :render-id render-id}] [:& filters/filters {:shape shape :filter-id filter-id}] diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 380c96f777..e65bc12d05 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -278,7 +278,6 @@ (let [point (gpt/transform point transform-inverse) end-x (/ (- (:x point) x) width) end-y (/ (- (:y point) y) height) - end-x (mth/precision end-x 2) end-y (mth/precision end-y 2)] (change! {:end-x end-x :end-y end-y}))) @@ -287,8 +286,8 @@ (let [scale-factor-y (/ gradient-length (/ height 2)) norm-dist (/ (gpt/distance point from-p) (* (/ width 2) scale-factor-y))] - - (change! {:width norm-dist})))] + (when (and norm-dist (mth/finite? norm-dist)) + (change! {:width norm-dist}))))] (when (and gradient (= id (:shape-id gradient))