diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 81791d652..b0229d42e 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -55,6 +55,33 @@ (>= % min-safe-int) (<= % max-safe-int))) + +(s/def :internal.page.gradient.stop/color ::string) +(s/def :internal.page.gradient.stop/opacity ::safe-number) +(s/def :internal.page.gradient.stop/offset ::safe-number) + +(s/def :internal.page.gradient/start-x ::safe-number) +(s/def :internal.page.gradient/start-y ::safe-number) +(s/def :internal.page.gradient/end-x ::safe-number) +(s/def :internal.page.gradient/end-y ::safe-number) +(s/def :internal.page.gradient/width ::safe-number) + +(s/def :internal.page.gradient/stop + (s/keys :req-un [:internal.page.gradient.stop/color + :internal.page.gradient.stop/opacity + :internal.page.gradient.stop/offset])) + +(s/def :internal.page.gradient/stops + (s/map-of ::safe-number :internal.page.gradient/stop)) + +(s/def ::gradient + (s/keys :req-un [:internal.page.gradient/start-x + :internal.page.gradient/start-y + :internal.page.gradient/end-x + :internal.page.gradient/end-y + :internal.page.gradient/width + :internal.page.gradient/stops])) + ;; Page Options (s/def :internal.page.grid.color/value string?) (s/def :internal.page.grid.color/opacity ::safe-number) @@ -110,10 +137,13 @@ (s/def :internal.shape/blocked boolean?) (s/def :internal.shape/collapsed boolean?) (s/def :internal.shape/content any?) + (s/def :internal.shape/fill-color string?) +(s/def :internal.shape/fill-opacity ::safe-number) +(s/def :internal.shape/fill-gradient (s/nilable ::gradient)) (s/def :internal.shape/fill-color-ref-file (s/nilable uuid?)) (s/def :internal.shape/fill-color-ref-id (s/nilable uuid?)) -(s/def :internal.shape/fill-opacity ::safe-number) + (s/def :internal.shape/font-family string?) (s/def :internal.shape/font-size ::safe-integer) (s/def :internal.shape/font-style string?) diff --git a/frontend/resources/styles/main/partials/colorpicker.scss b/frontend/resources/styles/main/partials/colorpicker.scss index fc3f6c457..45a62c6c0 100644 --- a/frontend/resources/styles/main/partials/colorpicker.scss +++ b/frontend/resources/styles/main/partials/colorpicker.scss @@ -280,6 +280,10 @@ justify-items: center; grid-column-gap: 0.25rem; + &.disable-opacity { + grid-template-columns: 3.5rem repeat(3, 1fr); + } + input { width: 100%; margin: 0; diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 99c2c45ab..d8f793656 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -83,6 +83,7 @@ gradient-data (select-keys gradient [:start-x :start-y :end-x :end-y :width])] + (cond-> {:type type :current-color current-color} gradient (assoc :gradient-data gradient-data) @@ -113,7 +114,7 @@ :width 1.0}) (mf/defc colorpicker - [{:keys [data on-change on-accept]}] + [{:keys [data disable-gradient disable-opacity on-change on-accept]}] (let [state (mf/use-state (data->state data)) active-tab (mf/use-state :ramp #_:harmony #_:hsva) locale (mf/deref i18n/locale) @@ -138,8 +139,9 @@ handle-change-color (fn [changes] (let [editing-stop (:editing-stop @state)] - (swap! state update :current-color merge changes) - (swap! state update-in [:stops editing-stop] merge changes) + (swap! state #(cond-> % + true (update :current-color merge changes) + editing-stop (update-in [:stops editing-stop] merge changes))) #_(when (:hex changes) (reset! value-ref (:hex changes))) @@ -150,10 +152,12 @@ handle-change-stop (fn [offset] - (let [offset-color (get-in @state [:stops offset])] - (swap! state assoc :current-color offset-color) - (swap! state assoc :editing-stop offset) - (st/emit! (dc/select-gradient-stop offset)))) + (when-let [offset-color (get-in @state [:stops offset])] + (do (swap! state assoc + :current-color offset-color + :editing-stop offset) + + (st/emit! (dc/select-gradient-stop offset))))) on-select-library-color (fn [color] (prn "color" color)) @@ -210,20 +214,21 @@ (mf/use-effect (mf/deps picking-color? picked-color) - (fn [] (when picking-color? - (let [[r g b] (or picked-color [0 0 0]) - hex (uc/rgb->hex [r g b]) - [h s v] (uc/hex->hsv hex)] - - (swap! state update :current-color assoc - :r r :g g :b b - :h h :s s :v v - :hex hex) + (fn [] + (when picking-color? + (let [[r g b] (or picked-color [0 0 0]) + hex (uc/rgb->hex [r g b]) + [h s v] (uc/hex->hsv hex)] - ;; TODO: UPDATE TO USE GRADIENTS - #_(reset! value-ref hex) - #_(when picked-color-select - (on-change hex (:alpha current-color) nil nil picked-shift?)))))) + (swap! state update :current-color assoc + :r r :g g :b b + :h h :s s :v v + :hex hex) + + ;; TODO: UPDATE TO USE GRADIENTS + #_(reset! value-ref hex) + #_(when picked-color-select + (on-change hex (:alpha current-color) nil nil picked-shift?)))))) ;; TODO: UPDATE TO USE GRADIENTS #_(mf/use-effect @@ -256,14 +261,15 @@ (st/emit! (dc/start-picker)))} i/picker] - [:div.gradients-buttons - [:button.gradient.linear-gradient - {:on-click (on-activate-gradient :linear-gradient) - :class (when (= :linear-gradient (:type @state)) "active")}] + (when (not disable-gradient) + [:div.gradients-buttons + [:button.gradient.linear-gradient + {:on-click (on-activate-gradient :linear-gradient) + :class (when (= :linear-gradient (:type @state)) "active")}] - [:button.gradient.radial-gradient - {:on-click (on-activate-gradient :radial-gradient) - :class (when (= :radial-gradient (:type @state)) "active")}]]] + [:button.gradient.radial-gradient + {:on-click (on-activate-gradient :radial-gradient) + :class (when (= :radial-gradient (:type @state)) "active")}]])] [:& gradients {:type (:type @state) :stops (:stops @state) @@ -275,12 +281,19 @@ [:div.center-circle] [:canvas#picker-detail {:width 200 :height 160}]] (case @active-tab - :ramp [:& ramp-selector {:color current-color :on-change handle-change-color}] - :harmony [:& harmony-selector {:color current-color :on-change handle-change-color}] - :hsva [:& hsva-selector {:color current-color :on-change handle-change-color}] + :ramp [:& ramp-selector {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color}] + :harmony [:& harmony-selector {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color}] + :hsva [:& hsva-selector {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color}] nil)) [:& color-inputs {:type (if (= @active-tab :hsva) :hsv :rgb) + :disable-opacity disable-opacity :color current-color :on-change handle-change-color}] @@ -321,7 +334,10 @@ (mf/defc colorpicker-modal {::mf/register modal/components ::mf/register-as :colorpicker} - [{:keys [x y default data page position on-change on-close on-accept] :as props}] + [{:keys [x y default data page position + disable-gradient + disable-opacity + on-change on-close on-accept] :as props}] (let [vport (mf/deref viewport) dirty? (mf/use-var false) last-change (mf/use-var nil) @@ -350,6 +366,8 @@ [:div.colorpicker-tooltip {:style (clj->js style)} [:& colorpicker {:data data + :disable-gradient disable-gradient + :disable-opacity disable-opacity :on-change handle-change :on-accept on-accept}]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index 699762ad4..72a6341bb 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -26,7 +26,7 @@ [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [t]])) -(mf/defc color-inputs [{:keys [type color on-change]}] +(mf/defc color-inputs [{:keys [type color disable-opacity on-change]}] (let [{red :r green :g blue :b hue :h saturation :s value :v hex :hex alpha :alpha} color @@ -94,6 +94,7 @@ (dom/set-value! node (math/round property-val))))))))) [:div.color-values + {:class (when disable-opacity "disable-opacity")} [:input {:id "hex-value" :ref (:hex refs) :default-value hex @@ -150,14 +151,15 @@ :default-value value :on-change (on-change-property :v 255)}]]) - [:input.alpha-value {:id "alpha-value" - :ref (:alpha refs) - :type "number" - :min 0 - :step 1 - :max 100 - :default-value (if (= alpha :multiple) "" (math/precision alpha 2)) - :on-change on-change-opacity}] + (when (not disable-opacity) + [:input.alpha-value {:id "alpha-value" + :ref (:alpha refs) + :type "number" + :min 0 + :step 1 + :max 100 + :default-value (if (= alpha :multiple) "" (math/precision alpha 2)) + :on-change on-change-opacity}]) [:label.hex-label {:for "hex-value"} "HEX"] (if (= type :rgb) @@ -169,4 +171,5 @@ [:label.red-label {:for "hue-value"} "H"] [:label.green-label {:for "saturation-value"} "S"] [:label.blue-label {:for "value-value"} "V"]]) - [:label.alpha-label {:for "alpha-value"} "A"]])) + (when (not disable-opacity) + [:label.alpha-label {:for "alpha-value"} "A"])])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index 79588ac9f..a17a51006 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -69,7 +69,7 @@ y (+ (/ canvas-side 2) (* comp-y (/ canvas-side 2)))] (gpt/point x y))) -(mf/defc harmony-selector [{:keys [color on-change]}] +(mf/defc harmony-selector [{:keys [color disable-opacity on-change]}] (let [canvas-ref (mf/use-ref nil) {hue :h saturation :s value :v alpha :alpha} color @@ -146,9 +146,10 @@ :max-value 255 :vertical true :on-change on-change-value}] - [:& slider-selector {:class "opacity" - :vertical? true - :value alpha - :max-value 1 - :vertical true - :on-change on-change-opacity}]]])) + (when (not disable-opacity) + [:& slider-selector {:class "opacity" + :vertical? true + :value alpha + :max-value 1 + :vertical true + :on-change on-change-opacity}])]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs index c7cbfde79..5112f7473 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs @@ -27,7 +27,7 @@ [app.util.i18n :as i18n :refer [t]] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]])) -(mf/defc hsva-selector [{:keys [color on-change]}] +(mf/defc hsva-selector [{:keys [color disable-opacity on-change]}] (let [{hue :h saturation :s value :v alpha :alpha} color handle-change-slider (fn [key] (fn [new-value] @@ -52,6 +52,8 @@ [:& slider-selector {:class "value" :reverse? true :max-value 255 :value value :on-change (handle-change-slider :v)}] - [:span.hsva-selector-label "A"] - [:& slider-selector - {:class "opacity" :max-value 1 :value alpha :on-change on-change-opacity}]])) + (when (not disable-opacity) + [:* + [:span.hsva-selector-label "A"] + [:& slider-selector + {:class "opacity" :max-value 1 :value alpha :on-change on-change-opacity}]])])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 8cab70362..ab68a5e57 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -49,7 +49,7 @@ :top (str (* 100 (- 1 (/ value 255))) "%")}}]])) -(mf/defc ramp-selector [{:keys [color on-change]}] +(mf/defc ramp-selector [{:keys [color disable-opacity on-change]}] (let [{hue :h saturation :s value :v alpha :alpha} color on-change-value-saturation @@ -86,7 +86,8 @@ :value hue :on-change on-change-hue}] - [:& slider-selector {:class "opacity" - :max-value 1 - :value alpha - :on-change on-change-opacity}]]])) + (when (not disable-opacity) + [:& slider-selector {:class "opacity" + :max-value 1 + :value alpha + :on-change on-change-opacity}])]])) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 1b3b46965..0882bf649 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -19,6 +19,7 @@ [app.main.ui.workspace.shapes.common :as common] [app.main.data.workspace.selection :as dws] [app.main.ui.shapes.frame :as frame] + [app.main.ui.shapes.gradients :as grad] [app.main.ui.shapes.filters :as filters] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] @@ -126,8 +127,18 @@ :on-context-menu on-context-menu :on-double-click on-double-click :on-mouse-down on-mouse-down}] + [:g.frame {:filter (filters/filter-str filter-id shape)} [:& filters/filters {:filter-id filter-id :shape shape}] + + (when (:fill-color-gradient shape) + [:& grad/gradient {:attr :fill-color-gradient + :shape shape}]) + + (when (:stroke-color-gradient shape) + [:& grad/gradient {:attr :stroke-color-gradient + :shape shape}]) + [:& frame-shape {:shape shape :childs children}]]]))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 2bfe53b19..bca5a51de 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -40,15 +40,15 @@ [{:keys [shape shapes-with-children page-id file-id]}] [:* (case (:type shape) - :frame [:& frame/options {:shape shape}] - :group [:& group/options {:shape shape :shape-with-children shapes-with-children}] - :text [:& text/options {:shape shape}] - :rect [:& rect/options {:shape shape}] - :icon [:& icon/options {:shape shape}] + :frame [:& frame/options {:shape shape}] + :group [:& group/options {:shape shape :shape-with-children shapes-with-children}] + :text [:& text/options {:shape shape}] + :rect [:& rect/options {:shape shape}] + :icon [:& icon/options {:shape shape}] :circle [:& circle/options {:shape shape}] - :path [:& path/options {:shape shape}] - :curve [:& path/options {:shape shape}] - :image [:& image/options {:shape shape}] + :path [:& path/options {:shape shape}] + :curve [:& path/options {:shape shape}] + :image [:& image/options {:shape shape}] nil) [:& exports-menu {:shape shape diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/fill.cljs index 409b101ab..005c6333a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/fill.cljs @@ -63,13 +63,14 @@ (mf/use-callback (mf/deps ids) (fn [event] - (st/emit! (dc/change-fill ids cp/default-color nil nil)))) + (st/emit! (dc/change-fill2 ids {:color cp/default-color + :opacity 1})))) on-delete (mf/use-callback (mf/deps ids) (fn [event] - (st/emit! (dc/change-fill ids nil nil nil)))) + (st/emit! (dc/change-fill2 ids nil)))) on-change (mf/use-callback diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index 04e6fe5e9..31381c3a0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -44,8 +44,9 @@ [:div.element-set [:div.element-set-title (t locale "workspace.options.canvas-background")] [:div.element-set-content - [:& color-row {:disable-opacity true - :color {:value (get options :background "#E8E9EA") + [:& color-row {:disable-gradient true + :disable-opacity true + :color {:color (get options :background "#E8E9EA") :opacity 1} :on-change handle-change-color :on-open on-open 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 2f86c5590..93439b626 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 @@ -21,12 +21,14 @@ [app.util.color :as uc])) (defn color-picker-callback - [color handle-change-color handle-open handle-close] + [color disable-gradient disable-opacity handle-change-color handle-open handle-close] (fn [event] (let [x (.-clientX event) y (.-clientY event) props {:x x :y y + :disable-gradient disable-gradient + :disable-opacity disable-opacity :on-change handle-change-color :on-close handle-close :data color}] @@ -57,7 +59,7 @@ (if (= v :multiple) nil v)) (mf/defc color-row - [{:keys [color on-change on-open on-close]}] + [{:keys [color disable-gradient disable-opacity on-change on-open on-close]}] (let [file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/workspace-libraries) @@ -69,28 +71,14 @@ (-> color (update :color #(or % (:value color))))) - state (mf/use-state (parse-color color)) - - value (:color @state) - opacity (:opacity @state) - change-value (fn [new-value] - (swap! state assoc :color new-value) - (when on-change (on-change new-value (remove-multiple opacity)))) + (when on-change (on-change (assoc color :color new-value)))) change-opacity (fn [new-opacity] - (swap! state assoc :opacity new-opacity) - (when on-change (on-change (remove-multiple value) new-opacity))) - - ;;handle-pick-color (fn [new-value new-opacity id file-id] - ;; (reset! state {:color new-value :opacity new-opacity}) - ;; (when on-change (on-change new-value new-opacity id file-id))) + (when on-change (on-change (assoc color :opacity new-opacity)))) handle-pick-color (fn [color] - (prn "handle-pick-color" color) - (reset! state color) - (when on-change - (on-change color))) + (when on-change (on-change color))) handle-open (fn [] (when on-open (on-open))) @@ -114,20 +102,24 @@ change-opacity)))) select-all (fn [event] - (dom/select-text! (dom/get-target event)))] + (dom/select-text! (dom/get-target event))) + + handle-click-color (mf/use-callback + (mf/deps color) + (color-picker-callback color disable-gradient disable-opacity + handle-pick-color handle-open handle-close))] (mf/use-effect (mf/deps color) (fn [] - (modal/update-props! :colorpicker {:data (parse-color color)}) - (reset! state (parse-color color)))) + (modal/update-props! :colorpicker {:data (parse-color color)}))) [:div.row-flex.color-data [:span.color-th {:class (when (and (:id color) (not= (:id color) :multiple)) "color-name") :style {:background (uc/color->background color)} - :on-click (color-picker-callback @state handle-pick-color handle-open handle-close)} - (when (= value :multiple) "?")] + :on-click handle-click-color} + (when (= (:color color) :multiple) "?")] (cond ;; Rendering a color with ID @@ -136,7 +128,7 @@ [:div.color-name (str (get-color-name color))]] ;; Rendering a gradient - (:gradient color) + (and (:gradient color) (get-in color [:gradient :type])) [:div.color-info [:div.color-name (case (get-in color [:gradient :type]) @@ -147,19 +139,20 @@ :else [:* [:div.color-info - [:input {:value (-> value remove-hash) + [:input {:value (-> color :color remove-hash) :pattern "^[0-9a-fA-F]{0,6}$" :placeholder (tr "settings.multiple") :on-click select-all :on-change handle-value-change}]] - [:div.input-element - {:class (classnames :percentail (not= opacity :multiple))} - [:input.input-text {:type "number" - :value (-> opacity opacity->string) - :placeholder (tr "settings.multiple") - :on-click select-all - :on-change handle-opacity-change - :min "0" - :max "100"}]]])])) + (when (not disable-opacity) + [:div.input-element + {:class (classnames :percentail (not= (:opacity color) :multiple))} + [:input.input-text {:type "number" + :value (-> color :opacity opacity->string) + :placeholder (tr "settings.multiple") + :on-click select-all + :on-change handle-opacity-change + :min "0" + :max "100"}]])])]))