mirror of
https://github.com/penpot/penpot.git
synced 2025-06-14 16:11:40 +02:00
✨ Adds blur effect for shapes
This commit is contained in:
parent
ca83e13802
commit
6b240da892
16 changed files with 358 additions and 116 deletions
|
@ -55,7 +55,7 @@
|
||||||
(>= % min-safe-int)
|
(>= % min-safe-int)
|
||||||
(<= % max-safe-int)))
|
(<= % max-safe-int)))
|
||||||
|
|
||||||
|
;; GRADIENTS
|
||||||
|
|
||||||
(s/def :internal.gradient.stop/color ::string)
|
(s/def :internal.gradient.stop/color ::string)
|
||||||
(s/def :internal.gradient.stop/opacity ::safe-number)
|
(s/def :internal.gradient.stop/opacity ::safe-number)
|
||||||
|
@ -85,6 +85,63 @@
|
||||||
:internal.gradient/width
|
:internal.gradient/width
|
||||||
:internal.gradient/stops]))
|
:internal.gradient/stops]))
|
||||||
|
|
||||||
|
|
||||||
|
;;; COLORS
|
||||||
|
|
||||||
|
(s/def :internal.color/name ::string)
|
||||||
|
(s/def :internal.color/value (s/nilable ::string))
|
||||||
|
(s/def :internal.color/color (s/nilable ::string))
|
||||||
|
(s/def :internal.color/opacity (s/nilable ::safe-number))
|
||||||
|
(s/def :internal.color/gradient (s/nilable ::gradient))
|
||||||
|
|
||||||
|
(s/def ::color
|
||||||
|
(s/keys :opt-un [::id
|
||||||
|
:internal.color/name
|
||||||
|
:internal.color/value
|
||||||
|
:internal.color/color
|
||||||
|
:internal.color/opacity
|
||||||
|
:internal.color/gradient]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;; SHADOW EFFECT
|
||||||
|
|
||||||
|
(s/def :internal.shadow/id uuid?)
|
||||||
|
(s/def :internal.shadow/style #{:drop-shadow :inner-shadow})
|
||||||
|
(s/def :internal.shadow/color ::color)
|
||||||
|
(s/def :internal.shadow/offset-x ::safe-number)
|
||||||
|
(s/def :internal.shadow/offset-y ::safe-number)
|
||||||
|
(s/def :internal.shadow/blur ::safe-number)
|
||||||
|
(s/def :internal.shadow/spread ::safe-number)
|
||||||
|
(s/def :internal.shadow/hidden boolean?)
|
||||||
|
|
||||||
|
(s/def :internal.shadow/shadow
|
||||||
|
(s/keys :req-un [:internal.shadow/id
|
||||||
|
:internal.shadow/style
|
||||||
|
:internal.shadow/color
|
||||||
|
:internal.shadow/offset-x
|
||||||
|
:internal.shadow/offset-y
|
||||||
|
:internal.shadow/blur
|
||||||
|
:internal.shadow/spread
|
||||||
|
:internal.shadow/hidden]))
|
||||||
|
|
||||||
|
(s/def ::shadow
|
||||||
|
(s/coll-of :internal.shadow/shadow :kind vector?))
|
||||||
|
|
||||||
|
|
||||||
|
;;; BLUR EFFECT
|
||||||
|
|
||||||
|
(s/def :internal.blur/id uuid?)
|
||||||
|
(s/def :internal.blur/type #{:layer-blur})
|
||||||
|
(s/def :internal.blur/value ::safe-number)
|
||||||
|
(s/def :internal.blur/hidden boolean?)
|
||||||
|
|
||||||
|
(s/def ::blur
|
||||||
|
(s/keys :req-un [:internal.blur/id
|
||||||
|
:internal.blur/type
|
||||||
|
:internal.blur/value
|
||||||
|
:internal.blur/hidden]))
|
||||||
|
|
||||||
;; Page Options
|
;; Page Options
|
||||||
(s/def :internal.page.grid.color/value string?)
|
(s/def :internal.page.grid.color/value string?)
|
||||||
(s/def :internal.page.grid.color/opacity ::safe-number)
|
(s/def :internal.page.grid.color/opacity ::safe-number)
|
||||||
|
@ -175,6 +232,8 @@
|
||||||
(s/def :internal.shape/width ::safe-number)
|
(s/def :internal.shape/width ::safe-number)
|
||||||
(s/def :internal.shape/height ::safe-number)
|
(s/def :internal.shape/height ::safe-number)
|
||||||
(s/def :internal.shape/index integer?)
|
(s/def :internal.shape/index integer?)
|
||||||
|
(s/def :internal.shape/shadow ::shadow)
|
||||||
|
(s/def :internal.shape/blur ::blur)
|
||||||
|
|
||||||
(s/def :internal.shape/x1 ::safe-number)
|
(s/def :internal.shape/x1 ::safe-number)
|
||||||
(s/def :internal.shape/y1 ::safe-number)
|
(s/def :internal.shape/y1 ::safe-number)
|
||||||
|
@ -246,7 +305,9 @@
|
||||||
:internal.shape/interactions
|
:internal.shape/interactions
|
||||||
:internal.shape/selrect
|
:internal.shape/selrect
|
||||||
:internal.shape/points
|
:internal.shape/points
|
||||||
:internal.shape/masked-group?]))
|
:internal.shape/masked-group?
|
||||||
|
:internal.shape/shadow
|
||||||
|
:internal.shape/blur]))
|
||||||
|
|
||||||
(def component-sync-attrs {:fill-color :fill-group
|
(def component-sync-attrs {:fill-color :fill-group
|
||||||
:fill-color-ref-file :fill-group
|
:fill-color-ref-file :fill-group
|
||||||
|
@ -295,20 +356,6 @@
|
||||||
:internal.page/objects]))
|
:internal.page/objects]))
|
||||||
|
|
||||||
|
|
||||||
(s/def :internal.color/name ::string)
|
|
||||||
(s/def :internal.color/value (s/nilable ::string))
|
|
||||||
(s/def :internal.color/color (s/nilable ::string))
|
|
||||||
(s/def :internal.color/opacity (s/nilable ::safe-number))
|
|
||||||
(s/def :internal.color/gradient (s/nilable ::gradient))
|
|
||||||
|
|
||||||
(s/def ::color
|
|
||||||
(s/keys :req-un [::id
|
|
||||||
:internal.color/name]
|
|
||||||
:opt-un [:internal.color/value
|
|
||||||
:internal.color/color
|
|
||||||
:internal.color/opacity
|
|
||||||
:internal.color/gradient]))
|
|
||||||
|
|
||||||
(s/def ::recent-color
|
(s/def ::recent-color
|
||||||
(s/keys :opt-un [:internal.color/value
|
(s/keys :opt-un [:internal.color/value
|
||||||
:internal.color/color
|
:internal.color/color
|
||||||
|
|
|
@ -2271,6 +2271,24 @@
|
||||||
},
|
},
|
||||||
"unused" : true
|
"unused" : true
|
||||||
},
|
},
|
||||||
|
"workspace.options.blur-options.background-blur" : {
|
||||||
|
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/blur.cljs:78" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Background"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspace.options.blur-options.layer-blur" : {
|
||||||
|
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/blur.cljs:77" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Layer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspace.options.blur-options.title" : {
|
||||||
|
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/blur.cljs:107" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Blur"
|
||||||
|
}
|
||||||
|
},
|
||||||
"workspace.options.canvas-background" : {
|
"workspace.options.canvas-background" : {
|
||||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/page.cljs:45" ],
|
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/page.cljs:45" ],
|
||||||
"translations" : {
|
"translations" : {
|
||||||
|
|
|
@ -163,6 +163,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.element-set-title-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.add-page {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.collapse-pages {
|
.collapse-pages {
|
||||||
margin-left: $small;
|
margin-left: $small;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[app.util.color :as color]
|
[app.util.color :as color]
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.uuid :as uuid]))
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
|
@ -21,7 +22,8 @@
|
||||||
(defn filter-str
|
(defn filter-str
|
||||||
[filter-id shape]
|
[filter-id shape]
|
||||||
|
|
||||||
(when (seq (:shadow shape))
|
(when (or (seq (->> (:shadow shape) (remove :hidden)))
|
||||||
|
(and (:blur shape) (-> shape :blur :hidden not)))
|
||||||
(str/fmt "url(#$0)" [filter-id])))
|
(str/fmt "url(#$0)" [filter-id])))
|
||||||
|
|
||||||
(mf/defc color-matrix
|
(mf/defc color-matrix
|
||||||
|
@ -34,10 +36,9 @@
|
||||||
:values (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])}]))
|
:values (str/fmt "0 0 0 0 $0 0 0 0 0 $1 0 0 0 0 $2 0 0 0 $3 0" [r g b a])}]))
|
||||||
|
|
||||||
(mf/defc drop-shadow-filter
|
(mf/defc drop-shadow-filter
|
||||||
[{:keys [filter-id filter shape]}]
|
[{:keys [filter-in filter-id params]}]
|
||||||
|
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [color offset-x offset-y blur spread]} params]
|
||||||
{:keys [id in-filter color offset-x offset-y blur spread]} filter]
|
|
||||||
[:*
|
[:*
|
||||||
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
|
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
|
||||||
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}]
|
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}]
|
||||||
|
@ -45,21 +46,20 @@
|
||||||
[:feMorphology {:radius spread
|
[:feMorphology {:radius spread
|
||||||
:operator "dilate"
|
:operator "dilate"
|
||||||
:in "SourceAlpha"
|
:in "SourceAlpha"
|
||||||
:result (str "filter" id)}])
|
:result filter-id}])
|
||||||
|
|
||||||
[:feOffset {:dx offset-x :dy offset-y}]
|
[:feOffset {:dx offset-x :dy offset-y}]
|
||||||
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
|
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
|
||||||
[:& color-matrix {:color color}]
|
[:& color-matrix {:color color}]
|
||||||
|
|
||||||
[:feBlend {:mode "normal"
|
[:feBlend {:mode "normal"
|
||||||
:in2 in-filter
|
:in2 filter-in
|
||||||
:result (str "filter" id)}]]))
|
:result filter-id}]]))
|
||||||
|
|
||||||
(mf/defc inner-shadow-filter
|
(mf/defc inner-shadow-filter
|
||||||
[{:keys [filter-id filter shape]}]
|
[{:keys [filter-in filter-id params]}]
|
||||||
|
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [color offset-x offset-y blur spread]} params]
|
||||||
{:keys [id in-filter color offset-x offset-y blur spread]} filter]
|
|
||||||
[:*
|
[:*
|
||||||
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
|
[:feColorMatrix {:in "SourceAlpha" :type "matrix"
|
||||||
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
:values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
[:feMorphology {:radius spread
|
[:feMorphology {:radius spread
|
||||||
:operator "erode"
|
:operator "erode"
|
||||||
:in "SourceAlpha"
|
:in "SourceAlpha"
|
||||||
:result (str "filter" id)}])
|
:result filter-id}])
|
||||||
|
|
||||||
[:feOffset {:dx offset-x :dy offset-y}]
|
[:feOffset {:dx offset-x :dy offset-y}]
|
||||||
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
|
[:feGaussianBlur {:stdDeviation (/ blur 2)}]
|
||||||
|
@ -82,12 +82,36 @@
|
||||||
[:& color-matrix {:color color}]
|
[:& color-matrix {:color color}]
|
||||||
|
|
||||||
[:feBlend {:mode "normal"
|
[:feBlend {:mode "normal"
|
||||||
:in2 in-filter
|
:in2 filter-in
|
||||||
:result (str "filter" id)}]]))
|
:result filter-id}]]))
|
||||||
|
|
||||||
(defn filter-bounds [shape filter]
|
(mf/defc background-blur-filter
|
||||||
|
[{:keys [filter-id filter-in params]}]
|
||||||
|
[:*
|
||||||
|
[:feGaussianBlur {:in "BackgroundImage"
|
||||||
|
:stdDeviation (/ (:value params) 2)}]
|
||||||
|
[:feComposite {:in2 "SourceAlpha"
|
||||||
|
:operator "in"
|
||||||
|
:result filter-id}]])
|
||||||
|
|
||||||
|
(mf/defc layer-blur-filter
|
||||||
|
[{:keys [filter-id params]}]
|
||||||
|
|
||||||
|
[:feGaussianBlur {:stdDeviation (/ (:value params) 2)
|
||||||
|
:result filter-id}])
|
||||||
|
|
||||||
|
(mf/defc image-fix-filter [{:keys [filter-id]}]
|
||||||
|
[:feFlood {:flood-opacity 0 :result filter-id}])
|
||||||
|
|
||||||
|
(mf/defc blend-filters [{:keys [filter-id filter-in]}]
|
||||||
|
[:feBlend {:mode "normal"
|
||||||
|
:in "SourceGraphic"
|
||||||
|
:in2 filter-in
|
||||||
|
:result filter-id}])
|
||||||
|
|
||||||
|
(defn filter-bounds [shape filter-entry]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [x y width height]} (:selrect shape)
|
||||||
{:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} filter
|
{:keys [offset-x offset-y blur spread] :or {offset-x 0 offset-y 0 blur 0 spread 0}} (:params filter-entry)
|
||||||
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
|
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
|
||||||
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
|
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
|
||||||
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
|
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
|
||||||
|
@ -98,67 +122,83 @@
|
||||||
:y2 (+ filter-y filter-height)}))
|
:y2 (+ filter-y filter-height)}))
|
||||||
|
|
||||||
(defn get-filters-bounds
|
(defn get-filters-bounds
|
||||||
[shape filters]
|
[shape filters blur-value]
|
||||||
|
|
||||||
(let [filter-bounds (->>
|
(let [filter-bounds (->> filters
|
||||||
filters
|
(filter #(= :drop-shadow (:type %)))
|
||||||
(filter #(= :drop-shadow (:style %)))
|
(map (partial filter-bounds shape) ))
|
||||||
(map (partial filter-bounds shape) ))
|
|
||||||
;; We add the selrect so the minimum size will be the selrect
|
;; We add the selrect so the minimum size will be the selrect
|
||||||
filter-bounds (conj filter-bounds (:selrect shape))
|
filter-bounds (conj filter-bounds (:selrect shape))
|
||||||
x1 (apply min (map :x1 filter-bounds))
|
x1 (apply min (map :x1 filter-bounds))
|
||||||
y1 (apply min (map :y1 filter-bounds))
|
y1 (apply min (map :y1 filter-bounds))
|
||||||
x2 (apply max (map :x2 filter-bounds))
|
x2 (apply max (map :x2 filter-bounds))
|
||||||
y2 (apply max (map :y2 filter-bounds))]
|
y2 (apply max (map :y2 filter-bounds))
|
||||||
|
|
||||||
|
x1 (- x1 (* blur-value 2))
|
||||||
|
x2 (+ x2 (* blur-value 2))
|
||||||
|
y1 (- y1 (* blur-value 2))
|
||||||
|
y2 (+ y2 (* blur-value 2))]
|
||||||
[x1 y1 (- x2 x1) (- y2 y1)]))
|
[x1 y1 (- x2 x1) (- y2 y1)]))
|
||||||
|
|
||||||
|
(defn blur-filters [type value]
|
||||||
|
(->> [value]
|
||||||
|
(remove :hidden)
|
||||||
|
(filter #(= (:type %) type))
|
||||||
|
(map #(hash-map :id (str "filter_" (:id %))
|
||||||
|
:type (:type %)
|
||||||
|
:params %))))
|
||||||
|
|
||||||
|
(defn shadow-filters [type filters]
|
||||||
|
(->> filters
|
||||||
|
(remove :hidden)
|
||||||
|
(filter #(= (:style %) type))
|
||||||
|
(map #(hash-map :id (str "filter_" (:id %))
|
||||||
|
:type (:style %)
|
||||||
|
:params %))))
|
||||||
|
|
||||||
|
(mf/defc filter-entry [{:keys [entry]}]
|
||||||
|
(let [props #js {:filter-id (:id entry)
|
||||||
|
:filter-in (:filter-in entry)
|
||||||
|
:params (:params entry)}]
|
||||||
|
(case (:type entry)
|
||||||
|
:drop-shadow [:> drop-shadow-filter props]
|
||||||
|
:inner-shadow [:> inner-shadow-filter props]
|
||||||
|
:background-blur [:> background-blur-filter props]
|
||||||
|
:layer-blur [:> layer-blur-filter props]
|
||||||
|
:image-fix [:> image-fix-filter props]
|
||||||
|
:blend-filters [:> blend-filters props])))
|
||||||
|
|
||||||
(mf/defc filters
|
(mf/defc filters
|
||||||
[{:keys [filter-id shape]}]
|
[{:keys [filter-id shape]}]
|
||||||
|
|
||||||
(let [add-in-filter
|
(let [filters (d/concat
|
||||||
(fn [filter in-filter]
|
[]
|
||||||
(assoc filter :in-filter in-filter))
|
[{:id "BackgroundImageFix" :type :image-fix}]
|
||||||
|
|
||||||
filters (->> shape :shadow (filter (comp not :hidden)))
|
;; Background blur won't work in current SVG specification
|
||||||
|
;; We can revisit this in the future
|
||||||
|
#_(->> shape :blur (blur-filters :background-blur))
|
||||||
|
|
||||||
[filter-x filter-y filter-width filter-height] (get-filters-bounds shape filters)]
|
(->> shape :shadow (shadow-filters :drop-shadow))
|
||||||
(when (seq filters)
|
[{:id "shape" :type :blend-filters}]
|
||||||
[:filter {:id filter-id
|
(->> shape :shadow (shadow-filters :inner-shadow))
|
||||||
:x filter-x :y filter-y
|
(->> shape :blur (blur-filters :layer-blur)))
|
||||||
:width filter-width :height filter-height
|
|
||||||
:filterUnits "userSpaceOnUse"
|
|
||||||
:color-interpolation-filters "sRGB"}
|
|
||||||
|
|
||||||
(let [;; Add as a paramter the input filter
|
;; Adds the previous filter as `filter-in` parameter
|
||||||
drop-shadow-filters (->> filters (filter #(= :drop-shadow (:style %))))
|
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))
|
||||||
drop-shadow-filters (->> drop-shadow-filters
|
|
||||||
(map #(str "filter" (:id %)))
|
|
||||||
(cons "BackgroundImageFix")
|
|
||||||
(map add-in-filter drop-shadow-filters))
|
|
||||||
|
|
||||||
inner-shadow-filters (->> filters (filter #(= :inner-shadow (:style %))))
|
[filter-x filter-y filter-width filter-height] (get-filters-bounds shape filters (or (-> shape :blur :value) 0))]
|
||||||
inner-shadow-filters (->> inner-shadow-filters
|
|
||||||
(map #(str "filter" (:id %)))
|
|
||||||
(cons "shape")
|
|
||||||
(map add-in-filter inner-shadow-filters))]
|
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:feFlood {:flood-opacity 0 :result "BackgroundImageFix"}]
|
(when (> (count filters) 2)
|
||||||
(for [{:keys [id type] :as filter} drop-shadow-filters]
|
[:filter {:id filter-id
|
||||||
[:& drop-shadow-filter {:key id
|
:x filter-x
|
||||||
:filter-id filter-id
|
:y filter-y
|
||||||
:filter filter
|
:width filter-width
|
||||||
:shape shape}])
|
:height filter-height
|
||||||
|
:filterUnits "userSpaceOnUse"
|
||||||
|
:color-interpolation-filters "sRGB"}
|
||||||
|
|
||||||
[:feBlend {:mode "normal"
|
(for [entry filters]
|
||||||
:in "SourceGraphic"
|
[:& filter-entry {:entry entry}])])]))
|
||||||
:in2 (if (seq drop-shadow-filters)
|
|
||||||
(str "filter" (:id (last drop-shadow-filters)))
|
|
||||||
"BackgroundImageFix")
|
|
||||||
:result "shape"}]
|
|
||||||
|
|
||||||
(for [{:keys [id type] :as filter} inner-shadow-filters]
|
|
||||||
[:& inner-shadow-filter {:key id
|
|
||||||
:filter-id filter-id
|
|
||||||
:filter filter
|
|
||||||
:shape shape}])])])))
|
|
||||||
|
|
|
@ -10,12 +10,35 @@
|
||||||
(ns app.main.ui.shapes.shape
|
(ns app.main.ui.shapes.shape
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
[app.common.geom.shapes :as geom]
|
||||||
[app.main.ui.shapes.filters :as filters]
|
[app.main.ui.shapes.filters :as filters]
|
||||||
[app.main.ui.shapes.gradients :as grad]
|
[app.main.ui.shapes.gradients :as grad]
|
||||||
[app.main.ui.context :as muc]))
|
[app.main.ui.context :as muc]))
|
||||||
|
|
||||||
|
(mf/defc background-blur [{:keys [shape]}]
|
||||||
|
(when-let [background-blur-filters (->> shape :blur (remove #(= (:type %) :layer-blur)) (remove :hidden))]
|
||||||
|
(for [filter background-blur-filters]
|
||||||
|
[:*
|
||||||
|
|
||||||
|
|
||||||
|
[:foreignObject {:key (str "blur_" (:id filter))
|
||||||
|
:pointerEvents "none"
|
||||||
|
:x (:x shape)
|
||||||
|
:y (:y shape)
|
||||||
|
:width (:width shape)
|
||||||
|
:height (:height shape)
|
||||||
|
:transform (geom/transform-matrix shape)}
|
||||||
|
[:style ""]
|
||||||
|
[:div.backround-blur
|
||||||
|
{:style {:width "100%"
|
||||||
|
:height "100%"
|
||||||
|
;; :backdrop-filter (str/format "blur(%spx)" (:value filter))
|
||||||
|
:filter (str/format "blur(4px")
|
||||||
|
}}]]])))
|
||||||
|
|
||||||
(mf/defc shape-container
|
(mf/defc shape-container
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
@ -28,12 +51,23 @@
|
||||||
(obj/clone)
|
(obj/clone)
|
||||||
(obj/without ["shape" "children"])
|
(obj/without ["shape" "children"])
|
||||||
(obj/set! "className" "shape")
|
(obj/set! "className" "shape")
|
||||||
(obj/set! "filter" (filters/filter-str filter-id shape)))]
|
(obj/set! "data-type" (:type shape))
|
||||||
|
(obj/set! "filter" (filters/filter-str filter-id shape)))
|
||||||
|
|
||||||
|
;;group-props (if (seq (:blur shape))
|
||||||
|
;; (obj/set! group-props "clip-path" (str/fmt "url(#%s)" (str "blur_" render-id)))
|
||||||
|
;; group-props)
|
||||||
|
]
|
||||||
[:& (mf/provider muc/render-ctx) {:value render-id}
|
[:& (mf/provider muc/render-ctx) {:value render-id}
|
||||||
[:> :g group-props
|
[:> :g group-props
|
||||||
[:defs
|
[:defs
|
||||||
[:& filters/filters {:shape shape :filter-id filter-id}]
|
[:& filters/filters {:shape shape :filter-id filter-id}]
|
||||||
[:& grad/gradient {:shape shape :attr :fill-color-gradient}]
|
[:& grad/gradient {:shape shape :attr :fill-color-gradient}]
|
||||||
[:& grad/gradient {:shape shape :attr :stroke-color-gradient}]]
|
[:& grad/gradient {:shape shape :attr :stroke-color-gradient}]
|
||||||
|
|
||||||
|
#_(when (:blur shape)
|
||||||
|
[:clipPath {:id (str "blur_" render-id)}
|
||||||
|
children])]
|
||||||
|
|
||||||
|
[:& background-blur {:shape shape}]
|
||||||
children]]))
|
children]]))
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.workspace.shapes.common :as common]
|
[app.main.ui.workspace.shapes.common :as common]
|
||||||
|
[app.main.ui.shapes.shape :refer [shape-container]]
|
||||||
[app.main.ui.shapes.group :as group]
|
[app.main.ui.shapes.group :as group]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
|
@ -72,11 +73,10 @@
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(st/emit! (dw/select-inside-group (:id shape) @ms/mouse-position))))]
|
(st/emit! (dw/select-inside-group (:id shape) @ms/mouse-position))))]
|
||||||
|
|
||||||
[:g.shape
|
[:> shape-container {:shape shape
|
||||||
{:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu
|
:on-context-menu on-context-menu
|
||||||
:on-double-click on-double-click}
|
:on-double-click on-double-click}
|
||||||
|
|
||||||
[:& group-shape
|
[:& group-shape
|
||||||
{:frame frame
|
{:frame frame
|
||||||
:shape shape
|
:shape shape
|
||||||
|
|
70
frontend/src/app/main/ui/workspace/sidebar/options/blur.cljs
Normal file
70
frontend/src/app/main/ui/workspace/sidebar/options/blur.cljs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.ui.workspace.sidebar.options.blur
|
||||||
|
(:require
|
||||||
|
[rumext.alpha :as mf]
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.workspace.common :as dwc]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.icons :as i]
|
||||||
|
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[app.util.i18n :as i18n :refer [t]]))
|
||||||
|
|
||||||
|
(defn create-blur []
|
||||||
|
(let [id (uuid/next)]
|
||||||
|
{:id id
|
||||||
|
:type :layer-blur
|
||||||
|
:value 4
|
||||||
|
:hidden false}))
|
||||||
|
|
||||||
|
(mf/defc blur-menu [{:keys [ids values]}]
|
||||||
|
(let [locale (i18n/use-locale)
|
||||||
|
blur (:blur values)
|
||||||
|
has-value? (not (nil? blur))
|
||||||
|
|
||||||
|
change! (fn [update-fn] (st/emit! (dwc/update-shapes ids update-fn)))
|
||||||
|
|
||||||
|
handle-add
|
||||||
|
(fn []
|
||||||
|
(change! #(assoc % :blur (create-blur))))
|
||||||
|
|
||||||
|
handle-delete
|
||||||
|
(fn []
|
||||||
|
(change! #(dissoc % :blur)))
|
||||||
|
|
||||||
|
handle-change
|
||||||
|
(fn [value]
|
||||||
|
(change! #(assoc-in % [:blur :value] value)))
|
||||||
|
|
||||||
|
handle-toggle-visibility
|
||||||
|
(fn []
|
||||||
|
(change! #(update-in % [:blur :hidden] not)))]
|
||||||
|
|
||||||
|
[:div.element-set
|
||||||
|
[:div.element-set-title
|
||||||
|
[:span (t locale "workspace.options.blur-options.title")]
|
||||||
|
[:div.element-set-title-actions
|
||||||
|
(if has-value?
|
||||||
|
[:div.add-page {:on-click handle-toggle-visibility} (if (:hidden blur) i/eye-closed i/eye)])
|
||||||
|
(if has-value?
|
||||||
|
[:div.add-page {:on-click handle-delete} i/minus]
|
||||||
|
[:div.add-page {:on-click handle-add} i/close])]]
|
||||||
|
|
||||||
|
(when has-value?
|
||||||
|
[:div.element-set-content
|
||||||
|
[:& input-row {:label "Value"
|
||||||
|
:class "pixels"
|
||||||
|
:min 0
|
||||||
|
:value (:value blur)
|
||||||
|
:on-change handle-change}]])]))
|
|
@ -13,7 +13,8 @@
|
||||||
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
@ -33,5 +34,6 @@
|
||||||
:type type
|
:type type
|
||||||
:values stroke-values}]
|
:values stroke-values}]
|
||||||
[:& shadow-menu {:ids ids
|
[:& shadow-menu {:ids ids
|
||||||
:type type
|
:values (select-keys shape [:shadow])}]
|
||||||
:values (select-keys shape [:shadow])}]]))
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]]))
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(st/emit! (dc/change-fill ids {:color cp/default-color
|
(st/emit! (dc/change-fill ids {:color cp/default-color
|
||||||
:opacity 1}))))
|
:opacity 1}))))
|
||||||
|
|
||||||
on-delete
|
on-delete
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]]
|
[app.main.ui.workspace.sidebar.options.frame-grid :refer [frame-grid]]
|
||||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]))
|
||||||
|
|
||||||
(declare +size-presets+)
|
(declare +size-presets+)
|
||||||
|
|
||||||
|
@ -204,16 +205,17 @@
|
||||||
(let [ids [(:id shape)]
|
(let [ids [(:id shape)]
|
||||||
type (:type shape)
|
type (:type shape)
|
||||||
stroke-values (select-keys shape stroke-attrs)]
|
stroke-values (select-keys shape stroke-attrs)]
|
||||||
[:*
|
[:*
|
||||||
[:& measures-menu {:shape shape}]
|
[:& measures-menu {:shape shape}]
|
||||||
[:& fill-menu {:ids ids
|
[:& fill-menu {:ids ids
|
||||||
:type type
|
|
||||||
:values (select-keys shape fill-attrs)}]
|
|
||||||
[:& stroke-menu {:ids ids
|
|
||||||
:type type
|
:type type
|
||||||
:values stroke-values}]
|
:values (select-keys shape fill-attrs)}]
|
||||||
[:& shadow-menu {:ids ids
|
[:& stroke-menu {:ids ids
|
||||||
:type type
|
:type type
|
||||||
:values (select-keys shape [:shadow])}]
|
:values stroke-values}]
|
||||||
[:& frame-grid {:shape shape}]]))
|
[:& shadow-menu {:ids ids
|
||||||
|
:values (select-keys shape [:shadow])}]
|
||||||
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]
|
||||||
|
[:& frame-grid {:shape shape}]]))
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
[app.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]]
|
[app.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]]
|
||||||
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.text :refer [text-fill-attrs
|
[app.main.ui.workspace.sidebar.options.text :refer [text-fill-attrs
|
||||||
text-font-attrs
|
text-font-attrs
|
||||||
|
@ -138,6 +139,10 @@
|
||||||
[:& fill-menu {:ids ids-with-children
|
[:& fill-menu {:ids ids-with-children
|
||||||
:type type
|
:type type
|
||||||
:values fill-values}]
|
:values fill-values}]
|
||||||
|
|
||||||
|
[:& blur-menu {:ids [id]
|
||||||
|
:values (select-keys shape [:blur])}]
|
||||||
|
|
||||||
(when-not (empty? other-ids)
|
(when-not (empty? other-ids)
|
||||||
[:& stroke-menu {:ids other-ids
|
[:& stroke-menu {:ids other-ids
|
||||||
:type type
|
:type type
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
(ns app.main.ui.workspace.sidebar.options.image
|
(ns app.main.ui.workspace.sidebar.options.image
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]))
|
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
@ -20,4 +22,9 @@
|
||||||
[:*
|
[:*
|
||||||
[:& measures-menu {:ids ids
|
[:& measures-menu {:ids ids
|
||||||
:type type
|
:type type
|
||||||
:values measure-values}]]))
|
:values measure-values}]
|
||||||
|
[:& shadow-menu {:ids ids
|
||||||
|
:values (select-keys shape [:shadow])}]
|
||||||
|
|
||||||
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]]))
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
|
@ -28,5 +29,6 @@
|
||||||
:type type
|
:type type
|
||||||
:values stroke-values}]
|
:values stroke-values}]
|
||||||
[:& shadow-menu {:ids ids
|
[:& shadow-menu {:ids ids
|
||||||
:type type
|
:values (select-keys shape [:shadow])}]
|
||||||
:values (select-keys shape [:shadow])}]]))
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]]))
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
[app.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]))
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
|
@ -30,10 +31,13 @@
|
||||||
[:& fill-menu {:ids ids
|
[:& fill-menu {:ids ids
|
||||||
:type type
|
:type type
|
||||||
:values fill-values}]
|
:values fill-values}]
|
||||||
|
|
||||||
[:& stroke-menu {:ids ids
|
[:& stroke-menu {:ids ids
|
||||||
:type type
|
:type type
|
||||||
:values stroke-values}]
|
:values stroke-values}]
|
||||||
[:& shadow-menu {:ids ids
|
|
||||||
:type type
|
|
||||||
:values (select-keys shape [:shadow])}]]))
|
|
||||||
|
|
||||||
|
[:& shadow-menu {:ids ids
|
||||||
|
:values (select-keys shape [:shadow])}]
|
||||||
|
|
||||||
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]]))
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
|
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
|
||||||
[app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]]
|
|
||||||
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]
|
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [t]]))
|
[app.util.i18n :as i18n :refer [t]]))
|
||||||
|
@ -25,8 +24,7 @@
|
||||||
(let [id (uuid/next)]
|
(let [id (uuid/next)]
|
||||||
{:id id
|
{:id id
|
||||||
:style :drop-shadow
|
:style :drop-shadow
|
||||||
:color "#000000"
|
:color {:color "#000000" :opacity 0.2}
|
||||||
:opacity 0.2
|
|
||||||
:offset-x 4
|
:offset-x 4
|
||||||
:offset-y 4
|
:offset-y 4
|
||||||
:blur 4
|
:blur 4
|
||||||
|
@ -183,7 +181,7 @@
|
||||||
:on-open #(st/emit! dwc/start-undo-transaction)
|
:on-open #(st/emit! dwc/start-undo-transaction)
|
||||||
:on-close #(st/emit! dwc/commit-undo-transaction)}]]]]))
|
:on-close #(st/emit! dwc/commit-undo-transaction)}]]]]))
|
||||||
(mf/defc shadow-menu
|
(mf/defc shadow-menu
|
||||||
[{:keys [ids type values] :as props}]
|
[{:keys [ids values] :as props}]
|
||||||
|
|
||||||
(let [locale (i18n/use-locale)
|
(let [locale (i18n/use-locale)
|
||||||
on-add-shadow
|
on-add-shadow
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
[app.main.ui.workspace.sidebar.options.fill :refer [fill-menu]]
|
[app.main.ui.workspace.sidebar.options.fill :refer [fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.typography :refer [typography-entry typography-options]]
|
[app.main.ui.workspace.sidebar.options.typography :refer [typography-entry typography-options]]
|
||||||
|
[app.main.ui.workspace.sidebar.options.blur :refer [blur-menu]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[app.util.i18n :as i18n :refer [tr t]]
|
[app.util.i18n :as i18n :refer [tr t]]
|
||||||
|
@ -318,8 +319,9 @@
|
||||||
:values fill-values
|
:values fill-values
|
||||||
:editor editor}]
|
:editor editor}]
|
||||||
[:& shadow-menu {:ids ids
|
[:& shadow-menu {:ids ids
|
||||||
:type type
|
|
||||||
:values (select-keys shape [:shadow])}]
|
:values (select-keys shape [:shadow])}]
|
||||||
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]
|
||||||
[:& text-menu {:ids ids
|
[:& text-menu {:ids ids
|
||||||
:type type
|
:type type
|
||||||
:values text-values
|
:values text-values
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue