From eec2fd00a285305a72d0a66c7e6098c45072a112 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 15 May 2023 01:21:23 +0530 Subject: [PATCH 1/3] :tada: Implement ability to preview layer blend modes Signed-off-by: Akshay Gupta --- .../src/app/main/ui/components/select.cljs | 16 +++- .../sidebar/options/menus/layer.cljs | 88 ++++++++++++------- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index 344ea38e0..8e1396530 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -12,9 +12,9 @@ [app.main.ui.icons :as i] [rumext.v2 :as mf])) -(mf/defc select [{:keys [default-value options class on-change]}] +(mf/defc select [{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option]}] (let [state (mf/use-state {:id (uuid/next) - :is-open? false + :is-open? (or is-open? false) :current-value default-value}) open-dropdown #(swap! state assoc :is-open? true) close-dropdown #(swap! state assoc :is-open? false) @@ -22,14 +22,20 @@ (fn [_] (swap! state assoc :current-value value) (when on-change (on-change value)))) + highlight-item (fn [value] + (when on-pointer-enter-option (on-pointer-enter-option value))) + unhighlight-item (fn [value] + (when on-pointer-leave-option (on-pointer-leave-option value))) as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item])) value->label (into {} (->> options (map as-key-value))) ] (mf/use-effect (mf/deps options) - #(reset! state {:is-open? false - :current-value default-value})) + #(if is-open? + (reset! state (assoc @state :current-value default-value)) + (reset! state {:is-open? false + :current-value default-value}))) [:div.custom-select {:on-click open-dropdown :class class} @@ -45,6 +51,8 @@ [:li.checked-element {:key (dm/str (:id @state) "-" index) :class (when (= value (-> @state :current-value)) "is-selected") + :on-pointer-enter #(highlight-item value) + :on-pointer-leave #(unhighlight-item value) :on-click (select-item value)} [:span.check-icon i/tick] [:span label]])))]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index 5623ed669..c02501c5a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -10,6 +10,7 @@ [app.main.data.workspace.changes :as dch] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] + [app.main.ui.components.select :refer [select]] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -28,7 +29,11 @@ (dom/select-text! (dom/get-target event))) (mf/defc layer-menu [{:keys [ids type values]}] - (let [change! + (let [selected-blend-mode (mf/use-state (or (d/name (:blend-mode values)) "normal")) + is-option-highlighted? (mf/use-state false) + is-preview-complete? (mf/use-state true) + + change! (mf/use-callback (mf/deps ids) (fn [prop value] @@ -37,10 +42,30 @@ handle-change-blend-mode (mf/use-callback (mf/deps change!) - (fn [event] - (let [value (-> (dom/get-target-val event) (keyword))] + (fn [value] + (when (not= "multiple" value) + (reset! selected-blend-mode value) + (reset! is-option-highlighted? false) + (reset! is-preview-complete? true) (change! :blend-mode value)))) + handle-option-enter + (mf/use-callback + (mf/deps change!) + (fn [value] + (when (not= :multiple (:blend-mode values)) + (reset! is-preview-complete? false) + (reset! is-option-highlighted? true) + (change! :blend-mode value)))) + + handle-option-leave + (mf/use-callback + (mf/deps change!) + (fn [value] + (when (not= :multiple (:blend-mode values)) + (reset! is-preview-complete? true) + (change! :blend-mode @selected-blend-mode)))) + handle-opacity-change (mf/use-callback (mf/deps change!) @@ -71,6 +96,11 @@ (mf/deps change!) (fn [_] (change! :blocked false)))] + + (mf/use-effect + (mf/deps (:blend-mode values)) + #(when (or (not @is-option-highlighted?) (and @is-option-highlighted? @is-preview-complete?)) + (reset! selected-blend-mode (or (d/name (:blend-mode values)) "normal")))) [:div.element-set [:div.element-set-title @@ -82,33 +112,31 @@ [:div.element-set-content [:div.row-flex - [:select.input-select {:on-change handle-change-blend-mode - :value (d/name (:blend-mode values) "normal")} - - (when (= :multiple (:blend-mode values)) - [:option {:value "multiple"} "--"]) - - [:option {:value "normal"} (tr "workspace.options.layer-options.blend-mode.normal")] - - [:option {:value "darken"} (tr "workspace.options.layer-options.blend-mode.darken")] - [:option {:value "multiply"} (tr "workspace.options.layer-options.blend-mode.multiply")] - [:option {:value "color-burn"} (tr "workspace.options.layer-options.blend-mode.color-burn")] - - [:option {:value "lighten"} (tr "workspace.options.layer-options.blend-mode.lighten")] - [:option {:value "screen"} (tr "workspace.options.layer-options.blend-mode.screen")] - [:option {:value "color-dodge"} (tr "workspace.options.layer-options.blend-mode.color-dodge")] - - [:option {:value "overlay"} (tr "workspace.options.layer-options.blend-mode.overlay")] - [:option {:value "soft-light"} (tr "workspace.options.layer-options.blend-mode.soft-light")] - [:option {:value "hard-light"} (tr "workspace.options.layer-options.blend-mode.hard-light")] - - [:option {:value "difference"} (tr "workspace.options.layer-options.blend-mode.difference")] - [:option {:value "exclusion"} (tr "workspace.options.layer-options.blend-mode.exclusion")] - - [:option {:value "hue"} (tr "workspace.options.layer-options.blend-mode.hue")] - [:option {:value "saturation"} (tr "workspace.options.layer-options.blend-mode.saturation")] - [:option {:value "color"} (tr "workspace.options.layer-options.blend-mode.color")] - [:option {:value "luminosity"} (tr "workspace.options.layer-options.blend-mode.luminosity")]] + [:& select + {:class "flex-grow" + :default-value @selected-blend-mode + :options (concat (when (= :multiple (:blend-mode values)) + [{:value "multiple" :label "--"}]) + [{:value "normal" :label (tr "workspace.options.layer-options.blend-mode.normal")} + {:value "darken" :label (tr "workspace.options.layer-options.blend-mode.darken")} + {:value "multiply" :label (tr "workspace.options.layer-options.blend-mode.multiply")} + {:value "color-burn" :label (tr "workspace.options.layer-options.blend-mode.color-burn")} + {:value "lighten" :label (tr "workspace.options.layer-options.blend-mode.lighten")} + {:value "screen" :label (tr "workspace.options.layer-options.blend-mode.screen")} + {:value "color-dodge" :label (tr "workspace.options.layer-options.blend-mode.color-dodge")} + {:value "overlay" :label (tr "workspace.options.layer-options.blend-mode.overlay")} + {:value "soft-light" :label (tr "workspace.options.layer-options.blend-mode.soft-light")} + {:value "hard-light" :label (tr "workspace.options.layer-options.blend-mode.hard-light")} + {:value "difference" :label (tr "workspace.options.layer-options.blend-mode.difference")} + {:value "exclusion" :label (tr "workspace.options.layer-options.blend-mode.exclusion")} + {:value "hue" :label (tr "workspace.options.layer-options.blend-mode.hue")} + {:value "saturation" :label (tr "workspace.options.layer-options.blend-mode.saturation")} + {:value "color" :label (tr "workspace.options.layer-options.blend-mode.color")} + {:value "luminosity" :label (tr "workspace.options.layer-options.blend-mode.luminosity")}]) + :on-change handle-change-blend-mode + :is-open? @is-option-highlighted? + :on-pointer-enter-option handle-option-enter + :on-pointer-leave-option handle-option-leave}] [:div.input-element {:title (tr "workspace.options.opacity") :class "percentail"} [:> numeric-input {:value (-> values :opacity opacity->string) From 23f0ee9e553f0803779a3be1289ddb2ca8697dd4 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 22 May 2023 12:47:31 +0200 Subject: [PATCH 2/3] :zap: Refactor select and layer-menu components --- .../src/app/main/ui/components/select.cljs | 114 ++++++---- .../sidebar/options/menus/layer.cljs | 202 ++++++++++-------- 2 files changed, 190 insertions(+), 126 deletions(-) diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index 8e1396530..3550d6163 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -6,53 +6,87 @@ (ns app.main.ui.components.select (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.uuid :as uuid] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.icons :as i] + [app.util.dom :as dom] [rumext.v2 :as mf])) -(mf/defc select [{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option]}] - (let [state (mf/use-state {:id (uuid/next) - :is-open? (or is-open? false) - :current-value default-value}) - open-dropdown #(swap! state assoc :is-open? true) - close-dropdown #(swap! state assoc :is-open? false) - select-item (fn [value] - (fn [_] - (swap! state assoc :current-value value) - (when on-change (on-change value)))) - highlight-item (fn [value] - (when on-pointer-enter-option (on-pointer-enter-option value))) - unhighlight-item (fn [value] - (when on-pointer-leave-option (on-pointer-leave-option value))) - as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item])) - value->label (into {} (->> options - (map as-key-value))) ] +(defn- as-key-value + [item] + (if (map? item) + [(:value item) (:label item)] + [item item])) - (mf/use-effect - (mf/deps options) - #(if is-open? - (reset! state (assoc @state :current-value default-value)) - (reset! state {:is-open? false - :current-value default-value}))) +(mf/defc select + [{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option]}] + (let [label-index (mf/with-memo [options] + (into {} (map as-key-value) options)) - [:div.custom-select {:on-click open-dropdown - :class class} - [:span (-> @state :current-value value->label)] + state* (mf/use-state + {:id (uuid/next) + :is-open? (or is-open? false) + :current-value default-value}) + + state (deref state*) + current-id (get state :id) + current-value (get state :current-value) + current-label (get label-index current-value) + is-open? (:is-open? state) + + open-dropdown (mf/use-fn #(swap! state* assoc :is-open? true)) + close-dropdown (mf/use-fn #(swap! state* assoc :is-open? false)) + + select-item + (mf/use-fn + (mf/deps on-change) + (fn [event] + (js/console.log event) + (let [value (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + + (swap! state* assoc :current-value value) + (when (fn? on-change) + (on-change value))))) + + highlight-item + (mf/use-fn + (mf/deps on-pointer-enter-option) + (fn [event] + (when (fn? on-pointer-enter-option) + (let [value (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + (on-pointer-enter-option value))))) + + unhighlight-item + (mf/use-fn + (mf/deps on-pointer-leave-option) + (fn [event] + (when (fn? on-pointer-leave-option) + (let [value (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + (on-pointer-leave-option value)))))] + + [:div.custom-select {:on-click open-dropdown :class class} + [:span current-label] [:span.dropdown-button i/arrow-down] - [:& dropdown {:show (:is-open? @state) - :on-close close-dropdown} + [:& dropdown {:show is-open? :on-close close-dropdown} [:ul.custom-select-dropdown - (for [[index item] (map-indexed vector options)] - (cond - (= :separator item) [:hr {:key (dm/str (:id @state) "-" index)}] - :else (let [[value label] (as-key-value item)] - [:li.checked-element - {:key (dm/str (:id @state) "-" index) - :class (when (= value (-> @state :current-value)) "is-selected") - :on-pointer-enter #(highlight-item value) - :on-pointer-leave #(unhighlight-item value) - :on-click (select-item value)} - [:span.check-icon i/tick] - [:span label]])))]]])) + (for [[index item] (d/enumerate options)] + (if (= :separator item) + [:hr {:key (dm/str current-id "-" index)}] + (let [[value label] (as-key-value item)] + [:li.checked-element + {:key (dm/str current-id "-" index) + :class (when (= value current-value) "is-selected") + :data-value (pr-str value) + :on-pointer-enter highlight-item + :on-pointer-leave unhighlight-item + :on-click select-item} + [:span.check-icon i/tick] + [:span label]])))]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index c02501c5a..0732d6465 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.sidebar.options.menus.layer (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.data.workspace.changes :as dch] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] @@ -16,91 +17,136 @@ [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) -(def layer-attrs [:opacity :blend-mode :blocked :hidden]) +(def layer-attrs + [:opacity :blend-mode :blocked :hidden]) -(defn opacity->string [opacity] +(defn opacity->string + [opacity] (if (= opacity :multiple) "" - (str (-> opacity - (d/coalesce 1) - (* 100))))) + (dm/str (-> opacity + (d/coalesce 1) + (* 100))))) -(defn select-all [event] - (dom/select-text! (dom/get-target event))) +(defn select-all! + [event] + (some-> event dom/get-target dom/select-text!)) -(mf/defc layer-menu [{:keys [ids type values]}] - (let [selected-blend-mode (mf/use-state (or (d/name (:blend-mode values)) "normal")) - is-option-highlighted? (mf/use-state false) - is-preview-complete? (mf/use-state true) - - change! - (mf/use-callback +(mf/defc layer-menu + {::mf/wrap-props false} + [props] + (let [ids (unchecked-get props "ids") + type (unchecked-get props "type") + values (unchecked-get props "values") + + current-blend-mode (d/name (or (:blend-mode values) :normal)) + current-opacity (:opacity values) + + state* (mf/use-state + {:selected-blend-mode current-blend-mode + :option-highlighted? false + :preview-complete? true}) + + state (deref state*) + selected-blend-mode (get state :selected-blend-mode) + option-highlighted? (get state :option-highlighted?) + preview-complete? (get state :preview-complete?) + + on-change + (mf/use-fn (mf/deps ids) (fn [prop value] (st/emit! (dch/update-shapes ids #(assoc % prop value))))) handle-change-blend-mode - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [value] (when (not= "multiple" value) - (reset! selected-blend-mode value) - (reset! is-option-highlighted? false) - (reset! is-preview-complete? true) - (change! :blend-mode value)))) + (swap! state* assoc + :selected-blend-mode value + :option-highlighted? false + :preview-complete? true) + (on-change :blend-mode value)))) handle-option-enter - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change current-blend-mode) (fn [value] - (when (not= :multiple (:blend-mode values)) - (reset! is-preview-complete? false) - (reset! is-option-highlighted? true) - (change! :blend-mode value)))) + (when (not= :multiple current-blend-mode) + (swap! state* assoc + :preview-complete? false + :option-highlighted? true) + (on-change :blend-mode value)))) handle-option-leave - (mf/use-callback - (mf/deps change!) - (fn [value] - (when (not= :multiple (:blend-mode values)) - (reset! is-preview-complete? true) - (change! :blend-mode @selected-blend-mode)))) + (mf/use-fn + (mf/deps on-change selected-blend-mode) + (fn [_value] + (when (not= :multiple current-blend-mode) + (swap! state* assoc :preview-complete? true) + (on-change :blend-mode selected-blend-mode)))) handle-opacity-change - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [value] - (let [value (-> value (/ 100))] - (change! :opacity value)))) + (let [value (/ value 100)] + (on-change :opacity value)))) handle-set-hidden - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [_] - (change! :hidden true))) + (on-change :hidden true))) handle-set-visible - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [_] - (change! :hidden false))) + (on-change :hidden false))) handle-set-blocked - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [_] - (change! :blocked true))) + (on-change :blocked true))) handle-set-unblocked - (mf/use-callback - (mf/deps change!) + (mf/use-fn + (mf/deps on-change) (fn [_] - (change! :blocked false)))] - - (mf/use-effect - (mf/deps (:blend-mode values)) - #(when (or (not @is-option-highlighted?) (and @is-option-highlighted? @is-preview-complete?)) - (reset! selected-blend-mode (or (d/name (:blend-mode values)) "normal")))) + (on-change :blocked false))) + + options + (mf/with-memo [current-blend-mode] + (d/concat-vec + (when (= :multiple current-blend-mode) + [{:value "multiple" :label "--"}]) + [{:value "normal" :label (tr "workspace.options.layer-options.blend-mode.normal")} + {:value "darken" :label (tr "workspace.options.layer-options.blend-mode.darken")} + {:value "multiply" :label (tr "workspace.options.layer-options.blend-mode.multiply")} + {:value "color-burn" :label (tr "workspace.options.layer-options.blend-mode.color-burn")} + {:value "lighten" :label (tr "workspace.options.layer-options.blend-mode.lighten")} + {:value "screen" :label (tr "workspace.options.layer-options.blend-mode.screen")} + {:value "color-dodge" :label (tr "workspace.options.layer-options.blend-mode.color-dodge")} + {:value "overlay" :label (tr "workspace.options.layer-options.blend-mode.overlay")} + {:value "soft-light" :label (tr "workspace.options.layer-options.blend-mode.soft-light")} + {:value "hard-light" :label (tr "workspace.options.layer-options.blend-mode.hard-light")} + {:value "difference" :label (tr "workspace.options.layer-options.blend-mode.difference")} + {:value "exclusion" :label (tr "workspace.options.layer-options.blend-mode.exclusion")} + {:value "hue" :label (tr "workspace.options.layer-options.blend-mode.hue")} + {:value "saturation" :label (tr "workspace.options.layer-options.blend-mode.saturation")} + {:value "color" :label (tr "workspace.options.layer-options.blend-mode.color")} + {:value "luminosity" :label (tr "workspace.options.layer-options.blend-mode.luminosity")}]))] + + (mf/with-effect [current-blend-mode + option-highlighted? + preview-complete?] + (when (or (not option-highlighted?) + (and option-highlighted? + preview-complete?)) + (swap! state* assoc :selected-blend-mode current-blend-mode))) [:div.element-set [:div.element-set-title @@ -112,40 +158,24 @@ [:div.element-set-content [:div.row-flex - [:& select - {:class "flex-grow" - :default-value @selected-blend-mode - :options (concat (when (= :multiple (:blend-mode values)) - [{:value "multiple" :label "--"}]) - [{:value "normal" :label (tr "workspace.options.layer-options.blend-mode.normal")} - {:value "darken" :label (tr "workspace.options.layer-options.blend-mode.darken")} - {:value "multiply" :label (tr "workspace.options.layer-options.blend-mode.multiply")} - {:value "color-burn" :label (tr "workspace.options.layer-options.blend-mode.color-burn")} - {:value "lighten" :label (tr "workspace.options.layer-options.blend-mode.lighten")} - {:value "screen" :label (tr "workspace.options.layer-options.blend-mode.screen")} - {:value "color-dodge" :label (tr "workspace.options.layer-options.blend-mode.color-dodge")} - {:value "overlay" :label (tr "workspace.options.layer-options.blend-mode.overlay")} - {:value "soft-light" :label (tr "workspace.options.layer-options.blend-mode.soft-light")} - {:value "hard-light" :label (tr "workspace.options.layer-options.blend-mode.hard-light")} - {:value "difference" :label (tr "workspace.options.layer-options.blend-mode.difference")} - {:value "exclusion" :label (tr "workspace.options.layer-options.blend-mode.exclusion")} - {:value "hue" :label (tr "workspace.options.layer-options.blend-mode.hue")} - {:value "saturation" :label (tr "workspace.options.layer-options.blend-mode.saturation")} - {:value "color" :label (tr "workspace.options.layer-options.blend-mode.color")} - {:value "luminosity" :label (tr "workspace.options.layer-options.blend-mode.luminosity")}]) - :on-change handle-change-blend-mode - :is-open? @is-option-highlighted? - :on-pointer-enter-option handle-option-enter - :on-pointer-leave-option handle-option-leave}] - - [:div.input-element {:title (tr "workspace.options.opacity") :class "percentail"} - [:> numeric-input {:value (-> values :opacity opacity->string) - :placeholder (tr "settings.multiple") - :on-focus select-all - :on-change handle-opacity-change - :min 0 - :max 100}]] + [:& select + {:class "flex-grow" + :default-value selected-blend-mode + :options options + :on-change handle-change-blend-mode + :is-open? option-highlighted? + :on-pointer-enter-option handle-option-enter + :on-pointer-leave-option handle-option-leave}] + [:div.input-element {:title (tr "workspace.options.opacity") + :class "percentail"} + [:> numeric-input + {:value (opacity->string current-opacity) + :placeholder (tr "settings.multiple") + :on-focus select-all! + :on-change handle-opacity-change + :min 0 + :max 100}]] [:div.element-set-actions.layer-actions (cond From 6eb5c75ad40b4c0d829ec0b13ab9a1159cf80474 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 24 May 2023 08:52:26 +0200 Subject: [PATCH 3/3] :bug: Fix preview layer blend modes on multiselection and avoid persisting data while previewing --- CHANGES.md | 1 + frontend/src/app/main/data/workspace.cljs | 19 ++++++++++ frontend/src/app/main/refs.cljs | 5 +++ .../src/app/main/ui/components/select.cljs | 3 ++ frontend/src/app/main/ui/shapes/shape.cljs | 21 +++++++---- .../sidebar/options/menus/layer.cljs | 36 +++++++++---------- 6 files changed, 59 insertions(+), 26 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8c92a234c..b74a11ba1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,7 @@ - Fix problem with layout not reflowing on shape deletion [Taiga #5289](https://tree.taiga.io/project/penpot/issue/5289) - Fix extra long typography names on assets and palette [Taiga #5199](https://tree.taiga.io/project/penpot/issue/5199) - Fix background-color property on inspect code [Taiga #5300](https://tree.taiga.io/project/penpot/issue/5300) +- Preview layer blend modes (by @akshay-gupta7) [Github #3235](https://github.com/penpot/penpot/pull/3235) ## 1.18.3 diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index d6177bcc1..3eb63b18c 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -2159,6 +2159,25 @@ (d/dissoc-in state [:workspace-annotations :id-for-create]))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Preview blend modes +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn set-preview-blend-mode + [ids blend-mode] + (ptk/reify ::set-preview-blend-mode + ptk/UpdateEvent + (update [_ state] + (reduce #(assoc-in %1 [:workspace-preview-blend %2] blend-mode) state ids)))) + +(defn unset-preview-blend-mode + [ids] + (ptk/reify ::unset-preview-blend-mode + ptk/UpdateEvent + (update [_ state] + (reduce #(update %1 :workspace-preview-blend dissoc %2) state ids)))) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Exports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 6fa852010..feb0d601a 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -550,3 +550,8 @@ (def current-file-id (l/derived :current-file-id st/state)) +(def workspace-preview-blend + (l/derived :workspace-preview-blend st/state)) + +(defn workspace-preview-blend-by-id [id] + (l/derived (l/key id) workspace-preview-blend =)) diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index 3550d6163..c3c117341 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -72,6 +72,9 @@ (d/read-string))] (on-pointer-leave-option value)))))] + (mf/with-effect [default-value] + (swap! state* assoc :current-value default-value)) + [:div.custom-select {:on-click open-dropdown :class class} [:span current-label] [:span.dropdown-button i/arrow-down] diff --git a/frontend/src/app/main/ui/shapes/shape.cljs b/frontend/src/app/main/ui/shapes/shape.cljs index 7e398d302..d1f767ead 100644 --- a/frontend/src/app/main/ui/shapes/shape.cljs +++ b/frontend/src/app/main/ui/shapes/shape.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] + [app.main.refs :as refs] [app.main.ui.context :as muc] [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.export :as ed] @@ -53,33 +54,39 @@ children (unchecked-get props "children") pointer-events (unchecked-get props "pointer-events") disable-shadows? (unchecked-get props "disable-shadows?") + shape-id (:id shape) + + preview-blend-mode-ref + (mf/with-memo [shape-id] (refs/workspace-preview-blend-by-id shape-id)) + + blend-mode (-> (mf/deref preview-blend-mode-ref) + (or (:blend-mode shape))) type (:type shape) render-id (mf/use-id) filter-id (dm/str "filter_" render-id) styles (-> (obj/create) (obj/set! "pointerEvents" pointer-events) - (cond-> (and (:blend-mode shape) (not= (:blend-mode shape) :normal)) - (obj/set! "mixBlendMode" (d/name (:blend-mode shape))))) + (cond-> (and blend-mode (not= blend-mode :normal)) + (obj/set! "mixBlendMode" (d/name blend-mode)))) include-metadata? (mf/use-ctx ed/include-metadata-ctx) shape-without-blur (dissoc shape :blur) shape-without-shadows (assoc shape :shadow []) - filter-str (when (and (or (cph/group-shape? shape) - (cph/frame-shape? shape) - (cph/svg-raw-shape? shape)) - (not disable-shadows?)) + (cph/frame-shape? shape) + (cph/svg-raw-shape? shape)) + (not disable-shadows?)) (filters/filter-str filter-id shape)) wrapper-props (-> (obj/clone props) (obj/without ["shape" "children" "disable-shadows?"]) (obj/set! "ref" ref) - (obj/set! "id" (dm/fmt "shape-%" (:id shape))) + (obj/set! "id" (dm/fmt "shape-%" shape-id)) (obj/set! "style" styles)) wrapper-props diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index 0732d6465..8b9d9667b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.main.data.workspace :as dw] [app.main.data.workspace.changes :as dch] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] @@ -62,30 +63,27 @@ (mf/use-fn (mf/deps on-change) (fn [value] - (when (not= "multiple" value) - (swap! state* assoc - :selected-blend-mode value - :option-highlighted? false - :preview-complete? true) - (on-change :blend-mode value)))) + (swap! state* assoc + :selected-blend-mode value + :option-highlighted? false + :preview-complete? true) + (on-change :blend-mode value))) - handle-option-enter + handle-blend-mode-enter (mf/use-fn (mf/deps on-change current-blend-mode) (fn [value] - (when (not= :multiple current-blend-mode) - (swap! state* assoc - :preview-complete? false - :option-highlighted? true) - (on-change :blend-mode value)))) + (swap! state* assoc + :preview-complete? false + :option-highlighted? true) + (st/emit! (dw/set-preview-blend-mode ids value)))) - handle-option-leave + handle-blend-mode-leave (mf/use-fn (mf/deps on-change selected-blend-mode) (fn [_value] - (when (not= :multiple current-blend-mode) - (swap! state* assoc :preview-complete? true) - (on-change :blend-mode selected-blend-mode)))) + (swap! state* assoc :preview-complete? true) + (st/emit! (dw/unset-preview-blend-mode ids)))) handle-opacity-change (mf/use-fn @@ -121,7 +119,7 @@ options (mf/with-memo [current-blend-mode] (d/concat-vec - (when (= :multiple current-blend-mode) + (when (= "multiple" current-blend-mode) [{:value "multiple" :label "--"}]) [{:value "normal" :label (tr "workspace.options.layer-options.blend-mode.normal")} {:value "darken" :label (tr "workspace.options.layer-options.blend-mode.darken")} @@ -164,8 +162,8 @@ :options options :on-change handle-change-blend-mode :is-open? option-highlighted? - :on-pointer-enter-option handle-option-enter - :on-pointer-leave-option handle-option-leave}] + :on-pointer-enter-option handle-blend-mode-enter + :on-pointer-leave-option handle-blend-mode-leave}] [:div.input-element {:title (tr "workspace.options.opacity") :class "percentail"}