diff --git a/common/src/app/common/geom/shapes/bounds.cljc b/common/src/app/common/geom/shapes/bounds.cljc index 95b215c686..e87ff975d1 100644 --- a/common/src/app/common/geom/shapes/bounds.cljc +++ b/common/src/app/common/geom/shapes/bounds.cljc @@ -38,13 +38,13 @@ (d/concat-vec [{:id "BackgroundImageFix" :type :image-fix}] - ;; Background blur won't work in current SVG specification - ;; We can revisit this in the future - #_(->> shape :blur (into []) (blur-filters :background-blur)) - (->> shape :shadow (apply-filters :style :drop-shadow)) [{:id "shape" :type :blend-filters}] (->> shape :shadow (apply-filters :style :inner-shadow)) + + ;; Background blur won't work in current SVG specification + ;; We can revisit this in the future + #_(->> shape :background-blur list (apply-filters :type :background-blur)) (->> shape :blur list (apply-filters :type :layer-blur)))) (defn- calculate-filter-bounds @@ -100,17 +100,13 @@ ;; shapes because selrect stores the unrotated rectangle, not the screen-space bbox. (and (empty? (-> shape :shadow)) (or (nil? (:blur shape)) - (not= :layer-blur (-> shape :blur :type)) (zero? (-> shape :blur :value (or 0))))) (-> (dm/get-prop shape :points) (grc/points->rect)) :else (let [filters (shape->filters shape) - blur-value (case (-> shape :blur :type) - :layer-blur (or (-> shape :blur :value) 0) - :background-blur 0 - 0) + blur-value (or (-> shape :blur :value) 0) srect (-> (dm/get-prop shape :points) (grc/points->rect))] (get-rect-filter-bounds srect filters blur-value ignore-shadow-margin?))))) @@ -242,10 +238,7 @@ (not (cfh/frame-shape? shape)) (or (:children-bounds shape))) filters (shape->filters shape) - blur-value (case (-> shape :blur :type) - :layer-blur (or (-> shape :blur :value) 0) - :background-blur 0 - 0)] + blur-value (or (-> shape :blur :value) 0)] (get-rect-filter-bounds children-bounds filters blur-value ignore-shadow-margin?)))) diff --git a/common/src/app/common/geom/shapes/effects.cljc b/common/src/app/common/geom/shapes/effects.cljc index 66859380c7..7e1096e6b8 100644 --- a/common/src/app/common/geom/shapes/effects.cljc +++ b/common/src/app/common/geom/shapes/effects.cljc @@ -24,3 +24,7 @@ [shape scale] (update-in shape [:blur :value] * scale)) +(defn update-background-blur-scale + [shape scale] + (update-in shape [:background-blur :value] * scale)) + diff --git a/common/src/app/common/types/component.cljc b/common/src/app/common/types/component.cljc index 5edb8c3675..46337ca813 100644 --- a/common/src/app/common/types/component.cljc +++ b/common/src/app/common/types/component.cljc @@ -91,6 +91,7 @@ :blend-mode :layer-effects-group :shadow :shadow-group :blur :blur-group + :background-blur :blur-group :masked-group :mask-group :constraints-h :constraints-group :constraints-v :constraints-group diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 68ab9e2584..dbc0b52296 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -692,6 +692,9 @@ (some? (:blur shape)) (gse/update-blur-scale value) + (some? (:background-blur shape)) + (gse/update-background-blur-scale value) + (ctl/flex-layout? shape) (ctl/update-flex-scale value) diff --git a/common/src/app/common/types/path/bool.cljc b/common/src/app/common/types/path/bool.cljc index 0c01ddf2ff..d2fdf01cb7 100644 --- a/common/src/app/common/types/path/bool.cljc +++ b/common/src/app/common/types/path/bool.cljc @@ -25,7 +25,7 @@ fills))) (def group-style-properties - #{:shadow :blur}) + #{:shadow :blur :background-blur}) ;; FIXME: revisit (def style-properties diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index c3275b421f..c7334d1717 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -24,6 +24,7 @@ [app.common.types.path :as path] [app.common.types.plugins :as ctpg] [app.common.types.shape.attrs :refer [default-color]] + [app.common.types.shape.background-blur :as ctsbb] [app.common.types.shape.blur :as ctsb] [app.common.types.shape.export :as ctse] [app.common.types.shape.interactions :as ctsi] @@ -222,6 +223,7 @@ [:shadow {:optional true} [:vector {:gen/max 1} ctss/schema:shadow]] [:blur {:optional true} ctsb/schema:blur] + [:background-blur {:optional true} ctsbb/schema:background-blur] [:grow-type {:optional true} [::sm/one-of grow-types]] [:applied-tokens {:optional true} cto/schema:applied-tokens] @@ -415,7 +417,7 @@ :remote-synced :shape-ref :touched :blocked :collapsed :locked :hidden :masked-group :fills :proportion :proportion-lock :constraints-h :constraints-v :fixed-scroll :r1 :r2 :r3 :r4 :rotation :opacity :grids :exports - :strokes :blend-mode :interactions :shadow :blur :grow-type :applied-tokens + :strokes :blend-mode :interactions :shadow :blur :background-blur :grow-type :applied-tokens :plugin-data}) (def ^:private allowed-shape-geom-attrs #{:x :y :width :height}) @@ -657,6 +659,7 @@ ;; - Contraints ;; - Shadow ;; - Blur +;; - Background blur ;; - Border radius (def ^:private basic-extract-props #{:fills @@ -681,6 +684,7 @@ :shadow :blur + :background-blur ;; Radius :r1 diff --git a/common/src/app/common/types/shape/attrs.cljc b/common/src/app/common/types/shape/attrs.cljc index 34d4ed62bb..0d76f5afa4 100644 --- a/common/src/app/common/types/shape/attrs.cljc +++ b/common/src/app/common/types/shape/attrs.cljc @@ -32,6 +32,7 @@ :shadow :blur + :background-blur :fills :fill-color @@ -108,6 +109,7 @@ :shadow :blur + :background-blur :exports @@ -166,6 +168,7 @@ :shadow :blur + :background-blur :exports @@ -223,6 +226,7 @@ :shadow :blur + :background-blur :exports @@ -280,6 +284,7 @@ :shadow :blur + :background-blur :exports @@ -336,6 +341,7 @@ :shadow :blur + :background-blur :typography-ref-id :typography-ref-file @@ -398,6 +404,7 @@ :shadow :blur + :background-blur :exports @@ -456,6 +463,7 @@ :shadow :blur + :background-blur :exports @@ -513,6 +521,7 @@ :shadow :blur + :background-blur :exports diff --git a/common/src/app/common/types/shape/background_blur.cljc b/common/src/app/common/types/shape/background_blur.cljc new file mode 100644 index 0000000000..214629a580 --- /dev/null +++ b/common/src/app/common/types/shape/background_blur.cljc @@ -0,0 +1,16 @@ +;; 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) KALEIDOS INC Sucursal en España SL + +(ns app.common.types.shape.background-blur + (:require + [app.common.schema :as sm])) + +(def schema:background-blur + [:map {:title "BackgroundBlur"} + [:id ::sm/uuid] + [:type [:enum :background-blur]] + [:value ::sm/safe-number] + [:hidden :boolean]]) \ No newline at end of file diff --git a/common/src/app/common/types/shape/blur.cljc b/common/src/app/common/types/shape/blur.cljc index 90eae19fb3..e0a149d2bc 100644 --- a/common/src/app/common/types/shape/blur.cljc +++ b/common/src/app/common/types/shape/blur.cljc @@ -8,12 +8,9 @@ (:require [app.common.schema :as sm])) -(def schema:blur-type - [:enum :layer-blur :background-blur]) - (def schema:blur [:map {:title "Blur"} [:id ::sm/uuid] - [:type schema:blur-type] + [:type [:enum :layer-blur]] [:value ::sm/safe-number] [:hidden :boolean]]) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index add4f050b4..96a1605704 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -73,6 +73,7 @@ :r4 :shadow :blur + :background-blur :strokes :width :height diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 5bd1a63f6d..35183701f5 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -281,7 +281,7 @@ (grc/fix-aspect-ratio aspect-ratio)) ;; Bounds without shadows/blur will be the bounds of the thumbnail - bounds2 (gsb/get-object-bounds objects (dissoc frame :shadow :blur)) + bounds2 (gsb/get-object-bounds objects (dissoc frame :shadow :blur :background-blur)) delta-bounds (gpt/point (:x bounds) (:y bounds)) vector (gpt/negate delta-bounds) diff --git a/frontend/src/app/main/ui/components/title_bar.cljs b/frontend/src/app/main/ui/components/title_bar.cljs index 1eb6631015..d294504dd4 100644 --- a/frontend/src/app/main/ui/components/title_bar.cljs +++ b/frontend/src/app/main/ui/components/title_bar.cljs @@ -14,33 +14,32 @@ (mf/defc title-bar* [{:keys [class collapsable collapsed title children btn-icon btn-title add-icon-gap - title-class on-collapsed on-btn-click]}] - [:div {:class [(stl/css :title-bar) - class]} + title-class on-collapsed on-btn-click] :rest props}] + (let [props (mf/spread-props props {:class (stl/css :icon-text-btn) + :on-click on-collapsed})] - (if ^boolean collapsable - [:div {:class [(stl/css :title-wrapper) title-class]} + [:div {:class [(stl/css :title-bar) class]} + (if ^boolean collapsable + [:div {:class [(stl/css :title-wrapper) title-class]} + (let [icon-id (if collapsed "arrow-right" "arrow-down")] + [:> :button props + [:> icon* {:icon-id icon-id + :size "s" + :class (stl/css :icon)}] + [:div {:class (stl/css :title)} title]])] - (let [icon-id (if collapsed "arrow-right" "arrow-down")] - [:button {:class (stl/css :icon-text-btn) - :on-click on-collapsed} - [:> icon* {:icon-id icon-id - :size "s" - :class (stl/css :icon)}] - [:div {:class (stl/css :title)} title]])] + [:div {:class [(stl/css-case :title-only true + :title-only-icon-gap add-icon-gap) + title-class]} + title]) - [:div {:class [(stl/css-case :title-only true - :title-only-icon-gap add-icon-gap) - title-class]} - title]) + children - children - - (when (some? on-btn-click) - [:> icon-button* {:variant "ghost" - :aria-label btn-title - :on-click on-btn-click - :icon btn-icon}])]) + (when (some? on-btn-click) + [:> icon-button* {:variant "ghost" + :aria-label btn-title + :on-click on-btn-click + :icon btn-icon}])])) (mf/defc inspect-title-bar* diff --git a/frontend/src/app/main/ui/components/title_bar.scss b/frontend/src/app/main/ui/components/title_bar.scss index 1dc26b6bf1..3f8045feeb 100644 --- a/frontend/src/app/main/ui/components/title_bar.scss +++ b/frontend/src/app/main/ui/components/title_bar.scss @@ -25,6 +25,7 @@ display: grid; align-items: center; justify-content: flex-start; + text-align: start; grid-auto-flow: column; height: 100%; min-height: deprecated.$s-32; diff --git a/frontend/src/app/main/ui/inspect/attributes/blur.cljs b/frontend/src/app/main/ui/inspect/attributes/blur.cljs index 831580fb13..7fcff35194 100644 --- a/frontend/src/app/main/ui/inspect/attributes/blur.cljs +++ b/frontend/src/app/main/ui/inspect/attributes/blur.cljs @@ -8,6 +8,8 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] + [app.config :as cf] + [app.main.features :as features] [app.main.ui.components.copy-button :refer [copy-button*]] [app.main.ui.components.title-bar :refer [inspect-title-bar*]] [app.util.code-gen.style-css :as css] @@ -15,35 +17,53 @@ [rumext.v2 :as mf])) (defn- has-blur? [shape] - (:blur shape)) - -(defn- blur-css-property [shape] - (if (= :background-blur (get-in shape [:blur :type])) - :backdrop-filter - :filter)) + (or (:blur shape) + (:background-blur shape))) (mf/defc blur-panel [{:keys [objects shapes]}] - (let [shapes (->> shapes (filter has-blur?))] + (let [render-wasm? (features/use-feature "render-wasm/v1") + bg-blur? (and render-wasm? + (contains? cf/flags :background-blur)) + shapes (->> shapes (filter #(has-blur? %))) + title (if bg-blur? + (tr "labels.blur-effects") + (tr "labels.blur"))] (when (seq shapes) [:div {:class (stl/css :attributes-block)} [:> inspect-title-bar* - {:title (tr "inspect.attributes.blur") + {:title title :class (stl/css :title-wrapper) :title-class (stl/css :blur-attr-title)} (when (= (count shapes) 1) - (let [prop (blur-css-property (first shapes))] - [:> copy-button* {:data (css/get-css-property objects (first shapes) prop) - :class (stl/css :copy-btn-title)}]))] + (let [background-blur (:background-blur (first shapes)) + layer-blur (:blur (first shapes))] + (when background-blur + [:> copy-button* {:data (css/get-css-property objects (first shapes) :backdrop-filter) + :class (stl/css :copy-btn-title)}]) + (when layer-blur + [:> copy-button* {:data (css/get-css-property objects (first shapes) :filter) + :class (stl/css :copy-btn-title)}])))] [:div {:class (stl/css :attributes-content)} (for [shape shapes] - (let [prop (blur-css-property shape)] + (let [background-blur (:background-blur (first shapes)) + layer-blur (:blur (first shapes))] [:div {:class (stl/css :blur-row) :key (dm/str "block-" (:id shape) "-blur")} - [:div {:class (stl/css :global/attr-label)} - (if (= prop :backdrop-filter) "Backdrop Filter" "Filter")] - [:div {:class (stl/css :global/attr-value)} - [:> copy-button* {:data (css/get-css-property objects shape prop)} - [:div {:class (stl/css :button-children)} - (css/get-css-value objects shape prop)]]]]))]]))) + (when background-blur + [:* + [:div {:class (stl/css :global/attr-label)} + "Backdrop Filter"] + [:div {:class (stl/css :global/attr-value)} + [:> copy-button* {:data (css/get-css-property objects shape :backdrop-filter)} + [:div {:class (stl/css :button-children)} + (css/get-css-value objects shape :backdrop-filter)]]]]) + (when layer-blur + [:* + [:div {:class (stl/css :global/attr-label)} + "Filter"] + [:div {:class (stl/css :global/attr-value)} + [:> copy-button* {:data (css/get-css-property objects shape :filter)} + [:div {:class (stl/css :button-children)} + (css/get-css-value objects shape :filter)]]]])]))]]))) diff --git a/frontend/src/app/main/ui/inspect/styles.cljs b/frontend/src/app/main/ui/inspect/styles.cljs index 307fcb66fd..7b8238e40c 100644 --- a/frontend/src/app/main/ui/inspect/styles.cljs +++ b/frontend/src/app/main/ui/inspect/styles.cljs @@ -51,7 +51,6 @@ :grid-column :grid-row]) - (def type->panel-group {:multiple [:fill :stroke :text :shadow :blur :layout-element] :frame [:visibility :geometry :fill :stroke :shadow :blur :layout :layout-element] @@ -72,7 +71,8 @@ (seq (:strokes shape))) (defn- has-blur? [shape] - (:blur shape)) + (or (:blur shape) + (:background-blur shape))) (defn- has-text? [shape] (:content shape)) diff --git a/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs b/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs index d7fd9b7202..0f4efc8409 100644 --- a/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs +++ b/frontend/src/app/main/ui/inspect/styles/panels/blur.cljs @@ -18,12 +18,24 @@ [:div {:class (stl/css :blur-panel)} (for [shape shapes] [:div {:key (:id shape) :class (stl/css :blur-shape)} - (let [property :filter - value (css/get-css-value objects shape property) - property-name (cmm/get-css-rule-humanized property) - property-value (css/get-css-property objects shape property)] - [:> properties-row* {:key (dm/str "blur-property-" property) - :term property-name - :detail (dm/str value) - :property property-value - :copiable true}])])]) + (let [blur-property :filter + blur-value (css/get-css-value objects shape blur-property) + background-blur-property :backdrop-filter + blur-property-name (cmm/get-css-rule-humanized blur-property) + blur-property-value (css/get-css-property objects shape blur-property) + background-blur-value (css/get-css-value objects shape background-blur-property) + background-blur-property-name (cmm/get-css-rule-humanized background-blur-property) + background-blur-property-value (css/get-css-property objects shape background-blur-property)] + [:* + (when blur-property-value + [:> properties-row* {:key (dm/str "blur-property-" blur-property) + :term blur-property-name + :detail (dm/str blur-value) + :property blur-property-value + :copiable true}]) + (when background-blur-property-value + [:> properties-row* {:key (dm/str "blur-property-" background-blur-property) + :term background-blur-property-name + :detail (dm/str background-blur-value) + :property background-blur-property-value + :copiable true}])])])]) diff --git a/frontend/src/app/main/ui/inspect/styles/style_box.cljs b/frontend/src/app/main/ui/inspect/styles/style_box.cljs index e285a867f6..c106197fa3 100644 --- a/frontend/src/app/main/ui/inspect/styles/style_box.cljs +++ b/frontend/src/app/main/ui/inspect/styles/style_box.cljs @@ -8,6 +8,8 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.config :as cf] + [app.main.features :as features] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.util.clipboard :as clipboard] @@ -16,22 +18,27 @@ (defn- panel->title [type] - (case type - :variant (tr "inspect.tabs.styles.variants-panel") - :token (tr "inspect.tabs.styles.token-panel") - :geometry (tr "inspect.attributes.size") - :fill (tr "labels.fill") - :stroke (tr "labels.stroke") - :text (tr "labels.text") - :blur (tr "labels.blur") - :shadow (tr "labels.shadow") - :layout (tr "labels.layout") - :flex-element "Flex Element" - :grid-element "Grid Element" - :layout-element "Layout Element" - :visibility (tr "labels.visibility") - :svg (tr "labels.svg") - nil)) + (let [render-wasm? (features/use-feature "render-wasm/v1") + bg-blur? (and render-wasm? + (contains? cf/flags :background-blur))] + (case type + :variant (tr "inspect.tabs.styles.variants-panel") + :token (tr "inspect.tabs.styles.token-panel") + :geometry (tr "inspect.attributes.size") + :fill (tr "labels.fill") + :stroke (tr "labels.stroke") + :text (tr "labels.text") + :blur (if bg-blur? + (tr "labels.blur-effects") + (tr "labels.blur")) + :shadow (tr "labels.shadow") + :layout (tr "labels.layout") + :flex-element "Flex Element" + :grid-element "Grid Element" + :layout-element "Layout Element" + :visibility (tr "labels.visibility") + :svg (tr "labels.svg") + nil))) (mf/defc style-box* [{:keys [panel shorthand children]}] diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index bf2642bc19..118812762e 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -183,6 +183,7 @@ ([props shape position render-id] (let [shape-fills (get shape :fills) shape-shadow (get shape :shadow) + shape-blur (get shape :blur) svg-attrs (get-svg-props shape render-id) diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index 201673302e..dfb0a5a1b8 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -480,7 +480,8 @@ stroke-id (dm/str (dm/fmt "strokes-%-%" prefix shape-id)) - shape-blur (get shape :blur) + shape-blur (get shape :blur) + shape-fills (get shape :fills) shape-shadow (get shape :shadow) shape-strokes (not-empty strokes) @@ -498,6 +499,7 @@ open-path? (and ^boolean (cfh/path-shape? shape) ^boolean (path/shape-with-open-path? shape))] + (when-not ^boolean (cfh/frame-shape? shape) (when (and (some? shape-blur) (not ^boolean (:hidden shape-blur))) diff --git a/frontend/src/app/main/ui/shapes/export.cljs b/frontend/src/app/main/ui/shapes/export.cljs index 39c2ecfa79..018544d59b 100644 --- a/frontend/src/app/main/ui/shapes/export.cljs +++ b/frontend/src/app/main/ui/shapes/export.cljs @@ -217,8 +217,8 @@ :penpot:spread (str spread)}]))) (defn- export-blur-data [{:keys [blur]}] - (when-let [{:keys [type hidden value]} blur] - (mf/html + (when-let [{:keys [type hidden value]} blur] + (mf/html [:> "penpot:blur" #js {:penpot:blur-type (d/name type) :penpot:hidden (str hidden) diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index 82acf0a70b..b95c887dd8 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -67,6 +67,7 @@ filter-id-blur (dm/fmt "filter-blur-%" render-id) filter-id-shadows (dm/fmt "filter-shadow-%" render-id) + filter-str-blur (filters/filter-str filter-id-blur (dissoc shape :shadow)) filter-str-shadows (filters/filter-str filter-id-shadows (dissoc shape :blur)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs index 82bd76c1ef..8c975fb64f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs @@ -14,146 +14,279 @@ [app.main.data.workspace.shapes :as dwsh] [app.main.features :as features] [app.main.store :as st] - [app.main.ui.components.numeric-input :refer [numeric-input*]] - [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.controls.numeric-input :refer [numeric-input*]] + [app.main.ui.ds.controls.select :refer [select*]] [app.main.ui.ds.foundations.assets.icon :as i] - [app.main.ui.icons :as deprecated-icon] + [app.main.ui.ds.tooltip.tooltip :refer [tooltip*]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) -(def blur-attrs [:blur]) +(def blur-attrs [:blur :background-blur]) -(defn create-blur [] +(defn create-blur [type] (let [id (uuid/next)] {:id id - :type :layer-blur + :type type :value 4 :hidden false})) -(mf/defc blur-menu* [{:keys [ids type values]}] - (let [blur (:blur values) - has-value? (not (nil? blur)) - render-wasm? (features/use-feature "render-wasm/v1") - bg-blur? (and render-wasm? - (contains? cf/flags :background-blur)) +(mf/defc blur-menu-content* + [{:keys [blur-key value change-fn blur-values]}] + (let [render-wasm? (features/use-feature "render-wasm/v1") + bg-blur? (and render-wasm? + (contains? cf/flags :background-blur)) + is-hidden (get value :hidden) + show-more-options* (mf/use-state false) + show-more-options (deref show-more-options*) + toggle-more-options (mf/use-fn #(swap! show-more-options* not)) - state* (mf/use-state {:show-content true - :show-more-options false}) + handle-delete + (mf/use-fn + (mf/deps change-fn blur-key) + (fn [] + (change-fn #(dissoc % blur-key)))) + + handle-toggle-visibility + (mf/use-fn + (mf/deps change-fn blur-key) + (fn [] + (change-fn #(update-in % [blur-key :hidden] not)))) + + handle-change + (mf/use-fn + (mf/deps change-fn blur-key) + (fn [value] + (change-fn #(assoc-in % [blur-key :value] value)))) + + handle-type-change + (mf/use-fn + (mf/deps change-fn value blur-key) + (fn [type] + (let [type-kw (keyword type) + target-key (if (= type-kw :layer-blur) :blur :background-blur)] + (change-fn + (fn [shape] + (cond + ;; mismo tipo + (= blur-key target-key) + shape + + ;; ya existe un blur del tipo destino + (contains? shape target-key) + shape + + ;; blur origen no existe + (not (contains? shape blur-key)) + shape + + :else + (let [blur (get shape blur-key)] + (-> shape + (dissoc blur-key) + (assoc target-key + (assoc blur :type type-kw)))))))))) + + bb-disabled? (and (= 2 (count blur-values)) + (not= blur-key :background-blur)) + lb-disabled? (and (= 2 (count blur-values)) + (not= blur-key :blur)) + label-ref (mf/use-ref nil) + + type-options + [{:value "layer-blur" :disabled lb-disabled? :id "layer-blur" :label (tr "workspace.options.blur-options.layer-blur")} + {:value "background-blur" :disabled bb-disabled? :id "background-blur" :label (tr "workspace.options.blur-options.background-blur")}]] + + [:* + [:div {:class (stl/css-case :first-row true + :hidden is-hidden)} + [:div {:class (stl/css :blur-info) + :data-testid "blur-info"} + [:> icon-button* {:class (stl/css-case :show-more true + :selected show-more-options) + :on-click toggle-more-options + :selected show-more-options + :variant "ghost" + :disabled (or + is-hidden + (and (= blur-key :background-blur) + (= false bg-blur?))) + :aria-label (tr "workspace.options.blur-options.toggle-more-options") + :icon i/menu}] + (if bg-blur? + [:> select* {:class (stl/css :blur-type-select) + :default-selected (d/name (:type value)) + :options type-options + :disabled is-hidden + :on-change handle-type-change}] + [:> tooltip* {:trigger-ref label-ref + :id "background-blur-disabled-label" + :class (stl/css :disabled-label-tooltip) + :content (tr "workspace.options.blur-options.disabled-blur-label")} + [:span {:aria-labelledby "background-blur-disabled-label" + :ref label-ref + :class (stl/css-case :label true + :disabled-label (and (= blur-key :background-blur) + (= false bg-blur?)))} + (d/name (:type value))]])] + + [:div {:class (stl/css :actions)} + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.blur-options.toggle-blur") + :on-click handle-toggle-visibility + :disabled (and (= blur-key :background-blur) + (= false bg-blur?)) + :tooltip-placement "top-left" + :icon (if (or is-hidden + (and (= blur-key :background-blur) + (= false bg-blur?))) i/hide i/shown)}] + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.blur-options.remove-blur") + :on-click handle-delete + :tooltip-placement "top-left" + :icon i/remove}]]] + + (when show-more-options + [:div {:class (stl/css :second-row)} + [:> numeric-input* + {:class (stl/css :numeric-input) + :placeholder "--" + :min 0 + :text-icon "value" + :on-change handle-change + :name "blur-value" + :value (:value value)}]])])) + +(defn get-blurs [values] + (cond-> [] + (:blur values) + (conj {:key :blur + :value (:blur values)}) + + (:background-blur values) + (conj {:key :background-blur + :value (:background-blur values)}))) + +(defn- check-props + "A blur-menu specific memoize check function that only checks if + specific values are changed on provided props. This allows pass the + whole shape as values without adding additional rerenders when other + shape properties changes." + [n-props o-props] + (and (identical? (unchecked-get n-props "ids") + (unchecked-get o-props "ids")) + (let [o-vals (unchecked-get o-props "values") + n-vals (unchecked-get n-props "values") + o-blur-values (get o-vals :blur) + n-blur-values (get n-vals :blur) + o-background-blur-values (get o-vals :background-blur) + n-background-blur-values (get n-vals :background-blur)] + (and (identical? o-blur-values n-blur-values) + (identical? o-background-blur-values n-background-blur-values))))) + +(mf/defc blur-menu* + {::mf/wrap [#(mf/memo' % check-props)]} + [{:keys [ids type values]}] + (let [render-wasm? (features/use-feature "render-wasm/v1") + bg-blur? (and render-wasm? + (contains? cf/flags :background-blur)) + + blur-values (get-blurs values) + + mixed-state (and (or (= :group type) + (= :multiple type)) + (boolean + (some #(= :multiple (:value %)) blur-values))) + + state* (mf/use-state {:show-content true}) state (deref state*) open? (:show-content state) - more-options? (:show-more-options state) toggle-content (mf/use-fn #(swap! state* update :show-content not)) - toggle-more-options (mf/use-fn #(swap! state* update :show-more-options not)) - hidden? (:hidden blur) - change! (mf/use-fn (mf/deps ids) (fn [update-fn] - (st/emit! (dwsh/update-shapes ids update-fn)))) + (st/emit! (dwsh/update-shapes ids update-fn) + (udw/trigger-bounding-box-cloaking ids)))) + + handle-delete-all + (mf/use-fn + (mf/deps change!) + (fn [] + (change! #(dissoc % :blur :background-blur)))) handle-add (mf/use-fn - (mf/deps change! ids) + (mf/deps change! blur-values) (fn [] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (change! #(assoc % :blur (create-blur))))) + (cond + (= 1 (count blur-values)) + (let [existing-key (:key (first blur-values)) + new-key (if (= existing-key :blur) + :background-blur + :blur)] + (change! #(assoc % new-key (create-blur (if (= :blur new-key) + :layer-blur + :background-blur))))) + (= 0 (count blur-values)) + (change! #(assoc % :blur (create-blur :layer-blur)))) + :else + blur-values))] - handle-delete - (mf/use-fn - (mf/deps change! ids) - (fn [] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (change! #(dissoc % :blur)))) - - handle-change - (mf/use-fn - (mf/deps change! ids) - (fn [value] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (change! #(cond-> % - (not (contains? % :blur)) - (assoc :blur (create-blur)) - - :always - (assoc-in [:blur :value] value))))) - - handle-type-change - (mf/use-fn - (mf/deps change! ids) - (fn [value] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (change! #(assoc-in % [:blur :type] (keyword value))))) - - handle-toggle-visibility - (mf/use-fn - (mf/deps change! ids) - (fn [] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (change! #(update-in % [:blur :hidden] not)))) - - type-options - (mf/with-memo [bg-blur?] - (cond-> [{:value "layer-blur" :label (tr "workspace.options.blur-options.layer-blur")}] - bg-blur? - (conj {:value "background-blur" :label (tr "workspace.options.blur-options.background-blur")})))] - - [:div {:class (stl/css :element-set)} + [:section {:class (stl/css :element-set) + :hidden (not open?) + :aria-label (if bg-blur? + (tr "labels.blur-effects") + (tr "labels.blur"))} [:div {:class (stl/css :element-title)} - [:> title-bar* {:collapsable has-value? + [:> title-bar* {:collapsable (seq blur-values) :collapsed (not open?) :on-collapsed toggle-content - :title (case type - :multiple (tr "workspace.options.blur-options.title.multiple") - :group (tr "workspace.options.blur-options.title.group") - (tr "workspace.options.blur-options.title")) - :class (stl/css-case :title-spacing-blur (not has-value?))} - (when-not has-value? - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.blur-options.add-blur") - :on-click handle-add - :icon i/add - :data-testid "add-blur"}])]] - (when (and open? has-value?) - [:div {:class (stl/css :element-set-content)} - [:div {:class (stl/css-case :first-row true - :hidden hidden?)} - [:div {:class (stl/css :blur-info) - :data-testid "blur-info"} - [:button {:class (stl/css-case :show-more true - :selected more-options?) - :on-click toggle-more-options} - deprecated-icon/menu] - (if bg-blur? - [:& select {:class (stl/css :blur-type-select) - :default-value (d/name (:type blur)) - :options type-options - :disabled hidden? - :on-change handle-type-change}] - [:span {:class (stl/css :label)} - (tr "workspace.options.blur-options.title")])] - [:div {:class (stl/css :actions)} - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.blur-options.toggle-blur") - :on-click handle-toggle-visibility - :icon (if hidden? i/hide i/shown)}] - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.blur-options.remove-blur") - :on-click handle-delete - :icon i/remove}]]] - (when more-options? - [:div {:class (stl/css :second-row)} - [:label {:class (stl/css :label) - :for "blur-input-sidebar"} - (tr "inspect.attributes.blur.value")] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :id "blur-input-sidebar" - :min "0" - :on-change handle-change - :value (:value blur)}]])])])) + :aria-expanded open? + :aria-controls "blur-content" + :title (if bg-blur? + (cond + (= type :multiple) (tr "workspace.options.blur-effects-options.title.multiple") + (= type :group) (tr "workspace.options.blur-effects-options.title.group") + :else (tr "labels.blur-effects")) + (cond + (= type :multiple) (tr "workspace.options.blur-options.title.multiple") + (= type :group) (tr "workspace.options.blur-options.title.group") + :else (tr "labels.blur"))) + :class (stl/css-case :title-spacing-blur (not (seq blur-values)) + :long-title true)} + (when (and + (not mixed-state) + (< (count blur-values) + (if bg-blur? 2 1))) + [:> icon-button* + {:variant "ghost" + :aria-label (tr "workspace.options.blur-options.add-blur") + :on-click handle-add + :icon i/add + :tooltip-placement "top-left" + :data-testid "add-blur"}])]] + (when (and open? (seq blur-values)) + [:div {:class (stl/css :element-set-content) + :hidden (not open?) + :id "blur-content"} + (if mixed-state + [:div {:class (stl/css :first-row)} + [:span {:class (stl/css :mixed-label)} + (tr "labels.mixed-values")] + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.blur-options.remove-blur") + :on-click handle-delete-all + :tooltip-placement "top-left" + :icon i/remove}]] + + (for [{:keys [key value]} blur-values] + [:> blur-menu-content* + {:key key + :blur-key key + :value value + :blur-values blur-values + :change-fn change!}]))])])) \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss index f3e4f60ba1..606a614f87 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss @@ -4,114 +4,130 @@ // // Copyright (c) KALEIDOS INC Sucursal en España SL -@use "refactor/common-refactor.scss" as deprecated; +@use "ds/_borders.scss" as *; +@use "ds/typography.scss" as t; +@use "ds/_sizes.scss" as *; +@use "ds/_utils.scss" as *; @use "../../../sidebar/common/sidebar.scss" as sidebar; -.element-set { - @include sidebar.option-grid-structure; -} - -.element-title { - grid-column: span 8; -} - .title-spacing-blur { - padding-left: deprecated.$s-2; + padding-left: var(--sp-xxs); margin: 0; } -.element-set-content { - @include deprecated.flex-column; +.long-title { + height: auto; +} - margin-bottom: deprecated.$s-8; +.element-set-content { + display: flex; + flex-direction: column; + gap: var(--sp-xs); + margin-bottom: var(--sp-s); } .first-row { @include sidebar.option-grid-structure; +} - .blur-info { - grid-column: span 6; - display: flex; - align-items: center; - gap: deprecated.$s-1; - flex-grow: 1; - border-radius: deprecated.$br-8; - background-color: var(--input-details-color); +.show-more { + background-color: var(--color-background-tertiary); + border: $b-1 solid var(--color-background-tertiary); + border-radius: $br-8 0 0 $br-8; - .show-more { - @extend %button-secondary; - - height: deprecated.$s-32; - width: deprecated.$s-28; - border-radius: deprecated.$br-8 0 0 deprecated.$br-8; - box-sizing: border-box; - border: deprecated.$s-1 solid var(--button-secondary-background-color-rest); - - svg { - @extend %button-icon; - } - - &.selected { - background-color: var(--button-radio-background-color-active); - - svg { - stroke: var(--button-radio-foreground-color-active); - } - } - } - - .label { - @include deprecated.body-small-typography; - - flex-grow: 1; - display: flex; - align-items: center; - height: deprecated.$s-32; - padding: 0 deprecated.$s-8; - border-radius: 0 deprecated.$br-8 deprecated.$br-8 0; - background-color: var(--input-background-color); - color: var(--menu-foreground-color); - box-sizing: border-box; - border: deprecated.$s-1 solid var(--input-border-color); - } - - .blur-type-select { - flex-grow: 1; - border-radius: 0 deprecated.$br-8 deprecated.$br-8 0; - } + &:hover { + background-color: var(--color-background-quaternary); + border: $b-1 solid var(--color-background-quaternary); } - .actions { - @include deprecated.flex-row; + &:disabled { + background-color: var(--color-background-primary); + border-block-start: $b-1 solid var(--color-background-quaternary); + border-block-end: $b-1 solid var(--color-background-quaternary); + border-inline-start: $b-1 solid var(--color-background-quaternary); } +} - &.hidden { - .blur-info { - @include deprecated.hidden-element; +.blur-info { + grid-column: span 6; + display: flex; + align-items: center; + flex-grow: 1; + gap: 1px; + border-radius: $br-8; + background-color: var(--color-background-primary); +} - .show-more { - @include deprecated.hidden-element; +.mixed-label { + @include t.use-typography("body-small"); - border: deprecated.$s-1 solid var(--input-border-color-disabled); - } + grid-column: span 7; + gap: 1px; + border-radius: $br-8; + display: flex; + align-items: center; + flex-grow: 1; + height: $sz-32; + padding: 0 var(--sp-s); + background-color: var(--color-background-tertiary); + border: $b-1 solid var(--color-background-tertiary); + color: var(--color-foreground-primary); + box-sizing: border-box; +} - .label { - @include deprecated.hidden-element; +.disabled-label-tooltip { + flex-grow:1; +} - border: deprecated.$s-1 solid var(--input-border-color-disabled); - } - } - } +.label { + @include t.use-typography("body-small"); + + display: flex; + align-items: center; + flex-grow: 1; + height: $sz-32; + padding: 0 var(--sp-s); + border-radius: 0 $br-8 $br-8 0; + background-color: var(--color-background-tertiary); + border: $b-1 solid var(--color-background-tertiary); + color: var(--color-foreground-primary); + box-sizing: border-box; +} + +.blur-type-select { + flex-grow: 1; + border-radius: 0 $br-8 $br-8 0; +} + +.actions { + display: flex; + align-items: center; + gap: var(--sp-xs); +} + +.hidden .blur-info, +.hidden .blur-info .label { + cursor: default; + pointer-events: none; + box-sizing: border-box; + color: var(--color-foreground-secondary); + stroke: var(--color-foreground-secondary); + background-color: transparent; +} + +.hidden .blur-info .label { + border: $b-1 solid var(--color-background-quaternary); } .second-row { - @extend %input-element; - @include deprecated.body-small-typography; - - width: deprecated.$s-92; - - .label { - padding-left: deprecated.$s-8; - width: deprecated.$s-60; - } + width: var(--three-columns-width); +} + +.disabled-label { + color: var(--color-foreground-secondary); + background-color: var(--color-background-primary); + border-top: $b-1 solid var(--color-background-quaternary); + border-bottom: $b-1 solid var(--color-background-quaternary); + border-right: $b-1 solid var(--color-background-quaternary); + border-left: $b-1 solid transparent; } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index dcc29cd0a8..701ba4d134 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -451,5 +451,5 @@ [:> icon-button* {:variant "ghost" :aria-label (tr "settings.select-this-color") :on-click handle-select - :tooltip-position "top-left" + :tooltip-placement "top-left" :icon i/move}])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs index f598da0abc..b5259e0e5d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs @@ -135,7 +135,7 @@ [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> exports-menu* {:type type :ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index d006be2d70..ed77629c22 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -132,7 +132,7 @@ :applied-tokens applied-tokens}] [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> svg-attrs-menu* {:ids ids :values (select-keys shape [:svg-attrs])}] [:> exports-menu* {:type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 059e92b1d3..a57cb7c853 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -159,7 +159,7 @@ :libraries libraries}] [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> frame-grid* {:shape shape}] [:> exports-menu* {:type shape-type :ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 24b5b7afa3..5e99bcb51a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -48,6 +48,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :children :exports :shape @@ -61,6 +62,7 @@ :fill :children :shadow :shape :blur :shape + :background-blur :shape :stroke :children :text :children :exports :shape @@ -74,6 +76,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :ignore :exports :shape @@ -87,6 +90,7 @@ :fill :text :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :text :exports :shape @@ -100,6 +104,7 @@ :fill :ignore :shadow :shape :blur :shape + :background-blur :shape :stroke :ignore :text :ignore :exports :shape @@ -113,6 +118,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :ignore :exports :shape @@ -126,6 +132,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :ignore :exports :shape @@ -139,6 +146,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :ignore :exports :shape @@ -152,6 +160,7 @@ :fill :shape :shadow :shape :blur :shape + :background-blur :shape :stroke :shape :text :ignore :exports :shape diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index 6105a1e69b..0ba8e24a76 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -133,7 +133,7 @@ :applied-tokens applied-tokens}] [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> svg-attrs-menu* {:ids ids :values (select-keys shape [:svg-attrs])}] [:> exports-menu* {:type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 3e1162cd8a..fb34713817 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -134,7 +134,7 @@ [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> svg-attrs-menu* {:ids ids :values (select-keys shape [:svg-attrs])}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index 7e1f9f8497..929ddda4e4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -201,7 +201,7 @@ [:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> svg-attrs-menu* {:ids ids :values (select-keys shape [:svg-attrs])}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 98c8f66bb8..34d8614b1c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -211,7 +211,7 @@ [:> blur-menu* {:ids ids - :values (select-keys shape [:blur])}] + :values (select-keys shape [:blur :background-blur])}] [:> exports-menu* {:type type :ids ids diff --git a/frontend/src/app/plugins/format.cljs b/frontend/src/app/plugins/format.cljs index 58bb8c0182..2eeec73024 100644 --- a/frontend/src/app/plugins/format.cljs +++ b/frontend/src/app/plugins/format.cljs @@ -232,7 +232,7 @@ ;; export interface Blur { ;; id?: string; -;; type?: 'layer-blur'; +;; type?: 'layer-blur' | 'background-blur'; ;; value?: number; ;; hidden?: boolean; ;; } diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 70c75fe43f..3422320fa2 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -24,6 +24,7 @@ [app.common.types.grid :as ctg] [app.common.types.path :as path] [app.common.types.shape :as cts] + [app.common.types.shape.background-blur :as ctsbb] [app.common.types.shape.blur :as ctsb] [app.common.types.shape.export :as ctse] [app.common.types.shape.interactions :as ctsi] @@ -176,6 +177,15 @@ :hidden false} blur)) +(defn- background-blur-defaults + [blur] + (d/patch-object + {:id (uuid/next) + :type :background-blur + :value 4 + :hidden false} + blur)) + (defn commit-fills! [plugin-id ^js self value] (let [shape (u/proxy->shape self) @@ -510,6 +520,25 @@ :else (st/emit! (dwsh/update-shapes [id] #(assoc % :blur value)))))))} + :background-blur + {:this true + :get #(-> % u/proxy->shape :background-blur format/format-blur) + :set + (fn [self value] + (if (nil? value) + (st/emit! (dwsh/update-shapes [id] #(dissoc % :background-blur))) + (let [id (obj/get self "$id") + value (background-blur-defaults (parser/parse-blur value))] + (cond + (not (sm/validate ctsbb/schema:background-blur value)) + (u/not-valid plugin-id :background-blur value) + + (not (r/check-permission plugin-id "content:write")) + (u/not-valid plugin-id :background-blur "Plugin doesn't have 'content:write' permission") + + :else + (st/emit! (dwsh/update-shapes [id] #(assoc % :background-blur value)))))))} + :exports {:this true :get #(-> % u/proxy->shape :exports format/format-exports) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index a1a0a2f6bf..73a646c5f7 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -945,12 +945,21 @@ (defn set-shape-blur [blur] (if (some? blur) - (let [type (-> blur :type sr/translate-blur-type) + (let [type (sr/translate-blur-type :layer-blur) hidden (:hidden blur) value (:value blur)] (h/call wasm/internal-module "_set_shape_blur" type hidden value)) (h/call wasm/internal-module "_clear_shape_blur"))) +(defn set-shape-background-blur + [background-blur] + (if (some? background-blur) + (let [type (sr/translate-blur-type :background-blur) + hidden (:hidden background-blur) + value (:value background-blur)] + (h/call wasm/internal-module "_set_shape_blur" type hidden value)) + (h/call wasm/internal-module "_clear_shape_blur"))) + (defn set-shape-corners [corners] (let [[r1 r2 r3 r4] (map #(d/nilv % 0) corners)] @@ -1331,6 +1340,7 @@ bool-type (get shape :bool-type) grow-type (get shape :grow-type) blur (get shape :blur) + background-blur (get shape :background-blur) svg-attrs (get shape :svg-attrs) shadows (get shape :shadow)] @@ -1339,6 +1349,7 @@ ;; Remaining properties that need separate calls (variable-length or conditional) (set-shape-children children) (set-shape-blur blur) + (set-shape-background-blur background-blur) (when (= type :group) (set-masked (boolean masked))) (when (= type :bool) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index 83a58a2499..54c292f59f 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -130,6 +130,7 @@ (defn- set-wasm-attr! [shape k] (when wasm/context-initialized? + ;;TODO_BLUR: ask about this, (let [shape (case k :svg-attrs (svg-filters/apply-svg-derived (assoc shape :svg-attrs (get shape :svg-attrs))) (:fills :blur :shadow) (svg-filters/apply-svg-derived shape) @@ -187,6 +188,9 @@ :blur (api/set-shape-blur v) + :background-blur + (api/set-shape-background-blur v) + :shadow (api/set-shape-shadows v) @@ -230,6 +234,7 @@ ;; Always update fills/blur/shadow to clear previous state if filters disappear (api/set-shape-fills id (:fills shape) false) (api/set-shape-blur (:blur shape)) + (api/set-shape-background-blur (:background-blur shape)) (api/set-shape-shadows (:shadow shape))) :masked-group diff --git a/frontend/src/app/render_wasm/wasm.cljs b/frontend/src/app/render_wasm/wasm.cljs index caf3d3a15a..afca7f0ba1 100644 --- a/frontend/src/app/render_wasm/wasm.cljs +++ b/frontend/src/app/render_wasm/wasm.cljs @@ -44,7 +44,7 @@ (set! context-initialized? false) (reset! context-lost? false)) - +;; TODO_BLUR: ask for blur-type?? (defonce serializers #js {:blur-type shared/RawBlurType :blend-mode shared/RawBlendMode diff --git a/frontend/src/app/util/code_gen/style_css_formats.cljs b/frontend/src/app/util/code_gen/style_css_formats.cljs index cfeb55f9e1..9a650f7528 100644 --- a/frontend/src/app/util/code_gen/style_css_formats.cljs +++ b/frontend/src/app/util/code_gen/style_css_formats.cljs @@ -38,7 +38,7 @@ :border-color :border-color :box-shadow :shadows :filter :blur - :backdrop-filter :blur + :backdrop-filter :background-blur :gap :size-array :row-gap :size-array :column-gap :size-array @@ -202,5 +202,6 @@ :tracks (format-tracks value) :shadows (format-shadow value options) :blur (format-blur value) + :background-blur (format-blur value) :matrix (format-matrix value) (if (keyword? value) (d/name value) value)))) diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index 044ca763c5..9bd9b787f3 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -256,14 +256,12 @@ (defn- get-filter [shape] (when-not (cgc/svg-markup? shape) - (when (= :layer-blur (get-in shape [:blur :type])) - (get-in shape [:blur :value])))) + (get-in shape [:blur :value]))) (defn- get-backdrop-filter [shape] (when-not (cgc/svg-markup? shape) - (when (= :background-blur (get-in shape [:blur :type])) - (get-in shape [:blur :value])))) + (get-in shape [:background-blur :value]))) (defn- get-display [shape] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 64dc9c4a41..5d4b2c9090 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2755,6 +2755,10 @@ msgstr "Bad Gateway" msgid "labels.blur" msgstr "Blur" +#: src/app/main/ui/inspect/styles/style_box.cljs +msgid "labels.blur-effects" +msgstr "Blur effects" + #: src/app/main/data/common.cljs:119, src/app/main/ui/dashboard/change_owner.cljs:67, src/app/main/ui/dashboard/change_owner.cljs:174, src/app/main/ui/dashboard/import.cljs:543, src/app/main/ui/dashboard/team.cljs:866, src/app/main/ui/dashboard/team.cljs:1345, src/app/main/ui/delete_shared.cljs:36, src/app/main/ui/exports/assets.cljs:163, src/app/main/ui/exports/files.cljs:167, src/app/main/ui/settings/integrations.cljs:228, src/app/main/ui/viewer/share_link.cljs:204, src/app/main/ui/workspace/sidebar/assets/groups.cljs:178, src/app/main/ui/workspace/tokens/export/modal.cljs:43, src/app/main/ui/workspace/tokens/import/modal.cljs:268, src/app/main/ui/workspace/tokens/import_from_library.cljs:88, src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs:364, src/app/main/ui/workspace/tokens/management/forms/rename_node_modal.cljs:73, src/app/main/ui/workspace/tokens/settings/menu.cljs:104, src/app/main/ui/workspace/tokens/themes/create_modal.cljs:242 msgid "labels.cancel" msgstr "Cancel" @@ -7159,10 +7163,30 @@ msgstr "Layer blur" msgid "workspace.options.blur-options.remove-blur" msgstr "Remove blur" +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-options.toggle-more-options" +msgstr "Show/hide more options" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-options.disabled-blur-label" +msgstr "Background blur is only supported in the new render. Switch to the new render in the Preferences menu to use this effect" + #: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:113, src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:138 msgid "workspace.options.blur-options.title" msgstr "Blur" +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title" +msgstr "Blur effects" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title.group" +msgstr "Group blur effects" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title.multiple" +msgstr "Selection blur effects" + #: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112 msgid "workspace.options.blur-options.title.group" msgstr "Group blur" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 9050f78a21..eb3e907a7f 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2685,6 +2685,10 @@ msgstr "Error del servidor (Bad Gateway)" msgid "labels.blur" msgstr "Desenfoque" +#: src/app/main/ui/inspect/styles/style_box.cljs +msgid "labels.blur-effects" +msgstr "Efectos de desenfoque" + #: src/app/main/data/common.cljs:119, src/app/main/ui/dashboard/change_owner.cljs:67, src/app/main/ui/dashboard/change_owner.cljs:174, src/app/main/ui/dashboard/import.cljs:543, src/app/main/ui/dashboard/team.cljs:866, src/app/main/ui/dashboard/team.cljs:1345, src/app/main/ui/delete_shared.cljs:36, src/app/main/ui/exports/assets.cljs:163, src/app/main/ui/exports/files.cljs:167, src/app/main/ui/settings/integrations.cljs:228, src/app/main/ui/viewer/share_link.cljs:204, src/app/main/ui/workspace/sidebar/assets/groups.cljs:178, src/app/main/ui/workspace/tokens/export/modal.cljs:43, src/app/main/ui/workspace/tokens/import/modal.cljs:268, src/app/main/ui/workspace/tokens/import_from_library.cljs:88, src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs:364, src/app/main/ui/workspace/tokens/management/forms/rename_node_modal.cljs:73, src/app/main/ui/workspace/tokens/settings/menu.cljs:104, src/app/main/ui/workspace/tokens/themes/create_modal.cljs:242 msgid "labels.cancel" msgstr "Cancelar" @@ -6986,10 +6990,30 @@ msgstr "Desenfoque de capa" msgid "workspace.options.blur-options.remove-blur" msgstr "Eliminar desenfoque" +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-options.toggle-more-options" +msgstr "Mostrar/ocultar más opciones" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-options.disabled-blur-label" +msgstr "El desenfoque de fondo (Background Blur) solo está disponible en el nuevo motor de renderizado. Actívalo desde el menú de Preferencias para utilizar este efecto." + #: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:113, src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:138 msgid "workspace.options.blur-options.title" msgstr "Desenfoque" +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title" +msgstr "Efectos de desenfoque" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title.group" +msgstr "Efectos de desenfoque del grupo" + +#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +msgid "workspace.options.blur-effects-options.title.multiple" +msgstr "Efectos de desenfoque de la selección" + #: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112 msgid "workspace.options.blur-options.title.group" msgstr "Desenfoque del grupo" diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index b613ec5586..d0b015fa46 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -24,6 +24,7 @@ use std::collections::{HashMap, HashSet}; use options::RenderOptions; pub use surfaces::{SurfaceId, Surfaces}; +// TODO_BLUR: should we add here BackgroundBlur use crate::error::{Error, Result}; use crate::math; use crate::shapes::{ @@ -370,7 +371,7 @@ pub(crate) struct RenderState { // migration to remove group-level fills is completed, this code should be removed. // Frames contained in groups must reset this nested_fills stack pushing a new empty vector. pub nested_fills: Vec>, - pub nested_blurs: Vec>, // FIXME: why is this an option? + pub nested_blurs: Vec>, // FIXME: why is this an option?, sholud be an option now? TODO_BLUR pub nested_shadows: Vec>, pub show_grid: Option, pub rulers: RulerState, @@ -587,7 +588,7 @@ impl RenderState { backbuffer_crop_cache: HashMap::default(), }) } - + /// TODO_BLUR: ? /// Combines every visible layer blur currently active (ancestors + shape) /// into a single equivalent blur. Layer blur radii compound by adding their /// variances (σ² = radius²), so we: