diff --git a/CHANGES.md b/CHANGES.md index 5b9d0d4df..8f5fb32ed 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ ### :sparkles: New features +- Add stroke properties for image shapes [Taiga #497](https://tree.taiga.io/project/penpot/us/497) - On user settings, hide the theme selector as long as we only have one theme [Taiga #2610](https://tree.taiga.io/project/penpot/us/2610) - Automatically open comments from dashboard notifications [Taiga #2605](https://tree.taiga.io/project/penpot/us/2605) - Enhance the behaviour of the artboards list on view mode [Taiga #2634](https://tree.taiga.io/project/penpot/us/2634) diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 081306f4c..06ef83ccf 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -81,6 +81,10 @@ (defn add-fill [attrs shape render-id] (let [fill-attrs (cond + (contains? shape :fill-image) + (let [fill-image-id (str "fill-image-" render-id)] + {:fill (str/format "url(#%s)" fill-image-id)}) + (contains? shape :fill-color-gradient) (let [fill-color-gradient-id (str "fill-color-gradient_" render-id)] {:fill (str/format "url(#%s)" fill-color-gradient-id)}) @@ -88,14 +92,10 @@ (contains? shape :fill-color) {:fill (:fill-color shape)} - (contains? shape :fill-image) - (let [fill-image-id (str "fill-image-" render-id)] - {:fill (str/format "url(#%s)" fill-image-id) }) - ;; If contains svg-attrs the origin is svg. If it's not svg origin ;; we setup the default fill as transparent (instead of black) (and (not (contains? shape :svg-attrs)) - (not (#{ :svg-raw :group } (:type shape)))) + (not (#{:svg-raw :group} (:type shape)))) {:fill "none"} :else @@ -206,3 +206,11 @@ [shape] (-> (obj/new) (add-style-attrs shape))) + +(defn extract-fill-attrs + [shape] + (let [render-id (mf/use-ctx muc/render-ctx) + fill-styles (-> (obj/get shape "style" (obj/new)) + (add-fill shape render-id))] + (-> (obj/new) + (obj/set! "style" fill-styles)))) diff --git a/frontend/src/app/main/ui/shapes/fill_image.cljs b/frontend/src/app/main/ui/shapes/fill_image.cljs index 986dbc37e..e3c8f2dc7 100644 --- a/frontend/src/app/main/ui/shapes/fill_image.cljs +++ b/frontend/src/app/main/ui/shapes/fill_image.cljs @@ -8,6 +8,7 @@ (:require [app.common.geom.shapes :as gsh] [app.config :as cfg] + [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.embed :as embed] [app.util.object :as obj] [rumext.alpha :as mf])) @@ -23,7 +24,11 @@ fill-image-id (str "fill-image-" render-id) uri (cfg/resolve-file-media (:fill-image shape)) embed (embed/use-data-uris [uri]) - transform (gsh/transform-matrix shape)] + transform (gsh/transform-matrix shape) + shape-without-image (dissoc shape :fill-image) + fill-attrs (-> (attrs/extract-fill-attrs shape-without-image) + (obj/set! "width" width) + (obj/set! "height" height))] [:pattern {:id fill-image-id :patternUnits "userSpaceOnUse" @@ -33,6 +38,9 @@ :width width :patternTransform transform :data-loading (str (not (contains? embed uri)))} - [:image {:xlinkHref (get embed uri uri) - :width width - :height height}]])))) + [:g + [:> :rect fill-attrs] + [:image {:xlinkHref (get embed uri uri) + :width width + :height height}] + ]])))) diff --git a/frontend/src/app/main/ui/shapes/image.cljs b/frontend/src/app/main/ui/shapes/image.cljs index 5fa4eec47..d438fa5cf 100644 --- a/frontend/src/app/main/ui/shapes/image.cljs +++ b/frontend/src/app/main/ui/shapes/image.cljs @@ -6,11 +6,12 @@ (ns app.main.ui.shapes.image (:require - [app.common.geom.shapes :as geom] + [app.common.geom.shapes :as gsh] [app.config :as cfg] + [app.main.ui.context :as muc] [app.main.ui.shapes.attrs :as attrs] + [app.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]] [app.main.ui.shapes.embed :as embed] - [app.util.dom :as dom] [app.util.object :as obj] [rumext.alpha :as mf])) @@ -23,22 +24,36 @@ uri (cfg/resolve-file-media metadata) embed (embed/use-data-uris [uri]) - transform (geom/transform-matrix shape) + transform (gsh/transform-matrix shape) + + fill-attrs (-> (attrs/extract-fill-attrs shape) + (obj/set! "width" width) + (obj/set! "height" height)) + + render-id (mf/use-ctx muc/render-ctx) + fill-image-id (str "fill-image-" render-id) + shape (assoc shape :fill-image fill-image-id) props (-> (attrs/extract-style-attrs shape) (obj/merge! #js {:x x :y y :transform transform :width width - :height height - :preserveAspectRatio "none" - :data-loading (str (not (contains? embed uri)))})) + :height height}))] - on-drag-start (fn [event] - ;; Prevent browser dragging of the image - (dom/prevent-default event))] - - [:> "image" (obj/merge! - props - #js {:xlinkHref (get embed uri uri) - :onDragStart on-drag-start})])) + [:g + [:defs + [:pattern {:id fill-image-id + :patternUnits "userSpaceOnUse" + :x x + :y y + :height height + :width width + :data-loading (str (not (contains? embed uri)))} + [:g + [:> :rect fill-attrs] + [:image {:xlinkHref (get embed uri uri) + :width width + :height height}]]]] + [:& shape-custom-stroke {:shape shape} + [:> :rect props]]])) diff --git a/frontend/src/app/main/ui/shapes/path.cljs b/frontend/src/app/main/ui/shapes/path.cljs index 36155fc7e..c7d0b3e0f 100644 --- a/frontend/src/app/main/ui/shapes/path.cljs +++ b/frontend/src/app/main/ui/shapes/path.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.shapes.path (:require [app.common.logging :as log] + [app.main.ui.context :as muc] [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]] [app.util.object :as obj] @@ -18,7 +19,10 @@ (mf/defc path-shape {::mf/wrap-props false} [props] - (let [shape (unchecked-get props "shape") + (let [shape (-> (unchecked-get props "shape") + (dissoc :fill-color) + (dissoc :fill-opacity) + (dissoc :fill-image)) content (:content shape) pdata (mf/with-memo [content] (try @@ -30,6 +34,8 @@ :cause e) ""))) + render-id (mf/use-ctx muc/render-ctx) + shape (assoc shape :fill-image (str "fill-image-" render-id)) props (-> (attrs/extract-style-attrs shape) (obj/set! "d" pdata))] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index b71574c29..eb91a0fa6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -8,9 +8,11 @@ (:require [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] + [app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs fill-menu]] [app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]] [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] + [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [rumext.alpha :as mf])) (mf/defc options @@ -19,7 +21,9 @@ type (:type shape) measure-values (select-keys shape measure-attrs) layer-values (select-keys shape layer-attrs) - constraint-values (select-keys shape constraint-attrs)] + constraint-values (select-keys shape constraint-attrs) + fill-values (select-keys shape fill-attrs) + stroke-values (select-keys shape stroke-attrs)] [:* [:& measures-menu {:ids ids :type type @@ -32,6 +36,14 @@ :type type :values layer-values}] + [:& fill-menu {:ids ids + :type type + :values fill-values}] + + [:& stroke-menu {:ids ids + :type type + :values stroke-values}] + [:& shadow-menu {:ids ids :values (select-keys shape [:shadow])}]